From 10cdc205f3883371eca6f856bebf2f5a579a69f5 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Fri, 13 Aug 2021 21:46:48 +0300 Subject: [PATCH 1/3] fix icons bg, filter padding, make filter popup reactive --- .../app/models/file/file-status.wrapper.ts | 7 +- .../file-workload.component.html | 14 +- .../file-workload/file-workload.component.ts | 6 - .../dossier-listing-screen.component.html | 30 +-- .../dossier-listing-screen.component.ts | 40 ++-- .../file-preview-screen.component.html | 10 +- .../file-preview-screen.component.ts | 44 +++-- .../popup-filter/popup-filter.component.html | 176 +++++++++--------- .../popup-filter/popup-filter.component.ts | 110 ++++++----- .../initials-avatar.component.ts | 2 +- .../page-header/page-header.component.html | 9 +- .../red-ui/src/app/state/app-state.service.ts | 12 +- .../src/app/state/model/dossier.wrapper.ts | 6 +- libs/common-ui | 2 +- 14 files changed, 228 insertions(+), 240 deletions(-) diff --git a/apps/red-ui/src/app/models/file/file-status.wrapper.ts b/apps/red-ui/src/app/models/file/file-status.wrapper.ts index d60a94f17..2d589be23 100644 --- a/apps/red-ui/src/app/models/file/file-status.wrapper.ts +++ b/apps/red-ui/src/app/models/file/file-status.wrapper.ts @@ -15,7 +15,7 @@ export class FileStatusWrapper implements FileStatus { readonly analysisDuration = this.fileStatus.analysisDuration; readonly analysisRequired = this.fileStatus.analysisRequired && !this.fileStatus.excluded; readonly approvalDate = this.fileStatus.approvalDate; - currentReviewer = this.fileStatus.currentReviewer; + readonly currentReviewer = this.fileStatus.currentReviewer; readonly dictionaryVersion = this.fileStatus.dictionaryVersion; readonly dossierDictionaryVersion = this.fileStatus.dossierDictionaryVersion; readonly dossierId = this.fileStatus.dossierId; @@ -67,6 +67,7 @@ export class FileStatusWrapper implements FileStatus { readonly hintsOnly = this.hasHints && !this.hasRedactions; readonly hasNone = !this.hasRedactions && !this.hasHints && !this.hasSuggestions; + readonly isUnassigned = !this.currentReviewer readonly isError = this.status === FileStatus.StatusEnum.ERROR; readonly isProcessing = processingStatuses.includes(this.status); readonly isApproved = this.status === FileStatus.StatusEnum.APPROVED; @@ -78,10 +79,6 @@ export class FileStatusWrapper implements FileStatus { readonly isWorkable = !this.isProcessing && this.canBeOpened; readonly canBeOCRed = !this.excluded && !this.lastOCRTime && ['UNASSIGNED', 'UNDER_REVIEW', 'UNDER_APPROVAL'].includes(this.status); - get isUnassigned() { - return !this.currentReviewer; - } - private get _pages() { if (this.fileStatus.status === 'ERROR') { return -1; diff --git a/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html b/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html index 00c82dbca..969d3c308 100644 --- a/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html +++ b/apps/red-ui/src/app/modules/dossier/components/file-workload/file-workload.component.html @@ -7,11 +7,9 @@ translate="file-preview.tabs.annotations.select" > @@ -233,14 +231,6 @@ - - - - - {{ filter.key | humanize: false }} - - - ; - @Input() primaryFilters: NestedFilter[]; - @Input() secondaryFilters: NestedFilter[]; @Input() fileData: FileDataModel; @Input() hideSkipped: boolean; @Input() excludePages: boolean; @@ -267,10 +265,6 @@ export class FileWorkloadComponent { this.selectPage.emit(this._nextPageWithAnnotations()); } - _(filter): NestedFilter { - return filter as NestedFilter; - } - private _selectFirstAnnotationOnCurrentPageIfNecessary() { if ( (!this._firstSelectedAnnotation || this.activeViewerPage !== this._firstSelectedAnnotation.pageNumber) && diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.html index 7b0bde7e9..ea79b6823 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.html @@ -23,54 +23,54 @@
-
- {{ item.dossierName }} +
+ {{ dossier.dossierName }}
- {{ item.dossierTemplateName }} + {{ dossier.dossierTemplateName }}
- {{ item.dossier.filesLength }} + {{ dossier.filesLength }}
- {{ item.dossier.totalNumberOfPages }} + {{ dossier.totalNumberOfPages }}
- {{ item.dossier.memberCount }} + {{ dossier.memberCount }}
- {{ item.dossier.date | date: 'mediumDate' }} + {{ dossier.date | date: 'mediumDate' }}
-
+
- {{ item.dossier.dueDate | date: 'mediumDate' }} + {{ dossier.dueDate | date: 'mediumDate' }}
- +
- +
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts index 9c472511e..d203fb223 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts @@ -29,20 +29,13 @@ import { import { PermissionsService } from '@services/permissions.service'; import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; -interface ListItem { - readonly dossierName: string; - readonly routerLink: string; - readonly dossierTemplateName: string; - readonly dossier: DossierWrapper; -} - @Component({ templateUrl: './dossier-listing-screen.component.html', styleUrls: ['./dossier-listing-screen.component.scss'], providers: [...DefaultListingServices] }) export class DossierListingScreenComponent - extends ListingComponent + extends ListingComponent implements OnInit, AfterViewInit, OnDestroy, OnAttach, OnDetach { readonly itemSize = 85; @@ -58,7 +51,7 @@ export class DossierListingScreenComponent type: 'primary' } ]; - readonly tableColumnConfigs: readonly TableColumnConfig[] = [ + readonly tableColumnConfigs: readonly TableColumnConfig[] = [ { label: _('dossier-listing.table-col-names.name'), sortByKey: 'dossierName' @@ -102,7 +95,7 @@ export class DossierListingScreenComponent } private get _activeDossiersCount(): number { - return this.entitiesService.all.filter(p => p.dossier.status === Dossier.StatusEnum.ACTIVE).length; + return this.entitiesService.all.filter(p => p.status === Dossier.StatusEnum.ACTIVE).length; } private get _inactiveDossiersCount(): number { @@ -178,17 +171,8 @@ export class DossierListingScreenComponent } private _loadEntitiesFromState() { - const entities = this._appStateService.allDossiers.map(dossier => this._toListItem(dossier)); - this.entitiesService.setEntities(entities); - } - - private _toListItem(dossier: DossierWrapper): ListItem { - return { - dossierName: dossier.dossierName, - routerLink: '/main/dossiers/' + dossier.dossierId.toString(), - dossierTemplateName: this._getDossierTemplate(dossier.dossierTemplateId).name, - dossier - }; + console.log(this._appStateService.allDossiers); + this.entitiesService.setEntities(this._appStateService.allDossiers); } private _computeAllFilters() { @@ -199,18 +183,18 @@ export class DossierListingScreenComponent this.entitiesService.all?.forEach(entry => { // all people - entry.dossier.memberIds.forEach(f => allDistinctPeople.add(f)); + entry.memberIds.forEach(f => allDistinctPeople.add(f)); // Needs work - entry.dossier.files.forEach(file => { + entry.files.forEach(file => { allDistinctFileStatus.add(file.status); if (file.analysisRequired) allDistinctNeedsWork.add('analysis'); - if (entry.dossier.hintsOnly) allDistinctNeedsWork.add('hint'); - if (entry.dossier.hasRedactions) allDistinctNeedsWork.add('redaction'); - if (entry.dossier.hasSuggestions) allDistinctNeedsWork.add('suggestion'); - if (entry.dossier.hasNone) allDistinctNeedsWork.add('none'); + if (entry.hintsOnly) allDistinctNeedsWork.add('hint'); + if (entry.hasRedactions) allDistinctNeedsWork.add('redaction'); + if (entry.hasSuggestions) allDistinctNeedsWork.add('suggestion'); + if (entry.hasNone) allDistinctNeedsWork.add('none'); }); - allDistinctDossierTemplates.add(entry.dossier.dossierTemplateId); + allDistinctDossierTemplates.add(entry.dossierTemplateId); }); const statusFilters = [...allDistinctFileStatus].map(status => ({ diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html index 666eac854..af0569a66 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.html @@ -177,8 +177,6 @@ [excludePages]="excludePages" [fileData]="fileData" [hideSkipped]="hideSkipped" - [primaryFilters]="primaryFilters" - [secondaryFilters]="secondaryFilters" [selectedAnnotations]="selectedAnnotations" [viewer]="activeViewer" > @@ -194,3 +192,11 @@ [viewer]="activeViewer" > + + + + + + {{ filter.key | humanize: false }} + + diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts index c877dfceb..8ce1df12c 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts @@ -1,9 +1,9 @@ -import { ChangeDetectorRef, Component, HostListener, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { ChangeDetectorRef, Component, HostListener, NgZone, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; import { ActivatedRoute, ActivatedRouteSnapshot, NavigationExtras, Router } from '@angular/router'; import { AppStateService } from '@state/app-state.service'; import { Annotations, WebViewerInstance } from '@pdftron/webviewer'; import { PdfViewerComponent } from '../../components/pdf-viewer/pdf-viewer.component'; -import { AutoUnsubscribe, CircleButtonTypes, Debounce, NestedFilter, processFilters } from '@iqser/common-ui'; +import { AutoUnsubscribe, CircleButtonTypes, Debounce, FilterService, NestedFilter, processFilters } from '@iqser/common-ui'; import { MatDialogRef, MatDialogState } from '@angular/material/dialog'; import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry.wrapper'; import { AnnotationWrapper } from '@models/file/annotation.wrapper'; @@ -41,7 +41,8 @@ const ALL_HOTKEY_ARRAY = ['Escape', 'F', 'f']; @Component({ templateUrl: './file-preview-screen.component.html', - styleUrls: ['./file-preview-screen.component.scss'] + styleUrls: ['./file-preview-screen.component.scss'], + providers: [FilterService] }) export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnInit, OnDestroy, OnAttach, OnDetach { readonly circleButtonTypes = CircleButtonTypes; @@ -55,8 +56,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni fileData: FileDataModel; annotationData: AnnotationData; selectedAnnotations: AnnotationWrapper[]; - primaryFilters: NestedFilter[]; - secondaryFilters: NestedFilter[]; canPerformAnnotationActions: boolean; hideSkipped = false; displayPDFViewer = false; @@ -67,6 +66,11 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni private _lastPage: string; private _reloadFileOnReanalysis = false; @ViewChild('fileWorkloadComponent') private _workloadComponent: FileWorkloadComponent; + @ViewChild('annotationFilterTemplate', { + read: TemplateRef, + static: true + }) + private readonly _filterTemplate: TemplateRef; constructor( readonly appStateService: AppStateService, @@ -87,6 +91,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni private readonly _ngZone: NgZone, private readonly _fileManagementControllerService: FileManagementControllerService, private readonly _loadingService: LoadingService, + private readonly _filterService: FilterService, private readonly _translateService: TranslateService ) { super(); @@ -269,11 +274,16 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni this.userPreferenceService.areDevFeaturesEnabled ); const annotationFilters = this._annotationProcessingService.getAnnotationFilter(this.annotations); - this.primaryFilters = processFilters(this.primaryFilters, annotationFilters); - this.secondaryFilters = processFilters(this.secondaryFilters, AnnotationProcessingService.secondaryAnnotationFilters); - this._workloadComponent?.filtersChanged({ - primary: this.primaryFilters, - secondary: this.secondaryFilters + const primaryFilters = this._filterService.getGroup('primaryFilters')?.filters; + this._filterService.addFilterGroup({ + slug: 'primaryFilters', + filterTemplate: this._filterTemplate, + filters: processFilters(primaryFilters, annotationFilters) + }); + const secondaryFilters = this._filterService.getGroup('secondaryFilters')?.filters; + this._filterService.addFilterGroup({ + slug: 'secondaryFilters', + filters: processFilters(secondaryFilters, AnnotationProcessingService.secondaryAnnotationFilters) }); console.log('[REDACTION] Process time: ' + (new Date().getTime() - processStartTime) + 'ms'); console.log( @@ -625,8 +635,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni } private _handleDeltaAnnotationFilters(currentPageAnnotations: AnnotationWrapper[], newPageAnnotations: AnnotationWrapper[]) { - const hasAnyFilterSet = - this.primaryFilters.find(f => f.checked || f.indeterminate) || this.secondaryFilters.find(f => f.checked || f.indeterminate); + const primaryFilterGroup = this._filterService.getGroup('primaryFilters'); + const primaryFilters = primaryFilterGroup.filters; + const secondaryFilters = this._filterService.getGroup('secondaryFilters').filters; + const hasAnyFilterSet = [...primaryFilters, ...secondaryFilters].find(f => f.checked || f.indeterminate); if (!hasAnyFilterSet) { return; @@ -634,10 +646,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni const oldPageSpecificFilters = this._annotationProcessingService.getAnnotationFilter(currentPageAnnotations); const newPageSpecificFilters = this._annotationProcessingService.getAnnotationFilter(newPageAnnotations); - handleFilterDelta(oldPageSpecificFilters, newPageSpecificFilters, this.primaryFilters); - this._workloadComponent.filtersChanged({ - primary: this.primaryFilters, - secondary: this.secondaryFilters + handleFilterDelta(oldPageSpecificFilters, newPageSpecificFilters, primaryFilters); + this._filterService.addFilterGroup({ + ...primaryFilterGroup, + filters: primaryFilters }); } diff --git a/apps/red-ui/src/app/modules/shared/components/filters/popup-filter/popup-filter.component.html b/apps/red-ui/src/app/modules/shared/components/filters/popup-filter/popup-filter.component.html index d2225de78..335429b53 100644 --- a/apps/red-ui/src/app/modules/shared/components/filters/popup-filter/popup-filter.component.html +++ b/apps/red-ui/src/app/modules/shared/components/filters/popup-filter/popup-filter.component.html @@ -1,101 +1,109 @@ - + + - + - - -
-
-
-
-
+ + +
+
+
+
+
+
-
-
-
+
+ +
+
+
+
+ +
+ +
+
+ + + + + {{ filter?.label }} + + + +
+
+ + +
+
 
+ + + +
-
-
-
-
+
+
+ + + -
- +
- - - - {{ _(filter)?.label }} - - - -
-
- - -
-
 
- - - - -
- -
-
- - - - - -
-
-
+ diff --git a/apps/red-ui/src/app/modules/shared/components/filters/popup-filter/popup-filter.component.ts b/apps/red-ui/src/app/modules/shared/components/filters/popup-filter/popup-filter.component.ts index a4dfa9f6f..b3a79fbe1 100644 --- a/apps/red-ui/src/app/modules/shared/components/filters/popup-filter/popup-filter.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/filters/popup-filter/popup-filter.component.ts @@ -1,12 +1,14 @@ -import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, TemplateRef } from '@angular/core'; -import { NestedFilter } from '@iqser/common-ui'; -import { handleCheckedValue } from '@iqser/common-ui'; +import { ChangeDetectionStrategy, Component, Input, OnInit, TemplateRef } from '@angular/core'; +import { FilterGroup, FilterService, handleCheckedValue, NestedFilter } from '@iqser/common-ui'; import { MAT_CHECKBOX_DEFAULT_OPTIONS } from '@angular/material/checkbox'; +import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; +import { delay, distinctUntilChanged, map, shareReplay } from 'rxjs/operators'; @Component({ selector: 'redaction-popup-filter', templateUrl: './popup-filter.component.html', styleUrls: ['./popup-filter.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, providers: [ { provide: MAT_CHECKBOX_DEFAULT_OPTIONS, @@ -17,88 +19,84 @@ import { MAT_CHECKBOX_DEFAULT_OPTIONS } from '@angular/material/checkbox'; } ] }) -export class PopupFilterComponent implements OnChanges { - @Output() filtersChanged = new EventEmitter<{ - primary: NestedFilter[]; - secondary?: NestedFilter[]; - }>(); - @Input() filterTemplate: TemplateRef; +export class PopupFilterComponent implements OnInit { @Input() actionsTemplate: TemplateRef; - @Input() primaryFilters: NestedFilter[] = []; - @Input() secondaryFilters: NestedFilter[] = []; - @Input() filterLabel; - @Input() icon: string; + @Input() primaryFiltersSlug: string; + @Input() secondaryFiltersSlug: string; - atLeastOneFilterIsExpandable = false; - atLeastOneSecondaryFilterIsExpandable = false; + atLeastOneFilterIsExpandable$?: Observable; + atLeastOneSecondaryFilterIsExpandable$?: Observable; + hasActiveFilters$?: Observable; + expanded = new BehaviorSubject(null); + expanded$ = this.expanded.asObservable().pipe(delay(200)); - constructor(private readonly _changeDetectorRef: ChangeDetectorRef) {} + primaryFilterGroup$?: Observable; + secondaryFilterGroup$?: Observable; - get hasActiveFilters(): boolean { - return !!this._allFilters.find(f => f.checked || f.indeterminate); + constructor(readonly filterService: FilterService) {} + + ngOnInit() { + this.primaryFilterGroup$ = this.filterService.getGroup$(this.primaryFiltersSlug); + this.secondaryFilterGroup$ = this.filterService.getGroup$(this.secondaryFiltersSlug); + this.hasActiveFilters$ = combineLatest([this.primaryFilterGroup$, this.secondaryFilterGroup$]).pipe( + map(([primary, secondary]) => [...primary.filters, ...(secondary?.filters || [])]), + map(filters => filters.some(f => f.checked || f.indeterminate)), + distinctUntilChanged() + ); + this.atLeastOneFilterIsExpandable$ = this.primaryFilterGroup$.pipe( + map(group => group.filters.some(f => this.isExpandable(f))), + distinctUntilChanged(), + shareReplay() + ); + this.atLeastOneSecondaryFilterIsExpandable$ = this.secondaryFilterGroup$.pipe( + map(group => group?.filters.some(f => this.isExpandable(f))), + distinctUntilChanged(), + shareReplay() + ); } - private get _allFilters(): NestedFilter[] { - return [...(this.primaryFilters ?? []), ...(this.secondaryFilters ?? [])]; - } - - ngOnChanges(): void { - this.atLeastOneFilterIsExpandable = !!this.primaryFilters?.find(f => this.isExpandable(f)); - this.atLeastOneSecondaryFilterIsExpandable = !!this.secondaryFilters?.find(f => this.isExpandable(f)); - } - - filterCheckboxClicked($event: any, filter: NestedFilter, parent?: NestedFilter) { + filterCheckboxClicked($event: any, nestedFilter: NestedFilter, parent?: NestedFilter) { $event.stopPropagation(); - filter.checked = !filter.checked; + nestedFilter.checked = !nestedFilter.checked; if (parent) { handleCheckedValue(parent); } else { - if (filter.indeterminate) filter.checked = false; - filter.indeterminate = false; - filter.children?.forEach(f => (f.checked = filter.checked)); + if (nestedFilter.indeterminate) nestedFilter.checked = false; + nestedFilter.indeterminate = false; + nestedFilter.children?.forEach(f => (f.checked = nestedFilter.checked)); } - this.applyFilters(); + this.filterService.refresh(); } activatePrimaryFilters() { - this._setFilters(true); + this._setFilters(this.primaryFiltersSlug, true); } deactivateFilters() { - this._setFilters(); + this._setFilters(this.primaryFiltersSlug); + this._setFilters(this.secondaryFiltersSlug); } - applyFilters() { - this.filtersChanged.emit({ - primary: this.primaryFilters, - secondary: this.secondaryFilters - }); - this._changeDetectorRef.detectChanges(); - } - - toggleFilterExpanded($event: MouseEvent, filter: NestedFilter) { + toggleFilterExpanded($event: MouseEvent, nestedFilter: NestedFilter) { $event.stopPropagation(); - filter.expanded = !filter.expanded; + nestedFilter.expanded = !nestedFilter.expanded; + this.filterService.refresh(); } - isExpandable(filter: NestedFilter) { - return filter?.children?.length > 0; + isExpandable(nestedFilter: NestedFilter) { + return nestedFilter?.children?.length > 0; } - _(obj): NestedFilter { - return obj as NestedFilter; - } - - private _setFilters(onlyPrimaryFilters = false) { - const filters = onlyPrimaryFilters ? this.primaryFilters : this._allFilters; + private _setFilters(filterGroup: string, checked = false) { + const filters = this.filterService.getGroup(filterGroup).filters; filters.forEach(f => { - f.checked = onlyPrimaryFilters; + f.checked = checked; f.indeterminate = false; - f.children?.forEach(ff => (ff.checked = onlyPrimaryFilters)); + f.children?.forEach(ff => (ff.checked = checked)); }); - this.applyFilters(); + this.filterService.refresh(); } } diff --git a/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.ts b/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.ts index 340d76ce1..2cc569821 100644 --- a/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/initials-avatar/initials-avatar.component.ts @@ -38,7 +38,7 @@ export class InitialsAvatarComponent extends AutoUnsubscribe implements OnChange } get disabled(): boolean { - return this.user && !this.user?.isActive; + return this.user && !this.user.isActive; } private get _colorClass() { diff --git a/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.html b/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.html index e7bb6a1fa..4f620c312 100644 --- a/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.html +++ b/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.html @@ -7,14 +7,7 @@ - + diff --git a/apps/red-ui/src/app/state/app-state.service.ts b/apps/red-ui/src/app/state/app-state.service.ts index 1a75da0a2..08f4047e4 100644 --- a/apps/red-ui/src/app/state/app-state.service.ts +++ b/apps/red-ui/src/app/state/app-state.service.ts @@ -222,7 +222,9 @@ export class AppStateService { return; } - const mappedDossiers = dossiers.map(p => new DossierWrapper(p, this._getExistingFiles(p.dossierId))); + const mappedDossiers = dossiers.map( + p => new DossierWrapper(p, this.getDossierTemplateById(p.dossierTemplateId).name, this._getExistingFiles(p.dossierId)) + ); const fileData = await this._statusControllerService.getFileStatusForDossiers(mappedDossiers.map(p => p.dossierId)).toPromise(); for (const dossierId of Object.keys(fileData)) { @@ -348,9 +350,13 @@ export class AppStateService { let foundDossier = this.allDossiers.find(p => p.dossierId === updatedDossier.dossierId); if (foundDossier) { this._appState.dossiers.splice(this._appState.dossiers.indexOf(foundDossier), 1); - foundDossier = new DossierWrapper(updatedDossier, foundDossier.files); + foundDossier = new DossierWrapper( + updatedDossier, + this.getDossierTemplateById(updatedDossier.dossierTemplateId).name, + foundDossier.files + ); } else { - foundDossier = new DossierWrapper(updatedDossier, []); + foundDossier = new DossierWrapper(updatedDossier, this.getDossierTemplateById(updatedDossier.dossierTemplateId).name, []); } this._appState.dossiers.push(foundDossier); diff --git a/apps/red-ui/src/app/state/model/dossier.wrapper.ts b/apps/red-ui/src/app/state/model/dossier.wrapper.ts index a08101e28..55b92a9ea 100644 --- a/apps/red-ui/src/app/state/model/dossier.wrapper.ts +++ b/apps/red-ui/src/app/state/model/dossier.wrapper.ts @@ -38,7 +38,7 @@ export class DossierWrapper implements Dossier { allFilesApproved?: boolean; type?: Dictionary; - constructor(private readonly _dossier: Dossier, private _files: FileStatusWrapper[] = []) { + constructor(private readonly _dossier: Dossier, readonly dossierTemplateName, private _files: FileStatusWrapper[] = []) { this._recomputeFileStatus(); } @@ -55,8 +55,8 @@ export class DossierWrapper implements Dossier { return !!this._files.find(f => f.status === status); } - hasMember(key: string) { - return this._dossier.memberIds.indexOf(key) >= 0; + hasMember(memberId: string) { + return this._dossier.memberIds.indexOf(memberId) >= 0; } addedDateMatches(key: string) { diff --git a/libs/common-ui b/libs/common-ui index 0bb0e4454..908256aac 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit 0bb0e4454f3015d1c81ccd23415c8135c89eeeff +Subproject commit 908256aacab10e189b04b7471cd7bf813723d76a From 4d840effd82db2a29a6e94a62fac90acc12699e5 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Mon, 16 Aug 2021 21:22:07 +0300 Subject: [PATCH 2/3] update lib eslint --- .eslintrc.json | 11 +- .../page-header/page-header.component.ts | 2 +- package.json | 2 + yarn.lock | 101 +++++++++++++++++- 4 files changed, 106 insertions(+), 10 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index 32ca8c20e..de604b636 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,7 +4,7 @@ "plugins": ["@nrwl/nx"], "overrides": [ { - "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "files": ["*.ts"], "rules": { "@nrwl/nx/enforce-module-boundaries": [ "error", @@ -36,15 +36,10 @@ } }, { - "files": ["*.ts", "*.tsx"], + "files": ["*.ts"], "extends": ["plugin:@nrwl/nx/typescript"], "rules": {} }, - { - "files": ["*.js", "*.jsx"], - "extends": ["plugin:@nrwl/nx/javascript"], - "rules": {} - }, { "files": ["*.ts"], "rules": { @@ -79,7 +74,7 @@ "@typescript-eslint/no-explicit-any": "off", "@typescript-eslint/ban-types": "off", "@typescript-eslint/explicit-member-accessibility": [ - "warn", + "error", { "accessibility": "no-public" } diff --git a/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.ts b/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.ts index 02f0e04d2..c6fb9a83d 100644 --- a/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/page-header/page-header.component.ts @@ -11,7 +11,7 @@ import { SearchPosition, SearchPositions } from '@shared/components/page-header/ templateUrl: './page-header.component.html', styleUrls: ['./page-header.component.scss'] }) -export class PageHeaderComponent { +export class PageHeaderComponent { readonly searchPositions = SearchPositions; @Input() pageLabel: string; diff --git a/package.json b/package.json index f5df6104f..972c44858 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,9 @@ "cypress-localstorage-commands": "^1.4.5", "dotenv": "10.0.0", "eslint": "7.28.0", + "eslint-config-airbnb-typescript": "^12.3.1", "eslint-config-prettier": "8.3.0", + "eslint-plugin-prettier": "^3.4.0", "eslint-plugin-import": "2.23.4", "google-translate-api-browser": "^1.1.71", "husky": "4.3.8", diff --git a/yarn.lock b/yarn.lock index fde77360b..1c3f5b4fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3333,6 +3333,16 @@ "@typescript-eslint/typescript-estree" "4.26.1" debug "^4.3.1" +"@typescript-eslint/parser@^4.4.1": + version "4.29.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.29.1.tgz#17dfbb45c9032ffa0fe15881d20fbc2a4bdeb02d" + integrity sha512-3fL5iN20hzX3Q4OkG7QEPFjZV2qsVGiDhEwwh+EkmE/w7oteiOvUNzmpu5eSwGJX/anCryONltJ3WDmAzAoCMg== + dependencies: + "@typescript-eslint/scope-manager" "4.29.1" + "@typescript-eslint/types" "4.29.1" + "@typescript-eslint/typescript-estree" "4.29.1" + debug "^4.3.1" + "@typescript-eslint/scope-manager@4.22.1": version "4.22.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.22.1.tgz#5bb357f94f9cd8b94e6be43dd637eb73b8f355b4" @@ -3357,6 +3367,14 @@ "@typescript-eslint/types" "4.26.1" "@typescript-eslint/visitor-keys" "4.26.1" +"@typescript-eslint/scope-manager@4.29.1": + version "4.29.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.29.1.tgz#f25da25bc6512812efa2ce5ebd36619d68e61358" + integrity sha512-Hzv/uZOa9zrD/W5mftZa54Jd5Fed3tL6b4HeaOpwVSabJK8CJ+2MkDasnX/XK4rqP5ZTWngK1ZDeCi6EnxPQ7A== + dependencies: + "@typescript-eslint/types" "4.29.1" + "@typescript-eslint/visitor-keys" "4.29.1" + "@typescript-eslint/types@4.22.1": version "4.22.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.22.1.tgz#bf99c6cec0b4a23d53a61894816927f2adad856a" @@ -3372,6 +3390,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.26.1.tgz#9e7c523f73c34b04a765e4167ca5650436ef1d38" integrity sha512-STyMPxR3cS+LaNvS8yK15rb8Y0iL0tFXq0uyl6gY45glyI7w0CsyqyEXl/Fa0JlQy+pVANeK3sbwPneCbWE7yg== +"@typescript-eslint/types@4.29.1": + version "4.29.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.29.1.tgz#94cce6cf7cc83451df03339cda99d326be2feaf5" + integrity sha512-Jj2yu78IRfw4nlaLtKjVaGaxh/6FhofmQ/j8v3NXmAiKafbIqtAPnKYrf0sbGjKdj0hS316J8WhnGnErbJ4RCA== + "@typescript-eslint/typescript-estree@4.22.1": version "4.22.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.1.tgz#dca379eead8cdfd4edc04805e83af6d148c164f9" @@ -3411,6 +3434,19 @@ semver "^7.3.5" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@4.29.1": + version "4.29.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.1.tgz#7b32a25ff8e51f2671ccc6b26cdbee3b1e6c5e7f" + integrity sha512-lIkkrR9E4lwZkzPiRDNq0xdC3f2iVCUjw/7WPJ4S2Sl6C3nRWkeE1YXCQ0+KsiaQRbpY16jNaokdWnm9aUIsfw== + dependencies: + "@typescript-eslint/types" "4.29.1" + "@typescript-eslint/visitor-keys" "4.29.1" + debug "^4.3.1" + globby "^11.0.3" + is-glob "^4.0.1" + semver "^7.3.5" + tsutils "^3.21.0" + "@typescript-eslint/visitor-keys@4.22.1": version "4.22.1" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.1.tgz#6045ae25a11662c671f90b3a403d682dfca0b7a6" @@ -3435,6 +3471,14 @@ "@typescript-eslint/types" "4.26.1" eslint-visitor-keys "^2.0.0" +"@typescript-eslint/visitor-keys@4.29.1": + version "4.29.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.1.tgz#0615be8b55721f5e854f3ee99f1a714f2d093e5d" + integrity sha512-zLqtjMoXvgdZY/PG6gqA73V8BjqPs4af1v2kiiETBObp+uC6gRYnJLmJHxC0QyUrrHDLJPIWNYxoBV3wbcRlag== + dependencies: + "@typescript-eslint/types" "4.29.1" + eslint-visitor-keys "^2.0.0" + "@webassemblyjs/ast@1.11.0": version "1.11.0" resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.0.tgz#a5aa679efdc9e51707a4207139da57920555961f" @@ -5234,7 +5278,7 @@ concat-stream@^1.5.0, concat-stream@^1.6.2: readable-stream "^2.2.2" typedarray "^0.0.6" -confusing-browser-globals@^1.0.9: +confusing-browser-globals@^1.0.10, confusing-browser-globals@^1.0.9: version "1.0.10" resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz#30d1e7f3d1b882b25ec4933d1d1adac353d20a59" integrity sha512-gNld/3lySHwuhaVluJUKLePYirM3QNCKzVxqAdhJII9/WXKVX5PURzMVJspS1jTslSqjeuG4KMVTSouit5YPHA== @@ -6572,6 +6616,33 @@ escodegen@^2.0.0: optionalDependencies: source-map "~0.6.1" +eslint-config-airbnb-base@^14.2.0, eslint-config-airbnb-base@^14.2.1: + version "14.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz#8a2eb38455dc5a312550193b319cdaeef042cd1e" + integrity sha512-GOrQyDtVEc1Xy20U7vsB2yAoB4nBlfH5HZJeatRXHleO+OS5Ot+MWij4Dpltw4/DyIkqUfqz1epfhVR5XWWQPA== + dependencies: + confusing-browser-globals "^1.0.10" + object.assign "^4.1.2" + object.entries "^1.1.2" + +eslint-config-airbnb-typescript@^12.3.1: + version "12.3.1" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-12.3.1.tgz#83ab40d76402c208eb08516260d1d6fac8f8acbc" + integrity sha512-ql/Pe6/hppYuRp4m3iPaHJqkBB7dgeEmGPQ6X0UNmrQOfTF+dXw29/ZjU2kQ6RDoLxaxOA+Xqv07Vbef6oVTWw== + dependencies: + "@typescript-eslint/parser" "^4.4.1" + eslint-config-airbnb "^18.2.0" + eslint-config-airbnb-base "^14.2.0" + +eslint-config-airbnb@^18.2.0: + version "18.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-18.2.1.tgz#b7fe2b42f9f8173e825b73c8014b592e449c98d9" + integrity sha512-glZNDEZ36VdlZWoxn/bUR1r/sdFKPd1mHPbqUtkctgNG4yT2DLLtJ3D+yCV+jzZCc2V1nBVkmdknOJBZ5Hc0fg== + dependencies: + eslint-config-airbnb-base "^14.2.1" + object.assign "^4.1.2" + object.entries "^1.1.2" + eslint-config-prettier@8.3.0: version "8.3.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz#f7471b20b6fe8a9a9254cc684454202886a2dd7a" @@ -6614,6 +6685,13 @@ eslint-plugin-import@2.23.4: resolve "^1.20.0" tsconfig-paths "^3.9.0" +eslint-plugin-prettier@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz#cdbad3bf1dbd2b177e9825737fe63b476a08f0c7" + integrity sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw== + dependencies: + prettier-linter-helpers "^1.0.0" + eslint-scope@5.1.1, eslint-scope@^5.0.0, eslint-scope@^5.1.0, eslint-scope@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" @@ -6991,6 +7069,11 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== +fast-diff@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" + integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w== + fast-glob@^3.1.1: version "3.2.4" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" @@ -10536,6 +10619,15 @@ object.assign@^4.1.2: has-symbols "^1.0.1" object-keys "^1.1.1" +object.entries@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.4.tgz#43ccf9a50bc5fd5b649d45ab1a579f24e088cafd" + integrity sha512-h4LWKWE+wKQGhtMjZEBud7uLGhqyLwj8fpHOarZhD2uY3C9cRtk57VQ89ke3moByLXMedqs3XCHzyb4AmA2DjA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.2" + object.pick@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" @@ -11734,6 +11826,13 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + prettier@2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.1.tgz#76903c3f8c4449bc9ac597acefa24dc5ad4cbea6" From 7b375e481ab383d9847aed00d12490d6f2e9b891 Mon Sep 17 00:00:00 2001 From: Dan Percic Date: Tue, 17 Aug 2021 16:39:25 +0300 Subject: [PATCH 3/3] fix dossier's status bar --- .../dossier-listing-actions.component.html | 2 +- .../dossier-listing-actions.component.ts | 21 +++++++------------ .../dossier-listing-screen.component.ts | 17 ++++++--------- .../popup-filter/popup-filter.component.ts | 20 +++++++++--------- 4 files changed, 25 insertions(+), 35 deletions(-) diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.html b/apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.html index caff3a7ed..f0d4832c2 100644 --- a/apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.html +++ b/apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.html @@ -1,4 +1,4 @@ - +
(); - statusBarConfig: readonly StatusBarConfig[]; - constructor( readonly permissionsService: PermissionsService, readonly appStateService: AppStateService, @@ -30,26 +27,24 @@ export class DossierListingActionsComponent implements OnInit { private readonly _userService: UserService ) {} - ngOnInit() { - this.statusBarConfig = this._getStatusConfig(this.dossier.files); - } - - openEditDossierDialog($event: MouseEvent, dossierWrapper: DossierWrapper) { + openEditDossierDialog($event: MouseEvent, dossierWrapper: DossierWrapper): void { this._dialogService.openDialog('editDossier', $event, { dossierWrapper, afterSave: () => this.actionPerformed.emit() }); } - reanalyseDossier($event: MouseEvent, dossier: DossierWrapper) { + reanalyseDossier($event: MouseEvent, dossier: DossierWrapper): void { $event.stopPropagation(); this.appStateService.reanalyzeDossier(dossier).then(() => { this.appStateService.loadAllDossiers().then(() => this.actionPerformed.emit()); }); } - private _getStatusConfig(files: readonly FileStatusWrapper[]) { - const obj = files.reduce((acc, file) => { + get statusConfig(): readonly StatusBarConfig[] { + if (!this.dossier) return []; + + const obj = this.dossier.files.reduce((acc, file) => { const status = file.status; if (!acc[status]) { acc[status] = 1; diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts index d203fb223..68718440f 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts @@ -1,5 +1,5 @@ import { AfterViewInit, Component, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core'; -import { Dossier, DossierTemplateModel } from '@redaction/red-ui-http'; +import { Dossier } from '@redaction/red-ui-http'; import { AppStateService } from '@state/app-state.service'; import { UserService } from '@services/user.service'; import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; @@ -45,7 +45,7 @@ export class DossierListingScreenComponent readonly buttonConfigs: readonly ButtonConfig[] = [ { label: _('dossier-listing.add-new'), - action: () => this.openAddDossierDialog(), + action: (): void => this.openAddDossierDialog(), hide: !this.currentUser.isManager, icon: 'red:plus', type: 'primary' @@ -74,7 +74,7 @@ export class DossierListingScreenComponent private _lastScrolledIndex: number; @ViewChild('needsWorkTemplate', { read: TemplateRef, static: true }) - private readonly _needsWorkTemplate: TemplateRef; + private readonly _needsWorkTemplate: TemplateRef; @ViewChild(CdkVirtualScrollViewport) private readonly _scrollViewport: CdkVirtualScrollViewport; @@ -116,11 +116,11 @@ export class DossierListingScreenComponent }); } - ngAfterViewInit() { + ngAfterViewInit(): void { this.addSubscription = this._scrollViewport.scrolledIndexChange.pipe(tap(index => (this._lastScrolledIndex = index))).subscribe(); } - ngOnAttach() { + ngOnAttach(): void { this._appStateService.reset(); this._loadEntitiesFromState(); this.ngOnInit(); @@ -132,10 +132,6 @@ export class DossierListingScreenComponent this.ngOnDestroy(); } - private _getDossierTemplate(dossierTemplateId: string): DossierTemplateModel { - return this._appStateService.getDossierTemplateById(dossierTemplateId); - } - openAddDossierDialog(): void { this._dialogService.openDialog('addDossier', null, null, async addResponse => { await this._router.navigate([`/main/dossiers/${addResponse.dossier.dossierId}`]); @@ -148,7 +144,7 @@ export class DossierListingScreenComponent }); } - calculateData() { + calculateData(): void { this._computeAllFilters(); this.dossiersChartData = [ @@ -171,7 +167,6 @@ export class DossierListingScreenComponent } private _loadEntitiesFromState() { - console.log(this._appStateService.allDossiers); this.entitiesService.setEntities(this._appStateService.allDossiers); } diff --git a/apps/red-ui/src/app/modules/shared/components/filters/popup-filter/popup-filter.component.ts b/apps/red-ui/src/app/modules/shared/components/filters/popup-filter/popup-filter.component.ts index b3a79fbe1..c40c56257 100644 --- a/apps/red-ui/src/app/modules/shared/components/filters/popup-filter/popup-filter.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/filters/popup-filter/popup-filter.component.ts @@ -20,22 +20,22 @@ import { delay, distinctUntilChanged, map, shareReplay } from 'rxjs/operators'; ] }) export class PopupFilterComponent implements OnInit { - @Input() actionsTemplate: TemplateRef; + @Input() actionsTemplate: TemplateRef; @Input() primaryFiltersSlug: string; @Input() secondaryFiltersSlug: string; atLeastOneFilterIsExpandable$?: Observable; atLeastOneSecondaryFilterIsExpandable$?: Observable; hasActiveFilters$?: Observable; - expanded = new BehaviorSubject(null); - expanded$ = this.expanded.asObservable().pipe(delay(200)); + readonly expanded = new BehaviorSubject(null); + readonly expanded$ = this.expanded.asObservable().pipe(delay(200)); primaryFilterGroup$?: Observable; secondaryFilterGroup$?: Observable; constructor(readonly filterService: FilterService) {} - ngOnInit() { + ngOnInit(): void { this.primaryFilterGroup$ = this.filterService.getGroup$(this.primaryFiltersSlug); this.secondaryFilterGroup$ = this.filterService.getGroup$(this.secondaryFiltersSlug); this.hasActiveFilters$ = combineLatest([this.primaryFilterGroup$, this.secondaryFilterGroup$]).pipe( @@ -55,7 +55,7 @@ export class PopupFilterComponent implements OnInit { ); } - filterCheckboxClicked($event: any, nestedFilter: NestedFilter, parent?: NestedFilter) { + filterCheckboxClicked($event: MouseEvent, nestedFilter: NestedFilter, parent?: NestedFilter): void { $event.stopPropagation(); nestedFilter.checked = !nestedFilter.checked; @@ -71,22 +71,22 @@ export class PopupFilterComponent implements OnInit { this.filterService.refresh(); } - activatePrimaryFilters() { + activatePrimaryFilters(): void { this._setFilters(this.primaryFiltersSlug, true); } - deactivateFilters() { + deactivateFilters(): void { this._setFilters(this.primaryFiltersSlug); - this._setFilters(this.secondaryFiltersSlug); + if (this.secondaryFiltersSlug) this._setFilters(this.secondaryFiltersSlug); } - toggleFilterExpanded($event: MouseEvent, nestedFilter: NestedFilter) { + toggleFilterExpanded($event: MouseEvent, nestedFilter: NestedFilter): void { $event.stopPropagation(); nestedFilter.expanded = !nestedFilter.expanded; this.filterService.refresh(); } - isExpandable(nestedFilter: NestedFilter) { + isExpandable(nestedFilter: NestedFilter): boolean { return nestedFilter?.children?.length > 0; }