From 69a2eb275097229cf9920893b578acd1672c9a0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adina=20=C8=9Aeudan?= Date: Wed, 11 May 2022 20:03:15 +0300 Subject: [PATCH] RED-3950: Trash module & improvements --- apps/red-ui/src/app/app-routing.module.ts | 11 ++++ .../base-screen/base-screen.component.ts | 2 +- apps/red-ui/src/app/guards/trash.guard.ts | 14 ++++++ .../app/modules/admin/admin-routing.module.ts | 13 ----- .../src/app/modules/admin/admin.module.ts | 14 ++---- .../trash/services/trash-dialog.service.ts | 50 +++++++++++++++++++ .../trash-screen}/trash-screen.component.html | 0 .../trash-screen}/trash-screen.component.scss | 0 .../trash-screen}/trash-screen.component.ts | 49 ++++++------------ .../trash-table-item.component.html | 0 .../trash-table-item.component.scss | 0 .../trash-table-item.component.ts | 0 .../src/app/modules/trash/trash.module.ts | 17 +++++++ .../services/entity-services/trash.service.ts | 19 ++++--- 14 files changed, 123 insertions(+), 66 deletions(-) create mode 100644 apps/red-ui/src/app/guards/trash.guard.ts create mode 100644 apps/red-ui/src/app/modules/trash/services/trash-dialog.service.ts rename apps/red-ui/src/app/modules/{admin/screens/trash => trash/trash-screen}/trash-screen.component.html (100%) rename apps/red-ui/src/app/modules/{admin/screens/trash => trash/trash-screen}/trash-screen.component.scss (100%) rename apps/red-ui/src/app/modules/{admin/screens/trash => trash/trash-screen}/trash-screen.component.ts (64%) rename apps/red-ui/src/app/modules/{admin/screens/trash => trash/trash-screen}/trash-table-item/trash-table-item.component.html (100%) rename apps/red-ui/src/app/modules/{admin/screens/trash => trash/trash-screen}/trash-table-item/trash-table-item.component.scss (100%) rename apps/red-ui/src/app/modules/{admin/screens/trash => trash/trash-screen}/trash-table-item/trash-table-item.component.ts (100%) create mode 100644 apps/red-ui/src/app/modules/trash/trash.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 6c5b7a67a..3226143ee 100644 --- a/apps/red-ui/src/app/app-routing.module.ts +++ b/apps/red-ui/src/app/app-routing.module.ts @@ -14,6 +14,7 @@ import { DossierTemplatesGuard } from '@guards/dossier-templates.guard'; import { DossierTemplateExistsGuard } from '@guards/dossier-template-exists.guard'; import { DashboardGuard } from '@guards/dashboard-guard.service'; import { ARCHIVE_ROUTE, DOSSIERS_ARCHIVE, DOSSIERS_ROUTE } from '@red/domain'; +import { TrashGuard } from '@guards/trash.guard'; const routes: Routes = [ { @@ -64,6 +65,16 @@ const routes: Routes = [ requiredRoles: ['RED_USER', 'RED_MANAGER'], }, }, + { + path: 'trash', + loadChildren: () => import('./modules/trash/trash.module').then(m => m.TrashModule), + canActivate: [CompositeRouteGuard], + data: { + routeGuards: [AuthGuard, RedRoleGuard, DossiersGuard, TrashGuard], + requiredRoles: ['RED_USER', 'RED_MANAGER'], + dossiersService: ACTIVE_DOSSIERS_SERVICE, + }, + }, { path: `:${DOSSIER_TEMPLATE_ID}`, children: [ 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 bc43783c2..be6c54f45 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 @@ -52,7 +52,7 @@ export class BaseScreenComponent { { id: 'trash', name: _('top-bar.navigation-items.my-account.children.trash'), - routerLink: '/main/admin/trash', + routerLink: '/main/trash', show: this.currentUser.isManager, }, ]; diff --git a/apps/red-ui/src/app/guards/trash.guard.ts b/apps/red-ui/src/app/guards/trash.guard.ts new file mode 100644 index 000000000..542a4ede1 --- /dev/null +++ b/apps/red-ui/src/app/guards/trash.guard.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { CanActivate } from '@angular/router'; +import { firstValueFrom } from 'rxjs'; +import { TrashService } from '@services/entity-services/trash.service'; + +@Injectable({ providedIn: 'root' }) +export class TrashGuard implements CanActivate { + constructor(private readonly _trashService: TrashService) {} + + async canActivate(): Promise { + await firstValueFrom(this._trashService.loadAll()); + return true; + } +} diff --git a/apps/red-ui/src/app/modules/admin/admin-routing.module.ts b/apps/red-ui/src/app/modules/admin/admin-routing.module.ts index 2fcbb5317..5788fa076 100644 --- a/apps/red-ui/src/app/modules/admin/admin-routing.module.ts +++ b/apps/red-ui/src/app/modules/admin/admin-routing.module.ts @@ -11,7 +11,6 @@ import { DigitalSignatureScreenComponent } from './screens/digital-signature/dig import { AuditScreenComponent } from './screens/audit/audit-screen.component'; import { RouterModule, Routes } from '@angular/router'; import { DossierAttributesListingScreenComponent } from './screens/dossier-attributes-listing/dossier-attributes-listing-screen.component'; -import { TrashScreenComponent } from './screens/trash/trash-screen.component'; import { GeneralConfigScreenComponent } from './screens/general-config/general-config-screen.component'; import { BaseAdminScreenComponent } from './base-admin-screen/base-admin-screen.component'; import { BaseDossierTemplateScreenComponent } from './base-dossier-templates-screen/base-dossier-template-screen.component'; @@ -20,8 +19,6 @@ import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@utils/constants'; import { DossierTemplateExistsGuard } from '@guards/dossier-template-exists.guard'; import { EntityExistsGuard } from '@guards/entity-exists-guard.service'; import { DossierStatesListingScreenComponent } from './screens/dossier-states-listing/dossier-states-listing-screen.component'; -import { DossiersGuard } from '@guards/dossiers.guard'; -import { ACTIVE_DOSSIERS_SERVICE } from '../../tokens'; import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-screen.component'; import { PermissionsGuard } from '../../guards/permissions-guard'; @@ -210,16 +207,6 @@ const routes: Routes = [ requiredRoles: ['RED_ADMIN'], }, }, - { - path: 'trash', - component: TrashScreenComponent, - canActivate: [CompositeRouteGuard], - data: { - routeGuards: [AuthGuard, RedRoleGuard, DossiersGuard], - requiredRoles: ['RED_MANAGER'], - dossiersService: ACTIVE_DOSSIERS_SERVICE, - }, - }, ]; @NgModule({ diff --git a/apps/red-ui/src/app/modules/admin/admin.module.ts b/apps/red-ui/src/app/modules/admin/admin.module.ts index f3be32ed2..de6e99167 100644 --- a/apps/red-ui/src/app/modules/admin/admin.module.ts +++ b/apps/red-ui/src/app/modules/admin/admin.module.ts @@ -25,7 +25,6 @@ import { ResetPasswordComponent } from './dialogs/add-edit-user-dialog/reset-pas import { UserDetailsComponent } from './dialogs/add-edit-user-dialog/user-details/user-details.component'; import { AddEditDossierAttributeDialogComponent } from './dialogs/add-edit-dossier-attribute-dialog/add-edit-dossier-attribute-dialog.component'; import { DossierAttributesListingScreenComponent } from './screens/dossier-attributes-listing/dossier-attributes-listing-screen.component'; -import { TrashScreenComponent } from './screens/trash/trash-screen.component'; import { AuditService } from './services/audit.service'; import { DigitalSignatureService } from './services/digital-signature.service'; import { BaseAdminScreenComponent } from './base-admin-screen/base-admin-screen.component'; @@ -41,7 +40,6 @@ import { DossierStatesListingScreenComponent } from './screens/dossier-states-li import { AddEditDossierStateDialogComponent } from './dialogs/add-edit-dossier-state-dialog/add-edit-dossier-state-dialog.component'; import { A11yModule } from '@angular/cdk/a11y'; import { ConfirmDeleteDossierStateDialogComponent } from './dialogs/confirm-delete-dossier-state-dialog/confirm-delete-dossier-state-dialog.component'; -import { TrashTableItemComponent } from './screens/trash/trash-table-item/trash-table-item.component'; import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-screen.component'; import { CloneDossierTemplateDialogComponent } from './dialogs/clone-dossier-template-dialog/clone-dossier-template-dialog.component'; import { AdminSideNavComponent } from './admin-side-nav/admin-side-nav.component'; @@ -58,6 +56,8 @@ const dialogs = [ FileAttributesCsvImportDialogComponent, AddEditDossierAttributeDialogComponent, UploadDictionaryDialogComponent, + AddEditDossierStateDialogComponent, + ConfirmDeleteDossierStateDialogComponent, ]; const screens = [ @@ -69,7 +69,7 @@ const screens = [ UserListingScreenComponent, GeneralConfigScreenComponent, DossierAttributesListingScreenComponent, - TrashScreenComponent, + DossierStatesListingScreenComponent, ]; const components = [ @@ -90,13 +90,7 @@ const components = [ ]; @NgModule({ - declarations: [ - ...components, - DossierStatesListingScreenComponent, - AddEditDossierStateDialogComponent, - ConfirmDeleteDossierStateDialogComponent, - TrashTableItemComponent, - ], + declarations: [...components], providers: [AdminDialogService, AuditService, DigitalSignatureService, RulesService, SmtpConfigService], imports: [CommonModule, SharedModule, AdminRoutingModule, SharedAdminModule, ColorPickerModule, A11yModule], }) diff --git a/apps/red-ui/src/app/modules/trash/services/trash-dialog.service.ts b/apps/red-ui/src/app/modules/trash/services/trash-dialog.service.ts new file mode 100644 index 000000000..9ef73d9d6 --- /dev/null +++ b/apps/red-ui/src/app/modules/trash/services/trash-dialog.service.ts @@ -0,0 +1,50 @@ +import { Injectable } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { + ConfirmationDialogComponent, + ConfirmationDialogInput, + DialogConfig, + DialogService, + LoadingService, + TitleColors, +} from '@iqser/common-ui'; +import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; +import { TrashItem } from '@red/domain'; +import { firstValueFrom } from 'rxjs'; +import { TrashService } from '@services/entity-services/trash.service'; + +type DialogType = 'confirm'; + +@Injectable() +export class TrashDialogService extends DialogService { + protected readonly _config: DialogConfig = { + confirm: { + component: ConfirmationDialogComponent, + }, + }; + + constructor( + protected readonly _dialog: MatDialog, + private readonly _loadingService: LoadingService, + private readonly _trashService: TrashService, + ) { + super(_dialog); + } + + confirmHardDelete(items: TrashItem[]): void { + const data = new ConfirmationDialogInput({ + title: _('confirmation-dialog.delete-items.title'), + titleColor: TitleColors.WARN, + question: _('confirmation-dialog.delete-items.question'), + translateParams: { + name: items[0].name, + itemsCount: items.length, + }, + }); + this.openDialog('confirm', null, data, async () => { + this._loadingService.start(); + await firstValueFrom(this._trashService.hardDelete(items)); + this._loadingService.stop(); + }); + } +} diff --git a/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.html b/apps/red-ui/src/app/modules/trash/trash-screen/trash-screen.component.html similarity index 100% rename from apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.html rename to apps/red-ui/src/app/modules/trash/trash-screen/trash-screen.component.html diff --git a/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.scss b/apps/red-ui/src/app/modules/trash/trash-screen/trash-screen.component.scss similarity index 100% rename from apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.scss rename to apps/red-ui/src/app/modules/trash/trash-screen/trash-screen.component.scss diff --git a/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.ts b/apps/red-ui/src/app/modules/trash/trash-screen/trash-screen.component.ts similarity index 64% rename from apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.ts rename to apps/red-ui/src/app/modules/trash/trash-screen/trash-screen.component.ts index 8f77182f1..c4d97b1b4 100644 --- a/apps/red-ui/src/app/modules/admin/screens/trash/trash-screen.component.ts +++ b/apps/red-ui/src/app/modules/trash/trash-screen/trash-screen.component.ts @@ -1,15 +1,13 @@ -import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, forwardRef, Injector } from '@angular/core'; import { CircleButtonTypes, - ConfirmationDialogInput, - DefaultListingServices, + DefaultListingServicesTmp, + EntitiesService, ListingComponent, LoadingService, SortingOrders, TableColumnConfig, - TitleColors, } from '@iqser/common-ui'; -import { AdminDialogService } from '../../services/admin-dialog.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { firstValueFrom, Observable } from 'rxjs'; import { distinctUntilChanged, map } from 'rxjs/operators'; @@ -18,15 +16,22 @@ 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/dossier-templates/dossier-templates.service'; +import { TrashDialogService } from '../services/trash-dialog.service'; @Component({ templateUrl: './trash-screen.component.html', styleUrls: ['./trash-screen.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, - providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => TrashScreenComponent) }], + providers: [ + ...DefaultListingServicesTmp, + { provide: EntitiesService, useExisting: TrashService }, + { + provide: ListingComponent, + useExisting: forwardRef(() => TrashScreenComponent), + }, + ], }) -export class TrashScreenComponent extends ListingComponent implements OnInit { +export class TrashScreenComponent extends ListingComponent { readonly circleButtonTypes = CircleButtonTypes; readonly tableHeaderLabel = _('trash.table-header.title'); readonly canRestoreSelected$ = this._canRestoreSelected$; @@ -46,8 +51,7 @@ export class TrashScreenComponent extends ListingComponent implements private readonly _activeDossiersService: ActiveDossiersService, private readonly _filesService: FilesService, readonly routerHistoryService: RouterHistoryService, - private readonly _adminDialogService: AdminDialogService, - private readonly _dossierTemplatesService: DossierTemplatesService, + private readonly _dialogService: TrashDialogService, ) { super(_injector); @@ -71,38 +75,15 @@ export class TrashScreenComponent extends ListingComponent implements ); } - async ngOnInit(): Promise { - this._loadingService.start(); - await firstValueFrom(this._dossierTemplatesService.loadAll()); - const entities: TrashItem[] = await firstValueFrom(this._trashService.all()); - this.entitiesService.setEntities(entities); - this._loadingService.stop(); - } - disabledFn = (dossier: TrashItem) => !dossier.canRestore; hardDelete(items = this.listingService.selected): void { - const data = new ConfirmationDialogInput({ - title: _('confirmation-dialog.delete-items.title'), - titleColor: TitleColors.WARN, - question: _('confirmation-dialog.delete-items.question'), - translateParams: { - name: items[0].name, - itemsCount: items.length, - }, - }); - this._adminDialogService.openDialog('confirm', null, data, async () => { - this._loadingService.start(); - await firstValueFrom(this._trashService.hardDelete(items)); - items.forEach(item => this.entitiesService.remove(item.id)); - this._loadingService.stop(); - }); + this._dialogService.confirmHardDelete(items); } async restore(items = this.listingService.selected): Promise { this._loadingService.start(); await firstValueFrom(this._trashService.restore(items)); - items.forEach(item => this.entitiesService.remove(item.id)); this._loadingService.stop(); } } diff --git a/apps/red-ui/src/app/modules/admin/screens/trash/trash-table-item/trash-table-item.component.html b/apps/red-ui/src/app/modules/trash/trash-screen/trash-table-item/trash-table-item.component.html similarity index 100% rename from apps/red-ui/src/app/modules/admin/screens/trash/trash-table-item/trash-table-item.component.html rename to apps/red-ui/src/app/modules/trash/trash-screen/trash-table-item/trash-table-item.component.html diff --git a/apps/red-ui/src/app/modules/admin/screens/trash/trash-table-item/trash-table-item.component.scss b/apps/red-ui/src/app/modules/trash/trash-screen/trash-table-item/trash-table-item.component.scss similarity index 100% rename from apps/red-ui/src/app/modules/admin/screens/trash/trash-table-item/trash-table-item.component.scss rename to apps/red-ui/src/app/modules/trash/trash-screen/trash-table-item/trash-table-item.component.scss diff --git a/apps/red-ui/src/app/modules/admin/screens/trash/trash-table-item/trash-table-item.component.ts b/apps/red-ui/src/app/modules/trash/trash-screen/trash-table-item/trash-table-item.component.ts similarity index 100% rename from apps/red-ui/src/app/modules/admin/screens/trash/trash-table-item/trash-table-item.component.ts rename to apps/red-ui/src/app/modules/trash/trash-screen/trash-table-item/trash-table-item.component.ts diff --git a/apps/red-ui/src/app/modules/trash/trash.module.ts b/apps/red-ui/src/app/modules/trash/trash.module.ts new file mode 100644 index 000000000..e145fb601 --- /dev/null +++ b/apps/red-ui/src/app/modules/trash/trash.module.ts @@ -0,0 +1,17 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RouterModule } from '@angular/router'; +import { TrashScreenComponent } from './trash-screen/trash-screen.component'; +import { CommonUiModule } from '@iqser/common-ui'; +import { TrashTableItemComponent } from './trash-screen/trash-table-item/trash-table-item.component'; +import { SharedModule } from '@shared/shared.module'; +import { TrashDialogService } from './services/trash-dialog.service'; + +const routes = [{ path: '', component: TrashScreenComponent }]; + +@NgModule({ + declarations: [TrashScreenComponent, TrashTableItemComponent], + imports: [CommonModule, RouterModule.forChild(routes), CommonUiModule, SharedModule], + providers: [TrashDialogService], +}) +export class TrashModule {} 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 506a44315..299c2bdd1 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 @@ -1,7 +1,7 @@ import { Injectable, Injector } from '@angular/core'; -import { GenericService, List, mapEach, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui'; +import { EntitiesService, List, mapEach, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui'; import { Dossier, File, IDossier, IFile, TrashDossier, TrashFile, TrashItem } from '@red/domain'; -import { catchError, switchMap, take } from 'rxjs/operators'; +import { catchError, switchMap, take, tap } from 'rxjs/operators'; import { forkJoin, map, Observable, of } from 'rxjs'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { ConfigService } from '../config.service'; @@ -15,7 +15,7 @@ import { FilesService } from '@services/entity-services/files.service'; @Injectable({ providedIn: 'root', }) -export class TrashService extends GenericService { +export class TrashService extends EntitiesService { constructor( protected readonly _injector: Injector, private readonly _toaster: Toaster, @@ -26,7 +26,7 @@ export class TrashService extends GenericService { private readonly _dossierStatsService: DossierStatsService, private readonly _filesService: FilesService, ) { - super(_injector, ''); + super(_injector, null, ''); } deleteDossier(dossier: Dossier): Observable { @@ -46,7 +46,7 @@ export class TrashService extends GenericService { items, (dossierIds: string[]) => this._restoreDossiers(dossierIds), (dossierId: string, fileIds: string[]) => this._restoreFiles(dossierId, fileIds), - ); + ).pipe(tap(() => items.forEach(item => this.remove(item.id)))); } @Validate() @@ -55,7 +55,7 @@ export class TrashService extends GenericService { items, (dossierIds: string[]) => this._hardDeleteDossiers(dossierIds), (dossierId: string, fileIds: string[]) => this._hardDeleteFiles(dossierId, fileIds), - ); + ).pipe(tap(() => items.forEach(item => this.remove(item.id)))); } getDossiers(): Observable { @@ -89,8 +89,11 @@ export class TrashService extends GenericService { ); } - all(): Observable { - return forkJoin([this.getDossiers(), this.getFiles()]).pipe(map(result => flatMap(result))); + loadAll(): Observable { + return forkJoin([this.getDossiers(), this.getFiles()]).pipe( + map(result => flatMap(result)), + tap(items => this.setEntities(items)), + ); } #executeAction(items: TrashItem[], dossiersFn: (...args) => Observable, filesFn: (...args) => Observable) {