View archived dossiers list, breadcrumbs WIP
This commit is contained in:
parent
84c4a128ef
commit
3d69d42150
@ -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,
|
||||
|
||||
@ -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, []);
|
||||
}
|
||||
|
||||
@ -9,16 +9,34 @@
|
||||
<mat-icon *ngIf="!first" svgIcon="iqser:arrow-right"></mat-icon>
|
||||
|
||||
<a
|
||||
[class.clamp]="breadcrumb.clamp"
|
||||
*ngIf="is(breadcrumb, 'text')"
|
||||
[class.clamp]="breadcrumb.options.clamp"
|
||||
[id]="first ? 'navigateToActiveDossiers' : ''"
|
||||
[matTooltip]="breadcrumb.clamp && (breadcrumb.name$ | async)"
|
||||
[routerLinkActiveOptions]="breadcrumb.routerLinkActiveOptions || { exact: false }"
|
||||
[routerLink]="breadcrumb.routerLink"
|
||||
[matTooltip]="breadcrumb.options.clamp && (breadcrumb.name$ | async)"
|
||||
[routerLinkActiveOptions]="breadcrumb.options.routerLinkActiveOptions || { exact: false }"
|
||||
[routerLink]="breadcrumb.options.routerLink"
|
||||
class="breadcrumb"
|
||||
routerLinkActive="active"
|
||||
>
|
||||
{{ breadcrumb.name$ | async }}
|
||||
</a>
|
||||
|
||||
<ng-container *ngIf="is(breadcrumb, 'dropdown')">
|
||||
<a [class.active]="breadcrumbs.length === 1" [matMenuTriggerFor]="dropdownMenu" class="breadcrumb">
|
||||
{{ breadcrumb.name$ | async }}
|
||||
</a>
|
||||
|
||||
<mat-menu #dropdownMenu="matMenu" class="padding-bottom-8">
|
||||
<a
|
||||
*ngFor="let option of breadcrumb.options.options"
|
||||
[routerLink]="option.options.routerLink"
|
||||
mat-menu-item
|
||||
routerLinkActive="active"
|
||||
>
|
||||
{{ option.name$ | async }}
|
||||
</a>
|
||||
</mat-menu>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
14
apps/red-ui/src/app/guards/archived-dossiers.guard.ts
Normal file
14
apps/red-ui/src/app/guards/archived-dossiers.guard.ts
Normal file
@ -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<boolean> {
|
||||
await firstValueFrom(this._archivedDossiersService.loadAll());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -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<DossierState> 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<DossierState>[] = [
|
||||
@ -40,6 +39,7 @@ export class DossierStatesListingScreenComponent extends ListingComponent<Dossie
|
||||
{ label: _('dossier-states-listing.table-col-names.dossiers-count'), sortByKey: 'dossierCount' },
|
||||
];
|
||||
chartData: DoughnutChartConfig[];
|
||||
readonly #dossierTemplateId: string;
|
||||
|
||||
constructor(
|
||||
protected readonly _injector: Injector,
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
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';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
pathMatch: 'full',
|
||||
component: ArchivedDossiersScreenComponent,
|
||||
data: { breadcrumbs: [BreadcrumbTypes.archive] },
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
})
|
||||
export class ArchiveRoutingModule {}
|
||||
18
apps/red-ui/src/app/modules/archive/archive.module.ts
Normal file
18
apps/red-ui/src/app/modules/archive/archive.module.ts
Normal file
@ -0,0 +1,18 @@
|
||||
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';
|
||||
|
||||
const components = [TableItemComponent];
|
||||
const screens = [ArchivedDossiersScreenComponent];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components, ...screens],
|
||||
imports: [CommonModule, ArchiveRoutingModule, SharedModule, CommonUiModule],
|
||||
providers: [ConfigService],
|
||||
})
|
||||
export class ArchiveModule {}
|
||||
@ -0,0 +1,13 @@
|
||||
<div class="cell">
|
||||
<redaction-dossiers-listing-dossier-name [dossierStats]="stats$ | async" [dossier]="dossier"></redaction-dossiers-listing-dossier-name>
|
||||
</div>
|
||||
|
||||
<div class="cell small-label">{{ dossier.archivedTime | date: 'd MMM. yyyy' }}</div>
|
||||
|
||||
<div class="cell user-column">
|
||||
<redaction-initials-avatar [user]="dossier.ownerId" [withName]="true"></redaction-initials-avatar>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<redaction-dossier-status [dossier]="dossier"></redaction-dossier-status>
|
||||
</div>
|
||||
@ -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<DossierStats>;
|
||||
readonly #ngOnChanges$ = new BehaviorSubject<string>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
<section>
|
||||
<iqser-page-header></iqser-page-header>
|
||||
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
<div class="content-inner">
|
||||
<div class="content-container">
|
||||
<iqser-table
|
||||
[itemSize]="80"
|
||||
[noDataText]="'archived-dossiers-listing.no-data.title' | translate"
|
||||
[noMatchText]="'archived-dossiers-listing.no-match.title' | translate"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
noDataIcon="red:folder"
|
||||
></iqser-table>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<ng-template #tableItemTemplate let-dossier="entity">
|
||||
<redaction-table-item [dossier]="dossier"></redaction-table-item>
|
||||
</ng-template>
|
||||
@ -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<Dossier> {
|
||||
readonly tableColumnConfigs = this._configService.tableConfig;
|
||||
readonly tableHeaderLabel = _('archived-dossiers-listing.table-header.title');
|
||||
|
||||
constructor(protected readonly _injector: Injector, private readonly _configService: ConfigService) {
|
||||
super(_injector);
|
||||
}
|
||||
}
|
||||
@ -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<Dossier>[] {
|
||||
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' },
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -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<ConfirmArchiveDossierDialogComponent>,
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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({
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
<ng-container *ngIf="dossier.dossierStatusId && currentState">
|
||||
<div class="flex-align-items-center dossier-status-container">
|
||||
<div class="dossier-status-text">{{ currentState.name }}</div>
|
||||
<redaction-small-chip [color]="currentState.color"></redaction-small-chip>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!dossier.dossierStatusId || !currentState">
|
||||
<div class="flex-align-items-center dossier-status-container">
|
||||
<div class="dossier-status-text">{{ 'edit-dossier-dialog.general-info.form.dossier-status.placeholder' | translate }}</div>
|
||||
<redaction-small-chip [color]="'#E2E4E9'"></redaction-small-chip>
|
||||
</div>
|
||||
</ng-container>
|
||||
@ -16,7 +16,7 @@
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<redaction-dossiers-listing-status [dossier]="dossier"></redaction-dossiers-listing-status>
|
||||
<redaction-dossier-status [dossier]="dossier"></redaction-dossier-status>
|
||||
|
||||
<redaction-dossiers-listing-actions [dossier]="dossier" [stats]="stats"></redaction-dossiers-listing-actions>
|
||||
</div>
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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],
|
||||
|
||||
@ -0,0 +1,6 @@
|
||||
<div class="flex-align-items-center dossier-status-container">
|
||||
<div class="dossier-status-text">
|
||||
{{ currentState?.name || ('edit-dossier-dialog.general-info.form.dossier-status.placeholder' | translate) }}
|
||||
</div>
|
||||
<redaction-small-chip [color]="currentState?.color || '#E2E4E9'"></redaction-small-chip>
|
||||
</div>
|
||||
@ -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;
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stats-subtitle">
|
||||
<div *ngIf="dossierStats" class="stats-subtitle">
|
||||
<div class="small-label">
|
||||
<mat-icon svgIcon="iqser:document"></mat-icon>
|
||||
{{ dossierStats.numberOfFiles }}
|
||||
@ -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;
|
||||
@ -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,
|
||||
];
|
||||
|
||||
@ -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<string>;
|
||||
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<Breadcrumb>;
|
||||
@ -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,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<Dossier, IDossier> {
|
||||
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<Dossier[]> {
|
||||
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<unknown> {
|
||||
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)));
|
||||
}
|
||||
}
|
||||
@ -118,20 +118,6 @@ export class DossiersService extends EntitiesService<Dossier, IDossier> {
|
||||
);
|
||||
}
|
||||
|
||||
archive(dossiers: Dossier[]): Observable<unknown> {
|
||||
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<unknown> {
|
||||
return firstValueFrom(this._post(dossierIds, 'deleted-dossiers/restore').pipe(switchMap(() => this.loadAll())));
|
||||
|
||||
@ -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": {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -21,4 +21,5 @@ export interface IDossier {
|
||||
readonly status: DossierStatus;
|
||||
readonly watermarkEnabled: boolean;
|
||||
readonly watermarkPreviewEnabled: boolean;
|
||||
readonly archivedTime: string;
|
||||
}
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user