From a11d02f126d1b823315adefbefa03191acf72fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Tue, 19 Apr 2022 23:43:42 +0300 Subject: [PATCH 01/12] RED-3796: Dashboard #1 --- apps/red-ui/src/app/app-routing.module.ts | 12 ++++++- .../base-admin-screen.component.scss | 2 +- .../template-stats.component.html | 12 +++++++ .../template-stats.component.scss | 23 +++++++++++++ .../template-stats.component.ts | 34 +++++++++++++++++++ .../dashboard-screen.component.html | 12 +++++++ .../dashboard-screen.component.scss | 11 ++++++ .../dashboard-screen.component.ts | 15 ++++++++ .../app/modules/dashboard/dashboard.module.ts | 23 +++++++++++++ apps/red-ui/src/assets/i18n/en.json | 6 ++++ libs/common-ui | 2 +- 11 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html create mode 100644 apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss create mode 100644 apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts create mode 100644 apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.html create mode 100644 apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.scss create mode 100644 apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts create mode 100644 apps/red-ui/src/app/modules/dashboard/dashboard.module.ts diff --git a/apps/red-ui/src/app/app-routing.module.ts b/apps/red-ui/src/app/app-routing.module.ts index ed3ddb7b1..8bf52eec7 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -15,7 +15,7 @@ import { DOSSIERS_ARCHIVE } from '@utils/constants'; const routes: Routes = [ { path: '', - redirectTo: 'main/dossiers', + redirectTo: 'main/dashboard', pathMatch: 'full', }, { @@ -33,6 +33,16 @@ const routes: Routes = [ component: BaseScreenComponent, loadChildren: () => import('./modules/admin/admin.module').then(m => m.AdminModule), }, + { + path: 'main/dashboard', + component: BaseScreenComponent, + loadChildren: () => import('./modules/dashboard/dashboard.module').then(m => m.DashboardModule), + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, RedRoleGuard], + requiredRoles: ['RED_USER', 'RED_MANAGER'], + }, + }, { path: 'main/dossiers', component: BaseScreenComponent, diff --git a/apps/red-ui/src/app/modules/admin/base-admin-screen/base-admin-screen.component.scss b/apps/red-ui/src/app/modules/admin/base-admin-screen/base-admin-screen.component.scss index e7a72018d..333a85d49 100644 --- a/apps/red-ui/src/app/modules/admin/base-admin-screen/base-admin-screen.component.scss +++ b/apps/red-ui/src/app/modules/admin/base-admin-screen/base-admin-screen.component.scss @@ -1,3 +1,3 @@ :host { - display: flex; + flex-direction: row; } diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html new file mode 100644 index 000000000..33cf9e9b8 --- /dev/null +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html @@ -0,0 +1,12 @@ +
+ + + + + + +
+
nothing here
+
btn
+
+
diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss new file mode 100644 index 000000000..9bbc901f0 --- /dev/null +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss @@ -0,0 +1,23 @@ +.dialog { + flex-direction: row; + max-width: unset; + + > div { + padding: 24px; + display: flex; + flex-direction: column; + flex: 1; + + &:not(:first-child) { + align-items: center; + justify-content: center; + border-left: 1px solid var(--iqser-separator); + } + + &.empty { + flex-direction: row; + justify-content: space-between; + align-items: center; + } + } +} diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts new file mode 100644 index 000000000..2d3e17e7b --- /dev/null +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts @@ -0,0 +1,34 @@ +import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; +import { DossierTemplatesService } from '../../../../services/entity-services/dossier-templates.service'; +import { DossierTemplate, DossierTemplateStats } from '@red/domain'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { switchMap } from 'rxjs/operators'; +import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service'; + +@Component({ + selector: 'redaction-template-stats [dossierTemplateId]', + templateUrl: './template-stats.component.html', + styleUrls: ['./template-stats.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TemplateStatsComponent implements OnChanges { + @Input() dossierTemplateId: string; + + readonly dossierTemplate$: Observable; + readonly stats$: Observable; + readonly #ngOnChanges$ = new BehaviorSubject(undefined); + + constructor( + private readonly _dossierTemplatesService: DossierTemplatesService, + private readonly _dossierTemplateStatsService: DossierTemplateStatsService, + ) { + this.dossierTemplate$ = this.#ngOnChanges$.pipe(switchMap(id => this._dossierTemplatesService.getEntityChanged$(id))); + this.stats$ = this.#ngOnChanges$.pipe(switchMap(id => this._dossierTemplateStatsService.watch$(id))); + } + + ngOnChanges() { + if (this.dossierTemplateId) { + this.#ngOnChanges$.next(this.dossierTemplateId); + } + } +} diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.html b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.html new file mode 100644 index 000000000..47dc25cce --- /dev/null +++ b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.html @@ -0,0 +1,12 @@ +
+ +
+

+ +

+ + +
diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.scss b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.scss new file mode 100644 index 000000000..f646df137 --- /dev/null +++ b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.scss @@ -0,0 +1,11 @@ +:host { + align-items: center; + background-color: var(--iqser-grey-2); + + .container { + padding: 32px; + width: 900px; + max-width: 100%; + box-sizing: border-box; + } +} diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts new file mode 100644 index 000000000..09bac094f --- /dev/null +++ b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts @@ -0,0 +1,15 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { UserService } from '../../../services/user.service'; +import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; + +@Component({ + selector: 'redaction-dashboard-screen', + templateUrl: './dashboard-screen.component.html', + styleUrls: ['./dashboard-screen.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class DashboardScreenComponent { + readonly currentUser = this._userService.currentUser; + + constructor(private readonly _userService: UserService, readonly dossierTemplatesService: DossierTemplatesService) {} +} diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts b/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts new file mode 100644 index 000000000..c53f748e8 --- /dev/null +++ b/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts @@ -0,0 +1,23 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { DashboardScreenComponent } from './dashboard-screen/dashboard-screen.component'; +import { RouterModule } from '@angular/router'; +import { SharedModule } from '../shared/shared.module'; +import { TemplateStatsComponent } from './components/template-stats/template-stats.component'; +import { DossierTemplatesGuard } from '../../guards/dossier-templates.guard'; +import { CompositeRouteGuard } from '@iqser/common-ui'; + +const routes = [ + { + path: '', + component: DashboardScreenComponent, + canActivate: [CompositeRouteGuard], + data: { routeGuards: [DossierTemplatesGuard] }, + }, +]; + +@NgModule({ + declarations: [DashboardScreenComponent, TemplateStatsComponent], + imports: [RouterModule.forChild(routes), CommonModule, SharedModule], +}) +export class DashboardModule {} diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index ff5d19017..0cad1169f 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -8,6 +8,12 @@ "all": "All", "none": "None" }, + "dashboard": { + "greeting": { + "title": "Welcome, {name}!", + "subtitle": "Here's what's happening in your redaction teams today." + } + }, "add-dossier-dialog": { "actions": { "save": "Save", diff --git a/libs/common-ui b/libs/common-ui index fd9d62241..3684acc2c 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit fd9d622413547de842439e8d91ee4316f2facff1 +Subproject commit 3684acc2c99fafc88351af188745c10065c16cdb From 127b77dceb5253612ae164e3a07f160916f609a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Wed, 20 Apr 2022 00:45:14 +0300 Subject: [PATCH 02/12] RED-3796: Dashboard #2 (empty dossier template) --- .../template-stats.component.html | 16 ++++++++-- .../template-stats.component.scss | 1 + .../template-stats.component.ts | 13 ++++++++- .../dashboard-screen.component.html | 8 +++-- .../app/modules/dashboard/dashboard.module.ts | 3 +- .../add-dossier-dialog.component.ts | 29 +++++++++++++++---- .../dossiers-listing/config.service.ts | 28 +++++++++++------- .../dossiers-listing-screen.component.ts | 28 +++++------------- apps/red-ui/src/assets/i18n/de.json | 10 +++++++ apps/red-ui/src/assets/i18n/en.json | 16 ++++++---- libs/common-ui | 2 +- 11 files changed, 104 insertions(+), 50 deletions(-) diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html index 33cf9e9b8..663ca4131 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html @@ -6,7 +6,19 @@
-
nothing here
-
btn
+
+
+ {{ dossierTemplate.name }} +
+
+ {{ 'dashboard.empty-template.description' | translate }} +
+
+
diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss index 9bbc901f0..090ade28f 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss @@ -1,6 +1,7 @@ .dialog { flex-direction: row; max-width: unset; + margin: 0 0 16px 0; > div { padding: 24px; diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts index 2d3e17e7b..87f9e76ae 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts @@ -1,9 +1,12 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; -import { DossierTemplatesService } from '../../../../services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; import { DossierTemplate, DossierTemplateStats } from '@red/domain'; import { BehaviorSubject, Observable } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service'; +import { IconButtonTypes } from '@iqser/common-ui'; +import { DossiersDialogService } from '../../../dossier/services/dossiers-dialog.service'; +import { Router } from '@angular/router'; @Component({ selector: 'redaction-template-stats [dossierTemplateId]', @@ -12,6 +15,8 @@ import { DossierTemplateStatsService } from '@services/entity-services/dossier-t changeDetection: ChangeDetectionStrategy.OnPush, }) export class TemplateStatsComponent implements OnChanges { + readonly iconButtonTypes = IconButtonTypes; + @Input() dossierTemplateId: string; readonly dossierTemplate$: Observable; @@ -21,6 +26,8 @@ export class TemplateStatsComponent implements OnChanges { constructor( private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _dossierTemplateStatsService: DossierTemplateStatsService, + private readonly _dialogService: DossiersDialogService, + private readonly _router: Router, ) { this.dossierTemplate$ = this.#ngOnChanges$.pipe(switchMap(id => this._dossierTemplatesService.getEntityChanged$(id))); this.stats$ = this.#ngOnChanges$.pipe(switchMap(id => this._dossierTemplateStatsService.watch$(id))); @@ -31,4 +38,8 @@ export class TemplateStatsComponent implements OnChanges { this.#ngOnChanges$.next(this.dossierTemplateId); } } + + newDossier(): void { + this._dialogService.openDialog('addDossier', null, { dossierTemplateId: this.dossierTemplateId }); + } } diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.html b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.html index 47dc25cce..abd8f5ad8 100644 --- a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.html +++ b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.html @@ -1,9 +1,13 @@
-

+
-

+
, + @Inject(MAT_DIALOG_DATA) readonly data: DialogData, ) { super(_injector, _dialogRef); this._getDossierTemplates(); @@ -61,10 +71,19 @@ export class AddDossierDialogComponent extends BaseDialogComponent { reportTemplateValueMapper = (reportTemplate: IReportTemplate) => reportTemplate.templateId; async save(options?: SaveOptions) { + this._loadingService.start(); const savedDossier = await firstValueFrom(this._activeDossiersService.createOrUpdate(this._formToObject())); if (savedDossier) { - this._dialogRef.close({ dossier: savedDossier, addMembers: options?.addMembers }); + await this._router.navigate([savedDossier.routerLink]); + if (options?.addMembers) { + this._dialogService.openDialog('editDossier', null, { + dossierId: savedDossier.dossierId, + section: 'members', + }); + } + this._dialogRef.close(savedDossier); } + this._loadingService.stop(); } async dossierTemplateChanged(dossierTemplateId) { @@ -98,7 +117,7 @@ export class AddDossierDialogComponent extends BaseDialogComponent { return this._formBuilder.group( { dossierName: [null, Validators.required], - dossierTemplateId: [null, Validators.required], + dossierTemplateId: [this.data?.dossierTemplateId, Validators.required], downloadFileTypes: [null], reportTemplateIds: [null], description: [null], diff --git a/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts b/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts index 3efed55d8..2861a033f 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts @@ -6,11 +6,12 @@ import { TranslateService } from '@ngx-translate/core'; import { UserPreferenceService } from '@services/user-preference.service'; import { UserService } from '@services/user.service'; import { workflowFileStatusTranslations } from '../../translations/file-status-translations'; -import { dossierMemberChecker, dossierStateChecker, dossierTemplateChecker, RedactionFilterSorter } from '@utils/index'; +import { dossierMemberChecker, dossierStateChecker, dossierTemplateChecker, RedactionFilterSorter } from '../../utils'; import { workloadTranslations } from '../dossier/translations/workload-translations'; import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; import { DossierStatesMapService } from '@services/entity-services/dossier-states-map.service'; +import { DossiersDialogService } from '../dossier/services/dossiers-dialog.service'; @Injectable() export class ConfigService { @@ -21,6 +22,7 @@ export class ConfigService { private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _dossierStatsService: DossierStatsService, private readonly _dossierStatesMapService: DossierStatesMapService, + private readonly _dialogService: DossiersDialogService, ) {} get tableConfig(): TableColumnConfig[] { @@ -38,19 +40,11 @@ export class ConfigService { return this._userService.currentUser; } - _myDossiersChecker = (dw: Dossier) => dw.ownerId === this._currentUser.id; - - _toApproveChecker = (dw: Dossier) => dw.approverIds.includes(this._currentUser.id); - - _toReviewChecker = (dw: Dossier) => dw.memberIds.includes(this._currentUser.id); - - _otherChecker = (dw: Dossier) => !dw.memberIds.includes(this._currentUser.id); - - buttonsConfig(addDossier: () => void): ButtonConfig[] { + get buttonsConfig(): ButtonConfig[] { return [ { label: _('dossier-listing.add-new'), - action: addDossier, + action: () => this._openAddDossierDialog(), hide: !this._currentUser.isManager, icon: 'iqser:plus', type: 'primary', @@ -208,6 +202,18 @@ export class ConfigService { return filterGroups; } + private _myDossiersChecker = (dw: Dossier) => dw.ownerId === this._currentUser.id; + + private _toApproveChecker = (dw: Dossier) => dw.approverIds.includes(this._currentUser.id); + + private _toReviewChecker = (dw: Dossier) => dw.memberIds.includes(this._currentUser.id); + + private _otherChecker = (dw: Dossier) => !dw.memberIds.includes(this._currentUser.id); + + private _openAddDossierDialog(): void { + this._dialogService.openDialog('addDossier', null, null); + } + private _quickFilters(entities: Dossier[]): NestedFilter[] { const myDossiersLabel = this._translateService.instant('dossier-listing.quick-filters.my-dossiers'); const filters = [ diff --git a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts index 97361b639..8bf91957f 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts @@ -2,16 +2,13 @@ import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit, Templ import { Dossier } from '@red/domain'; import { UserService } from '@services/user.service'; import { PermissionsService } from '@services/permissions.service'; -import { TranslateChartService } from '@services/translate-chart.service'; -import { Router } from '@angular/router'; -import { DossiersDialogService } from '../../dossier/services/dossiers-dialog.service'; import { DefaultListingServicesTmp, EntitiesService, ListingComponent, OnAttach, TableComponent } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { ConfigService } from '../config.service'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; -import { FilesService } from '@services/entity-services/files.service'; import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; import { tap } from 'rxjs/operators'; +import { DossiersDialogService } from '../../dossier/services/dossiers-dialog.service'; @Component({ templateUrl: './dossiers-listing-screen.component.html', @@ -27,7 +24,7 @@ export class DossiersListingScreenComponent extends ListingComponent im readonly currentUser = this._userService.currentUser; readonly tableColumnConfigs = this._configService.tableConfig; readonly tableHeaderLabel = _('dossier-listing.table-header.title'); - readonly buttonConfigs = this._configService.buttonsConfig(() => this.openAddDossierDialog()); + readonly buttonConfigs = this._configService.buttonsConfig; @ViewChild('needsWorkFilterTemplate', { read: TemplateRef, static: true, @@ -36,16 +33,13 @@ export class DossiersListingScreenComponent extends ListingComponent im @ViewChild(TableComponent) private readonly _tableComponent: TableComponent; constructor( - private readonly _router: Router, protected readonly _injector: Injector, private readonly _userService: UserService, readonly permissionsService: PermissionsService, private readonly _activeDossiersService: ActiveDossiersService, - private readonly _dialogService: DossiersDialogService, - private readonly _translateChartService: TranslateChartService, private readonly _configService: ConfigService, - private readonly _filesService: FilesService, private readonly _dossierTemplatesService: DossierTemplatesService, + private readonly _dialogService: DossiersDialogService, ) { super(_injector); } @@ -54,6 +48,10 @@ export class DossiersListingScreenComponent extends ListingComponent im return this._dossierTemplatesService.all[0].id; } + openAddDossierDialog(): void { + this._dialogService.openDialog('addDossier', null, null); + } + ngOnInit(): void { this.addSubscription = this._activeDossiersService.all$.pipe(tap(() => this._computeAllFilters())).subscribe(); } @@ -62,18 +60,6 @@ export class DossiersListingScreenComponent extends ListingComponent im this._tableComponent?.scrollToLastIndex(); } - openAddDossierDialog(): void { - this._dialogService.openDialog('addDossier', null, null, async (addResponse: { dossier: Dossier; addMembers: boolean }) => { - await this._router.navigate([addResponse.dossier.routerLink]); - if (addResponse.addMembers) { - this._dialogService.openDialog('editDossier', null, { - dossierId: addResponse.dossier.dossierId, - section: 'members', - }); - } - }); - } - private _computeAllFilters() { const filterGroups = this._configService.filterGroups(this.entitiesService.all, this._needsWorkFilterTemplate); this.filterService.addFilterGroups(filterGroups); diff --git a/apps/red-ui/src/assets/i18n/de.json b/apps/red-ui/src/assets/i18n/de.json index 11b7ad284..6d9d53fc8 100644 --- a/apps/red-ui/src/assets/i18n/de.json +++ b/apps/red-ui/src/assets/i18n/de.json @@ -585,6 +585,16 @@ } }, "content": "Begründung", + "dashboard": { + "empty-template": { + "description": "", + "new-dossier": "" + }, + "greeting": { + "subtitle": "", + "title": "" + } + }, "default-colors-screen": { "action": { "edit": "Farbe bearbeiten" diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 0cad1169f..cbd1a8491 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -8,12 +8,6 @@ "all": "All", "none": "None" }, - "dashboard": { - "greeting": { - "title": "Welcome, {name}!", - "subtitle": "Here's what's happening in your redaction teams today." - } - }, "add-dossier-dialog": { "actions": { "save": "Save", @@ -591,6 +585,16 @@ } }, "content": "Reason", + "dashboard": { + "empty-template": { + "description": "This template does not contain any dossiers. Start by creating a dossier to use it on.", + "new-dossier": "New Dossier" + }, + "greeting": { + "subtitle": "Here's what's happening in your redaction teams today.", + "title": "Welcome, {name}!" + } + }, "default-colors-screen": { "action": { "edit": "Edit Color" diff --git a/libs/common-ui b/libs/common-ui index 3684acc2c..d815449b4 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit 3684acc2c99fafc88351af188745c10065c16cdb +Subproject commit d815449b409ce3bd04f8f7fddbb74fe6ed5ef9b5 From fadbf3489457b5a6bb333a02c1444a130f7dff0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Mon, 2 May 2022 20:04:58 +0300 Subject: [PATCH 03/12] RED-3796: Navigation WIP (no files) --- apps/red-ui/src/app/app-routing.module.ts | 145 +++++++++--------- .../base-screen/base-screen.component.html | 4 +- .../guards/dossier-template-exists.guard.ts | 5 +- .../modules/archive/archive-routing.module.ts | 6 +- .../archived-dossiers-screen.component.html | 6 +- .../template-stats.component.html | 16 +- .../template-stats.component.scss | 8 + .../template-stats.component.ts | 4 + .../app/modules/dashboard/dashboard.module.ts | 6 +- ...sier-overview-screen-header.component.html | 74 ++++----- .../dossier/dossiers-routing.module.ts | 6 +- .../dossiers-listing/config.service.ts | 23 +-- .../dossiers-listing-screen.component.html | 6 +- .../dossiers-type-switch.component.html | 9 ++ .../dossiers-type-switch.component.scss | 11 ++ .../dossiers-type-switch.component.ts | 9 ++ .../src/app/modules/shared/shared.module.ts | 6 +- .../src/app/services/breadcrumbs.service.ts | 84 +++++----- .../app/services/router-history.service.ts | 6 +- apps/red-ui/src/assets/i18n/de.json | 7 +- apps/red-ui/src/assets/i18n/en.json | 9 +- libs/common-ui | 2 +- .../dossier-template.model.ts | 4 + .../src/lib/dossiers/dossier.model.ts | 2 +- libs/red-domain/src/lib/files/file.model.ts | 4 +- .../src/lib/shared/breadcrumb-types.ts | 6 +- 26 files changed, 264 insertions(+), 204 deletions(-) create mode 100644 apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.html create mode 100644 apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.scss create mode 100644 apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.ts diff --git a/apps/red-ui/src/app/app-routing.module.ts b/apps/red-ui/src/app/app-routing.module.ts index 8bf52eec7..92a08b043 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -6,11 +6,12 @@ import { BaseScreenComponent } from '@components/base-screen/base-screen.compone import { RouteReuseStrategy, RouterModule, Routes } from '@angular/router'; import { NgModule } from '@angular/core'; import { DownloadsListScreenComponent } from '@components/downloads-list-screen/downloads-list-screen.component'; -import { DossierTemplatesGuard } from '@guards/dossier-templates.guard'; import { DossiersGuard } from '@guards/dossiers.guard'; import { ACTIVE_DOSSIERS_SERVICE, ARCHIVED_DOSSIERS_SERVICE } from './tokens'; import { FeaturesGuard } from '@guards/features-guard.service'; -import { DOSSIERS_ARCHIVE } from '@utils/constants'; +import { DOSSIER_TEMPLATE_ID, DOSSIERS_ARCHIVE } from '@utils/constants'; +import { DossierTemplatesGuard } from '@guards/dossier-templates.guard'; +import { DossierTemplateExistsGuard } from '@guards/dossier-template-exists.guard'; const routes: Routes = [ { @@ -18,81 +19,85 @@ const routes: Routes = [ redirectTo: 'main/dashboard', pathMatch: 'full', }, + { + path: 'main', + component: BaseScreenComponent, + children: [ + { + path: '', + redirectTo: 'dashboard', + pathMatch: 'full', + }, + { + path: 'account', + loadChildren: () => import('./modules/account/account.module').then(m => m.AccountModule), + }, + { + path: 'admin', + loadChildren: () => import('./modules/admin/admin.module').then(m => m.AdminModule), + }, + { + path: 'dashboard', + loadChildren: () => import('./modules/dashboard/dashboard.module').then(m => m.DashboardModule), + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, RedRoleGuard], + requiredRoles: ['RED_USER', 'RED_MANAGER'], + }, + }, + { + path: `:${DOSSIER_TEMPLATE_ID}/dossiers`, + loadChildren: () => import('./modules/dossier/dossiers.module').then(m => m.DossiersModule), + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, RedRoleGuard, DossierTemplatesGuard, DossierTemplateExistsGuard, DossiersGuard], + requiredRoles: ['RED_USER', 'RED_MANAGER'], + dossiersService: ACTIVE_DOSSIERS_SERVICE, + }, + }, + { + path: `:${DOSSIER_TEMPLATE_ID}/archive`, + loadChildren: () => import('./modules/archive/archive.module').then(m => m.ArchiveModule), + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [FeaturesGuard, AuthGuard, RedRoleGuard, DossierTemplatesGuard, DossierTemplateExistsGuard, DossiersGuard], + requiredRoles: ['RED_USER', 'RED_MANAGER'], + dossiersService: ARCHIVED_DOSSIERS_SERVICE, + features: [DOSSIERS_ARCHIVE], + }, + }, + { + path: 'downloads', + component: DownloadsListScreenComponent, + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, RedRoleGuard], + }, + }, + { + path: 'search', + loadChildren: () => import('./modules/search/search.module').then(m => m.SearchModule), + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, RedRoleGuard, DossiersGuard], + requiredRoles: ['RED_USER', 'RED_MANAGER'], + }, + }, + { + path: `:${DOSSIER_TEMPLATE_ID}`, + redirectTo: `:${DOSSIER_TEMPLATE_ID}/dossiers`, + pathMatch: 'full', + }, + ], + }, { path: 'auth-error', component: AuthErrorComponent, canActivate: [AuthGuard], }, - { - path: 'main/account', - component: BaseScreenComponent, - loadChildren: () => import('./modules/account/account.module').then(m => m.AccountModule), - }, - { - path: 'main/admin', - component: BaseScreenComponent, - loadChildren: () => import('./modules/admin/admin.module').then(m => m.AdminModule), - }, - { - path: 'main/dashboard', - component: BaseScreenComponent, - loadChildren: () => import('./modules/dashboard/dashboard.module').then(m => m.DashboardModule), - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, RedRoleGuard], - requiredRoles: ['RED_USER', 'RED_MANAGER'], - }, - }, - { - path: 'main/dossiers', - component: BaseScreenComponent, - loadChildren: () => import('./modules/dossier/dossiers.module').then(m => m.DossiersModule), - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, RedRoleGuard, DossierTemplatesGuard, DossiersGuard], - requiredRoles: ['RED_USER', 'RED_MANAGER'], - dossiersService: ACTIVE_DOSSIERS_SERVICE, - }, - }, - { - path: 'main/archive', - component: BaseScreenComponent, - loadChildren: () => import('./modules/archive/archive.module').then(m => m.ArchiveModule), - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [FeaturesGuard, AuthGuard, RedRoleGuard, DossierTemplatesGuard, DossiersGuard], - requiredRoles: ['RED_USER', 'RED_MANAGER'], - dossiersService: ARCHIVED_DOSSIERS_SERVICE, - features: [DOSSIERS_ARCHIVE], - }, - }, - { - path: 'main/downloads', - component: BaseScreenComponent, - children: [ - { - path: '', - component: DownloadsListScreenComponent, - }, - ], - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, RedRoleGuard], - }, - }, - { - path: 'main/search', - component: BaseScreenComponent, - loadChildren: () => import('./modules/search/search.module').then(m => m.SearchModule), - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, RedRoleGuard, DossiersGuard], - requiredRoles: ['RED_USER', 'RED_MANAGER'], - }, - }, { path: '**', - redirectTo: 'main/dossiers', + redirectTo: 'main/dashboard', pathMatch: 'full', }, ]; diff --git a/apps/red-ui/src/app/components/base-screen/base-screen.component.html b/apps/red-ui/src/app/components/base-screen/base-screen.component.html index 7040eba5c..2f6675b9e 100644 --- a/apps/red-ui/src/app/components/base-screen/base-screen.component.html +++ b/apps/red-ui/src/app/components/base-screen/base-screen.component.html @@ -7,12 +7,12 @@
-
diff --git a/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts b/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts index 850ba72ca..aa0bf8ec1 100644 --- a/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts +++ b/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts @@ -9,9 +9,10 @@ export class DossierTemplateExistsGuard implements CanActivate { async canActivate(route: ActivatedRouteSnapshot): Promise { const dossierTemplateId: string = route.paramMap.get(DOSSIER_TEMPLATE_ID); - if (!this._dossierTemplatesService.find(dossierTemplateId)) { - await this._router.navigate(['main', 'admin', 'dossier-templates']); + const adminView = !(route.routeConfig.path.includes('dossiers') || route.routeConfig.path.includes('archive')); + const routerPath = adminView ? ['main', 'admin', 'dossier-templates'] : ['']; + await this._router.navigate(routerPath); return false; } diff --git a/apps/red-ui/src/app/modules/archive/archive-routing.module.ts b/apps/red-ui/src/app/modules/archive/archive-routing.module.ts index 9a2774a25..d9b734f59 100644 --- a/apps/red-ui/src/app/modules/archive/archive-routing.module.ts +++ b/apps/red-ui/src/app/modules/archive/archive-routing.module.ts @@ -12,14 +12,14 @@ const routes: Routes = [ path: '', pathMatch: 'full', component: ArchivedDossiersScreenComponent, - data: { breadcrumbs: [BreadcrumbTypes.archive] }, + data: { breadcrumbs: [BreadcrumbTypes.dossierTemplate] }, }, { path: `:${DOSSIER_ID}`, canActivate: [CompositeRouteGuard], data: { routeGuards: [DossierFilesGuard], - breadcrumbs: [BreadcrumbTypes.archive, BreadcrumbTypes.dossier], + breadcrumbs: [BreadcrumbTypes.dossierTemplate, BreadcrumbTypes.dossier], dossiersService: ARCHIVED_DOSSIERS_SERVICE, }, loadChildren: () => import('../dossier-overview/dossier-overview.module').then(m => m.DossierOverviewModule), @@ -29,7 +29,7 @@ const routes: Routes = [ canActivate: [CompositeRouteGuard], data: { routeGuards: [DossierFilesGuard], - breadcrumbs: [BreadcrumbTypes.archive, BreadcrumbTypes.dossier, BreadcrumbTypes.file], + breadcrumbs: [BreadcrumbTypes.dossierTemplate, BreadcrumbTypes.dossier, BreadcrumbTypes.file], dossiersService: ARCHIVED_DOSSIERS_SERVICE, }, loadChildren: () => import('../file-preview/file-preview.module').then(m => m.FilePreviewModule), diff --git a/apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.html b/apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.html index 5786e6f44..520f31b7f 100644 --- a/apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.html +++ b/apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.html @@ -1,5 +1,9 @@
- + + + + +
diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html index 663ca4131..1eb4e5072 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html @@ -1,11 +1,13 @@ -
- - - - - +
+ + {{ dossierTemplate.name }} +
+ +
+
stats2
+
-
+
{{ dossierTemplate.name }} diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss index 090ade28f..7f20e26b4 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss @@ -3,6 +3,14 @@ max-width: unset; margin: 0 0 16px 0; + .heading { + color: var(--iqser-accent); + + &:not(:hover) { + text-decoration: none; + } + } + > div { padding: 24px; display: flex; diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts index 87f9e76ae..bf1042717 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts @@ -33,6 +33,10 @@ export class TemplateStatsComponent implements OnChanges { this.stats$ = this.#ngOnChanges$.pipe(switchMap(id => this._dossierTemplateStatsService.watch$(id))); } + get empty(): boolean { + return false; + } + ngOnChanges() { if (this.dossierTemplateId) { this.#ngOnChanges$.next(this.dossierTemplateId); diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts b/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts index 588c40d67..00d7d285c 100644 --- a/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts +++ b/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts @@ -7,13 +7,17 @@ import { TemplateStatsComponent } from './components/template-stats/template-sta import { DossierTemplatesGuard } from '../../guards/dossier-templates.guard'; import { CompositeRouteGuard } from '@iqser/common-ui'; import { SharedDossiersModule } from '../dossier/shared/shared-dossiers.module'; +import { BreadcrumbTypes } from '@red/domain'; const routes = [ { path: '', component: DashboardScreenComponent, canActivate: [CompositeRouteGuard], - data: { routeGuards: [DossierTemplatesGuard] }, + data: { + routeGuards: [DossierTemplatesGuard], + breadcrumbs: [BreadcrumbTypes.dashboard], + }, }, ]; diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html index 15b9a88a0..c0a317eba 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html +++ b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html @@ -5,45 +5,47 @@ [showCloseButton]="true" [viewModeSelection]="viewModeSelection" > - + + - + - + - + + 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 2112b6bdf..98342b542 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 @@ -12,7 +12,7 @@ const routes: Routes = [ canActivate: [CompositeRouteGuard], data: { routeGuards: [DossierFilesGuard], - breadcrumbs: [BreadcrumbTypes.main, BreadcrumbTypes.dossier], + breadcrumbs: [BreadcrumbTypes.dossierTemplate, BreadcrumbTypes.dossier], dossiersService: ACTIVE_DOSSIERS_SERVICE, }, loadChildren: () => import('../dossier-overview/dossier-overview.module').then(m => m.DossierOverviewModule), @@ -22,7 +22,7 @@ const routes: Routes = [ canActivate: [CompositeRouteGuard], data: { routeGuards: [DossierFilesGuard], - breadcrumbs: [BreadcrumbTypes.main, BreadcrumbTypes.dossier, BreadcrumbTypes.file], + breadcrumbs: [BreadcrumbTypes.dossierTemplate, BreadcrumbTypes.dossier, BreadcrumbTypes.file], dossiersService: ACTIVE_DOSSIERS_SERVICE, }, loadChildren: () => import('../file-preview/file-preview.module').then(m => m.FilePreviewModule), @@ -31,7 +31,7 @@ const routes: Routes = [ path: '', pathMatch: 'full', loadChildren: () => import('../dossiers-listing/dossiers-listing.module').then(m => m.DossiersListingModule), - data: { breadcrumbs: [BreadcrumbTypes.main] }, + data: { breadcrumbs: [BreadcrumbTypes.dossierTemplate] }, }, ]; diff --git a/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts b/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts index 2861a033f..ee63347c8 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts @@ -6,9 +6,8 @@ import { TranslateService } from '@ngx-translate/core'; import { UserPreferenceService } from '@services/user-preference.service'; import { UserService } from '@services/user.service'; import { workflowFileStatusTranslations } from '../../translations/file-status-translations'; -import { dossierMemberChecker, dossierStateChecker, dossierTemplateChecker, RedactionFilterSorter } from '../../utils'; +import { dossierMemberChecker, dossierStateChecker, RedactionFilterSorter } from '../../utils'; import { workloadTranslations } from '../dossier/translations/workload-translations'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; import { DossierStatesMapService } from '@services/entity-services/dossier-states-map.service'; import { DossiersDialogService } from '../dossier/services/dossiers-dialog.service'; @@ -19,7 +18,6 @@ export class ConfigService { private readonly _translateService: TranslateService, private readonly _userPreferenceService: UserPreferenceService, private readonly _userService: UserService, - private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _dossierStatsService: DossierStatsService, private readonly _dossierStatesMapService: DossierStatesMapService, private readonly _dialogService: DossiersDialogService, @@ -57,7 +55,6 @@ export class ConfigService { const allDistinctFileStatus = new Set(); const allDistinctPeople = new Set(); const allDistinctNeedsWork = new Set(); - const allDistinctDossierTemplates = new Set(); const allDistinctDossierStates = new Set(); const stateToTemplateMap = new Map(); @@ -66,7 +63,6 @@ export class ConfigService { entities?.forEach(entry => { entry.memberIds.forEach(f => allDistinctPeople.add(f)); - allDistinctDossierTemplates.add(entry.dossierTemplateId); if (entry.dossierStatusId) { allDistinctDossierStates.add(entry.dossierStatusId); stateToTemplateMap.set(entry.dossierStatusId, entry.dossierTemplateId); @@ -160,23 +156,6 @@ export class ConfigService { matchAll: true, }); - const dossierTemplateFilters = [...allDistinctDossierTemplates].map( - id => - new NestedFilter({ - id: id, - label: this._dossierTemplatesService.find(id)?.name || '-', - }), - ); - - filterGroups.push({ - slug: 'dossierTemplateFilters', - label: this._translateService.instant('filters.dossier-templates'), - icon: 'red:template', - hide: dossierTemplateFilters.length <= 1, - filters: dossierTemplateFilters, - checker: dossierTemplateChecker, - }); - filterGroups.push({ slug: 'quickFilters', filters: this._quickFilters(entities), diff --git a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.html b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.html index 23835ba78..9f0d65e65 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.html @@ -1,5 +1,9 @@
- + + + + +
diff --git a/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.html b/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.html new file mode 100644 index 000000000..773a1e2b2 --- /dev/null +++ b/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.html @@ -0,0 +1,9 @@ + + {{ 'dossiers-type-switch.active' | translate }} + + + + {{ 'dossiers-type-switch.archive' | translate }} + + +
diff --git a/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.scss b/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.scss new file mode 100644 index 000000000..0f3831df2 --- /dev/null +++ b/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.scss @@ -0,0 +1,11 @@ +:host { + display: flex; +} + +.separator { + background-color: var(--iqser-separator); + width: 1px; + height: 30px; + margin-left: 8px; + margin-right: 16px; +} diff --git a/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.ts b/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.ts new file mode 100644 index 000000000..3f4a5b308 --- /dev/null +++ b/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.ts @@ -0,0 +1,9 @@ +import { ChangeDetectionStrategy, Component } from '@angular/core'; + +@Component({ + selector: 'redaction-dossiers-type-switch', + templateUrl: './dossiers-type-switch.component.html', + styleUrls: ['./dossiers-type-switch.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class DossiersTypeSwitchComponent {} 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 40152677f..e77823834 100644 --- a/apps/red-ui/src/app/modules/shared/shared.module.ts +++ b/apps/red-ui/src/app/modules/shared/shared.module.ts @@ -31,6 +31,9 @@ import { FileNameColumnComponent } from '@shared/components/file-name-column/fil import { DossierNameColumnComponent } from '@shared/components/dossier-name-column/dossier-name-column.component'; import { MAT_DATE_FORMATS } from '@angular/material/core'; import { DragDropFileUploadDirective } from '@shared/directives/drag-drop-file-upload.directive'; +import { DossiersTypeSwitchComponent } from '@shared/components/dossiers-type-switch/dossiers-type-switch.component'; +import { TranslateModule } from '@ngx-translate/core'; +import { RouterModule } from '@angular/router'; const buttons = [FileDownloadBtnComponent, UserButtonComponent]; @@ -51,6 +54,7 @@ const components = [ DossierNameColumnComponent, FileStatsComponent, FileNameColumnComponent, + DossiersTypeSwitchComponent, ...buttons, ]; @@ -61,7 +65,7 @@ const modules = [MatConfigModule, ScrollingModule, IconsModule, FormsModule, Rea @NgModule({ declarations: [...components, ...utils, EditorComponent], - imports: [CommonModule, ...modules, MonacoEditorModule], + imports: [CommonModule, ...modules, MonacoEditorModule, TranslateModule, RouterModule], exports: [...modules, ...components, ...utils], providers: [ { diff --git a/apps/red-ui/src/app/services/breadcrumbs.service.ts b/apps/red-ui/src/app/services/breadcrumbs.service.ts index 12238cd6b..0ac465ea4 100644 --- a/apps/red-ui/src/app/services/breadcrumbs.service.ts +++ b/apps/red-ui/src/app/services/breadcrumbs.service.ts @@ -6,10 +6,11 @@ import { filter, pluck } from 'rxjs/operators'; import { FilesMapService } from '@services/entity-services/files-map.service'; import { TranslateService } from '@ngx-translate/core'; import { BreadcrumbTypes } from '@red/domain'; -import { DOSSIER_ID, DOSSIERS_ARCHIVE, FILE_ID } from '@utils/constants'; +import { DOSSIER_ID, DOSSIER_TEMPLATE_ID, DOSSIERS_ARCHIVE, FILE_ID } from '@utils/constants'; import { DossiersService } from '@services/dossiers/dossiers.service'; import { dossiersServiceResolver } from '@services/entity-services/dossiers.service.provider'; import { FeaturesService } from '@services/features.service'; +import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; export type RouterLinkActiveOptions = { exact: boolean } | IsActiveMatchOptions; export type BreadcrumbDisplayType = 'text' | 'dropdown'; @@ -40,6 +41,7 @@ export class BreadcrumbsService { private readonly _router: Router, private readonly _translateService: TranslateService, private readonly _filesMapService: FilesMapService, + private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _featuresService: FeaturesService, ) { this.breadcrumbs$ = this._store$.asObservable(); @@ -59,23 +61,12 @@ export class BreadcrumbsService { return dossiersServiceResolver(this._injector); } - private get _mainBreadcrumb(): Breadcrumb { + private get _dashboardBreadcrumb(): Breadcrumb { return { - name$: of(this._translateService.instant('top-bar.navigation-items.dossiers')), + name$: of(this._translateService.instant('top-bar.navigation-items.dashboard')), type: 'text' as BreadcrumbDisplayType, options: { - routerLink: ['/main', 'dossiers'], - routerLinkActiveOptions: { exact: true }, - }, - }; - } - - private get _archiveBreadcrumb(): Breadcrumb { - return { - name$: of(this._translateService.instant('top-bar.navigation-items.archived-dossiers')), - type: 'text' as BreadcrumbDisplayType, - options: { - routerLink: ['/main', 'archive'], + routerLink: ['/main', 'dashboard'], routerLinkActiveOptions: { exact: true }, }, }; @@ -89,81 +80,94 @@ export class BreadcrumbsService { this._store$.next([]); } - private _addBreadcrumbs(route: ActivatedRouteSnapshot) { + private _addBreadcrumbs(route: ActivatedRouteSnapshot, params: Record = {}) { if (route.firstChild) { - this._addBreadcrumbs(route.firstChild); + this._addBreadcrumbs(route.firstChild, { ...params, ...route.params }); return; } const breadcrumbs = route.data.breadcrumbs || []; if (breadcrumbs.length === 1 && this._featuresService.isEnabled(DOSSIERS_ARCHIVE)) { - if (breadcrumbs[0] === BreadcrumbTypes.main) { - this._addMainDropdownBreadcrumb('active'); + if (breadcrumbs[0] === BreadcrumbTypes.dossierTemplate) { + this._addDossierTemplateDropdown(params); return; } - if (breadcrumbs[0] === BreadcrumbTypes.archive) { - this._addMainDropdownBreadcrumb('archived'); + if (breadcrumbs[0] === BreadcrumbTypes.dashboard) { + this._append(this._dashboardBreadcrumb); return; } } for (const breadcrumb of breadcrumbs) { switch (breadcrumb) { - case BreadcrumbTypes.main: - this._append(this._mainBreadcrumb); - break; - case BreadcrumbTypes.archive: - this._append(this._archiveBreadcrumb); + case BreadcrumbTypes.dossierTemplate: + this._append(this._dossierTemplateBreadcrumb(params)); break; case BreadcrumbTypes.dossier: - this._addDossierBreadcrumb(route); + this._addDossierBreadcrumb(params); break; case BreadcrumbTypes.file: - this._addFileBreadcrumb(route); + this._addFileBreadcrumb(params); break; } } } - private _addMainDropdownBreadcrumb(type: 'active' | 'archived'): void { - const activeDossiers: Breadcrumb = this._mainBreadcrumb; - const archivedDossiers: Breadcrumb = this._archiveBreadcrumb; - const activeOption = type === 'active' ? activeDossiers : archivedDossiers; + private _addDossierTemplateDropdown(params: Record): void { + const breadcrumbs = this._dossierTemplatesService.all.map(dossierTemplate => + this._dossierTemplateBreadcrumb({ dossierTemplateId: dossierTemplate.id }), + ); + const activeOption = breadcrumbs.find(b => b.options.routerLink[1] === params[DOSSIER_TEMPLATE_ID]); this._append({ name$: activeOption.name$, type: 'dropdown' as BreadcrumbDisplayType, options: { - options: [activeDossiers, archivedDossiers], + options: breadcrumbs, activeOption, }, }); } - private _addDossierBreadcrumb(route: ActivatedRouteSnapshot): void { + private _dossierTemplateBreadcrumb(params: Record): Breadcrumb { + const dossierTemplateId: string = params[DOSSIER_TEMPLATE_ID]; + return { + name$: this._dossierTemplatesService.getEntityChanged$(dossierTemplateId).pipe(pluck('name')), + type: 'text' as BreadcrumbDisplayType, + options: { + routerLink: ['/main', dossierTemplateId], + routerLinkActiveOptions: { exact: true }, + clamp: true, + }, + }; + } + + private _addDossierBreadcrumb(params: Record): void { const dossiersService = this._dossiersService; - const dossierId = route.paramMap.get(DOSSIER_ID); + const dossierId: string = params[DOSSIER_ID]; + const dossierTemplateId: string = params[DOSSIER_TEMPLATE_ID]; this._append({ name$: dossiersService.getEntityChanged$(dossierId).pipe(pluck('dossierName')), type: 'text' as BreadcrumbDisplayType, options: { - routerLink: ['/main', dossiersService.routerPath, dossierId], + routerLink: ['/main', dossierTemplateId, dossiersService.routerPath, dossierId], routerLinkActiveOptions: { exact: true }, clamp: true, }, }); } - private _addFileBreadcrumb(route: ActivatedRouteSnapshot): void { - const dossierId = route.paramMap.get(DOSSIER_ID); - const fileId = route.paramMap.get(FILE_ID); + private _addFileBreadcrumb(params: Record): void { + const dossierTemplateId: string = params[DOSSIER_TEMPLATE_ID]; + const dossierId: string = params[DOSSIER_ID]; + const fileId: string = params[FILE_ID]; const dossiersService = this._dossiersService; this._append({ name$: this._filesMapService.watch$(dossierId, fileId).pipe(pluck('filename')), type: 'text' as BreadcrumbDisplayType, options: { - routerLink: ['/main', dossiersService.routerPath, dossierId, 'file', fileId], + routerLink: ['/main', dossierTemplateId, dossiersService.routerPath, dossierId, 'file', fileId], clamp: true, }, }); diff --git a/apps/red-ui/src/app/services/router-history.service.ts b/apps/red-ui/src/app/services/router-history.service.ts index 5e87a8b82..62fc4177a 100644 --- a/apps/red-ui/src/app/services/router-history.service.ts +++ b/apps/red-ui/src/app/services/router-history.service.ts @@ -6,11 +6,11 @@ import { filter } from 'rxjs/operators'; providedIn: 'root', }) export class RouterHistoryService { - private _lastDossiersScreen = '/main/dossiers'; + private _lastDossiersScreen = '/'; constructor(private readonly _router: Router) { this._router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe((event: NavigationEnd) => { - if (event.url.startsWith('/main/dossiers')) { + if (event.url.includes('/dossiers') || event.url.includes('/archive')) { this._lastDossiersScreen = event.url; } }); @@ -18,7 +18,7 @@ export class RouterHistoryService { navigateToLastDossiersScreen(): void { if (this._router.url === this._lastDossiersScreen) { - this._router.navigate(['/main/dossiers']); + this._router.navigate(['/']); } else { this._router.navigate([this._lastDossiersScreen]); } diff --git a/apps/red-ui/src/assets/i18n/de.json b/apps/red-ui/src/assets/i18n/de.json index c1a3b4833..c7e80f795 100644 --- a/apps/red-ui/src/assets/i18n/de.json +++ b/apps/red-ui/src/assets/i18n/de.json @@ -976,6 +976,10 @@ "incomplete": "" } }, + "dossiers-type-switch": { + "active": "", + "archive": "" + }, "download-includes": "Wählen Sie die Dokumente für Ihr Download-Paket aus", "download-status": { "queued": "Ihr Download wurde zur Warteschlange hinzugefügt. Hier finden Sie alle angeforderten Downloads: My Downloads." @@ -1877,9 +1881,8 @@ }, "top-bar": { "navigation-items": { - "archived-dossiers": "", "back": "Zurück", - "dossiers": "Aktives Dossier", + "dashboard": "", "my-account": { "children": { "account": "Konto", diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index a606856e6..506ab0e25 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -976,6 +976,10 @@ "incomplete": "Incomplete" } }, + "dossiers-type-switch": { + "active": "Active", + "archive": "Archived" + }, "download-includes": "Choose what is included at download:", "download-status": { "queued": "Your download has been queued, you can see all your requested downloads here: My Downloads." @@ -1393,7 +1397,7 @@ "dossier-state": "Dossier State", "dossier-templates": "Dossier Templates", "empty": "Empty", - "filter-by": "Filter:", + "filter-by": "Filter by:", "needs-work": "Workload", "people": "Dossier Member(s)" }, @@ -1877,9 +1881,8 @@ }, "top-bar": { "navigation-items": { - "archived-dossiers": "Archived Dossiers", "back": "Back", - "dossiers": "Active Dossiers", + "dashboard": "Dashboard", "my-account": { "children": { "account": "Account", diff --git a/libs/common-ui b/libs/common-ui index d815449b4..7bc942ae1 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit d815449b409ce3bd04f8f7fddbb74fe6ed5ef9b5 +Subproject commit 7bc942ae164164dadba94045f1f249a6cbb17284 diff --git a/libs/red-domain/src/lib/dossier-templates/dossier-template.model.ts b/libs/red-domain/src/lib/dossier-templates/dossier-template.model.ts index 703853f39..82f5cc5d3 100644 --- a/libs/red-domain/src/lib/dossier-templates/dossier-template.model.ts +++ b/libs/red-domain/src/lib/dossier-templates/dossier-template.model.ts @@ -47,4 +47,8 @@ export class DossierTemplate implements IDossierTemplate, IListable { get routerLink(): string { return `/main/admin/dossier-templates/${this.dossierTemplateId}`; } + + get dossiersRouterLink(): string { + return `/main/${this.dossierTemplateId}/dossiers`; + } } diff --git a/libs/red-domain/src/lib/dossiers/dossier.model.ts b/libs/red-domain/src/lib/dossiers/dossier.model.ts index 8d3eb5db6..f50d5ecec 100644 --- a/libs/red-domain/src/lib/dossiers/dossier.model.ts +++ b/libs/red-domain/src/lib/dossiers/dossier.model.ts @@ -50,7 +50,7 @@ export class Dossier implements IDossier, IListable, IRouterPath { } get routerLink(): string { - return `/main/${this.routerPath}/${this.dossierId}`; + return `/main/${this.dossierTemplateId}/${this.routerPath}/${this.dossierId}`; } get searchKey(): string { diff --git a/libs/red-domain/src/lib/files/file.model.ts b/libs/red-domain/src/lib/files/file.model.ts index c47c6e092..5ec6048dc 100644 --- a/libs/red-domain/src/lib/files/file.model.ts +++ b/libs/red-domain/src/lib/files/file.model.ts @@ -70,7 +70,7 @@ export class File extends Entity implements IFile, IRouterPath { readonly canBeOpened: boolean; readonly canBeOCRed: boolean; - constructor(file: IFile, readonly reviewerName: string, readonly routerPath: string) { + constructor(file: IFile, readonly reviewerName: string, readonly routerPath: string, readonly dossierTemplateId?: string) { super(file); this.added = file.added; this.allManualRedactionsApplied = !!file.allManualRedactionsApplied; @@ -146,6 +146,6 @@ export class File extends Entity implements IFile, IRouterPath { } get routerLink(): string | undefined { - return this.canBeOpened ? `/main/${this.routerPath}/${this.dossierId}/file/${this.fileId}` : undefined; + return this.canBeOpened ? `/main/${this.dossierTemplateId}/${this.routerPath}/${this.dossierId}/file/${this.fileId}` : undefined; } } diff --git a/libs/red-domain/src/lib/shared/breadcrumb-types.ts b/libs/red-domain/src/lib/shared/breadcrumb-types.ts index 74ed8ae69..727c9afee 100644 --- a/libs/red-domain/src/lib/shared/breadcrumb-types.ts +++ b/libs/red-domain/src/lib/shared/breadcrumb-types.ts @@ -1,8 +1,8 @@ -export type BreadcrumbType = 'main' | 'dossier' | 'file' | 'archive'; +export type BreadcrumbType = 'dossierTemplate' | 'dossier' | 'file' | 'dashboard'; export const BreadcrumbTypes = { - main: 'main' as BreadcrumbType, + dossierTemplate: 'dossierTemplate' as BreadcrumbType, dossier: 'dossier' as BreadcrumbType, file: 'file' as BreadcrumbType, - archive: 'archive' as BreadcrumbType, + dashboard: 'dashboard' as BreadcrumbType, }; From 06c9b2bbc78c373f1fa2824061ab4a8dc13d3d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Tue, 3 May 2022 23:02:13 +0300 Subject: [PATCH 04/12] RED-3796: Removed routerPath --- apps/red-ui/src/app/app-routing.module.ts | 50 +++++++++++-------- .../base-screen/base-screen.component.ts | 7 ++- .../src/app/guards/dossier-files-guard.ts | 7 +-- .../guards/dossier-template-exists.guard.ts | 2 +- ...clone-dossier-template-dialog.component.ts | 30 +++++------ .../src/app/modules/auth/red-role.guard.ts | 12 ++--- .../dossier-details-stats.component.ts | 2 +- ...sier-overview-screen-header.component.html | 2 +- .../dossier-overview-screen.component.ts | 4 +- .../edit-dossier-general-info.component.ts | 4 +- .../services/file-preview-state.service.ts | 2 +- .../dossiers-type-switch.component.html | 4 +- .../dossiers-type-switch.component.ts | 6 ++- .../services/file-upload.service.ts | 2 +- .../src/app/services/breadcrumbs.service.ts | 9 ++-- .../dossiers/active-dossiers.service.ts | 4 +- .../dossiers/archived-dossiers.service.ts | 4 +- .../app/services/dossiers/dossiers.service.ts | 4 +- .../file-management.service.ts | 9 ++-- .../entity-services/files-map.service.ts | 6 +-- .../services/entity-services/files.service.ts | 42 ++++++---------- .../platform-search.service.ts | 2 +- .../services/entity-services/trash.service.ts | 4 +- .../src/app/services/reanalysis.service.ts | 27 ++++------ apps/red-ui/src/app/utils/constants.ts | 3 ++ apps/red-ui/src/assets/config/config.json | 4 +- libs/common-ui | 2 +- .../src/lib/dossiers/dossier.model.ts | 14 ++++-- libs/red-domain/src/lib/files/file.model.ts | 14 ++++-- libs/red-domain/src/lib/files/file.ts | 4 ++ 30 files changed, 144 insertions(+), 142 deletions(-) diff --git a/apps/red-ui/src/app/app-routing.module.ts b/apps/red-ui/src/app/app-routing.module.ts index 92a08b043..fde2d9f9c 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -9,7 +9,7 @@ import { DownloadsListScreenComponent } from '@components/downloads-list-screen/ import { DossiersGuard } from '@guards/dossiers.guard'; import { ACTIVE_DOSSIERS_SERVICE, ARCHIVED_DOSSIERS_SERVICE } from './tokens'; import { FeaturesGuard } from '@guards/features-guard.service'; -import { DOSSIER_TEMPLATE_ID, DOSSIERS_ARCHIVE } from '@utils/constants'; +import { ARCHIVE_ROUTE, DOSSIER_TEMPLATE_ID, DOSSIERS_ARCHIVE, DOSSIERS_ROUTE } from '@utils/constants'; import { DossierTemplatesGuard } from '@guards/dossier-templates.guard'; import { DossierTemplateExistsGuard } from '@guards/dossier-template-exists.guard'; @@ -46,24 +46,37 @@ const routes: Routes = [ }, }, { - path: `:${DOSSIER_TEMPLATE_ID}/dossiers`, - loadChildren: () => import('./modules/dossier/dossiers.module').then(m => m.DossiersModule), + path: `:${DOSSIER_TEMPLATE_ID}`, + children: [ + { + path: `${DOSSIERS_ROUTE}`, + loadChildren: () => import('./modules/dossier/dossiers.module').then(m => m.DossiersModule), + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [DossiersGuard], + dossiersService: ACTIVE_DOSSIERS_SERVICE, + }, + }, + { + path: `${ARCHIVE_ROUTE}`, + loadChildren: () => import('./modules/archive/archive.module').then(m => m.ArchiveModule), + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [FeaturesGuard, DossiersGuard], + dossiersService: ARCHIVED_DOSSIERS_SERVICE, + features: [DOSSIERS_ARCHIVE], + }, + }, + { + path: '**', + redirectTo: `${DOSSIERS_ROUTE}`, + pathMatch: 'full', + }, + ], canActivate: [CompositeRouteGuard], data: { - routeGuards: [AuthGuard, RedRoleGuard, DossierTemplatesGuard, DossierTemplateExistsGuard, DossiersGuard], + routeGuards: [AuthGuard, RedRoleGuard, DossierTemplatesGuard, DossierTemplateExistsGuard], requiredRoles: ['RED_USER', 'RED_MANAGER'], - dossiersService: ACTIVE_DOSSIERS_SERVICE, - }, - }, - { - path: `:${DOSSIER_TEMPLATE_ID}/archive`, - loadChildren: () => import('./modules/archive/archive.module').then(m => m.ArchiveModule), - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [FeaturesGuard, AuthGuard, RedRoleGuard, DossierTemplatesGuard, DossierTemplateExistsGuard, DossiersGuard], - requiredRoles: ['RED_USER', 'RED_MANAGER'], - dossiersService: ARCHIVED_DOSSIERS_SERVICE, - features: [DOSSIERS_ARCHIVE], }, }, { @@ -83,11 +96,6 @@ const routes: Routes = [ requiredRoles: ['RED_USER', 'RED_MANAGER'], }, }, - { - path: `:${DOSSIER_TEMPLATE_ID}`, - redirectTo: `:${DOSSIER_TEMPLATE_ID}/dossiers`, - pathMatch: 'full', - }, ], }, { diff --git a/apps/red-ui/src/app/components/base-screen/base-screen.component.ts b/apps/red-ui/src/app/components/base-screen/base-screen.component.ts index 12e8a0df5..943d9e36c 100644 --- a/apps/red-ui/src/app/components/base-screen/base-screen.component.ts +++ b/apps/red-ui/src/app/components/base-screen/base-screen.component.ts @@ -7,10 +7,10 @@ import { TranslateService } from '@ngx-translate/core'; import { SpotlightSearchAction } from '@components/spotlight-search/spotlight-search-action'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { filter, map, startWith } from 'rxjs/operators'; -import { HelpModeService, shareDistinctLast } from '@iqser/common-ui'; +import { shareDistinctLast } from '@iqser/common-ui'; import { BreadcrumbsService } from '@services/breadcrumbs.service'; import { FeaturesService } from '@services/features.service'; -import { DOSSIERS_ARCHIVE } from '@utils/constants'; +import { ARCHIVE_ROUTE, DOSSIERS_ARCHIVE, DOSSIERS_ROUTE } from '@utils/constants'; interface MenuItem { readonly id: string; @@ -91,7 +91,6 @@ export class BaseScreenComponent { readonly userPreferenceService: UserPreferenceService, readonly titleService: Title, readonly breadcrumbsService: BreadcrumbsService, - readonly helpModeService: HelpModeService, ) {} private get _hideSearchThisDossier() { @@ -100,7 +99,7 @@ export class BaseScreenComponent { return true; } - const isDossierOverview = (routerLink.includes('dossiers') || routerLink.includes('archive')) && routerLink.length === 3; + const isDossierOverview = (routerLink.includes(DOSSIERS_ROUTE) || routerLink.includes(ARCHIVE_ROUTE)) && routerLink.length === 3; return !isDossierOverview; } diff --git a/apps/red-ui/src/app/guards/dossier-files-guard.ts b/apps/red-ui/src/app/guards/dossier-files-guard.ts index b6229360b..9aab2878a 100644 --- a/apps/red-ui/src/app/guards/dossier-files-guard.ts +++ b/apps/red-ui/src/app/guards/dossier-files-guard.ts @@ -3,7 +3,7 @@ import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; import { FilesMapService } from '@services/entity-services/files-map.service'; import { FilesService } from '@services/entity-services/files.service'; import { firstValueFrom } from 'rxjs'; -import { DOSSIER_ID } from '@utils/constants'; +import { DOSSIER_ID, DOSSIER_TEMPLATE_ID } from '@utils/constants'; import { DossiersService } from '@services/dossiers/dossiers.service'; @Injectable({ providedIn: 'root' }) @@ -17,16 +17,17 @@ export class DossierFilesGuard implements CanActivate { async canActivate(route: ActivatedRouteSnapshot): Promise { const dossierId = route.paramMap.get(DOSSIER_ID); + const dossierTemplateId = route.paramMap.get(DOSSIER_TEMPLATE_ID); const token: ProviderToken = route.data.dossiersService; const dossiersService: DossiersService = this._injector.get(token); if (!dossiersService.has(dossierId)) { - await this._router.navigate(['/main', dossiersService.routerPath]); + await this._router.navigate(['/main', dossierTemplateId]); return false; } if (!this._filesMapService.has(dossierId)) { - await firstValueFrom(this._filesService.loadAll(dossierId, dossiersService.routerPath)); + await firstValueFrom(this._filesService.loadAll(dossierId)); } return true; } diff --git a/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts b/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts index aa0bf8ec1..655a56dfe 100644 --- a/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts +++ b/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts @@ -10,7 +10,7 @@ export class DossierTemplateExistsGuard implements CanActivate { async canActivate(route: ActivatedRouteSnapshot): Promise { const dossierTemplateId: string = route.paramMap.get(DOSSIER_TEMPLATE_ID); if (!this._dossierTemplatesService.find(dossierTemplateId)) { - const adminView = !(route.routeConfig.path.includes('dossiers') || route.routeConfig.path.includes('archive')); + const adminView = !!route.pathFromRoot.find(r => r.routeConfig?.path === 'admin'); const routerPath = adminView ? ['main', 'admin', 'dossier-templates'] : ['']; await this._router.navigate(routerPath); return false; diff --git a/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.ts index 51437e070..3ae953481 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.ts @@ -1,8 +1,8 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { DossierTemplatesService } from '../../../../services/entity-services/dossier-templates.service'; -import { DossierTemplate, IDossierTemplate } from '../../../../../../../../libs/red-domain/src'; -import { LoadingService, Toaster } from '../../../../../../../../libs/common-ui/src'; +import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplate } from '@red/domain'; +import { LoadingService, Toaster } from '@iqser/common-ui'; import { firstValueFrom } from 'rxjs'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; @@ -11,8 +11,8 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; styleUrls: ['./clone-dossier-template-dialog.component.scss'], }) export class CloneDossierTemplateDialogComponent { - private readonly _dossierTemplate: DossierTemplate; nameOfClonedDossierTemplate: string; + private readonly _dossierTemplate: DossierTemplate; constructor( private readonly _toaster: Toaster, @@ -25,6 +25,17 @@ export class CloneDossierTemplateDialogComponent { this.nameOfClonedDossierTemplate = this._getCloneName(); } + async save() { + this._loadingService.start(); + try { + await firstValueFrom(this._dossierTemplatesService.clone(this.dossierTemplateId, this.nameOfClonedDossierTemplate)); + this._dialogRef.close(true); + } catch (error: any) { + this._toaster.error(_('clone-dossier-template.error.generic'), { error }); + } + this._loadingService.stop(); + } + private _getCloneName(): string | null { const templateName = this._dossierTemplate.name.trim(); @@ -47,15 +58,4 @@ export class CloneDossierTemplateDialogComponent { } return `Clone of ${nameOfClonedTemplate}`; } - - async save() { - this._loadingService.start(); - try { - await firstValueFrom(this._dossierTemplatesService.clone(this.dossierTemplateId, this.nameOfClonedDossierTemplate)); - this._dialogRef.close(true); - } catch (error: any) { - this._toaster.error(_('clone-dossier-template.error.generic'), { error }); - } - this._loadingService.stop(); - } } diff --git a/apps/red-ui/src/app/modules/auth/red-role.guard.ts b/apps/red-ui/src/app/modules/auth/red-role.guard.ts index f9d43d465..e9f33c587 100644 --- a/apps/red-ui/src/app/modules/auth/red-role.guard.ts +++ b/apps/red-ui/src/app/modules/auth/red-role.guard.ts @@ -49,18 +49,16 @@ export class RedRoleGuard implements CanActivate { return; } - if (!this._userService.currentUser.isUser && state.url.startsWith('/main/dossiers')) { - this._router.navigate(['/main/admin']); - obs.next(false); - obs.complete(); - return; - } if (route.data.requiredRoles) { if (this._userService.hasAnyRole(route.data.requiredRoles)) { obs.next(true); obs.complete(); } else { - this._router.navigate(['/main/dossiers']); + if (!this._userService.currentUser.isUser) { + this._router.navigate(['/main/admin']); + } else { + this._router.navigate(['/']); + } obs.next(false); obs.complete(); } diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.ts b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.ts index 171927d46..eb0f1d0ce 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.ts @@ -35,7 +35,7 @@ export class DossierDetailsStatsComponent implements OnInit { openEditDossierDialog(section: string): void { const data = { dossierId: this.dossier.dossierId, section }; this._dialogService.openDialog('editDossier', null, data, async () => { - await firstValueFrom(this._filesService.loadAll(this.dossier.dossierId, this.dossier.routerPath)); + await firstValueFrom(this._filesService.loadAll(this.dossier.dossierId)); }); } } diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html index c0a317eba..c8e337ebf 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html +++ b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.html @@ -1,5 +1,5 @@ imple get #dossierFilesChange$() { return this._dossiersService.dossierFileChanges$.pipe( filter(dossierId => dossierId === this.dossierId), - switchMap(dossierId => this._filesService.loadAll(dossierId, this._dossiersService.routerPath)), + switchMap(dossierId => this._filesService.loadAll(dossierId)), ); } diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.ts index a7a060260..abcdf8c98 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.ts @@ -139,7 +139,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti this._loadingService.start(); await firstValueFrom(this._trashService.deleteDossier(this.dossier)); this._editDossierDialogRef.close(); - await this._router.navigate(['main', 'dossiers']); + await this._router.navigate([this.dossier.dossiersListRouterLink]); this._loadingService.stop(); this._toaster.success(_('edit-dossier-dialog.delete-successful'), { params: this.dossier }); }); @@ -161,7 +161,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti if (result === ConfirmOptions.CONFIRM) { this._loadingService.start(); await firstValueFrom(this._archivedDossiersService.archive([this.dossier])); - await this._router.navigate(['main', 'dossiers']); + await this._router.navigate([this.dossier.dossiersListRouterLink]); this._toaster.success(_('dossier-listing.archive.archive-succeeded'), { params: this.dossier }); this._editDossierDialogRef.close(); this._loadingService.stop(); diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts index 34e546838..ddf8ac2e2 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts @@ -81,7 +81,7 @@ export class FilePreviewStateService { #dossierFilesChange$() { return this._dossiersService.dossierFileChanges$.pipe( filter(dossierId => dossierId === this.dossierId), - switchMap(dossierId => this._filesService.loadAll(dossierId, this._dossiersService.routerPath)), + switchMap(dossierId => this._filesService.loadAll(dossierId)), ); } diff --git a/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.html b/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.html index 773a1e2b2..885248299 100644 --- a/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.html +++ b/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.html @@ -1,8 +1,8 @@ - + {{ 'dossiers-type-switch.active' | translate }} - + {{ 'dossiers-type-switch.archive' | translate }} diff --git a/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.ts b/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.ts index 3f4a5b308..7488e01da 100644 --- a/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/dossiers-type-switch/dossiers-type-switch.component.ts @@ -1,4 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; +import { ARCHIVE_ROUTE, DOSSIERS_ROUTE } from '@utils/constants'; @Component({ selector: 'redaction-dossiers-type-switch', @@ -6,4 +7,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; styleUrls: ['./dossiers-type-switch.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class DossiersTypeSwitchComponent {} +export class DossiersTypeSwitchComponent { + readonly DOSSIERS_ROUTE = DOSSIERS_ROUTE; + readonly ARCHIVE_ROUTE = ARCHIVE_ROUTE; +} diff --git a/apps/red-ui/src/app/modules/upload-download/services/file-upload.service.ts b/apps/red-ui/src/app/modules/upload-download/services/file-upload.service.ts index 5a7e86f1c..9d669a7f3 100644 --- a/apps/red-ui/src/app/modules/upload-download/services/file-upload.service.ts +++ b/apps/red-ui/src/app/modules/upload-download/services/file-upload.service.ts @@ -42,7 +42,7 @@ export class FileUploadService extends GenericService impleme super(_injector, 'upload'); const fileFetch$ = this._fetchFiles$.pipe( throttleTime(250), - switchMap(dossierId => this._filesService.loadAll(dossierId, 'dossiers')), + switchMap(dossierId => this._filesService.loadAll(dossierId)), ); this._subscriptions.add(fileFetch$.subscribe()); const interval$ = interval(2500).pipe(tap(() => this._handleUploads())); diff --git a/apps/red-ui/src/app/services/breadcrumbs.service.ts b/apps/red-ui/src/app/services/breadcrumbs.service.ts index 0ac465ea4..1cd1d22aa 100644 --- a/apps/red-ui/src/app/services/breadcrumbs.service.ts +++ b/apps/red-ui/src/app/services/breadcrumbs.service.ts @@ -136,7 +136,7 @@ export class BreadcrumbsService { name$: this._dossierTemplatesService.getEntityChanged$(dossierTemplateId).pipe(pluck('name')), type: 'text' as BreadcrumbDisplayType, options: { - routerLink: ['/main', dossierTemplateId], + routerLink: ['/main', dossierTemplateId, this._dossiersService.routerPath], routerLinkActiveOptions: { exact: true }, clamp: true, }, @@ -146,12 +146,11 @@ export class BreadcrumbsService { private _addDossierBreadcrumb(params: Record): void { const dossiersService = this._dossiersService; const dossierId: string = params[DOSSIER_ID]; - const dossierTemplateId: string = params[DOSSIER_TEMPLATE_ID]; this._append({ name$: dossiersService.getEntityChanged$(dossierId).pipe(pluck('dossierName')), type: 'text' as BreadcrumbDisplayType, options: { - routerLink: ['/main', dossierTemplateId, dossiersService.routerPath, dossierId], + routerLink: [dossiersService.find(dossierId).routerLink], routerLinkActiveOptions: { exact: true }, clamp: true, }, @@ -159,15 +158,13 @@ export class BreadcrumbsService { } private _addFileBreadcrumb(params: Record): void { - const dossierTemplateId: string = params[DOSSIER_TEMPLATE_ID]; const dossierId: string = params[DOSSIER_ID]; const fileId: string = params[FILE_ID]; - const dossiersService = this._dossiersService; this._append({ name$: this._filesMapService.watch$(dossierId, fileId).pipe(pluck('filename')), type: 'text' as BreadcrumbDisplayType, options: { - routerLink: ['/main', dossierTemplateId, dossiersService.routerPath, dossierId, 'file', fileId], + routerLink: [this._filesMapService.get(dossierId, fileId).routerLink], clamp: true, }, }); diff --git a/apps/red-ui/src/app/services/dossiers/active-dossiers.service.ts b/apps/red-ui/src/app/services/dossiers/active-dossiers.service.ts index 0112b0ac6..95291300e 100644 --- a/apps/red-ui/src/app/services/dossiers/active-dossiers.service.ts +++ b/apps/red-ui/src/app/services/dossiers/active-dossiers.service.ts @@ -1,7 +1,7 @@ import { Injectable, Injector } from '@angular/core'; import { switchMap, tap } from 'rxjs/operators'; import { timer } from 'rxjs'; -import { CHANGED_CHECK_INTERVAL } from '@utils/constants'; +import { CHANGED_CHECK_INTERVAL, DOSSIERS_ROUTE } from '@utils/constants'; import { DossiersService } from './dossiers.service'; export interface IDossiersStats { @@ -14,7 +14,7 @@ export interface IDossiersStats { }) export class ActiveDossiersService extends DossiersService { constructor(protected readonly _injector: Injector) { - super(_injector, 'dossier', 'dossiers'); + super(_injector, 'dossier', DOSSIERS_ROUTE); timer(CHANGED_CHECK_INTERVAL, CHANGED_CHECK_INTERVAL) .pipe( diff --git a/apps/red-ui/src/app/services/dossiers/archived-dossiers.service.ts b/apps/red-ui/src/app/services/dossiers/archived-dossiers.service.ts index 0f496c809..739933d98 100644 --- a/apps/red-ui/src/app/services/dossiers/archived-dossiers.service.ts +++ b/apps/red-ui/src/app/services/dossiers/archived-dossiers.service.ts @@ -7,7 +7,7 @@ import { ActiveDossiersService } from './active-dossiers.service'; import { DossiersService } from './dossiers.service'; import { FilesMapService } from '../entity-services/files-map.service'; import { FeaturesService } from '@services/features.service'; -import { DOSSIERS_ARCHIVE } from '@utils/constants'; +import { ARCHIVE_ROUTE, DOSSIERS_ARCHIVE } from '@utils/constants'; @Injectable({ providedIn: 'root' }) export class ArchivedDossiersService extends DossiersService { @@ -17,7 +17,7 @@ export class ArchivedDossiersService extends DossiersService { private readonly _filesMapService: FilesMapService, private readonly _featuresService: FeaturesService, ) { - super(_injector, 'archived-dossiers', 'archive'); + super(_injector, 'archived-dossiers', ARCHIVE_ROUTE); } archive(dossiers: Dossier[]): Observable { diff --git a/apps/red-ui/src/app/services/dossiers/dossiers.service.ts b/apps/red-ui/src/app/services/dossiers/dossiers.service.ts index 9f8f9d5a2..32d44d88f 100644 --- a/apps/red-ui/src/app/services/dossiers/dossiers.service.ts +++ b/apps/red-ui/src/app/services/dossiers/dossiers.service.ts @@ -61,7 +61,7 @@ export abstract class DossiersService extends EntitiesService loadAll(): Observable { const dossierIds = (dossiers: Dossier[]) => dossiers.map(d => d.id); return this.getAll().pipe( - mapEach(entity => new Dossier(entity, this.routerPath)), + mapEach(entity => new Dossier(entity)), /* Load stats before updating entities */ switchMap(dossiers => this._dossierStatsService.getFor(dossierIds(dossiers)).pipe(map(() => dossiers))), switchMap(dossiers => this._dossierStateService.loadAllForAllTemplates().pipe(map(() => dossiers))), @@ -81,7 +81,7 @@ export abstract class DossiersService extends EntitiesService private _load(id: string): Observable { const queryParams: List = [{ key: 'includeArchived', value: this._path === 'archived-dossiers' }]; return super._getOne([id], this._defaultModelPath, queryParams).pipe( - map(entity => new Dossier(entity, 'dossiers')), + map(entity => new Dossier(entity)), tap(dossier => this.replace(dossier)), switchMap(dossier => this._dossierStatsService.getFor([dossier.dossierId])), ); diff --git a/apps/red-ui/src/app/services/entity-services/file-management.service.ts b/apps/red-ui/src/app/services/entity-services/file-management.service.ts index 0d26bb4cd..a37a33a07 100644 --- a/apps/red-ui/src/app/services/entity-services/file-management.service.ts +++ b/apps/red-ui/src/app/services/entity-services/file-management.service.ts @@ -1,11 +1,11 @@ -import { GenericService, HeadersConfiguration, IRouterPath, List, QueryParam, RequiredParam, Validate } from '@iqser/common-ui'; +import { GenericService, HeadersConfiguration, List, QueryParam, RequiredParam, Validate } from '@iqser/common-ui'; import { Injectable, Injector } from '@angular/core'; import { HttpHeaders, HttpResponse } from '@angular/common/http'; import { Observable } from 'rxjs'; import { switchMap } from 'rxjs/operators'; import { FilesService } from '@services/entity-services/files.service'; import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; -import { IPageRotationRequest } from '@red/domain'; +import { File, IPageRotationRequest } from '@red/domain'; @Injectable({ providedIn: 'root', @@ -20,10 +20,9 @@ export class FileManagementService extends GenericService { } @Validate() - delete(@RequiredParam() files: List, @RequiredParam() dossierId: string) { + delete(@RequiredParam() files: List, @RequiredParam() dossierId: string) { const fileIds = files.map(f => f.id); - const routerPath: string = files[0].routerPath; - return super._post(fileIds, `delete/${dossierId}`).pipe(switchMap(() => this._filesService.loadAll(dossierId, routerPath))); + return super._post(fileIds, `delete/${dossierId}`).pipe(switchMap(() => this._filesService.loadAll(dossierId))); } @Validate() diff --git a/apps/red-ui/src/app/services/entity-services/files-map.service.ts b/apps/red-ui/src/app/services/entity-services/files-map.service.ts index bfe6587aa..d71f717d1 100644 --- a/apps/red-ui/src/app/services/entity-services/files-map.service.ts +++ b/apps/red-ui/src/app/services/entity-services/files-map.service.ts @@ -12,11 +12,7 @@ export class FilesMapService extends EntitiesMapService { replaceFiles(files: File[], property: keyof IFile, generateValue: Function) { const newFiles = files.map( file => - new File( - { ...file, [property]: generateValue(file[property]), lastUpdated: new Date().toISOString() }, - file.reviewerName, - file.routerPath, - ), + new File({ ...file, [property]: generateValue(file[property]), lastUpdated: new Date().toISOString() }, file.reviewerName), ); this.replace(newFiles); } diff --git a/apps/red-ui/src/app/services/entity-services/files.service.ts b/apps/red-ui/src/app/services/entity-services/files.service.ts index 3569e678b..9d8b48ef2 100644 --- a/apps/red-ui/src/app/services/entity-services/files.service.ts +++ b/apps/red-ui/src/app/services/entity-services/files.service.ts @@ -1,5 +1,5 @@ import { Injectable, Injector } from '@angular/core'; -import { EntitiesService, IRouterPath, List, mapEach, RequiredParam, Validate } from '@iqser/common-ui'; +import { EntitiesService, List, mapEach, RequiredParam, Validate } from '@iqser/common-ui'; import { File, IFile } from '@red/domain'; import { Observable } from 'rxjs'; import { UserService } from '../user.service'; @@ -23,9 +23,9 @@ export class FilesService extends EntitiesService { } /** Reload dossier files + stats. */ - loadAll(dossierId: string, routerPath: string) { + loadAll(dossierId: string) { const files$ = this.getFor(dossierId).pipe( - mapEach(file => new File(file, this._userService.getNameForId(file.assignee), routerPath)), + mapEach(file => new File(file, this._userService.getNameForId(file.assignee))), tap(() => this._logger.info('[FILE] Loaded')), ); const loadStats$ = files$.pipe(switchMap(files => this._dossierStatsService.getFor([dossierId]).pipe(map(() => files)))); @@ -34,7 +34,7 @@ export class FilesService extends EntitiesService { reload(dossierId: string, file: File): Observable { return super._getOne([dossierId, file.id]).pipe( - map(_file => new File(_file, this._userService.getNameForId(_file.assignee), file.routerPath)), + map(_file => new File(_file, this._userService.getNameForId(_file.assignee))), switchMap(_file => this._dossierStatsService.getFor([dossierId]).pipe(map(() => _file))), map(_file => this._filesMapService.replace([_file])), tap(() => this._logger.info('[FILE] Reloaded')), @@ -42,56 +42,46 @@ export class FilesService extends EntitiesService { } @Validate() - setUnassigned(@RequiredParam() files: List, @RequiredParam() dossierId: string) { + setUnassigned(@RequiredParam() files: List, @RequiredParam() dossierId: string) { const url = `${this._defaultModelPath}/set-assignee/${dossierId}/bulk`; const fileIds = files.map(f => f.id); - const routerPath: string = files[0].routerPath; - return this._post(fileIds, url).pipe(switchMap(() => this.loadAll(dossierId, routerPath))); + return this._post(fileIds, url).pipe(switchMap(() => this.loadAll(dossierId))); } @Validate() - setToNewFor(@RequiredParam() files: List, @RequiredParam() dossierId: string) { + setToNewFor(@RequiredParam() files: List, @RequiredParam() dossierId: string) { const url = `${this._defaultModelPath}/new/${dossierId}/bulk`; const fileIds = files.map(f => f.id); - const routerPath: string = files[0].routerPath; - return this._post(fileIds, url).pipe(switchMap(() => this.loadAll(dossierId, routerPath))); + return this._post(fileIds, url).pipe(switchMap(() => this.loadAll(dossierId))); } @Validate() - setUnderApprovalFor(@RequiredParam() files: List, @RequiredParam() dossierId: string, assigneeId: string) { + setUnderApprovalFor(@RequiredParam() files: List, @RequiredParam() dossierId: string, assigneeId: string) { const url = `${this._defaultModelPath}/under-approval/${dossierId}/bulk`; const fileIds = files.map(f => f.id); - const routerPath: string = files[0].routerPath; - return this._post(fileIds, url, [{ key: 'assigneeId', value: assigneeId }]).pipe( - switchMap(() => this.loadAll(dossierId, routerPath)), - ); + return this._post(fileIds, url, [{ key: 'assigneeId', value: assigneeId }]).pipe(switchMap(() => this.loadAll(dossierId))); } @Validate() - setReviewerFor(@RequiredParam() files: List, @RequiredParam() dossierId: string, assigneeId: string) { + setReviewerFor(@RequiredParam() files: List, @RequiredParam() dossierId: string, assigneeId: string) { const url = `${this._defaultModelPath}/under-review/${dossierId}/bulk`; const fileIds = files.map(f => f.id); - const routerPath: string = files[0].routerPath; - return this._post(fileIds, url, [{ key: 'assigneeId', value: assigneeId }]).pipe( - switchMap(() => this.loadAll(dossierId, routerPath)), - ); + return this._post(fileIds, url, [{ key: 'assigneeId', value: assigneeId }]).pipe(switchMap(() => this.loadAll(dossierId))); } @Validate() - setApprovedFor(@RequiredParam() files: List, @RequiredParam() dossierId: string) { + setApprovedFor(@RequiredParam() files: List, @RequiredParam() dossierId: string) { const fileIds = files.map(f => f.id); - const routerPath: string = files[0].routerPath; return this._post(fileIds, `${this._defaultModelPath}/approved/${dossierId}/bulk`).pipe( - switchMap(() => this.loadAll(dossierId, routerPath)), + switchMap(() => this.loadAll(dossierId)), ); } @Validate() - setUnderReviewFor(@RequiredParam() files: List, @RequiredParam() dossierId: string) { + setUnderReviewFor(@RequiredParam() files: List, @RequiredParam() dossierId: string) { const fileIds = files.map(f => f.id); - const routerPath: string = files[0].routerPath; return this._post(fileIds, `${this._defaultModelPath}/under-review/${dossierId}/bulk`).pipe( - switchMap(() => this.loadAll(dossierId, routerPath)), + switchMap(() => this.loadAll(dossierId)), ); } } diff --git a/apps/red-ui/src/app/services/entity-services/platform-search.service.ts b/apps/red-ui/src/app/services/entity-services/platform-search.service.ts index d729373d4..a0d03df4f 100644 --- a/apps/red-ui/src/app/services/entity-services/platform-search.service.ts +++ b/apps/red-ui/src/app/services/entity-services/platform-search.service.ts @@ -56,6 +56,6 @@ export class PlatformSearchService extends GenericService { } private _loadFilesFor$(dossiers: Dossier[]) { - return zip(...dossiers.map(dossier => this._filesService.loadAll(dossier.id, dossier.routerPath))); + return zip(...dossiers.map(dossier => this._filesService.loadAll(dossier.id))); } } diff --git a/apps/red-ui/src/app/services/entity-services/trash.service.ts b/apps/red-ui/src/app/services/entity-services/trash.service.ts index 06153fc4c..841bda468 100644 --- a/apps/red-ui/src/app/services/entity-services/trash.service.ts +++ b/apps/red-ui/src/app/services/entity-services/trash.service.ts @@ -81,7 +81,7 @@ export class TrashService extends GenericService { getFiles(dossierIds = this._activeDossiersService.all.map(d => d.id)): Observable { return this._post>(dossierIds, 'status/softdeleted').pipe( map(res => flatMap(Object.values(res))), - mapEach(file => new File(file, this._userService.getNameForId(file.assignee), this._activeDossiersService.routerPath)), + mapEach(file => new File(file, this._userService.getNameForId(file.assignee))), mapEach(file => { const dossier = this._activeDossiersService.find(file.dossierId); return new TrashFile( @@ -133,6 +133,6 @@ export class TrashService extends GenericService { } private _restoreFiles(@RequiredParam() dossierId: string, @RequiredParam() fileIds: List) { - return this._post(fileIds, `delete/restore/${dossierId}`).pipe(switchMap(() => this._filesService.loadAll(dossierId, 'dossiers'))); + return this._post(fileIds, `delete/restore/${dossierId}`).pipe(switchMap(() => this._filesService.loadAll(dossierId))); } } diff --git a/apps/red-ui/src/app/services/reanalysis.service.ts b/apps/red-ui/src/app/services/reanalysis.service.ts index d58a2e406..243c98b21 100644 --- a/apps/red-ui/src/app/services/reanalysis.service.ts +++ b/apps/red-ui/src/app/services/reanalysis.service.ts @@ -1,5 +1,5 @@ import { Injectable, Injector } from '@angular/core'; -import { GenericService, IRouterPath, List, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui'; +import { GenericService, List, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui'; import { Dossier, File, IPageExclusionRequest } from '@red/domain'; import { catchError, switchMap, tap } from 'rxjs/operators'; import { FilesService } from './entity-services/files.service'; @@ -36,9 +36,8 @@ export class ReanalysisService extends GenericService { } @Validate() - reanalyzeFilesForDossier(@RequiredParam() files: List, @RequiredParam() dossierId: string, params?: ReanalyzeQueryParams) { + reanalyzeFilesForDossier(@RequiredParam() files: List, @RequiredParam() dossierId: string, params?: ReanalyzeQueryParams) { const fileIds = files.map(f => f.id); - const routerPath: string = files[0].routerPath; const queryParams: QueryParam[] = []; if (params?.force) { queryParams.push({ key: 'force', value: true }); @@ -47,22 +46,19 @@ export class ReanalysisService extends GenericService { queryParams.push({ key: 'triggeredByUser', value: true }); } - return this._post(fileIds, `reanalyze/${dossierId}/bulk`, queryParams).pipe( - switchMap(() => this._filesService.loadAll(dossierId, routerPath)), - ); + return this._post(fileIds, `reanalyze/${dossierId}/bulk`, queryParams).pipe(switchMap(() => this._filesService.loadAll(dossierId))); } @Validate() - toggleAnalysis(@RequiredParam() dossierId: string, @RequiredParam() files: List, excluded?: boolean) { + toggleAnalysis(@RequiredParam() dossierId: string, @RequiredParam() files: List, excluded?: boolean) { const fileIds = files.map(f => f.id); - const routerPath: string = files[0].routerPath; const queryParams: QueryParam[] = []; if (excluded) { queryParams.push({ key: 'excluded', value: excluded }); } return this._post(fileIds, `toggle-analysis/${dossierId}/bulk`, queryParams).pipe( - switchMap(() => this._filesService.loadAll(dossierId, routerPath)), + switchMap(() => this._filesService.loadAll(dossierId)), ); } @@ -86,24 +82,19 @@ export class ReanalysisService extends GenericService { } @Validate() - ocrFiles(@RequiredParam() files: List, @RequiredParam() dossierId: string) { + ocrFiles(@RequiredParam() files: List, @RequiredParam() dossierId: string) { const fileIds = files.map(f => f.id); - const routerPath: string = files[0].routerPath; - return this._post(fileIds, `ocr/reanalyze/${dossierId}/bulk`).pipe( - switchMap(() => this._filesService.loadAll(dossierId, routerPath)), - ); + return this._post(fileIds, `ocr/reanalyze/${dossierId}/bulk`).pipe(switchMap(() => this._filesService.loadAll(dossierId))); } @Validate() reanalyzeDossier(@RequiredParam() dossier: Dossier, force?: boolean) { - const { dossierId, routerPath } = dossier; + const { dossierId } = dossier; const queryParams: QueryParam[] = []; if (force) { queryParams.push({ key: 'force', value: force }); } - return this._post({}, `reanalyze/${dossierId}`, queryParams).pipe( - switchMap(() => this._filesService.loadAll(dossierId, routerPath)), - ); + return this._post({}, `reanalyze/${dossierId}`, queryParams).pipe(switchMap(() => this._filesService.loadAll(dossierId))); } } diff --git a/apps/red-ui/src/app/utils/constants.ts b/apps/red-ui/src/app/utils/constants.ts index 1f808d01d..4fb7381f9 100644 --- a/apps/red-ui/src/app/utils/constants.ts +++ b/apps/red-ui/src/app/utils/constants.ts @@ -5,3 +5,6 @@ export const FILE_ID = 'fileId'; export const DOSSIER_TEMPLATE_ID = 'dossierTemplateId'; export const ENTITY_TYPE = 'entity'; export const DOSSIERS_ARCHIVE = 'DOSSIERS_ARCHIVE'; + +export const ARCHIVE_ROUTE = 'archive'; +export const DOSSIERS_ROUTE = 'dossiers'; diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json index 684210fa7..0cb5f13c3 100644 --- a/apps/red-ui/src/assets/config/config.json +++ b/apps/red-ui/src/assets/config/config.json @@ -1,7 +1,7 @@ { "ADMIN_CONTACT_NAME": null, "ADMIN_CONTACT_URL": null, - "API_URL": "https://dev-08.iqser.cloud/redaction-gateway-v1", + "API_URL": "https://dev-04.iqser.cloud/redaction-gateway-v1", "APP_NAME": "RedactManager", "AUTO_READ_TIME": 3, "BACKEND_APP_VERSION": "4.4.40", @@ -17,7 +17,7 @@ "MAX_RETRIES_ON_SERVER_ERROR": 3, "OAUTH_CLIENT_ID": "redaction", "OAUTH_IDP_HINT": null, - "OAUTH_URL": "https://dev-08.iqser.cloud/auth/realms/redaction", + "OAUTH_URL": "https://dev-04.iqser.cloud/auth/realms/redaction", "RECENT_PERIOD_IN_HOURS": 24, "SELECTION_MODE": "structural", "MANUAL_BASE_URL": "https://docs.redactmanager.com/preview" diff --git a/libs/common-ui b/libs/common-ui index 7bc942ae1..f06c007be 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit 7bc942ae164164dadba94045f1f249a6cbb17284 +Subproject commit f06c007bec1a7da5c257e68d6df8c806419ceb2b diff --git a/libs/red-domain/src/lib/dossiers/dossier.model.ts b/libs/red-domain/src/lib/dossiers/dossier.model.ts index f50d5ecec..6a2bb1727 100644 --- a/libs/red-domain/src/lib/dossiers/dossier.model.ts +++ b/libs/red-domain/src/lib/dossiers/dossier.model.ts @@ -1,8 +1,9 @@ -import { IListable, IRouterPath, List } from '@iqser/common-ui'; +import { IListable, List } from '@iqser/common-ui'; import { IDossier } from './dossier'; import { DownloadFileType } from '../shared'; +import { ARCHIVE_ROUTE, DOSSIERS_ROUTE } from '@utils/constants'; -export class Dossier implements IDossier, IListable, IRouterPath { +export class Dossier implements IDossier, IListable { readonly dossierId: string; readonly dossierTemplateId: string; readonly ownerId: string; @@ -23,7 +24,7 @@ export class Dossier implements IDossier, IListable, IRouterPath { readonly archivedTime: string; readonly hasReviewers: boolean; - constructor(dossier: IDossier, readonly routerPath: string) { + constructor(dossier: IDossier) { this.dossierId = dossier.dossierId; this.approverIds = dossier.approverIds; this.date = dossier.date; @@ -50,7 +51,12 @@ export class Dossier implements IDossier, IListable, IRouterPath { } get routerLink(): string { - return `/main/${this.dossierTemplateId}/${this.routerPath}/${this.dossierId}`; + return `${this.dossiersListRouterLink}/${this.dossierId}`; + } + + get dossiersListRouterLink(): string { + const routerPath = this.isArchived ? ARCHIVE_ROUTE : DOSSIERS_ROUTE; + return `/main/${this.dossierTemplateId}/${routerPath}`; } get searchKey(): string { diff --git a/libs/red-domain/src/lib/files/file.model.ts b/libs/red-domain/src/lib/files/file.model.ts index 5ec6048dc..764ea776e 100644 --- a/libs/red-domain/src/lib/files/file.model.ts +++ b/libs/red-domain/src/lib/files/file.model.ts @@ -1,4 +1,4 @@ -import { Entity, IRouterPath } from '@iqser/common-ui'; +import { Entity } from '@iqser/common-ui'; import { StatusSorter } from '../shared'; import { isFullProcessingStatuses, @@ -10,8 +10,9 @@ import { } from './types'; import { IFile } from './file'; import { FileAttributes } from '../file-attributes'; +import { ARCHIVE_ROUTE, DOSSIERS_ROUTE } from '@utils/constants'; -export class File extends Entity implements IFile, IRouterPath { +export class File extends Entity implements IFile { readonly added?: string; readonly allManualRedactionsApplied: boolean; readonly analysisDuration?: number; @@ -51,6 +52,8 @@ export class File extends Entity implements IFile, IRouterPath { readonly redactionModificationDate: string; readonly lastManualChangeDate?: string; readonly hasHighlights: boolean; + readonly dossierArchived: boolean; + readonly dossierTemplateId: string; readonly statusSort: number; readonly cacheIdentifier?: string; @@ -70,7 +73,7 @@ export class File extends Entity implements IFile, IRouterPath { readonly canBeOpened: boolean; readonly canBeOCRed: boolean; - constructor(file: IFile, readonly reviewerName: string, readonly routerPath: string, readonly dossierTemplateId?: string) { + constructor(file: IFile, readonly reviewerName: string) { super(file); this.added = file.added; this.allManualRedactionsApplied = !!file.allManualRedactionsApplied; @@ -112,6 +115,8 @@ export class File extends Entity implements IFile, IRouterPath { this.redactionModificationDate = file.redactionModificationDate ?? ''; this.lastManualChangeDate = file.lastManualChangeDate; this.hasHighlights = file.hasHighlights; + this.dossierArchived = file.dossierArchived; + this.dossierTemplateId = file.dossierTemplateId; this.statusSort = StatusSorter[this.workflowStatus]; this.cacheIdentifier = btoa(this.fileManipulationDate ?? ''); @@ -146,6 +151,7 @@ export class File extends Entity implements IFile, IRouterPath { } get routerLink(): string | undefined { - return this.canBeOpened ? `/main/${this.dossierTemplateId}/${this.routerPath}/${this.dossierId}/file/${this.fileId}` : undefined; + const routerPath = this.dossierArchived ? ARCHIVE_ROUTE : DOSSIERS_ROUTE; + return this.canBeOpened ? `/main/${this.dossierTemplateId}/${routerPath}/${this.dossierId}/file/${this.fileId}` : undefined; } } diff --git a/libs/red-domain/src/lib/files/file.ts b/libs/red-domain/src/lib/files/file.ts index cbdd0e21e..59ba00cd8 100644 --- a/libs/red-domain/src/lib/files/file.ts +++ b/libs/red-domain/src/lib/files/file.ts @@ -149,6 +149,10 @@ export interface IFile { readonly hasHighlights: boolean; + readonly dossierArchived: boolean; + + readonly dossierTemplateId: string; + /** * Last time the actual file was touched */ From 30dbee52d26f23997ce575a80948236142b28187 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Wed, 4 May 2022 19:03:39 +0300 Subject: [PATCH 05/12] RED-3796: Use dossier template stats endpoint --- .../src/app/guards/dashboard-guard.service.ts | 14 +++ .../guards/dossier-template-exists.guard.ts | 2 +- .../src/app/guards/dossier-templates.guard.ts | 8 +- .../app/guards/entity-exists-guard.service.ts | 2 +- .../base-entity-screen.component.ts | 2 +- .../dossier-template-breadcrumbs.component.ts | 2 +- ...add-edit-dossier-state-dialog.component.ts | 4 +- ...-edit-dossier-template-dialog.component.ts | 2 +- ...clone-dossier-template-dialog.component.ts | 2 +- ...m-delete-dossier-state-dialog.component.ts | 4 +- ...ributes-configurations-dialog.component.ts | 2 +- .../default-colors-screen.component.ts | 2 +- ...sier-templates-listing-screen.component.ts | 2 +- ...ile-attributes-listing-screen.component.ts | 2 +- .../dossier-template-info-screen.component.ts | 2 +- ...add-edit-justification-dialog.component.ts | 2 +- .../justifications-dialog.service.ts | 2 +- .../reports-screen.component.ts | 2 +- .../screens/trash/trash-screen.component.ts | 2 +- .../dossier-template-actions.component.ts | 3 +- .../archive/services/config.service.ts | 2 +- .../template-stats.component.html | 35 ++++++-- .../template-stats.component.scss | 17 ++-- .../template-stats.component.ts | 45 +++------- .../dashboard-screen.component.html | 5 +- .../dashboard-screen.component.ts | 5 +- .../app/modules/dashboard/dashboard.module.ts | 5 +- .../dossier-details-stats.component.ts | 4 +- .../dossier-details.component.ts | 4 +- .../dossier-overview/config.service.ts | 2 +- .../dossier-overview-screen.component.ts | 2 +- .../services/bulk-actions.service.ts | 2 +- .../add-dossier-dialog.component.ts | 4 +- .../edit-dossier-general-info.component.ts | 4 +- .../file-actions/file-actions.component.ts | 3 +- .../services/dossiers-dialog.service.ts | 8 +- .../shared/services/file-assign.service.ts | 2 +- .../dossier/shared/shared-dossiers.module.ts | 2 +- .../dossiers-listing-actions.component.ts | 2 +- .../dossiers-listing-details.component.html | 20 ++--- .../dossiers-listing-details.component.ts | 70 +++------------ .../dossiers-listing/config.service.ts | 2 +- .../dossiers-listing-screen.component.ts | 7 +- .../document-info/document-info.component.ts | 2 +- .../services/document-info.service.ts | 2 +- .../dictionary-manager.component.ts | 2 +- .../dossier-name-column.component.ts | 2 +- .../simple-doughnut-chart.component.scss | 1 + .../simple-doughnut-chart.component.ts | 19 ++-- .../team-members/team-members.component.ts | 2 +- .../src/app/services/breadcrumbs.service.ts | 2 +- .../dashboard-stats.service.ts | 29 ++++++ .../dossier-templates.service.ts | 6 +- .../dossiers/active-dossiers.service.ts | 9 -- .../app/services/dossiers/dossiers.service.ts | 36 ++------ .../entity-services/dossier-states.service.ts | 2 +- .../services/entity-services/trash.service.ts | 5 -- .../app/services/translate-chart.service.ts | 21 ++++- apps/red-ui/src/assets/i18n/de.json | 8 +- apps/red-ui/src/assets/i18n/en.json | 8 +- libs/common-ui | 2 +- .../dashboard-stats.model.ts | 89 +++++++++++++++++++ .../lib/dossier-templates/dashboard-stats.ts | 33 +++++++ .../src/lib/dossier-templates/index.ts | 2 + 64 files changed, 348 insertions(+), 249 deletions(-) create mode 100644 apps/red-ui/src/app/guards/dashboard-guard.service.ts rename apps/red-ui/src/app/modules/dossier/{ => shared}/services/dossiers-dialog.service.ts (71%) create mode 100644 apps/red-ui/src/app/services/dossier-templates/dashboard-stats.service.ts rename apps/red-ui/src/app/services/{entity-services => dossier-templates}/dossier-templates.service.ts (93%) create mode 100644 libs/red-domain/src/lib/dossier-templates/dashboard-stats.model.ts create mode 100644 libs/red-domain/src/lib/dossier-templates/dashboard-stats.ts diff --git a/apps/red-ui/src/app/guards/dashboard-guard.service.ts b/apps/red-ui/src/app/guards/dashboard-guard.service.ts new file mode 100644 index 000000000..a9eec07ae --- /dev/null +++ b/apps/red-ui/src/app/guards/dashboard-guard.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate } from '@angular/router'; +import { firstValueFrom } from 'rxjs'; +import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; + +@Injectable({ providedIn: 'root' }) +export class DashboardGuard implements CanActivate { + constructor(private readonly _dashboardStatsService: DashboardStatsService) {} + + async canActivate(route: ActivatedRouteSnapshot): Promise { + await firstValueFrom(this._dashboardStatsService.loadAll()); + return true; + } +} diff --git a/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts b/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts index 655a56dfe..a50d2c8a2 100644 --- a/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts +++ b/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { DOSSIER_TEMPLATE_ID } from '@utils/constants'; @Injectable({ providedIn: 'root' }) diff --git a/apps/red-ui/src/app/guards/dossier-templates.guard.ts b/apps/red-ui/src/app/guards/dossier-templates.guard.ts index 9a163ee8f..7495d23ff 100644 --- a/apps/red-ui/src/app/guards/dossier-templates.guard.ts +++ b/apps/red-ui/src/app/guards/dossier-templates.guard.ts @@ -1,15 +1,11 @@ import { Injectable } from '@angular/core'; import { CanActivate } from '@angular/router'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { firstValueFrom } from 'rxjs'; -import { DictionaryService } from '@services/entity-services/dictionary.service'; @Injectable({ providedIn: 'root' }) export class DossierTemplatesGuard implements CanActivate { - constructor( - private readonly _dossierTemplatesService: DossierTemplatesService, - private readonly _dictionaryService: DictionaryService, - ) {} + constructor(private readonly _dossierTemplatesService: DossierTemplatesService) {} async canActivate(): Promise { await firstValueFrom(this._dossierTemplatesService.loadAll()); diff --git a/apps/red-ui/src/app/guards/entity-exists-guard.service.ts b/apps/red-ui/src/app/guards/entity-exists-guard.service.ts index f363829ff..012583808 100644 --- a/apps/red-ui/src/app/guards/entity-exists-guard.service.ts +++ b/apps/red-ui/src/app/guards/entity-exists-guard.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@utils/constants'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; @Injectable({ providedIn: 'root' }) export class EntityExistsGuard implements CanActivate { diff --git a/apps/red-ui/src/app/modules/admin/base-entity-screen/base-entity-screen.component.ts b/apps/red-ui/src/app/modules/admin/base-entity-screen/base-entity-screen.component.ts index 3551ba542..e76e6980e 100644 --- a/apps/red-ui/src/app/modules/admin/base-entity-screen/base-entity-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/base-entity-screen/base-entity-screen.component.ts @@ -6,7 +6,7 @@ import { AdminDialogService } from '../services/admin-dialog.service'; import { DictionaryService } from '@services/entity-services/dictionary.service'; import { UserService } from '@services/user.service'; import { LoadingService } from '@iqser/common-ui'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import { map } from 'rxjs/operators'; import { PermissionsService } from '@services/permissions.service'; diff --git a/apps/red-ui/src/app/modules/admin/components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component.ts b/apps/red-ui/src/app/modules/admin/components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component.ts index da0e9ac58..b5108a29e 100644 --- a/apps/red-ui/src/app/modules/admin/components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component.ts +++ b/apps/red-ui/src/app/modules/admin/components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component.ts @@ -1,5 +1,5 @@ import { Component, Input } from '@angular/core'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { Observable, of } from 'rxjs'; import { map, switchMap } from 'rxjs/operators'; import { ActivatedRoute } from '@angular/router'; diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-state-dialog/add-edit-dossier-state-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-state-dialog/add-edit-dossier-state-dialog.component.ts index f9ad50bd4..c3c8dab56 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-state-dialog/add-edit-dossier-state-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-state-dialog/add-edit-dossier-state-dialog.component.ts @@ -23,7 +23,7 @@ export class AddEditDossierStateDialogComponent extends BaseDialogComponent { private readonly _formBuilder: FormBuilder, private readonly _loadingService: LoadingService, private readonly _toaster: Toaster, - private readonly _dossierStateService: DossierStatesService, + private readonly _dossierStatesService: DossierStatesService, protected readonly _injector: Injector, protected readonly _dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) readonly data: DialogData, @@ -45,7 +45,7 @@ export class AddEditDossierStateDialogComponent extends BaseDialogComponent { }; this._loadingService.start(); try { - await firstValueFrom(this._dossierStateService.createOrUpdate(dossierState)); + await firstValueFrom(this._dossierStatesService.createOrUpdate(dossierState)); this._toaster.success(_('add-edit-dossier-state.success'), { params: { type: this.type } }); this._dialogRef.close(); } catch (e) {} diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.ts index 8a5534542..e98272044 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component.ts @@ -3,7 +3,7 @@ import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/fo import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { applyIntervalConstraints } from '@utils/date-inputs-utils'; import { downloadTypesTranslations } from '../../../../translations/download-types-translations'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { BaseDialogComponent, LoadingService, Toaster } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { DossierTemplate, DownloadFileType, IDossierTemplate } from '@red/domain'; diff --git a/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.ts index 3ae953481..c26e9b629 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component.ts @@ -1,6 +1,6 @@ import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { DossierTemplate } from '@red/domain'; import { LoadingService, Toaster } from '@iqser/common-ui'; import { firstValueFrom } from 'rxjs'; diff --git a/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-dossier-state-dialog/confirm-delete-dossier-state-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-dossier-state-dialog/confirm-delete-dossier-state-dialog.component.ts index 910b6e977..5d32ec0c7 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-dossier-state-dialog/confirm-delete-dossier-state-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/confirm-delete-dossier-state-dialog/confirm-delete-dossier-state-dialog.component.ts @@ -29,7 +29,7 @@ export class ConfirmDeleteDossierStateDialogComponent { private readonly _formBuilder: FormBuilder, private readonly _loadingService: LoadingService, private readonly _toaster: Toaster, - private readonly _dossierStateService: DossierStatesService, + private readonly _dossierStatesService: DossierStatesService, private readonly _dialogRef: MatDialogRef, private readonly _activeDossiersService: ActiveDossiersService, private readonly _archivedDossiersService: ArchivedDossiersService, @@ -55,7 +55,7 @@ export class ConfirmDeleteDossierStateDialogComponent { async save(): Promise { this._loadingService.start(); - await firstValueFrom(this._dossierStateService.deleteState(this.data.toBeDeletedState, this.replaceDossierStatusId)); + await firstValueFrom(this._dossierStatesService.deleteState(this.data.toBeDeletedState, this.replaceDossierStatusId)); await firstValueFrom( forkJoin([this._activeDossiersService.loadAll().pipe(take(1)), this._archivedDossiersService.loadAll().pipe(take(1))]), ); diff --git a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-configurations-dialog/file-attributes-configurations-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-configurations-dialog/file-attributes-configurations-dialog.component.ts index 6c20af995..45334ed9c 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-configurations-dialog/file-attributes-configurations-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/file-attributes-configurations-dialog/file-attributes-configurations-dialog.component.ts @@ -4,7 +4,7 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { FileAttributeEncodingTypes, IFileAttributesConfig } from '@red/domain'; import { fileAttributeEncodingTypesTranslations } from '../../translations/file-attribute-encoding-types-translations'; import { BaseDialogComponent, Toaster } from '@iqser/common-ui'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { firstValueFrom } from 'rxjs'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { FileAttributesService } from '@services/entity-services/file-attributes.service'; 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 d93f3e956..97643322c 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 @@ -13,7 +13,7 @@ import { defaultColorsTranslations } from '../../translations/default-colors-tra import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { UserService } from '@services/user.service'; import { DictionaryService } from '@services/entity-services/dictionary.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { firstValueFrom } from 'rxjs'; import { ActivatedRoute } from '@angular/router'; import { DOSSIER_TEMPLATE_ID } from '@utils/constants'; diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts index 896cd6ed9..1059bbc20 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-templates-listing/dossier-templates-listing-screen/dossier-templates-listing-screen.component.ts @@ -15,7 +15,7 @@ import { import { UserService } from '@services/user.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { RouterHistoryService } from '@services/router-history.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { firstValueFrom } from 'rxjs'; @Component({ 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 a06e24ba3..36f8ee278 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 @@ -28,7 +28,7 @@ import { HttpStatusCode } from '@angular/common/http'; import { firstValueFrom } from 'rxjs'; import { ReportTemplateService } from '../../../../services/report-template.service'; import { ActivatedRoute } from '@angular/router'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { DOSSIER_TEMPLATE_ID } from '@utils/constants'; @Component({ diff --git a/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts index e1cfc90a0..c953e8a70 100644 --- a/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/info/info-screen/dossier-template-info-screen.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { ActivatedRoute } from '@angular/router'; import { Observable } from 'rxjs'; import { DossierTemplate, DossierTemplateStats } from '@red/domain'; diff --git a/apps/red-ui/src/app/modules/admin/screens/justifications/add-edit-justification-dialog/add-edit-justification-dialog.component.ts b/apps/red-ui/src/app/modules/admin/screens/justifications/add-edit-justification-dialog/add-edit-justification-dialog.component.ts index 5a53c1d98..4d61f4f73 100644 --- a/apps/red-ui/src/app/modules/admin/screens/justifications/add-edit-justification-dialog/add-edit-justification-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/justifications/add-edit-justification-dialog/add-edit-justification-dialog.component.ts @@ -3,7 +3,7 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Justification } from '@red/domain'; import { JustificationsService } from '@services/entity-services/justifications.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { BaseDialogComponent, LoadingService } from '@iqser/common-ui'; import { firstValueFrom } from 'rxjs'; diff --git a/apps/red-ui/src/app/modules/admin/screens/justifications/justifications-dialog.service.ts b/apps/red-ui/src/app/modules/admin/screens/justifications/justifications-dialog.service.ts index 6fcf1f246..668de1d80 100644 --- a/apps/red-ui/src/app/modules/admin/screens/justifications/justifications-dialog.service.ts +++ b/apps/red-ui/src/app/modules/admin/screens/justifications/justifications-dialog.service.ts @@ -10,7 +10,7 @@ import { } from '@iqser/common-ui'; import { AddEditJustificationDialogComponent } from './add-edit-justification-dialog/add-edit-justification-dialog.component'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { JustificationsService } from '@services/entity-services/justifications.service'; import { Justification } from '@red/domain'; import { firstValueFrom } from 'rxjs'; diff --git a/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen/reports-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen/reports-screen.component.ts index 04ddca911..1742a103a 100644 --- a/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen/reports-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/reports/reports-screen/reports-screen.component.ts @@ -10,7 +10,7 @@ import { import { removeBraces } from '@utils/functions'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { AdminDialogService } from '../../../services/admin-dialog.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { ReportTemplateService } from '@services/report-template.service'; import { BehaviorSubject, firstValueFrom } from 'rxjs'; import { ActivatedRoute } from '@angular/router'; 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 335e5c128..8f77182f1 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 @@ -18,7 +18,7 @@ import { TrashItem } from '@red/domain'; import { TrashService } from '@services/entity-services/trash.service'; import { FilesService } from '@services/entity-services/files.service'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; @Component({ templateUrl: './trash-screen.component.html', diff --git a/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.ts b/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.ts index f43070a56..172e66f72 100644 --- a/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.ts +++ b/apps/red-ui/src/app/modules/admin/shared/components/dossier-template-actions/dossier-template-actions.component.ts @@ -3,7 +3,7 @@ import { ActivatedRoute, Router } from '@angular/router'; import { AdminDialogService } from '../../../services/admin-dialog.service'; import { CircleButtonTypes, LoadingService, Toaster } from '@iqser/common-ui'; import { UserService } from '@services/user.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { firstValueFrom } from 'rxjs'; import { DictionaryService } from '@services/entity-services/dictionary.service'; import { DOSSIER_TEMPLATE_ID } from '@utils/constants'; @@ -37,6 +37,7 @@ export class DossierTemplateActionsComponent implements OnInit { openEditDossierTemplateDialog($event: MouseEvent) { this._dialogService.openDialog('addEditDossierTemplate', $event, this.dossierTemplateId); } + openCloneDossierTemplateDialog($event: MouseEvent) { this._dialogService.openDialog('cloneDossierTemplate', $event, this.dossierTemplateId); } diff --git a/apps/red-ui/src/app/modules/archive/services/config.service.ts b/apps/red-ui/src/app/modules/archive/services/config.service.ts index 227fecad7..29ebf051e 100644 --- a/apps/red-ui/src/app/modules/archive/services/config.service.ts +++ b/apps/red-ui/src/app/modules/archive/services/config.service.ts @@ -5,7 +5,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { dossierMemberChecker, dossierTemplateChecker } from '@utils/index'; import { UserService } from '@services/user.service'; import { TranslateService } from '@ngx-translate/core'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; @Injectable() export class ConfigService { diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html index 1eb4e5072..efc0d7ac0 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html @@ -1,13 +1,32 @@ -
- - {{ dossierTemplate.name }} -
- +
+ +
+ {{ dossierTemplate.name }} + {{ dossierTemplate.id }} +
+
+ +
+
+
-
stats2
-
+
{{ dossierTemplate.name }} @@ -22,5 +41,5 @@ [type]="iconButtonTypes.primary" icon="iqser:plus" > -
+
diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss index 7f20e26b4..18acdf1c2 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss @@ -1,6 +1,7 @@ .dialog { flex-direction: row; max-width: unset; + min-height: unset; margin: 0 0 16px 0; .heading { @@ -11,22 +12,20 @@ } } - > div { + &.empty { + justify-content: space-between; + align-items: center; + padding: 24px; + } + + &:not(.empty) > div { padding: 24px; display: flex; flex-direction: column; - flex: 1; &:not(:first-child) { - align-items: center; justify-content: center; border-left: 1px solid var(--iqser-separator); } - - &.empty { - flex-direction: row; - justify-content: space-between; - align-items: center; - } } } diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts index bf1042717..c8181b4e4 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.ts @@ -1,49 +1,28 @@ -import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; -import { DossierTemplate, DossierTemplateStats } from '@red/domain'; -import { BehaviorSubject, Observable } from 'rxjs'; -import { switchMap } from 'rxjs/operators'; -import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service'; +import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; +import { DashboardStats } from '@red/domain'; import { IconButtonTypes } from '@iqser/common-ui'; -import { DossiersDialogService } from '../../../dossier/services/dossiers-dialog.service'; -import { Router } from '@angular/router'; +import { DossiersDialogService } from '../../../dossier/shared/services/dossiers-dialog.service'; +import { TranslateService } from '@ngx-translate/core'; +import { TranslateChartService } from '@services/translate-chart.service'; @Component({ - selector: 'redaction-template-stats [dossierTemplateId]', + selector: 'redaction-template-stats [stats]', templateUrl: './template-stats.component.html', styleUrls: ['./template-stats.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class TemplateStatsComponent implements OnChanges { +export class TemplateStatsComponent { readonly iconButtonTypes = IconButtonTypes; - @Input() dossierTemplateId: string; - - readonly dossierTemplate$: Observable; - readonly stats$: Observable; - readonly #ngOnChanges$ = new BehaviorSubject(undefined); + @Input() stats: DashboardStats; constructor( - private readonly _dossierTemplatesService: DossierTemplatesService, - private readonly _dossierTemplateStatsService: DossierTemplateStatsService, private readonly _dialogService: DossiersDialogService, - private readonly _router: Router, - ) { - this.dossierTemplate$ = this.#ngOnChanges$.pipe(switchMap(id => this._dossierTemplatesService.getEntityChanged$(id))); - this.stats$ = this.#ngOnChanges$.pipe(switchMap(id => this._dossierTemplateStatsService.watch$(id))); - } - - get empty(): boolean { - return false; - } - - ngOnChanges() { - if (this.dossierTemplateId) { - this.#ngOnChanges$.next(this.dossierTemplateId); - } - } + private readonly _translateService: TranslateService, + readonly translateChartService: TranslateChartService, + ) {} newDossier(): void { - this._dialogService.openDialog('addDossier', null, { dossierTemplateId: this.dossierTemplateId }); + this._dialogService.openDialog('addDossier', null, { dossierTemplateId: this.stats.dossierTemplateId }); } } diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.html b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.html index abd8f5ad8..b87902860 100644 --- a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.html +++ b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.html @@ -9,8 +9,5 @@
- +
diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts index 09bac094f..e413f5d90 100644 --- a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts +++ b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { UserService } from '../../../services/user.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; @Component({ selector: 'redaction-dashboard-screen', @@ -10,6 +10,7 @@ import { DossierTemplatesService } from '@services/entity-services/dossier-templ }) export class DashboardScreenComponent { readonly currentUser = this._userService.currentUser; + readonly stats$ = this._dashboardStatsService.all$; - constructor(private readonly _userService: UserService, readonly dossierTemplatesService: DossierTemplatesService) {} + constructor(private readonly _userService: UserService, private readonly _dashboardStatsService: DashboardStatsService) {} } diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts b/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts index 00d7d285c..3fcc0de17 100644 --- a/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts +++ b/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts @@ -4,10 +4,11 @@ import { DashboardScreenComponent } from './dashboard-screen/dashboard-screen.co import { RouterModule } from '@angular/router'; import { SharedModule } from '../shared/shared.module'; import { TemplateStatsComponent } from './components/template-stats/template-stats.component'; -import { DossierTemplatesGuard } from '../../guards/dossier-templates.guard'; import { CompositeRouteGuard } from '@iqser/common-ui'; import { SharedDossiersModule } from '../dossier/shared/shared-dossiers.module'; import { BreadcrumbTypes } from '@red/domain'; +import { DossierTemplatesGuard } from '../../guards/dossier-templates.guard'; +import { DashboardGuard } from '../../guards/dashboard-guard.service'; const routes = [ { @@ -15,8 +16,8 @@ const routes = [ component: DashboardScreenComponent, canActivate: [CompositeRouteGuard], data: { - routeGuards: [DossierTemplatesGuard], breadcrumbs: [BreadcrumbTypes.dashboard], + routeGuards: [DossierTemplatesGuard, DashboardGuard], }, }, ]; diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.ts b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.ts index eb0f1d0ce..7418a07bb 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details-stats/dossier-details-stats.component.ts @@ -1,10 +1,10 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; import { Dossier, DossierAttributeWithValue, DossierStats } from '@red/domain'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { FilesService } from '@services/entity-services/files.service'; import { firstValueFrom, Observable } from 'rxjs'; import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; -import { DossiersDialogService } from '../../../dossier/services/dossiers-dialog.service'; +import { DossiersDialogService } from '../../../dossier/shared/services/dossiers-dialog.service'; @Component({ selector: 'redaction-dossier-details-stats', diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts index b7cd35d50..9214c1424 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/components/dossier-details/dossier-details.component.ts @@ -10,7 +10,7 @@ import { ActivatedRoute } from '@angular/router'; import { firstValueFrom, Observable } from 'rxjs'; import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; import { map, pluck, switchMap } from 'rxjs/operators'; -import { DossiersDialogService } from '../../../dossier/services/dossiers-dialog.service'; +import { DossiersDialogService } from '../../../dossier/shared/services/dossiers-dialog.service'; import { FilesService } from '@services/entity-services/files.service'; import { DOSSIER_ID } from '@utils/constants'; import { DossiersService } from '@services/dossiers/dossiers.service'; @@ -80,7 +80,7 @@ export class DossierDetailsComponent { key: status, })); documentsChartData.sort((a, b) => StatusSorter.byStatus(a.key, b.key)); - return this.translateChartService.translateStatus(documentsChartData); + return this.translateChartService.translateLabels(documentsChartData); } #calculateStatusConfig(stats: DossierStats): ProgressBarConfigModel[] { diff --git a/apps/red-ui/src/app/modules/dossier-overview/config.service.ts b/apps/red-ui/src/app/modules/dossier-overview/config.service.ts index 3361e3ab4..1bb5b8b2e 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/config.service.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/config.service.ts @@ -17,7 +17,7 @@ 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 '../dossier/services/dossiers-dialog.service'; +import { DossiersDialogService } from '../dossier/shared/services/dossiers-dialog.service'; import { annotationFilterChecker, RedactionFilterSorter } from '../../utils'; import { workloadTranslations } from '../dossier/translations/workload-translations'; import { ConfigService as AppConfigService } from '@services/config.service'; diff --git a/apps/red-ui/src/app/modules/dossier-overview/screen/dossier-overview-screen.component.ts b/apps/red-ui/src/app/modules/dossier-overview/screen/dossier-overview-screen.component.ts index 3f845465f..04f5092f3 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/screen/dossier-overview-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/screen/dossier-overview-screen.component.ts @@ -28,7 +28,7 @@ import { PermissionsService } from '@services/permissions.service'; import { ActivatedRoute, NavigationEnd, Router } from '@angular/router'; import { FileAttributesService } from '@services/entity-services/file-attributes.service'; import { ConfigService } from '../config.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { UserPreferenceService } from '@services/user-preference.service'; import { FilesMapService } from '@services/entity-services/files-map.service'; import { FilesService } from '@services/entity-services/files.service'; diff --git a/apps/red-ui/src/app/modules/dossier-overview/services/bulk-actions.service.ts b/apps/red-ui/src/app/modules/dossier-overview/services/bulk-actions.service.ts index 018dfd6b4..7877dd3c2 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/services/bulk-actions.service.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/services/bulk-actions.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { Dossier, File } from '@red/domain'; -import { DossiersDialogService } from '../../dossier/services/dossiers-dialog.service'; +import { DossiersDialogService } from '../../dossier/shared/services/dossiers-dialog.service'; import { ConfirmationDialogInput, LoadingService } from '@iqser/common-ui'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; import { FilesService } from '@services/entity-services/files.service'; diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts index ecf117bcd..6bd41503d 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts @@ -5,13 +5,13 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { downloadTypesTranslations } from '../../../../translations/download-types-translations'; import { BaseDialogComponent, IconButtonTypes, LoadingService, SaveOptions } from '@iqser/common-ui'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { ReportTemplateService } from '@services/report-template.service'; import { firstValueFrom } from 'rxjs'; import { DOSSIER_TEMPLATE_ID } from '@utils/constants'; import dayjs from 'dayjs'; import { Router } from '@angular/router'; -import { DossiersDialogService } from '../../services/dossiers-dialog.service'; +import { DossiersDialogService } from '../../shared/services/dossiers-dialog.service'; interface DialogData { readonly dossierTemplateId?: string; diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.ts index abcdf8c98..5844f7680 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.ts @@ -2,14 +2,14 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Dossier, IDossierRequest, IDossierTemplate } from '@red/domain'; import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface'; -import { DossiersDialogService } from '../../../services/dossiers-dialog.service'; +import { DossiersDialogService } from '../../../shared/services/dossiers-dialog.service'; import { PermissionsService } from '@services/permissions.service'; import { Router } from '@angular/router'; import { MatDialogRef } from '@angular/material/dialog'; import { EditDossierDialogComponent } from '../edit-dossier-dialog.component'; import { ConfirmationDialogInput, ConfirmOptions, IconButtonTypes, LoadingService, TitleColors, Toaster } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; import { firstValueFrom } from 'rxjs'; import { DOSSIER_TEMPLATE_ID } from '@utils/constants'; diff --git a/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.ts b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.ts index 51b7578b3..56584737c 100644 --- a/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.ts +++ b/apps/red-ui/src/app/modules/dossier/shared/components/file-actions/file-actions.component.ts @@ -1,7 +1,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostBinding, Input, OnChanges, Optional, ViewChild } from '@angular/core'; import { PermissionsService } from '@services/permissions.service'; import { Action, ActionTypes, Dossier, File } from '@red/domain'; -import { DossiersDialogService } from '../../../services/dossiers-dialog.service'; +import { DossiersDialogService } from '../../services/dossiers-dialog.service'; import { CircleButtonType, CircleButtonTypes, @@ -24,7 +24,6 @@ import { ExcludedPagesService } from '../../../../file-preview/services/excluded import { DocumentInfoService } from '../../../../file-preview/services/document-info.service'; import { ExpandableFileActionsComponent } from '@shared/components/expandable-file-actions/expandable-file-actions.component'; import { firstValueFrom, Observable } from 'rxjs'; -import { RedactionImportService } from '../../services/redaction-import.service'; import { PageRotationService } from '../../../../file-preview/services/page-rotation.service'; @Component({ diff --git a/apps/red-ui/src/app/modules/dossier/services/dossiers-dialog.service.ts b/apps/red-ui/src/app/modules/dossier/shared/services/dossiers-dialog.service.ts similarity index 71% rename from apps/red-ui/src/app/modules/dossier/services/dossiers-dialog.service.ts rename to apps/red-ui/src/app/modules/dossier/shared/services/dossiers-dialog.service.ts index 41ce299fc..18811f5d5 100644 --- a/apps/red-ui/src/app/modules/dossier/services/dossiers-dialog.service.ts +++ b/apps/red-ui/src/app/modules/dossier/shared/services/dossiers-dialog.service.ts @@ -1,10 +1,10 @@ import { Injectable } from '@angular/core'; import { MatDialog } from '@angular/material/dialog'; -import { AddDossierDialogComponent } from '../dialogs/add-dossier-dialog/add-dossier-dialog.component'; -import { EditDossierDialogComponent } from '../dialogs/edit-dossier-dialog/edit-dossier-dialog.component'; -import { AssignReviewerApproverDialogComponent } from '../dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component'; +import { AddDossierDialogComponent } from '../../dialogs/add-dossier-dialog/add-dossier-dialog.component'; +import { EditDossierDialogComponent } from '../../dialogs/edit-dossier-dialog/edit-dossier-dialog.component'; +import { AssignReviewerApproverDialogComponent } from '../../dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component'; import { ConfirmationDialogComponent, DialogConfig, DialogService, largeDialogConfig } from '@iqser/common-ui'; -import { ImportRedactionsDialogComponent } from '../../file-preview/dialogs/import-redactions-dialog/import-redactions-dialog'; +import { ImportRedactionsDialogComponent } from '../../../file-preview/dialogs/import-redactions-dialog/import-redactions-dialog'; type DialogType = 'confirm' | 'editDossier' | 'addDossier' | 'assignFile' | 'importRedactions'; diff --git a/apps/red-ui/src/app/modules/dossier/shared/services/file-assign.service.ts b/apps/red-ui/src/app/modules/dossier/shared/services/file-assign.service.ts index 63718d1fe..b346509a5 100644 --- a/apps/red-ui/src/app/modules/dossier/shared/services/file-assign.service.ts +++ b/apps/red-ui/src/app/modules/dossier/shared/services/file-assign.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { UserService } from '@services/user.service'; import { Dossier, File } from '@red/domain'; -import { DossiersDialogService } from '../../services/dossiers-dialog.service'; +import { DossiersDialogService } from './dossiers-dialog.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { FilesService } from '@services/entity-services/files.service'; import { ConfirmationDialogInput, LoadingService, Toaster } from '@iqser/common-ui'; 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 index 57cb8d531..99ad2410c 100644 --- 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 @@ -4,7 +4,7 @@ import { FileAssignService } from './services/file-assign.service'; import { FileActionsComponent } from './components/file-actions/file-actions.component'; import { SharedModule } from '@shared/shared.module'; import { RedactionImportService } from './services/redaction-import.service'; -import { DossiersDialogService } from '../services/dossiers-dialog.service'; +import { DossiersDialogService } from './services/dossiers-dialog.service'; import { EditDossierDialogComponent } from '../dialogs/edit-dossier-dialog/edit-dossier-dialog.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'; diff --git a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.ts b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.ts index ed03d6ded..8339f752c 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-actions/dossiers-listing-actions.component.ts @@ -3,7 +3,7 @@ import { PermissionsService } from '@services/permissions.service'; import { CircleButtonTypes, List, ScrollableParentView, ScrollableParentViews, StatusBarConfig } from '@iqser/common-ui'; import { UserService } from '@services/user.service'; import { Dossier, DossierStats, File } from '@red/domain'; -import { DossiersDialogService } from '../../../dossier/services/dossiers-dialog.service'; +import { DossiersDialogService } from '../../../dossier/shared/services/dossiers-dialog.service'; import { LongPressEvent } from '@shared/directives/long-press.directive'; import { UserPreferenceService } from '@services/user-preference.service'; import { FilesMapService } from '@services/entity-services/files-map.service'; diff --git a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html index 3cd68756d..38b884779 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html +++ b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html @@ -1,25 +1,24 @@ -
+
-
+
-
{{ stats.totalAnalyzedPages | number }}
-
+
{{ stats.numberOfPages | number }}
+
-
{{ stats.totalPeople }}
+
{{ stats.numberOfPeople }}
@@ -28,10 +27,9 @@
diff --git a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts index d2033d0f1..4974c67f9 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts @@ -1,15 +1,12 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; -import { FilterService, mapEach } from '@iqser/common-ui'; -import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; -import { combineLatest, Observable } from 'rxjs'; -import { DossierStats, FileCountPerWorkflowStatus, StatusSorter } from '@red/domain'; -import { workflowFileStatusTranslations } from '../../../../translations/file-status-translations'; +import { Observable } from 'rxjs'; import { TranslateChartService } from '@services/translate-chart.service'; -import { filter, map, switchMap } from 'rxjs/operators'; -import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; -import { TranslateService } from '@ngx-translate/core'; -import { DossierStatesMapService } from '@services/entity-services/dossier-states-map.service'; +import { map } from 'rxjs/operators'; +import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; +import { ActivatedRoute } from '@angular/router'; +import { DOSSIER_TEMPLATE_ID } from '@utils/constants'; +import { DashboardStats } from '@red/domain'; @Component({ selector: 'redaction-dossiers-listing-details', @@ -18,59 +15,20 @@ import { DossierStatesMapService } from '@services/entity-services/dossier-state changeDetection: ChangeDetectionStrategy.OnPush, }) export class DossiersListingDetailsComponent { + readonly stats$: Observable; readonly documentsChartData$: Observable; readonly dossiersChartData$: Observable; constructor( - readonly filterService: FilterService, - readonly activeDossiersService: ActiveDossiersService, - private readonly _dossierStatsMap: DossierStatsService, + private readonly _dashboardStatsService: DashboardStatsService, private readonly _translateChartService: TranslateChartService, - private readonly _dossierStatesMapService: DossierStatesMapService, - private readonly _translateService: TranslateService, + private readonly _route: ActivatedRoute, ) { - this.documentsChartData$ = this.activeDossiersService.all$.pipe( - mapEach(dossier => _dossierStatsMap.watch$(dossier.dossierId)), - switchMap(stats$ => combineLatest(stats$)), - filter(stats => !stats.some(s => s === undefined)), - map(stats => this._toChartData(stats)), + const dossierTemplateId: string = this._route.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID); + this.stats$ = this._dashboardStatsService.getEntityChanged$(dossierTemplateId); + this.dossiersChartData$ = this.stats$.pipe( + map(s => this._translateChartService.translateDossierStates(s.dossiersChartData, dossierTemplateId)), ); - - this.dossiersChartData$ = this.activeDossiersService.all$.pipe(map(() => this._toDossierChartData())); - } - - private _toDossierChartData(): DoughnutChartConfig[] { - const configArray: DoughnutChartConfig[] = this._dossierStatesMapService.stats; - const undefinedStateLength = - this.activeDossiersService.all.length - configArray.map(v => v.value).reduce((acc, val) => acc + val, 0); - configArray.push({ - value: undefinedStateLength, - label: this._translateService.instant('edit-dossier-dialog.general-info.form.dossier-state.placeholder'), - color: '#E2E4E9', - }); - - return configArray; - } - - private _toChartData(stats: DossierStats[]) { - const chartData: FileCountPerWorkflowStatus = {}; - stats.forEach(stat => { - const statuses: FileCountPerWorkflowStatus = stat.fileCountPerWorkflowStatus; - Object.keys(statuses).forEach(status => { - chartData[status] = chartData[status] ? (chartData[status] as number) + (statuses[status] as number) : statuses[status]; - }); - }); - - const documentsChartData = Object.keys(chartData).map( - status => - ({ - value: chartData[status], - color: status, - label: workflowFileStatusTranslations[status], - key: status, - } as DoughnutChartConfig), - ); - documentsChartData.sort((a, b) => StatusSorter.byStatus(a.key, b.key)); - return this._translateChartService.translateStatus(documentsChartData); + this.documentsChartData$ = this.stats$.pipe(map(s => this._translateChartService.translateWorkflowStatus(s.documentsChartData))); } } diff --git a/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts b/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts index ee63347c8..426d157e1 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts @@ -10,7 +10,7 @@ import { dossierMemberChecker, dossierStateChecker, RedactionFilterSorter } from import { workloadTranslations } from '../dossier/translations/workload-translations'; import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; import { DossierStatesMapService } from '@services/entity-services/dossier-states-map.service'; -import { DossiersDialogService } from '../dossier/services/dossiers-dialog.service'; +import { DossiersDialogService } from '../dossier/shared/services/dossiers-dialog.service'; @Injectable() export class ConfigService { diff --git a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts index 8bf91957f..0b7b59ea3 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts @@ -6,9 +6,10 @@ import { DefaultListingServicesTmp, EntitiesService, ListingComponent, OnAttach, import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { ConfigService } from '../config.service'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { tap } from 'rxjs/operators'; -import { DossiersDialogService } from '../../dossier/services/dossiers-dialog.service'; +import { DossiersDialogService } from '../../dossier/shared/services/dossiers-dialog.service'; +import { Router } from '@angular/router'; @Component({ templateUrl: './dossiers-listing-screen.component.html', @@ -40,8 +41,10 @@ export class DossiersListingScreenComponent extends ListingComponent im private readonly _configService: ConfigService, private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _dialogService: DossiersDialogService, + private readonly _router: Router, ) { super(_injector); + this._router.routeReuseStrategy.shouldReuseRoute = () => false; } get defaultDossierTemplateId(): string { diff --git a/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.ts b/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.ts index c84117b21..70a2777ea 100644 --- a/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/components/document-info/document-info.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { DocumentInfoService } from '../../services/document-info.service'; import { combineLatest, Observable, switchMap } from 'rxjs'; import { PermissionsService } from '@services/permissions.service'; diff --git a/apps/red-ui/src/app/modules/file-preview/services/document-info.service.ts b/apps/red-ui/src/app/modules/file-preview/services/document-info.service.ts index 60023ef3a..db0e9ed95 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/document-info.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/document-info.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject, merge, Observable } from 'rxjs'; import { shareLast } from '@iqser/common-ui'; import { filter, map, startWith, tap, withLatestFrom } from 'rxjs/operators'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { FileAttributesService } from '@services/entity-services/file-attributes.service'; import { FilesMapService } from '@services/entity-services/files-map.service'; import { File, IFileAttributeConfig } from '@red/domain'; diff --git a/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts b/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts index 02ec11ae4..935b36fb6 100644 --- a/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts @@ -6,7 +6,7 @@ import { Dictionary, DICTIONARY_TYPE_KEY_MAP, DictionaryType, Dossier, DossierTe import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { DictionaryService } from '@services/entity-services/dictionary.service'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { EditorComponent } from '@shared/components/editor/editor.component'; import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration; diff --git a/apps/red-ui/src/app/modules/shared/components/dossier-name-column/dossier-name-column.component.ts b/apps/red-ui/src/app/modules/shared/components/dossier-name-column/dossier-name-column.component.ts index 6b7635966..94b423232 100644 --- a/apps/red-ui/src/app/modules/shared/components/dossier-name-column/dossier-name-column.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/dossier-name-column/dossier-name-column.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { Dossier, DossierStats } from '@red/domain'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { List } from '@iqser/common-ui'; import dayjs from 'dayjs'; diff --git a/apps/red-ui/src/app/modules/shared/components/simple-doughnut-chart/simple-doughnut-chart.component.scss b/apps/red-ui/src/app/modules/shared/components/simple-doughnut-chart/simple-doughnut-chart.component.scss index 2e474e4dd..51fdd8722 100644 --- a/apps/red-ui/src/app/modules/shared/components/simple-doughnut-chart/simple-doughnut-chart.component.scss +++ b/apps/red-ui/src/app/modules/shared/components/simple-doughnut-chart/simple-doughnut-chart.component.scss @@ -47,6 +47,7 @@ > div { border-radius: 4px; padding: 3px 8px; + width: 100%; &:not(:last-child) { margin-bottom: 8px; diff --git a/apps/red-ui/src/app/modules/shared/components/simple-doughnut-chart/simple-doughnut-chart.component.ts b/apps/red-ui/src/app/modules/shared/components/simple-doughnut-chart/simple-doughnut-chart.component.ts index d91417945..ffa553406 100644 --- a/apps/red-ui/src/app/modules/shared/components/simple-doughnut-chart/simple-doughnut-chart.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/simple-doughnut-chart/simple-doughnut-chart.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnChanges, OnInit } from '@angular/core'; +import { Component, Input, OnChanges, OnInit, Optional } from '@angular/core'; import { Color } from '@red/domain'; import { FilterService, INestedFilter } from '@iqser/common-ui'; import { Observable, of } from 'rxjs'; @@ -30,17 +30,20 @@ export class SimpleDoughnutChartComponent implements OnChanges, OnInit { filtersEnabled: boolean; chartData: any[] = []; - perimeter: number; cx = 0; cy = 0; size = 0; filters$: Observable; - constructor(readonly filterService: FilterService) { - this.filterService.filterGroups$.subscribe(() => { - this.filtersEnabled = !!this.filterService.filterGroups.find(g => g.slug === this.filterKey); - }); + constructor(@Optional() readonly filterService: FilterService) { + if (filterService) { + this.filterService.filterGroups$.subscribe(() => { + this.filtersEnabled = !!this.filterService.filterGroups.find(g => g.slug === this.filterKey); + }); + } else { + this.filtersEnabled = false; + } } get circumference(): number { @@ -56,7 +59,7 @@ export class SimpleDoughnutChartComponent implements OnChanges, OnInit { } ngOnInit() { - this.filters$ = this.filterService.getFilterModels$(this.filterKey) ?? of([]); + this.filters$ = (this.filtersEnabled && this.filterService.getFilterModels$(this.filterKey)) ?? of([]); } ngOnChanges(): void { @@ -67,7 +70,7 @@ export class SimpleDoughnutChartComponent implements OnChanges, OnInit { } filterChecked$(key: string): Observable { - return this.filters$.pipe(map(all => all?.find(e => e.id === key)?.checked)); + return this.filtersEnabled ? this.filters$.pipe(map(all => all?.find(e => e.id === key)?.checked)) : of(false); } calculateChartData() { diff --git a/apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.ts b/apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.ts index fc3d0f8e0..2ec1357f0 100644 --- a/apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/team-members/team-members.component.ts @@ -1,7 +1,7 @@ import { Component, ElementRef, EventEmitter, Input, Output, ViewChild } from '@angular/core'; import { CircleButtonTypes, List } from '@iqser/common-ui'; import { UserService } from '@services/user.service'; -import { DossiersDialogService } from '../../../dossier/services/dossiers-dialog.service'; +import { DossiersDialogService } from '../../../dossier/shared/services/dossiers-dialog.service'; @Component({ selector: 'redaction-team-members', diff --git a/apps/red-ui/src/app/services/breadcrumbs.service.ts b/apps/red-ui/src/app/services/breadcrumbs.service.ts index 1cd1d22aa..27f1bf465 100644 --- a/apps/red-ui/src/app/services/breadcrumbs.service.ts +++ b/apps/red-ui/src/app/services/breadcrumbs.service.ts @@ -10,7 +10,7 @@ import { DOSSIER_ID, DOSSIER_TEMPLATE_ID, DOSSIERS_ARCHIVE, FILE_ID } from '@uti import { DossiersService } from '@services/dossiers/dossiers.service'; import { dossiersServiceResolver } from '@services/entity-services/dossiers.service.provider'; import { FeaturesService } from '@services/features.service'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; export type RouterLinkActiveOptions = { exact: boolean } | IsActiveMatchOptions; export type BreadcrumbDisplayType = 'text' | 'dropdown'; diff --git a/apps/red-ui/src/app/services/dossier-templates/dashboard-stats.service.ts b/apps/red-ui/src/app/services/dossier-templates/dashboard-stats.service.ts new file mode 100644 index 000000000..79819f682 --- /dev/null +++ b/apps/red-ui/src/app/services/dossier-templates/dashboard-stats.service.ts @@ -0,0 +1,29 @@ +import { EntitiesService, mapEach } from '@iqser/common-ui'; +import { DashboardStats, IDashboardStats } from '@red/domain'; +import { Injectable, Injector } from '@angular/core'; +import { NGXLogger } from 'ngx-logger'; +import { Observable } from 'rxjs'; +import { map, switchMap, tap } from 'rxjs/operators'; +import { DossierStatesService } from '@services/entity-services/dossier-states.service'; + +@Injectable({ + providedIn: 'root', +}) +export class DashboardStatsService extends EntitiesService { + constructor( + protected readonly _injector: Injector, + private readonly _dossierStatesService: DossierStatesService, + private readonly _logger: NGXLogger, + ) { + super(_injector, DashboardStats, 'dossier-template/stats'); + } + + loadAll(): Observable { + return this.getAll(this._defaultModelPath).pipe( + mapEach(entity => new DashboardStats(entity)), + switchMap(entities => this._dossierStatesService.loadAllForAllTemplates().pipe(map(() => entities))), + tap(entities => entities.sort((a, b) => (a.numberOfActiveDossiers > 0 && b.numberOfActiveDossiers === 0 ? -1 : 1))), + tap(entities => this.setEntities(entities)), + ); + } +} diff --git a/apps/red-ui/src/app/services/entity-services/dossier-templates.service.ts b/apps/red-ui/src/app/services/dossier-templates/dossier-templates.service.ts similarity index 93% rename from apps/red-ui/src/app/services/entity-services/dossier-templates.service.ts rename to apps/red-ui/src/app/services/dossier-templates/dossier-templates.service.ts index a6479d814..979e3d9e5 100644 --- a/apps/red-ui/src/app/services/entity-services/dossier-templates.service.ts +++ b/apps/red-ui/src/app/services/dossier-templates/dossier-templates.service.ts @@ -2,12 +2,12 @@ import { EntitiesService, List, mapEach, RequiredParam, Toaster, Validate } from import { DossierTemplate, IDossierTemplate } from '@red/domain'; import { Injectable, Injector } from '@angular/core'; import { forkJoin, Observable, of } from 'rxjs'; -import { FileAttributesService } from './file-attributes.service'; +import { FileAttributesService } from '../entity-services/file-attributes.service'; import { catchError, mapTo, switchMap, tap } from 'rxjs/operators'; -import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service'; +import { DossierTemplateStatsService } from '../entity-services/dossier-template-stats.service'; import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { DictionaryService } from '@services/entity-services/dictionary.service'; +import { DictionaryService } from '../entity-services/dictionary.service'; const DOSSIER_TEMPLATE_CONFLICT_MSG = _('dossier-templates-listing.error.conflict'); const GENERIC_MSG = _('dossier-templates-listing.error.generic'); diff --git a/apps/red-ui/src/app/services/dossiers/active-dossiers.service.ts b/apps/red-ui/src/app/services/dossiers/active-dossiers.service.ts index 95291300e..54a4f8d01 100644 --- a/apps/red-ui/src/app/services/dossiers/active-dossiers.service.ts +++ b/apps/red-ui/src/app/services/dossiers/active-dossiers.service.ts @@ -4,11 +4,6 @@ import { timer } from 'rxjs'; import { CHANGED_CHECK_INTERVAL, DOSSIERS_ROUTE } from '@utils/constants'; import { DossiersService } from './dossiers.service'; -export interface IDossiersStats { - totalPeople: number; - totalAnalyzedPages: number; -} - @Injectable({ providedIn: 'root', }) @@ -23,8 +18,4 @@ export class ActiveDossiersService extends DossiersService { ) .subscribe(); } - - getCountWithState(dossierStatusId: string): number { - return this.all.filter(dossier => dossier.dossierStatusId === dossierStatusId).length; - } } diff --git a/apps/red-ui/src/app/services/dossiers/dossiers.service.ts b/apps/red-ui/src/app/services/dossiers/dossiers.service.ts index 32d44d88f..2a576a40f 100644 --- a/apps/red-ui/src/app/services/dossiers/dossiers.service.ts +++ b/apps/red-ui/src/app/services/dossiers/dossiers.service.ts @@ -1,23 +1,21 @@ -import { EntitiesService, List, mapEach, QueryParam, RequiredParam, shareLast, Toaster, Validate } from '@iqser/common-ui'; +import { EntitiesService, List, mapEach, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui'; import { Dossier, DossierStats, IDossier, IDossierChanges, IDossierRequest } from '@red/domain'; -import { combineLatest, forkJoin, Observable, of, Subject, throwError } from 'rxjs'; +import { forkJoin, Observable, of, Subject, throwError } from 'rxjs'; import { catchError, filter, map, switchMap, tap } from 'rxjs/operators'; import { Injector } from '@angular/core'; -import { DossierStatesService } from '../entity-services/dossier-states.service'; import { DossierStatsService } from './dossier-stats.service'; -import { IDossiersStats } from './active-dossiers.service'; import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { NGXLogger } from 'ngx-logger'; +import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; const CONFLICT_MSG = _('add-dossier-dialog.errors.dossier-already-exists'); const GENERIC_MSG = _('add-dossier-dialog.errors.generic'); export abstract class DossiersService extends EntitiesService { readonly dossierFileChanges$ = new Subject(); - readonly generalStats$ = this.all$.pipe(switchMap(entities => this.#generalStats$(entities))); protected readonly _dossierStatsService = this._injector.get(DossierStatsService); - protected readonly _dossierStateService = this._injector.get(DossierStatesService); + protected readonly _dashboardStatsService = this._injector.get(DashboardStatsService); protected readonly _toaster = this._injector.get(Toaster); protected readonly _logger = this._injector.get(NGXLogger); @@ -64,7 +62,7 @@ export abstract class DossiersService extends EntitiesService mapEach(entity => new Dossier(entity)), /* Load stats before updating entities */ switchMap(dossiers => this._dossierStatsService.getFor(dossierIds(dossiers)).pipe(map(() => dossiers))), - switchMap(dossiers => this._dossierStateService.loadAllForAllTemplates().pipe(map(() => dossiers))), + switchMap(dossiers => this._dashboardStatsService.loadAll().pipe(map(() => dossiers))), tap(dossiers => this.setEntities(dossiers)), ); } @@ -86,28 +84,4 @@ export abstract class DossiersService extends EntitiesService switchMap(dossier => this._dossierStatsService.getFor([dossier.dossierId])), ); } - - #computeStats(entities: List): IDossiersStats { - let totalAnalyzedPages = 0; - const totalPeople = new Set(); - - entities.forEach(dossier => { - dossier.memberIds?.forEach(m => totalPeople.add(m)); - totalAnalyzedPages += this._dossierStatsService.get(dossier.dossierId).numberOfPages; - }); - - return { - totalPeople: totalPeople.size, - totalAnalyzedPages, - }; - } - - #generalStats$(entities: List): Observable { - const stats$ = entities.map(entity => this._dossierStatsService.watch$(entity.dossierId)); - return combineLatest(stats$).pipe( - filter(stats => stats.every(s => !!s)), - map(() => this.#computeStats(entities)), - shareLast(), - ); - } } diff --git a/apps/red-ui/src/app/services/entity-services/dossier-states.service.ts b/apps/red-ui/src/app/services/entity-services/dossier-states.service.ts index 7e2659262..1fa21f731 100644 --- a/apps/red-ui/src/app/services/entity-services/dossier-states.service.ts +++ b/apps/red-ui/src/app/services/entity-services/dossier-states.service.ts @@ -2,7 +2,7 @@ import { Injectable, Injector } from '@angular/core'; import { EntitiesService, mapEach, RequiredParam, Toaster, Validate } from '@iqser/common-ui'; import { DossierState, IDossierState } from '@red/domain'; import { EMPTY, forkJoin, Observable, switchMap } from 'rxjs'; -import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { catchError, defaultIfEmpty, tap } from 'rxjs/operators'; import { DossierStatesMapService } from '@services/entity-services/dossier-states-map.service'; import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http'; diff --git a/apps/red-ui/src/app/services/entity-services/trash.service.ts b/apps/red-ui/src/app/services/entity-services/trash.service.ts index 841bda468..e0cf923fb 100644 --- a/apps/red-ui/src/app/services/entity-services/trash.service.ts +++ b/apps/red-ui/src/app/services/entity-services/trash.service.ts @@ -12,11 +12,6 @@ import { flatMap } from 'lodash-es'; import { DossierStatsService } from '@services/dossiers/dossier-stats.service'; import { FilesService } from '@services/entity-services/files.service'; -export interface IDossiersStats { - totalPeople: number; - totalAnalyzedPages: number; -} - @Injectable({ providedIn: 'root', }) diff --git a/apps/red-ui/src/app/services/translate-chart.service.ts b/apps/red-ui/src/app/services/translate-chart.service.ts index 97c14b8e6..335022e91 100644 --- a/apps/red-ui/src/app/services/translate-chart.service.ts +++ b/apps/red-ui/src/app/services/translate-chart.service.ts @@ -2,17 +2,34 @@ import { Injectable } from '@angular/core'; import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; import { TranslateService } from '@ngx-translate/core'; import { rolesTranslations } from '../translations/roles-translations'; +import { workflowFileStatusTranslations } from '../translations/file-status-translations'; +import { DossierStatesMapService } from './entity-services/dossier-states-map.service'; @Injectable({ providedIn: 'root', }) export class TranslateChartService { - constructor(private readonly _translateService: TranslateService) {} + constructor(private readonly _translateService: TranslateService, private readonly _dossierStatesMapService: DossierStatesMapService) {} - translateStatus(config: DoughnutChartConfig[]): DoughnutChartConfig[] { + translateLabels(config: DoughnutChartConfig[]): DoughnutChartConfig[] { return config.map(val => ({ ...val, label: this._translateService.instant(val.label) })); } + translateDossierStates(config: DoughnutChartConfig[], dossierTemplateId: string): DoughnutChartConfig[] { + return config.map(val => { + if (!val.key) { + return { ...val, label: this._translateService.instant(val.label) }; + } else { + const dossierState = this._dossierStatesMapService.get(dossierTemplateId, val.key); + return { ...val, key: null, label: dossierState.name, color: dossierState.color }; + } + }); + } + + translateWorkflowStatus(config: DoughnutChartConfig[]): DoughnutChartConfig[] { + return config.map(val => ({ ...val, label: this._translateService.instant(workflowFileStatusTranslations[val.label] as string) })); + } + translateRoles(config: DoughnutChartConfig[]): DoughnutChartConfig[] { return config.map(val => ({ ...val, diff --git a/apps/red-ui/src/assets/i18n/de.json b/apps/red-ui/src/assets/i18n/de.json index c7e80f795..bbedce60f 100644 --- a/apps/red-ui/src/assets/i18n/de.json +++ b/apps/red-ui/src/assets/i18n/de.json @@ -775,10 +775,6 @@ }, "stats": { "analyzed-pages": "Seiten", - "charts": { - "dossiers": "Dossiers", - "total-documents": "Anzahl der Dokumente" - }, "total-people": "Anzahl der Benutzer" }, "table-col-names": { @@ -793,6 +789,10 @@ "title": "{length} {length, plural, one{aktives Dossier} other{aktive Dossiers}}" } }, + "dossier-template-charts": { + "active-dossiers": "Aktive Dossiers", + "total-documents": "Anzahl der Dokumente" + }, "dossier-overview": { "approve": "Genehmigen", "approve-disabled": "Das Dokument kann erst genehmigt werden, wenn eine Analyse auf Basis der aktuellen Wörterbücher durchgeführt wurde und die Vorschläge bearbeitet wurden.", diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 506ab0e25..e7cb7e021 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -775,10 +775,6 @@ }, "stats": { "analyzed-pages": "{count, plural, one{Page} other{Pages}}", - "charts": { - "dossiers": "{count, plural, one{Dossier} other{Dossiers}}", - "total-documents": "Total Documents" - }, "total-people": "Total users" }, "table-col-names": { @@ -793,6 +789,10 @@ "title": "{length} active {length, plural, one{Dossier} other{Dossiers}}" } }, + "dossier-template-charts": { + "active-dossiers": "Active {count, plural, one{Dossier} other{Dossiers}}", + "total-documents": "Total Documents" + }, "dossier-overview": { "approve": "Approve", "approve-disabled": "File can only be approved once it has been analysed with the latest dictionaries and all suggestions have been processed.", diff --git a/libs/common-ui b/libs/common-ui index f06c007be..5444b09e6 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit f06c007bec1a7da5c257e68d6df8c806419ceb2b +Subproject commit 5444b09e647672383a0b39d23400a98d7efb6536 diff --git a/libs/red-domain/src/lib/dossier-templates/dashboard-stats.model.ts b/libs/red-domain/src/lib/dossier-templates/dashboard-stats.model.ts new file mode 100644 index 000000000..d99a9b03c --- /dev/null +++ b/libs/red-domain/src/lib/dossier-templates/dashboard-stats.model.ts @@ -0,0 +1,89 @@ +import { IDashboardStats, ProcessingFileStatus, StatusSorter, WorkflowFileStatus } from '@red/domain'; +import { IListable } from '@iqser/common-ui'; +import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; + +export class DashboardStats implements IListable, IDashboardStats { + readonly dossierCountByStatus: [ + { + count: number; + statusId: string; + }, + ]; + readonly dossierTemplateId: string; + readonly dossiersInTemplate: [string]; + readonly fileCountPerProcessingStatus: [ + { + readonly count: number; + readonly processingStatus: ProcessingFileStatus; + }, + ]; + readonly fileCountPerWorkflowStatus: [ + { + readonly count: number; + readonly workflowStatus: WorkflowFileStatus; + }, + ]; + readonly name: string; + readonly numberOfActiveDossiers: number; + readonly numberOfActiveFiles: number; + readonly numberOfArchivedDossiers: number; + readonly numberOfDeletedDossiers: number; + readonly numberOfExcludedPages: number; + readonly numberOfPages: number; + readonly numberOfPeople: number; + readonly numberOfSoftDeletedFiles: number; + readonly dossiersChartData: DoughnutChartConfig[]; + readonly documentsChartData: DoughnutChartConfig[]; + + constructor(stats: IDashboardStats) { + this.dossierCountByStatus = stats.dossierCountByStatus; + this.dossierTemplateId = stats.dossierTemplateId; + this.dossiersInTemplate = stats.dossiersInTemplate; + this.fileCountPerProcessingStatus = stats.fileCountPerProcessingStatus; + this.fileCountPerWorkflowStatus = stats.fileCountPerWorkflowStatus; + this.name = stats.name; + this.numberOfActiveDossiers = stats.numberOfActiveDossiers; + this.numberOfActiveFiles = stats.numberOfActiveFiles; + this.numberOfArchivedDossiers = stats.numberOfArchivedDossiers; + this.numberOfDeletedDossiers = stats.numberOfDeletedDossiers; + this.numberOfExcludedPages = stats.numberOfExcludedPages; + this.numberOfPages = stats.numberOfPages; + this.numberOfPeople = stats.numberOfPeople; + this.numberOfSoftDeletedFiles = stats.numberOfSoftDeletedFiles; + + this.dossiersChartData = this._dossiersChartData; + this.documentsChartData = this._documentsChartData; + } + + get isEmpty(): boolean { + return this.numberOfActiveDossiers === 0; + } + + get id(): string { + return this.dossierTemplateId; + } + + get searchKey(): string { + return this.name; + } + + private get _dossiersChartData(): DoughnutChartConfig[] { + return this.dossierCountByStatus.map(d => ({ + value: d.count, + color: '#e2e4e9', + label: 'edit-dossier-dialog.general-info.form.dossier-state.placeholder', + key: d.statusId, + })); + } + + private get _documentsChartData(): DoughnutChartConfig[] { + const configArray: DoughnutChartConfig[] = this.fileCountPerWorkflowStatus.map(d => ({ + value: d.count, + color: d.workflowStatus, + label: d.workflowStatus, + key: d.workflowStatus, + })); + configArray.sort((a: DoughnutChartConfig, b) => StatusSorter.byStatus(a.label, b.label)); + return configArray; + } +} diff --git a/libs/red-domain/src/lib/dossier-templates/dashboard-stats.ts b/libs/red-domain/src/lib/dossier-templates/dashboard-stats.ts new file mode 100644 index 000000000..b7db72f1d --- /dev/null +++ b/libs/red-domain/src/lib/dossier-templates/dashboard-stats.ts @@ -0,0 +1,33 @@ +import { ProcessingFileStatus, WorkflowFileStatus } from '@red/domain'; + +export interface IDashboardStats { + readonly dossierCountByStatus: [ + { + count: number; + statusId: string; + }, + ]; + readonly dossierTemplateId: string; + readonly dossiersInTemplate: [string]; + readonly fileCountPerProcessingStatus: [ + { + readonly count: number; + readonly processingStatus: ProcessingFileStatus; + }, + ]; + readonly fileCountPerWorkflowStatus: [ + { + readonly count: number; + readonly workflowStatus: WorkflowFileStatus; + }, + ]; + readonly name: string; + readonly numberOfActiveDossiers: number; + readonly numberOfActiveFiles: number; + readonly numberOfArchivedDossiers: number; + readonly numberOfDeletedDossiers: number; + readonly numberOfExcludedPages: number; + readonly numberOfPages: number; + readonly numberOfPeople: number; + readonly numberOfSoftDeletedFiles: number; +} diff --git a/libs/red-domain/src/lib/dossier-templates/index.ts b/libs/red-domain/src/lib/dossier-templates/index.ts index cf815ad22..8af5fc988 100644 --- a/libs/red-domain/src/lib/dossier-templates/index.ts +++ b/libs/red-domain/src/lib/dossier-templates/index.ts @@ -2,4 +2,6 @@ export * from './dossier-template'; export * from './dossier-template.model'; export * from './dossier-template-stats'; export * from './dossier-template-stats.model'; +export * from './dashboard-stats'; +export * from './dashboard-stats.model'; export * from './types'; From f27b68a951af8ecbd61c54d241284628ad2dbd14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Wed, 4 May 2022 19:45:12 +0300 Subject: [PATCH 06/12] RED-3796: Dossier template stats --- .../template-stats.component.html | 46 ++++++++++++++--- .../template-stats.component.scss | 50 +++++++++++++------ .../dossiers-listing-details.component.html | 4 +- apps/red-ui/src/assets/i18n/de.json | 12 +++-- apps/red-ui/src/assets/i18n/en.json | 12 +++-- 5 files changed, 92 insertions(+), 32 deletions(-) diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html index efc0d7ac0..1536fe05b 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html @@ -1,15 +1,47 @@ -
+ -
- {{ dossierTemplate.name }} - {{ dossierTemplate.id }} +
+
{{ dossierTemplate.name }}
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
@@ -19,7 +51,7 @@ [config]="translateChartService.translateWorkflowStatus(dossierTemplate.documentsChartData)" [radius]="70" [strokeWidth]="15" - [subtitle]="'dossier-template-charts.total-documents' | translate" + [subtitle]="'dossier-template-stats.total-documents' | translate" direction="row" totalType="sum" > @@ -42,4 +74,4 @@ icon="iqser:plus" > -
+ diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss index 18acdf1c2..6f4fc35f8 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss @@ -1,16 +1,12 @@ +@use 'common-mixins'; + .dialog { + @include common-mixins.clear-a; flex-direction: row; max-width: unset; min-height: unset; margin: 0 0 16px 0; - - .heading { - color: var(--iqser-accent); - - &:not(:hover) { - text-decoration: none; - } - } + transition: background-color 0.2s; &.empty { justify-content: space-between; @@ -18,14 +14,38 @@ padding: 24px; } - &:not(.empty) > div { - padding: 24px; - display: flex; - flex-direction: column; + &:not(.empty) { + &:hover { + background-color: var(--iqser-grey-2); - &:not(:first-child) { - justify-content: center; - border-left: 1px solid var(--iqser-separator); + .heading { + text-decoration: underline; + } + } + + > div { + padding: 24px; + display: flex; + flex-direction: column; + + &:not(:first-child) { + justify-content: center; + border-left: 1px solid var(--iqser-separator); + } } } } + +.stats-subtitle { + flex-direction: column; + + > div { + margin-top: 10px; + } + + mat-icon { + min-height: 14px; + min-width: 14px; + margin-right: 8px; + } +} diff --git a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html index 38b884779..65ece10d7 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html +++ b/apps/red-ui/src/app/modules/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.html @@ -3,7 +3,7 @@ [config]="dossiersChartData$ | async" [radius]="80" [strokeWidth]="15" - [subtitle]="'dossier-template-charts.active-dossiers' | translate: { count: stats.numberOfActiveDossiers }" + [subtitle]="'dossier-template-stats.active-dossiers' | translate: { count: stats.numberOfActiveDossiers }" >
@@ -30,6 +30,6 @@ [config]="documentsChartData$ | async" [radius]="80" [strokeWidth]="15" - [subtitle]="'dossier-template-charts.total-documents' | translate" + [subtitle]="'dossier-template-stats.total-documents' | translate" >
diff --git a/apps/red-ui/src/assets/i18n/de.json b/apps/red-ui/src/assets/i18n/de.json index bbedce60f..ed05f1c84 100644 --- a/apps/red-ui/src/assets/i18n/de.json +++ b/apps/red-ui/src/assets/i18n/de.json @@ -789,10 +789,6 @@ "title": "{length} {length, plural, one{aktives Dossier} other{aktive Dossiers}}" } }, - "dossier-template-charts": { - "active-dossiers": "Aktive Dossiers", - "total-documents": "Anzahl der Dokumente" - }, "dossier-overview": { "approve": "Genehmigen", "approve-disabled": "Das Dokument kann erst genehmigt werden, wenn eine Analyse auf Basis der aktuellen Wörterbücher durchgeführt wurde und die Vorschläge bearbeitet wurden.", @@ -933,6 +929,14 @@ "valid-from": "", "valid-to": "" }, + "dossier-template-stats": { + "active-dossiers": "Aktive Dossiers", + "analyzed-pages": "", + "archived-dossiers": "", + "deleted-dossiers": "", + "total-documents": "Anzahl der Dokumente", + "total-people": "" + }, "dossier-templates-listing": { "action": { "clone": "", diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index e7cb7e021..7bb13a438 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -789,10 +789,6 @@ "title": "{length} active {length, plural, one{Dossier} other{Dossiers}}" } }, - "dossier-template-charts": { - "active-dossiers": "Active {count, plural, one{Dossier} other{Dossiers}}", - "total-documents": "Total Documents" - }, "dossier-overview": { "approve": "Approve", "approve-disabled": "File can only be approved once it has been analysed with the latest dictionaries and all suggestions have been processed.", @@ -933,6 +929,14 @@ "valid-from": "Valid from: {date}", "valid-to": "Valid to: {date}" }, + "dossier-template-stats": { + "active-dossiers": "Active {count, plural, one{Dossier} other{Dossiers}}", + "analyzed-pages": "{count} {count, plural, one{Page} other {Pages}} Analysed", + "archived-dossiers": "{count} {count, plural, one{Dossier} other {Dossiers}} in Archive", + "deleted-dossiers": "{count} {count, plural, one{Dossier} other {Dossiers}} in Trash", + "total-documents": "Total Documents", + "total-people": "{count} {count, plural, one{User} other {Users}}" + }, "dossier-templates-listing": { "action": { "clone": "Clone Template", From e1be225c1794ccfff74e0a7d841e8876063b47ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Thu, 5 May 2022 16:43:39 +0300 Subject: [PATCH 07/12] RED-3796: Empty dossier template checks --- .../app/guards/dossier-template-exists.guard.ts | 11 ++++++----- .../template-stats.component.scss | 1 + .../src/app/services/breadcrumbs.service.ts | 17 +++++++++-------- .../dossiers.service.provider.ts | 4 ++-- libs/common-ui | 2 +- 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts b/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts index a50d2c8a2..b53592a16 100644 --- a/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts +++ b/apps/red-ui/src/app/guards/dossier-template-exists.guard.ts @@ -1,17 +1,18 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; -import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { DOSSIER_TEMPLATE_ID } from '@utils/constants'; +import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; @Injectable({ providedIn: 'root' }) export class DossierTemplateExistsGuard implements CanActivate { - constructor(private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _router: Router) {} + constructor(private readonly _dashboardStatsService: DashboardStatsService, private readonly _router: Router) {} async canActivate(route: ActivatedRouteSnapshot): Promise { const dossierTemplateId: string = route.paramMap.get(DOSSIER_TEMPLATE_ID); - if (!this._dossierTemplatesService.find(dossierTemplateId)) { - const adminView = !!route.pathFromRoot.find(r => r.routeConfig?.path === 'admin'); - const routerPath = adminView ? ['main', 'admin', 'dossier-templates'] : ['']; + const dossiersListView = !route.pathFromRoot.find(r => r.routeConfig?.path === 'admin'); + const dossierTemplateStats = this._dashboardStatsService.find(dossierTemplateId); + if (!dossierTemplateStats || (dossiersListView && dossierTemplateStats.isEmpty)) { + const routerPath = dossiersListView ? [''] : ['main', 'admin', 'dossier-templates']; await this._router.navigate(routerPath); return false; } diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss index 6f4fc35f8..fad1efcf3 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.scss @@ -12,6 +12,7 @@ justify-content: space-between; align-items: center; padding: 24px; + cursor: default; } &:not(.empty) { diff --git a/apps/red-ui/src/app/services/breadcrumbs.service.ts b/apps/red-ui/src/app/services/breadcrumbs.service.ts index 27f1bf465..ce911d9a0 100644 --- a/apps/red-ui/src/app/services/breadcrumbs.service.ts +++ b/apps/red-ui/src/app/services/breadcrumbs.service.ts @@ -10,7 +10,7 @@ import { DOSSIER_ID, DOSSIER_TEMPLATE_ID, DOSSIERS_ARCHIVE, FILE_ID } from '@uti import { DossiersService } from '@services/dossiers/dossiers.service'; import { dossiersServiceResolver } from '@services/entity-services/dossiers.service.provider'; import { FeaturesService } from '@services/features.service'; -import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; +import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; export type RouterLinkActiveOptions = { exact: boolean } | IsActiveMatchOptions; export type BreadcrumbDisplayType = 'text' | 'dropdown'; @@ -41,7 +41,7 @@ export class BreadcrumbsService { private readonly _router: Router, private readonly _translateService: TranslateService, private readonly _filesMapService: FilesMapService, - private readonly _dossierTemplatesService: DossierTemplatesService, + private readonly _dashboardStatsService: DashboardStatsService, private readonly _featuresService: FeaturesService, ) { this.breadcrumbs$ = this._store$.asObservable(); @@ -49,7 +49,7 @@ export class BreadcrumbsService { this._router.events.pipe(filter(event => event instanceof NavigationEnd)).subscribe(() => { const root = this._router.routerState.snapshot.root; this._clear(); - this._addBreadcrumbs(root.firstChild); + this._addBreadcrumbs(root); }); } @@ -58,7 +58,7 @@ export class BreadcrumbsService { } private get _dossiersService(): DossiersService { - return dossiersServiceResolver(this._injector); + return dossiersServiceResolver(this._injector, this._router.routerState.root); } private get _dashboardBreadcrumb(): Breadcrumb { @@ -115,9 +115,10 @@ export class BreadcrumbsService { } private _addDossierTemplateDropdown(params: Record): void { - const breadcrumbs = this._dossierTemplatesService.all.map(dossierTemplate => - this._dossierTemplateBreadcrumb({ dossierTemplateId: dossierTemplate.id }), - ); + const breadcrumbs = this._dashboardStatsService.all + .filter(dt => !dt.isEmpty) + .map(dt => this._dossierTemplateBreadcrumb({ dossierTemplateId: dt.id })); + const activeOption = breadcrumbs.find(b => b.options.routerLink[1] === params[DOSSIER_TEMPLATE_ID]); this._append({ @@ -133,7 +134,7 @@ export class BreadcrumbsService { private _dossierTemplateBreadcrumb(params: Record): Breadcrumb { const dossierTemplateId: string = params[DOSSIER_TEMPLATE_ID]; return { - name$: this._dossierTemplatesService.getEntityChanged$(dossierTemplateId).pipe(pluck('name')), + name$: this._dashboardStatsService.getEntityChanged$(dossierTemplateId).pipe(pluck('name')), type: 'text' as BreadcrumbDisplayType, options: { routerLink: ['/main', dossierTemplateId, this._dossiersService.routerPath], diff --git a/apps/red-ui/src/app/services/entity-services/dossiers.service.provider.ts b/apps/red-ui/src/app/services/entity-services/dossiers.service.provider.ts index 42b0de04a..bd30faa3f 100644 --- a/apps/red-ui/src/app/services/entity-services/dossiers.service.provider.ts +++ b/apps/red-ui/src/app/services/entity-services/dossiers.service.provider.ts @@ -4,8 +4,8 @@ import { DossiersService } from '../dossiers/dossiers.service'; /** Usage in components or services is only allowed in guards or in constructors. * Otherwise, it causes errors on navigation to other screens if the component is reused. */ -export const dossiersServiceResolver = (injector: Injector) => { - let route: ActivatedRoute = injector.get(ActivatedRoute); +export const dossiersServiceResolver = (injector: Injector, _route?: ActivatedRoute) => { + let route: ActivatedRoute = _route || injector.get(ActivatedRoute); while (route.firstChild) { route = route.firstChild; } diff --git a/libs/common-ui b/libs/common-ui index 5444b09e6..dc9323a0e 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit 5444b09e647672383a0b39d23400a98d7efb6536 +Subproject commit dc9323a0ec4d2cdc8ffbb31df67995531160462c From 3739e7a46891a7f4fddc6da2bd7b913aedae71a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Thu, 5 May 2022 18:01:47 +0300 Subject: [PATCH 08/12] RED-3796: Dossiers cache for notifications --- apps/red-ui/src/app/app-routing.module.ts | 5 +- .../notifications/notifications.component.ts | 7 ++- .../app/modules/dashboard/dashboard.module.ts | 5 -- .../dossiers/dossiers-cache.service.ts | 49 +++++++++++++++++++ .../src/app/services/notifications.service.ts | 16 +++--- .../src/lib/dossiers/dossier.model.ts | 15 +++--- 6 files changed, 73 insertions(+), 24 deletions(-) create mode 100644 apps/red-ui/src/app/services/dossiers/dossiers-cache.service.ts diff --git a/apps/red-ui/src/app/app-routing.module.ts b/apps/red-ui/src/app/app-routing.module.ts index fde2d9f9c..e4ae72779 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -12,6 +12,7 @@ import { FeaturesGuard } from '@guards/features-guard.service'; import { ARCHIVE_ROUTE, DOSSIER_TEMPLATE_ID, DOSSIERS_ARCHIVE, DOSSIERS_ROUTE } from '@utils/constants'; import { DossierTemplatesGuard } from '@guards/dossier-templates.guard'; import { DossierTemplateExistsGuard } from '@guards/dossier-template-exists.guard'; +import { DashboardGuard } from '@guards/dashboard-guard.service'; const routes: Routes = [ { @@ -41,7 +42,7 @@ const routes: Routes = [ loadChildren: () => import('./modules/dashboard/dashboard.module').then(m => m.DashboardModule), canActivate: [CompositeRouteGuard], data: { - routeGuards: [AuthGuard, RedRoleGuard], + routeGuards: [AuthGuard, RedRoleGuard, DossierTemplatesGuard, DashboardGuard], requiredRoles: ['RED_USER', 'RED_MANAGER'], }, }, @@ -75,7 +76,7 @@ const routes: Routes = [ ], canActivate: [CompositeRouteGuard], data: { - routeGuards: [AuthGuard, RedRoleGuard, DossierTemplatesGuard, DossierTemplateExistsGuard], + routeGuards: [AuthGuard, RedRoleGuard, DossierTemplatesGuard, DashboardGuard, DossierTemplateExistsGuard], requiredRoles: ['RED_USER', 'RED_MANAGER'], }, }, diff --git a/apps/red-ui/src/app/components/notifications/notifications.component.ts b/apps/red-ui/src/app/components/notifications/notifications.component.ts index e86ba6b10..ea129b453 100644 --- a/apps/red-ui/src/app/components/notifications/notifications.component.ts +++ b/apps/red-ui/src/app/components/notifications/notifications.component.ts @@ -5,6 +5,7 @@ import { Notification } from '@red/domain'; import { distinctUntilChanged, map } from 'rxjs/operators'; import { firstValueFrom, Observable } from 'rxjs'; import { shareLast } from '@iqser/common-ui'; +import { DossiersCacheService } from '@services/dossiers/dossiers-cache.service'; interface NotificationsGroup { date: string; @@ -21,7 +22,11 @@ export class NotificationsComponent { readonly hasUnreadNotifications$: Observable; readonly groupedNotifications$: Observable; - constructor(private readonly _notificationsService: NotificationsService, private readonly _datePipe: DatePipe) { + constructor( + private readonly _notificationsService: NotificationsService, + private readonly _datePipe: DatePipe, + private readonly _dossiersCacheService: DossiersCacheService, + ) { this.groupedNotifications$ = this._notificationsService.all$.pipe(map(notifications => this._groupNotifications(notifications))); this.hasUnreadNotifications$ = this._hasUnreadNotifications$; } diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts b/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts index 3fcc0de17..db67fc124 100644 --- a/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts +++ b/apps/red-ui/src/app/modules/dashboard/dashboard.module.ts @@ -4,20 +4,15 @@ import { DashboardScreenComponent } from './dashboard-screen/dashboard-screen.co import { RouterModule } from '@angular/router'; import { SharedModule } from '../shared/shared.module'; import { TemplateStatsComponent } from './components/template-stats/template-stats.component'; -import { CompositeRouteGuard } from '@iqser/common-ui'; import { SharedDossiersModule } from '../dossier/shared/shared-dossiers.module'; import { BreadcrumbTypes } from '@red/domain'; -import { DossierTemplatesGuard } from '../../guards/dossier-templates.guard'; -import { DashboardGuard } from '../../guards/dashboard-guard.service'; const routes = [ { path: '', component: DashboardScreenComponent, - canActivate: [CompositeRouteGuard], data: { breadcrumbs: [BreadcrumbTypes.dashboard], - routeGuards: [DossierTemplatesGuard, DashboardGuard], }, }, ]; diff --git a/apps/red-ui/src/app/services/dossiers/dossiers-cache.service.ts b/apps/red-ui/src/app/services/dossiers/dossiers-cache.service.ts new file mode 100644 index 000000000..72b955c21 --- /dev/null +++ b/apps/red-ui/src/app/services/dossiers/dossiers-cache.service.ts @@ -0,0 +1,49 @@ +import { EventEmitter, Injectable } from '@angular/core'; +import { ActiveDossiersService } from './active-dossiers.service'; +import { ArchivedDossiersService } from './archived-dossiers.service'; +import { firstValueFrom, forkJoin, merge } from 'rxjs'; +import { map, skip, take } from 'rxjs/operators'; +import { flatten } from 'lodash-es'; +import { Dossier } from '@red/domain'; + +@Injectable({ + providedIn: 'root', +}) +export class DossiersCacheService { + readonly changed$ = new EventEmitter(); + private _dossiers: Dossier[] = JSON.parse(localStorage.getItem('dossiers')) || []; + + constructor( + private readonly _activeDossiersService: ActiveDossiersService, + private readonly _archivedDossiersService: ArchivedDossiersService, + ) { + // Skip 1 to avoid clearing the cache when the dossier services are initialized + merge(_activeDossiersService.all$.pipe(skip(1)), _archivedDossiersService.all$.pipe(skip(1))).subscribe(() => { + this.set(); + }); + } + + get empty(): boolean { + return !localStorage.getItem('dossiers'); + } + + async load(): Promise { + await firstValueFrom( + forkJoin([this._activeDossiersService.loadAll().pipe(take(1)), this._archivedDossiersService.loadAll().pipe(take(1))]).pipe( + map(list => flatten(list)), + ), + ); + this.set(); + } + + set(): void { + const dossiers = flatten([this._activeDossiersService.all, this._archivedDossiersService.all]); + this._dossiers = dossiers; + localStorage.setItem('dossiers', JSON.stringify(dossiers)); + this.changed$.emit(); + } + + get(dossierId: string) { + return this._dossiers.find(dossier => dossier.dossierId === dossierId); + } +} diff --git a/apps/red-ui/src/app/services/notifications.service.ts b/apps/red-ui/src/app/services/notifications.service.ts index e68359f12..2356cd6c1 100644 --- a/apps/red-ui/src/app/services/notifications.service.ts +++ b/apps/red-ui/src/app/services/notifications.service.ts @@ -6,12 +6,11 @@ import { Dossier, INotification, Notification, NotificationTypes } from '@red/do import { map, switchMap, tap } from 'rxjs/operators'; import { notificationsTranslations } from '../translations/notifications-translations'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { ActiveDossiersService } from './dossiers/active-dossiers.service'; import { UserService } from '@services/user.service'; import dayjs from 'dayjs'; import { CHANGED_CHECK_INTERVAL } from '@utils/constants'; import { BASE_HREF } from '../tokens'; -import { ArchivedDossiersService } from '@services/dossiers/archived-dossiers.service'; +import { DossiersCacheService } from '@services/dossiers/dossiers-cache.service'; const INCLUDE_SEEN = false; @@ -23,19 +22,22 @@ export class NotificationsService extends EntitiesService (this._activeDossiersService.all.length ? of(null) : this._activeDossiersService.loadAll())), - switchMap(() => (this._archivedDossiersService.all.length ? of(null) : this._archivedDossiersService.loadAll())), + switchMap(() => (this._dossiersCacheService.empty ? this._dossiersCacheService.load() : of(null))), switchMap(() => this.#loadNotificationsIfChanged()), ) .subscribe(); + + // Rebuild notifications when cached dossiers are updated + this._dossiersCacheService.changed$.subscribe(() => { + this.setEntities(this.all.map(e => this._new(e))); + }); } @Validate() @@ -75,7 +77,7 @@ export class NotificationsService extends EntitiesService 1; + + const routerPath = (this.isArchived ? ARCHIVE_ROUTE : DOSSIERS_ROUTE) as string; + this.dossiersListRouterLink = `/main/${this.dossierTemplateId}/${routerPath}`; + this.routerLink = `${this.dossiersListRouterLink}/${this.dossierId}`; } get id(): string { return this.dossierId; } - get routerLink(): string { - return `${this.dossiersListRouterLink}/${this.dossierId}`; - } - - get dossiersListRouterLink(): string { - const routerPath = this.isArchived ? ARCHIVE_ROUTE : DOSSIERS_ROUTE; - return `/main/${this.dossierTemplateId}/${routerPath}`; - } - get searchKey(): string { return this.dossierName; } From 56765ea81ed61508f0b2f2ce65c73b00aea42f40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Fri, 6 May 2022 18:12:51 +0300 Subject: [PATCH 09/12] RED-3796: Working downloads & search --- apps/red-ui/src/app/app-routing.module.ts | 34 +++++++++---------- .../table-item/table-item.component.ts | 2 +- .../template-stats.component.html | 8 ++--- .../template-stats.component.scss | 1 + .../dossier-details-stats.component.ts | 6 ++-- ...ossier-overview-screen-header.component.ts | 2 +- .../add-dossier-dialog.component.ts | 2 +- .../edit-dossier-team.component.html | 10 +++--- .../edit-dossier-general-info.component.ts | 2 +- .../dossiers-listing-actions.component.html | 2 +- .../dossiers-listing-actions.component.ts | 2 +- .../table-item/table-item.component.ts | 2 +- .../dossiers-listing/config.service.ts | 4 +-- .../accept-recommendation-dialog.component.ts | 5 +-- .../manual-annotation-dialog.component.ts | 5 +-- .../services/annotation-actions.service.ts | 2 +- .../search-screen/search-screen.component.ts | 12 +++---- .../dictionary-manager.component.ts | 2 +- .../dossiers/active-dossiers.service.ts | 18 ++++++++-- .../dossiers/dossiers-cache.service.ts | 11 +++--- .../platform-search.service.ts | 20 +++++------ .../services/entity-services/trash.service.ts | 2 +- .../src/app/services/permissions.service.ts | 2 +- libs/common-ui | 2 +- .../src/lib/dossiers/dossier.model.ts | 6 ++-- .../src/lib/trash/trash-dossier.model.ts | 5 ++- 26 files changed, 86 insertions(+), 83 deletions(-) diff --git a/apps/red-ui/src/app/app-routing.module.ts b/apps/red-ui/src/app/app-routing.module.ts index e4ae72779..a9c7fc151 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -46,6 +46,23 @@ const routes: Routes = [ requiredRoles: ['RED_USER', 'RED_MANAGER'], }, }, + { + path: 'downloads', + component: DownloadsListScreenComponent, + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, RedRoleGuard], + }, + }, + { + path: 'search', + loadChildren: () => import('./modules/search/search.module').then(m => m.SearchModule), + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, RedRoleGuard], + requiredRoles: ['RED_USER', 'RED_MANAGER'], + }, + }, { path: `:${DOSSIER_TEMPLATE_ID}`, children: [ @@ -80,23 +97,6 @@ const routes: Routes = [ requiredRoles: ['RED_USER', 'RED_MANAGER'], }, }, - { - path: 'downloads', - component: DownloadsListScreenComponent, - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, RedRoleGuard], - }, - }, - { - path: 'search', - loadChildren: () => import('./modules/search/search.module').then(m => m.SearchModule), - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, RedRoleGuard, DossiersGuard], - requiredRoles: ['RED_USER', 'RED_MANAGER'], - }, - }, ], }, { diff --git a/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.ts b/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.ts index 84c4bcd65..b978de713 100644 --- a/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.ts +++ b/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.ts @@ -22,7 +22,7 @@ export class TableItemComponent implements OnChanges { ngOnChanges() { if (this.dossier) { - this.#ngOnChanges$.next(this.dossier.dossierId); + this.#ngOnChanges$.next(this.dossier.id); } } } diff --git a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html index 1536fe05b..be41704eb 100644 --- a/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html +++ b/apps/red-ui/src/app/modules/dashboard/components/template-stats/template-stats.component.html @@ -36,20 +36,20 @@
-
+
-
+
{ - await firstValueFrom(this._filesService.loadAll(this.dossier.dossierId)); + await firstValueFrom(this._filesService.loadAll(this.dossier.id)); }); } } diff --git a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.ts b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.ts index 666a68e48..ced3ba7d5 100644 --- a/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.ts +++ b/apps/red-ui/src/app/modules/dossier-overview/components/screen-header/dossier-overview-screen-header.component.ts @@ -51,7 +51,7 @@ export class DossierOverviewScreenHeaderComponent implements OnInit { ) {} ngOnInit() { - this.actionConfigs = this.configService.actionConfig(this.dossier.dossierId, this.listingService.areSomeSelected$); + this.actionConfigs = this.configService.actionConfig(this.dossier.id, this.listingService.areSomeSelected$); } async reanalyseDossier() { diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts index 6bd41503d..b6be00297 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts @@ -77,7 +77,7 @@ export class AddDossierDialogComponent extends BaseDialogComponent { await this._router.navigate([savedDossier.routerLink]); if (options?.addMembers) { this._dialogService.openDialog('editDossier', null, { - dossierId: savedDossier.dossierId, + dossierId: savedDossier.id, section: 'members', }); } diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.html b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.html index de53985b0..c446cf066 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.html +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component.html @@ -3,7 +3,7 @@ {{ 'assign-dossier-owner.dialog.single-user' | translate }} - + {{ userId | name }} @@ -11,12 +11,12 @@
-
+
-
+
{ - const stats = this._dossierStatsService.get(dossier.dossierId); + const stats = this._dossierStatsService.get(dossier.id); return stats?.fileCountPerWorkflowStatus[filter.id]; }; private _annotationFilterChecker = (dossier: Dossier, filter: INestedFilter) => { - const stats = this._dossierStatsService.get(dossier.dossierId); + const stats = this._dossierStatsService.get(dossier.id); switch (filter.id) { // case 'analysis': { // return stats.reanalysisRequired; diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/accept-recommendation-dialog/accept-recommendation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/accept-recommendation-dialog/accept-recommendation-dialog.component.ts index a945a3430..a63b328a3 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/accept-recommendation-dialog/accept-recommendation-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/accept-recommendation-dialog/accept-recommendation-dialog.component.ts @@ -54,10 +54,7 @@ export class AcceptRecommendationDialogComponent extends BaseDialogComponent imp async ngOnInit() { super.ngOnInit(); - this.possibleDictionaries = await this._dictionaryService.getDictionariesOptions( - this._dossier.dossierTemplateId, - this._dossier.dossierId, - ); + this.possibleDictionaries = await this._dictionaryService.getDictionariesOptions(this._dossier.dossierTemplateId, this._dossier.id); this.form.patchValue({ dictionary: this.possibleDictionaries.find(dict => dict.type === this.data.annotations[0].recommendationType).type, }); diff --git a/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts b/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts index 4fc46241b..de35d8d0b 100644 --- a/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts +++ b/apps/red-ui/src/app/modules/file-preview/dialogs/manual-redaction-dialog/manual-annotation-dialog.component.ts @@ -76,10 +76,7 @@ export class ManualAnnotationDialogComponent extends BaseDialogComponent impleme async ngOnInit() { super.ngOnInit(); - this.possibleDictionaries = await this._dictionaryService.getDictionariesOptions( - this._dossier.dossierTemplateId, - this._dossier.dossierId, - ); + this.possibleDictionaries = await this._dictionaryService.getDictionariesOptions(this._dossier.dossierTemplateId, this._dossier.id); const data = await firstValueFrom(this._justificationsService.getForDossierTemplate(this._dossier.dossierTemplateId)); this.legalOptions = data.map(lbm => ({ legalBasis: lbm.reason, diff --git a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts index faa35213f..bd202f432 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/annotation-actions.service.ts @@ -427,7 +427,7 @@ export class AnnotationActionsService { value: text, }; - this._processObsAndEmit(this._manualRedactionService.resizeOrSuggestResize([resizeRequest], data.dossier.dossierId, fileId)); + this._processObsAndEmit(this._manualRedactionService.resizeOrSuggestResize([resizeRequest], data.dossier.id, fileId)); }); } diff --git a/apps/red-ui/src/app/modules/search/search-screen/search-screen.component.ts b/apps/red-ui/src/app/modules/search/search-screen/search-screen.component.ts index eed89ea85..6276490ab 100644 --- a/apps/red-ui/src/app/modules/search/search-screen/search-screen.component.ts +++ b/apps/red-ui/src/app/modules/search/search-screen/search-screen.component.ts @@ -20,10 +20,9 @@ import { RouterHistoryService } from '@services/router-history.service'; import { Dossier, IMatchedDocument, ISearchListItem, ISearchResponse } from '@red/domain'; import { FilesMapService } from '@services/entity-services/files-map.service'; import { PlatformSearchService } from '@services/entity-services/platform-search.service'; -import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; -import { ArchivedDossiersService } from '@services/dossiers/archived-dossiers.service'; import { FeaturesService } from '@services/features.service'; import { DOSSIERS_ARCHIVE } from '@utils/constants'; +import { DossiersCacheService } from '../../../services/dossiers/dossiers-cache.service'; @Component({ templateUrl: './search-screen.component.html', @@ -66,8 +65,7 @@ export class SearchScreenComponent extends ListingComponent imp protected readonly _injector: Injector, private readonly _activatedRoute: ActivatedRoute, private readonly _loadingService: LoadingService, - private readonly _activeDossiersService: ActiveDossiersService, - private readonly _archivedDossiersService: ArchivedDossiersService, + private readonly _dossiersCacheService: DossiersCacheService, readonly routerHistoryService: RouterHistoryService, private readonly _translateService: TranslateService, private readonly _filesMapService: FilesMapService, @@ -83,13 +81,12 @@ export class SearchScreenComponent extends ListingComponent imp const checked = dossierIds.includes(id); return new NestedFilter({ id, label: dossierName, checked }); }; - const allDossiers = [...this._activeDossiersService.all, ...this._archivedDossiersService.all]; const dossierNameFilter: IFilterGroup = { slug: 'dossiers', label: this._translateService.instant('search-screen.filters.by-dossier'), filterceptionPlaceholder: this._translateService.instant('search-screen.filters.search-placeholder'), icon: 'red:folder', - filters: allDossiers.map(dossierToFilter), + filters: this._dossiersCacheService.all.map(dossierToFilter), checker: keyChecker('dossierId'), }; this.filterService.addFilterGroups([dossierNameFilter]); @@ -166,10 +163,11 @@ export class SearchScreenComponent extends ListingComponent imp }: IMatchedDocument): ISearchListItem { const file = this._filesMapService.get(dossierId, fileId); if (!file) { + console.error('Missing file'); return undefined; } - const dossier = (dossierArchived ? this._archivedDossiersService : this._activeDossiersService).find(dossierId); + const dossier = this._dossiersCacheService.get(dossierId); return { id: fileId, diff --git a/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts b/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts index 935b36fb6..004482d7f 100644 --- a/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/dictionary-manager/dictionary-manager.component.ts @@ -82,7 +82,7 @@ export class DictionaryManagerComponent implements OnChanges { return; } - this._onDossierChanged(dossier.dossierTemplateId, dossier.dossierId) + this._onDossierChanged(dossier.dossierTemplateId, dossier.id) .pipe(take(1)) .subscribe(entries => { this.diffEditorText = entries; diff --git a/apps/red-ui/src/app/services/dossiers/active-dossiers.service.ts b/apps/red-ui/src/app/services/dossiers/active-dossiers.service.ts index 54a4f8d01..817d9e97f 100644 --- a/apps/red-ui/src/app/services/dossiers/active-dossiers.service.ts +++ b/apps/red-ui/src/app/services/dossiers/active-dossiers.service.ts @@ -1,16 +1,25 @@ import { Injectable, Injector } from '@angular/core'; -import { switchMap, tap } from 'rxjs/operators'; -import { timer } from 'rxjs'; import { CHANGED_CHECK_INTERVAL, DOSSIERS_ROUTE } from '@utils/constants'; import { DossiersService } from './dossiers.service'; +import { Observable, timer } from 'rxjs'; +import { switchMap, tap } from 'rxjs/operators'; +import { Dossier } from '@red/domain'; @Injectable({ providedIn: 'root', }) export class ActiveDossiersService extends DossiersService { + private _initializedRefresh = false; + constructor(protected readonly _injector: Injector) { super(_injector, 'dossier', DOSSIERS_ROUTE); + } + initializeRefresh() { + if (this._initializedRefresh) { + return; + } + this._initializedRefresh = true; timer(CHANGED_CHECK_INTERVAL, CHANGED_CHECK_INTERVAL) .pipe( switchMap(() => this.loadOnlyChanged()), @@ -18,4 +27,9 @@ export class ActiveDossiersService extends DossiersService { ) .subscribe(); } + + loadAll(): Observable { + this.initializeRefresh(); + return super.loadAll(); + } } diff --git a/apps/red-ui/src/app/services/dossiers/dossiers-cache.service.ts b/apps/red-ui/src/app/services/dossiers/dossiers-cache.service.ts index 72b955c21..76570444b 100644 --- a/apps/red-ui/src/app/services/dossiers/dossiers-cache.service.ts +++ b/apps/red-ui/src/app/services/dossiers/dossiers-cache.service.ts @@ -3,7 +3,6 @@ import { ActiveDossiersService } from './active-dossiers.service'; import { ArchivedDossiersService } from './archived-dossiers.service'; import { firstValueFrom, forkJoin, merge } from 'rxjs'; import { map, skip, take } from 'rxjs/operators'; -import { flatten } from 'lodash-es'; import { Dossier } from '@red/domain'; @Injectable({ @@ -27,23 +26,27 @@ export class DossiersCacheService { return !localStorage.getItem('dossiers'); } + get all(): Dossier[] { + return this._dossiers; + } + async load(): Promise { await firstValueFrom( forkJoin([this._activeDossiersService.loadAll().pipe(take(1)), this._archivedDossiersService.loadAll().pipe(take(1))]).pipe( - map(list => flatten(list)), + map(list => list.flat()), ), ); this.set(); } set(): void { - const dossiers = flatten([this._activeDossiersService.all, this._archivedDossiersService.all]); + const dossiers = [this._activeDossiersService.all, this._archivedDossiersService.all].flat(); this._dossiers = dossiers; localStorage.setItem('dossiers', JSON.stringify(dossiers)); this.changed$.emit(); } get(dossierId: string) { - return this._dossiers.find(dossier => dossier.dossierId === dossierId); + return this._dossiers.find(dossier => dossier.id === dossierId); } } diff --git a/apps/red-ui/src/app/services/entity-services/platform-search.service.ts b/apps/red-ui/src/app/services/entity-services/platform-search.service.ts index a0d03df4f..671a4fdd1 100644 --- a/apps/red-ui/src/app/services/entity-services/platform-search.service.ts +++ b/apps/red-ui/src/app/services/entity-services/platform-search.service.ts @@ -2,20 +2,17 @@ import { Injectable, Injector } from '@angular/core'; import { GenericService } from '@iqser/common-ui'; import { Dossier, IMatchedDocument, ISearchInput, ISearchRequest, ISearchResponse } from '@red/domain'; import { Observable, of, zip } from 'rxjs'; -import { mapTo, switchMap } from 'rxjs/operators'; -import { ActiveDossiersService } from '../dossiers/active-dossiers.service'; +import { map, switchMap } from 'rxjs/operators'; import { FilesMapService } from './files-map.service'; import { FilesService } from './files.service'; -import { ArchivedDossiersService } from '../dossiers/archived-dossiers.service'; -import { DossiersService } from '../dossiers/dossiers.service'; +import { DossiersCacheService } from '../dossiers/dossiers-cache.service'; @Injectable({ providedIn: 'root' }) export class PlatformSearchService extends GenericService { constructor( protected readonly _injector: Injector, private readonly _filesService: FilesService, - private readonly _activeDossiersService: ActiveDossiersService, - private readonly _archivedDossiersService: ArchivedDossiersService, + private readonly _dossiersCacheService: DossiersCacheService, private readonly _filesMapService: FilesMapService, ) { super(_injector, 'search-v2'); @@ -42,17 +39,16 @@ export class PlatformSearchService extends GenericService { return this._post(body).pipe(switchMap(searchValue => this._loadMissingFiles$(searchValue))); } - private _dossiersWithMissingFiles(searchResponse: ISearchResponse, service: DossiersService): Dossier[] { - const documentsOfType = searchResponse.matchedDocuments.filter(document => service.has(document.dossierId)); + private _dossiersWithMissingFiles(searchResponse: ISearchResponse): Dossier[] { + const documentsOfType = searchResponse.matchedDocuments.filter(document => this._dossiersCacheService.get(document.dossierId)); const fileNotLoaded = ({ dossierId, fileId }: IMatchedDocument) => !this._filesMapService.get(dossierId, fileId); const dossiersWithNotLoadedFiles = documentsOfType.filter(fileNotLoaded).map(document => document.dossierId); - return Array.from(new Set(dossiersWithNotLoadedFiles)).map(dossierId => service.find(dossierId)); + return Array.from(new Set(dossiersWithNotLoadedFiles)).map(dossierId => this._dossiersCacheService.get(dossierId)); } private _loadMissingFiles$(searchResponse: ISearchResponse): Observable { - const services = [this._activeDossiersService, this._archivedDossiersService]; - const dossiers = services.map(service => this._dossiersWithMissingFiles(searchResponse, service)).flat(); - return dossiers.length ? this._loadFilesFor$(dossiers).pipe(mapTo(searchResponse)) : of(searchResponse); + const dossiers = this._dossiersWithMissingFiles(searchResponse); + return dossiers.length ? this._loadFilesFor$(dossiers).pipe(map(() => searchResponse)) : of(searchResponse); } private _loadFilesFor$(dossiers: Dossier[]) { diff --git a/apps/red-ui/src/app/services/entity-services/trash.service.ts b/apps/red-ui/src/app/services/entity-services/trash.service.ts index e0cf923fb..506a44315 100644 --- a/apps/red-ui/src/app/services/entity-services/trash.service.ts +++ b/apps/red-ui/src/app/services/entity-services/trash.service.ts @@ -34,7 +34,7 @@ export class TrashService extends GenericService { this._toaster.error(_('dossier-listing.delete.delete-failed'), { params: dossier }); return of({}); }; - return this.delete(dossier.dossierId, 'dossier').pipe( + return this.delete(dossier.id, 'dossier').pipe( switchMap(() => this._activeDossiersService.loadAll()), catchError(showToast), ); diff --git a/apps/red-ui/src/app/services/permissions.service.ts b/apps/red-ui/src/app/services/permissions.service.ts index e7c0fca74..33210687e 100644 --- a/apps/red-ui/src/app/services/permissions.service.ts +++ b/apps/red-ui/src/app/services/permissions.service.ts @@ -33,7 +33,7 @@ export class PermissionsService { } displayReanalyseBtn(dossier: Dossier): boolean { - return this.isApprover(dossier) && !!this._filesMapService.get(dossier.dossierId).find(f => f.analysisRequired); + return this.isApprover(dossier) && !!this._filesMapService.get(dossier.id).find(f => f.analysisRequired); } canUploadFiles(dossier: Dossier): boolean { diff --git a/libs/common-ui b/libs/common-ui index dc9323a0e..224e078b5 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit dc9323a0ec4d2cdc8ffbb31df67995531160462c +Subproject commit 224e078b583a33c1e4a621c071d0a24d2d49d4c6 diff --git a/libs/red-domain/src/lib/dossiers/dossier.model.ts b/libs/red-domain/src/lib/dossiers/dossier.model.ts index b356a4a03..d84139928 100644 --- a/libs/red-domain/src/lib/dossiers/dossier.model.ts +++ b/libs/red-domain/src/lib/dossiers/dossier.model.ts @@ -25,6 +25,7 @@ export class Dossier implements IDossier, IListable { readonly hasReviewers: boolean; readonly routerLink: string; readonly dossiersListRouterLink: string; + readonly id: string; constructor(dossier: IDossier) { this.dossierId = dossier.dossierId; @@ -47,15 +48,12 @@ export class Dossier implements IDossier, IListable { this.archivedTime = dossier.archivedTime; this.hasReviewers = !!this.memberIds && this.memberIds.length > 1; + this.id = this.dossierId; const routerPath = (this.isArchived ? ARCHIVE_ROUTE : DOSSIERS_ROUTE) as string; this.dossiersListRouterLink = `/main/${this.dossierTemplateId}/${routerPath}`; this.routerLink = `${this.dossiersListRouterLink}/${this.dossierId}`; } - get id(): string { - return this.dossierId; - } - get searchKey(): string { return this.dossierName; } diff --git a/libs/red-domain/src/lib/trash/trash-dossier.model.ts b/libs/red-domain/src/lib/trash/trash-dossier.model.ts index fc0d78981..db1b61104 100644 --- a/libs/red-domain/src/lib/trash/trash-dossier.model.ts +++ b/libs/red-domain/src/lib/trash/trash-dossier.model.ts @@ -16,6 +16,7 @@ export class TrashDossier extends TrashItem { readonly dueDate?: string; readonly ownerId: string; readonly softDeletedTime: string; + readonly id: string; constructor( dossier: IDossier, @@ -35,10 +36,8 @@ export class TrashDossier extends TrashItem { // Because of migrations, for some this is not set this.softDeletedTime = dossier.softDeletedTime || '-'; this.canRestore = this.canRestore && this._hasRestoreRights; - } - get id(): string { - return this.dossierId; + this.id = this.dossierId; } get searchKey(): string { From 81311dbdb4206798252c761ce8eaa541f6abef22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Fri, 6 May 2022 19:14:19 +0300 Subject: [PATCH 10/12] RED-3796: Fixed provider, filter dossiers, initialize add dossier --- .../archived-dossiers-screen.component.ts | 29 ++++++++++++++----- .../add-dossier-dialog.component.ts | 8 +++-- .../edit-dossier-dialog.component.ts | 7 ++--- .../dossiers-listing/config.service.ts | 8 ++--- .../dossiers-listing-screen.component.ts | 21 ++++++++------ .../services/file-preview-state.service.ts | 5 ++-- .../src/app/services/breadcrumbs.service.ts | 2 +- .../dossiers.service.provider.ts | 8 ++--- 8 files changed, 54 insertions(+), 34 deletions(-) diff --git a/apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.ts b/apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.ts index 2efab9ccc..f535c5b58 100644 --- a/apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.ts +++ b/apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.ts @@ -1,32 +1,45 @@ import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit } from '@angular/core'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { DefaultListingServicesTmp, EntitiesService, ListingComponent } from '@iqser/common-ui'; -import { ArchivedDossiersService } from '@services/dossiers/archived-dossiers.service'; +import { DefaultListingServices, ListingComponent } from '@iqser/common-ui'; import { Dossier } from '@red/domain'; import { ConfigService } from '../../services/config.service'; import { tap } from 'rxjs/operators'; +import { ArchivedDossiersService } from '@services/dossiers/archived-dossiers.service'; +import { DOSSIER_TEMPLATE_ID } from '@utils/constants'; +import { Router } from '@angular/router'; @Component({ selector: 'redaction-archived-dossiers-screen', templateUrl: './archived-dossiers-screen.component.html', styleUrls: ['./archived-dossiers-screen.component.scss'], - providers: [ - ...DefaultListingServicesTmp, - { provide: EntitiesService, useExisting: ArchivedDossiersService }, - { provide: ListingComponent, useExisting: forwardRef(() => ArchivedDossiersScreenComponent) }, - ], + providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => ArchivedDossiersScreenComponent) }], changeDetection: ChangeDetectionStrategy.OnPush, }) export class ArchivedDossiersScreenComponent extends ListingComponent implements OnInit { readonly tableColumnConfigs = this._configService.tableConfig; readonly tableHeaderLabel = _('archived-dossiers-listing.table-header.title'); + private readonly _dossierTemplateId: string; - constructor(protected readonly _injector: Injector, private readonly _configService: ConfigService) { + constructor( + protected readonly _injector: Injector, + private readonly _configService: ConfigService, + private readonly _archivedDossiersService: ArchivedDossiersService, + private readonly _router: Router, + ) { super(_injector); + this._dossierTemplateId = this._router.routerState.snapshot.root.firstChild.firstChild.paramMap.get(DOSSIER_TEMPLATE_ID); + this._router.routeReuseStrategy.shouldReuseRoute = () => false; + console.log(this._dossierTemplateId); } ngOnInit(): void { this.addSubscription = this.entitiesService.all$.pipe(tap(() => this._computeAllFilters())).subscribe(); + this.addSubscription = this._archivedDossiersService.all$ + .pipe( + tap(dossiers => console.log(dossiers.map(d => d.dossierTemplateId))), + tap(dossiers => this.entitiesService.setEntities(dossiers.filter(d => d.dossierTemplateId === this._dossierTemplateId))), + ) + .subscribe(); } private _computeAllFilters() { diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts index b6be00297..c8d84feeb 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/add-dossier-dialog/add-dossier-dialog.component.ts @@ -1,4 +1,4 @@ -import { Component, Inject, Injector } from '@angular/core'; +import { Component, Inject, Injector, OnInit } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { DownloadFileType, IDossierRequest, IDossierTemplate, IReportTemplate } from '@red/domain'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; @@ -21,7 +21,7 @@ interface DialogData { templateUrl: './add-dossier-dialog.component.html', styleUrls: ['./add-dossier-dialog.component.scss'], }) -export class AddDossierDialogComponent extends BaseDialogComponent { +export class AddDossierDialogComponent extends BaseDialogComponent implements OnInit { readonly iconButtonTypes = IconButtonTypes; hasDueDate = false; @@ -68,6 +68,10 @@ export class AddDossierDialogComponent extends BaseDialogComponent { return this.form.invalid; } + async ngOnInit(): Promise { + await this.dossierTemplateChanged(this.form.get('dossierTemplateId').value); + } + reportTemplateValueMapper = (reportTemplate: IReportTemplate) => reportTemplate.templateId; async save(options?: SaveOptions) { diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.ts index a723bc52d..ed5407b64 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/edit-dossier-dialog.component.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, ChangeDetectorRef, Component, Inject, Injector, ViewChild } from '@angular/core'; +import { AfterViewInit, Component, Inject, Injector, ViewChild } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Dossier } from '@red/domain'; import { EditDossierGeneralInfoComponent } from './general-info/edit-dossier-general-info.component'; @@ -48,8 +48,7 @@ export class EditDossierDialogComponent extends BaseDialogComponent implements A constructor( private readonly _toaster: Toaster, - private readonly _activeDossiersService: DossiersService, - private readonly _changeRef: ChangeDetectorRef, + private readonly _dossiersService: DossiersService, private readonly _loadingService: LoadingService, private readonly _permissionsService: PermissionsService, private readonly _userService: UserService, @@ -62,7 +61,7 @@ export class EditDossierDialogComponent extends BaseDialogComponent implements A }, ) { super(_injector, _dialogRef, true); - this.dossier$ = this._activeDossiersService.getEntityChanged$(_data.dossierId).pipe( + this.dossier$ = this._dossiersService.getEntityChanged$(_data.dossierId).pipe( tap(dossier => { this._dossier = dossier; this._initializeNavItems(); diff --git a/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts b/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts index 2f19f3467..f57e33fe0 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/config.service.ts @@ -38,11 +38,11 @@ export class ConfigService { return this._userService.currentUser; } - get buttonsConfig(): ButtonConfig[] { + buttonsConfig(dossierTemplateId: string): ButtonConfig[] { return [ { label: _('dossier-listing.add-new'), - action: () => this._openAddDossierDialog(), + action: () => this._openAddDossierDialog(dossierTemplateId), hide: !this._currentUser.isManager, icon: 'iqser:plus', type: 'primary', @@ -189,8 +189,8 @@ export class ConfigService { private _otherChecker = (dw: Dossier) => !dw.memberIds.includes(this._currentUser.id); - private _openAddDossierDialog(): void { - this._dialogService.openDialog('addDossier', null, null); + private _openAddDossierDialog(dossierTemplateId: string): void { + this._dialogService.openDialog('addDossier', null, { dossierTemplateId }); } private _quickFilters(entities: Dossier[]): NestedFilter[] { diff --git a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts index 0b7b59ea3..fe52199c6 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts @@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit, Templ import { Dossier } from '@red/domain'; import { UserService } from '@services/user.service'; import { PermissionsService } from '@services/permissions.service'; -import { DefaultListingServicesTmp, EntitiesService, ListingComponent, OnAttach, TableComponent } from '@iqser/common-ui'; +import { ButtonConfig, DefaultListingServices, ListingComponent, OnAttach, TableComponent } from '@iqser/common-ui'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { ConfigService } from '../config.service'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; @@ -10,28 +10,26 @@ import { DossierTemplatesService } from '@services/dossier-templates/dossier-tem import { tap } from 'rxjs/operators'; import { DossiersDialogService } from '../../dossier/shared/services/dossiers-dialog.service'; import { Router } from '@angular/router'; +import { DOSSIER_TEMPLATE_ID } from '@utils/constants'; @Component({ templateUrl: './dossiers-listing-screen.component.html', styleUrls: ['./dossiers-listing-screen.component.scss'], - providers: [ - ...DefaultListingServicesTmp, - { provide: EntitiesService, useExisting: ActiveDossiersService }, - { provide: ListingComponent, useExisting: forwardRef(() => DossiersListingScreenComponent) }, - ], + providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DossiersListingScreenComponent) }], changeDetection: ChangeDetectionStrategy.OnPush, }) export class DossiersListingScreenComponent extends ListingComponent implements OnInit, OnAttach { readonly currentUser = this._userService.currentUser; readonly tableColumnConfigs = this._configService.tableConfig; readonly tableHeaderLabel = _('dossier-listing.table-header.title'); - readonly buttonConfigs = this._configService.buttonsConfig; + readonly buttonConfigs: ButtonConfig[]; @ViewChild('needsWorkFilterTemplate', { read: TemplateRef, static: true, }) private readonly _needsWorkFilterTemplate: TemplateRef; @ViewChild(TableComponent) private readonly _tableComponent: TableComponent; + private readonly _dossierTemplateId: string; constructor( protected readonly _injector: Injector, @@ -44,7 +42,9 @@ export class DossiersListingScreenComponent extends ListingComponent im private readonly _router: Router, ) { super(_injector); + this._dossierTemplateId = this._router.routerState.snapshot.root.firstChild.firstChild.paramMap.get(DOSSIER_TEMPLATE_ID); this._router.routeReuseStrategy.shouldReuseRoute = () => false; + this.buttonConfigs = this._configService.buttonsConfig(this._dossierTemplateId); } get defaultDossierTemplateId(): string { @@ -52,11 +52,14 @@ export class DossiersListingScreenComponent extends ListingComponent im } openAddDossierDialog(): void { - this._dialogService.openDialog('addDossier', null, null); + this._dialogService.openDialog('addDossier', null, { dossierTemplateId: this._dossierTemplateId }); } ngOnInit(): void { - this.addSubscription = this._activeDossiersService.all$.pipe(tap(() => this._computeAllFilters())).subscribe(); + this.addSubscription = this.entitiesService.all$.pipe(tap(() => this._computeAllFilters())).subscribe(); + this.addSubscription = this._activeDossiersService.all$ + .pipe(tap(dossiers => this.entitiesService.setEntities(dossiers.filter(d => d.dossierTemplateId === this._dossierTemplateId)))) + .subscribe(); } ngOnAttach(): void { diff --git a/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts b/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts index ddf8ac2e2..5ce48cb69 100644 --- a/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts +++ b/apps/red-ui/src/app/modules/file-preview/services/file-preview-state.service.ts @@ -1,7 +1,7 @@ import { Injectable, Injector } from '@angular/core'; import { combineLatest, firstValueFrom, from, merge, Observable, of, pairwise, Subject, switchMap } from 'rxjs'; import { Dossier, File } from '@red/domain'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { FilesMapService } from '@services/entity-services/files-map.service'; import { PermissionsService } from '@services/permissions.service'; import { boolFactory } from '@iqser/common-ui'; @@ -39,8 +39,9 @@ export class FilePreviewStateService { private readonly _filesService: FilesService, private readonly _dossiersService: DossiersService, private readonly _fileManagementService: FileManagementService, + private readonly _router: Router, ) { - const dossiersService = dossiersServiceResolver(_injector); + const dossiersService = dossiersServiceResolver(_injector, _router); this.fileId = route.snapshot.paramMap.get(FILE_ID); this.dossierId = route.snapshot.paramMap.get(DOSSIER_ID); diff --git a/apps/red-ui/src/app/services/breadcrumbs.service.ts b/apps/red-ui/src/app/services/breadcrumbs.service.ts index ce911d9a0..fb0c23760 100644 --- a/apps/red-ui/src/app/services/breadcrumbs.service.ts +++ b/apps/red-ui/src/app/services/breadcrumbs.service.ts @@ -58,7 +58,7 @@ export class BreadcrumbsService { } private get _dossiersService(): DossiersService { - return dossiersServiceResolver(this._injector, this._router.routerState.root); + return dossiersServiceResolver(this._injector, this._router); } private get _dashboardBreadcrumb(): Breadcrumb { diff --git a/apps/red-ui/src/app/services/entity-services/dossiers.service.provider.ts b/apps/red-ui/src/app/services/entity-services/dossiers.service.provider.ts index bd30faa3f..ddc69712a 100644 --- a/apps/red-ui/src/app/services/entity-services/dossiers.service.provider.ts +++ b/apps/red-ui/src/app/services/entity-services/dossiers.service.provider.ts @@ -1,11 +1,11 @@ -import { ActivatedRoute } from '@angular/router'; +import { Router } from '@angular/router'; import { Injector, ProviderToken } from '@angular/core'; import { DossiersService } from '../dossiers/dossiers.service'; /** Usage in components or services is only allowed in guards or in constructors. * Otherwise, it causes errors on navigation to other screens if the component is reused. */ -export const dossiersServiceResolver = (injector: Injector, _route?: ActivatedRoute) => { - let route: ActivatedRoute = _route || injector.get(ActivatedRoute); +export const dossiersServiceResolver = (injector: Injector, router: Router) => { + let route = router.routerState.root; while (route.firstChild) { route = route.firstChild; } @@ -16,5 +16,5 @@ export const dossiersServiceResolver = (injector: Injector, _route?: ActivatedRo export const dossiersServiceProvider = { provide: DossiersService, useFactory: dossiersServiceResolver, - deps: [Injector], + deps: [Injector, Router], }; From 87d101e24a286122fbfddc36c5d37626eb1031d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Tue, 10 May 2022 16:20:53 +0300 Subject: [PATCH 11/12] RED-3796: Redirect to last opened template --- apps/red-ui/src/app/app-routing.module.ts | 4 +- apps/red-ui/src/app/app.module.ts | 1 + .../red-ui/src/app/modules/auth/auth.guard.ts | 6 +-- .../dashboard-screen.component.ts | 17 +++++++-- .../dossiers-listing-screen.component.html | 2 +- .../dossiers-listing-screen.component.ts | 21 +++++----- .../app/services/user-preference.service.ts | 38 ++++++++++--------- .../app/utils/configuration.initializer.ts | 12 ++++++ apps/red-ui/src/assets/config/config.json | 4 +- 9 files changed, 64 insertions(+), 41 deletions(-) diff --git a/apps/red-ui/src/app/app-routing.module.ts b/apps/red-ui/src/app/app-routing.module.ts index a9c7fc151..7f0060461 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -17,7 +17,7 @@ import { DashboardGuard } from '@guards/dashboard-guard.service'; const routes: Routes = [ { path: '', - redirectTo: 'main/dashboard', + redirectTo: 'main', pathMatch: 'full', }, { @@ -106,7 +106,7 @@ const routes: Routes = [ }, { path: '**', - redirectTo: 'main/dashboard', + redirectTo: 'main', pathMatch: 'full', }, ]; diff --git a/apps/red-ui/src/app/app.module.ts b/apps/red-ui/src/app/app.module.ts index 90bd1aba0..07c42e3e1 100644 --- a/apps/red-ui/src/app/app.module.ts +++ b/apps/red-ui/src/app/app.module.ts @@ -163,6 +163,7 @@ const components = [AppComponent, AuthErrorComponent, NotificationsComponent, Sp multi: true, useFactory: configurationInitializer, deps: [ + BASE_HREF, KeycloakService, Title, ConfigService, diff --git a/apps/red-ui/src/app/modules/auth/auth.guard.ts b/apps/red-ui/src/app/modules/auth/auth.guard.ts index 12803b3b0..6701e12cc 100644 --- a/apps/red-ui/src/app/modules/auth/auth.guard.ts +++ b/apps/red-ui/src/app/modules/auth/auth.guard.ts @@ -1,5 +1,5 @@ import { Inject, Injectable } from '@angular/core'; -import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router'; +import { ActivatedRouteSnapshot, Router } from '@angular/router'; import { KeycloakAuthGuard, KeycloakService } from 'keycloak-angular'; import { UserService } from '@services/user.service'; import { ConfigService } from '@services/config.service'; @@ -19,12 +19,12 @@ export class AuthGuard extends KeycloakAuthGuard { super(_router, _keycloak); } - async isAccessAllowed(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise { + async isAccessAllowed(route: ActivatedRouteSnapshot): Promise { if (!this.authenticated) { const kcIdpHint = route.queryParamMap.get('kc_idp_hint'); await this._keycloak.login({ idpHint: kcIdpHint ?? this._configService.values.OAUTH_IDP_HINT, - redirectUri: window.location.origin + this._baseHref + state.url, + redirectUri: window.location.href, }); return false; } diff --git a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts index e413f5d90..94c2046d1 100644 --- a/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts +++ b/apps/red-ui/src/app/modules/dashboard/dashboard-screen/dashboard-screen.component.ts @@ -1,6 +1,7 @@ -import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { UserService } from '../../../services/user.service'; +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { UserService } from '@services/user.service'; import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service'; +import { UserPreferenceService } from '@services/user-preference.service'; @Component({ selector: 'redaction-dashboard-screen', @@ -8,9 +9,17 @@ import { DashboardStatsService } from '@services/dossier-templates/dashboard-sta styleUrls: ['./dashboard-screen.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class DashboardScreenComponent { +export class DashboardScreenComponent implements OnInit { readonly currentUser = this._userService.currentUser; readonly stats$ = this._dashboardStatsService.all$; - constructor(private readonly _userService: UserService, private readonly _dashboardStatsService: DashboardStatsService) {} + constructor( + private readonly _userService: UserService, + private readonly _dashboardStatsService: DashboardStatsService, + private readonly _userPreferenceService: UserPreferenceService, + ) {} + + async ngOnInit(): Promise { + await this._userPreferenceService.saveLastDossierTemplate(null); + } } diff --git a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.html b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.html index 9f0d65e65..a1051a9f8 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.html +++ b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.html @@ -29,7 +29,7 @@
- + diff --git a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts index fe52199c6..895ac8c2a 100644 --- a/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/dossiers-listing/screen/dossiers-listing-screen.component.ts @@ -6,11 +6,11 @@ import { ButtonConfig, DefaultListingServices, ListingComponent, OnAttach, Table import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { ConfigService } from '../config.service'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; -import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service'; import { tap } from 'rxjs/operators'; import { DossiersDialogService } from '../../dossier/shared/services/dossiers-dialog.service'; import { Router } from '@angular/router'; import { DOSSIER_TEMPLATE_ID } from '@utils/constants'; +import { UserPreferenceService } from '@services/user-preference.service'; @Component({ templateUrl: './dossiers-listing-screen.component.html', @@ -23,13 +23,13 @@ export class DossiersListingScreenComponent extends ListingComponent im readonly tableColumnConfigs = this._configService.tableConfig; readonly tableHeaderLabel = _('dossier-listing.table-header.title'); readonly buttonConfigs: ButtonConfig[]; + readonly dossierTemplateId: string; @ViewChild('needsWorkFilterTemplate', { read: TemplateRef, static: true, }) private readonly _needsWorkFilterTemplate: TemplateRef; @ViewChild(TableComponent) private readonly _tableComponent: TableComponent; - private readonly _dossierTemplateId: string; constructor( protected readonly _injector: Injector, @@ -37,28 +37,25 @@ export class DossiersListingScreenComponent extends ListingComponent im readonly permissionsService: PermissionsService, private readonly _activeDossiersService: ActiveDossiersService, private readonly _configService: ConfigService, - private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _dialogService: DossiersDialogService, private readonly _router: Router, + private readonly _userPreferenceService: UserPreferenceService, ) { super(_injector); - this._dossierTemplateId = this._router.routerState.snapshot.root.firstChild.firstChild.paramMap.get(DOSSIER_TEMPLATE_ID); + this.dossierTemplateId = this._router.routerState.snapshot.root.firstChild.firstChild.paramMap.get(DOSSIER_TEMPLATE_ID); this._router.routeReuseStrategy.shouldReuseRoute = () => false; - this.buttonConfigs = this._configService.buttonsConfig(this._dossierTemplateId); - } - - get defaultDossierTemplateId(): string { - return this._dossierTemplatesService.all[0].id; + this.buttonConfigs = this._configService.buttonsConfig(this.dossierTemplateId); } openAddDossierDialog(): void { - this._dialogService.openDialog('addDossier', null, { dossierTemplateId: this._dossierTemplateId }); + this._dialogService.openDialog('addDossier', null, { dossierTemplateId: this.dossierTemplateId }); } - ngOnInit(): void { + async ngOnInit(): Promise { + await this._userPreferenceService.saveLastDossierTemplate(this.dossierTemplateId); this.addSubscription = this.entitiesService.all$.pipe(tap(() => this._computeAllFilters())).subscribe(); this.addSubscription = this._activeDossiersService.all$ - .pipe(tap(dossiers => this.entitiesService.setEntities(dossiers.filter(d => d.dossierTemplateId === this._dossierTemplateId)))) + .pipe(tap(dossiers => this.entitiesService.setEntities(dossiers.filter(d => d.dossierTemplateId === this.dossierTemplateId)))) .subscribe(); } diff --git a/apps/red-ui/src/app/services/user-preference.service.ts b/apps/red-ui/src/app/services/user-preference.service.ts index 7ae1d333d..5df934cac 100644 --- a/apps/red-ui/src/app/services/user-preference.service.ts +++ b/apps/red-ui/src/app/services/user-preference.service.ts @@ -8,6 +8,7 @@ const KEYS = { language: 'Language', dossierRecent: 'Dossier-Recent', filePreviewTooltips: 'File-Preview-Tooltips', + lastDossierTemplate: 'Last-Dossier-Template', } as const; @Injectable({ @@ -30,38 +31,36 @@ export class UserPreferenceService extends GenericService { } getLastOpenedFileForDossier(dossierId: string): string { - const key = `${KEYS.dossierRecent}-${dossierId}`; - return this._getAttribute(key); + return this._getAttribute(`${KEYS.dossierRecent}-${dossierId}`); } async saveLastOpenedFileForDossier(dossierId: string, fileId: string): Promise { - const key = `${KEYS.dossierRecent}-${dossierId}`; - this.userAttributes[key] = [fileId]; - await firstValueFrom(this.savePreferences([fileId], key)); + await this._save(`${KEYS.dossierRecent}-${dossierId}`, fileId); + } + + getLastDossierTemplate(): string { + return this._getAttribute(KEYS.lastDossierTemplate); + } + + async saveLastDossierTemplate(dossierTemplateId: string): Promise { + await this._save(KEYS.lastDossierTemplate, dossierTemplateId); } getLanguage(): string { - const key = KEYS.language; - return this._getAttribute(key); + return this._getAttribute(KEYS.language); } async saveLanguage(language: string): Promise { - const key = KEYS.language; - this.userAttributes[key] = [language]; - await firstValueFrom(this.savePreferences([language], key)); + await this._save(KEYS.language, language); } getFilePreviewTooltipsPreference(): boolean { - const key = KEYS.filePreviewTooltips; - return this._getAttribute(key, 'false') === 'true'; + return this._getAttribute(KEYS.filePreviewTooltips, 'false') === 'true'; } async toggleFilePreviewTooltipsPreference(): Promise { - const key = KEYS.filePreviewTooltips; - const currentValue = this.getFilePreviewTooltipsPreference(); - const nextValue = [(!currentValue).toString()]; - this.userAttributes[key] = nextValue; - await firstValueFrom(this.savePreferences(nextValue, key)); + const nextValue = (!this.getFilePreviewTooltipsPreference()).toString(); + await this._save(KEYS.filePreviewTooltips, nextValue); } toggleDevFeatures(): void { @@ -79,6 +78,11 @@ export class UserPreferenceService extends GenericService { return this._put(body, `${this._defaultModelPath}/${key}`); } + private async _save(key: string, value: string): Promise { + this.userAttributes[key] = [value]; + await firstValueFrom(this.savePreferences([value], key)); + } + private _getAttribute(key: string, defaultValue = ''): string { if (this.userAttributes[key]?.length > 0) { return this.userAttributes[key][0]; diff --git a/apps/red-ui/src/app/utils/configuration.initializer.ts b/apps/red-ui/src/app/utils/configuration.initializer.ts index bbd074151..849145c01 100644 --- a/apps/red-ui/src/app/utils/configuration.initializer.ts +++ b/apps/red-ui/src/app/utils/configuration.initializer.ts @@ -9,7 +9,16 @@ import { UserPreferenceService } from '@services/user-preference.service'; import { UserService } from '@services/user.service'; import { FeaturesService } from '@services/features.service'; +function lastDossierTemplateRedirect(baseHref: string, userPreferenceService: UserPreferenceService) { + const url = window.location.href.split('/').filter(s => s.length > 0); + const lastDossierTemplate = userPreferenceService.getLastDossierTemplate(); + if (lastDossierTemplate && [baseHref, 'main'].includes(url[url.length - 1])) { + window.location.href = `/${baseHref}/main/${lastDossierTemplate}`; + } +} + export function configurationInitializer( + baseHref: string, keycloakService: KeycloakService, title: Title, configService: ConfigService, @@ -36,6 +45,9 @@ export function configurationInitializer( title.setTitle('RedactManager'); return of({}); }), + tap(() => { + lastDossierTemplateRedirect(baseHref.replace('/', ''), userPreferenceService); + }), switchMap(() => languageService.chooseAndSetInitialLanguage()), tap(() => userService.initialize()), take(1), diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json index 0cb5f13c3..684210fa7 100644 --- a/apps/red-ui/src/assets/config/config.json +++ b/apps/red-ui/src/assets/config/config.json @@ -1,7 +1,7 @@ { "ADMIN_CONTACT_NAME": null, "ADMIN_CONTACT_URL": null, - "API_URL": "https://dev-04.iqser.cloud/redaction-gateway-v1", + "API_URL": "https://dev-08.iqser.cloud/redaction-gateway-v1", "APP_NAME": "RedactManager", "AUTO_READ_TIME": 3, "BACKEND_APP_VERSION": "4.4.40", @@ -17,7 +17,7 @@ "MAX_RETRIES_ON_SERVER_ERROR": 3, "OAUTH_CLIENT_ID": "redaction", "OAUTH_IDP_HINT": null, - "OAUTH_URL": "https://dev-04.iqser.cloud/auth/realms/redaction", + "OAUTH_URL": "https://dev-08.iqser.cloud/auth/realms/redaction", "RECENT_PERIOD_IN_HOURS": 24, "SELECTION_MODE": "structural", "MANUAL_BASE_URL": "https://docs.redactmanager.com/preview" From a4e0b598e26bcd373d879d28a8f8ad53ab5bdf72 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Tue, 10 May 2022 17:03:18 +0300 Subject: [PATCH 12/12] RED-3796: common-ui --- libs/common-ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/common-ui b/libs/common-ui index 224e078b5..37ab9a6ed 160000 --- a/libs/common-ui +++ b/libs/common-ui @@ -1 +1 @@ -Subproject commit 224e078b583a33c1e4a621c071d0a24d2d49d4c6 +Subproject commit 37ab9a6ed7fb9f0a70a2226f75a86611405f907d