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:
commit
d3ebe3d9c4
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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({
|
||||||
|
|||||||
@ -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',
|
||||||
|
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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">
|
||||||
|
|||||||
@ -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'];
|
||||||
|
|||||||
@ -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(
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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';
|
||||||
|
|
||||||
|
|||||||
@ -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',
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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)
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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'];
|
||||||
|
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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 [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,4 +9,5 @@ export interface FilterModel {
|
|||||||
matches?: number;
|
matches?: number;
|
||||||
filters?: FilterModel[];
|
filters?: FilterModel[];
|
||||||
checker?: (obj?) => boolean;
|
checker?: (obj?) => boolean;
|
||||||
|
required?: boolean;
|
||||||
}
|
}
|
||||||
@ -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 {
|
||||||
@ -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[];
|
||||||
@ -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[],
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<div
|
||||||
|
(click)="toggle(filter)"
|
||||||
|
*ngFor="let filter of filters"
|
||||||
|
[class.active]="filter.checked"
|
||||||
|
class="quick-filter"
|
||||||
|
>
|
||||||
|
{{ filter.label | translate }}
|
||||||
|
</div>
|
||||||
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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;
|
||||||
|
|||||||
@ -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] },
|
||||||
{
|
{
|
||||||
|
|||||||
@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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": {
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user