Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2741 - Ministry Filter Search Programs and Offerings [Location and Program Status Search] #3819

Conversation

sh16011993
Copy link
Collaborator

@sh16011993 sh16011993 commented Oct 23, 2024

As a part of the PR, the following were completed:

  • Added Location Search and Program Status Search for the institution programs in the UI. Each of the searches act as an && operation.
  • Added sorting for the Location Name and the Program Status columns.
  • Updated the api to include the location and the program status in the pagination for the search and updated the sql query fetching the result.

Screenshots:

Location Search and Program Status Search added:

image

Location Search with Program Search Empty and Program Statuses: Pending and Inactive selected:

image

Both Location and Program Search with Program Statuses: Pending and Approved selected

image

Location Search along with the Program Status: Pending selected:

image

Inactive Programs selected:

image

Nothing selected from the Program Status filter:

image

Descending Sort by Program Status:

image

Natural Sorting (without ASC / DESC selected) on page load:

image

Ascending Sort by Program Status:

image

@sh16011993 sh16011993 self-assigned this Oct 23, 2024
@sh16011993 sh16011993 added Ministry Ministry Features SIMS-Api SIMS-Api labels Oct 23, 2024
@guru-aot guru-aot self-requested a review October 23, 2024 16:18
);
queryParams.push(`%${paginationOptions.locationNameSearch}%`);
}
if (paginationOptions.status) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

👍

@@ -331,6 +331,33 @@ export class EducationProgramService extends RecordDataModelService<EducationPro
});
queryParams.push(`%${paginationOptions.searchCriteria}%`);
}
if (paginationOptions.programNameSearch) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please correct me if i am wrong, the paginationOptions, if searched with only one criteria, paginationOptions.searchCriteria is used else the paginationOptions.programNameSearch and paginationOptions.locationNameSearch is pushed. If that is the case, either paginationOptions.searchCriteria should be pushed or the paginationOptions.programNameSearch and paginationOptions.locationNameSearch.

Copy link
Collaborator

Choose a reason for hiding this comment

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

searchCriteria should not be used for programs.
@sh16011993 what if we change the service models as below to ensure the searchCriteria will not be present.

export interface BasePaginationOptions {
  sortField?: string;
  sortOrder?: FieldSortOrder;
  page: number;
  pageLimit: number;
}

/**
 *  Pagination option.
 */
export interface PaginationOptions extends BasePaginationOptions {
  searchCriteria?: string;
}

export interface ProgramPaginationOptions extends BasePaginationOptions {
  programNameSearch?: string;
  locationNameSearch?: string;
  status?: string;
}

Copy link
Collaborator

@guru-aot guru-aot left a comment

Choose a reason for hiding this comment

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

