Pull request #200: Quick filters

Merge in RED/ui from RED-1548 to master

* commit 'da5360bacfec21a8b43527e78f693a3123927458':
  RED-1549: Dossier overview quick filters
  Dossier listing quick filters
This commit is contained in:
Timo Bejan 2021-06-07 14:04:35 +02:00
commit d3ebe3d9c4
32 changed files with 320 additions and 113 deletions

View File

@ -21,9 +21,9 @@ export class ConfirmDeleteUsersDialogComponent {
private readonly _appStateService: AppStateService, private readonly _appStateService: AppStateService,
public dialogRef: MatDialogRef<ConfirmDeleteUsersDialogComponent> public dialogRef: MatDialogRef<ConfirmDeleteUsersDialogComponent>
) { ) {
this.dossiersCount = this._appStateService.allDossiers.filter(pw => { this.dossiersCount = this._appStateService.allDossiers.filter(dw => {
for (const user of this.users) { for (const user of this.users) {
if (pw.memberIds.indexOf(user.userId) !== -1) { if (dw.memberIds.indexOf(user.userId) !== -1) {
return true; return true;
} }
} }

View File

@ -7,8 +7,8 @@ import { TranslateService } from '@ngx-translate/core';
import { saveAs } from 'file-saver'; import { saveAs } from 'file-saver';
import { ComponentHasChanges } from '@guards/can-deactivate.guard'; import { ComponentHasChanges } from '@guards/can-deactivate.guard';
import { AdminDialogService } from '../../services/admin-dialog.service'; import { AdminDialogService } from '../../services/admin-dialog.service';
import { DictionaryManagerComponent } from '../../../shared/components/dictionary-manager/dictionary-manager.component'; import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
import { DictionarySaveService } from '../../../shared/services/dictionary-save.service'; import { DictionarySaveService } from '@shared/services/dictionary-save.service';
import { TypeValueWrapper } from '../../../../models/file/type-value.wrapper'; import { TypeValueWrapper } from '../../../../models/file/type-value.wrapper';
@Component({ @Component({

View File

@ -17,6 +17,7 @@ export enum AppConfigKey {
ADMIN_CONTACT_URL = 'ADMIN_CONTACT_URL', ADMIN_CONTACT_URL = 'ADMIN_CONTACT_URL',
AUTO_READ_TIME = 'AUTO_READ_TIME', AUTO_READ_TIME = 'AUTO_READ_TIME',
MAX_FILE_SIZE_MB = 'MAX_FILE_SIZE_MB', MAX_FILE_SIZE_MB = 'MAX_FILE_SIZE_MB',
RECENT_PERIOD_IN_HOURS = 'RECENT_PERIOD_IN_HOURS',
DELETE_RETENTION_HOURS = 'DELETE_RETENTION_HOURS', DELETE_RETENTION_HOURS = 'DELETE_RETENTION_HOURS',
APP_NAME = 'APP_NAME', APP_NAME = 'APP_NAME',

View File

@ -3,11 +3,11 @@ import { AppStateService } from '@state/app-state.service';
import { groupBy } from '@utils/functions'; import { groupBy } from '@utils/functions';
import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component';
import { Router } from '@angular/router'; import { Router } from '@angular/router';
import { FilterModel } from '@shared/components/filter/model/filter.model';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { TranslateChartService } from '@services/translate-chart.service'; import { TranslateChartService } from '@services/translate-chart.service';
import { StatusSorter } from '@utils/sorters/status-sorter'; import { StatusSorter } from '@utils/sorters/status-sorter';
import { DossiersDialogService } from '../../services/dossiers-dialog.service'; import { DossiersDialogService } from '../../services/dossiers-dialog.service';
import { FilterModel } from '@shared/components/filters/popup-filter/model/filter.model';
@Component({ @Component({
selector: 'redaction-dossier-details', selector: 'redaction-dossier-details',

View File

@ -36,8 +36,8 @@ export class DossierListingActionsComponent {
}); });
} }
getDossierStatusConfig(pw: DossierWrapper) { getDossierStatusConfig(dw: DossierWrapper) {
const obj = pw.files.reduce((acc, file) => { const obj = dw.files.reduce((acc, file) => {
const status = file.status; const status = file.status;
if (!acc[status]) { if (!acc[status]) {
acc[status] = 1; acc[status] = 1;

View File

@ -1,7 +1,7 @@
import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Component, EventEmitter, Input, Output } from '@angular/core';
import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component';
import { AppStateService } from '@state/app-state.service'; import { AppStateService } from '@state/app-state.service';
import { FilterModel } from '@shared/components/filter/model/filter.model'; import { FilterModel } from '@shared/components/filters/popup-filter/model/filter.model';
@Component({ @Component({
selector: 'redaction-dossier-listing-details', selector: 'redaction-dossier-listing-details',

View File

@ -6,14 +6,14 @@
class="all-caps-label primary pointer" class="all-caps-label primary pointer"
translate="file-preview.tabs.annotations.select" translate="file-preview.tabs.annotations.select"
></div> ></div>
<redaction-filter <redaction-popup-filter
(filtersChanged)="filtersChanged($event)" (filtersChanged)="filtersChanged($event)"
[actionsTemplate]="annotationFilterActionTemplate" [actionsTemplate]="annotationFilterActionTemplate"
[chevron]="true" [chevron]="true"
[filterTemplate]="annotationFilterTemplate" [filterTemplate]="annotationFilterTemplate"
[primaryFilters]="primaryFilters" [primaryFilters]="primaryFilters"
[secondaryFilters]="secondaryFilters" [secondaryFilters]="secondaryFilters"
></redaction-filter> ></redaction-popup-filter>
</div> </div>
</div> </div>
<div class="right-content"> <div class="right-content">

View File

@ -9,13 +9,13 @@ import {
TemplateRef, TemplateRef,
ViewChild ViewChild
} from '@angular/core'; } from '@angular/core';
import { FilterModel } from '@shared/components/filter/model/filter.model';
import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { AnnotationProcessingService } from '../../services/annotation-processing.service'; import { AnnotationProcessingService } from '../../services/annotation-processing.service';
import { MatDialogRef, MatDialogState } from '@angular/material/dialog'; import { MatDialogRef, MatDialogState } from '@angular/material/dialog';
import scrollIntoView from 'scroll-into-view-if-needed'; import scrollIntoView from 'scroll-into-view-if-needed';
import { debounce } from '@utils/debounce'; import { debounce } from '@utils/debounce';
import { FileDataModel } from '@models/file/file-data.model'; import { FileDataModel } from '@models/file/file-data.model';
import { FilterModel } from '@shared/components/filters/popup-filter/model/filter.model';
const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape']; const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape'];
const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown']; const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];

View File

@ -92,11 +92,11 @@ export class TeamMembersManagerComponent implements OnInit {
const ownerId = this.selectedOwnerId; const ownerId = this.selectedOwnerId;
const memberIds = this.selectedMembersList; const memberIds = this.selectedMembersList;
const approverIds = this.selectedApproversList; const approverIds = this.selectedApproversList;
const pw = Object.assign({}, this.dossierWrapper); const dw = Object.assign({}, this.dossierWrapper);
pw.dossier.memberIds = memberIds; dw.dossier.memberIds = memberIds;
pw.dossier.approverIds = approverIds; dw.dossier.approverIds = approverIds;
pw.dossier.ownerId = ownerId; dw.dossier.ownerId = ownerId;
result = await this._appStateService.addOrUpdateDossier(pw.dossier); result = await this._appStateService.addOrUpdateDossier(dw.dossier);
this.save.emit(result); this.save.emit(result);
} catch (error) { } catch (error) {
this._notificationService.showToastNotification( this._notificationService.showToastNotification(

View File

@ -1,6 +1,6 @@
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { FilterModel } from '@shared/components/filter/model/filter.model';
import { AppStateService } from '@state/app-state.service'; import { AppStateService } from '@state/app-state.service';
import { FilterModel } from '@shared/components/filters/popup-filter/model/filter.model';
@Component({ @Component({
selector: 'redaction-type-filter', selector: 'redaction-type-filter',

View File

@ -1,8 +1,8 @@
import { Component, Inject, ViewChild } from '@angular/core'; import { Component, Inject, ViewChild } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { DossierWrapper } from '../../../../state/model/dossier.wrapper'; import { DossierWrapper } from '../../../../state/model/dossier.wrapper';
import { DictionaryManagerComponent } from '../../../shared/components/dictionary-manager/dictionary-manager.component'; import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
import { DictionarySaveService } from '../../../shared/services/dictionary-save.service'; import { DictionarySaveService } from '@shared/services/dictionary-save.service';
import { AppStateService } from '../../../../state/app-state.service'; import { AppStateService } from '../../../../state/app-state.service';
import { PermissionsService } from '../../../../services/permissions.service'; import { PermissionsService } from '../../../../services/permissions.service';

View File

@ -2,9 +2,9 @@ import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core
import { AppStateService } from '../../../../../state/app-state.service'; import { AppStateService } from '../../../../../state/app-state.service';
import { DossierWrapper } from '../../../../../state/model/dossier.wrapper'; import { DossierWrapper } from '../../../../../state/model/dossier.wrapper';
import { EditDossierSectionInterface } from '../edit-dossier-section.interface'; import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { DictionarySaveService } from '../../../../shared/services/dictionary-save.service';
import { DictionaryManagerComponent } from '../../../../shared/components/dictionary-manager/dictionary-manager.component';
import { PermissionsService } from '../../../../../services/permissions.service'; import { PermissionsService } from '../../../../../services/permissions.service';
import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
import { DictionarySaveService } from '@shared/services/dictionary-save.service';
@Component({ @Component({
selector: 'redaction-edit-dossier-dictionary', selector: 'redaction-edit-dossier-dictionary',

View File

@ -2,36 +2,36 @@
<div class="page-header"> <div class="page-header">
<div class="filters"> <div class="filters">
<div translate="filters.filter-by"></div> <div translate="filters.filter-by"></div>
<redaction-filter <redaction-popup-filter
#statusFilter #statusFilter
(filtersChanged)="filtersChanged()" (filtersChanged)="filtersChanged()"
[filterLabel]="'filters.status'" [filterLabel]="'filters.status'"
[icon]="'red:status'" [icon]="'red:status'"
[primaryFilters]="statusFilters" [primaryFilters]="statusFilters"
></redaction-filter> ></redaction-popup-filter>
<redaction-filter <redaction-popup-filter
#peopleFilter #peopleFilter
(filtersChanged)="filtersChanged()" (filtersChanged)="filtersChanged()"
[filterLabel]="'filters.people'" [filterLabel]="'filters.people'"
[icon]="'red:user'" [icon]="'red:user'"
[primaryFilters]="peopleFilters" [primaryFilters]="peopleFilters"
></redaction-filter> ></redaction-popup-filter>
<redaction-filter <redaction-popup-filter
#needsWorkFilter #needsWorkFilter
(filtersChanged)="filtersChanged()" (filtersChanged)="filtersChanged()"
[filterLabel]="'filters.needs-work'" [filterLabel]="'filters.needs-work'"
[filterTemplate]="needsWorkTemplate" [filterTemplate]="needsWorkTemplate"
[icon]="'red:needs-work'" [icon]="'red:needs-work'"
[primaryFilters]="needsWorkFilters" [primaryFilters]="needsWorkFilters"
></redaction-filter> ></redaction-popup-filter>
<redaction-filter <redaction-popup-filter
#dossierTemplateFilter #dossierTemplateFilter
(filtersChanged)="filtersChanged()" (filtersChanged)="filtersChanged()"
*ngIf="dossierTemplateFilters.length > 1" *ngIf="dossierTemplateFilters.length > 1"
[filterLabel]="'filters.dossier-templates'" [filterLabel]="'filters.dossier-templates'"
[icon]="'red:template'" [icon]="'red:template'"
[primaryFilters]="dossierTemplateFilters" [primaryFilters]="dossierTemplateFilters"
></redaction-filter> ></redaction-popup-filter>
<redaction-search-input <redaction-search-input
[form]="searchForm" [form]="searchForm"
[placeholder]="'dossier-listing.search'" [placeholder]="'dossier-listing.search'"
@ -63,6 +63,11 @@
| translate: { length: displayedEntities.length || 0 } | translate: { length: displayedEntities.length || 0 }
}} }}
</span> </span>
<redaction-quick-filters
(filtersChanged)="filtersChanged()"
[filters]="quickFilters"
></redaction-quick-filters>
</div> </div>
<div class="table-header" redactionSyncWidth="table-item"> <div class="table-header" redactionSyncWidth="table-item">
@ -107,63 +112,63 @@
<cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar> <cdk-virtual-scroll-viewport [itemSize]="itemSize" redactionHasScrollbar>
<div <div
*cdkVirtualFor=" *cdkVirtualFor="
let pw of displayedEntities let dw of displayedEntities
| sortBy: sortingOption.order:sortingOption.column | sortBy: sortingOption.order:sortingOption.column
" "
[class.pointer]="canOpenDossier(pw)" [class.pointer]="canOpenDossier(dw)"
[routerLink]="[ [routerLink]="[
canOpenDossier(pw) ? '/main/dossiers/' + pw.dossier.dossierId : [] canOpenDossier(dw) ? '/main/dossiers/' + dw.dossier.dossierId : []
]" ]"
class="table-item" class="table-item"
> >
<div class="filename"> <div class="filename">
<div class="table-item-title heading"> <div class="table-item-title heading">
{{ pw.dossier.dossierName }} {{ dw.dossier.dossierName }}
</div> </div>
<div class="small-label stats-subtitle"> <div class="small-label stats-subtitle">
<div> <div>
<mat-icon svgIcon="red:template"></mat-icon> <mat-icon svgIcon="red:template"></mat-icon>
{{ getDossierTemplate(pw).name }} {{ getDossierTemplate(dw).name }}
</div> </div>
</div> </div>
<div class="small-label stats-subtitle"> <div class="small-label stats-subtitle">
<div> <div>
<mat-icon svgIcon="red:document"></mat-icon> <mat-icon svgIcon="red:document"></mat-icon>
{{ documentCount(pw) }} {{ documentCount(dw) }}
</div> </div>
<div> <div>
<mat-icon svgIcon="red:pages"></mat-icon> <mat-icon svgIcon="red:pages"></mat-icon>
{{ pw.totalNumberOfPages }} {{ dw.totalNumberOfPages }}
</div> </div>
<div> <div>
<mat-icon svgIcon="red:user"></mat-icon> <mat-icon svgIcon="red:user"></mat-icon>
{{ userCount(pw) }} {{ userCount(dw) }}
</div> </div>
<div> <div>
<mat-icon svgIcon="red:calendar"></mat-icon> <mat-icon svgIcon="red:calendar"></mat-icon>
{{ pw.dossier.date | date: 'mediumDate' }} {{ dw.dossier.date | date: 'mediumDate' }}
</div> </div>
<div *ngIf="pw.dossier.dueDate"> <div *ngIf="dw.dossier.dueDate">
<mat-icon svgIcon="red:lightning"></mat-icon> <mat-icon svgIcon="red:lightning"></mat-icon>
{{ pw.dossier.dueDate | date: 'mediumDate' }} {{ dw.dossier.dueDate | date: 'mediumDate' }}
</div> </div>
</div> </div>
</div> </div>
<div> <div>
<redaction-needs-work-badge <redaction-needs-work-badge
[needsWorkInput]="pw" [needsWorkInput]="dw"
></redaction-needs-work-badge> ></redaction-needs-work-badge>
</div> </div>
<div class="user-column"> <div class="user-column">
<redaction-initials-avatar <redaction-initials-avatar
[userId]="pw.dossier.ownerId" [userId]="dw.dossier.ownerId"
[withName]="true" [withName]="true"
></redaction-initials-avatar> ></redaction-initials-avatar>
</div> </div>
<div class="status-container"> <div class="status-container">
<redaction-dossier-listing-actions <redaction-dossier-listing-actions
(actionPerformed)="actionPerformed()" (actionPerformed)="actionPerformed()"
[dossier]="pw" [dossier]="dw"
></redaction-dossier-listing-actions> ></redaction-dossier-listing-actions>
</div> </div>
<div class="scrollbar-placeholder"></div> <div class="scrollbar-placeholder"></div>

View File

@ -4,14 +4,6 @@ import { AppStateService } from '@state/app-state.service';
import { UserService } from '@services/user.service'; import { UserService } from '@services/user.service';
import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component';
import { groupBy } from '@utils/functions'; import { groupBy } from '@utils/functions';
import { FilterModel } from '@shared/components/filter/model/filter.model';
import {
annotationFilterChecker,
dossierMemberChecker,
dossierStatusChecker,
dossierTemplateChecker,
processFilters
} from '@shared/components/filter/utils/filter-utils';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { DossierWrapper } from '@state/model/dossier.wrapper'; import { DossierWrapper } from '@state/model/dossier.wrapper';
@ -21,11 +13,20 @@ import { TranslateChartService } from '@services/translate-chart.service';
import { RedactionFilterSorter } from '@utils/sorters/redaction-filter-sorter'; import { RedactionFilterSorter } from '@utils/sorters/redaction-filter-sorter';
import { StatusSorter } from '@utils/sorters/status-sorter'; import { StatusSorter } from '@utils/sorters/status-sorter';
import { NavigationEnd, NavigationStart, Router } from '@angular/router'; import { NavigationEnd, NavigationStart, Router } from '@angular/router';
import { FilterComponent } from '@shared/components/filter/filter.component';
import { DossiersDialogService } from '../../services/dossiers-dialog.service'; import { DossiersDialogService } from '../../services/dossiers-dialog.service';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { BaseListingComponent } from '@shared/base/base-listing.component'; import { BaseListingComponent } from '@shared/base/base-listing.component';
import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy'; import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy';
import { FilterModel } from '@shared/components/filters/popup-filter/model/filter.model';
import { PopupFilterComponent } from '@shared/components/filters/popup-filter/popup-filter.component';
import {
annotationFilterChecker,
dossierMemberChecker,
dossierStatusChecker,
dossierTemplateChecker,
processFilters
} from '@shared/components/filters/popup-filter/utils/filter-utils';
import { QuickFiltersComponent } from '../../../shared/components/filters/quick-filters/quick-filters.component';
@Component({ @Component({
selector: 'redaction-dossier-listing-screen', selector: 'redaction-dossier-listing-screen',
@ -47,17 +48,19 @@ export class DossierListingScreenComponent
} = { } = {
statusFilters: [] statusFilters: []
}; };
quickFilters: FilterModel[];
readonly itemSize = 85; readonly itemSize = 85;
@ViewChild(CdkVirtualScrollViewport) scrollBar: CdkVirtualScrollViewport; @ViewChild(CdkVirtualScrollViewport) scrollBar: CdkVirtualScrollViewport;
protected readonly _searchKey = 'name'; protected readonly _searchKey = 'name';
protected readonly _sortKey = 'dossier-listing'; protected readonly _sortKey = 'dossier-listing';
@ViewChild(QuickFiltersComponent) protected _quickFiltersComponent: QuickFiltersComponent;
private _dossierAutoUpdateTimer: Subscription; private _dossierAutoUpdateTimer: Subscription;
private _lastScrollPosition: number; private _lastScrollPosition: number;
@ViewChild('statusFilter') private _statusFilterComponent: FilterComponent; @ViewChild('statusFilter') private _statusFilterComponent: PopupFilterComponent;
@ViewChild('peopleFilter') private _peopleFilterComponent: FilterComponent; @ViewChild('peopleFilter') private _peopleFilterComponent: PopupFilterComponent;
@ViewChild('needsWorkFilter') private _needsWorkFilterComponent: FilterComponent; @ViewChild('needsWorkFilter') private _needsWorkFilterComponent: PopupFilterComponent;
@ViewChild('dossierTemplateFilter') private _dossierTemplateFilterComponent: FilterComponent; @ViewChild('dossierTemplateFilter')
private _dossierTemplateFilterComponent: PopupFilterComponent;
private _routerEventsScrollPositionSub: Subscription; private _routerEventsScrollPositionSub: Subscription;
private _fileChangedSub: Subscription; private _fileChangedSub: Subscription;
@ -92,12 +95,13 @@ export class DossierListingScreenComponent
return this.allEntities.length - this.activeDossiersCount; return this.allEntities.length - this.activeDossiersCount;
} }
protected get _filterComponents(): FilterComponent[] { protected get _filterComponents(): (PopupFilterComponent | QuickFiltersComponent)[] {
return [ return [
this._statusFilterComponent, this._statusFilterComponent,
this._peopleFilterComponent, this._peopleFilterComponent,
this._needsWorkFilterComponent, this._needsWorkFilterComponent,
this._dossierTemplateFilterComponent this._dossierTemplateFilterComponent,
this._quickFiltersComponent
]; ];
} }
@ -116,7 +120,12 @@ export class DossierListingScreenComponent
matchAll: true, matchAll: true,
checkerArgs: this.permissionsService checkerArgs: this.permissionsService
}, },
{ values: this.dossierTemplateFilters, checker: dossierTemplateChecker } { values: this.dossierTemplateFilters, checker: dossierTemplateChecker },
{
values: this.quickFilters,
checker: (dw: DossierWrapper) =>
this.quickFilters.reduce((acc, f) => acc || (f.checked && f.checker(dw)), false)
}
]; ];
} }
@ -174,12 +183,12 @@ export class DossierListingScreenComponent
return dossier.numberOfMembers; return dossier.numberOfMembers;
} }
canOpenDossier(pw: DossierWrapper): boolean { canOpenDossier(dw: DossierWrapper): boolean {
return !!pw; return !!dw;
} }
getDossierTemplate(pw: DossierWrapper): DossierTemplateModel { getDossierTemplate(dw: DossierWrapper): DossierTemplateModel {
return this._appStateService.getDossierTemplateById(pw.dossier.dossierTemplateId); return this._appStateService.getDossierTemplateById(dw.dossier.dossierTemplateId);
} }
openAddDossierDialog(): void { openAddDossierDialog(): void {
@ -303,5 +312,28 @@ export class DossierListingScreenComponent
this.dossierTemplateFilters, this.dossierTemplateFilters,
dossierTemplateFilters dossierTemplateFilters
); );
this.quickFilters = [
{
key: this.user.id,
label: 'dossier-listing.quick-filters.my-dossiers',
checker: (dw: DossierWrapper) => dw.ownerId === this.user.id
},
{
key: this.user.id,
label: 'dossier-listing.quick-filters.to-approve',
checker: (dw: DossierWrapper) => dw.approverIds.includes(this.user.id)
},
{
key: this.user.id,
label: 'dossier-listing.quick-filters.to-review',
checker: (dw: DossierWrapper) => dw.memberIds.includes(this.user.id)
},
{
key: this.user.id,
label: 'dossier-listing.quick-filters.other',
checker: (dw: DossierWrapper) => !dw.memberIds.includes(this.user.id)
}
];
} }
} }

View File

@ -2,28 +2,28 @@
<div class="page-header"> <div class="page-header">
<div class="filters"> <div class="filters">
<div translate="filters.filter-by"></div> <div translate="filters.filter-by"></div>
<redaction-filter <redaction-popup-filter
#statusFilter #statusFilter
(filtersChanged)="filtersChanged()" (filtersChanged)="filtersChanged()"
[filterLabel]="'filters.status'" [filterLabel]="'filters.status'"
[icon]="'red:status'" [icon]="'red:status'"
[primaryFilters]="statusFilters" [primaryFilters]="statusFilters"
></redaction-filter> ></redaction-popup-filter>
<redaction-filter <redaction-popup-filter
#peopleFilter #peopleFilter
(filtersChanged)="filtersChanged()" (filtersChanged)="filtersChanged()"
[filterLabel]="'filters.assigned-people'" [filterLabel]="'filters.assigned-people'"
[icon]="'red:user'" [icon]="'red:user'"
[primaryFilters]="peopleFilters" [primaryFilters]="peopleFilters"
></redaction-filter> ></redaction-popup-filter>
<redaction-filter <redaction-popup-filter
#needsWorkFilter #needsWorkFilter
(filtersChanged)="filtersChanged()" (filtersChanged)="filtersChanged()"
[filterLabel]="'filters.needs-work'" [filterLabel]="'filters.needs-work'"
[filterTemplate]="needsWorkTemplate" [filterTemplate]="needsWorkTemplate"
[icon]="'red:needs-work'" [icon]="'red:needs-work'"
[primaryFilters]="needsWorkFilters" [primaryFilters]="needsWorkFilters"
></redaction-filter> ></redaction-popup-filter>
<redaction-search-input <redaction-search-input
[form]="searchForm" [form]="searchForm"
@ -106,6 +106,11 @@
(reload)="bulkActionPerformed()" (reload)="bulkActionPerformed()"
[selectedFileIds]="selectedEntitiesIds" [selectedFileIds]="selectedEntitiesIds"
></redaction-dossier-overview-bulk-actions> ></redaction-dossier-overview-bulk-actions>
<redaction-quick-filters
(filtersChanged)="filtersChanged()"
[filters]="quickFilters"
></redaction-quick-filters>
</div> </div>
<div <div

View File

@ -15,15 +15,9 @@ import { FileUploadModel } from '@upload-download/model/file-upload.model';
import { FileUploadService } from '@upload-download/services/file-upload.service'; import { FileUploadService } from '@upload-download/services/file-upload.service';
import { StatusOverlayService } from '@upload-download/services/status-overlay.service'; import { StatusOverlayService } from '@upload-download/services/status-overlay.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { FilterModel } from '@shared/components/filter/model/filter.model';
import * as moment from 'moment'; import * as moment from 'moment';
import { DossierDetailsComponent } from '../../components/dossier-details/dossier-details.component'; import { DossierDetailsComponent } from '../../components/dossier-details/dossier-details.component';
import { FileStatusWrapper } from '@models/file/file-status.wrapper'; import { FileStatusWrapper } from '@models/file/file-status.wrapper';
import {
annotationFilterChecker,
keyChecker,
processFilters
} from '@shared/components/filter/utils/filter-utils';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { UserService } from '@services/user.service'; import { UserService } from '@services/user.service';
import { FileStatus, UserPreferenceControllerService } from '@redaction/red-ui-http'; import { FileStatus, UserPreferenceControllerService } from '@redaction/red-ui-http';
@ -32,12 +26,20 @@ import { filter, tap } from 'rxjs/operators';
import { RedactionFilterSorter } from '@utils/sorters/redaction-filter-sorter'; import { RedactionFilterSorter } from '@utils/sorters/redaction-filter-sorter';
import { StatusSorter } from '@utils/sorters/status-sorter'; import { StatusSorter } from '@utils/sorters/status-sorter';
import { convertFiles, handleFileDrop } from '@utils/file-drop-utils'; import { convertFiles, handleFileDrop } from '@utils/file-drop-utils';
import { FilterComponent } from '@shared/components/filter/filter.component';
import { DossiersDialogService } from '../../services/dossiers-dialog.service'; import { DossiersDialogService } from '../../services/dossiers-dialog.service';
import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling';
import { BaseListingComponent } from '@shared/base/base-listing.component'; import { BaseListingComponent } from '@shared/base/base-listing.component';
import { DossierWrapper } from '@state/model/dossier.wrapper'; import { DossierWrapper } from '@state/model/dossier.wrapper';
import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy'; import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy';
import {
annotationFilterChecker,
keyChecker,
processFilters
} from '@shared/components/filters/popup-filter/utils/filter-utils';
import { FilterModel } from '@shared/components/filters/popup-filter/model/filter.model';
import { PopupFilterComponent } from '@shared/components/filters/popup-filter/popup-filter.component';
import { QuickFiltersComponent } from '../../../shared/components/filters/quick-filters/quick-filters.component';
import { AppConfigService } from '../../../app-config/app-config.service';
@Component({ @Component({
selector: 'redaction-dossier-overview-screen', selector: 'redaction-dossier-overview-screen',
@ -57,7 +59,9 @@ export class DossierOverviewScreenComponent
statusFilters: FilterModel[]; statusFilters: FilterModel[];
} = { needsWorkFilters: [], statusFilters: [] }; } = { needsWorkFilters: [], statusFilters: [] };
readonly itemSize = 80; readonly itemSize = 80;
quickFilters: FilterModel[];
@ViewChild(CdkVirtualScrollViewport) scrollBar: CdkVirtualScrollViewport; @ViewChild(CdkVirtualScrollViewport) scrollBar: CdkVirtualScrollViewport;
@ViewChild(QuickFiltersComponent) protected _quickFiltersComponent: QuickFiltersComponent;
protected readonly _searchKey = 'searchField'; protected readonly _searchKey = 'searchField';
protected readonly _selectionKey = 'fileId'; protected readonly _selectionKey = 'fileId';
protected readonly _sortKey = 'dossier-overview'; protected readonly _sortKey = 'dossier-overview';
@ -68,9 +72,9 @@ export class DossierOverviewScreenComponent
private _fileChangedSub: Subscription; private _fileChangedSub: Subscription;
private _lastScrollPosition: number; private _lastScrollPosition: number;
private _lastOpenedFileId = ''; private _lastOpenedFileId = '';
@ViewChild('statusFilter') private _statusFilterComponent: FilterComponent; @ViewChild('statusFilter') private _statusFilterComponent: PopupFilterComponent;
@ViewChild('peopleFilter') private _peopleFilterComponent: FilterComponent; @ViewChild('peopleFilter') private _peopleFilterComponent: PopupFilterComponent;
@ViewChild('needsWorkFilter') private _needsWorkFilterComponent: FilterComponent; @ViewChild('needsWorkFilter') private _needsWorkFilterComponent: PopupFilterComponent;
@ViewChild('fileInput') private _fileInput: ElementRef; @ViewChild('fileInput') private _fileInput: ElementRef;
constructor( constructor(
@ -85,6 +89,7 @@ export class DossierOverviewScreenComponent
private readonly _fileDropOverlayService: FileDropOverlayService, private readonly _fileDropOverlayService: FileDropOverlayService,
private readonly _appStateService: AppStateService, private readonly _appStateService: AppStateService,
private readonly _userPreferenceControllerService: UserPreferenceControllerService, private readonly _userPreferenceControllerService: UserPreferenceControllerService,
private readonly _appConfigService: AppConfigService,
protected readonly _injector: Injector protected readonly _injector: Injector
) { ) {
super(_injector); super(_injector);
@ -95,11 +100,24 @@ export class DossierOverviewScreenComponent
return this._appStateService.activeDossier; return this._appStateService.activeDossier;
} }
protected get _filterComponents(): FilterComponent[] { get user() {
return this._userService.user;
}
get checkedRequiredFilters() {
return this.quickFilters.filter(f => f.required && f.checked);
}
get checkedNotRequiredFilters() {
return this.quickFilters.filter(f => !f.required && f.checked);
}
protected get _filterComponents(): (PopupFilterComponent | QuickFiltersComponent)[] {
return [ return [
this._statusFilterComponent, this._statusFilterComponent,
this._peopleFilterComponent, this._peopleFilterComponent,
this._needsWorkFilterComponent this._needsWorkFilterComponent,
this._quickFiltersComponent
]; ];
} }
@ -117,6 +135,16 @@ export class DossierOverviewScreenComponent
checker: annotationFilterChecker, checker: annotationFilterChecker,
matchAll: true, matchAll: true,
checkerArgs: this.permissionsService checkerArgs: this.permissionsService
},
{
values: this.quickFilters,
checker: (file: FileStatusWrapper) =>
this.checkedRequiredFilters.reduce((acc, f) => acc && f.checker(file), true) &&
(this.checkedNotRequiredFilters.length === 0 ||
this.checkedNotRequiredFilters.reduce(
(acc, f) => acc || f.checker(file),
false
))
} }
]; ];
} }
@ -286,6 +314,11 @@ export class DossierOverviewScreenComponent
this.collapsedDetails = !this.collapsedDetails; this.collapsedDetails = !this.collapsedDetails;
} }
recentlyModifiedChecker = (file: FileStatusWrapper) =>
moment(file.lastUpdated)
.add(this._appConfigService.getConfig('RECENT_PERIOD_IN_HOURS'), 'hours')
.isAfter(moment());
protected _preFilter() { protected _preFilter() {
this.detailsContainerFilters = { this.detailsContainerFilters = {
needsWorkFilters: this.needsWorkFilters.map(f => ({ ...f })), needsWorkFilters: this.needsWorkFilters.map(f => ({ ...f })),
@ -377,5 +410,41 @@ export class DossierOverviewScreenComponent
(a, b) => RedactionFilterSorter[a.key] - RedactionFilterSorter[b.key] (a, b) => RedactionFilterSorter[a.key] - RedactionFilterSorter[b.key]
); );
this.needsWorkFilters = processFilters(this.needsWorkFilters, needsWorkFilters); this.needsWorkFilters = processFilters(this.needsWorkFilters, needsWorkFilters);
this._computeQuickFilters();
}
private _computeQuickFilters() {
if (this.allEntities.filter(this.recentlyModifiedChecker).length > 0) {
this.quickFilters = [
{
key: this.user.id,
label: 'dossier-overview.quick-filters.recent',
required: true,
checker: this.recentlyModifiedChecker
}
];
} else {
this.quickFilters = [];
}
this.quickFilters = [
...this.quickFilters,
{
key: this.user.id,
label: 'dossier-overview.quick-filters.assigned-to-me',
checker: (file: FileStatusWrapper) => file.currentReviewer === this.user.id
},
{
key: this.user.id,
label: 'dossier-overview.quick-filters.unassigned',
checker: (file: FileStatusWrapper) => !file.currentReviewer
},
{
key: this.user.id,
label: 'dossier-overview.quick-filters.assigned-to-others',
checker: (file: FileStatusWrapper) => file.currentReviewer !== this.user.id
}
];
} }
} }

View File

@ -20,13 +20,11 @@ import { AnnotationData, FileDataModel } from '@models/file/file-data.model';
import { FileActionService } from '../../services/file-action.service'; import { FileActionService } from '../../services/file-action.service';
import { AnnotationDrawService } from '../../services/annotation-draw.service'; import { AnnotationDrawService } from '../../services/annotation-draw.service';
import { AnnotationProcessingService } from '../../services/annotation-processing.service'; import { AnnotationProcessingService } from '../../services/annotation-processing.service';
import { FilterModel } from '@shared/components/filter/model/filter.model';
import { tap } from 'rxjs/operators'; import { tap } from 'rxjs/operators';
import { NotificationService } from '@services/notification.service'; import { NotificationService } from '@services/notification.service';
import { FileStatusWrapper } from '@models/file/file-status.wrapper'; import { FileStatusWrapper } from '@models/file/file-status.wrapper';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '@services/permissions.service';
import { Subscription, timer } from 'rxjs'; import { Subscription, timer } from 'rxjs';
import { handleFilterDelta, processFilters } from '@shared/components/filter/utils/filter-utils';
import { UserPreferenceService } from '@services/user-preference.service'; import { UserPreferenceService } from '@services/user-preference.service';
import { UserService } from '@services/user.service'; import { UserService } from '@services/user.service';
import { FormBuilder, FormGroup } from '@angular/forms'; import { FormBuilder, FormGroup } from '@angular/forms';
@ -41,6 +39,11 @@ import { ViewMode } from '@models/file/view-mode';
import { FileWorkloadComponent } from '../../components/file-workload/file-workload.component'; import { FileWorkloadComponent } from '../../components/file-workload/file-workload.component';
import { DossiersDialogService } from '../../services/dossiers-dialog.service'; import { DossiersDialogService } from '../../services/dossiers-dialog.service';
import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy'; import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy';
import { FilterModel } from '@shared/components/filters/popup-filter/model/filter.model';
import {
handleFilterDelta,
processFilters
} from '@shared/components/filters/popup-filter/utils/filter-utils';
const ALL_HOTKEY_ARRAY = ['Escape', 'F', 'f']; const ALL_HOTKEY_ARRAY = ['Escape', 'F', 'f'];

View File

@ -1,8 +1,8 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { FilterModel } from '@shared/components/filter/model/filter.model';
import { handleCheckedValue } from '@shared/components/filter/utils/filter-utils';
import { SuperTypeSorter } from '@utils/sorters/super-type-sorter'; import { SuperTypeSorter } from '@utils/sorters/super-type-sorter';
import { FilterModel } from '@shared/components/filters/popup-filter/model/filter.model';
import { handleCheckedValue } from '@shared/components/filters/popup-filter/utils/filter-utils';
@Injectable() @Injectable()
export class AnnotationProcessingService { export class AnnotationProcessingService {

View File

@ -1,10 +1,11 @@
import { ChangeDetectorRef, Component, Injector } from '@angular/core'; import { ChangeDetectorRef, Component, Injector } from '@angular/core';
import { FilterModel } from '../components/filter/model/filter.model';
import { getFilteredEntities } from '../components/filter/utils/filter-utils';
import { FilterComponent } from '../components/filter/filter.component';
import { FormBuilder, FormGroup } from '@angular/forms'; import { FormBuilder, FormGroup } from '@angular/forms';
import { debounce } from '@utils/debounce'; import { debounce } from '@utils/debounce';
import { ScreenName, SortingOption, SortingService } from '@services/sorting.service'; import { ScreenName, SortingOption, SortingService } from '@services/sorting.service';
import { FilterModel } from '../components/filters/popup-filter/model/filter.model';
import { PopupFilterComponent } from '../components/filters/popup-filter/popup-filter.component';
import { getFilteredEntities } from '../components/filters/popup-filter/utils/filter-utils';
import { QuickFiltersComponent } from '../components/filters/quick-filters/quick-filters.component';
// Functionalities: Filter, search, select, sort // Functionalities: Filter, search, select, sort
@ -68,7 +69,7 @@ export abstract class BaseListingComponent<T = any> {
return []; return [];
} }
protected get _filterComponents(): FilterComponent[] { protected get _filterComponents(): (PopupFilterComponent | QuickFiltersComponent)[] {
return []; return [];
} }

View File

@ -9,4 +9,5 @@ export interface FilterModel {
matches?: number; matches?: number;
filters?: FilterModel[]; filters?: FilterModel[];
checker?: (obj?) => boolean; checker?: (obj?) => boolean;
required?: boolean;
} }

View File

@ -1,4 +1,4 @@
@import '../../../../../assets/styles/red-variables'; @import '../../../../../../assets/styles/red-variables';
.filter-menu-options, .filter-menu-options,
.filter-menu-header { .filter-menu-header {

View File

@ -12,9 +12,9 @@ import { handleCheckedValue } from './utils/filter-utils';
import { MAT_CHECKBOX_DEFAULT_OPTIONS } from '@angular/material/checkbox'; import { MAT_CHECKBOX_DEFAULT_OPTIONS } from '@angular/material/checkbox';
@Component({ @Component({
selector: 'redaction-filter', selector: 'redaction-popup-filter',
templateUrl: './filter.component.html', templateUrl: './popup-filter.component.html',
styleUrls: ['./filter.component.scss'], styleUrls: ['./popup-filter.component.scss'],
providers: [ providers: [
{ {
provide: MAT_CHECKBOX_DEFAULT_OPTIONS, provide: MAT_CHECKBOX_DEFAULT_OPTIONS,
@ -25,7 +25,7 @@ import { MAT_CHECKBOX_DEFAULT_OPTIONS } from '@angular/material/checkbox';
} }
] ]
}) })
export class FilterComponent implements OnChanges { export class PopupFilterComponent implements OnChanges {
@Output() filtersChanged = new EventEmitter<{ @Output() filtersChanged = new EventEmitter<{
primary: FilterModel[]; primary: FilterModel[];
secondary?: FilterModel[]; secondary?: FilterModel[];

View File

@ -1,7 +1,7 @@
import { FilterModel } from '../model/filter.model'; import { FilterModel } from '../model/filter.model';
import { FileStatusWrapper } from '@models/file/file-status.wrapper'; import { FileStatusWrapper } from '../../../../../../models/file/file-status.wrapper';
import { DossierWrapper } from '@state/model/dossier.wrapper'; import { DossierWrapper } from '../../../../../../state/model/dossier.wrapper';
import { PermissionsService } from '@services/permissions.service'; import { PermissionsService } from '../../../../../../services/permissions.service';
export function processFilters(oldFilters: FilterModel[], newFilters: FilterModel[]) { export function processFilters(oldFilters: FilterModel[], newFilters: FilterModel[]) {
copySettings(oldFilters, newFilters); copySettings(oldFilters, newFilters);
@ -157,20 +157,23 @@ export const annotationFilterChecker = (
} }
}; };
export const dossierStatusChecker = (pw: DossierWrapper, filter: FilterModel) => export const dossierStatusChecker = (dw: DossierWrapper, filter: FilterModel) =>
pw.hasStatus(filter.key); dw.hasStatus(filter.key);
export const dossierMemberChecker = (pw: DossierWrapper, filter: FilterModel) => export const dossierMemberChecker = (dw: DossierWrapper, filter: FilterModel) =>
pw.hasMember(filter.key); dw.hasMember(filter.key);
export const dossierTemplateChecker = (pw: DossierWrapper, filter: FilterModel) => export const dossierTemplateChecker = (dw: DossierWrapper, filter: FilterModel) =>
pw.dossierTemplateId === filter.key; dw.dossierTemplateId === filter.key;
export const dueDateChecker = (pw: DossierWrapper, filter: FilterModel) => export const dueDateChecker = (dw: DossierWrapper, filter: FilterModel) =>
pw.dueDateMatches(filter.key); dw.dueDateMatches(filter.key);
export const addedDateChecker = (pw: DossierWrapper, filter: FilterModel) => export const addedDateChecker = (dw: DossierWrapper, filter: FilterModel) =>
pw.addedDateMatches(filter.key); dw.addedDateMatches(filter.key);
export const dossierApproverChecker = (dw: DossierWrapper, filter: FilterModel) =>
dw.approverIds.includes(filter.key);
export function getFilteredEntities( export function getFilteredEntities(
entities: any[], entities: any[],

View File

@ -0,0 +1,8 @@
<div
(click)="toggle(filter)"
*ngFor="let filter of filters"
[class.active]="filter.checked"
class="quick-filter"
>
{{ filter.label | translate }}
</div>

View File

@ -0,0 +1,34 @@
@import '../../../../../../assets/styles/red-variables';
:host {
display: flex;
flex: 1;
justify-content: flex-end;
}
.quick-filter {
box-sizing: border-box;
border: 1px solid $grey-5;
border-radius: 17px;
background-color: $grey-6;
padding: 0 14px;
height: 34px;
display: flex;
align-items: center;
cursor: pointer;
transition: background-color 0.2s;
&:hover {
background-color: $white;
}
&.active {
background-color: $white;
font-weight: 600;
border: none;
}
&:not(:last-child) {
margin-right: 8px;
}
}

View File

@ -0,0 +1,29 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { FilterModel } from '../popup-filter/model/filter.model';
@Component({
selector: 'redaction-quick-filters',
templateUrl: './quick-filters.component.html',
styleUrls: ['./quick-filters.component.scss']
})
export class QuickFiltersComponent {
@Output() filtersChanged = new EventEmitter<FilterModel[]>();
@Input() filters: FilterModel[];
constructor() {}
get hasActiveFilters(): boolean {
return this.filters.filter(f => f.checked).length > 0;
}
deactivateAllFilters() {
for (const filter of this.filters) {
filter.checked = false;
}
}
toggle(filter: FilterModel) {
filter.checked = !filter.checked;
this.filtersChanged.emit(this.filters);
}
}

View File

@ -1,6 +1,6 @@
import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core'; import { Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
import { Color } from '@utils/types'; import { Color } from '@utils/types';
import { FilterModel } from '../filter/model/filter.model'; import { FilterModel } from '@shared/components/filters/popup-filter/model/filter.model';
export class DoughnutChartConfig { export class DoughnutChartConfig {
value: number; value: number;

View File

@ -24,7 +24,6 @@ import { HasScrollbarDirective } from './directives/has-scrollbar.directive';
import { DictionaryAnnotationIconComponent } from './components/dictionary-annotation-icon/dictionary-annotation-icon.component'; import { DictionaryAnnotationIconComponent } from './components/dictionary-annotation-icon/dictionary-annotation-icon.component';
import { HiddenActionComponent } from './components/hidden-action/hidden-action.component'; import { HiddenActionComponent } from './components/hidden-action/hidden-action.component';
import { ConfirmationDialogComponent } from './dialogs/confirmation-dialog/confirmation-dialog.component'; import { ConfirmationDialogComponent } from './dialogs/confirmation-dialog/confirmation-dialog.component';
import { FilterComponent } from './components/filter/filter.component';
import { EmptyStateComponent } from './components/empty-state/empty-state.component'; import { EmptyStateComponent } from './components/empty-state/empty-state.component';
import { SortByPipe } from './components/sort-pipe/sort-by.pipe'; import { SortByPipe } from './components/sort-pipe/sort-by.pipe';
import { RoundCheckboxComponent } from './components/checkbox/round-checkbox.component'; import { RoundCheckboxComponent } from './components/checkbox/round-checkbox.component';
@ -35,6 +34,8 @@ import { NavigateLastDossiersScreenDirective } from './directives/navigate-last-
import { DictionaryManagerComponent } from './components/dictionary-manager/dictionary-manager.component'; import { DictionaryManagerComponent } from './components/dictionary-manager/dictionary-manager.component';
import { SideNavComponent } from '@shared/components/side-nav/side-nav.component'; import { SideNavComponent } from '@shared/components/side-nav/side-nav.component';
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor'; import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
import { QuickFiltersComponent } from './components/filters/quick-filters/quick-filters.component';
import { PopupFilterComponent } from '@shared/components/filters/popup-filter/popup-filter.component';
const buttons = [ const buttons = [
ChevronButtonComponent, ChevronButtonComponent,
@ -55,7 +56,7 @@ const components = [
StatusBarComponent, StatusBarComponent,
DictionaryAnnotationIconComponent, DictionaryAnnotationIconComponent,
HiddenActionComponent, HiddenActionComponent,
FilterComponent, PopupFilterComponent,
ConfirmationDialogComponent, ConfirmationDialogComponent,
EmptyStateComponent, EmptyStateComponent,
SortByPipe, SortByPipe,
@ -84,9 +85,9 @@ const modules = [
]; ];
@NgModule({ @NgModule({
declarations: [...components, ...utils], declarations: [...components, ...utils, QuickFiltersComponent],
imports: [CommonModule, ...modules, MonacoEditorModule], imports: [CommonModule, ...modules, MonacoEditorModule],
exports: [...modules, ...components, ...utils], exports: [...modules, ...components, ...utils, QuickFiltersComponent],
providers: [ providers: [
{ provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] }, { provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE] },
{ {

View File

@ -10,6 +10,7 @@
"LICENSE_START": "01-01-2021", "LICENSE_START": "01-01-2021",
"LICENSE_END": "31-12-2021", "LICENSE_END": "31-12-2021",
"LICENSE_PAGE_COUNT": 1000000, "LICENSE_PAGE_COUNT": 1000000,
"RECENT_PERIOD_IN_HOURS": 24,
"MAX_FILE_SIZE_MB": 100, "MAX_FILE_SIZE_MB": 100,
"DELETE_RETENTION_HOURS": 96 "DELETE_RETENTION_HOURS": 96
} }

View File

@ -137,6 +137,12 @@
}, },
"no-match": { "no-match": {
"title": "No dossiers match your current filters." "title": "No dossiers match your current filters."
},
"quick-filters": {
"my-dossiers": "My Dossiers",
"to-approve": "To Approve",
"to-review": "To Review",
"other": "Other"
} }
}, },
"add-dossier-dialog": { "add-dossier-dialog": {
@ -327,6 +333,12 @@
"reanalyse-dossier": { "reanalyse-dossier": {
"success": "Files scheduled for reanalysis.", "success": "Files scheduled for reanalysis.",
"error": "Failed to schedule files for reanalysis. Please try again." "error": "Failed to schedule files for reanalysis. Please try again."
},
"quick-filters": {
"recent": "Recent",
"assigned-to-me": "Assigned to me",
"unassigned": "Unassigned",
"assigned-to-others": "Assigned to others"
} }
}, },
"file-preview": { "file-preview": {

View File

@ -10,6 +10,7 @@ ADMIN_CONTACT_URL="${ADMIN_CONTACT_URL:-}"
AUTO_READ_TIME="${AUTO_READ_TIME:-1.5}" AUTO_READ_TIME="${AUTO_READ_TIME:-1.5}"
MAX_FILE_SIZE_MB="${MAX_FILE_SIZE_MB:-50}" MAX_FILE_SIZE_MB="${MAX_FILE_SIZE_MB:-50}"
DELETE_RETENTION_HOURS="${DELETE_RETENTION_HOURS:-96}" DELETE_RETENTION_HOURS="${DELETE_RETENTION_HOURS:-96}"
RECENT_PERIOD_IN_HOURS="${RECENT_PERIOD_IN_HOURS:-24}"
BACKEND_APP_VERSION="${BACKEND_APP_VERSION:-4.7.0}" BACKEND_APP_VERSION="${BACKEND_APP_VERSION:-4.7.0}"
@ -35,6 +36,7 @@ echo '{
"APP_NAME":"'"$APP_NAME"'", "APP_NAME":"'"$APP_NAME"'",
"AUTO_READ_TIME":'"$AUTO_READ_TIME"', "AUTO_READ_TIME":'"$AUTO_READ_TIME"',
"MAX_FILE_SIZE_MB":"'"$MAX_FILE_SIZE_MB"'", "MAX_FILE_SIZE_MB":"'"$MAX_FILE_SIZE_MB"'",
"RECENT_PERIOD_IN_HOURS":"'"RECENT_PERIOD_IN_HOURS"'",
"DELETE_RETENTION_HOURS":"'"$DELETE_RETENTION_HOURS"'", "DELETE_RETENTION_HOURS":"'"$DELETE_RETENTION_HOURS"'",
"API_URL":"'"$API_URL"'" "API_URL":"'"$API_URL"'"
}' > /usr/share/nginx/html/ui/assets/config/config.json }' > /usr/share/nginx/html/ui/assets/config/config.json