RED-3950: Trash module & improvements

This commit is contained in:
Adina Țeudan 2022-05-11 20:03:15 +03:00
parent 9284d14bb7
commit 69a2eb2750
14 changed files with 123 additions and 66 deletions

View File

@ -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: [

View File

@ -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,
},
];

View File

@ -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<boolean> {
await firstValueFrom(this._trashService.loadAll());
return true;
}
}

View File

@ -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({

View File

@ -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],
})

View File

@ -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<DialogType> {
protected readonly _config: DialogConfig<DialogType> = {
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();
});
}
}

View File

@ -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<TrashItem> implements OnInit {
export class TrashScreenComponent extends ListingComponent<TrashItem> {
readonly circleButtonTypes = CircleButtonTypes;
readonly tableHeaderLabel = _('trash.table-header.title');
readonly canRestoreSelected$ = this._canRestoreSelected$;
@ -46,8 +51,7 @@ export class TrashScreenComponent extends ListingComponent<TrashItem> 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<TrashItem> implements
);
}
async ngOnInit(): Promise<void> {
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<void> {
this._loadingService.start();
await firstValueFrom(this._trashService.restore(items));
items.forEach(item => this.entitiesService.remove(item.id));
this._loadingService.stop();
}
}

View File

@ -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 {}

View File

@ -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<TrashItem> {
export class TrashService extends EntitiesService<TrashItem> {
constructor(
protected readonly _injector: Injector,
private readonly _toaster: Toaster,
@ -26,7 +26,7 @@ export class TrashService extends GenericService<TrashItem> {
private readonly _dossierStatsService: DossierStatsService,
private readonly _filesService: FilesService,
) {
super(_injector, '');
super(_injector, null, '');
}
deleteDossier(dossier: Dossier): Observable<unknown> {
@ -46,7 +46,7 @@ export class TrashService extends GenericService<TrashItem> {
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<TrashItem> {
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<TrashDossier[]> {
@ -89,8 +89,11 @@ export class TrashService extends GenericService<TrashItem> {
);
}
all(): Observable<TrashItem[]> {
return forkJoin([this.getDossiers(), this.getFiles()]).pipe(map(result => flatMap<TrashItem>(result)));
loadAll(): Observable<TrashItem[]> {
return forkJoin([this.getDossiers(), this.getFiles()]).pipe(
map(result => flatMap<TrashItem>(result)),
tap(items => this.setEntities(items)),
);
}
#executeAction(items: TrashItem[], dossiersFn: (...args) => Observable<unknown>, filesFn: (...args) => Observable<unknown>) {