Looks good, please have a look on the comment

}
if (paginationOptions.status) {
paginatedProgramQuery.andWhere(
"programs.programStatus Ilike :programStatusSearchCriteria",
Copy link
Collaborator

Choose a reason for hiding this comment

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

programStatus does not require Ilike.

@@ -11,6 +11,12 @@ export interface PaginationOptions {
pageLimit: number;
}

export interface ProgramPaginationOptions extends PaginationOptions {
Copy link
Collaborator

@andrewsignori-aot andrewsignori-aot Oct 23, 2024

Choose a reason for hiding this comment

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

Comment on lines +99 to +107
if (
paginationOptions.searchCriteria &&
typeof paginationOptions.searchCriteria === "object"
) {
const searchCriteria = paginationOptions.searchCriteria;
for (const searchCriterion in searchCriteria) {
parameters.push(`${searchCriterion}=${searchCriteria[searchCriterion]}`);
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggestion:

if (!paginationOptions.searchCriteria) {
  return parameters.join("&");
}
// Search criteria.
if (typeof paginationOptions.searchCriteria === "string") {
  // Single search criteria.
  parameters.push(
    `${PaginationParams.SearchCriteria}=${paginationOptions.searchCriteria}`,
  );
  return parameters.join("&");
}
// Multiple search criteria.
const searchCriteria = paginationOptions.searchCriteria;
for (const searchCriterion in paginationOptions.searchCriteria) {
  parameters.push(`${searchCriterion}=${searchCriteria[searchCriterion]}`);
}
return parameters.join("&");

@@ -123,7 +123,7 @@ export enum PaginationParams {
* todo: remove sortOrder: DataTableSortOrder when all primevue datatables are removed.
*/
export interface PaginationOptions {
searchCriteria?: string;
searchCriteria?: string | Record<string, string>;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you please add a comment to this parameter.

Copy link
Collaborator

@andrewsignori-aot andrewsignori-aot left a comment

Choose a reason for hiding this comment

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

Great work. Please take a look at the comments.

@sh16011993 sh16011993 marked this pull request as draft October 23, 2024 23:11
@sh16011993 sh16011993 marked this pull request as ready for review October 29, 2024 00:57
@sh16011993 sh16011993 marked this pull request as draft October 29, 2024 00:58
@sh16011993 sh16011993 marked this pull request as ready for review October 29, 2024 16:29
@sh16011993 sh16011993 changed the title #2741 - Ministry Filter Search Programs and Offerings [Location Search] #2741 - Ministry Filter Search Programs and Offerings [Location and Program Status Search] Oct 29, 2024
// query parameter assigned to paginatedProgramQuery like
// paginationOptions.searchCriteria or institutionId
// queryParams should follow the order/index.
const queryParams: any[] = [...offeringTypes, institutionId];
Copy link
Collaborator

Choose a reason for hiding this comment

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

Even being from the old code, it can be changed to unknown without a need for further modifications.

institutionId: number,
): {
programQuery: SelectQueryBuilder<EducationProgram>;
queryParams: any[];
Copy link
Collaborator

Choose a reason for hiding this comment

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

Comment on lines 305 to 313
if (
!paginationOptions.statusSearch &&
!paginationOptions.inactiveProgramSearch
) {
return {
results: [],
count: 0,
};
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

I am not following up on why "nothing" should be returned for this case. Can you please elaborate?

Copy link
Collaborator

Choose a reason for hiding this comment

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

As we talked let's move this to the beginning of the method.
It seems okay to stay if it respects the business requirements.
My advise would be to UI and DTO enforce that one of these should be present.

private async preparePaginatedProgramQuery(
paginatedProgramQuery: SelectQueryBuilder<EducationProgram>,
paginationOptions: PaginationOptions,
queryParams: any[],
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please change to unknown.

Comment on lines 899 to 925
// sort
if (
paginationOptions.sortField === "programStatus" &&
paginationOptions.sortOrder === "DESC"
) {
paginatedProgramQuery.orderBy(
`CASE
WHEN programs.programStatus = '${ProgramStatus.Pending}' and programs.isActive = true THEN ${SortPriority.Priority1}
WHEN programs.isActive = false THEN ${SortPriority.Priority2}
WHEN programs.programStatus = '${ProgramStatus.Declined}' and programs.isActive = true THEN ${SortPriority.Priority3}
WHEN programs.programStatus = '${ProgramStatus.Approved}' and programs.isActive = true THEN ${SortPriority.Priority4}
ELSE ${SortPriority.Priority5}
END`,
);
} else if (
paginationOptions.sortField === "programStatus" &&
paginationOptions.sortOrder === "ASC"
) {
paginatedProgramQuery.orderBy(
`CASE
WHEN programs.programStatus = '${ProgramStatus.Approved}' and programs.isActive = true THEN ${SortPriority.Priority1}
WHEN programs.programStatus = '${ProgramStatus.Declined}' and programs.isActive = true THEN ${SortPriority.Priority2}
WHEN programs.isActive = false THEN ${SortPriority.Priority3}
WHEN programs.programStatus = '${ProgramStatus.Pending}' and programs.isActive = true THEN ${SortPriority.Priority4}
ELSE ${SortPriority.Priority5}
END`,
);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since the requirement is to have this ordered alphabetically, can the first part be simplified as below?

// Sort
if (paginationOptions.sortField === "programStatus") {
  paginatedProgramQuery.orderBy(
    `CASE WHEN programs.isActive = false THEN '${INACTIVE_PROGRAM_STATUS}' ELSE programs.programStatus :: text end`,
    paginationOptions.sortOrder,
  );
} else if (paginationOptions.sortField && paginationOptions.sortOrder) {
  paginatedProgramQuery.orderBy(
    sortProgramsColumnMap(paginationOptions.sortField),
    paginationOptions.sortOrder,
  );
}

} from "@/types";
import { AESTRoutesConst } from "@/constants/routes/RouteConstants";
import StatusChipProgram from "@/components/generic/StatusChipProgram.vue";
import { EducationProgramService } from "@/services/EducationProgramService";

const INACTIVE_PROGRAM = "Inactive";
Copy link
Collaborator

Choose a reason for hiding this comment

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

This can be added to a common location and shared with the program status chip.

Comment on lines 167 to 188
const statusSearchList = JSON.parse(
JSON.stringify(searchProgramStatus.value),
);
const searchInactiveProgram = statusSearchList.indexOf("Inactive") > -1;
if (searchInactiveProgram) {
statusSearchList.splice(statusSearchList.indexOf("Inactive"), 1);
}
let searchCriteria: Record<string, string | string[] | boolean>;
if (statusSearchList.length) {
searchCriteria = {
programNameSearch: searchProgramName.value,
locationNameSearch: searchLocationName.value,
statusSearch: statusSearchList,
inactiveProgramSearch: searchInactiveProgram,
};
} else {
searchCriteria = {
programNameSearch: searchProgramName.value,
locationNameSearch: searchLocationName.value,
inactiveProgramSearch: searchInactiveProgram,
};
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can it be refactored as below? The idea is to execute more array checks than string manipulations.

const statusSearchList = searchProgramStatus.value.filter(
    (searchItem) => searchItem !== INACTIVE_PROGRAM,
  );
  const searchInactiveProgram = searchProgramStatus.value.some(
    (searchItem) => searchItem === INACTIVE_PROGRAM,
  );
  let searchCriteria: Record<string, string | string[] | boolean> = {
    programNameSearch: searchProgramName.value,
    locationNameSearch: searchLocationName.value,
    statusSearch: statusSearchList,
    inactiveProgramSearch: searchInactiveProgram,
  };
  if (statusSearchList.length) {
    searchCriteria.statusSearch = statusSearchList.toString(); // Check if we need JSON.stringify.
  }

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No conversion needed here as filter returns a string array.

Copy link
Collaborator

@andrewsignori-aot andrewsignori-aot left a comment

Choose a reason for hiding this comment

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

Great work doing the changes and refactors. Please take a look a the comments.

@@ -0,0 +1 @@
export const INACTIVE_PROGRAM = "Inactive";
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please use the same name from the API: INACTIVE_PROGRAM_STATUS.

// sort
if (paginationOptions.sortField === "programStatus") {
paginatedProgramQuery.orderBy(
`CASE WHEN programs.isActive = false THEN '${INACTIVE_PROGRAM_STATUS}' ELSE programs.programStatus :: text end`,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Please change it to "END".

Copy link
Collaborator

@andrewsignori-aot andrewsignori-aot left a comment

Choose a reason for hiding this comment

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

Thanks for making the changes and for all the effort. The search seems a great addition. Looks good 👍

Copy link

Copy link

Backend Unit Tests Coverage Report

Totals Coverage
Statements: 22.3% ( 3695 / 16568 )
Methods: 10.31% ( 212 / 2057 )
Lines: 25.63% ( 3205 / 12507 )
Branches: 13.87% ( 278 / 2004 )

Copy link

E2E Queue Consumers Coverage Report

Totals Coverage
Statements: 85.88% ( 1216 / 1416 )
Methods: 87.86% ( 123 / 140 )
Lines: 86.8% ( 1032 / 1189 )
Branches: 70.11% ( 61 / 87 )

Copy link

E2E SIMS API Coverage Report

Totals Coverage
Statements: 65.65% ( 5574 / 8490 )
Methods: 63.07% ( 683 / 1083 )
Lines: 69.83% ( 4404 / 6307 )
Branches: 44.27% ( 487 / 1100 )

Copy link

E2E Workflow Workers Coverage Report

Totals Coverage
Statements: 65.43% ( 583 / 891 )
Methods: 59.26% ( 64 / 108 )
Lines: 68.54% ( 464 / 677 )
Branches: 51.89% ( 55 / 106 )

@sh16011993 sh16011993 added this pull request to the merge queue Oct 31, 2024
Merged via the queue into main with commit 69840a9 Oct 31, 2024
20 checks passed
@sh16011993 sh16011993 deleted the 2741_ministry_filter_search_programs_and_offerings_add_location_search branch October 31, 2024 21:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Ministry Ministry Features SIMS-Api SIMS-Api
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants