From 84c4a128ef32cd293d2be97ab028fc6142e1908d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Fri, 18 Feb 2022 01:53:08 +0200 Subject: [PATCH 01/20] Archive dossier action --- ...firm-archive-dossier-dialog.component.html | 32 ++++++++++++++ ...firm-archive-dossier-dialog.component.scss | 13 ++++++ ...onfirm-archive-dossier-dialog.component.ts | 43 +++++++++++++++++++ .../edit-dossier-general-info.component.html | 10 ++++- .../edit-dossier-general-info.component.ts | 8 +++- .../app/modules/dossier/dossiers.module.ts | 2 + .../services/dossiers-dialog.service.ts | 5 +++ .../src/app/modules/icons/icons.module.ts | 1 + .../entity-services/dossiers.service.ts | 28 +++++++++--- .../src/app/services/permissions.service.ts | 4 ++ apps/red-ui/src/assets/config/config.json | 4 +- apps/red-ui/src/assets/i18n/en.json | 16 +++++++ .../src/assets/icons/general/archive.svg | 9 ++++ 13 files changed, 166 insertions(+), 9 deletions(-) create mode 100644 apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.html create mode 100644 apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.scss create mode 100644 apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.ts create mode 100644 apps/red-ui/src/assets/icons/general/archive.svg diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.html b/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.html new file mode 100644 index 000000000..a076d6010 --- /dev/null +++ b/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.html @@ -0,0 +1,32 @@ +
+
+ +
+
+ + + +
+ +
+
+
+ + + {{ checkbox.label | translate }} + +
+ +
+ +
+
+ +
diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.scss b/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.scss new file mode 100644 index 000000000..1cbdb4e5b --- /dev/null +++ b/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.scss @@ -0,0 +1,13 @@ +@use 'variables'; + +.dialog-header { + color: variables.$primary; +} + +mat-checkbox { + width: 100%; + + &:not(:last-of-type) { + margin-bottom: 6px; + } +} diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.ts new file mode 100644 index 000000000..ef3a45175 --- /dev/null +++ b/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.ts @@ -0,0 +1,43 @@ +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { LoadingService, Toaster } from '@iqser/common-ui'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { firstValueFrom } from 'rxjs'; +import { Dossier } from '@red/domain'; +import { DossiersService } from '@services/entity-services/dossiers.service'; + +@Component({ + templateUrl: './confirm-archive-dossier-dialog.component.html', + styleUrls: ['./confirm-archive-dossier-dialog.component.scss'], +}) +export class ConfirmArchiveDossierDialogComponent { + readonly checkboxes = [{ value: false, label: _('confirm-archive-dossier.checkbox.documents') }]; + showToast = false; + + constructor( + private readonly _loadingService: LoadingService, + private readonly _dossiersService: DossiersService, + private readonly _toaster: Toaster, + @Inject(MAT_DIALOG_DATA) readonly dossier: Dossier, + readonly dialogRef: MatDialogRef, + ) {} + + get valid() { + return this.checkboxes[0].value; + } + + async archiveDossier() { + if (this.valid) { + this._loadingService.start(); + await firstValueFrom(this._dossiersService.archive([this.dossier])); + this._toaster.success(_('dossier-listing.archive.archive-succeeded'), { params: this.dossier }); + this.dialogRef.close(true); + } else { + this.showToast = true; + } + } + + cancel() { + this.dialogRef.close(); + } +} diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.html b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.html index 4d60d4b0f..dc5f3cd46 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.html +++ b/apps/red-ui/src/app/modules/dossier/dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component.html @@ -55,7 +55,7 @@
- +
@@ -95,5 +95,13 @@ [type]="iconButtonTypes.dark" icon="iqser:trash" > + +
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 622aca251..5f895cdb9 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 @@ -148,6 +148,12 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti }); } + archiveDossier() { + this._dialogService.openDialog('archiveDossier', null, this.dossier, () => { + this._editDossierDialogRef.close(); + }); + } + #getForm(): FormGroup { return this._formBuilder.group({ dossierName: [this.dossier.dossierName, Validators.required], @@ -167,7 +173,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti } #notifyDossierDeleted() { - this._toaster.success(_('edit-dossier-dialog.delete-successful'), { params: { dossierName: this.dossier.dossierName } }); + this._toaster.success(_('edit-dossier-dialog.delete-successful'), { params: this.dossier }); } #filterInvalidDossierTemplates() { diff --git a/apps/red-ui/src/app/modules/dossier/dossiers.module.ts b/apps/red-ui/src/app/modules/dossier/dossiers.module.ts index 9fd58b8cb..2ff709a8a 100644 --- a/apps/red-ui/src/app/modules/dossier/dossiers.module.ts +++ b/apps/red-ui/src/app/modules/dossier/dossiers.module.ts @@ -25,12 +25,14 @@ import { OverlayModule } from '@angular/cdk/overlay'; import { SharedDossiersModule } from './shared/shared-dossiers.module'; import { ResizeAnnotationDialogComponent } from './dialogs/resize-annotation-dialog/resize-annotation-dialog.component'; import { EditDossierTeamComponent } from './dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component'; +import { ConfirmArchiveDossierDialogComponent } from './dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component'; const screens = [SearchScreenComponent]; const dialogs = [ AddDossierDialogComponent, EditDossierDialogComponent, + ConfirmArchiveDossierDialogComponent, ManualAnnotationDialogComponent, ForceAnnotationDialogComponent, RemoveAnnotationsDialogComponent, diff --git a/apps/red-ui/src/app/modules/dossier/services/dossiers-dialog.service.ts b/apps/red-ui/src/app/modules/dossier/services/dossiers-dialog.service.ts index ca5aef32e..2f0f150b4 100644 --- a/apps/red-ui/src/app/modules/dossier/services/dossiers-dialog.service.ts +++ b/apps/red-ui/src/app/modules/dossier/services/dossiers-dialog.service.ts @@ -11,12 +11,14 @@ import { ChangeLegalBasisDialogComponent } from '../dialogs/change-legal-basis-d import { RecategorizeImageDialogComponent } from '../dialogs/recategorize-image-dialog/recategorize-image-dialog.component'; import { ConfirmationDialogComponent, DialogConfig, DialogService, largeDialogConfig } from '@iqser/common-ui'; import { ResizeAnnotationDialogComponent } from '../dialogs/resize-annotation-dialog/resize-annotation-dialog.component'; +import { ConfirmArchiveDossierDialogComponent } from '../dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component'; type DialogType = | 'confirm' | 'documentInfo' | 'editDossier' | 'addDossier' + | 'archiveDossier' | 'assignFile' | 'recategorizeImage' | 'changeLegalBasis' @@ -44,6 +46,9 @@ export class DossiersDialogService extends DialogService { component: AddDossierDialogComponent, dialogConfig: { width: '900px', autoFocus: true }, }, + archiveDossier: { + component: ConfirmArchiveDossierDialogComponent, + }, assignFile: { component: AssignReviewerApproverDialogComponent, dialogConfig: { disableClose: false }, diff --git a/apps/red-ui/src/app/modules/icons/icons.module.ts b/apps/red-ui/src/app/modules/icons/icons.module.ts index 7d808ccd7..06fa9e338 100644 --- a/apps/red-ui/src/app/modules/icons/icons.module.ts +++ b/apps/red-ui/src/app/modules/icons/icons.module.ts @@ -13,6 +13,7 @@ export class IconsModule { const icons = [ 'ai', 'approved', + 'archive', 'arrow-up', 'assign', 'assign-me', diff --git a/apps/red-ui/src/app/services/entity-services/dossiers.service.ts b/apps/red-ui/src/app/services/entity-services/dossiers.service.ts index 0e48fc9c7..669383561 100644 --- a/apps/red-ui/src/app/services/entity-services/dossiers.service.ts +++ b/apps/red-ui/src/app/services/entity-services/dossiers.service.ts @@ -108,19 +108,33 @@ export class DossiersService extends EntitiesService { } delete(dossier: Dossier): Observable { - const updateDossiers = () => { - this.setEntities(this.all.filter(d => d.dossierId !== dossier.dossierId)); - }; const showToast = () => { this._toaster.error(_('dossier-listing.delete.delete-failed'), { params: dossier }); return of({}); }; - return super.delete(dossier.dossierId).pipe(tap(updateDossiers), catchError(showToast)); + return super.delete(dossier.dossierId).pipe( + tap(() => this.#removeDossiers([dossier])), + catchError(showToast), + ); + } + + archive(dossiers: Dossier[]): Observable { + const showToast = () => { + this._toaster.error(_('dossier-listing.archive.archive-failed'), { params: dossiers }); + return of({}); + }; + return this._post( + dossiers.map(d => d.id), + 'archived-dossiers/archive', + ).pipe( + tap(() => this.#removeDossiers(dossiers)), + catchError(showToast), + ); } @Validate() restore(@RequiredParam() dossierIds: List): Promise { - return firstValueFrom(this._post(dossierIds, 'deleted-dossiers/restore')); + return firstValueFrom(this._post(dossierIds, 'deleted-dossiers/restore').pipe(switchMap(() => this.loadAll()))); } @Validate() @@ -133,6 +147,10 @@ export class DossiersService extends EntitiesService { return this.all.filter(dossier => dossier.dossierStatusId === dossierStatusId).length; } + #removeDossiers(dossiers: Dossier[]): void { + this.setEntities(this.all.filter(dossier => !dossiers.find(d => dossier.id === d.id))); + } + private _load(id: string, queryParams?: List): Observable { return super._getOne([id], this._defaultModelPath, queryParams).pipe( map(entity => new Dossier(entity)), diff --git a/apps/red-ui/src/app/services/permissions.service.ts b/apps/red-ui/src/app/services/permissions.service.ts index 361e96385..22912c866 100644 --- a/apps/red-ui/src/app/services/permissions.service.ts +++ b/apps/red-ui/src/app/services/permissions.service.ts @@ -133,6 +133,10 @@ export class PermissionsService { return dossier.ownerId === this._userService.currentUser.id; } + canArchiveDossier(dossier: IDossier): boolean { + return dossier.ownerId === this._userService.currentUser.id; + } + canEditDossier(dossier: Dossier, user = this._userService.currentUser): boolean { return user.isManager && !!dossier?.ownerId; } diff --git a/apps/red-ui/src/assets/config/config.json b/apps/red-ui/src/assets/config/config.json index bf72886ff..4b275311e 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-05.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-05.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" diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 4facffb34..a1b84ce97 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -408,6 +408,17 @@ } }, "configurations": "Configurations", + "confirm-archive-dossier": { + "archive": "Archive Dossier", + "cancel": "Cancel", + "checkbox": { + "documents": "All documents will be archived and cannot be put back to active" + }, + "details": "Restoring an archived dossier is not possible anymore, once it got archived.", + "title": "Archive {dossierName}", + "toast-error": "Please confirm that you understand the ramifications of your action!", + "warning": "Are you sure you want to archive the dossier?" + }, "confirm-delete-dossier-state": { "cancel": "Cancel", "delete": "Delete only", @@ -678,6 +689,11 @@ }, "dossier-listing": { "add-new": "New Dossier", + "archive": { + "action": "Archive Dossier", + "archive-failed": "Failed to archive dossier {dossierName}!", + "archive-succeeded": "Successfully archived dossier {dossierName}." + }, "delete": { "action": "Delete Dossier", "delete-failed": "Failed to delete dossier: {dossierName}" diff --git a/apps/red-ui/src/assets/icons/general/archive.svg b/apps/red-ui/src/assets/icons/general/archive.svg new file mode 100644 index 000000000..0d4414f55 --- /dev/null +++ b/apps/red-ui/src/assets/icons/general/archive.svg @@ -0,0 +1,9 @@ + + + + + + + + From 3d69d421505f7612023283c5fd0642396e9d5f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Sat, 19 Feb 2022 02:40:33 +0200 Subject: [PATCH 02/20] View archived dossiers list, breadcrumbs WIP --- apps/red-ui/src/app/app-routing.module.ts | 11 ++++ .../base-screen/base-screen.component.ts | 6 +- .../breadcrumbs/breadcrumbs.component.html | 26 ++++++-- .../breadcrumbs/breadcrumbs.component.ts | 6 +- .../src/app/guards/archived-dossiers.guard.ts | 14 +++++ .../src/app/guards/dictionary-exists.guard.ts | 2 +- ...dossier-states-listing-screen.component.ts | 10 +-- .../modules/archive/archive-routing.module.ts | 19 ++++++ .../src/app/modules/archive/archive.module.ts | 18 ++++++ .../table-item/table-item.component.html | 13 ++++ .../table-item/table-item.component.scss} | 0 .../table-item/table-item.component.ts | 28 +++++++++ .../archived-dossiers-screen.component.html | 21 +++++++ .../archived-dossiers-screen.component.scss | 0 .../archived-dossiers-screen.component.ts | 26 ++++++++ .../archive/services/config.service.ts | 16 +++++ ...onfirm-archive-dossier-dialog.component.ts | 5 +- .../dossiers-listing-details.component.ts | 2 +- .../dossiers-listing-status.component.html | 13 ---- .../table-item/table-item.component.html | 2 +- .../dossiers-listing/config.service.ts | 2 +- .../dossiers-listing.module.ts | 4 -- .../dossier-status.component.html | 6 ++ .../dossier-status.component.scss} | 0 .../dossier-status.component.ts} | 13 ++-- ...ssiers-listing-dossier-name.component.html | 2 +- ...ssiers-listing-dossier-name.component.scss | 0 ...dossiers-listing-dossier-name.component.ts | 7 +-- .../src/app/modules/shared/shared.module.ts | 4 ++ .../src/app/services/breadcrumbs.service.ts | 62 +++++++++++++++---- .../archived-dossiers.service.ts | 53 ++++++++++++++++ .../entity-services/dossiers.service.ts | 14 ----- apps/red-ui/src/assets/i18n/en.json | 18 ++++++ .../src/lib/dossiers/dossier.model.ts | 2 + libs/red-domain/src/lib/dossiers/dossier.ts | 1 + .../src/lib/shared/breadcrumb-types.ts | 3 +- 36 files changed, 352 insertions(+), 77 deletions(-) create mode 100644 apps/red-ui/src/app/guards/archived-dossiers.guard.ts create mode 100644 apps/red-ui/src/app/modules/archive/archive-routing.module.ts create mode 100644 apps/red-ui/src/app/modules/archive/archive.module.ts create mode 100644 apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.html rename apps/red-ui/src/app/modules/{dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.scss => archive/components/table-item/table-item.component.scss} (100%) create mode 100644 apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.ts create mode 100644 apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.html create mode 100644 apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.scss create mode 100644 apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.ts create mode 100644 apps/red-ui/src/app/modules/archive/services/config.service.ts delete mode 100644 apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-status/dossiers-listing-status.component.html create mode 100644 apps/red-ui/src/app/modules/shared/components/dossier-status/dossier-status.component.html rename apps/red-ui/src/app/modules/{dossier/screens/dossiers-listing/components/dossiers-listing-status/dossiers-listing-status.component.scss => shared/components/dossier-status/dossier-status.component.scss} (100%) rename apps/red-ui/src/app/modules/{dossier/screens/dossiers-listing/components/dossiers-listing-status/dossiers-listing-status.component.ts => shared/components/dossier-status/dossier-status.component.ts} (57%) rename apps/red-ui/src/app/modules/{dossier/screens/dossiers-listing => shared}/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.html (95%) create mode 100644 apps/red-ui/src/app/modules/shared/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.scss rename apps/red-ui/src/app/modules/{dossier/screens/dossiers-listing => shared}/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.ts (79%) create mode 100644 apps/red-ui/src/app/services/entity-services/archived-dossiers.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 45c892ee1..19618afeb 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -8,6 +8,7 @@ import { NgModule } from '@angular/core'; import { DownloadsListScreenComponent } from '@components/downloads-list-screen/downloads-list-screen.component'; import { DossiersGuard } from '@guards/dossiers.guard'; import { DossierTemplatesGuard } from '@guards/dossier-templates.guard'; +import { ArchivedDossiersGuard } from '@guards/archived-dossiers.guard'; const routes: Routes = [ { @@ -40,6 +41,16 @@ const routes: Routes = [ requiredRoles: ['RED_USER', 'RED_MANAGER'], }, }, + { + path: 'main/archive', + component: BaseScreenComponent, + loadChildren: () => import('./modules/archive/archive.module').then(m => m.ArchiveModule), + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, RedRoleGuard, DossierTemplatesGuard, ArchivedDossiersGuard], + requiredRoles: ['RED_USER', 'RED_MANAGER'], + }, + }, { path: 'main/downloads', component: BaseScreenComponent, 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 b7087c041..d16e358c5 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 @@ -19,7 +19,7 @@ interface MenuItem { } const isNavigationStart = event => event instanceof NavigationStart; -const isSearchScreen = url => url.includes('/main/dossiers') && url.includes('/search'); +const isSearchScreen: (url: string) => boolean = url => url.includes('/main/dossiers') && url.includes('/search'); @Component({ templateUrl: './base-screen.component.html', @@ -80,7 +80,7 @@ export class BaseScreenComponent { ) {} private get _hideSearchThisDossier() { - const routerLink = this.breadcrumbsService.breadcrumbs[1]?.routerLink; + const routerLink = this.breadcrumbsService.breadcrumbs[1]?.options?.routerLink; if (!routerLink) { return true; } @@ -99,7 +99,7 @@ export class BaseScreenComponent { } private _searchThisDossier(query: string) { - const routerLink = this.breadcrumbsService.breadcrumbs[1]?.routerLink; + const routerLink = this.breadcrumbsService.breadcrumbs[1]?.options?.routerLink; if (!routerLink) { return this._search(query, []); } diff --git a/apps/red-ui/src/app/components/breadcrumbs/breadcrumbs.component.html b/apps/red-ui/src/app/components/breadcrumbs/breadcrumbs.component.html index 9d0d70f19..4eb851077 100644 --- a/apps/red-ui/src/app/components/breadcrumbs/breadcrumbs.component.html +++ b/apps/red-ui/src/app/components/breadcrumbs/breadcrumbs.component.html @@ -9,16 +9,34 @@ {{ breadcrumb.name$ | async }} + + + + {{ breadcrumb.name$ | async }} + + + + + {{ option.name$ | async }} + + +
diff --git a/apps/red-ui/src/app/components/breadcrumbs/breadcrumbs.component.ts b/apps/red-ui/src/app/components/breadcrumbs/breadcrumbs.component.ts index 9b2256831..bbf75f194 100644 --- a/apps/red-ui/src/app/components/breadcrumbs/breadcrumbs.component.ts +++ b/apps/red-ui/src/app/components/breadcrumbs/breadcrumbs.component.ts @@ -1,5 +1,5 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; -import { BreadcrumbsService } from '@services/breadcrumbs.service'; +import { Breadcrumb, BreadcrumbDisplayType, BreadcrumbsService } from '@services/breadcrumbs.service'; @Component({ selector: 'redaction-breadcrumbs', @@ -9,4 +9,8 @@ import { BreadcrumbsService } from '@services/breadcrumbs.service'; }) export class BreadcrumbsComponent { constructor(readonly breadcrumbsService: BreadcrumbsService) {} + + is(breadcrumb: Breadcrumb, type: BreadcrumbDisplayType): boolean { + return breadcrumb.type === type; + } } diff --git a/apps/red-ui/src/app/guards/archived-dossiers.guard.ts b/apps/red-ui/src/app/guards/archived-dossiers.guard.ts new file mode 100644 index 000000000..dd2577221 --- /dev/null +++ b/apps/red-ui/src/app/guards/archived-dossiers.guard.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { CanActivate } from '@angular/router'; +import { firstValueFrom } from 'rxjs'; +import { ArchivedDossiersService } from '@services/entity-services/archived-dossiers.service'; + +@Injectable({ providedIn: 'root' }) +export class ArchivedDossiersGuard implements CanActivate { + constructor(private readonly _archivedDossiersService: ArchivedDossiersService) {} + + async canActivate(): Promise { + await firstValueFrom(this._archivedDossiersService.loadAll()); + return true; + } +} diff --git a/apps/red-ui/src/app/guards/dictionary-exists.guard.ts b/apps/red-ui/src/app/guards/dictionary-exists.guard.ts index f7d07f8d9..4f7377cba 100644 --- a/apps/red-ui/src/app/guards/dictionary-exists.guard.ts +++ b/apps/red-ui/src/app/guards/dictionary-exists.guard.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router'; import { DICTIONARY_TYPE, DOSSIER_TEMPLATE_ID } from '@utils/constants'; -import { DictionariesMapService } from '../services/entity-services/dictionaries-map.service'; +import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service'; @Injectable({ providedIn: 'root' }) export class DictionaryExistsGuard implements CanActivate { diff --git a/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen.component.ts index dde759d49..483430a56 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dossier-states-listing/dossier-states-listing-screen.component.ts @@ -10,15 +10,15 @@ import { } from '../../../../../../../../libs/common-ui/src'; import { DossierState, IDossierState } from '@red/domain'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { DossiersService } from '../../../../services/entity-services/dossiers.service'; -import { DossierStateService } from '../../../../services/entity-services/dossier-state.service'; +import { DossiersService } from '@services/entity-services/dossiers.service'; +import { DossierStateService } from '@services/entity-services/dossier-state.service'; import { firstValueFrom } from 'rxjs'; import { AdminDialogService } from '../../services/admin-dialog.service'; -import { UserService } from '../../../../services/user.service'; +import { UserService } from '@services/user.service'; import { HttpStatusCode } from '@angular/common/http'; import { DoughnutChartConfig } from '../../../shared/components/simple-doughnut-chart/simple-doughnut-chart.component'; import { ActivatedRoute } from '@angular/router'; -import { DossierTemplatesService } from '../../../../services/entity-services/dossier-templates.service'; +import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; @Component({ templateUrl: './dossier-states-listing-screen.component.html', @@ -32,7 +32,6 @@ import { DossierTemplatesService } from '../../../../services/entity-services/do export class DossierStatesListingScreenComponent extends ListingComponent implements OnInit, OnDestroy { readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; - readonly #dossierTemplateId: string; readonly currentUser = this._userService.currentUser; readonly tableHeaderLabel = _('dossier-states-listing.table-header.title'); readonly tableColumnConfigs: TableColumnConfig[] = [ @@ -40,6 +39,7 @@ export class DossierStatesListingScreenComponent extends ListingComponent + +
+ +
{{ dossier.archivedTime | date: 'd MMM. yyyy' }}
+ +
+ +
+ +
+ +
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.scss b/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.scss similarity index 100% rename from apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.scss rename to apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.scss 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 new file mode 100644 index 000000000..96639f6dd --- /dev/null +++ b/apps/red-ui/src/app/modules/archive/components/table-item/table-item.component.ts @@ -0,0 +1,28 @@ +import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; +import { Dossier, DossierStats } from '@red/domain'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { DossierStatsService } from '@services/entity-services/dossier-stats.service'; +import { switchMap } from 'rxjs/operators'; + +@Component({ + selector: 'redaction-table-item [dossier]', + templateUrl: './table-item.component.html', + styleUrls: ['./table-item.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class TableItemComponent implements OnChanges { + @Input() dossier!: Dossier; + + readonly stats$: Observable; + readonly #ngOnChanges$ = new BehaviorSubject(undefined); + + constructor(readonly dossierStatsService: DossierStatsService) { + this.stats$ = this.#ngOnChanges$.pipe(switchMap(dossierId => this.dossierStatsService.watch$(dossierId))); + } + + ngOnChanges() { + if (this.dossier) { + this.#ngOnChanges$.next(this.dossier.dossierId); + } + } +} 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 new file mode 100644 index 000000000..5786e6f44 --- /dev/null +++ b/apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.html @@ -0,0 +1,21 @@ +
+ + +
+ +
+
+ +
+
+
+ + + + diff --git a/apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.scss b/apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.scss new file mode 100644 index 000000000..e69de29bb 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 new file mode 100644 index 000000000..011f62a2d --- /dev/null +++ b/apps/red-ui/src/app/modules/archive/screens/archived-dossiers-screen/archived-dossiers-screen.component.ts @@ -0,0 +1,26 @@ +import { ChangeDetectionStrategy, Component, forwardRef, Injector } from '@angular/core'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { ConfigService } from '../../services/config.service'; +import { DefaultListingServicesTmp, EntitiesService, ListingComponent } from '@iqser/common-ui'; +import { ArchivedDossiersService } from '@services/entity-services/archived-dossiers.service'; +import { Dossier } from '@red/domain'; + +@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) }, + ], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ArchivedDossiersScreenComponent extends ListingComponent { + readonly tableColumnConfigs = this._configService.tableConfig; + readonly tableHeaderLabel = _('archived-dossiers-listing.table-header.title'); + + constructor(protected readonly _injector: Injector, private readonly _configService: ConfigService) { + super(_injector); + } +} 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 new file mode 100644 index 000000000..49c876ccb --- /dev/null +++ b/apps/red-ui/src/app/modules/archive/services/config.service.ts @@ -0,0 +1,16 @@ +import { Injectable } from '@angular/core'; +import { TableColumnConfig } from '@iqser/common-ui'; +import { Dossier } from '@red/domain'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; + +@Injectable() +export class ConfigService { + get tableConfig(): TableColumnConfig[] { + return [ + { label: _('archived-dossiers-listing.table-col-names.name'), sortByKey: 'searchKey', width: '2fr' }, + { label: _('archived-dossiers-listing.table-col-names.last-modified'), sortByKey: 'archivedTime' }, + { label: _('archived-dossiers-listing.table-col-names.owner'), class: 'user-column' }, + { label: _('archived-dossiers-listing.table-col-names.dossier-status'), class: 'flex-end', width: '2fr' }, + ]; + } +} diff --git a/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.ts b/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.ts index ef3a45175..662e261b1 100644 --- a/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.ts +++ b/apps/red-ui/src/app/modules/dossier/dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component.ts @@ -5,6 +5,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { firstValueFrom } from 'rxjs'; import { Dossier } from '@red/domain'; import { DossiersService } from '@services/entity-services/dossiers.service'; +import { ArchivedDossiersService } from '@services/entity-services/archived-dossiers.service'; @Component({ templateUrl: './confirm-archive-dossier-dialog.component.html', @@ -17,6 +18,7 @@ export class ConfirmArchiveDossierDialogComponent { constructor( private readonly _loadingService: LoadingService, private readonly _dossiersService: DossiersService, + private readonly _archivedDossiersService: ArchivedDossiersService, private readonly _toaster: Toaster, @Inject(MAT_DIALOG_DATA) readonly dossier: Dossier, readonly dialogRef: MatDialogRef, @@ -29,9 +31,10 @@ export class ConfirmArchiveDossierDialogComponent { async archiveDossier() { if (this.valid) { this._loadingService.start(); - await firstValueFrom(this._dossiersService.archive([this.dossier])); + await firstValueFrom(this._archivedDossiersService.archive([this.dossier])); this._toaster.success(_('dossier-listing.archive.archive-succeeded'), { params: this.dossier }); this.dialogRef.close(true); + this._loadingService.stop(); } else { this.showToast = true; } diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts index 49106327e..8a2997f48 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-details/dossiers-listing-details.component.ts @@ -8,7 +8,7 @@ import { workflowFileStatusTranslations } from '../../../../translations/file-st import { TranslateChartService } from '@services/translate-chart.service'; import { filter, map, switchMap } from 'rxjs/operators'; import { DossierStatsService } from '@services/entity-services/dossier-stats.service'; -import { DossierStateService } from '../../../../../../services/entity-services/dossier-state.service'; +import { DossierStateService } from '@services/entity-services/dossier-state.service'; import { TranslateService } from '@ngx-translate/core'; @Component({ diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-status/dossiers-listing-status.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-status/dossiers-listing-status.component.html deleted file mode 100644 index 3df7ebc04..000000000 --- a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-status/dossiers-listing-status.component.html +++ /dev/null @@ -1,13 +0,0 @@ - -
-
{{ currentState.name }}
- -
-
- - -
-
{{ 'edit-dossier-dialog.general-info.form.dossier-status.placeholder' | translate }}
- -
-
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.html b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.html index 7ad67122e..c83181f57 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.html +++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/table-item/table-item.component.html @@ -16,7 +16,7 @@
- +
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/config.service.ts b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/config.service.ts index 10a207470..4e54ab5e5 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/config.service.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/config.service.ts @@ -10,7 +10,7 @@ import { dossierMemberChecker, dossierStateChecker, dossierTemplateChecker, Reda import { workloadTranslations } from '../../translations/workload-translations'; import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service'; import { DossierStatsService } from '@services/entity-services/dossier-stats.service'; -import { DossierStateService } from '../../../../services/entity-services/dossier-state.service'; +import { DossierStateService } from '@services/entity-services/dossier-state.service'; @Injectable() export class ConfigService { diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/dossiers-listing.module.ts b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/dossiers-listing.module.ts index 29af016b3..d36444a4d 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/dossiers-listing.module.ts +++ b/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/dossiers-listing.module.ts @@ -7,12 +7,10 @@ import { RouterModule, Routes } from '@angular/router'; import { DossiersListingActionsComponent } from './components/dossiers-listing-actions/dossiers-listing-actions.component'; import { SharedModule } from '@shared/shared.module'; import { DossiersListingDetailsComponent } from './components/dossiers-listing-details/dossiers-listing-details.component'; -import { DossiersListingDossierNameComponent } from './components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component'; import { ConfigService } from './config.service'; import { TableItemComponent } from './components/table-item/table-item.component'; import { SharedDossiersModule } from '../../shared/shared-dossiers.module'; import { DossierWorkloadColumnComponent } from './components/dossier-workload-column/dossier-workload-column.component'; -import { DossiersListingStatusComponent } from './components/dossiers-listing-status/dossiers-listing-status.component'; import { DossierDocumentsStatusComponent } from './components/dossier-documents-status/dossier-documents-status.component'; const routes: Routes = [ @@ -29,10 +27,8 @@ const routes: Routes = [ DossiersListingScreenComponent, DossiersListingActionsComponent, DossiersListingDetailsComponent, - DossiersListingDossierNameComponent, DossierWorkloadColumnComponent, TableItemComponent, - DossiersListingStatusComponent, DossierDocumentsStatusComponent, ], providers: [ConfigService], diff --git a/apps/red-ui/src/app/modules/shared/components/dossier-status/dossier-status.component.html b/apps/red-ui/src/app/modules/shared/components/dossier-status/dossier-status.component.html new file mode 100644 index 000000000..f4c5f96bf --- /dev/null +++ b/apps/red-ui/src/app/modules/shared/components/dossier-status/dossier-status.component.html @@ -0,0 +1,6 @@ +
+
+ {{ currentState?.name || ('edit-dossier-dialog.general-info.form.dossier-status.placeholder' | translate) }} +
+ +
diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-status/dossiers-listing-status.component.scss b/apps/red-ui/src/app/modules/shared/components/dossier-status/dossier-status.component.scss similarity index 100% rename from apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-status/dossiers-listing-status.component.scss rename to apps/red-ui/src/app/modules/shared/components/dossier-status/dossier-status.component.scss diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-status/dossiers-listing-status.component.ts b/apps/red-ui/src/app/modules/shared/components/dossier-status/dossier-status.component.ts similarity index 57% rename from apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-status/dossiers-listing-status.component.ts rename to apps/red-ui/src/app/modules/shared/components/dossier-status/dossier-status.component.ts index e3994df3d..7ad21eca7 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-status/dossiers-listing-status.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/dossier-status/dossier-status.component.ts @@ -1,15 +1,14 @@ import { ChangeDetectionStrategy, Component, Input, OnChanges, OnInit } from '@angular/core'; -import { Dossier } from '../../../../../../../../../../libs/red-domain/src'; -import { DossierStateService } from '../../../../../../services/entity-services/dossier-state.service'; -import { DossierState } from '@red/domain'; +import { Dossier, DossierState } from '@red/domain'; +import { DossierStateService } from '@services/entity-services/dossier-state.service'; @Component({ - selector: 'redaction-dossiers-listing-status', - templateUrl: './dossiers-listing-status.component.html', - styleUrls: ['./dossiers-listing-status.component.scss'], + selector: 'redaction-dossier-status', + templateUrl: './dossier-status.component.html', + styleUrls: ['./dossier-status.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class DossiersListingStatusComponent implements OnInit, OnChanges { +export class DossierStatusComponent implements OnInit, OnChanges { @Input() dossier: Dossier; currentState: DossierState; diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.html b/apps/red-ui/src/app/modules/shared/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.html similarity index 95% rename from apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.html rename to apps/red-ui/src/app/modules/shared/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.html index c12eabe47..dea2c6bfa 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.html +++ b/apps/red-ui/src/app/modules/shared/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.html @@ -9,7 +9,7 @@ -
+
{{ dossierStats.numberOfFiles }} diff --git a/apps/red-ui/src/app/modules/shared/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.scss b/apps/red-ui/src/app/modules/shared/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.ts b/apps/red-ui/src/app/modules/shared/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.ts similarity index 79% rename from apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.ts rename to apps/red-ui/src/app/modules/shared/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.ts index 30a26f8b5..d4b86aa17 100644 --- a/apps/red-ui/src/app/modules/dossier/screens/dossiers-listing/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.ts +++ b/apps/red-ui/src/app/modules/shared/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component.ts @@ -1,7 +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 { DossierStatsService } from '@services/entity-services/dossier-stats.service'; import { DossiersService } from '@services/entity-services/dossiers.service'; import * as moment from 'moment'; @@ -17,11 +16,7 @@ export class DossiersListingDossierNameComponent { @Input() dossier: Dossier; @Input() dossierStats: DossierStats; - constructor( - private readonly _dossierTemplatesService: DossierTemplatesService, - private readonly _dossierStatsService: DossierStatsService, - private readonly _dossiersService: DossiersService, - ) {} + constructor(private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _dossiersService: DossiersService) {} get approachingDueDate(): boolean { return this._dueDateDaysDiff >= 0 && this._dueDateDaysDiff <= DUE_DATE_WARN_DAYS; 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 939fd0eb7..a185ccf62 100644 --- a/apps/red-ui/src/app/modules/shared/shared.module.ts +++ b/apps/red-ui/src/app/modules/shared/shared.module.ts @@ -27,6 +27,8 @@ import { TeamMembersComponent } from './components/team-members/team-members.com import { EditorComponent } from './components/editor/editor.component'; import { ExpandableFileActionsComponent } from './components/expandable-file-actions/expandable-file-actions.component'; import { ProcessingIndicatorComponent } from '@shared/components/processing-indicator/processing-indicator.component'; +import { DossierStatusComponent } from '@shared/components/dossier-status/dossier-status.component'; +import { DossiersListingDossierNameComponent } from '@shared/components/dossiers-listing-dossier-name/dossiers-listing-dossier-name.component'; const buttons = [FileDownloadBtnComponent, UserButtonComponent]; @@ -43,6 +45,8 @@ const components = [ TeamMembersComponent, ExpandableFileActionsComponent, ProcessingIndicatorComponent, + DossierStatusComponent, + DossiersListingDossierNameComponent, ...buttons, ]; diff --git a/apps/red-ui/src/app/services/breadcrumbs.service.ts b/apps/red-ui/src/app/services/breadcrumbs.service.ts index a6a082738..a6491df9a 100644 --- a/apps/red-ui/src/app/services/breadcrumbs.service.ts +++ b/apps/red-ui/src/app/services/breadcrumbs.service.ts @@ -10,12 +10,18 @@ import { BreadcrumbTypes } from '@red/domain'; import { DOSSIER_ID, FILE_ID } from '@utils/constants'; export type RouterLinkActiveOptions = { exact: boolean } | IsActiveMatchOptions; +export type BreadcrumbDisplayType = 'text' | 'dropdown'; export interface Breadcrumb { readonly name$: Observable; - readonly routerLink?: string[]; - readonly routerLinkActiveOptions?: RouterLinkActiveOptions | undefined; - readonly clamp?: boolean; + readonly type: BreadcrumbDisplayType; + readonly options: { + readonly routerLink?: string[]; + readonly routerLinkActiveOptions?: RouterLinkActiveOptions | undefined; + readonly clamp?: boolean; + readonly options?: Breadcrumb[]; + readonly activeOption?: Breadcrumb; + }; } export type Breadcrumbs = List; @@ -63,7 +69,8 @@ export class BreadcrumbsService { for (const breadcrumb of route.data.breadcrumbs || []) { switch (breadcrumb) { case BreadcrumbTypes.main: - this._addMainBreadcrumb(); + case BreadcrumbTypes.archive: + this._addMainBreadcrumb(breadcrumb as 'main' | 'archive'); break; case BreadcrumbTypes.dossier: this._addDossierBreadcrumb(route); @@ -75,11 +82,34 @@ export class BreadcrumbsService { } } - private _addMainBreadcrumb(): void { - this._append({ + private _addMainBreadcrumb(type: 'main' | 'archive'): void { + const activeDossiers: Breadcrumb = { name$: of(this._translateService.instant('top-bar.navigation-items.dossiers')), - routerLink: ['/main', 'dossiers'], - routerLinkActiveOptions: { exact: true }, + type: 'text' as BreadcrumbDisplayType, + options: { + routerLink: ['/main', 'dossiers'], + routerLinkActiveOptions: { exact: true }, + }, + }; + + const archivedDossiers: Breadcrumb = { + name$: of(this._translateService.instant('top-bar.navigation-items.archived-dossiers')), + type: 'text' as BreadcrumbDisplayType, + options: { + routerLink: ['/main', 'archive'], + routerLinkActiveOptions: { exact: true }, + }, + }; + + const activeOption = type === 'main' ? activeDossiers : archivedDossiers; + + this._append({ + name$: activeOption.name$, + type: 'dropdown' as BreadcrumbDisplayType, + options: { + options: [activeDossiers, archivedDossiers], + activeOption, + }, }); } @@ -87,9 +117,12 @@ export class BreadcrumbsService { const dossierId = route.paramMap.get(DOSSIER_ID); this._append({ name$: this._dossiersService.getEntityChanged$(dossierId).pipe(pluck('dossierName')), - routerLink: ['/main', 'dossiers', dossierId], - routerLinkActiveOptions: { exact: true }, - clamp: true, + type: 'text' as BreadcrumbDisplayType, + options: { + routerLink: ['/main', 'dossiers', dossierId], + routerLinkActiveOptions: { exact: true }, + clamp: true, + }, }); } @@ -98,8 +131,11 @@ export class BreadcrumbsService { const fileId = route.paramMap.get(FILE_ID); this._append({ name$: this._filesMapService.watch$(dossierId, fileId).pipe(pluck('filename')), - routerLink: ['/main', 'dossiers', dossierId, 'file', fileId], - clamp: true, + type: 'text' as BreadcrumbDisplayType, + options: { + routerLink: ['/main', 'dossiers', dossierId, 'file', fileId], + clamp: true, + }, }); } } diff --git a/apps/red-ui/src/app/services/entity-services/archived-dossiers.service.ts b/apps/red-ui/src/app/services/entity-services/archived-dossiers.service.ts new file mode 100644 index 000000000..9721d69ab --- /dev/null +++ b/apps/red-ui/src/app/services/entity-services/archived-dossiers.service.ts @@ -0,0 +1,53 @@ +import { Injectable, Injector } from '@angular/core'; +import { EntitiesService, mapEach, Toaster } from '@iqser/common-ui'; +import { Dossier, IDossier } from '@red/domain'; +import { catchError, mapTo, switchMap, tap } from 'rxjs/operators'; +import { Observable, of } from 'rxjs'; +import { DossierStateService } from '@services/entity-services/dossier-state.service'; +import { DossierStatsService } from '@services/entity-services/dossier-stats.service'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { DossiersService } from '@services/entity-services/dossiers.service'; + +@Injectable({ + providedIn: 'root', +}) +export class ArchivedDossiersService extends EntitiesService { + constructor( + protected readonly _injector: Injector, + private readonly _toaster: Toaster, + private readonly _dossierStateService: DossierStateService, + private readonly _dossierStatsService: DossierStatsService, + private readonly _dossiersService: DossiersService, + ) { + super(_injector, Dossier, 'archived-dossiers'); + } + + loadAll(): Observable { + const dossierIds = (dossiers: Dossier[]) => dossiers.map(d => d.id); + return this.getAll().pipe( + mapEach(entity => new Dossier(entity)), + /* Load stats before updating entities */ + switchMap(dossiers => this._dossierStatsService.getFor(dossierIds(dossiers)).pipe(mapTo(dossiers))), + switchMap(dossiers => this._dossierStateService.loadAllForAllTemplates().pipe(mapTo(dossiers))), + tap(dossiers => this.setEntities(dossiers)), + ); + } + + archive(dossiers: Dossier[]): Observable { + const showToast = () => { + this._toaster.error(_('dossier-listing.archive.archive-failed'), { params: dossiers }); + return of({}); + }; + return this._post( + dossiers.map(d => d.id), + `${this._defaultModelPath}/archive`, + ).pipe( + tap(() => this.#removeDossiers(dossiers)), + catchError(showToast), + ); + } + + #removeDossiers(dossiers: Dossier[]): void { + this._dossiersService.setEntities(this._dossiersService.all.filter(dossier => !dossiers.find(d => dossier.id === d.id))); + } +} diff --git a/apps/red-ui/src/app/services/entity-services/dossiers.service.ts b/apps/red-ui/src/app/services/entity-services/dossiers.service.ts index 669383561..2610d479f 100644 --- a/apps/red-ui/src/app/services/entity-services/dossiers.service.ts +++ b/apps/red-ui/src/app/services/entity-services/dossiers.service.ts @@ -118,20 +118,6 @@ export class DossiersService extends EntitiesService { ); } - archive(dossiers: Dossier[]): Observable { - const showToast = () => { - this._toaster.error(_('dossier-listing.archive.archive-failed'), { params: dossiers }); - return of({}); - }; - return this._post( - dossiers.map(d => d.id), - 'archived-dossiers/archive', - ).pipe( - tap(() => this.#removeDossiers(dossiers)), - catchError(showToast), - ); - } - @Validate() restore(@RequiredParam() dossierIds: List): Promise { return firstValueFrom(this._post(dossierIds, 'deleted-dossiers/restore').pipe(switchMap(() => this.loadAll()))); diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index a1b84ce97..ba47d3192 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -313,6 +313,23 @@ "suggestion-resize": "Suggested Resize" }, "annotations": "Annotations", + "archived-dossiers-listing": { + "no-data": { + "title": "No archived dossiers." + }, + "no-match": { + "title": "No archived dossiers match your current filters." + }, + "table-col-names": { + "dossier-status": "Dossier Status", + "last-modified": "Last Modified", + "name": "Name", + "owner": "Owner" + }, + "table-header": { + "title": "{length} Archived {length, plural, one{Dossier} other{Dossiers}}" + } + }, "assign-dossier-owner": { "dialog": { "approvers": "Approvers", @@ -1722,6 +1739,7 @@ }, "top-bar": { "navigation-items": { + "archived-dossiers": "Archived Dossiers", "back": "Back", "dossiers": "Active Dossiers", "my-account": { diff --git a/libs/red-domain/src/lib/dossiers/dossier.model.ts b/libs/red-domain/src/lib/dossiers/dossier.model.ts index e2a79d550..b95caf827 100644 --- a/libs/red-domain/src/lib/dossiers/dossier.model.ts +++ b/libs/red-domain/src/lib/dossiers/dossier.model.ts @@ -22,6 +22,7 @@ export class Dossier implements IDossier, IListable { readonly status: DossierStatus; readonly watermarkEnabled: boolean; readonly watermarkPreviewEnabled: boolean; + readonly archivedTime: string; readonly hasReviewers: boolean; constructor(dossier: IDossier) { @@ -43,6 +44,7 @@ export class Dossier implements IDossier, IListable { this.status = dossier.status; this.watermarkEnabled = dossier.watermarkEnabled; this.watermarkPreviewEnabled = dossier.watermarkPreviewEnabled; + this.archivedTime = dossier.archivedTime; this.hasReviewers = !!this.memberIds && this.memberIds.length > 1; } diff --git a/libs/red-domain/src/lib/dossiers/dossier.ts b/libs/red-domain/src/lib/dossiers/dossier.ts index 1ff219033..59689a5d9 100644 --- a/libs/red-domain/src/lib/dossiers/dossier.ts +++ b/libs/red-domain/src/lib/dossiers/dossier.ts @@ -21,4 +21,5 @@ export interface IDossier { readonly status: DossierStatus; readonly watermarkEnabled: boolean; readonly watermarkPreviewEnabled: boolean; + readonly archivedTime: string; } diff --git a/libs/red-domain/src/lib/shared/breadcrumb-types.ts b/libs/red-domain/src/lib/shared/breadcrumb-types.ts index 3366c25a2..74ed8ae69 100644 --- a/libs/red-domain/src/lib/shared/breadcrumb-types.ts +++ b/libs/red-domain/src/lib/shared/breadcrumb-types.ts @@ -1,7 +1,8 @@ -export type BreadcrumbType = 'main' | 'dossier' | 'file'; +export type BreadcrumbType = 'main' | 'dossier' | 'file' | 'archive'; export const BreadcrumbTypes = { main: 'main' as BreadcrumbType, dossier: 'dossier' as BreadcrumbType, file: 'file' as BreadcrumbType, + archive: 'archive' as BreadcrumbType, }; From 8e54d5284532518ad2ab28dca18b36bf052dd09f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Tue, 22 Feb 2022 00:56:49 +0200 Subject: [PATCH 03/20] Breadcrumbs --- .../base-screen/base-screen.component.html | 4 +- .../base-screen/base-screen.component.scss | 6 ++ .../breadcrumbs/breadcrumbs.component.html | 8 ++- .../breadcrumbs/breadcrumbs.component.scss | 6 +- .../breadcrumbs/breadcrumbs.component.ts | 5 +- ...ossier-template-breadcrumbs.component.html | 2 +- .../src/app/services/breadcrumbs.service.ts | 65 ++++++++++++------- libs/common-ui | 2 +- 8 files changed, 66 insertions(+), 32 deletions(-) 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 106f8e0d7..fe081fb50 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 @@ -3,7 +3,7 @@
- -