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

feat: #572 public search by fom #615

Merged
merged 11 commits into from
Apr 10, 2024
5,212 changes: 2,610 additions & 2,602 deletions api/openapi/swagger-spec.json

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions api/src/app/modules/project/project.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ export class ProjectController {
// Anonymous access allowed
@Get('/publicSummary')
@AuthGuardMeta(GUARD_OPTIONS.PUBLIC)
@ApiQuery({ name: 'projectId', required: false})
@ApiQuery({ name: 'includeCommentOpen', required: false})
@ApiQuery({ name: 'includePostCommentOpen', required: false})
@ApiQuery({ name: 'forestClientName', required: false})
@ApiQuery({ name: 'openedOnOrAfter', required: false})
@ApiResponse({ status: HttpStatus.OK, type: [ProjectPublicSummaryResponse] })
async findPublicSummary(
@Query('projectId') projectId?: string,
@Query('includeCommentOpen') includeCommentOpen: string = 'true',
@Query('includePostCommentOpen') includePostCommentOpen: string = 'true',
@Query('forestClientName') forestClientName?: string,
Expand All @@ -36,6 +38,10 @@ export class ProjectController {

const findCriteria: ProjectFindCriteria = new ProjectFindCriteria();

if (projectId) {
findCriteria.projectId = await new ParseIntPipe().transform(projectId, null);
}

if (forestClientName) {
findCriteria.likeForestClientName = forestClientName;
}
Expand Down
4 changes: 4 additions & 0 deletions api/src/app/modules/project/project.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,12 @@ export class ProjectFindCriteria {
fspId?: number;
districtId?: number;
includeForestClientNumbers: string[] = [];
projectId?: number;

applyFindCriteria(query: SelectQueryBuilder<Project>) {
if (this.projectId) {
query.andWhere("p.id = :projectId", {projectId: this.projectId})
}
if (this.fspId) {
query.andWhere("p.fsp_id = :fspId", {fspId: `${this.fspId}`});
}
Expand Down
13 changes: 9 additions & 4 deletions libs/client/typescript-ng/api/project.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -455,19 +455,24 @@ export class ProjectService {
}

/**
* @param projectId
* @param includeCommentOpen
* @param includePostCommentOpen
* @param forestClientName
* @param openedOnOrAfter
* @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body.
* @param reportProgress flag to report request and response progress.
*/
public projectControllerFindPublicSummary(includeCommentOpen?: string, includePostCommentOpen?: string, forestClientName?: string, openedOnOrAfter?: string, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json'}): Observable<Array<ProjectPublicSummaryResponse>>;
public projectControllerFindPublicSummary(includeCommentOpen?: string, includePostCommentOpen?: string, forestClientName?: string, openedOnOrAfter?: string, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json'}): Observable<HttpResponse<Array<ProjectPublicSummaryResponse>>>;
public projectControllerFindPublicSummary(includeCommentOpen?: string, includePostCommentOpen?: string, forestClientName?: string, openedOnOrAfter?: string, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json'}): Observable<HttpEvent<Array<ProjectPublicSummaryResponse>>>;
public projectControllerFindPublicSummary(includeCommentOpen?: string, includePostCommentOpen?: string, forestClientName?: string, openedOnOrAfter?: string, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json'}): Observable<any> {
public projectControllerFindPublicSummary(projectId?: string, includeCommentOpen?: string, includePostCommentOpen?: string, forestClientName?: string, openedOnOrAfter?: string, observe?: 'body', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json'}): Observable<Array<ProjectPublicSummaryResponse>>;
public projectControllerFindPublicSummary(projectId?: string, includeCommentOpen?: string, includePostCommentOpen?: string, forestClientName?: string, openedOnOrAfter?: string, observe?: 'response', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json'}): Observable<HttpResponse<Array<ProjectPublicSummaryResponse>>>;
public projectControllerFindPublicSummary(projectId?: string, includeCommentOpen?: string, includePostCommentOpen?: string, forestClientName?: string, openedOnOrAfter?: string, observe?: 'events', reportProgress?: boolean, options?: {httpHeaderAccept?: 'application/json'}): Observable<HttpEvent<Array<ProjectPublicSummaryResponse>>>;
public projectControllerFindPublicSummary(projectId?: string, includeCommentOpen?: string, includePostCommentOpen?: string, forestClientName?: string, openedOnOrAfter?: string, observe: any = 'body', reportProgress: boolean = false, options?: {httpHeaderAccept?: 'application/json'}): Observable<any> {

let queryParameters = new HttpParams({encoder: this.encoder});
if (projectId !== undefined && projectId !== null) {
queryParameters = this.addToHttpParams(queryParameters,
<any>projectId, 'projectId');
}
if (includeCommentOpen !== undefined && includeCommentOpen !== null) {
queryParameters = this.addToHttpParams(queryParameters,
<any>includeCommentOpen, 'includeCommentOpen');
Expand Down
13 changes: 12 additions & 1 deletion public/src/app/applications/find-panel/find-panel.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ <h3 class="title">Find FOM</h3>

<div class="flex-panel__scroll">
<div class="find-form">
<div class="form-group">
<label class="control-label">FOM #</label>
<input id="fomNumberInput" type="text"
class="form-control limit-width-1"
[maxlength]="maxInputLength"
(keyup)="verifyFomNumberInput($event)"
(keyup.enter)="applyAllFilters()"
(mousewheel)="$event.preventDefault()"
[(ngModel)]="fomNumberFilter.filter.value" />
</div>

<div class="form-group">
<label class="control-label">FOM Holder Name (or portion)</label>
<input id="forestClientNameInput" type="text"
Expand Down Expand Up @@ -81,4 +92,4 @@ <h3>What is a FOM Holder Name?</h3>
</section>

</div>
</div>
</div>
13 changes: 13 additions & 0 deletions public/src/app/applications/find-panel/find-panel.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ export class FindPanelComponent implements OnDestroy, OnInit {
private ngUnsubscribe: Subject<void> = new Subject<void>();
public workflowState: _.Dictionary<WorkflowStateCode>;
private fomFilters: Map<string, IFilter | IMultiFilter>;
public fomNumberFilter = new Filter<number>({ filter: { queryParam: 'fomNumber', value: null }});
public forestClientNameFilter = new Filter<string>({ filter: { queryParam: 'fcName', value: null }});
public commentStatusFilters: MultiFilter<boolean>; // For 'Commenting Open' or 'Commenting Closed'.
public postedOnAfterFilter = new Filter<Date>({ filter: { queryParam: 'pdOnAfter', value: null } });
readonly minDate = moment('2018-03-23').toDate(); // first app created
readonly maxDate = moment().toDate(); // today
readonly maxInputLength = 9;
basilv marked this conversation as resolved.
Show resolved Hide resolved

constructor(public urlSvc: UrlService,
private fomFiltersSvc: FOMFiltersService) {
Expand All @@ -52,6 +54,7 @@ export class FindPanelComponent implements OnDestroy, OnInit {
ngOnInit(): void {
this.fomFiltersSvc.filters$.pipe(takeUntil(this.ngUnsubscribe)).subscribe((filters) => {
this.fomFilters = filters;
this.fomNumberFilter = this.fomFilters.get(FOM_FILTER_NAME.FOM_NUMBER) as Filter<number>;
this.forestClientNameFilter = this.fomFilters.get(FOM_FILTER_NAME.FOREST_CLIENT_NAME) as Filter<string>;
this.commentStatusFilters = this.fomFilters.get(FOM_FILTER_NAME.COMMENT_STATUS) as MultiFilter<boolean>;
this.postedOnAfterFilter = this.fomFilters.get(FOM_FILTER_NAME.POSTED_ON_AFTER) as Filter<Date>;
Expand All @@ -67,6 +70,7 @@ export class FindPanelComponent implements OnDestroy, OnInit {
*/
public checkAndSetFiltersHash(): boolean {
const newFilterHash = FilterUtils.hashFilters(
this.fomNumberFilter,
this.forestClientNameFilter,
this.commentStatusFilters,
this.postedOnAfterFilter);
Expand Down Expand Up @@ -98,6 +102,15 @@ export class FindPanelComponent implements OnDestroy, OnInit {
}
}

public verifyFomNumberInput(event) {
let parsed = parseInt(event.target.value.toString().replace(/^0+(?=\d)/, ''), 10);
// fomNumber search field is a positive integer excluding 0;
if (isNaN(parsed) || parsed == 0) {
parsed = null;
}
this.fomNumberFilter.filter.value = parsed;
}

/**
* Emit the current selected filters to the parent, if the filters have changed since the last time emit was called.
*
Expand Down
2 changes: 2 additions & 0 deletions public/src/app/applications/projects.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ export class ProjectsComponent implements OnInit, OnDestroy {
}

fetchFOMs(fomFilters: Map<string, IFilter | IMultiFilter>) {
const fomNumberParam = (fomFilters.get(FOM_FILTER_NAME.FOM_NUMBER) as Filter<number>).filter.value;
const forestClientNameParam = (fomFilters.get(FOM_FILTER_NAME.FOREST_CLIENT_NAME) as Filter<string>).filter.value;
const commentStatusFilters = fomFilters.get(FOM_FILTER_NAME.COMMENT_STATUS)['filters'] as Array<IMultiFilterFields<boolean>>;
const commentOpenParam = commentStatusFilters.filter(filter => filter.queryParam == COMMENT_STATUS_FILTER_PARAMS.COMMENT_OPEN)[0].value;
Expand All @@ -173,6 +174,7 @@ export class ProjectsComponent implements OnInit, OnDestroy {
this.loading = true;
this.projectService
.projectControllerFindPublicSummary(
fomNumberParam?.toString(),
commentOpenParam.toString(),
commentClosedParam.toString(),
forestClientNameParam,
Expand Down
4 changes: 4 additions & 0 deletions public/src/core/services/fomFilters.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
import { Filter, IFilter, IMultiFilter, IMultiFilterFields, MultiFilter } from '../../app/applications/utils/filter';

export enum FOM_FILTER_NAME {
FOM_NUMBER = 'fomNumber',
FOREST_CLIENT_NAME = 'fcName',
POSTED_ON_AFTER = 'pdOnAfter',
COMMENT_STATUS = 'cmtStatus'
Expand All @@ -22,6 +23,7 @@ export const COMMENT_STATUS_FILTER_PARAMS = {
(However, that inteface definition is kind of strange, may need to review/refactor later.)
*/
export const DEFAULT_FOM_FILTERS = {
fomNumberFilter: { filter: {queryParam: FOM_FILTER_NAME.FOM_NUMBER, value: null }},
fcNameFilter: { filter: {queryParam: FOM_FILTER_NAME.FOREST_CLIENT_NAME, value: null }},
postedOnAfterFilter: { filter: {queryParam: FOM_FILTER_NAME.POSTED_ON_AFTER, value: null }},
commentStatusFilters: {
Expand Down Expand Up @@ -89,9 +91,11 @@ export class FOMFiltersService {

_getDefaultFilters(): Map<string, IFilter|IMultiFilter> {
let defaultFilters = new Map();
const fomNumberFilter = new Filter<string>(AppUtils.copy(DEFAULT_FOM_FILTERS.fomNumberFilter));
const forestClientNameFilter = new Filter<string>(AppUtils.copy(DEFAULT_FOM_FILTERS.fcNameFilter));
const postedOnAfterFilter = new Filter<Date>(AppUtils.copy(DEFAULT_FOM_FILTERS.postedOnAfterFilter));
const commentStatusFilters = new MultiFilter<boolean>(AppUtils.copy(DEFAULT_FOM_FILTERS.commentStatusFilters));
defaultFilters.set(FOM_FILTER_NAME.FOM_NUMBER, fomNumberFilter);
defaultFilters.set(FOM_FILTER_NAME.FOREST_CLIENT_NAME, forestClientNameFilter);
defaultFilters.set(FOM_FILTER_NAME.POSTED_ON_AFTER, postedOnAfterFilter);
defaultFilters.set(FOM_FILTER_NAME.COMMENT_STATUS, commentStatusFilters);
Expand Down
Loading