- {{ download.filename }}
+
+
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/apps/red-ui/src/app/components/downloads-list-screen/downloads-list-screen.component.ts b/apps/red-ui/src/app/components/downloads-list-screen/downloads-list-screen.component.ts
index 41207582a..1bb7b56ac 100644
--- a/apps/red-ui/src/app/components/downloads-list-screen/downloads-list-screen.component.ts
+++ b/apps/red-ui/src/app/components/downloads-list-screen/downloads-list-screen.component.ts
@@ -1,4 +1,4 @@
-import { Component, forwardRef, Injector, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { Component, forwardRef, Injector, OnInit } from '@angular/core';
import { FileDownloadService } from '@upload-download/services/file-download.service';
import { DownloadStatusWrapper } from '@upload-download/model/download-status.wrapper';
import { DownloadControllerService } from '@redaction/red-ui-http';
@@ -16,11 +16,12 @@ import { RouterHistoryService } from '@services/router-history.service';
export class DownloadsListScreenComponent extends ListingComponent implements OnInit {
readonly circleButtonTypes = CircleButtonTypes;
readonly tableHeaderLabel = _('downloads-list.table-header.title');
- tableColumnConfigs: TableColumnConfig[];
- @ViewChild('filenameTemplate', { static: true }) filenameTemplate: TemplateRef;
- @ViewChild('sizeTemplate', { static: true }) sizeTemplate: TemplateRef;
- @ViewChild('creationDateTemplate', { static: true }) creationDateTemplate: TemplateRef;
- @ViewChild('statusTemplate', { static: true }) statusTemplate: TemplateRef;
+ readonly tableColumnConfigs: TableColumnConfig[] = [
+ { label: _('downloads-list.table-col-names.name'), width: '2fr' },
+ { label: _('downloads-list.table-col-names.size') },
+ { label: _('downloads-list.table-col-names.date') },
+ { label: _('downloads-list.table-col-names.status') }
+ ];
constructor(
protected readonly _injector: Injector,
@@ -33,7 +34,6 @@ export class DownloadsListScreenComponent extends ListingComponent {
@@ -50,15 +50,6 @@ export class DownloadsListScreenComponent extends ListingComponent d.storageId);
await this._downloadControllerService.deleteDownload({ storageIds }).toPromise();
diff --git a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.html b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.html
index fba752dd7..dd8dbc600 100644
--- a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.html
+++ b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.html
@@ -1,5 +1,4 @@
-
-
+
+
+
+
+
+
+ {{ download.filename }}
+
+
+
+
+
+ {{ download.size }}
+
+
+
+
+
+ {{ download.creationDate | date: 'd MMM. yyyy, hh:mm a' }}
+
+
+
+ {{ download.status }}
+
+
+
+
+
+
+
+
+
-
-
- {{ download.size }}
-
-
-
-
- {{ download.creationDate | date: 'd MMM. yyyy, hh:mm a' }}
-
-
-
-
- {{ download.status }}
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
-
-
+
+
+
+
-
-
-
-
+
-
+
+
+
+ {{ translations[type] | translate }}
+
+
+
+
+
-
-
-
-
-
diff --git a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.scss b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.scss
index d87b9c85d..053574610 100644
--- a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.scss
+++ b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.scss
@@ -30,19 +30,19 @@
cdk-virtual-scroll-viewport {
height: calc(100% - 80px) !important;
-
- .cdk-virtual-scroll-content-wrapper .table-item > div.cell {
- iqser-editable-input:not(.editing) {
- padding-left: 12px;
- }
-
- iqser-editable-input::ng-deep .edit-button {
- display: none;
- }
-
- &:hover iqser-editable-input::ng-deep .edit-button {
- display: block;
- }
- }
+ }
+}
+
+.cell {
+ iqser-editable-input:not(.editing) {
+ padding-left: 12px;
+ }
+
+ iqser-editable-input::ng-deep .edit-button {
+ display: none;
+ }
+
+ &:hover iqser-editable-input::ng-deep .edit-button {
+ display: block;
}
}
diff --git a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.ts
index b267c26a1..faa19b678 100644
--- a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.ts
+++ b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component.ts
@@ -1,16 +1,4 @@
-import {
- Component,
- EventEmitter,
- forwardRef,
- Injector,
- Input,
- OnChanges,
- OnInit,
- Output,
- SimpleChanges,
- TemplateRef,
- ViewChild
-} from '@angular/core';
+import { Component, EventEmitter, forwardRef, Injector, Input, OnChanges, Output, SimpleChanges } from '@angular/core';
import { Field } from '../file-attributes-csv-import-dialog.component';
import { FileAttributeConfigTypes } from '@redaction/red-ui-http';
import { CircleButtonTypes, DefaultListingServices, ListingComponent, TableColumnConfig } from '@iqser/common-ui';
@@ -23,16 +11,35 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
styleUrls: ['./active-fields-listing.component.scss'],
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => ActiveFieldsListingComponent) }]
})
-export class ActiveFieldsListingComponent extends ListingComponent implements OnChanges, OnInit {
+export class ActiveFieldsListingComponent extends ListingComponent implements OnChanges {
readonly circleButtonTypes = CircleButtonTypes;
readonly translations = fileAttributeTypesTranslations;
readonly tableHeaderLabel = _('file-attributes-csv-import.table-header.title');
- tableColumnConfigs: TableColumnConfig[];
+ readonly tableColumnConfigs: TableColumnConfig[] = [
+ {
+ label: _('file-attributes-csv-import.table-col-names.name'),
+ class: 'name',
+ width: 'minmax(0, 350px)'
+ },
+ {
+ label: _('file-attributes-csv-import.table-col-names.type'),
+ width: '150px'
+ },
+ {
+ label: _('file-attributes-csv-import.table-col-names.read-only'),
+ class: 'flex-center',
+ leftIcon: 'red:read-only',
+ width: 'auto'
+ },
+ {
+ label: _('file-attributes-csv-import.table-col-names.primary'),
+ class: 'flex-center',
+ rightIcon: 'red:status-info',
+ rightIconTooltip: _('file-attributes-csv-import.table-col-names.primary-info-tooltip'),
+ width: 'auto'
+ }
+ ];
readonly typeOptions = Object.keys(FileAttributeConfigTypes);
- @ViewChild('labelTemplate', { static: true }) labelTemplate: TemplateRef;
- @ViewChild('typeTemplate', { static: true }) typeTemplate: TemplateRef;
- @ViewChild('readonlyTemplate', { static: true }) readonlyTemplate: TemplateRef;
- @ViewChild('primaryTemplate', { static: true }) primaryTemplate: TemplateRef;
@Input() entities: Field[];
@Output() readonly entitiesChange = new EventEmitter();
@Output() readonly setHoveredColumn = new EventEmitter();
@@ -42,10 +49,6 @@ export class ActiveFieldsListingComponent extends ListingComponent implem
super(_injector);
}
- ngOnInit(): void {
- this._configureTableColumns();
- }
-
ngOnChanges(changes: SimpleChanges): void {
if (changes.entities) {
this.entitiesService.setEntities(this.entities);
@@ -80,35 +83,4 @@ export class ActiveFieldsListingComponent extends ListingComponent implem
itemMouseEnterFn = (field: Field) => this.setHoveredColumn.emit(field.csvColumn);
itemMouseLeaveFn = () => this.setHoveredColumn.emit();
-
- private _configureTableColumns() {
- this.tableColumnConfigs = [
- {
- label: _('file-attributes-csv-import.table-col-names.name'),
- class: 'name',
- template: this.labelTemplate,
- width: 'minmax(0, 350px)'
- },
- {
- label: _('file-attributes-csv-import.table-col-names.type'),
- template: this.typeTemplate,
- width: '150px'
- },
- {
- label: _('file-attributes-csv-import.table-col-names.read-only'),
- class: 'flex-center',
- leftIcon: 'red:read-only',
- template: this.readonlyTemplate,
- width: 'auto'
- },
- {
- label: _('file-attributes-csv-import.table-col-names.primary'),
- class: 'flex-center',
- rightIcon: 'red:status-info',
- rightIconTooltip: _('file-attributes-csv-import.table-col-names.primary-info-tooltip'),
- template: this.primaryTemplate,
- width: 'auto'
- }
- ];
- }
}
diff --git a/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.html
index 9311d73f9..0f97a58ed 100644
--- a/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.html
+++ b/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.html
@@ -97,24 +97,20 @@
-
-
-
- {{ translations[type] | translate }}
-
-
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
- {{ log.message }}
+
+
-
-
-
-
-
-
-
-
-
-
diff --git a/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.ts
index 635d4b141..ad2c4c828 100644
--- a/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.ts
+++ b/apps/red-ui/src/app/modules/admin/screens/audit/audit-screen.component.ts
@@ -1,4 +1,4 @@
-import { Component, forwardRef, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { Component, forwardRef, Injector, OnDestroy, OnInit } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { AuditControllerService, AuditResponse, AuditSearchRequest, IAudit } from '@redaction/red-ui-http';
import { Moment } from 'moment';
@@ -22,15 +22,16 @@ export class AuditScreenComponent extends ListingComponent implements OnD
readonly ALL_USERS = _('audit-screen.all-users');
readonly translations = auditCategoriesTranslations;
readonly currentUser = this._userService.currentUser;
- @ViewChild('messageTemplate', { static: true }) messageTemplate: TemplateRef;
- @ViewChild('dateTemplate', { static: true }) dateTemplate: TemplateRef;
- @ViewChild('userTemplate', { static: true }) userTemplate: TemplateRef;
- @ViewChild('categoryTemplate', { static: true }) categoryTemplate: TemplateRef;
filterForm: FormGroup;
categories: string[] = [];
userIds: Set;
logs: AuditResponse;
- tableColumnConfigs: TableColumnConfig[];
+ readonly tableColumnConfigs: TableColumnConfig[] = [
+ { label: _('audit-screen.table-col-names.message') },
+ { label: _('audit-screen.table-col-names.date') },
+ { label: _('audit-screen.table-col-names.user'), class: 'user-column' },
+ { label: _('audit-screen.table-col-names.category') }
+ ];
readonly tableHeaderLabel = _('audit-screen.table-header.title');
private _previousFrom: Moment;
private _previousTo: Moment;
@@ -69,32 +70,9 @@ export class AuditScreenComponent extends ListingComponent implements OnD
}
async ngOnInit() {
- this._configureTableColumns();
await this._fetchData();
}
- private _configureTableColumns() {
- this.tableColumnConfigs = [
- {
- label: _('audit-screen.table-col-names.message'),
- template: this.messageTemplate
- },
- {
- label: _('audit-screen.table-col-names.date'),
- template: this.dateTemplate
- },
- {
- label: _('audit-screen.table-col-names.user'),
- class: 'user-column',
- template: this.userTemplate
- },
- {
- label: _('audit-screen.table-col-names.category'),
- template: this.categoryTemplate
- }
- ];
- }
-
private _updateDateFilters(value): boolean {
if (applyIntervalConstraints(value, this._previousFrom, this._previousTo, this.filterForm, 'from', 'to')) {
return true;
diff --git a/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.html
index 460f9c2c9..f70c2dd2b 100644
--- a/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.html
+++ b/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.html
@@ -20,31 +20,31 @@
-
+
+ {{ log.message }}
+
+
+
+ {{ log.recordDate | date: 'd MMM. yyyy, hh:mm a' }}
+
+
+
+
+
+
+
- {{ log.recordDate | date: 'd MMM. yyyy, hh:mm a' }}
-
-
-
-
-
-
+
-
-
-
+
-
+
-
diff --git a/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.scss
index c24b7ea42..5adbb8506 100644
--- a/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.scss
+++ b/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.scss
@@ -1,15 +1,9 @@
-:host ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell {
- &:not(.scrollbar-placeholder) {
- padding-left: 24px;
- }
+.color-wrapper {
+ align-items: center;
- &.color-wrapper {
- align-items: center;
-
- .color-square {
- width: 16px;
- height: 16px;
- min-width: 16px;
- }
+ .color-square {
+ width: 16px;
+ height: 16px;
+ min-width: 16px;
}
}
diff --git a/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.ts
index 384cda27c..fb6ac773b 100644
--- a/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.ts
+++ b/apps/red-ui/src/app/modules/admin/screens/default-colors/default-colors-screen.component.ts
@@ -1,4 +1,4 @@
-import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit } from '@angular/core';
import { AppStateService } from '@state/app-state.service';
import { Colors } from '@redaction/red-ui-http';
import { ActivatedRoute } from '@angular/router';
@@ -29,13 +29,14 @@ interface ListItem extends IListable {
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DefaultColorsScreenComponent) }]
})
export class DefaultColorsScreenComponent extends ListingComponent implements OnInit {
- @ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef;
- @ViewChild('colorTemplate', { static: true }) colorTemplate: TemplateRef;
readonly circleButtonTypes = CircleButtonTypes;
readonly currentUser = this._userService.currentUser;
readonly translations = defaultColorsTranslations;
readonly tableHeaderLabel = _('default-colors-screen.table-header.title');
- tableColumnConfigs: TableColumnConfig[];
+ readonly tableColumnConfigs: TableColumnConfig[] = [
+ { label: _('default-colors-screen.table-col-names.key'), sortByKey: 'searchKey', width: '2fr' },
+ { label: _('default-colors-screen.table-col-names.color'), class: 'flex-center' }
+ ];
private _colorsObj: Colors;
constructor(
@@ -52,7 +53,6 @@ export class DefaultColorsScreenComponent extends ListingComponent imp
}
async ngOnInit() {
- this._configureTableColumns();
await this._loadColors();
}
@@ -72,22 +72,6 @@ export class DefaultColorsScreenComponent extends ListingComponent imp
);
}
- private _configureTableColumns() {
- this.tableColumnConfigs = [
- {
- label: _('default-colors-screen.table-col-names.key'),
- sortByKey: 'searchKey',
- template: this.nameTemplate,
- width: '2fr'
- },
- {
- label: _('default-colors-screen.table-col-names.color'),
- class: 'flex-center',
- template: this.colorTemplate
- }
- ];
- }
-
private async _loadColors() {
this._loadingService.start();
const data = await this._appStateService.loadColors(this._appStateService.activeDossierTemplateId).toPromise();
diff --git a/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.html
index 77d1ff07a..b54ae5350 100644
--- a/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.html
+++ b/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.html
@@ -22,7 +22,6 @@
-
-
+
+
-
-
-
-
+
+
-
-
+
+
+
+
+
-
-
-
- {{ entity.label }}
+
+
+
-
-
-
-
-
-
-
diff --git a/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.scss
index 93f51990a..40a7ed6bb 100644
--- a/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.scss
+++ b/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.scss
@@ -1,39 +1,36 @@
-:host {
- ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell {
- flex-direction: row;
- align-items: center;
- justify-content: flex-start;
+.cell {
+ flex-direction: row !important;
+ align-items: center;
- &.center {
- justify-content: center;
- }
-
- .color-square {
- width: 16px;
- height: 16px;
- min-width: 16px;
- margin-right: 16px;
- }
-
- .dict-name {
- z-index: 1;
- max-width: 100%;
- }
-
- .stats-subtitle {
- margin-top: 4px;
- }
+ &:not(.center) {
+ justify-content: flex-start !important;
}
- .right-container {
- display: flex;
- width: 353px;
- min-width: 353px;
- justify-content: center;
- padding: 50px 20px 30px 20px;
+ .color-square {
+ width: 16px;
+ height: 16px;
+ min-width: 16px;
+ margin-right: 16px;
+ }
- &.has-scrollbar:hover {
- padding-right: 9px;
- }
+ .dict-name {
+ z-index: 1;
+ max-width: 100%;
+ }
+
+ .stats-subtitle {
+ margin-top: 4px;
+ }
+}
+
+.right-container {
+ display: flex;
+ width: 353px;
+ min-width: 353px;
+ justify-content: center;
+ padding: 50px 20px 30px 20px;
+
+ &.has-scrollbar:hover {
+ padding-right: 9px;
}
}
diff --git a/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.ts
index 6d9ed2807..cb7270617 100644
--- a/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.ts
+++ b/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.ts
@@ -1,4 +1,4 @@
-import { Component, forwardRef, Injector, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { Component, forwardRef, Injector, OnInit } from '@angular/core';
import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component';
import { AppStateService } from '@state/app-state.service';
import { catchError, defaultIfEmpty, tap } from 'rxjs/operators';
@@ -36,11 +36,12 @@ export class DictionaryListingScreenComponent extends ListingComponent[];
+ readonly tableColumnConfigs: TableColumnConfig[] = [
+ { label: _('dictionary-listing.table-col-names.type'), sortByKey: 'searchKey', width: '2fr' },
+ { label: _('dictionary-listing.table-col-names.order-of-importance'), sortByKey: 'rank', class: 'flex-center' },
+ { label: _('dictionary-listing.table-col-names.hint-redaction'), class: 'flex-center' }
+ ];
chartData: DoughnutChartConfig[] = [];
- @ViewChild('labelTemplate', { static: true }) labelTemplate: TemplateRef;
- @ViewChild('rankTemplate', { static: true }) rankTemplate: TemplateRef;
- @ViewChild('iconTemplate', { static: true }) iconTemplate: TemplateRef;
constructor(
protected readonly _injector: Injector,
@@ -58,7 +59,6 @@ export class DictionaryListingScreenComponent extends ListingComponent !d.virtual);
diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.html
index 9635022f1..def1dfab3 100644
--- a/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.html
+++ b/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.html
@@ -22,7 +22,6 @@
-
-
+
+
-
-
+
-
+ {{ dict.label }}
+
+
+
+
+ {{ dict.entries?.length }}
+
+
+
+ {{ 'dictionary-listing.case-sensitive' | translate }}
+
+
-
+
+
-
- {{ entity.entries?.length }}
-
-
-
- {{ 'dictionary-listing.case-sensitive' | translate }}
-
+
+ {{ dict.rank }}
+
+
+
+
+
+
+
+
+
+
+
- {{ dict.rank }}
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts
index 09cd2466f..d087bb15a 100644
--- a/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts
+++ b/apps/red-ui/src/app/modules/admin/screens/dossier-attributes-listing/dossier-attributes-listing-screen.component.ts
@@ -1,4 +1,4 @@
-import { Component, forwardRef, Injector, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { Component, forwardRef, Injector, OnInit } from '@angular/core';
import {
CircleButtonTypes,
DefaultListingServices,
@@ -31,10 +31,11 @@ export class DossierAttributesListingScreenComponent extends ListingComponent[];
- @ViewChild('labelTemplate', { static: true }) labelTemplate: TemplateRef;
- @ViewChild('placeholderTemplate', { static: true }) placeholderTemplate: TemplateRef;
- @ViewChild('typeTemplate', { static: true }) typeTemplate: TemplateRef;
+ readonly tableColumnConfigs: TableColumnConfig[] = [
+ { label: _('dossier-attributes-listing.table-col-names.label'), sortByKey: 'label', width: '2fr' },
+ { label: _('dossier-attributes-listing.table-col-names.placeholder'), width: '2fr' },
+ { label: _('dossier-attributes-listing.table-col-names.type'), sortByKey: 'type' }
+ ];
constructor(
protected readonly _injector: Injector,
@@ -50,7 +51,6 @@ export class DossierAttributesListingScreenComponent extends ListingComponent
-
-
+
-
-
+ {{ attribute.label }}
+
-
- {{ attribute.label }}
-
-
- {{ attribute.placeholder }}
-
-
- {{ translations[attribute.type] | translate }}
+
+ {{ attribute.placeholder }}
+
+
+
+ {{ translations[attribute.type] | translate }}
+
+
+
+
+
+
+
+
+
-
- {{ dossierTemplate.name }}
-
-
-
-
- {{ 'dossier-templates-listing.dictionaries' | translate: { length: dossierTemplate.dictionariesCount } }}
+
+
-
-
-
-
-
-
-
-
+
-
+
-
+ {{ dossierTemplate.name }}
+
+
+
+
+ {{ 'dossier-templates-listing.dictionaries' | translate: { length: dossierTemplate.dictionariesCount } }}
+
-
-
-
- {{ dossierTemplate.dateAdded | date: 'd MMM. yyyy' }}
-
-
- [];
- @ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef;
- @ViewChild('userTemplate', { static: true }) userTemplate: TemplateRef;
- @ViewChild('dateAddedTemplate', { static: true }) dateAddedTemplate: TemplateRef;
- @ViewChild('dateModifiedTemplate', { static: true }) dateModifiedTemplate: TemplateRef;
+ readonly tableColumnConfigs: TableColumnConfig[] = [
+ { label: _('dossier-templates-listing.table-col-names.name'), sortByKey: 'searchKey' },
+ { label: _('dossier-templates-listing.table-col-names.created-by'), class: 'user-column' },
+ { label: _('dossier-templates-listing.table-col-names.created-on'), sortByKey: 'dateAdded' },
+ { label: _('dossier-templates-listing.table-col-names.modified-on'), sortByKey: 'dateModified' }
+ ];
constructor(
protected readonly _injector: Injector,
@@ -52,7 +53,6 @@ export class DossierTemplatesListingScreenComponent extends ListingComponent d.dossierTemplateId)) {
await this._dossierTemplateControllerService
.deleteDossierTemplates(templateIds)
diff --git a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.html
index ce9844247..61635162f 100644
--- a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.html
+++ b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.html
@@ -21,7 +21,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ dossierTemplate.dateModified | date: 'd MMM. yyyy' }}
+
diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.scss
index 009e0d63a..232ac1f4c 100644
--- a/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.scss
+++ b/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.scss
@@ -1,15 +1,7 @@
-:host {
- ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell {
- .stats-subtitle {
- margin-top: 4px;
- }
-
- .table-item-title {
- max-width: 100%;
- }
- }
-
- .page-header .actions > *:not(:last-child) {
- margin-right: 16px;
- }
+.stats-subtitle {
+ margin-top: 4px;
+}
+
+.table-item-title {
+ max-width: 100%;
}
diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.ts
index f7a9989ca..ef14dcb22 100644
--- a/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.ts
+++ b/apps/red-ui/src/app/modules/admin/screens/dossier-template-listing/dossier-templates-listing-screen.component.ts
@@ -1,4 +1,4 @@
-import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit } from '@angular/core';
import { AppStateService } from '@state/app-state.service';
import { UserPreferenceService } from '@services/user-preference.service';
import { AdminDialogService } from '../../services/admin-dialog.service';
@@ -31,11 +31,12 @@ export class DossierTemplatesListingScreenComponent extends ListingComponent
+
+
+
+
+ {{ dossierTemplate.dateAdded | date: 'd MMM. yyyy' }}
+
+
+
+
-
+ {{ dossierTemplate.dateModified | date: 'd MMM. yyyy' }}
+
+
-
-
-
-
- {{ attribute.label }}
-
-
-
-
-
- {{ attribute.csvColumnHeader }}
-
-
-
-
-
-
-
-
-
+
+
diff --git a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.scss
index 6b4d12879..14a44a51a 100644
--- a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.scss
+++ b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.scss
@@ -1,10 +1,6 @@
@use 'common-mixins';
-:host ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell {
- &.center {
- align-items: center;
- }
-
+.cell {
&.label span {
@include common-mixins.line-clamp(1);
}
diff --git a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.ts
index 70f0e6f2d..0a277efda 100644
--- a/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.ts
+++ b/apps/red-ui/src/app/modules/admin/screens/file-attributes-listing/file-attributes-listing-screen.component.ts
@@ -1,14 +1,4 @@
-import {
- ChangeDetectionStrategy,
- Component,
- ElementRef,
- forwardRef,
- Injector,
- OnDestroy,
- OnInit,
- TemplateRef,
- ViewChild
-} from '@angular/core';
+import { ChangeDetectionStrategy, Component, ElementRef, forwardRef, Injector, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { FileAttributesConfig, IFileAttributeConfig } from '@redaction/red-ui-http';
import { AppStateService } from '@state/app-state.service';
import { ActivatedRoute } from '@angular/router';
@@ -42,14 +32,20 @@ export class FileAttributesListingScreenComponent extends ListingComponent[];
- @ViewChild('labelTemplate', { static: true }) labelTemplate: TemplateRef;
- @ViewChild('typeTemplate', { static: true }) typeTemplate: TemplateRef;
- @ViewChild('readonlyTemplate', { static: true }) readonlyTemplate: TemplateRef;
- @ViewChild('csvColumnHeaderTemplate', { static: true }) csvColumnHeaderTemplate: TemplateRef;
- @ViewChild('filterableTemplate', { static: true }) filterableTemplate: TemplateRef;
- @ViewChild('displayedInFileListTemplate', { static: true }) displayedInFileListTemplate: TemplateRef;
- @ViewChild('primaryAttributeTemplate', { static: true }) primaryAttributeTemplate: TemplateRef;
+ readonly tableColumnConfigs: TableColumnConfig[] = [
+ { label: _('file-attributes-listing.table-col-names.name'), sortByKey: 'searchKey', width: '2fr' },
+ { label: _('file-attributes-listing.table-col-names.type'), sortByKey: 'type' },
+ { label: _('file-attributes-listing.table-col-names.read-only'), sortByKey: 'editable', class: 'flex-center' },
+ { label: _('file-attributes-listing.table-col-names.csv-column') },
+ { label: _('file-attributes-listing.table-col-names.filterable'), class: 'flex-center' },
+ { label: _('file-attributes-listing.table-col-names.displayed-in-file-list'), class: 'flex-center' },
+ {
+ label: _('file-attributes-listing.table-col-names.primary'),
+ class: 'flex-center',
+ rightIcon: 'red:status-info',
+ rightIconTooltip: _('file-attributes-listing.table-col-names.primary-info-tooltip')
+ }
+ ];
private _existingConfiguration: FileAttributesConfig;
@ViewChild('fileInput') private _fileInput: ElementRef;
@@ -67,7 +63,6 @@ export class FileAttributesListingScreenComponent extends ListingComponent
-
-
+
+ {{ attribute.label }}
+
+
+
+
+
+
+
+
+
+ {{ attribute.csvColumnHeader }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- {{ entity.dossierName }}
+
+
+
+
-
+ {{ entity.dossierName }}
+
+
+
+
+ {{ entity.memberIds.length }}
+
+
+
+ {{ entity.date | date: 'mediumDate' }}
+
+
+
+ {{ entity.dueDate | date: 'mediumDate' }}
+
+
-
-
- {{ entity.memberIds.length }}
+
+
-
-
-
-
-
-
-
diff --git a/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.scss
index e69de29bb..b0ed00292 100644
--- a/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.scss
+++ b/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.scss
@@ -0,0 +1,3 @@
+.stats-subtitle {
+ margin-top: 4px;
+}
diff --git a/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.ts
index bed1882f5..bdec52e11 100644
--- a/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.ts
+++ b/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.ts
@@ -1,4 +1,4 @@
-import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit } from '@angular/core';
import { IDossier } from '@redaction/red-ui-http';
import {
CircleButtonTypes,
@@ -35,11 +35,12 @@ export class TrashScreenComponent extends ListingComponent impl
readonly circleButtonTypes = CircleButtonTypes;
readonly tableHeaderLabel = _('trash.table-header.title');
readonly canRestoreSelected$ = this._canRestoreSelected$;
- tableColumnConfigs: TableColumnConfig[];
- @ViewChild('filenameTemplate', { static: true }) filenameTemplate: TemplateRef;
- @ViewChild('ownerTemplate', { static: true }) ownerTemplate: TemplateRef;
- @ViewChild('deletedTimeTemplate', { static: true }) deletedTimeTemplate: TemplateRef;
- @ViewChild('restoreDateTemplate', { static: true }) restoreDateTemplate: TemplateRef;
+ readonly tableColumnConfigs: TableColumnConfig[] = [
+ { label: _('trash.table-col-names.name'), sortByKey: 'searchKey' },
+ { label: _('trash.table-col-names.owner'), class: 'user-column' },
+ { label: _('trash.table-col-names.deleted-on'), sortByKey: 'softDeletedTime' },
+ { label: _('trash.table-col-names.time-to-restore'), sortByKey: 'softDeletedTime' }
+ ];
constructor(
protected readonly _injector: Injector,
@@ -62,7 +63,6 @@ export class TrashScreenComponent extends ListingComponent impl
disabledFn = (dossier: DossierListItem) => !dossier.canRestore;
async ngOnInit(): Promise {
- this._configureTableColumns();
this._loadingService.start();
await this._loadDossiersData();
this.sortingService.setSortingOption({
@@ -95,31 +95,6 @@ export class TrashScreenComponent extends ListingComponent impl
this._loadingService.loadWhile(this._restore(dossiers));
}
- private _configureTableColumns() {
- this.tableColumnConfigs = [
- {
- label: _('trash.table-col-names.name'),
- sortByKey: 'searchKey',
- template: this.filenameTemplate
- },
- {
- label: _('trash.table-col-names.owner'),
- class: 'user-column',
- template: this.ownerTemplate
- },
- {
- label: _('trash.table-col-names.deleted-on'),
- sortByKey: 'softDeletedTime',
- template: this.deletedTimeTemplate
- },
- {
- label: _('trash.table-col-names.time-to-restore'),
- sortByKey: 'softDeletedTime',
- template: this.restoreDateTemplate
- }
- ];
- }
-
private _getRestoreDate(softDeletedTime: string): string {
return moment(softDeletedTime).add(this._configService.values.DELETE_RETENTION_HOURS, 'hours').toISOString();
}
diff --git a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html
index a050c77b9..a2b46998f 100644
--- a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html
+++ b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.html
@@ -33,7 +33,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+ {{ entity.softDeletedTime | date: 'd MMM. yyyy, hh:mm a' }}
+
+
+
+
+
-
-
+ {{ entity.restoreDate | date: 'timeFromNow' }}
-
-
- {{ entity.date | date: 'mediumDate' }}
-
-
-
- {{ entity.dueDate | date: 'mediumDate' }}
+
+
+
+
-
-
-
-
- {{ entity.softDeletedTime | date: 'd MMM. yyyy, hh:mm a' }}
-
-
-
-
-
- {{ entity.restoreDate | date: 'timeFromNow' }}
-
-
-
-
-
-
-
-
-
-{{ user.email || '-' }}
-
-
-
-{{ getDisplayRoles(user) }}
-
-
-
+
+
diff --git a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.scss b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.scss
index 5a09cdf01..097d651bc 100644
--- a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.scss
+++ b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.scss
@@ -1,7 +1,3 @@
-:host ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell.center {
- align-items: center;
-}
-
.right-container {
display: flex;
width: 353px;
diff --git a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts
index fa92bdd2f..ff0e8f244 100644
--- a/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts
+++ b/apps/red-ui/src/app/modules/admin/screens/user-listing/user-listing-screen.component.ts
@@ -1,4 +1,4 @@
-import { Component, forwardRef, Injector, OnInit, QueryList, TemplateRef, ViewChild, ViewChildren } from '@angular/core';
+import { Component, forwardRef, Injector, OnInit, QueryList, ViewChildren } from '@angular/core';
import { UserService } from '@services/user.service';
import { UserControllerService } from '@redaction/red-ui-http';
import { AdminDialogService } from '../../services/admin-dialog.service';
@@ -32,13 +32,14 @@ export class UserListingScreenComponent extends ListingComponent implement
readonly currentUser = this.userService.currentUser;
readonly canDeleteSelected$ = this._canDeleteSelected$;
readonly tableHeaderLabel = _('user-listing.table-header.title');
- tableColumnConfigs: TableColumnConfig[];
+ readonly tableColumnConfigs: TableColumnConfig[] = [
+ { label: _('user-listing.table-col-names.name'), width: '2fr' },
+ { label: _('user-listing.table-col-names.email') },
+ { label: _('user-listing.table-col-names.active'), class: 'flex-center' },
+ { label: _('user-listing.table-col-names.roles') }
+ ];
collapsedDetails = false;
chartData: DoughnutChartConfig[] = [];
- @ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef;
- @ViewChild('emailTemplate', { static: true }) emailTemplate: TemplateRef;
- @ViewChild('activeTemplate', { static: true }) activeTemplate: TemplateRef;
- @ViewChild('rolesTemplate', { static: true }) rolesTemplate: TemplateRef;
@ViewChildren(InitialsAvatarComponent)
private readonly _avatars: QueryList;
@@ -60,7 +61,6 @@ export class UserListingScreenComponent extends ListingComponent implement
}
async ngOnInit() {
- this._configureTableColumns();
await this._loadData();
}
@@ -96,15 +96,6 @@ export class UserListingScreenComponent extends ListingComponent implement
this.openDeleteUsersDialog(this.entitiesService.all.filter(u => this.isSelected(u)));
}
- private _configureTableColumns() {
- this.tableColumnConfigs = [
- { label: _('user-listing.table-col-names.name'), template: this.nameTemplate, width: '2fr' },
- { label: _('user-listing.table-col-names.email'), template: this.emailTemplate },
- { label: _('user-listing.table-col-names.active'), class: 'flex-center', template: this.activeTemplate },
- { label: _('user-listing.table-col-names.roles'), template: this.rolesTemplate }
- ];
- }
-
private async _loadData() {
this.entitiesService.setEntities(await this.userService.loadAllUsers());
await this.userService.loadAllUsers();
diff --git a/apps/red-ui/src/app/modules/dossier/components/team-members-manager/team-members-manager.component.ts b/apps/red-ui/src/app/modules/dossier/components/team-members-manager/team-members-manager.component.ts
index be0aef561..be438a273 100644
--- a/apps/red-ui/src/app/modules/dossier/components/team-members-manager/team-members-manager.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/components/team-members-manager/team-members-manager.component.ts
@@ -4,7 +4,7 @@ import { AppStateService } from '@state/app-state.service';
import { UserService } from '@services/user.service';
import { Toaster } from '@iqser/common-ui';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
-import { Dossier } from '../../../../state/model/dossier';
+import { Dossier } from '@state/model/dossier';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
@Component({
@@ -119,6 +119,13 @@ export class TeamMembersManagerComponent implements OnInit {
this._loadData();
}
+ setMembersSelectOptions(): void {
+ this.membersSelectOptions = this.userService.eligibleUsers
+ .filter(user => this.userService.getNameForId(user.id).toLowerCase().includes(this.searchQuery.toLowerCase()))
+ .filter(user => this.selectedOwnerId !== user.id)
+ .map(user => user.id);
+ }
+
private _updateChanged() {
if (this.dossier.ownerId !== this.selectedOwnerId) {
this.changed = true;
@@ -138,13 +145,6 @@ export class TeamMembersManagerComponent implements OnInit {
this.selectedReviewersList = this.selectedMembersList.filter(m => this.selectedApproversList.indexOf(m) === -1);
}
- setMembersSelectOptions(): void {
- this.membersSelectOptions = this.userService.eligibleUsers
- .filter(user => this.userService.getNameForId(user.id).toLowerCase().includes(this.searchQuery.toLowerCase()))
- .filter(user => this.selectedOwnerId !== user.id)
- .map(user => user.id);
- }
-
private _loadData() {
this.teamForm = this._formBuilder.group({
owner: [this.dossier?.ownerId, Validators.required],
diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts
index 7bbbd4ff5..3a49970ba 100644
--- a/apps/red-ui/src/app/modules/dossier/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component.ts
@@ -69,7 +69,6 @@ export class AssignReviewerApproverDialogComponent {
const selectedUser = this.selectedSingleUser;
if (this.data.mode === 'reviewer') {
- console.log('assign reviewer');
await this._filesService
.setReviewerFor(
this.data.files.map(f => f.fileId),
diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.html b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.html
index 019278fc4..81c1f8810 100644
--- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.html
+++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.html
@@ -34,45 +34,41 @@
>
-
-
+
+
+
+
+
+
+ {{ user.email || '-' }}
+
+
+
+
+
+ {{ getDisplayRoles(user) }}
+
+
+
+
+
+
+
- {{ file.filename }}
-
-
+
-
-
-
-
-
-
-
+ {{ file.filename }}
+
-
-
-
-
- {{ file.numberOfPages }}
-
-
- {{ file.softDeleted | date: 'exactDate' }}
-
-
- [];
+ readonly tableColumnConfigs: TableColumnConfig[] = [
+ { label: _('edit-dossier-dialog.deleted-documents.table-col-names.name'), width: '3fr' },
+ { label: _('edit-dossier-dialog.deleted-documents.table-col-names.pages') },
+ { label: _('edit-dossier-dialog.deleted-documents.table-col-names.deleted-on'), sortByKey: 'softDeleted', width: '2fr' },
+ { label: _('edit-dossier-dialog.deleted-documents.table-col-names.time-to-restore'), sortByKey: 'softDeleted', width: '2fr' }
+ ];
readonly tableHeaderLabel = _('edit-dossier-dialog.deleted-documents.table-header.label');
readonly circleButtonTypes = CircleButtonTypes;
readonly deleteRetentionHours = this._configService.values.DELETE_RETENTION_HOURS;
- @ViewChild('filenameTemplate', { static: true }) filenameTemplate: TemplateRef;
- @ViewChild('pagesTemplate', { static: true }) pagesTemplate: TemplateRef;
- @ViewChild('deletedDateTemplate', { static: true }) deletedDateTemplate: TemplateRef;
- @ViewChild('restoreDateTemplate', { static: true }) restoreDateTemplate: TemplateRef;
constructor(
protected readonly _injector: Injector,
@@ -89,7 +90,6 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent !file.canRestore;
- private _configureTableColumns() {
- this.tableColumnConfigs = [
- {
- label: _('edit-dossier-dialog.deleted-documents.table-col-names.name'),
- template: this.filenameTemplate,
- width: '3fr'
- },
- {
- label: _('edit-dossier-dialog.deleted-documents.table-col-names.pages'),
- template: this.pagesTemplate
- },
- {
- label: _('edit-dossier-dialog.deleted-documents.table-col-names.deleted-on'),
- template: this.deletedDateTemplate,
- sortByKey: 'softDeleted',
- width: '2fr'
- },
- {
- label: _('edit-dossier-dialog.deleted-documents.table-col-names.time-to-restore'),
- template: this.restoreDateTemplate,
- sortByKey: 'softDeleted',
- width: '2fr'
- }
- ];
- }
-
private async _restore(files: FileListItem[]): Promise {
const fileIds = files.map(f => f.fileId);
await this._fileManagementController.restoreFiles(fileIds, this.dossier.id).toPromise();
diff --git a/apps/red-ui/src/app/modules/dossier/dossiers-routing.module.ts b/apps/red-ui/src/app/modules/dossier/dossiers-routing.module.ts
index b695f17eb..33a456ffe 100644
--- a/apps/red-ui/src/app/modules/dossier/dossiers-routing.module.ts
+++ b/apps/red-ui/src/app/modules/dossier/dossiers-routing.module.ts
@@ -1,13 +1,11 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
-import { DossierListingScreenComponent } from './screens/dossier-listing-screen/dossier-listing-screen.component';
import { CompositeRouteGuard } from '@guards/composite-route.guard';
import { AuthGuard } from '../auth/auth.guard';
import { RedRoleGuard } from '../auth/red-role.guard';
import { AppStateGuard } from '@state/app-state.guard';
import { SearchScreenComponent } from './screens/search-screen/search-screen.component';
import { FilePreviewScreenComponent } from './screens/file-preview-screen/file-preview-screen.component';
-import { DossierOverviewScreenComponent } from './screens/dossier-overview-screen/dossier-overview-screen.component';
const routes: Routes = [
{
@@ -20,12 +18,12 @@ const routes: Routes = [
},
{
path: ':dossierId',
- component: DossierOverviewScreenComponent,
canActivate: [CompositeRouteGuard],
data: {
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
reuse: true
- }
+ },
+ loadChildren: () => import('./screens/dossier-overview/dossier-overview.module').then(m => m.DossierOverviewModule)
},
{
path: ':dossierId/file/:fileId',
@@ -39,12 +37,12 @@ const routes: Routes = [
{
path: '',
pathMatch: 'full',
- component: DossierListingScreenComponent,
canActivate: [CompositeRouteGuard],
data: {
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
reuse: true
- }
+ },
+ loadChildren: () => import('./screens/dossiers-listing/dossiers-listing.module').then(m => m.DossiersListingModule)
}
];
diff --git a/apps/red-ui/src/app/modules/dossier/dossiers.module.ts b/apps/red-ui/src/app/modules/dossier/dossiers.module.ts
index 4daae1ee8..c4b617945 100644
--- a/apps/red-ui/src/app/modules/dossier/dossiers.module.ts
+++ b/apps/red-ui/src/app/modules/dossier/dossiers.module.ts
@@ -1,7 +1,5 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
-import { DossierListingScreenComponent } from './screens/dossier-listing-screen/dossier-listing-screen.component';
-import { DossierOverviewScreenComponent } from './screens/dossier-overview-screen/dossier-overview-screen.component';
import { FilePreviewScreenComponent } from './screens/file-preview-screen/file-preview-screen.component';
import { AddDossierDialogComponent } from './dialogs/add-dossier-dialog/add-dossier-dialog.component';
import { AssignReviewerApproverDialogComponent } from './dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component';
@@ -11,17 +9,9 @@ import { RemoveAnnotationsDialogComponent } from './dialogs/remove-annotations-d
import { DocumentInfoDialogComponent } from './dialogs/document-info-dialog/document-info-dialog.component';
import { PdfViewerComponent } from './components/pdf-viewer/pdf-viewer.component';
import { CommentsComponent } from './components/comments/comments.component';
-import { DossierDetailsComponent } from './components/dossier-details/dossier-details.component';
import { PageIndicatorComponent } from './components/page-indicator/page-indicator.component';
-import { NeedsWorkBadgeComponent } from './components/needs-work-badge/needs-work-badge.component';
import { AnnotationActionsComponent } from './components/annotation-actions/annotation-actions.component';
-import { DossierListingDetailsComponent } from './components/dossier-listing-details/dossier-listing-details.component';
-import { FileActionsComponent } from './components/file-actions/file-actions.component';
import { TypeAnnotationIconComponent } from './components/type-annotation-icon/type-annotation-icon.component';
-import { TypeFilterComponent } from './components/type-filter/type-filter.component';
-import { DossierOverviewBulkActionsComponent } from './components/bulk-actions/dossier-overview-bulk-actions.component';
-import { TeamMembersComponent } from './components/team-members/team-members.component';
-import { DossierListingActionsComponent } from './components/dossier-listing-actions/dossier-listing-actions.component';
import { DocumentInfoComponent } from './components/document-info/document-info.component';
import { FileWorkloadComponent } from './components/file-workload/file-workload.component';
import { SharedModule } from '@shared/shared.module';
@@ -29,7 +19,6 @@ import { DossiersRoutingModule } from './dossiers-routing.module';
import { FileUploadDownloadModule } from '@upload-download/file-upload-download.module';
import { DossiersDialogService } from './services/dossiers-dialog.service';
import { AnnotationActionsService } from './services/annotation-actions.service';
-import { FileActionService } from './services/file-action.service';
import { PdfViewerDataService } from './services/pdf-viewer-data.service';
import { ManualAnnotationService } from './services/manual-annotation.service';
import { AnnotationDrawService } from './services/annotation-draw.service';
@@ -46,14 +35,14 @@ import { PageExclusionComponent } from './components/page-exclusion/page-exclusi
import { RecategorizeImageDialogComponent } from './dialogs/recategorize-image-dialog/recategorize-image-dialog.component';
import { EditDossierAttributesComponent } from './dialogs/edit-dossier-dialog/attributes/edit-dossier-attributes.component';
import { DossiersService } from './services/dossiers.service';
-import { DossierDetailsStatsComponent } from './components/dossier-details-stats/dossier-details-stats.component';
import { SearchScreenComponent } from './screens/search-screen/search-screen.component';
import { EditDossierDeletedDocumentsComponent } from './dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component';
import { AnnotationsListComponent } from './components/file-workload/components/annotations-list/annotations-list.component';
import { AnnotationSourceComponent } from './components/file-workload/components/annotation-source/annotation-source.component';
import { OverlayModule } from '@angular/cdk/overlay';
+import { SharedDossiersModule } from './shared/shared-dossiers.module';
-const screens = [DossierListingScreenComponent, DossierOverviewScreenComponent, FilePreviewScreenComponent, SearchScreenComponent];
+const screens = [FilePreviewScreenComponent, SearchScreenComponent];
const dialogs = [
AddDossierDialogComponent,
@@ -70,17 +59,9 @@ const dialogs = [
const components = [
PdfViewerComponent,
CommentsComponent,
- DossierDetailsComponent,
PageIndicatorComponent,
- NeedsWorkBadgeComponent,
AnnotationActionsComponent,
- DossierListingDetailsComponent,
TypeAnnotationIconComponent,
- TypeFilterComponent,
- DossierOverviewBulkActionsComponent,
- FileActionsComponent,
- TeamMembersComponent,
- DossierListingActionsComponent,
DocumentInfoComponent,
FileWorkloadComponent,
EditDossierGeneralInfoComponent,
@@ -90,7 +71,6 @@ const components = [
EditDossierAttributesComponent,
TeamMembersManagerComponent,
PageExclusionComponent,
- DossierDetailsStatsComponent,
EditDossierDeletedDocumentsComponent,
AnnotationsListComponent,
AnnotationSourceComponent,
@@ -102,7 +82,6 @@ const components = [
const services = [
DossiersService,
DossiersDialogService,
- FileActionService,
AnnotationActionsService,
ManualAnnotationService,
PdfViewerDataService,
@@ -114,6 +93,6 @@ const services = [
@NgModule({
declarations: [...components],
providers: [...services],
- imports: [CommonModule, SharedModule, FileUploadDownloadModule, DossiersRoutingModule, OverlayModule]
+ imports: [CommonModule, SharedModule, SharedDossiersModule, FileUploadDownloadModule, DossiersRoutingModule, OverlayModule]
})
export class DossiersModule {}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.html
deleted file mode 100644
index a7d8f738f..000000000
--- a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.html
+++ /dev/null
@@ -1,86 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.scss
deleted file mode 100644
index cb00faaf2..000000000
--- a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.scss
+++ /dev/null
@@ -1,22 +0,0 @@
-:host {
- ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell {
- &.status-container {
- width: 160px;
- }
- }
-
- .right-container {
- display: flex;
- width: 466px;
- min-width: 466px;
- padding-right: 11px;
-
- &.has-scrollbar:hover {
- padding-right: 0;
- }
-
- redaction-dossier-listing-details {
- min-width: 466px;
- }
- }
-}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts
deleted file mode 100644
index 8b4b7661f..000000000
--- a/apps/red-ui/src/app/modules/dossier/screens/dossier-listing-screen/dossier-listing-screen.component.ts
+++ /dev/null
@@ -1,336 +0,0 @@
-import { AfterViewInit, Component, forwardRef, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
-import { DossierStatuses } from '@redaction/red-ui-http';
-import { AppStateService } from '@state/app-state.service';
-import { UserService } from '@services/user.service';
-import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component';
-import { groupBy } from '@utils/functions';
-import { TranslateService } from '@ngx-translate/core';
-import { Dossier } from '@state/model/dossier';
-import { timer } from 'rxjs';
-import { tap } from 'rxjs/operators';
-import { TranslateChartService } from '@services/translate-chart.service';
-import { RedactionFilterSorter } from '@utils/sorters/redaction-filter-sorter';
-import { StatusSorter } from '@utils/sorters/status-sorter';
-import { Router } from '@angular/router';
-import { DossiersDialogService } from '../../services/dossiers-dialog.service';
-import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy';
-import { UserPreferenceService } from '@services/user-preference.service';
-import { ButtonConfig } from '@shared/components/page-header/models/button-config.model';
-import { DefaultListingServices, keyChecker, ListingComponent, NestedFilter, TableColumnConfig, TableComponent } from '@iqser/common-ui';
-import { workloadTranslations } from '../../translations/workload-translations';
-import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
-import { fileStatusTranslations } from '../../translations/file-status-translations';
-import { annotationFilterChecker, dossierMemberChecker, dossierStatusChecker, dossierTemplateChecker } from '@utils/filter-utils';
-import { PermissionsService } from '@services/permissions.service';
-
-@Component({
- templateUrl: './dossier-listing-screen.component.html',
- styleUrls: ['./dossier-listing-screen.component.scss'],
- providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DossierListingScreenComponent) }]
-})
-export class DossierListingScreenComponent
- extends ListingComponent
- implements OnInit, AfterViewInit, OnDestroy, OnAttach, OnDetach
-{
- readonly currentUser = this._userService.currentUser;
- readonly tableHeaderLabel = _('dossier-listing.table-header.title');
- readonly buttonConfigs: readonly ButtonConfig[] = [
- {
- label: _('dossier-listing.add-new'),
- action: (): void => this.openAddDossierDialog(),
- hide: !this.currentUser.isManager,
- icon: 'red:plus',
- type: 'primary'
- }
- ];
- tableColumnConfigs: TableColumnConfig[];
- dossiersChartData: DoughnutChartConfig[] = [];
- documentsChartData: DoughnutChartConfig[] = [];
- @ViewChild('nameTemplate', { static: true }) nameTemplate: TemplateRef;
- @ViewChild('needsWorkTemplate', { static: true }) needsWorkTemplate: TemplateRef;
- @ViewChild('ownerTemplate', { static: true }) ownerTemplate: TemplateRef;
- @ViewChild('statusTemplate', { static: true }) statusTemplate: TemplateRef;
- private _lastScrolledIndex: number;
- @ViewChild('needsWorkFilterTemplate', {
- read: TemplateRef,
- static: true
- })
- private readonly _needsWorkFilterTemplate: TemplateRef;
- @ViewChild(TableComponent) private readonly _tableComponent: TableComponent;
-
- constructor(
- private readonly _router: Router,
- protected readonly _injector: Injector,
- private readonly _userService: UserService,
- readonly permissionsService: PermissionsService,
- private readonly _appStateService: AppStateService,
- private readonly _translateService: TranslateService,
- private readonly _dialogService: DossiersDialogService,
- private readonly _translateChartService: TranslateChartService,
- private readonly _userPreferenceService: UserPreferenceService
- ) {
- super(_injector);
- this._appStateService.reset();
- this._loadEntitiesFromState();
- }
-
- private get _activeDossiersCount(): number {
- return this.entitiesService.all.filter(p => p.status === DossierStatuses.ACTIVE).length;
- }
-
- private get _inactiveDossiersCount(): number {
- return this.entitiesService.all.length - this._activeDossiersCount;
- }
-
- getDossierTemplateNameFor(dossierTemplateId: string): string {
- return this._appStateService.getDossierTemplateById(dossierTemplateId).name;
- }
-
- ngOnInit(): void {
- this._configureTableColumns();
- this.calculateData();
-
- this.addSubscription = timer(0, 10000).subscribe(async () => {
- await this._appStateService.loadAllDossiers();
- this._loadEntitiesFromState();
- this.calculateData();
- });
-
- this.addSubscription = this._appStateService.fileChanged$.subscribe(() => {
- this.calculateData();
- });
- }
-
- ngAfterViewInit(): void {
- this.addSubscription = this._tableComponent.scrollViewport.scrolledIndexChange
- .pipe(tap(index => (this._lastScrolledIndex = index)))
- .subscribe();
- }
-
- ngOnAttach(): void {
- this._appStateService.reset();
- this._loadEntitiesFromState();
- this.ngOnInit();
- this.ngAfterViewInit();
- this._tableComponent.scrollViewport.scrollToIndex(this._lastScrolledIndex, 'smooth');
- }
-
- ngOnDetach(): void {
- this.ngOnDestroy();
- }
-
- openAddDossierDialog(): void {
- this._dialogService.openDialog('addDossier', null, null, async addResponse => {
- await this._router.navigate([`/main/dossiers/${addResponse.dossier.id}`]);
- if (addResponse.addMembers) {
- this._dialogService.openDialog('editDossier', null, {
- dossier: addResponse.dossier,
- section: 'members'
- });
- }
- });
- }
-
- calculateData(): void {
- this._computeAllFilters();
-
- this.dossiersChartData = [
- { value: this._activeDossiersCount, color: 'ACTIVE', label: _('active') },
- { value: this._inactiveDossiersCount, color: 'DELETED', label: _('archived') }
- ];
- const groups = groupBy(this._appStateService.aggregatedFiles, 'status');
- this.documentsChartData = [];
-
- for (const status of Object.keys(groups)) {
- this.documentsChartData.push({
- value: groups[status].length,
- color: status,
- label: fileStatusTranslations[status],
- key: status
- });
- }
- this.documentsChartData.sort(StatusSorter.byStatus);
- this.documentsChartData = this._translateChartService.translateStatus(this.documentsChartData);
- }
-
- private _configureTableColumns() {
- this.tableColumnConfigs = [
- {
- label: _('dossier-listing.table-col-names.name'),
- sortByKey: 'searchKey',
- template: this.nameTemplate,
- width: '2fr'
- },
- {
- label: _('dossier-listing.table-col-names.needs-work'),
- template: this.needsWorkTemplate
- },
- {
- label: _('dossier-listing.table-col-names.owner'),
- class: 'user-column',
- template: this.ownerTemplate
- },
- {
- label: _('dossier-listing.table-col-names.status'),
- class: 'flex-end',
- template: this.statusTemplate,
- width: 'auto'
- }
- ];
- }
-
- private _loadEntitiesFromState() {
- this.entitiesService.setEntities(this._appStateService.allDossiers);
- }
-
- private _computeAllFilters() {
- const allDistinctFileStatus = new Set();
- const allDistinctPeople = new Set();
- const allDistinctNeedsWork = new Set();
- const allDistinctDossierTemplates = new Set();
-
- this.entitiesService.all?.forEach(entry => {
- // all people
- entry.memberIds.forEach(f => allDistinctPeople.add(f));
- // Needs work
- entry.files.forEach(file => {
- allDistinctFileStatus.add(file.status);
- if (file.analysisRequired) {
- allDistinctNeedsWork.add('analysis');
- }
- if (entry.hintsOnly) {
- allDistinctNeedsWork.add('hint');
- }
- if (entry.hasRedactions) {
- allDistinctNeedsWork.add('redaction');
- }
- if (entry.hasSuggestions) {
- allDistinctNeedsWork.add('suggestion');
- }
- if (entry.hasNone) {
- allDistinctNeedsWork.add('none');
- }
- });
-
- allDistinctDossierTemplates.add(entry.dossierTemplateId);
- });
-
- const statusFilters = [...allDistinctFileStatus].map(
- status =>
- new NestedFilter({
- id: status,
- label: this._translateService.instant(fileStatusTranslations[status])
- })
- );
-
- this.filterService.addFilterGroup({
- slug: 'statusFilters',
- label: this._translateService.instant('filters.status'),
- icon: 'red:status',
- filters: statusFilters.sort((a, b) => StatusSorter[a.id] - StatusSorter[b.id]),
- checker: dossierStatusChecker
- });
-
- const peopleFilters = [...allDistinctPeople].map(
- userId =>
- new NestedFilter({
- id: userId,
- label: this._userService.getNameForId(userId)
- })
- );
-
- this.filterService.addFilterGroup({
- slug: 'peopleFilters',
- label: this._translateService.instant('filters.people'),
- icon: 'red:user',
- filters: peopleFilters,
- checker: dossierMemberChecker
- });
-
- const needsWorkFilters = [...allDistinctNeedsWork].map(
- type =>
- new NestedFilter({
- id: type,
- label: workloadTranslations[type]
- })
- );
-
- this.filterService.addFilterGroup({
- slug: 'needsWorkFilters',
- label: this._translateService.instant('filters.needs-work'),
- icon: 'red:needs-work',
- filterTemplate: this._needsWorkFilterTemplate,
- filters: needsWorkFilters.sort((a, b) => RedactionFilterSorter[a.id] - RedactionFilterSorter[b.id]),
- checker: annotationFilterChecker,
- matchAll: true
- });
-
- const dossierTemplateFilters = [...allDistinctDossierTemplates].map(
- id =>
- new NestedFilter({
- id: id,
- label: this._appStateService.getDossierTemplateById(id).name
- })
- );
-
- this.filterService.addFilterGroup({
- slug: 'dossierTemplateFilters',
- label: this._translateService.instant('filters.dossier-templates'),
- icon: 'red:template',
- hide: dossierTemplateFilters.length <= 1,
- filters: dossierTemplateFilters,
- checker: dossierTemplateChecker
- });
-
- const quickFilters = this._createQuickFilters();
- this.filterService.addFilterGroup({
- slug: 'quickFilters',
- filters: quickFilters,
- checker: (dw: Dossier) => quickFilters.reduce((acc, f) => acc || (f.checked && f.checker(dw)), false)
- });
-
- const dossierFilters = this.entitiesService.all.map(
- dossier =>
- new NestedFilter({
- id: dossier.dossierName,
- label: dossier.dossierName
- })
- );
- this.filterService.addFilterGroup({
- slug: 'dossierNameFilter',
- label: this._translateService.instant('dossier-listing.filters.label'),
- icon: 'red:folder',
- filters: dossierFilters,
- filterceptionPlaceholder: this._translateService.instant('dossier-listing.filters.search'),
- checker: keyChecker('dossierName')
- });
- }
-
- private _createQuickFilters(): NestedFilter[] {
- const myDossiersLabel = this._translateService.instant('dossier-listing.quick-filters.my-dossiers');
- const filters: NestedFilter[] = [
- {
- id: 'my-dossiers',
- label: myDossiersLabel,
- checker: (dw: Dossier) => dw.ownerId === this.currentUser.id
- },
- {
- id: 'to-approve',
- label: this._translateService.instant('dossier-listing.quick-filters.to-approve'),
- checker: (dw: Dossier) => dw.approverIds.includes(this.currentUser.id)
- },
- {
- id: 'to-review',
- label: this._translateService.instant('dossier-listing.quick-filters.to-review'),
- checker: (dw: Dossier) => dw.memberIds.includes(this.currentUser.id)
- },
- {
- id: 'other',
- label: this._translateService.instant('dossier-listing.quick-filters.other'),
- checker: (dw: Dossier) => !dw.memberIds.includes(this.currentUser.id)
- }
- ].map(filter => new NestedFilter(filter));
-
- return filters.filter(f => f.label === myDossiersLabel || this._userPreferenceService.areDevFeaturesEnabled);
- }
-}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.ts
deleted file mode 100644
index a75cf483d..000000000
--- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.ts
+++ /dev/null
@@ -1,601 +0,0 @@
-import {
- ChangeDetectorRef,
- Component,
- ElementRef,
- forwardRef,
- HostListener,
- Injector,
- OnDestroy,
- OnInit,
- TemplateRef,
- ViewChild
-} from '@angular/core';
-import { FileStatus, FileStatuses, IFileAttributeConfig } from '@redaction/red-ui-http';
-import { AppStateService } from '@state/app-state.service';
-import { FileDropOverlayService } from '@upload-download/services/file-drop-overlay.service';
-import { FileUploadModel } from '@upload-download/model/file-upload.model';
-import { FileUploadService } from '@upload-download/services/file-upload.service';
-import { StatusOverlayService } from '@upload-download/services/status-overlay.service';
-import { TranslateService } from '@ngx-translate/core';
-import * as moment from 'moment';
-import { DossierDetailsComponent } from '../../components/dossier-details/dossier-details.component';
-import { File } from '@models/file/file';
-import { UserService } from '@services/user.service';
-import { timer } from 'rxjs';
-import { tap } from 'rxjs/operators';
-import { RedactionFilterSorter } from '@utils/sorters/redaction-filter-sorter';
-import { StatusSorter } from '@utils/sorters/status-sorter';
-import { convertFiles, Files, handleFileDrop } from '@utils/file-drop-utils';
-import { DossiersDialogService } from '../../services/dossiers-dialog.service';
-import { OnAttach, OnDetach } from '@utils/custom-route-reuse.strategy';
-import { ConfigService } from '@services/config.service';
-import { ActionConfig } from '@shared/components/page-header/models/action-config.model';
-import {
- CircleButtonTypes,
- DefaultListingServices,
- INestedFilter,
- keyChecker,
- ListingComponent,
- ListingModes,
- LoadingService,
- NestedFilter,
- TableColumnConfig,
- TableComponent,
- Toaster,
- WorkflowConfig
-} from '@iqser/common-ui';
-import { DossierAttributesService } from '@shared/services/controller-wrappers/dossier-attributes.service';
-import { DossierAttributeWithValue } from '@models/dossier-attributes.model';
-import { workloadTranslations } from '../../translations/workload-translations';
-import { fileStatusTranslations } from '../../translations/file-status-translations';
-import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
-import { annotationFilterChecker } from '@utils/filter-utils';
-import { PermissionsService } from '@services/permissions.service';
-import { RouterHistoryService } from '@services/router-history.service';
-import { Dossier } from '@state/model/dossier';
-import { Router } from '@angular/router';
-import { FileActionService } from '../../services/file-action.service';
-import { FileAttributesService } from '../../services/file-attributes.service';
-
-@Component({
- templateUrl: './dossier-overview-screen.component.html',
- styleUrls: ['./dossier-overview-screen.component.scss'],
- providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DossierOverviewScreenComponent) }]
-})
-export class DossierOverviewScreenComponent extends ListingComponent implements OnInit, OnDestroy, OnDetach, OnAttach {
- readonly listingModes = ListingModes;
- readonly circleButtonTypes = CircleButtonTypes;
- readonly currentUser = this._userService.currentUser;
- currentDossier = this._appStateService.activeDossier;
- readonly tableHeaderLabel = _('dossier-overview.table-header.title');
- readonly actionConfigs: readonly ActionConfig[] = [
- {
- label: this._translateService.instant('dossier-overview.header-actions.edit'),
- action: ($event): void => this.openEditDossierDialog($event),
- icon: 'iqser:edit',
- hide: !this.currentUser.isManager
- }
- ];
- tableColumnConfigs: readonly TableColumnConfig[] = [];
- collapsedDetails = false;
- dossierAttributes: DossierAttributeWithValue[] = [];
- fileAttributeConfigs: IFileAttributeConfig[];
- @ViewChild('filenameTemplate', { static: true }) filenameTemplate: TemplateRef;
- @ViewChild('addedOnTemplate', { static: true }) addedOnTemplate: TemplateRef;
- @ViewChild('attributeTemplate', { static: true }) attributeTemplate: TemplateRef;
- @ViewChild('needsWorkTemplate', { static: true }) needsWorkTemplate: TemplateRef;
- @ViewChild('reviewerTemplate', { static: true }) reviewerTemplate: TemplateRef;
- @ViewChild('pagesTemplate', { static: true }) pagesTemplate: TemplateRef;
- @ViewChild('statusTemplate', { static: true }) statusTemplate: TemplateRef;
- readonly workflowConfig: WorkflowConfig;
- @ViewChild(DossierDetailsComponent, { static: false })
- private readonly _dossierDetailsComponent: DossierDetailsComponent;
- private _lastScrolledIndex: number;
- @ViewChild('needsWorkFilterTemplate', { read: TemplateRef, static: true })
- private readonly _needsWorkFilterTemplate: TemplateRef;
- @ViewChild('fileInput') private readonly _fileInput: ElementRef;
- @ViewChild(TableComponent) private readonly _tableComponent: TableComponent;
-
- constructor(
- private readonly _toaster: Toaster,
- protected readonly _injector: Injector,
- private readonly _router: Router,
- private readonly _userService: UserService,
- readonly permissionsService: PermissionsService,
- private readonly _loadingService: LoadingService,
- private readonly _appStateService: AppStateService,
- readonly routerHistoryService: RouterHistoryService,
- private readonly _configService: ConfigService,
- private readonly _translateService: TranslateService,
- private readonly _dialogService: DossiersDialogService,
- private readonly _changeDetectorRef: ChangeDetectorRef,
- private readonly _fileUploadService: FileUploadService,
- private readonly _statusOverlayService: StatusOverlayService,
- private readonly _fileDropOverlayService: FileDropOverlayService,
- private readonly _dossierAttributesService: DossierAttributesService,
- private readonly _fileActionService: FileActionService,
- private readonly _fileAttributesService: FileAttributesService
- ) {
- super(_injector);
- this._loadEntitiesFromState();
- this.fileAttributeConfigs = this._fileAttributesService.getFileAttributeConfig(
- this.currentDossier.dossierTemplateId
- )?.fileAttributeConfigs;
- this.workflowConfig = {
- columnIdentifierFn: entity => entity.status,
- itemVersionFn: (entity: File) => `${entity.lastUpdated}-${entity.numberOfAnalyses}`,
- columns: [
- {
- label: fileStatusTranslations[FileStatuses.UNASSIGNED],
- key: FileStatuses.UNASSIGNED,
- enterFn: this.unassignFn,
- enterPredicate: () => false,
- color: '#D3D5DA'
- },
- {
- label: fileStatusTranslations[FileStatuses.UNDER_REVIEW],
- enterFn: this.underReviewFn,
- enterPredicate: (file: File) =>
- this.permissionsService.canSetUnderReview(file) ||
- this.permissionsService.canAssignToSelf(file) ||
- this.permissionsService.canAssignUser(file),
- key: FileStatuses.UNDER_REVIEW,
- color: '#FDBD00'
- },
- {
- label: fileStatusTranslations[FileStatuses.UNDER_APPROVAL],
- enterFn: this.underApprovalFn,
- enterPredicate: (file: File) =>
- this.permissionsService.canSetUnderApproval(file) || this.permissionsService.canUndoApproval(file),
- key: FileStatuses.UNDER_APPROVAL,
- color: '#374C81'
- },
- {
- label: fileStatusTranslations[FileStatuses.APPROVED],
- enterFn: this.approveFn,
- enterPredicate: (file: File) => this.permissionsService.isReadyForApproval(file),
- key: FileStatuses.APPROVED,
- color: '#48C9F7'
- }
- ]
- };
- }
-
- get checkedRequiredFilters() {
- return this.filterService.getGroup('quickFilters')?.filters.filter(f => f.required && f.checked);
- }
-
- get checkedNotRequiredFilters() {
- return this.filterService.getGroup('quickFilters')?.filters.filter(f => !f.required && f.checked);
- }
-
- get displayedInFileListAttributes() {
- return this.fileAttributeConfigs?.filter(config => config.displayedInFileList) || [];
- }
-
- unassignFn = async (file: File) => {
- // TODO
- console.log('unassign', file);
- };
-
- underReviewFn = (file: File) => {
- this._fileActionService.assignFile('reviewer', null, file, () => this._loadingService.loadWhile(this.reloadDossiers()), true);
- };
-
- underApprovalFn = async (file: File) => {
- if (this._appStateService.activeDossier.approverIds.length > 1) {
- this._fileActionService.assignFile('approver', null, file, () => this._loadingService.loadWhile(this.reloadDossiers()), true);
- } else {
- this._loadingService.start();
- await this._fileActionService.setFilesUnderApproval([file]).toPromise();
- await this.reloadDossiers();
- this._loadingService.stop();
- }
- };
-
- approveFn = async (file: File) => {
- this._loadingService.start();
- await this._fileActionService.setFilesApproved([file]).toPromise();
- await this.reloadDossiers();
- this._loadingService.stop();
- };
-
- actionPerformed(action?: string, file?: File) {
- this.calculateData();
-
- if (action === 'navigate') {
- this._router.navigate([file.routerLink]);
- }
- }
-
- disabledFn = (fileStatus: File) => fileStatus.excluded;
-
- lastOpenedFn = (fileStatus: File) => fileStatus.lastOpened;
-
- async ngOnInit(): Promise {
- this._configureTableColumns();
- this._loadingService.start();
- try {
- this._fileDropOverlayService.initFileDropHandling();
-
- this.calculateData();
-
- this.addSubscription = timer(0, 7500).subscribe(async () => {
- await this._appStateService.reloadActiveDossierFilesIfNecessary();
- this._loadEntitiesFromState();
- });
-
- this.addSubscription = this._appStateService.fileChanged$.subscribe(() => {
- this.calculateData();
- });
-
- this.addSubscription = this._appStateService.dossierTemplateChanged$.subscribe(() => {
- this.fileAttributeConfigs = this._fileAttributesService.getFileAttributeConfig(
- this.currentDossier.dossierTemplateId
- )?.fileAttributeConfigs;
- });
-
- this.addSubscription = this._tableComponent.scrollViewport.scrolledIndexChange
- .pipe(tap(index => (this._lastScrolledIndex = index)))
- .subscribe();
-
- this.dossierAttributes = await this._dossierAttributesService.getValues(this.currentDossier);
- } catch (e) {
- console.log('Error from dossier overview screen: ', e);
- } finally {
- this._loadingService.stop();
- }
- }
-
- ngOnDestroy(): void {
- this._fileDropOverlayService.cleanupFileDropHandling();
- super.ngOnDestroy();
- }
-
- async ngOnAttach() {
- await this._appStateService.reloadActiveDossierFiles();
- this._loadEntitiesFromState();
- await this.ngOnInit();
- this._tableComponent.scrollViewport.scrollToIndex(this._lastScrolledIndex, 'smooth');
- }
-
- ngOnDetach() {
- this.ngOnDestroy();
- }
-
- async reanalyseDossier() {
- try {
- await this._appStateService.reanalyzeDossier();
- await this.reloadDossiers();
- this._toaster.success(_('dossier-overview.reanalyse-dossier.success'));
- } catch (e) {
- this._toaster.error(_('dossier-overview.reanalyse-dossier.error'));
- }
- }
-
- async reloadDossiers() {
- await this._appStateService.getFiles(this.currentDossier, false);
- this.calculateData();
- }
-
- calculateData(): void {
- if (!this._appStateService.activeDossierId) {
- return;
- }
-
- this._loadEntitiesFromState();
- this._computeAllFilters();
-
- this._dossierDetailsComponent?.calculateChartConfig();
- this._changeDetectorRef.detectChanges();
- }
-
- @HostListener('drop', ['$event'])
- onDrop(event: DragEvent): void {
- handleFileDrop(event, this.currentDossier, this._uploadFiles.bind(this));
- }
-
- @HostListener('dragover', ['$event'])
- onDragOver(event): void {
- event.stopPropagation();
- event.preventDefault();
- }
-
- async uploadFiles(files: Files): Promise {
- await this._uploadFiles(convertFiles(files, this.currentDossier));
- this._fileInput.nativeElement.value = null;
- }
-
- async bulkActionPerformed(): Promise {
- this.entitiesService.setSelected([]);
- await this.reloadDossiers();
- }
-
- openEditDossierDialog($event: MouseEvent) {
- this._dialogService.openDialog('editDossier', $event, {
- dossier: this.currentDossier
- });
- }
-
- openAssignDossierMembersDialog(): void {
- const data = { dossier: this.currentDossier, section: 'members' };
- this._dialogService.openDialog('editDossier', null, data, async () => await this.reloadDossiers());
- }
-
- openDossierDictionaryDialog() {
- const data = { dossier: this.currentDossier, section: 'dossierDictionary' };
- this._dialogService.openDialog('editDossier', null, data, async () => {
- await this.reloadDossiers();
- });
- }
-
- toggleCollapsedDetails() {
- this.collapsedDetails = !this.collapsedDetails;
- }
-
- recentlyModifiedChecker = (file: File) =>
- moment(file.lastUpdated).add(this._configService.values.RECENT_PERIOD_IN_HOURS, 'hours').isAfter(moment());
-
- private _configureTableColumns() {
- const dynamicColumns: TableColumnConfig[] = [];
- for (const config of this.displayedInFileListAttributes) {
- if (config.displayedInFileList) {
- dynamicColumns.push({ label: config.label, notTranslatable: true, template: this.attributeTemplate, extra: config });
- }
- }
- this.tableColumnConfigs = [
- {
- label: _('dossier-overview.table-col-names.name'),
- sortByKey: 'searchKey',
- template: this.filenameTemplate,
- width: '3fr'
- },
- {
- label: _('dossier-overview.table-col-names.added-on'),
- sortByKey: 'added',
- template: this.addedOnTemplate,
- width: '2fr'
- },
- ...dynamicColumns,
- {
- label: _('dossier-overview.table-col-names.needs-work'),
- template: this.needsWorkTemplate
- },
- {
- label: _('dossier-overview.table-col-names.assigned-to'),
- class: 'user-column',
- sortByKey: 'reviewerName',
- template: this.reviewerTemplate,
- width: '2fr'
- },
- {
- label: _('dossier-overview.table-col-names.pages'),
- sortByKey: 'numberOfPages',
- template: this.pagesTemplate
- },
- {
- label: _('dossier-overview.table-col-names.status'),
- class: 'flex-end',
- sortByKey: 'statusSort',
- template: this.statusTemplate
- }
- ];
- }
-
- private _loadEntitiesFromState() {
- this.currentDossier = this._appStateService.activeDossier;
- if (this.currentDossier) {
- this.entitiesService.setEntities(this.currentDossier.files);
- }
- }
-
- private async _uploadFiles(files: FileUploadModel[]) {
- const fileCount = await this._fileUploadService.uploadFiles(files);
- if (fileCount) {
- this._statusOverlayService.openUploadStatusOverlay();
- }
- }
-
- private _computeAllFilters() {
- if (!this.currentDossier) {
- return;
- }
-
- const allDistinctFileStatuses = new Set();
- const allDistinctPeople = new Set();
- const allDistinctAddedDates = new Set();
- const allDistinctNeedsWork = new Set();
-
- const dynamicFilters = new Map>();
-
- this.entitiesService.all.forEach(file => {
- allDistinctPeople.add(file.currentReviewer);
- allDistinctFileStatuses.add(file.status);
- allDistinctAddedDates.add(moment(file.added).format('DD/MM/YYYY'));
-
- if (file.analysisRequired) {
- allDistinctNeedsWork.add('analysis');
- }
- if (file.hintsOnly) {
- allDistinctNeedsWork.add('hint');
- }
- if (file.hasRedactions) {
- allDistinctNeedsWork.add('redaction');
- }
- if (file.hasSuggestions) {
- allDistinctNeedsWork.add('suggestion');
- }
- if (file.hasUpdates) {
- allDistinctNeedsWork.add('updated');
- }
- if (file.hasImages) {
- allDistinctNeedsWork.add('image');
- }
- if (file.hasNone) {
- allDistinctNeedsWork.add('none');
- }
- if (file.hasAnnotationComments) {
- allDistinctNeedsWork.add('comment');
- }
-
- // extract values for dynamic filters
- this.fileAttributeConfigs.forEach(config => {
- if (config.filterable) {
- const filterKey = `${config.id}:${config.label}`;
- let filters = dynamicFilters.get(filterKey);
- if (!filters) {
- dynamicFilters.set(filterKey, new Set());
- filters = dynamicFilters.get(filterKey);
- }
- let filterValue = file.fileAttributes?.attributeIdToValue[config.id];
- if (!filterValue) {
- filterValue = '-';
- file.fileAttributes.attributeIdToValue[config.id] = '-';
- }
- filters.add(filterValue);
- }
- });
- });
-
- const statusFilters = [...allDistinctFileStatuses].map(
- status =>
- new NestedFilter({
- id: status,
- label: this._translateService.instant(fileStatusTranslations[status])
- })
- );
-
- this.filterService.addFilterGroup({
- slug: 'statusFilters',
- label: this._translateService.instant('filters.status'),
- icon: 'red:status',
- filters: statusFilters.sort((a, b) => StatusSorter[a.id] - StatusSorter[b.id]),
- checker: keyChecker('status')
- });
-
- const peopleFilters: NestedFilter[] = [];
- if (allDistinctPeople.has(undefined) || allDistinctPeople.has(null)) {
- allDistinctPeople.delete(undefined);
- allDistinctPeople.delete(null);
- peopleFilters.push(
- new NestedFilter({
- id: null,
- label: this._translateService.instant('initials-avatar.unassigned')
- })
- );
- }
- allDistinctPeople.forEach(userId => {
- peopleFilters.push(
- new NestedFilter({
- id: userId,
- label: this._userService.getNameForId(userId)
- })
- );
- });
- this.filterService.addFilterGroup({
- slug: 'peopleFilters',
- label: this._translateService.instant('filters.assigned-people'),
- icon: 'red:user',
- filters: peopleFilters,
- checker: keyChecker('currentReviewer')
- });
-
- const needsWorkFilters = [...allDistinctNeedsWork].map(
- item =>
- new NestedFilter({
- id: item,
- label: workloadTranslations[item]
- })
- );
-
- this.filterService.addFilterGroup({
- slug: 'needsWorkFilters',
- label: this._translateService.instant('filters.needs-work'),
- icon: 'red:needs-work',
- filterTemplate: this._needsWorkFilterTemplate,
- filters: needsWorkFilters.sort(RedactionFilterSorter.byKey),
- checker: annotationFilterChecker,
- matchAll: true
- });
-
- dynamicFilters.forEach((filterValue: Set, filterKey: string) => {
- const id = filterKey.split(':')[0];
- const key = filterKey.split(':')[1];
- this.filterService.addFilterGroup({
- slug: key,
- label: key,
- icon: 'red:template',
- filters: [...filterValue].map(
- (value: string) =>
- new NestedFilter({
- id: value,
- label: value === '-' ? this._translateService.instant('filters.empty') : value
- })
- ),
- checker: (input: File, filter: INestedFilter) => filter.id === input.fileAttributes.attributeIdToValue[id]
- });
- });
-
- this.filterService.addFilterGroup({
- slug: 'quickFilters',
- filters: this._createQuickFilters(),
- checker: (file: File) =>
- this.checkedRequiredFilters.reduce((acc, f) => acc && f.checker(file), true) &&
- (this.checkedNotRequiredFilters.length === 0 ||
- this.checkedNotRequiredFilters.reduce((acc, f) => acc || f.checker(file), false))
- });
-
- const filesNamesFilters = this.entitiesService.all.map(
- file =>
- new NestedFilter({
- id: file.filename,
- label: file.filename
- })
- );
-
- this.filterService.addFilterGroup({
- slug: 'filesNamesFilter',
- label: this._translateService.instant('dossier-overview.filters.label'),
- icon: 'red:document',
- filters: filesNamesFilters,
- checker: keyChecker('filename'),
- filterceptionPlaceholder: this._translateService.instant('dossier-overview.filters.search')
- });
- }
-
- private _createQuickFilters(): NestedFilter[] {
- let quickFilters: INestedFilter[] = [];
- if (this.entitiesService.all.filter(this.recentlyModifiedChecker).length > 0) {
- const recentPeriod = this._configService.values.RECENT_PERIOD_IN_HOURS;
- quickFilters = [
- {
- id: 'recent',
- label: this._translateService.instant('dossier-overview.quick-filters.recent', {
- hours: recentPeriod
- }),
- required: true,
- checker: this.recentlyModifiedChecker
- }
- ];
- }
-
- return [
- ...quickFilters,
- {
- id: 'assigned-to-me',
- label: this._translateService.instant('dossier-overview.quick-filters.assigned-to-me'),
- checker: (file: File) => file.currentReviewer === this.currentUser.id
- },
- {
- id: 'unassigned',
- label: this._translateService.instant('dossier-overview.quick-filters.unassigned'),
- checker: (file: File) => !file.currentReviewer
- },
- {
- id: 'assigned-to-others',
- label: this._translateService.instant('dossier-overview.quick-filters.assigned-to-others'),
- checker: (file: File) => !!file.currentReviewer && file.currentReviewer !== this.currentUser.id
- }
- ].map(filter => new NestedFilter(filter));
- }
-}
diff --git a/apps/red-ui/src/app/modules/dossier/components/bulk-actions/dossier-overview-bulk-actions.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.html
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/bulk-actions/dossier-overview-bulk-actions.component.html
rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.html
diff --git a/apps/red-ui/src/app/modules/dossier/components/bulk-actions/dossier-overview-bulk-actions.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.scss
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/bulk-actions/dossier-overview-bulk-actions.component.scss
rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.scss
diff --git a/apps/red-ui/src/app/modules/dossier/components/bulk-actions/dossier-overview-bulk-actions.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.ts
similarity index 94%
rename from apps/red-ui/src/app/modules/dossier/components/bulk-actions/dossier-overview-bulk-actions.component.ts
rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.ts
index f98e39318..8f2b6f6eb 100644
--- a/apps/red-ui/src/app/modules/dossier/components/bulk-actions/dossier-overview-bulk-actions.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/bulk-actions/dossier-overview-bulk-actions.component.ts
@@ -1,13 +1,13 @@
import { Component, EventEmitter, Output } from '@angular/core';
-import { AppStateService } from '@state/app-state.service';
+import { AppStateService } from '../../../../../../state/app-state.service';
import { FileManagementControllerService, ReanalysisControllerService } from '@redaction/red-ui-http';
-import { PermissionsService } from '@services/permissions.service';
-import { File } from '@models/file/file';
-import { FileActionService } from '../../services/file-action.service';
+import { PermissionsService } from '../../../../../../services/permissions.service';
+import { File } from '../../../../../../models/file/file';
+import { FileActionService } from '../../../../shared/services/file-action.service';
import { Observable } from 'rxjs';
-import { DossiersDialogService } from '../../services/dossiers-dialog.service';
+import { DossiersDialogService } from '../../../../services/dossiers-dialog.service';
import { CircleButtonTypes, EntitiesService, LoadingService } from '@iqser/common-ui';
-import { ConfirmationDialogInput } from '@shared/dialogs/confirmation-dialog/confirmation-dialog.component';
+import { ConfirmationDialogInput } from '../../../../../shared/dialogs/confirmation-dialog/confirmation-dialog.component';
import { TranslateService } from '@ngx-translate/core';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.html
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.html
rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.html
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.scss
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.scss
rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.scss
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.ts
similarity index 93%
rename from apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.ts
rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.ts
index 045dec7e8..dcfb93f0e 100644
--- a/apps/red-ui/src/app/modules/dossier/components/dossier-details-stats/dossier-details-stats.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.ts
@@ -3,7 +3,7 @@ import { DossierAttributeWithValue } from '@models/dossier-attributes.model';
import { AppStateService } from '@state/app-state.service';
import { Dossier } from '@state/model/dossier';
import { IDossierTemplate } from '@redaction/red-ui-http';
-import { DossiersDialogService } from '../../services/dossiers-dialog.service';
+import { DossiersDialogService } from '../../../../services/dossiers-dialog.service';
@Component({
selector: 'redaction-dossier-details-stats',
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details/dossier-details.component.html
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.html
rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details/dossier-details.component.html
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details/dossier-details.component.scss
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.scss
rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details/dossier-details.component.scss
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details/dossier-details.component.ts
similarity index 95%
rename from apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.ts
rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details/dossier-details.component.ts
index 6d1fa343f..c291dce12 100644
--- a/apps/red-ui/src/app/modules/dossier/components/dossier-details/dossier-details.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/dossier-details/dossier-details.component.ts
@@ -1,13 +1,12 @@
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { AppStateService } from '@state/app-state.service';
-import { groupBy } from '@utils/functions';
+import { groupBy, StatusSorter } from '@utils/index';
import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component';
import { TranslateChartService } from '@services/translate-chart.service';
-import { StatusSorter } from '@utils/sorters/status-sorter';
import { UserService } from '@services/user.service';
import { FilterService, Toaster } from '@iqser/common-ui';
import { DossierAttributeWithValue } from '@models/dossier-attributes.model';
-import { fileStatusTranslations } from '../../translations/file-status-translations';
+import { fileStatusTranslations } from '../../../../translations/file-status-translations';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { List } from '@redaction/red-ui-http';
import { User } from '@models/user';
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.html
new file mode 100644
index 000000000..43de75f4a
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.html
@@ -0,0 +1,70 @@
+;
+ @Input() @Required() displayedAttributes!: IFileAttributeConfig[];
+ @Output() readonly calculateData = new EventEmitter();
+
+ constructor() {}
+}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/config.service.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/config.service.ts
new file mode 100644
index 000000000..5c390ea88
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/config.service.ts
@@ -0,0 +1,364 @@
+import { Injectable, TemplateRef } from '@angular/core';
+import { IFilterGroup, INestedFilter, keyChecker, LoadingService, NestedFilter, TableColumnConfig, WorkflowConfig } from '@iqser/common-ui';
+import { File } from '@models/file/file';
+import { fileStatusTranslations } from '../../translations/file-status-translations';
+import { FileStatus, FileStatuses, IFileAttributeConfig } from '@redaction/red-ui-http';
+import { FileActionService } from '../../shared/services/file-action.service';
+import { AppStateService } from '@state/app-state.service';
+import { PermissionsService } from '@services/permissions.service';
+import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
+import { TranslateService } from '@ngx-translate/core';
+import { UserService } from '@services/user.service';
+import { DossiersDialogService } from '../../services/dossiers-dialog.service';
+import { annotationFilterChecker, RedactionFilterSorter, StatusSorter } from '@utils/index';
+import { workloadTranslations } from '../../translations/workload-translations';
+import * as moment from 'moment';
+import { ConfigService as AppConfigService } from '@services/config.service';
+
+@Injectable()
+export class ConfigService {
+ constructor(
+ private readonly _fileActionService: FileActionService,
+ private readonly _loadingService: LoadingService,
+ private readonly _appStateService: AppStateService,
+ private readonly _permissionsService: PermissionsService,
+ private readonly _translateService: TranslateService,
+ private readonly _userService: UserService,
+ private readonly _dialogService: DossiersDialogService,
+ private readonly _appConfigService: AppConfigService
+ ) {}
+
+ get actionConfig() {
+ return [
+ {
+ label: this._translateService.instant('dossier-overview.header-actions.edit'),
+ action: $event => this._openEditDossierDialog($event),
+ icon: 'iqser:edit',
+ hide: !this._userService.currentUser.isManager
+ }
+ ];
+ }
+
+ tableConfig(displayedAttributes: IFileAttributeConfig[]): TableColumnConfig[] {
+ const dynamicColumns: TableColumnConfig[] = displayedAttributes.map(config => ({
+ label: config.label,
+ notTranslatable: true
+ }));
+ return [
+ {
+ label: _('dossier-overview.table-col-names.name'),
+ sortByKey: 'searchKey',
+ width: '3fr'
+ },
+ {
+ label: _('dossier-overview.table-col-names.added-on'),
+ sortByKey: 'added',
+ width: '2fr'
+ },
+ ...dynamicColumns,
+ {
+ label: _('dossier-overview.table-col-names.needs-work')
+ },
+ {
+ label: _('dossier-overview.table-col-names.assigned-to'),
+ class: 'user-column',
+ sortByKey: 'reviewerName',
+ width: '2fr'
+ },
+ {
+ label: _('dossier-overview.table-col-names.pages'),
+ sortByKey: 'numberOfPages'
+ },
+ {
+ label: _('dossier-overview.table-col-names.status'),
+ class: 'flex-end',
+ sortByKey: 'statusSort'
+ }
+ ];
+ }
+
+ workflowConfig(reloadDossiers: () => Promise): WorkflowConfig {
+ return {
+ columnIdentifierFn: entity => entity.status,
+ itemVersionFn: (entity: File) => `${entity.lastUpdated}-${entity.numberOfAnalyses}`,
+ columns: [
+ {
+ label: fileStatusTranslations[FileStatuses.UNASSIGNED],
+ key: FileStatuses.UNASSIGNED,
+ enterFn: this._unassignFn(reloadDossiers),
+ enterPredicate: () => false,
+ color: '#D3D5DA'
+ },
+ {
+ label: fileStatusTranslations[FileStatuses.UNDER_REVIEW],
+ enterFn: this._underReviewFn(reloadDossiers),
+ enterPredicate: (file: File) =>
+ this._permissionsService.canSetUnderReview(file) ||
+ this._permissionsService.canAssignToSelf(file) ||
+ this._permissionsService.canAssignUser(file),
+ key: FileStatuses.UNDER_REVIEW,
+ color: '#FDBD00'
+ },
+ {
+ label: fileStatusTranslations[FileStatuses.UNDER_APPROVAL],
+ enterFn: this._underApprovalFn(reloadDossiers),
+ enterPredicate: (file: File) =>
+ this._permissionsService.canSetUnderApproval(file) || this._permissionsService.canUndoApproval(file),
+ key: FileStatuses.UNDER_APPROVAL,
+ color: '#374C81'
+ },
+ {
+ label: fileStatusTranslations[FileStatuses.APPROVED],
+ enterFn: this._approveFn(reloadDossiers),
+ enterPredicate: (file: File) => this._permissionsService.isReadyForApproval(file) && file.canBeApproved,
+ key: FileStatuses.APPROVED,
+ color: '#48C9F7'
+ }
+ ]
+ };
+ }
+
+ filterGroups(
+ entities: File[],
+ fileAttributeConfigs: IFileAttributeConfig[],
+ needsWorkFilterTemplate: TemplateRef,
+ checkedRequiredFilters: () => NestedFilter[],
+ checkedNotRequiredFilters: () => NestedFilter[]
+ ) {
+ const allDistinctFileStatuses = new Set();
+ const allDistinctPeople = new Set();
+ const allDistinctAddedDates = new Set();
+ const allDistinctNeedsWork = new Set();
+
+ const dynamicFilters = new Map>();
+
+ const filterGroups: IFilterGroup[] = [];
+
+ entities.forEach(file => {
+ allDistinctPeople.add(file.currentReviewer);
+ allDistinctFileStatuses.add(file.status);
+ allDistinctAddedDates.add(moment(file.added).format('DD/MM/YYYY'));
+
+ if (file.analysisRequired) {
+ allDistinctNeedsWork.add('analysis');
+ }
+ if (file.hintsOnly) {
+ allDistinctNeedsWork.add('hint');
+ }
+ if (file.hasRedactions) {
+ allDistinctNeedsWork.add('redaction');
+ }
+ if (file.hasSuggestions) {
+ allDistinctNeedsWork.add('suggestion');
+ }
+ if (file.hasUpdates) {
+ allDistinctNeedsWork.add('updated');
+ }
+ if (file.hasImages) {
+ allDistinctNeedsWork.add('image');
+ }
+ if (file.hasNone) {
+ allDistinctNeedsWork.add('none');
+ }
+ if (file.hasAnnotationComments) {
+ allDistinctNeedsWork.add('comment');
+ }
+
+ // extract values for dynamic filters
+ fileAttributeConfigs.forEach(config => {
+ if (config.filterable) {
+ const filterKey = `${config.id}:${config.label}`;
+ let filters = dynamicFilters.get(filterKey);
+ if (!filters) {
+ dynamicFilters.set(filterKey, new Set());
+ filters = dynamicFilters.get(filterKey);
+ }
+ let filterValue = file.fileAttributes?.attributeIdToValue[config.id];
+ if (!filterValue) {
+ filterValue = '-';
+ file.fileAttributes.attributeIdToValue[config.id] = '-';
+ }
+ filters.add(filterValue);
+ }
+ });
+ });
+
+ const statusFilters = [...allDistinctFileStatuses].map(
+ status =>
+ new NestedFilter({
+ id: status,
+ label: this._translateService.instant(fileStatusTranslations[status])
+ })
+ );
+
+ filterGroups.push({
+ slug: 'statusFilters',
+ label: this._translateService.instant('filters.status'),
+ icon: 'red:status',
+ filters: statusFilters.sort((a, b) => StatusSorter[a.id] - StatusSorter[b.id]),
+ checker: keyChecker('status')
+ });
+
+ const peopleFilters: NestedFilter[] = [];
+ if (allDistinctPeople.has(undefined) || allDistinctPeople.has(null)) {
+ allDistinctPeople.delete(undefined);
+ allDistinctPeople.delete(null);
+ peopleFilters.push(
+ new NestedFilter({
+ id: null,
+ label: this._translateService.instant('initials-avatar.unassigned')
+ })
+ );
+ }
+ allDistinctPeople.forEach(userId => {
+ peopleFilters.push(
+ new NestedFilter({
+ id: userId,
+ label: this._userService.getNameForId(userId)
+ })
+ );
+ });
+ filterGroups.push({
+ slug: 'peopleFilters',
+ label: this._translateService.instant('filters.assigned-people'),
+ icon: 'red:user',
+ filters: peopleFilters,
+ checker: keyChecker('currentReviewer')
+ });
+
+ const needsWorkFilters = [...allDistinctNeedsWork].map(
+ item =>
+ new NestedFilter({
+ id: item,
+ label: workloadTranslations[item]
+ })
+ );
+
+ filterGroups.push({
+ slug: 'needsWorkFilters',
+ label: this._translateService.instant('filters.needs-work'),
+ icon: 'red:needs-work',
+ filterTemplate: needsWorkFilterTemplate,
+ filters: needsWorkFilters.sort(RedactionFilterSorter.byKey),
+ checker: annotationFilterChecker,
+ matchAll: true
+ });
+
+ dynamicFilters.forEach((filterValue: Set, filterKey: string) => {
+ const id = filterKey.split(':')[0];
+ const key = filterKey.split(':')[1];
+ filterGroups.push({
+ slug: key,
+ label: key,
+ icon: 'red:template',
+ filters: [...filterValue].map(
+ (value: string) =>
+ new NestedFilter({
+ id: value,
+ label: value === '-' ? this._translateService.instant('filters.empty') : value
+ })
+ ),
+ checker: (input: File, filter: INestedFilter) => filter.id === input.fileAttributes.attributeIdToValue[id]
+ });
+ });
+
+ filterGroups.push({
+ slug: 'quickFilters',
+ filters: this._quickFilters(entities),
+ checker: (file: File) =>
+ checkedRequiredFilters().reduce((acc, f) => acc && f.checker(file), true) &&
+ (checkedNotRequiredFilters().length === 0 || checkedNotRequiredFilters().reduce((acc, f) => acc || f.checker(file), false))
+ });
+
+ const filesNamesFilters = entities.map(
+ file =>
+ new NestedFilter({
+ id: file.filename,
+ label: file.filename
+ })
+ );
+
+ filterGroups.push({
+ slug: 'filesNamesFilter',
+ label: this._translateService.instant('dossier-overview.filters.label'),
+ icon: 'red:document',
+ filters: filesNamesFilters,
+ checker: keyChecker('filename'),
+ filterceptionPlaceholder: this._translateService.instant('dossier-overview.filters.search')
+ });
+
+ return filterGroups;
+ }
+
+ _recentlyModifiedChecker = (file: File) =>
+ moment(file.lastUpdated).add(this._appConfigService.values.RECENT_PERIOD_IN_HOURS, 'hours').isAfter(moment());
+
+ private _quickFilters(entities: File[]): NestedFilter[] {
+ let quickFilters: INestedFilter[] = [];
+ if (entities.filter(this._recentlyModifiedChecker).length > 0) {
+ const recentPeriod = this._appConfigService.values.RECENT_PERIOD_IN_HOURS;
+ quickFilters = [
+ {
+ id: 'recent',
+ label: this._translateService.instant('dossier-overview.quick-filters.recent', {
+ hours: recentPeriod
+ }),
+ required: true,
+ checker: this._recentlyModifiedChecker
+ }
+ ];
+ }
+
+ return [
+ ...quickFilters,
+ {
+ id: 'assigned-to-me',
+ label: this._translateService.instant('dossier-overview.quick-filters.assigned-to-me'),
+ checker: (file: File) => file.currentReviewer === this._userService.currentUser.id
+ },
+ {
+ id: 'unassigned',
+ label: this._translateService.instant('dossier-overview.quick-filters.unassigned'),
+ checker: (file: File) => !file.currentReviewer
+ },
+ {
+ id: 'assigned-to-others',
+ label: this._translateService.instant('dossier-overview.quick-filters.assigned-to-others'),
+ checker: (file: File) => !!file.currentReviewer && file.currentReviewer !== this._userService.currentUser.id
+ }
+ ].map(filter => new NestedFilter(filter));
+ }
+
+ private _openEditDossierDialog($event: MouseEvent) {
+ this._dialogService.openDialog('editDossier', $event, {
+ dossier: this._appStateService.activeDossier
+ });
+ }
+
+ private _unassignFn = (reloadDossiers: () => Promise) => async (file: File) => {
+ // TODO
+ console.log('unassign', file);
+ };
+
+ private _underReviewFn = (reloadDossiers: () => Promise) => (file: File) => {
+ this._fileActionService.assignFile('reviewer', null, file, () => this._loadingService.loadWhile(reloadDossiers()), true);
+ };
+
+ private _underApprovalFn = (reloadDossiers: () => Promise) => async (file: File) => {
+ if (this._appStateService.activeDossier.approverIds.length > 1) {
+ this._fileActionService.assignFile('approver', null, file, () => this._loadingService.loadWhile(reloadDossiers()), true);
+ } else {
+ this._loadingService.start();
+ await this._fileActionService.setFilesUnderApproval([file]).toPromise();
+ await reloadDossiers();
+ this._loadingService.stop();
+ }
+ };
+
+ private _approveFn = (reloadDossiers: () => Promise) => async (file: File) => {
+ this._loadingService.start();
+ await this._fileActionService.setFilesApproved([file]).toPromise();
+ await reloadDossiers();
+ this._loadingService.stop();
+ };
+}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/dossier-overview.module.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/dossier-overview.module.ts
new file mode 100644
index 000000000..76b7ee087
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/dossier-overview.module.ts
@@ -0,0 +1,34 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { RouterModule } from '@angular/router';
+import { SharedModule } from '@shared/shared.module';
+import { IqserIconsModule } from '@iqser/common-ui';
+import { TranslateModule } from '@ngx-translate/core';
+import { DossierOverviewScreenComponent } from './screen/dossier-overview-screen.component';
+import { DossierOverviewBulkActionsComponent } from './components/bulk-actions/dossier-overview-bulk-actions.component';
+import { DossierDetailsComponent } from './components/dossier-details/dossier-details.component';
+import { DossierDetailsStatsComponent } from './components/dossier-details-stats/dossier-details-stats.component';
+import { TableItemComponent } from './components/table-item/table-item.component';
+import { ConfigService } from './config.service';
+import { SharedDossiersModule } from '../../shared/shared-dossiers.module';
+
+const routes = [
+ {
+ path: '',
+ component: DossierOverviewScreenComponent,
+ pathMatch: 'full'
+ }
+];
+
+@NgModule({
+ declarations: [
+ DossierOverviewScreenComponent,
+ DossierOverviewBulkActionsComponent,
+ DossierDetailsComponent,
+ DossierDetailsStatsComponent,
+ TableItemComponent
+ ],
+ providers: [ConfigService],
+ imports: [RouterModule.forChild(routes), CommonModule, SharedModule, SharedDossiersModule, IqserIconsModule, TranslateModule]
+})
+export class DossierOverviewModule {}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html
similarity index 66%
rename from apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.html
rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html
index fb56c35c2..d85606bcb 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.html
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.html
@@ -91,95 +91,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
{{ file.restoreDate | date: 'timeFromNow' }}
-
-
-
-
+
diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.scss b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.scss
index d7bf4a0af..305ab6377 100644
--- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.scss
+++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.scss
@@ -9,8 +9,8 @@
:host ::ng-deep iqser-table cdk-virtual-scroll-viewport {
height: calc(100% - 81px) !important;
-
- .cdk-virtual-scroll-content-wrapper .table-item > div.cell.filename span {
- @include common-mixins.line-clamp(1);
- }
+}
+
+.cell.filename span {
+ @include common-mixins.line-clamp(1);
}
diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.ts
index 920cff75e..f408458d9 100644
--- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component.ts
@@ -1,4 +1,4 @@
-import { Component, EventEmitter, forwardRef, Injector, Input, OnInit, Output, TemplateRef, ViewChild } from '@angular/core';
+import { Component, EventEmitter, forwardRef, Injector, Input, OnInit, Output } from '@angular/core';
import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { Dossier } from '@state/model/dossier';
import {
@@ -42,14 +42,15 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent
+
+
+
+
+ {{ file.numberOfPages }}
+
+
+ {{ file.softDeleted | date: 'exactDate' }}
+
+
+
+
{{ file.restoreDate | date: 'timeFromNow' }}
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
- {{ dossier.dossierName }}
-
-
-
-
-
- {{ getDossierTemplateNameFor(dossier.dossierTemplateId) }}
-
-
-
-
-
- {{ dossier.filesLength }}
-
-
-
- {{ dossier.totalNumberOfPages }}
-
-
-
- {{ dossier.memberIds.length }}
-
-
-
- {{ dossier.date | date: 'mediumDate' }}
-
-
-
- {{ dossier.dueDate | date: 'mediumDate' }}
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+ {{ file.filename }}
+
+
+
+
+
+ {{ file.primaryAttribute }}
+
+
+
+
+
+
+ {{ file.added | date: 'd MMM. yyyy, hh:mm a' }}
+
+
+ {{ file.fileAttributes.attributeIdToValue[config.id] }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ file.numberOfPages }}
+
+
+
+
+
+
+
+
+
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.scss
new file mode 100644
index 000000000..8450b2bf1
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.scss
@@ -0,0 +1,26 @@
+@use 'common-mixins';
+@use 'variables';
+
+.cell {
+ .error {
+ color: variables.$primary;
+ }
+
+ .table-item-title {
+ max-width: 25vw;
+ }
+
+ .primary-attribute {
+ padding-top: 6px;
+ @include common-mixins.line-clamp(1);
+ }
+
+ &.extend-cols {
+ grid-column-end: span 3;
+ align-items: flex-end;
+ }
+
+ &.status-container {
+ align-items: flex-end;
+ }
+}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.ts
new file mode 100644
index 000000000..3507e73cb
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/components/table-item/table-item.component.ts
@@ -0,0 +1,19 @@
+import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output, TemplateRef } from '@angular/core';
+import { File } from '@models/file/file';
+import { Required } from '@iqser/common-ui';
+import { IFileAttributeConfig } from '@redaction/red-ui-http';
+
+@Component({
+ selector: 'redaction-table-item',
+ templateUrl: './table-item.component.html',
+ styleUrls: ['./table-item.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class TableItemComponent {
+ @Input() @Required() file!: File;
+ @Input() @Required() statsTemplate!: TemplateRef
-
-
-
-
-
- {{ file.filename }}
-
-
-
-
-
- {{ file.primaryAttribute }}
-
-
-
-
-
- {{ file.added | date: 'd MMM. yyyy, hh:mm a' }}
-
-
- {{ file.fileAttributes.attributeIdToValue[config.id] }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {{ file.numberOfPages }}
-
-
-
-
-
-
-
-
-
-
@@ -199,6 +110,15 @@
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.scss
similarity index 77%
rename from apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.scss
rename to apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.scss
index 5359d5727..501b10239 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview-screen/dossier-overview-screen.component.scss
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.scss
@@ -7,39 +7,17 @@
:host ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item {
&.last-opened {
- > .selection-column {
+ .selection-column {
padding-left: 6px !important;
border-left: 4px solid variables.$primary;
}
- > div {
+ .selection-column,
+ .cell,
+ .scrollbar-placeholder {
animation: red-fading-background 3s 1;
}
}
-
- > div.cell {
- .error {
- color: variables.$primary;
- }
-
- .table-item-title {
- max-width: 25vw;
- }
-
- .primary-attribute {
- padding-top: 6px;
- @include common-mixins.line-clamp(1);
- }
-
- &.extend-cols {
- grid-column-end: span 3;
- align-items: flex-end;
- }
-
- &.status-container {
- align-items: flex-end;
- }
- }
}
.right-container {
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.ts
new file mode 100644
index 000000000..87ffe450e
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossier-overview/screen/dossier-overview-screen.component.ts
@@ -0,0 +1,280 @@
+import {
+ ChangeDetectorRef,
+ Component,
+ ElementRef,
+ forwardRef,
+ HostListener,
+ Injector,
+ OnDestroy,
+ OnInit,
+ TemplateRef,
+ ViewChild
+} from '@angular/core';
+import { FileStatus, IFileAttributeConfig } from '@redaction/red-ui-http';
+import { AppStateService } from '@state/app-state.service';
+import { FileDropOverlayService } from '@upload-download/services/file-drop-overlay.service';
+import { FileUploadModel } from '@upload-download/model/file-upload.model';
+import { FileUploadService } from '@upload-download/services/file-upload.service';
+import { StatusOverlayService } from '@upload-download/services/status-overlay.service';
+import { TranslateService } from '@ngx-translate/core';
+import * as moment from 'moment';
+import { DossierDetailsComponent } from '../components/dossier-details/dossier-details.component';
+import { File } from '@models/file/file';
+import { UserService } from '@services/user.service';
+import { timer } from 'rxjs';
+import { tap } from 'rxjs/operators';
+import { convertFiles, Files, handleFileDrop, OnAttach, OnDetach } from '@utils/index';
+import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
+import { ActionConfig } from '@shared/components/page-header/models/action-config.model';
+import {
+ CircleButtonTypes,
+ DefaultListingServices,
+ ListingComponent,
+ ListingModes,
+ LoadingService,
+ NestedFilter,
+ TableColumnConfig,
+ TableComponent,
+ Toaster,
+ WorkflowConfig
+} from '@iqser/common-ui';
+import { DossierAttributesService } from '@shared/services/controller-wrappers/dossier-attributes.service';
+import { DossierAttributeWithValue } from '@models/dossier-attributes.model';
+import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
+import { PermissionsService } from '@services/permissions.service';
+import { RouterHistoryService } from '@services/router-history.service';
+import { Dossier } from '@state/model/dossier';
+import { Router } from '@angular/router';
+import { FileAttributesService } from '../../../services/file-attributes.service';
+import { ConfigService as AppConfigService } from '@services/config.service';
+import { ConfigService } from '../config.service';
+
+@Component({
+ templateUrl: './dossier-overview-screen.component.html',
+ styleUrls: ['./dossier-overview-screen.component.scss'],
+ providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DossierOverviewScreenComponent) }]
+})
+export class DossierOverviewScreenComponent extends ListingComponent implements OnInit, OnDestroy, OnDetach, OnAttach {
+ readonly listingModes = ListingModes;
+ readonly circleButtonTypes = CircleButtonTypes;
+ readonly currentUser = this._userService.currentUser;
+ currentDossier = this._appStateService.activeDossier;
+ readonly tableHeaderLabel = _('dossier-overview.table-header.title');
+ collapsedDetails = false;
+ dossierAttributes: DossierAttributeWithValue[] = [];
+ fileAttributeConfigs: IFileAttributeConfig[];
+ tableColumnConfigs: readonly TableColumnConfig[];
+ readonly workflowConfig: WorkflowConfig = this._configService.workflowConfig(() => this.reloadDossiers());
+ readonly actionConfigs: readonly ActionConfig[] = this._configService.actionConfig;
+ @ViewChild(DossierDetailsComponent, { static: false }) private readonly _dossierDetailsComponent: DossierDetailsComponent;
+ private _lastScrolledIndex: number;
+ @ViewChild('needsWorkFilterTemplate', { read: TemplateRef, static: true })
+ private readonly _needsWorkFilterTemplate: TemplateRef;
+ @ViewChild('fileInput') private readonly _fileInput: ElementRef;
+ @ViewChild(TableComponent) private readonly _tableComponent: TableComponent;
+
+ constructor(
+ private readonly _toaster: Toaster,
+ protected readonly _injector: Injector,
+ private readonly _router: Router,
+ private readonly _userService: UserService,
+ readonly permissionsService: PermissionsService,
+ private readonly _loadingService: LoadingService,
+ private readonly _appStateService: AppStateService,
+ readonly routerHistoryService: RouterHistoryService,
+ private readonly _appConfigService: AppConfigService,
+ private readonly _translateService: TranslateService,
+ private readonly _dialogService: DossiersDialogService,
+ private readonly _changeDetectorRef: ChangeDetectorRef,
+ private readonly _fileUploadService: FileUploadService,
+ private readonly _statusOverlayService: StatusOverlayService,
+ private readonly _fileDropOverlayService: FileDropOverlayService,
+ private readonly _dossierAttributesService: DossierAttributesService,
+ private readonly _fileAttributesService: FileAttributesService,
+ private readonly _configService: ConfigService
+ ) {
+ super(_injector);
+ this._loadEntitiesFromState();
+ this.fileAttributeConfigs = this._fileAttributesService.getFileAttributeConfig(
+ this.currentDossier.dossierTemplateId
+ )?.fileAttributeConfigs;
+ this.tableColumnConfigs = this._configService.tableConfig(this.displayedAttributes);
+ }
+
+ get checkedRequiredFilters(): NestedFilter[] {
+ return this.filterService.getGroup('quickFilters')?.filters.filter(f => f.required && f.checked);
+ }
+
+ get checkedNotRequiredFilters(): NestedFilter[] {
+ return this.filterService.getGroup('quickFilters')?.filters.filter(f => !f.required && f.checked);
+ }
+
+ get displayedInFileListAttributes() {
+ return this.fileAttributeConfigs?.filter(config => config.displayedInFileList) || [];
+ }
+
+ get displayedAttributes(): IFileAttributeConfig[] {
+ return this.displayedInFileListAttributes.filter(c => c.displayedInFileList);
+ }
+
+ actionPerformed(action?: string, file?: File) {
+ this.calculateData();
+
+ if (action === 'navigate') {
+ this._router.navigate([file.routerLink]);
+ }
+ }
+
+ disabledFn = (fileStatus: File) => fileStatus.excluded;
+
+ lastOpenedFn = (fileStatus: File) => fileStatus.lastOpened;
+
+ async ngOnInit(): Promise {
+ this._loadingService.start();
+ try {
+ this._fileDropOverlayService.initFileDropHandling();
+
+ this.calculateData();
+
+ this.addSubscription = timer(0, 7500).subscribe(async () => {
+ await this._appStateService.reloadActiveDossierFilesIfNecessary();
+ this._loadEntitiesFromState();
+ });
+
+ this.addSubscription = this._appStateService.fileChanged$.subscribe(() => {
+ this.calculateData();
+ });
+
+ this.addSubscription = this._appStateService.dossierTemplateChanged$.subscribe(() => {
+ this.fileAttributeConfigs = this._fileAttributesService.getFileAttributeConfig(
+ this.currentDossier.dossierTemplateId
+ )?.fileAttributeConfigs;
+ });
+
+ this.addSubscription = this._tableComponent.scrollViewport.scrolledIndexChange
+ .pipe(tap(index => (this._lastScrolledIndex = index)))
+ .subscribe();
+
+ this.dossierAttributes = await this._dossierAttributesService.getValues(this.currentDossier);
+ } catch (e) {
+ console.log('Error from dossier overview screen: ', e);
+ } finally {
+ this._loadingService.stop();
+ }
+ }
+
+ ngOnDestroy(): void {
+ this._fileDropOverlayService.cleanupFileDropHandling();
+ super.ngOnDestroy();
+ }
+
+ async ngOnAttach() {
+ await this._appStateService.reloadActiveDossierFiles();
+ this._loadEntitiesFromState();
+ await this.ngOnInit();
+ this._tableComponent.scrollViewport.scrollToIndex(this._lastScrolledIndex, 'smooth');
+ }
+
+ ngOnDetach() {
+ this.ngOnDestroy();
+ }
+
+ async reanalyseDossier() {
+ try {
+ await this._appStateService.reanalyzeDossier();
+ await this.reloadDossiers();
+ this._toaster.success(_('dossier-overview.reanalyse-dossier.success'));
+ } catch (e) {
+ this._toaster.error(_('dossier-overview.reanalyse-dossier.error'));
+ }
+ }
+
+ async reloadDossiers() {
+ await this._appStateService.getFiles(this.currentDossier, false);
+ this.calculateData();
+ }
+
+ calculateData(): void {
+ if (!this._appStateService.activeDossierId) {
+ return;
+ }
+
+ this._loadEntitiesFromState();
+ this._computeAllFilters();
+
+ this._dossierDetailsComponent?.calculateChartConfig();
+ this._changeDetectorRef.detectChanges();
+ }
+
+ @HostListener('drop', ['$event'])
+ onDrop(event: DragEvent): void {
+ handleFileDrop(event, this.currentDossier, this._uploadFiles.bind(this));
+ }
+
+ @HostListener('dragover', ['$event'])
+ onDragOver(event): void {
+ event.stopPropagation();
+ event.preventDefault();
+ }
+
+ async uploadFiles(files: Files): Promise {
+ await this._uploadFiles(convertFiles(files, this.currentDossier));
+ this._fileInput.nativeElement.value = null;
+ }
+
+ async bulkActionPerformed(): Promise {
+ this.entitiesService.setSelected([]);
+ await this.reloadDossiers();
+ }
+
+ openAssignDossierMembersDialog(): void {
+ const data = { dossier: this.currentDossier, section: 'members' };
+ this._dialogService.openDialog('editDossier', null, data, async () => await this.reloadDossiers());
+ }
+
+ openDossierDictionaryDialog() {
+ const data = { dossier: this.currentDossier, section: 'dossierDictionary' };
+ this._dialogService.openDialog('editDossier', null, data, async () => {
+ await this.reloadDossiers();
+ });
+ }
+
+ toggleCollapsedDetails() {
+ this.collapsedDetails = !this.collapsedDetails;
+ }
+
+ recentlyModifiedChecker = (file: File) =>
+ moment(file.lastUpdated).add(this._appConfigService.values.RECENT_PERIOD_IN_HOURS, 'hours').isAfter(moment());
+
+ private _loadEntitiesFromState() {
+ this.currentDossier = this._appStateService.activeDossier;
+ if (this.currentDossier) {
+ this.entitiesService.setEntities(this.currentDossier.files);
+ }
+ }
+
+ private async _uploadFiles(files: FileUploadModel[]) {
+ const fileCount = await this._fileUploadService.uploadFiles(files);
+ if (fileCount) {
+ this._statusOverlayService.openUploadStatusOverlay();
+ }
+ }
+
+ private _computeAllFilters() {
+ if (!this.currentDossier) {
+ return;
+ }
+
+ const filterGroups = this._configService.filterGroups(
+ this.entitiesService.all,
+ this.fileAttributeConfigs,
+ this._needsWorkFilterTemplate,
+ () => this.checkedRequiredFilters,
+ () => this.checkedNotRequiredFilters
+ );
+
+ for (const filterGroup of filterGroups) {
+ this.filterService.addFilterGroup(filterGroup);
+ }
+ }
+}
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.html
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.html
rename to apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.html
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.scss
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.scss
rename to apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.scss
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.ts
similarity index 84%
rename from apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.ts
rename to apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.ts
index 9493e4fee..5b9c6c153 100644
--- a/apps/red-ui/src/app/modules/dossier/components/dossier-listing-actions/dossier-listing-actions.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.ts
@@ -1,19 +1,19 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
import { PermissionsService } from '@services/permissions.service';
-import { Dossier } from '../../../../state/model/dossier';
import { StatusSorter } from '@utils/sorters/status-sorter';
-import { AppStateService } from '@state/app-state.service';
-import { DossiersDialogService } from '../../services/dossiers-dialog.service';
import { CircleButtonTypes, StatusBarConfig } from '@iqser/common-ui';
import { UserService } from '@services/user.service';
+import { AppStateService } from '@state/app-state.service';
+import { Dossier } from '@state/model/dossier';
+import { DossiersDialogService } from '../../../../services/dossiers-dialog.service';
@Component({
- selector: 'redaction-dossier-listing-actions',
- templateUrl: './dossier-listing-actions.component.html',
- styleUrls: ['./dossier-listing-actions.component.scss'],
+ selector: 'redaction-dossiers-listing-actions',
+ templateUrl: './dossiers-listing-actions.component.html',
+ styleUrls: ['./dossiers-listing-actions.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
-export class DossierListingActionsComponent {
+export class DossiersListingActionsComponent {
readonly circleButtonTypes = CircleButtonTypes;
readonly currentUser = this._userService.currentUser;
@@ -27,20 +27,6 @@ export class DossierListingActionsComponent {
private readonly _userService: UserService
) {}
- openEditDossierDialog($event: MouseEvent, dossier: Dossier): void {
- this._dialogService.openDialog('editDossier', $event, {
- dossier,
- afterSave: () => this.actionPerformed.emit()
- });
- }
-
- reanalyseDossier($event: MouseEvent, dossier: Dossier): void {
- $event.stopPropagation();
- this.appStateService.reanalyzeDossier(dossier).then(() => {
- this.appStateService.loadAllDossiers().then(() => this.actionPerformed.emit());
- });
- }
-
get statusConfig(): readonly StatusBarConfig[] {
if (!this.dossier) {
return [];
@@ -60,4 +46,18 @@ export class DossierListingActionsComponent {
.sort(StatusSorter.byStatus)
.map(status => ({ length: obj[status], color: status }));
}
+
+ openEditDossierDialog($event: MouseEvent, dossier: Dossier): void {
+ this._dialogService.openDialog('editDossier', $event, {
+ dossier,
+ afterSave: () => this.actionPerformed.emit()
+ });
+ }
+
+ reanalyseDossier($event: MouseEvent, dossier: Dossier): void {
+ $event.stopPropagation();
+ this.appStateService.reanalyzeDossier(dossier).then(() => {
+ this.appStateService.loadAllDossiers().then(() => this.actionPerformed.emit());
+ });
+ }
}
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-listing-details/dossier-listing-details.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/dossier-listing-details/dossier-listing-details.component.html
rename to apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-listing-details/dossier-listing-details.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.scss
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/dossier-listing-details/dossier-listing-details.component.scss
rename to apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.scss
diff --git a/apps/red-ui/src/app/modules/dossier/components/dossier-listing-details/dossier-listing-details.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts
similarity index 72%
rename from apps/red-ui/src/app/modules/dossier/components/dossier-listing-details/dossier-listing-details.component.ts
rename to apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts
index 3c94dc235..dfaf1c60a 100644
--- a/apps/red-ui/src/app/modules/dossier/components/dossier-listing-details/dossier-listing-details.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts
@@ -4,12 +4,12 @@ import { AppStateService } from '@state/app-state.service';
import { FilterService } from '@iqser/common-ui';
@Component({
- selector: 'redaction-dossier-listing-details',
- templateUrl: './dossier-listing-details.component.html',
- styleUrls: ['./dossier-listing-details.component.scss'],
+ selector: 'redaction-dossiers-listing-details',
+ templateUrl: './dossiers-listing-details.component.html',
+ styleUrls: ['./dossiers-listing-details.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
-export class DossierListingDetailsComponent {
+export class DossiersListingDetailsComponent {
@Input() dossiersChartData: DoughnutChartConfig[];
@Input() documentsChartData: DoughnutChartConfig[];
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.html
new file mode 100644
index 000000000..30b70e884
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.html
@@ -0,0 +1,31 @@
+();
+
+ constructor() {}
+}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/config.service.ts b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/config.service.ts
new file mode 100644
index 000000000..aa8395e22
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/config.service.ts
@@ -0,0 +1,213 @@
+import { Injectable, TemplateRef } from '@angular/core';
+import { IFilterGroup, keyChecker, NestedFilter, TableColumnConfig } from '@iqser/common-ui';
+import { Dossier } from '@state/model/dossier';
+import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
+import { TranslateService } from '@ngx-translate/core';
+import { UserPreferenceService } from '@services/user-preference.service';
+import { UserService } from '@services/user.service';
+import { ButtonConfig } from '@shared/components/page-header/models/button-config.model';
+import { User } from '@models/user';
+import { fileStatusTranslations } from '../../translations/file-status-translations';
+import {
+ annotationFilterChecker,
+ dossierMemberChecker,
+ dossierStatusChecker,
+ dossierTemplateChecker,
+ RedactionFilterSorter,
+ StatusSorter
+} from '@utils/index';
+import { workloadTranslations } from '../../translations/workload-translations';
+import { AppStateService } from '@state/app-state.service';
+
+@Injectable()
+export class ConfigService {
+ constructor(
+ private readonly _translateService: TranslateService,
+ private readonly _userPreferenceService: UserPreferenceService,
+ private readonly _userService: UserService,
+ private readonly _appStateService: AppStateService
+ ) {}
+
+ get tableConfig(): TableColumnConfig[] {
+ return [
+ { label: _('dossier-listing.table-col-names.name'), sortByKey: 'searchKey', width: '2fr' },
+ { label: _('dossier-listing.table-col-names.needs-work') },
+ { label: _('dossier-listing.table-col-names.owner'), class: 'user-column' },
+ { label: _('dossier-listing.table-col-names.status'), class: 'flex-end', width: 'auto' }
+ ];
+ }
+
+ get _currentUser(): User {
+ return this._userService.currentUser;
+ }
+
+ private get _quickFilters(): NestedFilter[] {
+ const myDossiersLabel = this._translateService.instant('dossier-listing.quick-filters.my-dossiers');
+ const filters = [
+ {
+ id: 'my-dossiers',
+ label: myDossiersLabel,
+ checker: (dw: Dossier) => {
+ console.log(dw.ownerId, this._currentUser.id);
+ return dw.ownerId === this._currentUser.id;
+ }
+ },
+ {
+ id: 'to-approve',
+ label: this._translateService.instant('dossier-listing.quick-filters.to-approve'),
+ checker: (dw: Dossier) => dw.approverIds.includes(this._currentUser.id)
+ },
+ {
+ id: 'to-review',
+ label: this._translateService.instant('dossier-listing.quick-filters.to-review'),
+ checker: (dw: Dossier) => dw.memberIds.includes(this._currentUser.id)
+ },
+ {
+ id: 'other',
+ label: this._translateService.instant('dossier-listing.quick-filters.other'),
+ checker: (dw: Dossier) => !dw.memberIds.includes(this._currentUser.id)
+ }
+ ].map(filter => new NestedFilter(filter));
+
+ return filters.filter(f => f.label === myDossiersLabel || this._userPreferenceService.areDevFeaturesEnabled);
+ }
+
+ buttonsConfig(addDossier: () => void): ButtonConfig[] {
+ return [
+ {
+ label: _('dossier-listing.add-new'),
+ action: addDossier,
+ hide: !this._currentUser.isManager,
+ icon: 'red:plus',
+ type: 'primary'
+ }
+ ];
+ }
+
+ filterGroups(entities: Dossier[], needsWorkFilterTemplate: TemplateRef) {
+ const allDistinctFileStatus = new Set();
+ const allDistinctPeople = new Set();
+ const allDistinctNeedsWork = new Set();
+ const allDistinctDossierTemplates = new Set();
+
+ const filterGroups: IFilterGroup[] = [];
+
+ entities?.forEach(entry => {
+ // all people
+ entry.memberIds.forEach(f => allDistinctPeople.add(f));
+ // Needs work
+ entry.files.forEach(file => {
+ allDistinctFileStatus.add(file.status);
+ if (file.analysisRequired) {
+ allDistinctNeedsWork.add('analysis');
+ }
+ if (entry.hintsOnly) {
+ allDistinctNeedsWork.add('hint');
+ }
+ if (entry.hasRedactions) {
+ allDistinctNeedsWork.add('redaction');
+ }
+ if (entry.hasSuggestions) {
+ allDistinctNeedsWork.add('suggestion');
+ }
+ if (entry.hasNone) {
+ allDistinctNeedsWork.add('none');
+ }
+ });
+
+ allDistinctDossierTemplates.add(entry.dossierTemplateId);
+ });
+
+ const statusFilters = [...allDistinctFileStatus].map(
+ status =>
+ new NestedFilter({
+ id: status,
+ label: this._translateService.instant(fileStatusTranslations[status])
+ })
+ );
+
+ filterGroups.push({
+ slug: 'statusFilters',
+ label: this._translateService.instant('filters.status'),
+ icon: 'red:status',
+ filters: statusFilters.sort((a, b) => StatusSorter[a.id] - StatusSorter[b.id]),
+ checker: dossierStatusChecker
+ });
+
+ const peopleFilters = [...allDistinctPeople].map(
+ userId =>
+ new NestedFilter({
+ id: userId,
+ label: this._userService.getNameForId(userId)
+ })
+ );
+
+ filterGroups.push({
+ slug: 'peopleFilters',
+ label: this._translateService.instant('filters.people'),
+ icon: 'red:user',
+ filters: peopleFilters,
+ checker: dossierMemberChecker
+ });
+
+ const needsWorkFilters = [...allDistinctNeedsWork].map(
+ type =>
+ new NestedFilter({
+ id: type,
+ label: workloadTranslations[type]
+ })
+ );
+
+ filterGroups.push({
+ slug: 'needsWorkFilters',
+ label: this._translateService.instant('filters.needs-work'),
+ icon: 'red:needs-work',
+ filterTemplate: needsWorkFilterTemplate,
+ filters: needsWorkFilters.sort((a, b) => RedactionFilterSorter[a.id] - RedactionFilterSorter[b.id]),
+ checker: annotationFilterChecker,
+ matchAll: true
+ });
+
+ const dossierTemplateFilters = [...allDistinctDossierTemplates].map(
+ id =>
+ new NestedFilter({
+ id: id,
+ label: this._appStateService.getDossierTemplateById(id).name
+ })
+ );
+
+ filterGroups.push({
+ slug: 'dossierTemplateFilters',
+ label: this._translateService.instant('filters.dossier-templates'),
+ icon: 'red:template',
+ hide: dossierTemplateFilters.length <= 1,
+ filters: dossierTemplateFilters,
+ checker: dossierTemplateChecker
+ });
+
+ const quickFilters = this._quickFilters;
+ filterGroups.push({
+ slug: 'quickFilters',
+ filters: quickFilters,
+ checker: (dw: Dossier) => quickFilters.reduce((acc, f) => acc || (f.checked && f.checker(dw)), false)
+ });
+
+ const dossierFilters = entities.map(
+ dossier =>
+ new NestedFilter({
+ id: dossier.dossierName,
+ label: dossier.dossierName
+ })
+ );
+ filterGroups.push({
+ slug: 'dossierNameFilter',
+ label: this._translateService.instant('dossier-listing.filters.label'),
+ icon: 'red:folder',
+ filters: dossierFilters,
+ filterceptionPlaceholder: this._translateService.instant('dossier-listing.filters.search'),
+ checker: keyChecker('dossierName')
+ });
+
+ return filterGroups;
+ }
+}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/dossiers-listing.module.ts b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/dossiers-listing.module.ts
new file mode 100644
index 000000000..0b6b2aa21
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/dossiers-listing.module.ts
@@ -0,0 +1,34 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { IqserIconsModule } from '@iqser/common-ui';
+import { TranslateModule } from '@ngx-translate/core';
+import { DossiersListingScreenComponent } from './screen/dossiers-listing-screen.component';
+import { RouterModule } from '@angular/router';
+import { DossiersListingActionsComponent } from './components/dossiers-listing-actions/dossiers-listing-actions.component';
+import { SharedModule } from '@shared/shared.module';
+import { DossiersListingDetailsComponent } from './components/dossiers-listing-details/dossiers-listing-details.component';
+import { DossiersListingDossierNameComponent } from './components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component';
+import { ConfigService } from './config.service';
+import { TableItemComponent } from './components/table-item/table-item.component';
+import { SharedDossiersModule } from '../../shared/shared-dossiers.module';
+
+const routes = [
+ {
+ path: '',
+ component: DossiersListingScreenComponent,
+ pathMatch: 'full'
+ }
+];
+
+@NgModule({
+ declarations: [
+ DossiersListingScreenComponent,
+ DossiersListingActionsComponent,
+ DossiersListingDetailsComponent,
+ DossiersListingDossierNameComponent,
+ TableItemComponent
+ ],
+ providers: [ConfigService],
+ imports: [RouterModule.forChild(routes), CommonModule, SharedModule, SharedDossiersModule, IqserIconsModule, TranslateModule]
+})
+export class DossiersListingModule {}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.html
new file mode 100644
index 000000000..82ee8a3a1
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.scss
new file mode 100644
index 000000000..c3c3a92e5
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.scss
@@ -0,0 +1,14 @@
+.right-container {
+ display: flex;
+ width: 466px;
+ min-width: 466px;
+ padding-right: 11px;
+
+ &.has-scrollbar:hover {
+ padding-right: 0;
+ }
+
+ redaction-dossiers-listing-details {
+ min-width: 466px;
+ }
+}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.ts
new file mode 100644
index 000000000..d48cebecf
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/screen/dossiers-listing-screen.component.ts
@@ -0,0 +1,141 @@
+import { AfterViewInit, Component, forwardRef, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { DossierStatuses } from '@redaction/red-ui-http';
+import { AppStateService } from '@state/app-state.service';
+import { Dossier } from '@state/model/dossier';
+import { UserService } from '@services/user.service';
+import { PermissionsService } from '@services/permissions.service';
+import { TranslateChartService } from '@services/translate-chart.service';
+import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component';
+import { timer } from 'rxjs';
+import { tap } from 'rxjs/operators';
+import { Router } from '@angular/router';
+import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
+import { groupBy, OnAttach, OnDetach, StatusSorter } from '@utils/index';
+import { DefaultListingServices, ListingComponent, TableComponent } from '@iqser/common-ui';
+import { fileStatusTranslations } from '../../../translations/file-status-translations';
+import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
+import { ConfigService } from '../config.service';
+
+@Component({
+ templateUrl: './dossiers-listing-screen.component.html',
+ styleUrls: ['./dossiers-listing-screen.component.scss'],
+ providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DossiersListingScreenComponent) }]
+})
+export class DossiersListingScreenComponent
+ extends ListingComponent
+ implements OnInit, AfterViewInit, OnDestroy, OnAttach, OnDetach
+{
+ readonly currentUser = this._userService.currentUser;
+ readonly tableColumnConfigs = this._configService.tableConfig;
+ readonly tableHeaderLabel = _('dossier-listing.table-header.title');
+ readonly buttonConfigs = this._configService.buttonsConfig(() => this.openAddDossierDialog());
+ dossiersChartData: DoughnutChartConfig[] = [];
+ documentsChartData: DoughnutChartConfig[] = [];
+ private _lastScrolledIndex: number;
+ @ViewChild('needsWorkFilterTemplate', {
+ read: TemplateRef,
+ static: true
+ })
+ private readonly _needsWorkFilterTemplate: TemplateRef;
+ @ViewChild(TableComponent) private readonly _tableComponent: TableComponent;
+
+ constructor(
+ private readonly _router: Router,
+ protected readonly _injector: Injector,
+ private readonly _userService: UserService,
+ readonly permissionsService: PermissionsService,
+ private readonly _appStateService: AppStateService,
+ private readonly _dialogService: DossiersDialogService,
+ private readonly _translateChartService: TranslateChartService,
+ private readonly _configService: ConfigService
+ ) {
+ super(_injector);
+ this._appStateService.reset();
+ this._loadEntitiesFromState();
+ }
+
+ private get _activeDossiersCount(): number {
+ return this.entitiesService.all.filter(p => p.status === DossierStatuses.ACTIVE).length;
+ }
+
+ private get _inactiveDossiersCount(): number {
+ return this.entitiesService.all.length - this._activeDossiersCount;
+ }
+
+ ngOnInit(): void {
+ this.calculateData();
+
+ this.addSubscription = timer(0, 10000).subscribe(async () => {
+ await this._appStateService.loadAllDossiers();
+ this._loadEntitiesFromState();
+ this.calculateData();
+ });
+
+ this.addSubscription = this._appStateService.fileChanged$.subscribe(() => {
+ this.calculateData();
+ });
+ }
+
+ ngAfterViewInit(): void {
+ this.addSubscription = this._tableComponent.scrollViewport.scrolledIndexChange
+ .pipe(tap(index => (this._lastScrolledIndex = index)))
+ .subscribe();
+ }
+
+ ngOnAttach(): void {
+ this._appStateService.reset();
+ this._loadEntitiesFromState();
+ this.ngOnInit();
+ this.ngAfterViewInit();
+ this._tableComponent.scrollViewport.scrollToIndex(this._lastScrolledIndex, 'smooth');
+ }
+
+ ngOnDetach(): void {
+ this.ngOnDestroy();
+ }
+
+ openAddDossierDialog(): void {
+ this._dialogService.openDialog('addDossier', null, null, async addResponse => {
+ await this._router.navigate([`/main/dossiers/${addResponse.dossier.id}`]);
+ if (addResponse.addMembers) {
+ this._dialogService.openDialog('editDossier', null, {
+ dossier: addResponse.dossier,
+ section: 'members'
+ });
+ }
+ });
+ }
+
+ calculateData(): void {
+ this._computeAllFilters();
+
+ this.dossiersChartData = [
+ { value: this._activeDossiersCount, color: 'ACTIVE', label: _('active') },
+ { value: this._inactiveDossiersCount, color: 'DELETED', label: _('archived') }
+ ];
+ const groups = groupBy(this._appStateService.aggregatedFiles, 'status');
+ this.documentsChartData = [];
+
+ for (const status of Object.keys(groups)) {
+ this.documentsChartData.push({
+ value: groups[status].length,
+ color: status,
+ label: fileStatusTranslations[status],
+ key: status
+ });
+ }
+ this.documentsChartData.sort(StatusSorter.byStatus);
+ this.documentsChartData = this._translateChartService.translateStatus(this.documentsChartData);
+ }
+
+ private _loadEntitiesFromState() {
+ this.entitiesService.setEntities(this._appStateService.allDossiers);
+ }
+
+ private _computeAllFilters() {
+ const filterGroups = this._configService.filterGroups(this.entitiesService.all, this._needsWorkFilterTemplate);
+ for (const filterGroup of filterGroups) {
+ this.filterService.addFilterGroup(filterGroup);
+ }
+ }
+}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts
index 39ee44aa1..e4dd75f46 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/file-preview-screen/file-preview-screen.component.ts
@@ -18,7 +18,7 @@ import { ManualRedactionEntryWrapper } from '@models/file/manual-redaction-entry
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { ManualAnnotationResponse } from '@models/file/manual-annotation-response';
import { AnnotationData, FileDataModel } from '@models/file/file-data.model';
-import { FileActionService } from '../../services/file-action.service';
+import { FileActionService } from '../../shared/services/file-action.service';
import { AnnotationDrawService } from '../../services/annotation-draw.service';
import { AnnotationProcessingService } from '../../services/annotation-processing.service';
import { File } from '@models/file/file';
@@ -38,7 +38,7 @@ import { TranslateService } from '@ngx-translate/core';
import { fileStatusTranslations } from '../../translations/file-status-translations';
import { handleFilterDelta } from '@utils/filter-utils';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
-import { FileActionsComponent } from '../../components/file-actions/file-actions.component';
+import { FileActionsComponent } from '../../shared/components/file-actions/file-actions.component';
import { User } from '@models/user';
import { FilesService } from '../../services/files.service';
import Annotation = Core.Annotations.Annotation;
diff --git a/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.html b/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.html
index f8c54b661..01c25929a 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.html
+++ b/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.html
@@ -21,66 +21,64 @@
-
+ {{ dossier.dossierName }}
+
+
+
+
+
+ {{ getDossierTemplateNameFor(dossier.dossierTemplateId) }}
+
+
+
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.ts
new file mode 100644
index 000000000..2ba4cc448
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.ts
@@ -0,0 +1,18 @@
+import { Component, Input } from '@angular/core';
+import { Dossier } from '@state/model/dossier';
+import { AppStateService } from '@state/app-state.service';
+
+@Component({
+ selector: 'redaction-dossiers-listing-dossier-name',
+ templateUrl: './dossiers-listing-dossier-name.component.html',
+ styleUrls: ['./dossiers-listing-dossier-name.component.scss']
+})
+export class DossiersListingDossierNameComponent {
+ @Input() dossier: Dossier;
+
+ constructor(private readonly _appStateService: AppStateService) {}
+
+ getDossierTemplateNameFor(dossierTemplateId: string): string {
+ return this._appStateService.getDossierTemplateById(dossierTemplateId).name;
+ }
+}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.html
new file mode 100644
index 000000000..352e0354e
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.html
@@ -0,0 +1,12 @@
+
+
+ {{ dossier.filesLength }}
+
+
+
+ {{ dossier.totalNumberOfPages }}
+
+
+
+ {{ dossier.memberIds.length }}
+
+
+
+ {{ dossier.date | date: 'mediumDate' }}
+
+
+
+ {{ dossier.dueDate | date: 'mediumDate' }}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.scss b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.scss
new file mode 100644
index 000000000..ed7edfb31
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.scss
@@ -0,0 +1,3 @@
+.status-container {
+ width: 160px;
+}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.ts
new file mode 100644
index 000000000..7c2e63ce1
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.ts
@@ -0,0 +1,15 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { Dossier } from '@state/model/dossier';
+import { Required } from '@iqser/common-ui';
+
+@Component({
+ selector: 'redaction-table-item',
+ templateUrl: './table-item.component.html',
+ styleUrls: ['./table-item.component.scss']
+})
+export class TableItemComponent {
+ @Input() @Required() dossier!: Dossier;
+ @Output() readonly calculateData = new EventEmitter
+
+
+
+
+
+
+
+
+
-
-
-
- {{ item.filename }}
-
-
- 0" class="small-label">
-
+
+
+
-
-
-
-
-
-
-
+
-
-
-
+
+ {{ item.filename }}
- 1" class="small-label">
-
+
+
+
+
+
- 0" class="small-label">
+
+
+ 1" class="small-label">
+
+
+
+
+ {{ 'search-screen.missing' | translate }}: {{ term }}. {{ 'search-screen.must-contain' | translate }}:
+ {{ term }}
+
-
+
-
- {{ 'search-screen.missing' | translate }}: {{ term }}. {{ 'search-screen.must-contain' | translate }}:
- {{ term }}
-
-
-
-
-
-
- {{ item.dossierName }}
-
-
- implements OnDestroy, OnInit {
+export class SearchScreenComponent extends ListingComponent implements OnDestroy {
readonly fileStatusTranslations = fileStatusTranslations;
readonly searchPositions = SearchPositions;
- @ViewChild('filenameTemplate', { static: true }) readonly filenameTemplate: TemplateRef;
- @ViewChild('statusTemplate', { static: true }) readonly statusTemplate: TemplateRef;
- @ViewChild('dossierTemplate', { static: true }) readonly dossierTemplate: TemplateRef;
- @ViewChild('pagesTemplate', { static: true }) readonly pagesTemplate: TemplateRef;
-
readonly tableHeaderLabel = _('search-screen.table-header');
- tableColumnConfigs: TableColumnConfig[];
+ readonly tableColumnConfigs: TableColumnConfig[] = [
+ { label: _('search-screen.cols.document'), width: '2fr' },
+ { label: _('search-screen.cols.status') },
+ { label: _('search-screen.cols.dossier') },
+ { label: _('search-screen.cols.pages'), width: 'auto' }
+ ];
readonly search$ = new BehaviorSubject(null);
readonly searchResults$: Observable = this.search$.asObservable().pipe(
switchMap(query => this._search(query)),
@@ -108,19 +108,6 @@ export class SearchScreenComponent extends ListingComponent implements
this._router.navigate([], { queryParams }).then();
}
- ngOnInit(): void {
- this._configureTableColumns();
- }
-
- private _configureTableColumns() {
- this.tableColumnConfigs = [
- { label: _('search-screen.cols.document'), template: this.filenameTemplate, width: '2fr' },
- { label: _('search-screen.cols.status'), template: this.statusTemplate },
- { label: _('search-screen.cols.dossier'), template: this.dossierTemplate },
- { label: _('search-screen.cols.pages'), template: this.pagesTemplate, width: 'auto' }
- ];
- }
-
private _search(searchInput: SearchInput): Observable {
return this._searchControllerService.search({
dossierIds: [...searchInput.dossierIds],
diff --git a/apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.html b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.html
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.html
rename to apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.html
diff --git a/apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.scss b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.scss
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.scss
rename to apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.scss
diff --git a/apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.ts b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.ts
similarity index 99%
rename from apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.ts
rename to apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.ts
index 01c179aa4..1231ca8c9 100644
--- a/apps/red-ui/src/app/modules/dossier/components/file-actions/file-actions.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.ts
@@ -2,8 +2,7 @@ import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, S
import { PermissionsService } from '@services/permissions.service';
import { File } from '@models/file/file';
import { AppStateService } from '@state/app-state.service';
-import { FileActionService } from '../../services/file-action.service';
-import { DossiersDialogService } from '../../services/dossiers-dialog.service';
+import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
import { ConfirmationDialogInput } from '@shared/dialogs/confirmation-dialog/confirmation-dialog.component';
import { AutoUnsubscribe, CircleButtonType, CircleButtonTypes, LoadingService, Required, StatusBarConfig, Toaster } from '@iqser/common-ui';
import { FileManagementControllerService, FileStatus } from '@redaction/red-ui-http';
@@ -12,6 +11,7 @@ import { UserService } from '@services/user.service';
import { filter } from 'rxjs/operators';
import { UserPreferenceService } from '@services/user-preference.service';
import { LongPressEvent } from '@shared/directives/long-press.directive';
+import { FileActionService } from '../../services/file-action.service';
@Component({
selector: 'redaction-file-actions',
diff --git a/apps/red-ui/src/app/modules/dossier/components/needs-work-badge/needs-work-badge.component.html b/apps/red-ui/src/app/modules/dossier/shared/components/needs-work-badge/needs-work-badge.component.html
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/needs-work-badge/needs-work-badge.component.html
rename to apps/red-ui/src/app/modules/dossier/shared/components/needs-work-badge/needs-work-badge.component.html
diff --git a/apps/red-ui/src/app/modules/dossier/components/needs-work-badge/needs-work-badge.component.scss b/apps/red-ui/src/app/modules/dossier/shared/components/needs-work-badge/needs-work-badge.component.scss
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/needs-work-badge/needs-work-badge.component.scss
rename to apps/red-ui/src/app/modules/dossier/shared/components/needs-work-badge/needs-work-badge.component.scss
diff --git a/apps/red-ui/src/app/modules/dossier/components/needs-work-badge/needs-work-badge.component.ts b/apps/red-ui/src/app/modules/dossier/shared/components/needs-work-badge/needs-work-badge.component.ts
similarity index 96%
rename from apps/red-ui/src/app/modules/dossier/components/needs-work-badge/needs-work-badge.component.ts
rename to apps/red-ui/src/app/modules/dossier/shared/components/needs-work-badge/needs-work-badge.component.ts
index b04bb5e76..27040f512 100644
--- a/apps/red-ui/src/app/modules/dossier/components/needs-work-badge/needs-work-badge.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/shared/components/needs-work-badge/needs-work-badge.component.ts
@@ -1,7 +1,7 @@
import { Component, Input } from '@angular/core';
import { AppStateService } from '@state/app-state.service';
import { File } from '@models/file/file';
-import { Dossier } from '../../../../state/model/dossier';
+import { Dossier } from '@state/model/dossier';
@Component({
selector: 'redaction-needs-work-badge',
diff --git a/apps/red-ui/src/app/modules/dossier/services/file-action.service.ts b/apps/red-ui/src/app/modules/dossier/shared/services/file-action.service.ts
similarity index 96%
rename from apps/red-ui/src/app/modules/dossier/services/file-action.service.ts
rename to apps/red-ui/src/app/modules/dossier/shared/services/file-action.service.ts
index c32aa4e20..c6fc526b0 100644
--- a/apps/red-ui/src/app/modules/dossier/services/file-action.service.ts
+++ b/apps/red-ui/src/app/modules/dossier/shared/services/file-action.service.ts
@@ -4,10 +4,10 @@ import { UserService } from '@services/user.service';
import { ReanalysisControllerService } from '@redaction/red-ui-http';
import { File } from '@models/file/file';
import { PermissionsService } from '@services/permissions.service';
-import { DossiersDialogService } from './dossiers-dialog.service';
+import { DossiersDialogService } from '../../services/dossiers-dialog.service';
import { ConfirmationDialogInput } from '@shared/dialogs/confirmation-dialog/confirmation-dialog.component';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
-import { FilesService } from './files.service';
+import { FilesService } from '../../services/files.service';
@Injectable()
export class FileActionService {
diff --git a/apps/red-ui/src/app/modules/dossier/shared/shared-dossiers.module.ts b/apps/red-ui/src/app/modules/dossier/shared/shared-dossiers.module.ts
new file mode 100644
index 000000000..b1c4b967e
--- /dev/null
+++ b/apps/red-ui/src/app/modules/dossier/shared/shared-dossiers.module.ts
@@ -0,0 +1,17 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FileActionService } from './services/file-action.service';
+import { FileActionsComponent } from './components/file-actions/file-actions.component';
+import { NeedsWorkBadgeComponent } from './components/needs-work-badge/needs-work-badge.component';
+import { IqserIconsModule } from '@iqser/common-ui';
+import { SharedModule } from '@shared/shared.module';
+
+const components = [FileActionsComponent, NeedsWorkBadgeComponent];
+
+@NgModule({
+ declarations: [...components],
+ exports: [...components],
+ providers: [FileActionService],
+ imports: [CommonModule, IqserIconsModule, SharedModule]
+})
+export class SharedDossiersModule {}
diff --git a/apps/red-ui/src/app/modules/dossier/components/team-members/team-members.component.html b/apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.html
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/team-members/team-members.component.html
rename to apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.html
diff --git a/apps/red-ui/src/app/modules/dossier/components/team-members/team-members.component.scss b/apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.scss
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/team-members/team-members.component.scss
rename to apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.scss
diff --git a/apps/red-ui/src/app/modules/dossier/components/team-members/team-members.component.ts b/apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.ts
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/team-members/team-members.component.ts
rename to apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.ts
diff --git a/apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.html b/apps/red-ui/src/app/modules/shared/components/type-filter/type-filter.component.html
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.html
rename to apps/red-ui/src/app/modules/shared/components/type-filter/type-filter.component.html
diff --git a/apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.scss b/apps/red-ui/src/app/modules/shared/components/type-filter/type-filter.component.scss
similarity index 100%
rename from apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.scss
rename to apps/red-ui/src/app/modules/shared/components/type-filter/type-filter.component.scss
diff --git a/apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.ts b/apps/red-ui/src/app/modules/shared/components/type-filter/type-filter.component.ts
similarity index 94%
rename from apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.ts
rename to apps/red-ui/src/app/modules/shared/components/type-filter/type-filter.component.ts
index 9d2866f9d..39c71c592 100644
--- a/apps/red-ui/src/app/modules/dossier/components/type-filter/type-filter.component.ts
+++ b/apps/red-ui/src/app/modules/shared/components/type-filter/type-filter.component.ts
@@ -1,5 +1,5 @@
import { Component, Input, OnInit } from '@angular/core';
-import { AppStateService } from '@state/app-state.service';
+import { AppStateService } from '../../../../state/app-state.service';
import { INestedFilter } from '@iqser/common-ui';
@Component({
diff --git a/apps/red-ui/src/app/modules/shared/shared.module.ts b/apps/red-ui/src/app/modules/shared/shared.module.ts
index 92d75e3b7..6545ecbbb 100644
--- a/apps/red-ui/src/app/modules/shared/shared.module.ts
+++ b/apps/red-ui/src/app/modules/shared/shared.module.ts
@@ -19,13 +19,15 @@ import { MomentDateAdapter } from '@angular/material-moment-adapter';
import { SelectComponent } from './components/select/select.component';
import { NavigateLastDossiersScreenDirective } from './directives/navigate-last-dossiers-screen.directive';
import { DictionaryManagerComponent } from './components/dictionary-manager/dictionary-manager.component';
-import { SideNavComponent } from '@shared/components/side-nav/side-nav.component';
+import { SideNavComponent } from './components/side-nav/side-nav.component';
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
import { AssignUserDropdownComponent } from './components/assign-user-dropdown/assign-user-dropdown.component';
import { PageHeaderComponent } from './components/page-header/page-header.component';
-import { DatePipe } from '@shared/pipes/date.pipe';
-import { LongPressDirective } from '@shared/directives/long-press.directive';
-import { NamePipe } from '@shared/pipes/name.pipe';
+import { DatePipe } from './pipes/date.pipe';
+import { LongPressDirective } from './directives/long-press.directive';
+import { NamePipe } from './pipes/name.pipe';
+import { TypeFilterComponent } from './components/type-filter/type-filter.component';
+import { TeamMembersComponent } from './components/team-members/team-members.component';
const buttons = [FileDownloadBtnComponent, UserButtonComponent];
@@ -42,6 +44,8 @@ const components = [
DictionaryManagerComponent,
AssignUserDropdownComponent,
PageHeaderComponent,
+ TypeFilterComponent,
+ TeamMembersComponent,
...buttons
];
diff --git a/apps/red-ui/src/app/utils/index.ts b/apps/red-ui/src/app/utils/index.ts
new file mode 100644
index 000000000..15c2674bb
--- /dev/null
+++ b/apps/red-ui/src/app/utils/index.ts
@@ -0,0 +1,17 @@
+export * from './sorters/redaction-filter-sorter';
+export * from './sorters/status-sorter';
+export * from './sorters/super-type-sorter';
+
+export * from './api-path-interceptor';
+export * from './configuration.initializer';
+export * from './custom-route-reuse.strategy';
+export * from './date-inputs-utils';
+export * from './file-download-utils';
+export * from './file-drop-utils';
+export * from './filter-utils';
+export * from './functions';
+export * from './global-error-handler.service';
+export * from './missing-translations-handler';
+export * from './page-stamper';
+export * from './pdf-coordinates';
+export * from './pruning-translation-loader';
diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json
index ebc96a5b5..3bc887fcb 100644
--- a/apps/red-ui/src/assets/i18n/en.json
+++ b/apps/red-ui/src/assets/i18n/en.json
@@ -1375,7 +1375,7 @@
"table-header": "{length} search {length, plural, one{result} other{results}}"
},
"search": {
- "entire-platform": "accross all dossiers",
+ "entire-platform": "across all dossiers",
"placeholder": "Search documents...",
"this-dossier": "in this dossier"
},
diff --git a/libs/common-ui b/libs/common-ui
index 54eb8173c..c0b445b06 160000
--- a/libs/common-ui
+++ b/libs/common-ui
@@ -1 +1 @@
-Subproject commit 54eb8173cf7ce35f29f4e9df309954bbd1cf7a5c
+Subproject commit c0b445b06ed86a07c4b9aa1803b29b9384021d54
-
- {{ item.numberOfPages }}
+
diff --git a/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.scss b/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.scss
index da9d39c30..25f846e32 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.scss
+++ b/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.scss
@@ -1,11 +1,9 @@
@use 'common-mixins';
-:host ::ng-deep iqser-table cdk-virtual-scroll-viewport .cdk-virtual-scroll-content-wrapper .table-item > div.cell {
- .highlights {
- @include common-mixins.line-clamp(1);
+.cell .highlights::ng-deep {
+ @include common-mixins.line-clamp(1);
- em {
- background-color: #fffcc4;
- }
+ em {
+ background-color: #fffcc4;
}
}
diff --git a/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.ts b/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.ts
index 7ffcb6273..bba7db62b 100644
--- a/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.ts
+++ b/apps/red-ui/src/app/modules/dossier/screens/search-screen/search-screen.component.ts
@@ -1,4 +1,4 @@
-import { Component, forwardRef, Injector, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { Component, forwardRef, Injector, OnDestroy } from '@angular/core';
import {
DefaultListingServices,
IListable,
@@ -40,17 +40,17 @@ interface SearchInput {
styleUrls: ['./search-screen.component.scss'],
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => SearchScreenComponent) }]
})
-export class SearchScreenComponent extends ListingComponent
+
+
+
+
+ {{ item.dossierName }}
+
+
+
+
+
+ {{ item.numberOfPages }}
+