Skip to content

Conversation

@tiago-graf
Copy link
Collaborator

@tiago-graf tiago-graf commented Jan 29, 2026

Summary

Adds a new view to the Ministry portal to list all programs in pending status.

Frontend Changes

  • Adds new view for pending programs.
  • Update left bar menu to include link to programs queue.
  • Update pending offerings view to remove "status" column.

Backend Changes

  • Update education program service class to add new pending programs method.
  • Update ministry education program controller to add new pending programs endpoint.

E2E Tests

  • Adds new E2E tests for the new pending programs endpoint
image

@tiago-graf tiago-graf self-assigned this Jan 29, 2026
@tiago-graf tiago-graf added Ministry Ministry Features E2E/Unit tests Web portal Backend Used by the dependabot pull requests to identify PRs related to the backend. labels Jan 29, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new Ministry dashboard view to display all programs in pending status, providing similar functionality to the existing pending offerings view. The implementation includes comprehensive backend support, frontend UI, and thorough e2e test coverage.

Changes:

  • New backend endpoint (GET /aest/education-program/pending) with pagination, sorting, and search capabilities for pending programs
  • New Vue component (ViewPendingPrograms.vue) displaying pending programs in a data table with institution details
  • Updated sidebar navigation to include link to the new programs queue view
  • Removed status column from pending offerings view for consistency

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
ViewPendingPrograms.vue New AEST view component for displaying pending programs with search and pagination
ViewPendingOfferings.vue Removed status column and StatusChipOffering component from pending offerings view
DataTableContract.ts Added PendingProgramsHeaders definition and updated PendingOfferingsHeaders
AppRoutes.ts Added PendingPrograms route constant
EducationProgram.dto.ts (frontend) Added EducationProgramPendingAPIOutDTO interface
EducationProgramApi.ts Added getPendingPrograms API client method
EducationProgramService.ts (frontend) Added getPendingPrograms service method
AESTRoutes.ts Added route configuration for ViewPendingPrograms component
RouteConstants.ts Added PENDING_PROGRAMS route constant
AESTHomeSideBar.vue Added "Programs" menu item under Institution requests
education-program.ts (factory) Enhanced factory to support name and programStatus in initialValues
education-program.service.ts Added getPendingPrograms method and addProgramsSort helper
education-program.service.models.ts Added PendingEducationProgram model class
pagination.dto.ts Added PendingProgramsPaginationOptionsAPIInDTO with sortField validation
education-program.dto.ts (backend) Added EducationProgramPendingAPIOutDTO class
education-program.aest.controller.ts Added getPendingPrograms endpoint handler
education-program.aest.controller.getPendingPrograms.e2e-spec.ts Comprehensive e2e tests covering pagination, sorting, filtering, and inactive programs

tiago-graf and others added 2 commits January 30, 2026 14:39
@tiago-graf tiago-graf marked this pull request as ready for review January 30, 2026 22:43
@andrewsignori-aot andrewsignori-aot self-requested a review January 30, 2026 22:52
@sonarqubecloud
Copy link

@github-actions
Copy link

Backend Unit Tests Coverage Report

Totals Coverage
Statements: 20.15% ( 4321 / 21443 )
Methods: 9.67% ( 253 / 2617 )
Lines: 24.32% ( 3710 / 15254 )
Branches: 10.02% ( 358 / 3572 )

@github-actions
Copy link

E2E Workflow Workers Coverage Report

Totals Coverage
Statements: 75.41% ( 1055 / 1399 )
Methods: 79.31% ( 115 / 145 )
Lines: 78.79% ( 769 / 976 )
Branches: 61.51% ( 171 / 278 )

@github-actions
Copy link

E2E Queue Consumers Coverage Report

Totals Coverage
Statements: 85.68% ( 1616 / 1886 )
Methods: 85% ( 187 / 220 )
Lines: 88.64% ( 1287 / 1452 )
Branches: 66.36% ( 142 / 214 )

@github-actions
Copy link

E2E SIMS API Coverage Report

Totals Coverage
Statements: 77.25% ( 8863 / 11473 )
Methods: 76.79% ( 1049 / 1366 )
Lines: 81.29% ( 6429 / 7909 )
Branches: 63.01% ( 1385 / 2198 )

const location = createFakeLocation(institution);
await db.institutionLocation.save(location);

const programA = createFakeEducationProgram(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker, but the code can be simplified as follows.

const [programA, programB, programC] = Array.from({ length: 3 }).map(
      (_, index) => {
        return createFakeEducationProgram(
          {
            auditUser: savedUser,
            institution,
          },
          {
            initialValues: {
              name: `Chemistry 30${index}`,
              programStatus: ProgramStatus.Pending,
              submittedDate: PAST_SUBMITTED_DATE,
            },
          },
        );
      },
    );
    await db.educationProgram.save([programC, programA, programB]);


it("Should return filtered pending programs when search by institution operating name is applied.", async () => {
// Arrange
const uniqueInstitutionName = "Unique Test Institution XYZ";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To avoid conflicts and allow the test to be executed multiple times locally, it would be preferable to use something really unique as faker.string.uuid(), as part of the name.
The full GUID can be used to execute the search partial match.

const uniqueInstitutionName = `Unique Institution - ${faker.string.uuid()}`;

</template>
</body-header>
<content-group>
<toggle-content :toggled="!programsAndCount?.count">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To allow the table loading behaviour, in the most recent task, we have been defining the toggle-content condition as follows.

<toggle-content :toggled="!programsAndCount?.count && !loading">

And also the v-skeleton-loader.

<template #loading>
  <v-skeleton-loader type="table-row@5"></v-skeleton-loader>
</template>

programsQuery: SelectQueryBuilder<EducationProgram>,
paginationOptions: PaginationOptions,
): void {
const sortField = paginationOptions.sortField || "submittedDate";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor, the submittedDate can be a const to be used at the three points below.

const defaultSortField = "submittedDate";
const sortField = paginationOptions.sortField || defaultSortField;
const sortOrder = paginationOptions.sortOrder || FieldSortOrder.ASC;

// Map the sort field to the correct column.
const sortColumnMap: Record<string, string> = {
  [defaultSortField]: "programs.submittedDate",
  programName: "programs.name",
  institutionOperatingName: "institution.operatingName",
};

const sortColumn = sortColumnMap[sortField] || sortColumnMap[defaultSortField];
programsQuery.orderBy(sortColumn, sortOrder);

Comment on lines +1037 to +1045
const pendingPrograms = entities.map((program, index) => ({
id: program.id,
name: program.name,
submittedDate: program.submittedDate,
institutionId: program.institution.id,
institutionOperatingName: program.institution.operatingName,
selectedLocationId:
raw[index].selectedLocationId ?? raw[index].selectedlocationid,
}));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We created the mapFromRawAndEntities to facilitate these conversions from raw executions. Can you please check if it can be applied here?

Comment on lines +1009 to +1015
.andWhere(
new Brackets((qb) => {
qb.where("programs.effectiveEndDate is null").orWhere(
"programs.effectiveEndDate > CURRENT_DATE",
);
}),
);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this condition required since the discussion and AC were adjusted to be only "check the is_active flag"?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Backend Used by the dependabot pull requests to identify PRs related to the backend. E2E/Unit tests Ministry Ministry Features Web portal

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants