Archived dossier overview WIP
This commit is contained in:
parent
12d655a7b7
commit
0a05eb9a6c
@ -1,15 +1,15 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, Injector, ProviderToken } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
|
||||
import { ActiveDossiersService } from '@services/entity-services/active-dossiers.service';
|
||||
import { FilesMapService } from '@services/entity-services/files-map.service';
|
||||
import { FilesService } from '@services/entity-services/files.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { DOSSIER_ID } from '@utils/constants';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class DossierFilesGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly _dossiersService: ActiveDossiersService,
|
||||
private readonly _injector: Injector,
|
||||
private readonly _filesMapService: FilesMapService,
|
||||
private readonly _filesService: FilesService,
|
||||
private readonly _router: Router,
|
||||
@ -17,9 +17,11 @@ export class DossierFilesGuard implements CanActivate {
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
|
||||
const dossierId = route.paramMap.get(DOSSIER_ID);
|
||||
const token: ProviderToken<DossiersService> = route.data.dossiersService;
|
||||
const dossiersService: DossiersService = this._injector.get<DossiersService>(token);
|
||||
|
||||
if (!this._dossiersService.has(dossierId)) {
|
||||
await this._router.navigate(['/main', 'dossiers']);
|
||||
if (!dossiersService.has(dossierId)) {
|
||||
await this._router.navigate(['/main', dossiersService.routerPath]);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,10 @@ import { NgModule } from '@angular/core';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { BreadcrumbTypes } from '@red/domain';
|
||||
import { ArchivedDossiersScreenComponent } from './screens/archived-dossiers-screen/archived-dossiers-screen.component';
|
||||
import { DOSSIER_ID } from '@utils/constants';
|
||||
import { CompositeRouteGuard } from '@iqser/common-ui';
|
||||
import { ARCHIVED_DOSSIERS_SERVICE } from '../../tokens';
|
||||
import { DossierFilesGuard } from '../../guards/dossier-files-guard';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@ -10,6 +14,16 @@ const routes: Routes = [
|
||||
component: ArchivedDossiersScreenComponent,
|
||||
data: { breadcrumbs: [BreadcrumbTypes.archive] },
|
||||
},
|
||||
{
|
||||
path: `:${DOSSIER_ID}`,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [DossierFilesGuard],
|
||||
breadcrumbs: [BreadcrumbTypes.archive, BreadcrumbTypes.dossier],
|
||||
dossiersService: ARCHIVED_DOSSIERS_SERVICE,
|
||||
},
|
||||
loadChildren: () => import('../dossier/screens/dossier-overview/dossier-overview.module').then(m => m.DossierOverviewModule),
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
||||
@ -2,7 +2,6 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { ArchivedDossiersScreenComponent } from './screens/archived-dossiers-screen/archived-dossiers-screen.component';
|
||||
import { ArchiveRoutingModule } from './archive-routing.module';
|
||||
import { CommonUiModule } from '@iqser/common-ui';
|
||||
import { TableItemComponent } from './components/table-item/table-item.component';
|
||||
import { ConfigService } from './services/config.service';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
@ -12,7 +11,7 @@ const screens = [ArchivedDossiersScreenComponent];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components, ...screens],
|
||||
imports: [CommonModule, ArchiveRoutingModule, SharedModule, CommonUiModule],
|
||||
imports: [CommonModule, ArchiveRoutingModule, SharedModule],
|
||||
providers: [ConfigService],
|
||||
})
|
||||
export class ArchiveModule {}
|
||||
|
||||
@ -5,10 +5,10 @@ import { PermissionsService } from '@services/permissions.service';
|
||||
import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
|
||||
import { DictionaryService } from '@shared/services/dictionary.service';
|
||||
import { CircleButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
|
||||
import { ActiveDossiersService } from '@services/entity-services/active-dossiers.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-edit-dossier-dictionary',
|
||||
@ -27,7 +27,7 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
|
||||
@ViewChild(DictionaryManagerComponent, { static: false }) private readonly _dictionaryManager: DictionaryManagerComponent;
|
||||
|
||||
constructor(
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
|
||||
@ -3,10 +3,10 @@ import { Dossier, DownloadFileType, IReportTemplate } from '@red/domain';
|
||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
|
||||
import { downloadTypesTranslations } from '../../../../../translations/download-types-translations';
|
||||
import { ActiveDossiersService } from '@services/entity-services/active-dossiers.service';
|
||||
import { ReportTemplateService } from '@services/report-template.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-edit-dossier-download-package',
|
||||
@ -26,7 +26,7 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS
|
||||
@Input() dossier: Dossier;
|
||||
|
||||
constructor(
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _reportTemplateController: ReportTemplateService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
@ -88,7 +88,7 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS
|
||||
reportTemplateIds: this.form.get('reportTemplateIds').value,
|
||||
};
|
||||
|
||||
const updatedDossier = await firstValueFrom(this._activeDossiersService.createOrUpdate(dossier));
|
||||
const updatedDossier = await firstValueFrom(this._dossiersService.createOrUpdate(dossier));
|
||||
return { success: !!updatedDossier };
|
||||
}
|
||||
|
||||
|
||||
@ -10,18 +10,20 @@ import { EditDossierAttributesComponent } from './attributes/edit-dossier-attrib
|
||||
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { EditDossierDeletedDocumentsComponent } from './deleted-documents/edit-dossier-deleted-documents.component';
|
||||
import { ActiveDossiersService } from '@services/entity-services/active-dossiers.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { EditDossierTeamComponent } from './edit-dossier-team/edit-dossier-team.component';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
import { dossiersServiceProvider } from '@services/entity-services/dossiers.service.provider';
|
||||
|
||||
type Section = 'dossierInfo' | 'downloadPackage' | 'dossierDictionary' | 'members' | 'dossierAttributes' | 'deletedDocuments';
|
||||
|
||||
@Component({
|
||||
templateUrl: './edit-dossier-dialog.component.html',
|
||||
styleUrls: ['./edit-dossier-dialog.component.scss'],
|
||||
providers: [dossiersServiceProvider],
|
||||
})
|
||||
export class EditDossierDialogComponent extends BaseDialogComponent implements AfterViewInit {
|
||||
readonly navItems: { key: Section; title?: string; sideNavTitle?: string }[];
|
||||
@ -40,7 +42,7 @@ export class EditDossierDialogComponent extends BaseDialogComponent implements A
|
||||
|
||||
constructor(
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _activeDossiersService: DossiersService,
|
||||
private readonly _changeRef: ChangeDetectorRef,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
|
||||
@ -1,12 +1,12 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit } from '@angular/core';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { ActiveDossiersService } from '@services/entity-services/active-dossiers.service';
|
||||
import { Dossier, IDossierRequest } from '@red/domain';
|
||||
import { AutoUnsubscribe } from '@iqser/common-ui';
|
||||
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
|
||||
import { BehaviorSubject, firstValueFrom } from 'rxjs';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-edit-dossier-team',
|
||||
@ -28,7 +28,7 @@ export class EditDossierTeamComponent extends AutoUnsubscribe implements EditDos
|
||||
constructor(
|
||||
readonly userService: UserService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
) {
|
||||
super();
|
||||
@ -91,7 +91,7 @@ export class EditDossierTeamComponent extends AutoUnsubscribe implements EditDos
|
||||
ownerId: this.selectedOwnerId,
|
||||
} as IDossierRequest;
|
||||
|
||||
const updatedDossier = await firstValueFrom(this._activeDossiersService.createOrUpdate(dossier));
|
||||
const updatedDossier = await firstValueFrom(this._dossiersService.createOrUpdate(dossier));
|
||||
return { success: !!updatedDossier };
|
||||
}
|
||||
|
||||
|
||||
@ -10,13 +10,13 @@ import { MatDialogRef } from '@angular/material/dialog';
|
||||
import { EditDossierDialogComponent } from '../edit-dossier-dialog.component';
|
||||
import { ConfirmationDialogInput, IconButtonTypes, TitleColors, Toaster } from '@iqser/common-ui';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { ActiveDossiersService } from '@services/entity-services/active-dossiers.service';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { DossierStatsService } from '@services/entity-services/dossier-stats.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { DossierStateService } from '@services/entity-services/dossier-state.service';
|
||||
import { DOSSIER_TEMPLATE_ID } from '@utils/constants';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-edit-dossier-general-info',
|
||||
@ -38,7 +38,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
readonly permissionsService: PermissionsService,
|
||||
private readonly _dossierStateService: DossierStateService,
|
||||
private readonly _dossierTemplatesService: DossierTemplatesService,
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _dossierStatsService: DossierStatsService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _dialogService: DossiersDialogService,
|
||||
@ -120,7 +120,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
dossierStatusId: this.form.get('dossierStatusId').value,
|
||||
} as IDossierRequest;
|
||||
|
||||
const updatedDossier = await firstValueFrom(this._activeDossiersService.createOrUpdate(dossier));
|
||||
const updatedDossier = await firstValueFrom(this._dossiersService.createOrUpdate(dossier));
|
||||
return { success: !!updatedDossier };
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
|
||||
},
|
||||
});
|
||||
this._dialogService.openDialog('confirm', null, data, async () => {
|
||||
await firstValueFrom(this._activeDossiersService.delete(this.dossier));
|
||||
await firstValueFrom(this._dossiersService.delete(this.dossier));
|
||||
this._editDossierDialogRef.close();
|
||||
this._router.navigate(['main', 'dossiers']).then(() => this.#notifyDossierDeleted());
|
||||
});
|
||||
|
||||
@ -6,6 +6,7 @@ import { DossierFilesGuard } from '@guards/dossier-files-guard';
|
||||
import { CompositeRouteGuard } from '@iqser/common-ui';
|
||||
import { BreadcrumbTypes } from '@red/domain';
|
||||
import { DOSSIER_ID, FILE_ID } from '@utils/constants';
|
||||
import { ACTIVE_DOSSIERS_SERVICE } from '../../tokens';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@ -18,6 +19,7 @@ const routes: Routes = [
|
||||
data: {
|
||||
routeGuards: [DossierFilesGuard],
|
||||
breadcrumbs: [BreadcrumbTypes.main, BreadcrumbTypes.dossier],
|
||||
dossiersService: ACTIVE_DOSSIERS_SERVICE,
|
||||
},
|
||||
loadChildren: () => import('./screens/dossier-overview/dossier-overview.module').then(m => m.DossierOverviewModule),
|
||||
},
|
||||
@ -27,6 +29,7 @@ const routes: Routes = [
|
||||
data: {
|
||||
routeGuards: [DossierFilesGuard, FilePreviewGuard],
|
||||
breadcrumbs: [BreadcrumbTypes.main, BreadcrumbTypes.dossier, BreadcrumbTypes.file],
|
||||
dossiersService: ACTIVE_DOSSIERS_SERVICE,
|
||||
},
|
||||
loadChildren: () => import('./screens/file-preview-screen/file-preview.module').then(m => m.FilePreviewModule),
|
||||
},
|
||||
|
||||
@ -1,65 +1,33 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { AddDossierDialogComponent } from './dialogs/add-dossier-dialog/add-dossier-dialog.component';
|
||||
import { AssignReviewerApproverDialogComponent } from './dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component';
|
||||
import { ManualAnnotationDialogComponent } from './dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
|
||||
import { ForceAnnotationDialogComponent } from './dialogs/force-redaction-dialog/force-annotation-dialog.component';
|
||||
import { RemoveAnnotationsDialogComponent } from './dialogs/remove-annotations-dialog/remove-annotations-dialog.component';
|
||||
import { DocumentInfoDialogComponent } from './dialogs/document-info-dialog/document-info-dialog.component';
|
||||
import { SharedModule } from '@shared/shared.module';
|
||||
import { DossiersRoutingModule } from './dossiers-routing.module';
|
||||
import { FileUploadDownloadModule } from '@upload-download/file-upload-download.module';
|
||||
import { DossiersDialogService } from './services/dossiers-dialog.service';
|
||||
import { ManualAnnotationService } from './services/manual-annotation.service';
|
||||
import { AnnotationProcessingService } from './services/annotation-processing.service';
|
||||
import { EditDossierDialogComponent } from './dialogs/edit-dossier-dialog/edit-dossier-dialog.component';
|
||||
import { EditDossierGeneralInfoComponent } from './dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component';
|
||||
import { EditDossierDownloadPackageComponent } from './dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component';
|
||||
import { EditDossierDictionaryComponent } from './dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component';
|
||||
import { ChangeLegalBasisDialogComponent } from './dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component';
|
||||
import { RecategorizeImageDialogComponent } from './dialogs/recategorize-image-dialog/recategorize-image-dialog.component';
|
||||
import { EditDossierAttributesComponent } from './dialogs/edit-dossier-dialog/attributes/edit-dossier-attributes.component';
|
||||
import { SearchScreenComponent } from './screens/search-screen/search-screen.component';
|
||||
import { EditDossierDeletedDocumentsComponent } from './dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component';
|
||||
import { 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,
|
||||
ResizeAnnotationDialogComponent,
|
||||
DocumentInfoDialogComponent,
|
||||
AssignReviewerApproverDialogComponent,
|
||||
ChangeLegalBasisDialogComponent,
|
||||
RecategorizeImageDialogComponent,
|
||||
];
|
||||
|
||||
const components = [
|
||||
EditDossierGeneralInfoComponent,
|
||||
EditDossierDownloadPackageComponent,
|
||||
EditDossierDictionaryComponent,
|
||||
EditDossierAttributesComponent,
|
||||
EditDossierTeamComponent,
|
||||
EditDossierDeletedDocumentsComponent,
|
||||
|
||||
...screens,
|
||||
...dialogs,
|
||||
];
|
||||
|
||||
const services = [DossiersDialogService, ManualAnnotationService, AnnotationProcessingService];
|
||||
const components = [...screens, ...dialogs];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components],
|
||||
providers: [...services],
|
||||
imports: [CommonModule, SharedModule, SharedDossiersModule, FileUploadDownloadModule, DossiersRoutingModule, OverlayModule],
|
||||
})
|
||||
export class DossiersModule {}
|
||||
|
||||
@ -6,7 +6,6 @@ import { FilterService, ProgressBarConfigModel, shareLast, Toaster } from '@iqse
|
||||
import { workflowFileStatusTranslations } from '../../../../translations/file-status-translations';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { Dossier, DossierAttributeWithValue, DossierStats, IDossierRequest, StatusSorter, User } from '@red/domain';
|
||||
import { ActiveDossiersService } from '@services/entity-services/active-dossiers.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
import { DossierStatsService } from '@services/entity-services/dossier-stats.service';
|
||||
@ -14,6 +13,7 @@ import { map, pluck, switchMap } from 'rxjs/operators';
|
||||
import { DossiersDialogService } from '../../../../services/dossiers-dialog.service';
|
||||
import { FilesService } from '@services/entity-services/files.service';
|
||||
import { DOSSIER_ID } from '@utils/constants';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dossier-details',
|
||||
@ -37,19 +37,19 @@ export class DossierDetailsComponent {
|
||||
statusConfig$: Observable<ProgressBarConfigModel[]>;
|
||||
|
||||
constructor(
|
||||
readonly activeDossiersService: ActiveDossiersService,
|
||||
readonly translateChartService: TranslateChartService,
|
||||
readonly filterService: FilterService,
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _changeDetectorRef: ChangeDetectorRef,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _filesService: FilesService,
|
||||
private readonly _dossierStatsService: DossierStatsService,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _dialogService: DossiersDialogService,
|
||||
activatedRoute: ActivatedRoute,
|
||||
private readonly _activatedRoute: ActivatedRoute,
|
||||
) {
|
||||
this.dossierId = activatedRoute.snapshot.paramMap.get(DOSSIER_ID);
|
||||
this.dossier$ = this.activeDossiersService.getEntityChanged$(this.dossierId).pipe(shareLast());
|
||||
this.dossierId = _activatedRoute.snapshot.paramMap.get(DOSSIER_ID);
|
||||
this.dossier$ = this._dossiersService.getEntityChanged$(this.dossierId).pipe(shareLast());
|
||||
this.dossierStats$ = this.dossier$.pipe(
|
||||
pluck('dossierId'),
|
||||
switchMap(dossierId => this._dossierStatsService.watch$(dossierId)),
|
||||
@ -65,7 +65,7 @@ export class DossierDetailsComponent {
|
||||
async assignOwner(user: User | string, dossier: Dossier) {
|
||||
const owner = typeof user === 'string' ? this._userService.find(user) : user;
|
||||
const dossierRequest: IDossierRequest = { ...dossier, ownerId: owner.id };
|
||||
await firstValueFrom(this.activeDossiersService.createOrUpdate(dossierRequest));
|
||||
await firstValueFrom(this._dossiersService.createOrUpdate(dossierRequest));
|
||||
|
||||
const ownerName = this._userService.getNameForId(owner.id);
|
||||
const dossierName = dossier.dossierName;
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { File } from '@red/domain';
|
||||
import { ActiveDossiersService } from '@services/entity-services/active-dossiers.service';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-file-workload',
|
||||
@ -16,7 +16,7 @@ export class FileWorkloadComponent {
|
||||
constructor(
|
||||
readonly userService: UserService,
|
||||
private readonly _dictionariesMapService: DictionariesMapService,
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _dossiersService: DossiersService,
|
||||
) {}
|
||||
|
||||
get suggestionColor() {
|
||||
@ -44,9 +44,7 @@ export class FileWorkloadComponent {
|
||||
}
|
||||
|
||||
private _getDictionaryColor(type: string) {
|
||||
return this._dictionariesMapService.getDictionaryColor(
|
||||
type,
|
||||
this._activeDossiersService.find(this.file.dossierId).dossierTemplateId,
|
||||
);
|
||||
const dossierTemplateId = this._dossiersService.find(this.file.dossierId).dossierTemplateId;
|
||||
return this._dictionariesMapService.getDictionaryColor(type, dossierTemplateId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +164,7 @@ export class ConfigService {
|
||||
checkedRequiredFilters: () => NestedFilter[],
|
||||
checkedNotRequiredFilters: () => NestedFilter[],
|
||||
) {
|
||||
const allDistinctWorkflowFileStatuses = new Set<string>();
|
||||
const allDistinctWorkflowFileStatuses = new Set<WorkflowFileStatus>();
|
||||
const allDistinctPeople = new Set<string>();
|
||||
const allDistinctAddedDates = new Set<string>();
|
||||
const allDistinctNeedsWork = new Set<string>();
|
||||
@ -328,7 +328,9 @@ export class ConfigService {
|
||||
}
|
||||
|
||||
_recentlyModifiedChecker = (file: File) =>
|
||||
moment(file.lastUpdated).add(this._appConfigService.values.RECENT_PERIOD_IN_HOURS, 'hours').isAfter(moment());
|
||||
moment(file.lastUpdated)
|
||||
.add(this._appConfigService.values.RECENT_PERIOD_IN_HOURS as number, 'hours')
|
||||
.isAfter(moment());
|
||||
|
||||
_assignedToMeChecker = (file: File) => file.assignee === this._userService.currentUser.id;
|
||||
|
||||
|
||||
@ -9,7 +9,6 @@ import { DossierOverviewBulkActionsComponent } from './components/bulk-actions/d
|
||||
import { DossierDetailsComponent } from './components/dossier-details/dossier-details.component';
|
||||
import { DossierDetailsStatsComponent } from './components/dossier-details-stats/dossier-details-stats.component';
|
||||
import { TableItemComponent } from './components/table-item/table-item.component';
|
||||
import { ConfigService } from './config.service';
|
||||
import { SharedDossiersModule } from '../../shared/shared-dossiers.module';
|
||||
import { FileWorkloadComponent } from './components/table-item/file-workload/file-workload.component';
|
||||
import { FileStatsComponent } from './components/file-stats/file-stats.component';
|
||||
@ -18,7 +17,6 @@ import { ScreenHeaderComponent } from './components/screen-header/screen-header.
|
||||
import { ViewModeSelectionComponent } from './components/view-mode-selection/view-mode-selection.component';
|
||||
import { FileNameColumnComponent } from './components/table-item/file-name-column/file-name-column.component';
|
||||
import { DateColumnComponent } from './components/table-item/date-column/date-column.component';
|
||||
import { BulkActionsService } from './services/bulk-actions.service';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@ -46,7 +44,6 @@ const routes: Routes = [
|
||||
FileNameColumnComponent,
|
||||
DateColumnComponent,
|
||||
],
|
||||
providers: [ConfigService, BulkActionsService],
|
||||
imports: [RouterModule.forChild(routes), CommonModule, SharedModule, SharedDossiersModule, IqserIconsModule, TranslateModule],
|
||||
})
|
||||
export class DossierOverviewModule {}
|
||||
|
||||
@ -38,18 +38,26 @@ import { PermissionsService } from '@services/permissions.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { FileAttributesService } from '@services/entity-services/file-attributes.service';
|
||||
import { ConfigService } from '../config.service';
|
||||
import { ActiveDossiersService } from '@services/entity-services/active-dossiers.service';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { LongPressEvent } from '@shared/directives/long-press.directive';
|
||||
import { UserPreferenceService } from '@services/user-preference.service';
|
||||
import { FilesMapService } from '@services/entity-services/files-map.service';
|
||||
import { FilesService } from '@services/entity-services/files.service';
|
||||
import { DOSSIER_ID } from '@utils/constants';
|
||||
import { BulkActionsService } from '../services/bulk-actions.service';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
import { dossiersServiceProvider } from '@services/entity-services/dossiers.service.provider';
|
||||
|
||||
@Component({
|
||||
templateUrl: './dossier-overview-screen.component.html',
|
||||
styleUrls: ['./dossier-overview-screen.component.scss'],
|
||||
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DossierOverviewScreenComponent) }],
|
||||
providers: [
|
||||
...DefaultListingServices,
|
||||
ConfigService,
|
||||
BulkActionsService,
|
||||
{ provide: ListingComponent, useExisting: forwardRef(() => DossierOverviewScreenComponent) },
|
||||
dossiersServiceProvider,
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DossierOverviewScreenComponent extends ListingComponent<File> implements OnInit, OnDestroy, OnAttach {
|
||||
@ -77,8 +85,8 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
|
||||
constructor(
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _router: Router,
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _dossierTemplatesService: DossierTemplatesService,
|
||||
private readonly _fileUploadService: FileUploadService,
|
||||
private readonly _filesService: FilesService,
|
||||
@ -89,16 +97,16 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
|
||||
private readonly _userPreferenceService: UserPreferenceService,
|
||||
private readonly _fileMapService: FilesMapService,
|
||||
private readonly _errorService: ErrorService,
|
||||
private readonly _route: ActivatedRoute,
|
||||
readonly permissionsService: PermissionsService,
|
||||
readonly configService: ConfigService,
|
||||
readonly activatedRoute: ActivatedRoute,
|
||||
) {
|
||||
super(_injector);
|
||||
this.dossierId = activatedRoute.snapshot.paramMap.get(DOSSIER_ID);
|
||||
this.dossier$ = this._activeDossiersService
|
||||
this.dossierId = _route.snapshot.paramMap.get(DOSSIER_ID);
|
||||
this.dossier$ = this._dossiersService
|
||||
.getEntityChanged$(this.dossierId)
|
||||
.pipe(tap(dossier => (this.dossierTemplateId = dossier.dossierTemplateId)));
|
||||
this.currentDossier = this._activeDossiersService.find(this.dossierId);
|
||||
this.currentDossier = this._dossiersService.find(this.dossierId);
|
||||
this._updateFileAttributes();
|
||||
}
|
||||
|
||||
@ -133,7 +141,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
|
||||
this._computeAllFilters();
|
||||
});
|
||||
|
||||
this.addSubscription = this._activeDossiersService.dossierFileChanges$
|
||||
this.addSubscription = this._dossiersService.dossierFileChanges$
|
||||
.pipe(
|
||||
filter(dossierId => dossierId === this.dossierId),
|
||||
switchMap(dossierId => this._filesService.loadAll(dossierId)),
|
||||
@ -176,7 +184,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
|
||||
|
||||
@HostListener('drop', ['$event'])
|
||||
onDrop(event: DragEvent): void {
|
||||
const currentDossier = this._activeDossiersService.find(this.dossierId);
|
||||
const currentDossier = this._dossiersService.find(this.dossierId);
|
||||
handleFileDrop(event, currentDossier, this._uploadFiles.bind(this));
|
||||
}
|
||||
|
||||
@ -192,7 +200,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
|
||||
}
|
||||
|
||||
private _setRemovableSubscriptions(): void {
|
||||
this.addActiveScreenSubscription = this._activeDossiersService
|
||||
this.addActiveScreenSubscription = this._dossiersService
|
||||
.getEntityDeleted$(this.dossierId)
|
||||
.pipe(tap(() => this._handleDeletedDossier()))
|
||||
.subscribe();
|
||||
@ -214,7 +222,7 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
|
||||
}
|
||||
|
||||
private _loadEntitiesFromState() {
|
||||
this.currentDossier = this._activeDossiersService.find(this.dossierId);
|
||||
this.currentDossier = this._dossiersService.find(this.dossierId);
|
||||
this._computeAllFilters();
|
||||
}
|
||||
|
||||
|
||||
@ -10,6 +10,8 @@ import { FilePreviewStateService } from './services/file-preview-state.service';
|
||||
import { PdfViewerDataService } from '../../services/pdf-viewer-data.service';
|
||||
import { AnnotationReferencesService } from './services/annotation-references.service';
|
||||
import { FilterService } from '@iqser/common-ui';
|
||||
import { ManualAnnotationService } from '../../services/manual-annotation.service';
|
||||
import { AnnotationProcessingService } from '../../services/annotation-processing.service';
|
||||
|
||||
export const filePreviewScreenProviders = [
|
||||
FilterService,
|
||||
@ -24,4 +26,6 @@ export const filePreviewScreenProviders = [
|
||||
FilePreviewStateService,
|
||||
PdfViewerDataService,
|
||||
AnnotationReferencesService,
|
||||
ManualAnnotationService,
|
||||
AnnotationProcessingService,
|
||||
];
|
||||
|
||||
@ -2,16 +2,43 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FileAssignService } from './services/file-assign.service';
|
||||
import { FileActionsComponent } from './components/file-actions/file-actions.component';
|
||||
import { IqserIconsModule } from '@iqser/common-ui';
|
||||
import { SharedModule } from '@shared/shared.module';
|
||||
import { RedactionImportService } from './services/redaction-import.service';
|
||||
import { DossiersDialogService } from '../services/dossiers-dialog.service';
|
||||
import { DocumentInfoDialogComponent } from '../dialogs/document-info-dialog/document-info-dialog.component';
|
||||
import { EditDossierDialogComponent } from '../dialogs/edit-dossier-dialog/edit-dossier-dialog.component';
|
||||
import { AddDossierDialogComponent } from '../dialogs/add-dossier-dialog/add-dossier-dialog.component';
|
||||
import { ConfirmArchiveDossierDialogComponent } from '../dialogs/confirm-archive-dossier-dialog/confirm-archive-dossier-dialog.component';
|
||||
import { AssignReviewerApproverDialogComponent } from '../dialogs/assign-reviewer-approver-dialog/assign-reviewer-approver-dialog.component';
|
||||
import { EditDossierGeneralInfoComponent } from '../dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component';
|
||||
import { EditDossierDownloadPackageComponent } from '../dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component';
|
||||
import { EditDossierDictionaryComponent } from '../dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component';
|
||||
import { EditDossierAttributesComponent } from '../dialogs/edit-dossier-dialog/attributes/edit-dossier-attributes.component';
|
||||
import { EditDossierTeamComponent } from '../dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component';
|
||||
import { EditDossierDeletedDocumentsComponent } from '../dialogs/edit-dossier-dialog/deleted-documents/edit-dossier-deleted-documents.component';
|
||||
|
||||
const components = [FileActionsComponent];
|
||||
const components = [
|
||||
FileActionsComponent,
|
||||
DocumentInfoDialogComponent,
|
||||
EditDossierGeneralInfoComponent,
|
||||
EditDossierDownloadPackageComponent,
|
||||
EditDossierDictionaryComponent,
|
||||
EditDossierAttributesComponent,
|
||||
EditDossierTeamComponent,
|
||||
EditDossierDeletedDocumentsComponent,
|
||||
];
|
||||
const dialogs = [
|
||||
EditDossierDialogComponent,
|
||||
AddDossierDialogComponent,
|
||||
ConfirmArchiveDossierDialogComponent,
|
||||
AssignReviewerApproverDialogComponent,
|
||||
];
|
||||
const services = [DossiersDialogService, FileAssignService, RedactionImportService];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components],
|
||||
exports: [...components],
|
||||
providers: [FileAssignService, RedactionImportService],
|
||||
imports: [CommonModule, IqserIconsModule, SharedModule],
|
||||
declarations: [...components, ...dialogs],
|
||||
exports: [...components, ...dialogs],
|
||||
providers: [...services],
|
||||
imports: [CommonModule, SharedModule],
|
||||
})
|
||||
export class SharedDossiersModule {}
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { List } from '@iqser/common-ui';
|
||||
import { ActivatedRouteSnapshot, IsActiveMatchOptions, NavigationEnd, Router } from '@angular/router';
|
||||
import { BehaviorSubject, Observable, of } from 'rxjs';
|
||||
import { filter, pluck } from 'rxjs/operators';
|
||||
import { FilesMapService } from '@services/entity-services/files-map.service';
|
||||
import { ActiveDossiersService } from './entity-services/active-dossiers.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { BreadcrumbTypes } from '@red/domain';
|
||||
import { DOSSIER_ID, FILE_ID } from '@utils/constants';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
import { dossiersServiceResolver } from '@services/entity-services/dossiers.service.provider';
|
||||
|
||||
export type RouterLinkActiveOptions = { exact: boolean } | IsActiveMatchOptions;
|
||||
export type BreadcrumbDisplayType = 'text' | 'dropdown';
|
||||
@ -34,10 +35,10 @@ export class BreadcrumbsService {
|
||||
private readonly _store$ = new BehaviorSubject<Breadcrumbs>([]);
|
||||
|
||||
constructor(
|
||||
private readonly _injector: Injector,
|
||||
private readonly _router: Router,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _filesMapService: FilesMapService,
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
) {
|
||||
this.breadcrumbs$ = this._store$.asObservable();
|
||||
|
||||
@ -52,6 +53,10 @@ export class BreadcrumbsService {
|
||||
return this._store$.value;
|
||||
}
|
||||
|
||||
private get _dossiersService(): DossiersService {
|
||||
return dossiersServiceResolver(this._injector);
|
||||
}
|
||||
|
||||
private get _mainBreadcrumb(): Breadcrumb {
|
||||
return {
|
||||
name$: of(this._translateService.instant('top-bar.navigation-items.dossiers')),
|
||||
@ -135,12 +140,13 @@ export class BreadcrumbsService {
|
||||
}
|
||||
|
||||
private _addDossierBreadcrumb(route: ActivatedRouteSnapshot): void {
|
||||
const dossiersService = this._dossiersService;
|
||||
const dossierId = route.paramMap.get(DOSSIER_ID);
|
||||
this._append({
|
||||
name$: this._activeDossiersService.getEntityChanged$(dossierId).pipe(pluck('dossierName')),
|
||||
name$: dossiersService.getEntityChanged$(dossierId).pipe(pluck('dossierName')),
|
||||
type: 'text' as BreadcrumbDisplayType,
|
||||
options: {
|
||||
routerLink: ['/main', 'dossiers', dossierId],
|
||||
routerLink: ['/main', dossiersService.routerPath, dossierId],
|
||||
routerLinkActiveOptions: { exact: true },
|
||||
clamp: true,
|
||||
},
|
||||
@ -150,11 +156,12 @@ export class BreadcrumbsService {
|
||||
private _addFileBreadcrumb(route: ActivatedRouteSnapshot): void {
|
||||
const dossierId = route.paramMap.get(DOSSIER_ID);
|
||||
const fileId = route.paramMap.get(FILE_ID);
|
||||
const dossiersService = this._dossiersService;
|
||||
this._append({
|
||||
name$: this._filesMapService.watch$(dossierId, fileId).pipe(pluck('filename')),
|
||||
type: 'text' as BreadcrumbDisplayType,
|
||||
options: {
|
||||
routerLink: ['/main', 'dossiers', dossierId, 'file', fileId],
|
||||
routerLink: ['/main', dossiersService.routerPath, dossierId, 'file', fileId],
|
||||
clamp: true,
|
||||
},
|
||||
});
|
||||
|
||||
@ -1,10 +1,9 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { List, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
|
||||
import { Dossier, DossierStats, IDossier, IDossierRequest } from '@red/domain';
|
||||
import { catchError, filter, map, mapTo, pluck, switchMap, tap } from 'rxjs/operators';
|
||||
import { firstValueFrom, forkJoin, Observable, of, Subject, throwError, timer } from 'rxjs';
|
||||
import { List, QueryParam, RequiredParam, Validate } from '@iqser/common-ui';
|
||||
import { Dossier, IDossier } from '@red/domain';
|
||||
import { catchError, switchMap, tap } from 'rxjs/operators';
|
||||
import { firstValueFrom, Observable, of, timer } from 'rxjs';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
|
||||
import { CHANGED_CHECK_INTERVAL } from '@utils/constants';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
|
||||
@ -13,78 +12,21 @@ export interface IDossiersStats {
|
||||
totalAnalyzedPages: number;
|
||||
}
|
||||
|
||||
interface DossierChange {
|
||||
readonly dossierChanges: boolean;
|
||||
readonly dossierId: string;
|
||||
readonly fileChanges: boolean;
|
||||
}
|
||||
|
||||
type DossierChanges = readonly DossierChange[];
|
||||
|
||||
interface ChangesDetails {
|
||||
readonly dossierChanges: DossierChanges;
|
||||
}
|
||||
|
||||
const DOSSIER_EXISTS_MSG = _('add-dossier-dialog.errors.dossier-already-exists');
|
||||
const GENERIC_MSG = _('add-dossier-dialog.errors.generic');
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class ActiveDossiersService extends DossiersService {
|
||||
readonly dossierFileChanges$ = new Subject<string>();
|
||||
|
||||
constructor(private readonly _toaster: Toaster, protected readonly _injector: Injector) {
|
||||
super(_injector, 'dossier');
|
||||
constructor(protected readonly _injector: Injector) {
|
||||
super(_injector, 'dossier', 'dossiers');
|
||||
|
||||
timer(CHANGED_CHECK_INTERVAL, CHANGED_CHECK_INTERVAL)
|
||||
.pipe(
|
||||
switchMap(() => this.loadOnlyChanged()),
|
||||
tap(changes => this.#emitFileChanges(changes)),
|
||||
tap(changes => this._emitFileChanges(changes)),
|
||||
)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
loadOnlyChanged(): Observable<DossierChanges> {
|
||||
const removeIfNotFound = (id: string) =>
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
if (error.status === HttpStatusCode.NotFound) {
|
||||
this.remove(id);
|
||||
return of([]);
|
||||
}
|
||||
return throwError(() => error);
|
||||
});
|
||||
|
||||
const load = (changes: DossierChanges) =>
|
||||
changes.map(change => this._load(change.dossierId).pipe(removeIfNotFound(change.dossierId)));
|
||||
|
||||
return this.hasChangesDetails$().pipe(
|
||||
pluck('dossierChanges'),
|
||||
switchMap(dossierChanges => forkJoin(load(dossierChanges)).pipe(mapTo(dossierChanges))),
|
||||
tap(() => this._updateLastChanged()),
|
||||
);
|
||||
}
|
||||
|
||||
hasChangesDetails$(): Observable<ChangesDetails> {
|
||||
const body = { value: this._lastCheckedForChanges.get('root') ?? '0' };
|
||||
return this._post<ChangesDetails>(body, `${this._defaultModelPath}/changes/details`).pipe(
|
||||
filter(changes => changes.dossierChanges.length > 0),
|
||||
);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
createOrUpdate(@RequiredParam() dossier: IDossierRequest): Observable<Dossier | undefined> {
|
||||
const showToast = (error: HttpErrorResponse) => {
|
||||
this._toaster.error(error.status === HttpStatusCode.Conflict ? DOSSIER_EXISTS_MSG : GENERIC_MSG);
|
||||
return of(undefined);
|
||||
};
|
||||
|
||||
return this._post(dossier).pipe(
|
||||
switchMap(newDossier => this.loadAll().pipe(map(() => this.find(newDossier.dossierId)))),
|
||||
catchError(showToast),
|
||||
);
|
||||
}
|
||||
|
||||
getDeleted(): Promise<IDossier[]> {
|
||||
return firstValueFrom(this.getAll('deleted-dossiers'));
|
||||
}
|
||||
@ -118,16 +60,4 @@ export class ActiveDossiersService extends DossiersService {
|
||||
#removeDossiers(dossiers: Dossier[]): void {
|
||||
this.setEntities(this.all.filter(dossier => !dossiers.find(d => dossier.id === d.id)));
|
||||
}
|
||||
|
||||
private _load(id: string, queryParams?: List<QueryParam>): Observable<DossierStats[]> {
|
||||
return super._getOne([id], this._defaultModelPath, queryParams).pipe(
|
||||
map(entity => new Dossier(entity)),
|
||||
tap(dossier => this.replace(dossier)),
|
||||
switchMap(dossier => this._dossierStatsService.getFor([dossier.dossierId])),
|
||||
);
|
||||
}
|
||||
|
||||
#emitFileChanges(dossierChanges: DossierChanges): void {
|
||||
dossierChanges.filter(change => change.fileChanges).forEach(change => this.dossierFileChanges$.next(change.dossierId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { Toaster } from '@iqser/common-ui';
|
||||
import { Dossier } from '@red/domain';
|
||||
import { catchError, tap } from 'rxjs/operators';
|
||||
import { Observable, of } from 'rxjs';
|
||||
@ -9,12 +8,8 @@ import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class ArchivedDossiersService extends DossiersService {
|
||||
constructor(
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
) {
|
||||
super(_injector, 'archived-dossiers');
|
||||
constructor(protected readonly _injector: Injector, private readonly _activeDossiersService: ActiveDossiersService) {
|
||||
super(_injector, 'archived-dossiers', 'archive');
|
||||
}
|
||||
|
||||
archive(dossiers: Dossier[]): Observable<unknown> {
|
||||
@ -26,14 +21,13 @@ export class ArchivedDossiersService extends DossiersService {
|
||||
dossiers.map(d => d.id),
|
||||
`${this._defaultModelPath}/archive`,
|
||||
).pipe(
|
||||
tap(() => this.#removeDossiers(dossiers)),
|
||||
tap(() => this.#removeFromActiveDossiers(dossiers)),
|
||||
catchError(showToast),
|
||||
);
|
||||
}
|
||||
|
||||
#removeDossiers(dossiers: Dossier[]): void {
|
||||
this._activeDossiersService.setEntities(
|
||||
this._activeDossiersService.all.filter(dossier => !dossiers.find(d => dossier.id === d.id)),
|
||||
);
|
||||
#removeFromActiveDossiers(dossiers: Dossier[]): void {
|
||||
const remainingEntities = this._activeDossiersService.all.filter(dossier => !dossiers.find(d => dossier.id === d.id));
|
||||
this._activeDossiersService.setEntities(remainingEntities);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,15 @@
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Injector, ProviderToken } from '@angular/core';
|
||||
import { DossiersService } from './dossiers.service';
|
||||
|
||||
export const dossiersServiceResolver = (injector: Injector) => {
|
||||
const route = injector.get<ActivatedRoute>(ActivatedRoute);
|
||||
const token: ProviderToken<DossiersService> = (route.firstChild || route).snapshot.data.dossiersService;
|
||||
return injector.get<DossiersService>(token);
|
||||
};
|
||||
|
||||
export const dossiersServiceProvider = {
|
||||
provide: DossiersService,
|
||||
useFactory: dossiersServiceResolver,
|
||||
deps: [Injector],
|
||||
};
|
||||
@ -1,25 +1,84 @@
|
||||
import { EntitiesService, List, mapEach, shareLast } from '@iqser/common-ui';
|
||||
import { Dossier, IDossier } from '@red/domain';
|
||||
import { combineLatest, Observable } from 'rxjs';
|
||||
import { filter, map, mapTo, switchMap, tap } from 'rxjs/operators';
|
||||
import { EntitiesService, List, mapEach, QueryParam, RequiredParam, shareLast, Toaster, Validate } from '@iqser/common-ui';
|
||||
import { Dossier, DossierStats, IDossier, IDossierRequest } from '@red/domain';
|
||||
import { combineLatest, forkJoin, Observable, of, Subject, throwError } from 'rxjs';
|
||||
import { catchError, filter, map, mapTo, pluck, switchMap, tap } from 'rxjs/operators';
|
||||
import { Injector } from '@angular/core';
|
||||
import { DossierStateService } from './dossier-state.service';
|
||||
import { DossierStatsService } from './dossier-stats.service';
|
||||
import { IDossiersStats } from '@services/entity-services/active-dossiers.service';
|
||||
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
|
||||
interface DossierChange {
|
||||
readonly dossierChanges: boolean;
|
||||
readonly dossierId: string;
|
||||
readonly fileChanges: boolean;
|
||||
}
|
||||
|
||||
type DossierChanges = readonly DossierChange[];
|
||||
|
||||
interface ChangesDetails {
|
||||
readonly dossierChanges: DossierChanges;
|
||||
}
|
||||
|
||||
const DOSSIER_EXISTS_MSG = _('add-dossier-dialog.errors.dossier-already-exists');
|
||||
const GENERIC_MSG = _('add-dossier-dialog.errors.generic');
|
||||
|
||||
export abstract class DossiersService extends EntitiesService<Dossier, IDossier> {
|
||||
readonly dossierFileChanges$ = new Subject<string>();
|
||||
readonly generalStats$ = this.all$.pipe(switchMap(entities => this.#generalStats$(entities)));
|
||||
protected readonly _dossierStatsService = this._injector.get(DossierStatsService);
|
||||
protected readonly _dossierStateService = this._injector.get(DossierStateService);
|
||||
protected readonly _toaster = this._injector.get(Toaster);
|
||||
|
||||
protected constructor(protected readonly _injector: Injector, protected readonly _path: string) {
|
||||
protected constructor(protected readonly _injector: Injector, protected readonly _path: string, readonly routerPath: string) {
|
||||
super(_injector, Dossier, _path);
|
||||
}
|
||||
|
||||
@Validate()
|
||||
createOrUpdate(@RequiredParam() dossier: IDossierRequest): Observable<Dossier | undefined> {
|
||||
const showToast = (error: HttpErrorResponse) => {
|
||||
this._toaster.error(error.status === HttpStatusCode.Conflict ? DOSSIER_EXISTS_MSG : GENERIC_MSG);
|
||||
return of(undefined);
|
||||
};
|
||||
|
||||
return this._post(dossier, 'dossier').pipe(
|
||||
switchMap(newDossier => this.loadAll().pipe(map(() => this.find(newDossier.dossierId)))),
|
||||
catchError(showToast),
|
||||
);
|
||||
}
|
||||
|
||||
loadOnlyChanged(): Observable<DossierChanges> {
|
||||
const removeIfNotFound = (id: string) =>
|
||||
catchError((error: HttpErrorResponse) => {
|
||||
if (error.status === HttpStatusCode.NotFound) {
|
||||
this.remove(id);
|
||||
return of([]);
|
||||
}
|
||||
return throwError(() => error);
|
||||
});
|
||||
|
||||
const load = (changes: DossierChanges) =>
|
||||
changes.map(change => this._load(change.dossierId).pipe(removeIfNotFound(change.dossierId)));
|
||||
|
||||
return this.hasChangesDetails$().pipe(
|
||||
pluck('dossierChanges'),
|
||||
switchMap(dossierChanges => forkJoin(load(dossierChanges)).pipe(mapTo(dossierChanges))),
|
||||
tap(() => this._updateLastChanged()),
|
||||
);
|
||||
}
|
||||
|
||||
hasChangesDetails$(): Observable<ChangesDetails> {
|
||||
const body = { value: this._lastCheckedForChanges.get('root') ?? '0' };
|
||||
return this._post<ChangesDetails>(body, `${this._defaultModelPath}/changes/details`).pipe(
|
||||
filter(changes => changes.dossierChanges.length > 0),
|
||||
);
|
||||
}
|
||||
|
||||
loadAll(): Observable<Dossier[]> {
|
||||
const dossierIds = (dossiers: Dossier[]) => dossiers.map(d => d.id);
|
||||
return this.getAll().pipe(
|
||||
mapEach(entity => new Dossier(entity)),
|
||||
mapEach(entity => new Dossier(entity, this.routerPath)),
|
||||
/* Load stats before updating entities */
|
||||
switchMap(dossiers => this._dossierStatsService.getFor(dossierIds(dossiers)).pipe(mapTo(dossiers))),
|
||||
switchMap(dossiers => this._dossierStateService.loadAllForAllTemplates().pipe(mapTo(dossiers))),
|
||||
@ -27,6 +86,18 @@ export abstract class DossiersService extends EntitiesService<Dossier, IDossier>
|
||||
);
|
||||
}
|
||||
|
||||
protected _emitFileChanges(dossierChanges: DossierChanges): void {
|
||||
dossierChanges.filter(change => change.fileChanges).forEach(change => this.dossierFileChanges$.next(change.dossierId));
|
||||
}
|
||||
|
||||
private _load(id: string, queryParams?: List<QueryParam>): Observable<DossierStats[]> {
|
||||
return super._getOne([id], this._defaultModelPath, queryParams).pipe(
|
||||
map(entity => new Dossier(entity, 'dossiers')),
|
||||
tap(dossier => this.replace(dossier)),
|
||||
switchMap(dossier => this._dossierStatsService.getFor([dossier.dossierId])),
|
||||
);
|
||||
}
|
||||
|
||||
#computeStats(entities: List<Dossier>): IDossiersStats {
|
||||
let totalAnalyzedPages = 0;
|
||||
const totalPeople = new Set<string>();
|
||||
|
||||
@ -1,13 +1,21 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { UserService } from './user.service';
|
||||
import { Dossier, File, IComment, IDossier } from '@red/domain';
|
||||
import { ActiveDossiersService } from './entity-services/active-dossiers.service';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { dossiersServiceResolver } from '@services/entity-services/dossiers.service.provider';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class PermissionsService {
|
||||
constructor(private readonly _userService: UserService, private readonly _activeDossiersService: ActiveDossiersService) {}
|
||||
constructor(
|
||||
private readonly _userService: UserService,
|
||||
private readonly _route: ActivatedRoute,
|
||||
private readonly _injector: Injector,
|
||||
) {}
|
||||
|
||||
private get _dossiersService(): DossiersService {
|
||||
return dossiersServiceResolver(this._injector);
|
||||
}
|
||||
|
||||
isReviewerOrApprover(file: File): boolean {
|
||||
const dossier = this._getDossier(file);
|
||||
@ -228,6 +236,6 @@ export class PermissionsService {
|
||||
}
|
||||
|
||||
private _getDossier(file: File): Dossier {
|
||||
return this._activeDossiersService.find(file.dossierId);
|
||||
return this._dossiersService.find(file.dossierId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,7 +25,7 @@ export class Dossier implements IDossier, IListable {
|
||||
readonly archivedTime: string;
|
||||
readonly hasReviewers: boolean;
|
||||
|
||||
constructor(dossier: IDossier) {
|
||||
constructor(dossier: IDossier, readonly routerPath: string) {
|
||||
this.dossierId = dossier.dossierId;
|
||||
this.approverIds = dossier.approverIds;
|
||||
this.date = dossier.date;
|
||||
@ -53,7 +53,7 @@ export class Dossier implements IDossier, IListable {
|
||||
}
|
||||
|
||||
get routerLink(): string {
|
||||
return `/main/dossiers/${this.dossierId}`;
|
||||
return `/main/${this.routerPath}/${this.dossierId}`;
|
||||
}
|
||||
|
||||
get searchKey(): string {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user