Pull request #337: RED-2769 - dossier template info
Merge in RED/ui from RED-2769 to master * commit '8eab831a5b669bc3500aab637b6326b067bbecfd': Update common Update backend url Fix config Fix rebase: common Improvement Edit dossier template from info Dossier template info
This commit is contained in:
commit
f032e9d2d9
@ -9,7 +9,6 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { SpotlightSearchAction } from '@components/spotlight-search/spotlight-search-action';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { filter, map, startWith } from 'rxjs/operators';
|
||||
import { DossiersService } from '@services/entity-services/dossiers.service';
|
||||
import { shareDistinctLast } from '@iqser/common-ui';
|
||||
import { BreadcrumbsService } from '@services/breadcrumbs.service';
|
||||
|
||||
@ -77,7 +76,6 @@ export class BaseScreenComponent {
|
||||
|
||||
constructor(
|
||||
readonly appStateService: AppStateService,
|
||||
readonly dossiersService: DossiersService,
|
||||
readonly userService: UserService,
|
||||
readonly userPreferenceService: UserPreferenceService,
|
||||
readonly titleService: Title,
|
||||
|
||||
@ -3,7 +3,7 @@ import { RouterModule } from '@angular/router';
|
||||
import { CompositeRouteGuard } from '@iqser/common-ui';
|
||||
import { AuthGuard } from '../auth/auth.guard';
|
||||
import { RedRoleGuard } from '../auth/red-role.guard';
|
||||
import { AppStateGuard } from '../../state/app-state.guard';
|
||||
import { AppStateGuard } from '@state/app-state.guard';
|
||||
import { BaseAccountScreenComponent } from './base-account-screen/base-account-screen-component';
|
||||
|
||||
const routes = [
|
||||
|
||||
@ -5,8 +5,8 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { LoadingService } from '@iqser/common-ui';
|
||||
import { IProfile } from '@red/domain';
|
||||
import { languagesTranslations } from '../../../translations/languages-translations';
|
||||
import { PermissionsService } from '../../../../../services/permissions.service';
|
||||
import { UserService } from '../../../../../services/user.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { ConfigService } from '../../../../../services/config.service';
|
||||
import { LanguageService } from '../../../../../i18n/language.service';
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { GenericService } from '@iqser/common-ui';
|
||||
import { Observable, of } from 'rxjs';
|
||||
import { UserService } from '../../../services/user.service';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { EmailNotificationScheduleTypes, INotificationPreferences } from '@red/domain';
|
||||
import { catchError } from 'rxjs/operators';
|
||||
|
||||
@ -11,14 +11,6 @@ export class NotificationPreferencesService extends GenericService<INotification
|
||||
super(_injector, 'notification-preferences');
|
||||
}
|
||||
|
||||
get(): Observable<INotificationPreferences> {
|
||||
return super.get<INotificationPreferences>().pipe(catchError(() => of(this._defaultPreferences)));
|
||||
}
|
||||
|
||||
update(notificationPreferences: INotificationPreferences): Observable<void> {
|
||||
return super._post(notificationPreferences);
|
||||
}
|
||||
|
||||
private get _defaultPreferences(): INotificationPreferences {
|
||||
return {
|
||||
emailNotificationType: EmailNotificationScheduleTypes.INSTANT,
|
||||
@ -28,4 +20,12 @@ export class NotificationPreferencesService extends GenericService<INotification
|
||||
inAppNotificationsEnabled: true,
|
||||
};
|
||||
}
|
||||
|
||||
get(): Observable<INotificationPreferences> {
|
||||
return super.get<INotificationPreferences>().pipe(catchError(() => of(this._defaultPreferences)));
|
||||
}
|
||||
|
||||
update(notificationPreferences: INotificationPreferences): Observable<void> {
|
||||
return super._post(notificationPreferences);
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@ import { AuthGuard } from '../auth/auth.guard';
|
||||
import { CompositeRouteGuard } from '@iqser/common-ui';
|
||||
import { RedRoleGuard } from '../auth/red-role.guard';
|
||||
import { AppStateGuard } from '@state/app-state.guard';
|
||||
import { DossierTemplatesListingScreenComponent } from './screens/dossier-template-listing/dossier-templates-listing-screen.component';
|
||||
import { DictionaryListingScreenComponent } from './screens/dictionary-listing/dictionary-listing-screen.component';
|
||||
import { DictionaryOverviewScreenComponent } from './screens/dictionary-overview/dictionary-overview-screen.component';
|
||||
import { PendingChangesGuard } from '@guards/can-deactivate.guard';
|
||||
@ -21,6 +20,7 @@ import { DossierAttributesListingScreenComponent } from './screens/dossier-attri
|
||||
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';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: 'dossier-templates', pathMatch: 'full' },
|
||||
@ -29,15 +29,25 @@ const routes: Routes = [
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
component: DossierTemplatesListingScreenComponent,
|
||||
component: BaseAdminScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
|
||||
},
|
||||
loadChildren: () =>
|
||||
import('./screens/dossier-templates-listing/dossier-templates-listing.module').then(
|
||||
m => m.DossierTemplatesListingModule,
|
||||
),
|
||||
},
|
||||
{
|
||||
path: ':dossierTemplateId',
|
||||
children: [
|
||||
{
|
||||
path: 'info',
|
||||
canActivate: [CompositeRouteGuard],
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
loadChildren: () => import('./screens/info/dossier-template-info.module').then(m => m.DossierTemplateInfoModule),
|
||||
},
|
||||
{
|
||||
path: 'dictionaries',
|
||||
children: [
|
||||
@ -111,11 +121,11 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'justifications',
|
||||
component: BaseAdminScreenComponent,
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
loadChildren: () => import('./screens/justifications/justifications.module').then(m => m.JustificationsModule),
|
||||
},
|
||||
{ path: '', redirectTo: 'dictionaries', pathMatch: 'full' },
|
||||
{ path: '', redirectTo: 'info', pathMatch: 'full' },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@ -50,6 +50,7 @@ export class AdminSideNavComponent implements OnInit {
|
||||
},
|
||||
],
|
||||
dossierTemplates: [
|
||||
{ screen: 'info', label: _('dossier-template-info') },
|
||||
{ screen: 'dictionaries', label: _('dictionaries') },
|
||||
{
|
||||
screen: 'rules',
|
||||
|
||||
@ -3,7 +3,6 @@ import { CommonModule } from '@angular/common';
|
||||
import { AdminRoutingModule } from './admin-routing.module';
|
||||
import { RulesScreenComponent } from './screens/rules/rules-screen.component';
|
||||
import { SharedModule } from '@shared/shared.module';
|
||||
import { DossierTemplatesListingScreenComponent } from './screens/dossier-template-listing/dossier-templates-listing-screen.component';
|
||||
import { AuditScreenComponent } from './screens/audit/audit-screen.component';
|
||||
import { DefaultColorsScreenComponent } from './screens/default-colors/default-colors-screen.component';
|
||||
import { DictionaryListingScreenComponent } from './screens/dictionary-listing/dictionary-listing-screen.component';
|
||||
@ -13,8 +12,7 @@ import { FileAttributesListingScreenComponent } from './screens/file-attributes-
|
||||
import { LicenseInformationScreenComponent } from './screens/license-information/license-information-screen.component';
|
||||
import { UserListingScreenComponent } from './screens/user-listing/user-listing-screen.component';
|
||||
import { WatermarkScreenComponent } from './screens/watermark/watermark-screen.component';
|
||||
import { AdminBreadcrumbsComponent } from './components/breadcrumbs/admin-breadcrumbs.component';
|
||||
import { DossierTemplateActionsComponent } from './components/dossier-template-actions/dossier-template-actions.component';
|
||||
import { DossierTemplateBreadcrumbsComponent } from './components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component';
|
||||
import { ColorPickerModule } from 'ngx-color-picker';
|
||||
import { AddEditFileAttributeDialogComponent } from './dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component';
|
||||
import { AddEditDossierTemplateDialogComponent } from './dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component';
|
||||
@ -48,6 +46,8 @@ import { SmtpConfigService } from './services/smtp-config.service';
|
||||
import { UploadDictionaryDialogComponent } from './dialogs/upload-dictionary-dialog/upload-dictionary-dialog.component';
|
||||
import { GeneralConfigFormComponent } from './screens/general-config/general-config-form/general-config-form.component';
|
||||
import { SmtpFormComponent } from './screens/general-config/smtp-form/smtp-form.component';
|
||||
import { SharedAdminModule } from './shared/shared-admin.module';
|
||||
import { BaseDossierTemplateScreenComponent } from './base-dossier-templates-screen/base-dossier-template-screen.component';
|
||||
|
||||
const dialogs = [
|
||||
AddEditDossierTemplateDialogComponent,
|
||||
@ -64,7 +64,6 @@ const dialogs = [
|
||||
];
|
||||
|
||||
const screens = [
|
||||
DossierTemplatesListingScreenComponent,
|
||||
RulesScreenComponent,
|
||||
AuditScreenComponent,
|
||||
DefaultColorsScreenComponent,
|
||||
@ -82,8 +81,7 @@ const screens = [
|
||||
];
|
||||
|
||||
const components = [
|
||||
AdminBreadcrumbsComponent,
|
||||
DossierTemplateActionsComponent,
|
||||
DossierTemplateBreadcrumbsComponent,
|
||||
ComboChartComponent,
|
||||
ComboSeriesVerticalComponent,
|
||||
UsersStatsComponent,
|
||||
@ -92,14 +90,17 @@ const components = [
|
||||
ResetPasswordComponent,
|
||||
UserDetailsComponent,
|
||||
BaseAdminScreenComponent,
|
||||
BaseDossierTemplateScreenComponent,
|
||||
GeneralConfigFormComponent,
|
||||
SmtpFormComponent,
|
||||
|
||||
...dialogs,
|
||||
...screens,
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components, GeneralConfigFormComponent, SmtpFormComponent],
|
||||
declarations: [...components],
|
||||
providers: [AdminDialogService, AuditService, DigitalSignatureService, LicenseReportService, RulesService, SmtpConfigService],
|
||||
imports: [CommonModule, SharedModule, AdminRoutingModule, NgxChartsModule, ColorPickerModule, MonacoEditorModule],
|
||||
imports: [CommonModule, SharedModule, AdminRoutingModule, SharedAdminModule, NgxChartsModule, ColorPickerModule, MonacoEditorModule],
|
||||
})
|
||||
export class AdminModule {}
|
||||
|
||||
@ -1,26 +1,5 @@
|
||||
<!--TODO: This is only used for justifications for now, should be used for all admin screens-->
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs class="flex-1"></redaction-admin-breadcrumbs>
|
||||
<redaction-admin-side-nav type="settings"></redaction-admin-side-nav>
|
||||
|
||||
<div class="flex-1 actions">
|
||||
<redaction-dossier-template-actions></redaction-dossier-template-actions>
|
||||
|
||||
<iqser-circle-button
|
||||
[routerLink]="['../..']"
|
||||
[tooltip]="'common.close' | translate"
|
||||
icon="iqser:close"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-inner">
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
<redaction-admin-side-nav type="dossierTemplates"></redaction-admin-side-nav>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</section>
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
:host {
|
||||
display: flex;
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-base-admin-screen',
|
||||
templateUrl: './base-admin-screen.component.html',
|
||||
styleUrls: ['./base-admin-screen.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
|
||||
@ -0,0 +1,26 @@
|
||||
<!--TODO: Use this for all dossier template screens -->
|
||||
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
<div class="flex-1 actions">
|
||||
<redaction-dossier-template-actions></redaction-dossier-template-actions>
|
||||
|
||||
<iqser-circle-button
|
||||
[routerLink]="['../..']"
|
||||
[tooltip]="'common.close' | translate"
|
||||
icon="iqser:close"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-inner">
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
<redaction-admin-side-nav type="dossierTemplates"></redaction-admin-side-nav>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</section>
|
||||
@ -0,0 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
templateUrl: './base-dossier-template-screen.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class BaseDossierTemplateScreenComponent {}
|
||||
@ -1,21 +0,0 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { UserPreferenceService } from '@services/user-preference.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-admin-breadcrumbs',
|
||||
templateUrl: './admin-breadcrumbs.component.html',
|
||||
styleUrls: ['./admin-breadcrumbs.component.scss'],
|
||||
})
|
||||
export class AdminBreadcrumbsComponent {
|
||||
@Input() root = false;
|
||||
|
||||
constructor(
|
||||
readonly userPreferenceService: UserPreferenceService,
|
||||
readonly permissionService: PermissionsService,
|
||||
readonly appStateService: AppStateService,
|
||||
readonly dossierTemplatesService: DossierTemplatesService,
|
||||
) {}
|
||||
}
|
||||
@ -6,10 +6,11 @@
|
||||
translate="dossier-templates"
|
||||
></a>
|
||||
|
||||
<ng-container *ngIf="dossierTemplatesService.activeDossierTemplate$ | async as activeDossierTemplate">
|
||||
<mat-icon svgIcon="iqser:arrow-right"></mat-icon>
|
||||
<a [class.active]="!appStateService.activeDictionaryType" [routerLink]="activeDossierTemplate.routerLink" class="breadcrumb ml-0">
|
||||
{{ activeDossierTemplate.name }}
|
||||
<mat-icon svgIcon="iqser:arrow-right"></mat-icon>
|
||||
|
||||
<ng-container *ngIf="dossierTemplate$ | async as dossierTemplate">
|
||||
<a [class.active]="!appStateService.activeDictionaryType" [routerLink]="dossierTemplate.routerLink" class="breadcrumb ml-0">
|
||||
{{ dossierTemplate.name }}
|
||||
</a>
|
||||
|
||||
<ng-container *ngIf="appStateService.activeDictionary">
|
||||
@ -17,7 +18,7 @@
|
||||
<a
|
||||
[routerLink]="
|
||||
'/main/admin/dossier-templates/' +
|
||||
activeDossierTemplate.dossierTemplateId +
|
||||
dossierTemplate.dossierTemplateId +
|
||||
'/dictionaries/' +
|
||||
appStateService.activeDictionaryType
|
||||
"
|
||||
@ -0,0 +1,32 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { UserPreferenceService } from '@services/user-preference.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { DossierTemplate } from '@red/domain';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dossier-template-breadcrumbs',
|
||||
templateUrl: './dossier-template-breadcrumbs.component.html',
|
||||
styleUrls: ['./dossier-template-breadcrumbs.component.scss'],
|
||||
})
|
||||
export class DossierTemplateBreadcrumbsComponent {
|
||||
@Input() root = false;
|
||||
readonly dossierTemplate$: Observable<DossierTemplate>;
|
||||
|
||||
constructor(
|
||||
readonly userPreferenceService: UserPreferenceService,
|
||||
readonly permissionService: PermissionsService,
|
||||
readonly appStateService: AppStateService,
|
||||
readonly dossierTemplatesService: DossierTemplatesService,
|
||||
private readonly _route: ActivatedRoute,
|
||||
) {
|
||||
this.dossierTemplate$ = _route.paramMap.pipe(
|
||||
map(params => params.get('dossierTemplateId')),
|
||||
switchMap((dossierTemplateId: string) => this.dossierTemplatesService.getEntityChanged$(dossierTemplateId)),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -95,11 +95,11 @@
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button>
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button type="button">
|
||||
{{ 'add-edit-dictionary.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<iqser-circle-button class="dialog-close" icon="iqser:close" (action)="close()"></iqser-circle-button>
|
||||
<iqser-circle-button (action)="close()" class="dialog-close" icon="iqser:close"></iqser-circle-button>
|
||||
</section>
|
||||
|
||||
@ -35,11 +35,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-actions">
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button>
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button type="button">
|
||||
{{ 'add-edit-dossier-attribute.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<iqser-circle-button class="dialog-close" icon="iqser:close" (action)="close()"></iqser-circle-button>
|
||||
<iqser-circle-button (action)="close()" class="dialog-close" icon="iqser:close"></iqser-circle-button>
|
||||
</section>
|
||||
|
||||
@ -82,11 +82,11 @@
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button>
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button type="button">
|
||||
{{ 'add-edit-dossier-template.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<iqser-circle-button class="dialog-close" icon="iqser:close" (action)="close()"></iqser-circle-button>
|
||||
<iqser-circle-button (action)="close()" class="dialog-close" icon="iqser:close"></iqser-circle-button>
|
||||
</section>
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
import { Component, Inject, Injector } from '@angular/core';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import * as moment from 'moment';
|
||||
import { Moment } from 'moment';
|
||||
import { applyIntervalConstraints } from '@utils/date-inputs-utils';
|
||||
import { downloadTypesTranslations } from '../../../../translations/download-types-translations';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { BaseDialogComponent, Toaster } from '@iqser/common-ui';
|
||||
import { BaseDialogComponent, LoadingService, Toaster } from '@iqser/common-ui';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { DownloadFileType, IDossierTemplate } from '@red/domain';
|
||||
import { HttpStatusCode } from '@angular/common/http';
|
||||
@ -36,6 +36,7 @@ export class AddEditDossierTemplateDialogComponent extends BaseDialogComponent {
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
protected readonly _injector: Injector,
|
||||
protected readonly _dialogRef: MatDialogRef<AddEditDossierTemplateDialogComponent>,
|
||||
private readonly _loadingService: LoadingService,
|
||||
@Inject(MAT_DIALOG_DATA) readonly dossierTemplate: IDossierTemplate,
|
||||
) {
|
||||
super(_injector, _dialogRef);
|
||||
@ -70,15 +71,15 @@ export class AddEditDossierTemplateDialogComponent extends BaseDialogComponent {
|
||||
}
|
||||
|
||||
async save() {
|
||||
this._loadingService.start();
|
||||
try {
|
||||
const dossierTemplate = {
|
||||
dossierTemplateId: this.dossierTemplate?.dossierTemplateId,
|
||||
...this.form.getRawValue(),
|
||||
validFrom: this.hasValidFrom ? this.form.get('validFrom').value : null,
|
||||
validTo: this.hasValidTo ? this.form.get('validTo').value : null,
|
||||
};
|
||||
} as IDossierTemplate;
|
||||
await this._dossierTemplatesService.createOrUpdate(dossierTemplate).toPromise();
|
||||
await this._dossierTemplatesService.loadAll().toPromise();
|
||||
await this._appStateService.loadDictionaryData();
|
||||
this._dialogRef.close(true);
|
||||
} catch (error: any) {
|
||||
@ -88,6 +89,7 @@ export class AddEditDossierTemplateDialogComponent extends BaseDialogComponent {
|
||||
: _('add-edit-dossier-template.error.generic');
|
||||
this._toaster.error(message, { error });
|
||||
}
|
||||
this._loadingService.stop();
|
||||
}
|
||||
|
||||
private _getForm(): FormGroup {
|
||||
@ -117,7 +119,7 @@ export class AddEditDossierTemplateDialogComponent extends BaseDialogComponent {
|
||||
}
|
||||
|
||||
private _requiredIfValidator(predicate) {
|
||||
return formControl => {
|
||||
return (formControl: AbstractControl) => {
|
||||
if (!formControl.parent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -84,11 +84,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="dialog-actions">
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button>
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button type="button">
|
||||
{{ 'add-edit-file-attribute.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<iqser-circle-button class="dialog-close" icon="iqser:close" (action)="close()"></iqser-circle-button>
|
||||
<iqser-circle-button (action)="close()" class="dialog-close" icon="iqser:close"></iqser-circle-button>
|
||||
</section>
|
||||
|
||||
@ -28,11 +28,11 @@
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button>
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button type="button">
|
||||
{{ 'edit-color-dialog.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<iqser-circle-button class="dialog-close" icon="iqser:close" (action)="close()"></iqser-circle-button>
|
||||
<iqser-circle-button (action)="close()" class="dialog-close" icon="iqser:close"></iqser-circle-button>
|
||||
</section>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs class="flex-1"></redaction-admin-breadcrumbs>
|
||||
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
<div class="flex-1 actions">
|
||||
<redaction-dossier-template-actions></redaction-dossier-template-actions>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs class="flex-1"></redaction-admin-breadcrumbs>
|
||||
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
<div class="flex-1 actions">
|
||||
<redaction-dossier-template-actions></redaction-dossier-template-actions>
|
||||
@ -78,51 +78,53 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #tableItemTemplate let-entity="entity">
|
||||
<div *ngIf="cast(entity) as dict">
|
||||
<div class="cell">
|
||||
<div [ngStyle]="{ 'background-color': dict.hexColor }" class="color-square"></div>
|
||||
<div class="dict-name">
|
||||
<div class="table-item-title heading">
|
||||
{{ dict.label }}
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:entries"></mat-icon>
|
||||
{{ dict.entries?.length }}
|
||||
<ng-container *ngIf="templateStats$ | async as templateStats">
|
||||
<ng-template #tableItemTemplate let-entity="entity">
|
||||
<div *ngIf="cast(entity) as dict">
|
||||
<div class="cell">
|
||||
<div [ngStyle]="{ 'background-color': dict.hexColor }" class="color-square"></div>
|
||||
<div class="dict-name">
|
||||
<div class="table-item-title heading">
|
||||
{{ dict.label }}
|
||||
</div>
|
||||
<div *ngIf="!dict.caseInsensitive">
|
||||
<mat-icon svgIcon="red:case-sensitive"></mat-icon>
|
||||
{{ 'dictionary-listing.case-sensitive' | translate }}
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:entries"></mat-icon>
|
||||
{{ templateStats.dictionarySummary(dict.type)?.entriesCount || 0 }}
|
||||
</div>
|
||||
<div *ngIf="!dict.caseInsensitive">
|
||||
<mat-icon svgIcon="red:case-sensitive"></mat-icon>
|
||||
{{ 'dictionary-listing.case-sensitive' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cell center small-label">
|
||||
{{ dict.rank }}
|
||||
</div>
|
||||
<div class="cell center small-label">
|
||||
{{ dict.rank }}
|
||||
</div>
|
||||
|
||||
<div class="cell center">
|
||||
<redaction-annotation-icon [dictionary]="dict" [type]="dict.hint ? 'circle' : 'square'"></redaction-annotation-icon>
|
||||
</div>
|
||||
<div class="cell center">
|
||||
<redaction-annotation-icon [dictionary]="dict" [type]="dict.hint ? 'circle' : 'square'"></redaction-annotation-icon>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<div *ngIf="currentUser.isAdmin" class="action-buttons">
|
||||
<iqser-circle-button
|
||||
(action)="openDeleteDictionariesDialog($event, [dict])"
|
||||
[tooltip]="'dictionary-listing.action.delete' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:trash"
|
||||
></iqser-circle-button>
|
||||
<div class="cell">
|
||||
<div *ngIf="currentUser.isAdmin" class="action-buttons">
|
||||
<iqser-circle-button
|
||||
(action)="openDeleteDictionariesDialog($event, [dict])"
|
||||
[tooltip]="'dictionary-listing.action.delete' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:trash"
|
||||
></iqser-circle-button>
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="openAddEditDictionaryDialog($event, dict)"
|
||||
[tooltip]="'dictionary-listing.action.edit' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:edit"
|
||||
></iqser-circle-button>
|
||||
<iqser-circle-button
|
||||
(action)="openAddEditDictionaryDialog($event, dict)"
|
||||
[tooltip]="'dictionary-listing.action.edit' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:edit"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
import { Component, forwardRef, Injector, OnInit } from '@angular/core';
|
||||
import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { catchError, defaultIfEmpty, tap } from 'rxjs/operators';
|
||||
import { forkJoin, of } from 'rxjs';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import {
|
||||
CircleButtonTypes,
|
||||
@ -17,14 +15,11 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { DictionaryService } from '@shared/services/dictionary.service';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { Dictionary } from '@red/domain';
|
||||
|
||||
const toChartConfig = (dict: Dictionary): DoughnutChartConfig => ({
|
||||
value: dict.entries?.length ?? 0,
|
||||
color: dict.hexColor,
|
||||
label: dict.label,
|
||||
key: dict.type,
|
||||
});
|
||||
import { Dictionary, DossierTemplateStats } from '@red/domain';
|
||||
import { Observable } from 'rxjs';
|
||||
import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { tap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
templateUrl: './dictionary-listing-screen.component.html',
|
||||
@ -42,6 +37,8 @@ export class DictionaryListingScreenComponent extends ListingComponent<Dictionar
|
||||
{ label: _('dictionary-listing.table-col-names.hint-redaction'), class: 'flex-center' },
|
||||
];
|
||||
chartData: DoughnutChartConfig[] = [];
|
||||
readonly templateStats$: Observable<DossierTemplateStats>;
|
||||
templateStats: DossierTemplateStats;
|
||||
|
||||
constructor(
|
||||
protected readonly _injector: Injector,
|
||||
@ -52,13 +49,18 @@ export class DictionaryListingScreenComponent extends ListingComponent<Dictionar
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _dossierTemplateStatsService: DossierTemplateStatsService,
|
||||
private readonly _route: ActivatedRoute,
|
||||
) {
|
||||
super(_injector);
|
||||
_loadingService.start();
|
||||
const dossierTemplateId = _route.snapshot.paramMap.get('dossierTemplateId');
|
||||
this.templateStats = this._dossierTemplateStatsService.get(dossierTemplateId);
|
||||
this.templateStats$ = this._dossierTemplateStatsService.watch$(dossierTemplateId).pipe(tap(stats => (this.templateStats = stats)));
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this._loadDictionaryData();
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this._loadDictionaryData(false);
|
||||
}
|
||||
|
||||
openDeleteDictionariesDialog($event?: MouseEvent, types = this.listingService.selected) {
|
||||
@ -70,9 +72,7 @@ export class DictionaryListingScreenComponent extends ListingComponent<Dictionar
|
||||
this._dossierTemplatesService.activeDossierTemplateId,
|
||||
)
|
||||
.toPromise();
|
||||
await this._appStateService.loadDictionaryData();
|
||||
this._loadDictionaryData(false);
|
||||
this._calculateData();
|
||||
await this._loadDictionaryData();
|
||||
this._loadingService.stop();
|
||||
});
|
||||
}
|
||||
@ -87,50 +87,31 @@ export class DictionaryListingScreenComponent extends ListingComponent<Dictionar
|
||||
},
|
||||
async () => {
|
||||
this._loadingService.start();
|
||||
await this._appStateService.loadDictionaryData();
|
||||
this._loadDictionaryData(false);
|
||||
this._calculateData();
|
||||
await this._loadDictionaryData();
|
||||
this._loadingService.stop();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
private _loadDictionaryData(loadEntries = true): void {
|
||||
private async _loadDictionaryData(refresh = true): Promise<void> {
|
||||
if (refresh) {
|
||||
await this._appStateService.loadDictionaryData();
|
||||
}
|
||||
|
||||
const appStateDictionaryData = this._appStateService.dictionaryData[this._dossierTemplatesService.activeDossierTemplateId];
|
||||
const entities = Object.values(appStateDictionaryData).filter(d => !d.virtual);
|
||||
this.entitiesService.setEntities(entities);
|
||||
|
||||
if (!loadEntries) {
|
||||
this.entitiesService.setEntities(
|
||||
entities.map(dict => {
|
||||
dict.entries = this.allEntities.find(d => d.type === dict.type)?.entries || [];
|
||||
return dict;
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
this.entitiesService.setEntities(entities);
|
||||
}
|
||||
|
||||
if (!loadEntries) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dataObs = this.allEntities.map(dict =>
|
||||
this._dictionaryService.getForType(this._dossierTemplatesService.activeDossierTemplateId, dict.type).pipe(
|
||||
tap(values => (dict.entries = [...values.entries] ?? [])),
|
||||
catchError(() => {
|
||||
dict.entries = [];
|
||||
return of({});
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
forkJoin(dataObs)
|
||||
.pipe(defaultIfEmpty(null))
|
||||
.subscribe(() => this._calculateData());
|
||||
this._calculateData();
|
||||
}
|
||||
|
||||
private _calculateData(): void {
|
||||
this.chartData = this.allEntities.map(dict => toChartConfig(dict));
|
||||
this.chartData = this.allEntities.map(dict => ({
|
||||
value: this.templateStats.dictionarySummary(dict.type).entriesCount ?? 0,
|
||||
color: dict.hexColor,
|
||||
label: dict.label,
|
||||
key: dict.type,
|
||||
}));
|
||||
this.chartData.sort((a, b) => (a.label < b.label ? -1 : 1));
|
||||
this._loadingService.stop();
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs></redaction-admin-breadcrumbs>
|
||||
<redaction-dossier-template-breadcrumbs></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
<div class="actions">
|
||||
<iqser-circle-button
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs class="flex-1"></redaction-admin-breadcrumbs>
|
||||
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
<div class="actions flex-1">
|
||||
<redaction-dossier-template-actions></redaction-dossier-template-actions>
|
||||
|
||||
@ -1,100 +0,0 @@
|
||||
<section class="settings">
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
<redaction-admin-side-nav type="settings"></redaction-admin-side-nav>
|
||||
|
||||
<div>
|
||||
<iqser-page-header
|
||||
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
|
||||
[pageLabel]="'dossier-templates' | translate"
|
||||
[showCloseButton]="currentUser.isUser"
|
||||
></iqser-page-header>
|
||||
|
||||
<div class="content-inner">
|
||||
<div class="content-container">
|
||||
<iqser-table
|
||||
[bulkActions]="bulkActions"
|
||||
[headerTemplate]="headerTemplate"
|
||||
[itemSize]="80"
|
||||
[noDataText]="'dossier-templates-listing.no-data.title' | translate"
|
||||
[noMatchText]="'dossier-templates-listing.no-match.title' | translate"
|
||||
[selectionEnabled]="true"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
noDataIcon="red:template"
|
||||
></iqser-table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<ng-template #bulkActions>
|
||||
<iqser-circle-button
|
||||
(action)="openBulkDeleteTemplatesDialog($event)"
|
||||
*ngIf="currentUser.isAdmin && (listingService.areSomeSelected$ | async)"
|
||||
[tooltip]="'dossier-templates-listing.bulk.delete' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:trash"
|
||||
></iqser-circle-button>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #actionsTemplate let-dossierTemplate="entity">
|
||||
<redaction-dossier-template-actions
|
||||
(loadDossierTemplatesData)="loadDossierTemplateStats()"
|
||||
[dossierTemplateId]="dossierTemplate.dossierTemplateId"
|
||||
class="actions-container"
|
||||
></redaction-dossier-template-actions>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #headerTemplate>
|
||||
<div class="table-header-actions">
|
||||
<iqser-input-with-action
|
||||
[(value)]="searchService.searchValue"
|
||||
[placeholder]="'dossier-templates-listing.search' | translate"
|
||||
></iqser-input-with-action>
|
||||
|
||||
<iqser-icon-button
|
||||
(action)="openAddDossierTemplateDialog()"
|
||||
*ngIf="currentUser.isAdmin && userPreferenceService.areDevFeaturesEnabled"
|
||||
[label]="'dossier-templates-listing.add-new' | translate"
|
||||
[type]="iconButtonTypes.primary"
|
||||
icon="iqser:plus"
|
||||
></iqser-icon-button>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #tableItemTemplate let-entity="entity">
|
||||
<div *ngIf="cast(entity) as dossierTemplate">
|
||||
<div class="cell">
|
||||
<div class="table-item-title heading">
|
||||
{{ dossierTemplate.name }}
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:dictionary"></mat-icon>
|
||||
{{ 'dossier-templates-listing.dictionaries' | translate: { length: dossierTemplate.dictionariesCount } }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cell user-column">
|
||||
<redaction-initials-avatar
|
||||
[defaultValue]="'unknown' | translate"
|
||||
[user]="dossierTemplate.createdBy || 'system'"
|
||||
[withName]="true"
|
||||
></redaction-initials-avatar>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<div class="small-label">
|
||||
{{ dossierTemplate.dateAdded | date: 'd MMM. yyyy' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<div class="small-label">
|
||||
{{ dossierTemplate.dateModified | date: 'd MMM. yyyy' }}
|
||||
</div>
|
||||
<ng-container *ngTemplateOutlet="actionsTemplate; context: { entity: dossierTemplate }"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
@ -0,0 +1,47 @@
|
||||
<iqser-page-header
|
||||
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
|
||||
[pageLabel]="'dossier-templates' | translate"
|
||||
[showCloseButton]="currentUser.isUser"
|
||||
></iqser-page-header>
|
||||
|
||||
<iqser-table
|
||||
[bulkActions]="bulkActions"
|
||||
[headerTemplate]="headerTemplate"
|
||||
[itemSize]="80"
|
||||
[noDataText]="'dossier-templates-listing.no-data.title' | translate"
|
||||
[noMatchText]="'dossier-templates-listing.no-match.title' | translate"
|
||||
[selectionEnabled]="true"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
noDataIcon="red:template"
|
||||
></iqser-table>
|
||||
|
||||
<ng-template #bulkActions>
|
||||
<iqser-circle-button
|
||||
(action)="openBulkDeleteTemplatesDialog($event)"
|
||||
*ngIf="currentUser.isAdmin && (listingService.areSomeSelected$ | async)"
|
||||
[tooltip]="'dossier-templates-listing.bulk.delete' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:trash"
|
||||
></iqser-circle-button>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #headerTemplate>
|
||||
<div class="table-header-actions">
|
||||
<iqser-input-with-action
|
||||
[(value)]="searchService.searchValue"
|
||||
[placeholder]="'dossier-templates-listing.search' | translate"
|
||||
></iqser-input-with-action>
|
||||
|
||||
<iqser-icon-button
|
||||
(action)="openAddDossierTemplateDialog()"
|
||||
*ngIf="currentUser.isAdmin && userPreferenceService.areDevFeaturesEnabled"
|
||||
[label]="'dossier-templates-listing.add-new' | translate"
|
||||
[type]="iconButtonTypes.primary"
|
||||
icon="iqser:plus"
|
||||
></iqser-icon-button>
|
||||
</div>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #tableItemTemplate let-entity="entity">
|
||||
<redaction-table-item [dossierTemplate]="entity"></redaction-table-item>
|
||||
</ng-template>
|
||||
@ -0,0 +1,6 @@
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, forwardRef, Injector } from '@angular/core';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { UserPreferenceService } from '@services/user-preference.service';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { AdminDialogService } from '../../../services/admin-dialog.service';
|
||||
import { DossierTemplate } from '@red/domain';
|
||||
import {
|
||||
CircleButtonTypes,
|
||||
@ -29,7 +29,7 @@ import { HttpStatusCode } from '@angular/common/http';
|
||||
{ provide: ListingComponent, useExisting: forwardRef(() => DossierTemplatesListingScreenComponent) },
|
||||
],
|
||||
})
|
||||
export class DossierTemplatesListingScreenComponent extends ListingComponent<DossierTemplate> implements OnInit {
|
||||
export class DossierTemplatesListingScreenComponent extends ListingComponent<DossierTemplate> {
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
@ -55,10 +55,6 @@ export class DossierTemplatesListingScreenComponent extends ListingComponent<Dos
|
||||
super(_injector);
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.loadDossierTemplateStats();
|
||||
}
|
||||
|
||||
openBulkDeleteTemplatesDialog($event?: MouseEvent) {
|
||||
return this._dialogService.openDialog('confirm', $event, null, () => {
|
||||
this._loadingService.loadWhile(this._deleteTemplates());
|
||||
@ -66,23 +62,7 @@ export class DossierTemplatesListingScreenComponent extends ListingComponent<Dos
|
||||
}
|
||||
|
||||
openAddDossierTemplateDialog() {
|
||||
this._dialogService.openDialog('addEditDossierTemplate', null, null, () => {
|
||||
this.loadDossierTemplateStats();
|
||||
});
|
||||
}
|
||||
|
||||
loadDossierTemplateStats() {
|
||||
this.entitiesService.all.forEach(rs => {
|
||||
const dictionaries = this._appStateService.dictionaryData[rs.dossierTemplateId];
|
||||
if (dictionaries) {
|
||||
rs.dictionariesCount = Object.keys(dictionaries)
|
||||
.map(key => dictionaries[key])
|
||||
.filter(d => !d.virtual || d.type === 'false_positive').length;
|
||||
} else {
|
||||
rs.dictionariesCount = 0;
|
||||
rs.totalDictionaryEntries = 0;
|
||||
}
|
||||
});
|
||||
this._dialogService.openDialog('addEditDossierTemplate', null, null);
|
||||
}
|
||||
|
||||
private async _deleteTemplates(templateIds = this.listingService.selected.map(d => d.dossierTemplateId)) {
|
||||
@ -96,8 +76,6 @@ export class DossierTemplatesListingScreenComponent extends ListingComponent<Dos
|
||||
this._toaster.error(_('dossier-templates-listing.error.generic'));
|
||||
}
|
||||
});
|
||||
await this._dossierTemplatesService.loadAll().toPromise();
|
||||
await this._appStateService.loadDictionaryData();
|
||||
this.loadDossierTemplateStats();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { SharedModule } from '@shared/shared.module';
|
||||
import { TableItemComponent } from './table-item/table-item.component';
|
||||
import { DossierTemplatesListingScreenComponent } from './dossier-templates-listing-screen/dossier-templates-listing-screen.component';
|
||||
import { SharedAdminModule } from '../../shared/shared-admin.module';
|
||||
|
||||
const routes = [{ path: '', component: DossierTemplatesListingScreenComponent }];
|
||||
|
||||
@NgModule({
|
||||
declarations: [TableItemComponent, DossierTemplatesListingScreenComponent],
|
||||
imports: [RouterModule.forChild(routes), CommonModule, SharedModule, SharedAdminModule],
|
||||
providers: [],
|
||||
})
|
||||
export class DossierTemplatesListingModule {}
|
||||
@ -0,0 +1,35 @@
|
||||
<div class="cell">
|
||||
<div class="table-item-title heading">
|
||||
{{ dossierTemplate.name }}
|
||||
</div>
|
||||
<div class="small-label stats-subtitle">
|
||||
<div *ngIf="stats$ | async as stats">
|
||||
<mat-icon svgIcon="red:dictionary"></mat-icon>
|
||||
{{ 'dossier-templates-listing.dictionaries' | translate: { length: stats.numberOfDictionaries } }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cell user-column">
|
||||
<redaction-initials-avatar
|
||||
[defaultValue]="'unknown' | translate"
|
||||
[user]="dossierTemplate.createdBy || 'system'"
|
||||
[withName]="true"
|
||||
></redaction-initials-avatar>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<div class="small-label">
|
||||
{{ dossierTemplate.dateAdded | date: 'd MMM. yyyy' }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<div class="small-label">
|
||||
{{ dossierTemplate.dateModified | date: 'd MMM. yyyy' }}
|
||||
</div>
|
||||
<redaction-dossier-template-actions
|
||||
[dossierTemplateId]="dossierTemplate.dossierTemplateId"
|
||||
class="actions-container"
|
||||
></redaction-dossier-template-actions>
|
||||
</div>
|
||||
@ -0,0 +1,28 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
|
||||
import { DossierTemplate, DossierTemplateStats } from '@red/domain';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-table-item [dossierTemplate]',
|
||||
templateUrl: './table-item.component.html',
|
||||
styleUrls: ['./table-item.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TableItemComponent implements OnChanges {
|
||||
@Input() dossierTemplate!: DossierTemplate;
|
||||
|
||||
readonly stats$: Observable<DossierTemplateStats>;
|
||||
private readonly _ngOnChanges$ = new BehaviorSubject<string>(undefined);
|
||||
|
||||
constructor(readonly dossierTemplateStatsService: DossierTemplateStatsService) {
|
||||
this.stats$ = this._ngOnChanges$.pipe(switchMap(id => this.dossierTemplateStatsService.watch$(id)));
|
||||
}
|
||||
|
||||
ngOnChanges() {
|
||||
if (this.dossierTemplate) {
|
||||
this._ngOnChanges$.next(this.dossierTemplate.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs class="flex-1"></redaction-admin-breadcrumbs>
|
||||
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
<div class="actions flex-1">
|
||||
<redaction-dossier-template-actions></redaction-dossier-template-actions>
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { DossierTemplateInfoScreenComponent } from './info-screen/dossier-template-info-screen.component';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { SharedModule } from '@shared/shared.module';
|
||||
|
||||
const routes = [{ path: '', component: DossierTemplateInfoScreenComponent }];
|
||||
|
||||
@NgModule({
|
||||
declarations: [DossierTemplateInfoScreenComponent],
|
||||
imports: [RouterModule.forChild(routes), CommonModule, SharedModule],
|
||||
})
|
||||
export class DossierTemplateInfoModule {}
|
||||
@ -0,0 +1,46 @@
|
||||
<div *ngIf="dossierTemplate$ | async as dossierTemplate" class="content-container" iqserHasScrollbar>
|
||||
<ng-container *ngIf="dossierTemplateStats$ | async as stats">
|
||||
<div class="heading-xl">{{ dossierTemplate.name }}</div>
|
||||
|
||||
<div class="all-caps-label mt-24 mb-8" translate="dossier-template-info-screen.created-by"></div>
|
||||
|
||||
<redaction-initials-avatar
|
||||
[user]="dossierTemplate.createdBy || 'system'"
|
||||
[withName]="true"
|
||||
size="large"
|
||||
></redaction-initials-avatar>
|
||||
|
||||
<div class="small-label stats-subtitle">
|
||||
<div>
|
||||
<mat-icon svgIcon="red:dictionary"></mat-icon>
|
||||
{{ 'dossier-template-info-screen.dictionaries' | translate: { count: stats.numberOfDictionaries } }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<mat-icon svgIcon="red:calendar"></mat-icon>
|
||||
{{ 'dossier-template-info-screen.created-on' | translate: { date: dossierTemplate.dateAdded | date: 'd MMM. yyyy' } }}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<mat-icon svgIcon="red:entries"></mat-icon>
|
||||
{{ 'dossier-template-info-screen.entries' | translate: { count: stats.numberOfEntries } }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="dossierTemplate.dateModified">
|
||||
<mat-icon svgIcon="red:calendar"></mat-icon>
|
||||
{{ 'dossier-template-info-screen.modified-on' | translate: { date: dossierTemplate.dateModified | date: 'd MMM. yyyy' } }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="heading mt-40" translate="dossier-template-info-screen.description">
|
||||
<iqser-circle-button
|
||||
(action)="openEditDossierTemplateDialog($event, dossierTemplate)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
class="ml-8"
|
||||
icon="iqser:edit"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
|
||||
<div>{{ dossierTemplate.description }}</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
@ -0,0 +1,30 @@
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.content-container {
|
||||
flex: 1;
|
||||
padding: 30px;
|
||||
overflow: auto;
|
||||
@include common-mixins.scroll-bar;
|
||||
}
|
||||
|
||||
.heading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.stats-subtitle {
|
||||
margin-top: 16px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, max-content);
|
||||
grid-row-gap: 8px;
|
||||
grid-column-gap: 40px;
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Observable } from 'rxjs';
|
||||
import { DossierTemplate, DossierTemplateStats } from '@red/domain';
|
||||
import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service';
|
||||
import { AdminDialogService } from '../../../services/admin-dialog.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './dossier-template-info-screen.component.html',
|
||||
styleUrls: ['./dossier-template-info-screen.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DossierTemplateInfoScreenComponent {
|
||||
dossierTemplate$: Observable<DossierTemplate>;
|
||||
dossierTemplateStats$: Observable<DossierTemplateStats>;
|
||||
|
||||
constructor(
|
||||
private readonly _dossierTemplatesService: DossierTemplatesService,
|
||||
private readonly _dossierTemplateStatsService: DossierTemplateStatsService,
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
private readonly _route: ActivatedRoute,
|
||||
readonly permissionsService: PermissionsService,
|
||||
) {
|
||||
const dossierTemplateId = _route.snapshot.paramMap.get('dossierTemplateId');
|
||||
this.dossierTemplate$ = this._dossierTemplatesService.getEntityChanged$(dossierTemplateId);
|
||||
this.dossierTemplateStats$ = this._dossierTemplateStatsService.watch$(dossierTemplateId);
|
||||
}
|
||||
|
||||
openEditDossierTemplateDialog($event: any, dossierTemplate: DossierTemplate) {
|
||||
this._dialogService.openDialog('addEditDossierTemplate', $event, dossierTemplate);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs class="flex-1"></redaction-admin-breadcrumbs>
|
||||
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
<div class="actions flex-1">
|
||||
<redaction-dossier-template-actions></redaction-dossier-template-actions>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs class="flex-1"></redaction-admin-breadcrumbs>
|
||||
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
<div class="flex-1 actions">
|
||||
<redaction-dossier-template-actions></redaction-dossier-template-actions>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-admin-breadcrumbs class="flex-1"></redaction-admin-breadcrumbs>
|
||||
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
<div class="actions flex-1">
|
||||
<redaction-dossier-template-actions></redaction-dossier-template-actions>
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { Router } from '@angular/router';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { AdminDialogService } from '../../../services/admin-dialog.service';
|
||||
import { CircleButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
@ -18,7 +18,6 @@ export class DossierTemplateActionsComponent implements OnInit {
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
|
||||
@Input() dossierTemplateId: string;
|
||||
@Output() readonly loadDossierTemplatesData = new EventEmitter<void>();
|
||||
|
||||
constructor(
|
||||
private readonly _router: Router,
|
||||
@ -39,9 +38,7 @@ export class DossierTemplateActionsComponent implements OnInit {
|
||||
}
|
||||
|
||||
openEditDossierTemplateDialog($event: any) {
|
||||
this._dialogService.openDialog('addEditDossierTemplate', $event, this.dossierTemplate, () => {
|
||||
this.loadDossierTemplatesData.emit();
|
||||
});
|
||||
this._dialogService.openDialog('addEditDossierTemplate', $event, this.dossierTemplate);
|
||||
}
|
||||
|
||||
openDeleteDossierTemplateDialog($event?: MouseEvent) {
|
||||
@ -54,7 +51,6 @@ export class DossierTemplateActionsComponent implements OnInit {
|
||||
.then(async () => {
|
||||
await this._dossierTemplatesService.loadAll().toPromise();
|
||||
await this._appStateService.loadDictionaryData();
|
||||
this.loadDossierTemplatesData.emit();
|
||||
await this._router.navigate(['main', 'admin']);
|
||||
})
|
||||
.catch(error => {
|
||||
@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SharedModule } from '@shared/shared.module';
|
||||
import { DossierTemplateActionsComponent } from './components/dossier-template-actions/dossier-template-actions.component';
|
||||
|
||||
const components = [DossierTemplateActionsComponent];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components],
|
||||
exports: [...components],
|
||||
providers: [],
|
||||
imports: [CommonModule, SharedModule],
|
||||
})
|
||||
export class SharedAdminModule {}
|
||||
@ -49,7 +49,7 @@
|
||||
</div>
|
||||
|
||||
<div *ngIf="showActionButtons" class="dialog-actions">
|
||||
<button (click)="save()" [disabled]="disabled || !valid || !changed" color="primary" mat-flat-button>
|
||||
<button (click)="save()" [disabled]="disabled || !valid || !changed" color="primary" mat-flat-button type="button">
|
||||
{{ 'edit-dossier-dialog.actions.save' | translate }}
|
||||
</button>
|
||||
<iqser-icon-button
|
||||
|
||||
@ -5,7 +5,7 @@ import { AutoUnsubscribe } from '@iqser/common-ui';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { DocumentInfoService } from '../../services/document-info.service';
|
||||
import { Observable } from 'rxjs';
|
||||
import { PermissionsService } from '../../../../../../services/permissions.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-document-info [file] [dossier]',
|
||||
|
||||
@ -2,8 +2,9 @@ import { Injectable, Injector } from '@angular/core';
|
||||
import { Observable, throwError } from 'rxjs';
|
||||
import { EntitiesService, List, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
|
||||
import { Dictionary, IColors, IDictionary, IUpdateDictionary } from '@red/domain';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { mapTo, switchMap, tap } from 'rxjs/operators';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service';
|
||||
|
||||
const MIN_WORD_LENGTH = 2;
|
||||
|
||||
@ -11,7 +12,11 @@ const MIN_WORD_LENGTH = 2;
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DictionaryService extends EntitiesService<Dictionary, IDictionary> {
|
||||
constructor(private readonly _toaster: Toaster, protected readonly _injector: Injector) {
|
||||
constructor(
|
||||
private readonly _toaster: Toaster,
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _dossierTemplateStatsService: DossierTemplateStatsService,
|
||||
) {
|
||||
super(_injector, Dictionary, 'dictionary');
|
||||
}
|
||||
|
||||
@ -31,7 +36,9 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
deleteDictionaries(@RequiredParam() body: List, @RequiredParam() dossierTemplateId: string, dossierId?: string) {
|
||||
const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined;
|
||||
const url = `${this._defaultModelPath}/type/${dossierTemplateId}/delete`;
|
||||
return this._post<unknown>(body, url, queryParams);
|
||||
return this._post<unknown>(body, url, queryParams).pipe(
|
||||
switchMap(dictionaries => this._dossierTemplateStatsService.getFor([dossierTemplateId]).pipe(mapTo(dictionaries))),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -63,7 +70,9 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
) {
|
||||
const url = `${this._defaultModelPath}/type/${type}/${dossierTemplateId}`;
|
||||
const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined;
|
||||
return this._post(body, url, queryParams);
|
||||
return this._post(body, url, queryParams).pipe(
|
||||
switchMap(dictionary => this._dossierTemplateStatsService.getFor([dossierTemplateId]).pipe(mapTo(dictionary))),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,43 +87,11 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
* Creates entry type with colors, hint and caseInsensitive
|
||||
*/
|
||||
@Validate()
|
||||
addDictionary(@RequiredParam() body: IDictionary, dossierId?: string) {
|
||||
addDictionary(@RequiredParam() dictionary: IDictionary, dossierId?: string) {
|
||||
const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined;
|
||||
return this._post(body, `${this._defaultModelPath}/type`, queryParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add dictionary entries with entry type.
|
||||
*/
|
||||
@Validate()
|
||||
addEntry(
|
||||
@RequiredParam() body: List,
|
||||
@RequiredParam() dossierTemplateId: string,
|
||||
@RequiredParam() type: string,
|
||||
dossierId?: string,
|
||||
removeCurrent?: boolean,
|
||||
) {
|
||||
const queryParams: List<QueryParam> = [
|
||||
{ key: 'dossierId', value: dossierId },
|
||||
{ key: 'removeCurrent', value: removeCurrent },
|
||||
];
|
||||
const url = `${this._defaultModelPath}/${type}/${dossierTemplateId}`;
|
||||
return this._post(body, url, queryParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete dictionary entries with entry type.
|
||||
*/
|
||||
@Validate()
|
||||
deleteEntries(
|
||||
@RequiredParam() body: List,
|
||||
@RequiredParam() dossierTemplateId: string,
|
||||
@RequiredParam() type: string,
|
||||
@RequiredParam() dossierId?: string,
|
||||
) {
|
||||
const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined;
|
||||
const url = `${this._defaultModelPath}/delete/${type}/${dossierTemplateId}`;
|
||||
return this._post(body, url, queryParams);
|
||||
return this._post(dictionary, `${this._defaultModelPath}/type`, queryParams).pipe(
|
||||
switchMap(() => this._dossierTemplateStatsService.getFor([dictionary.dossierTemplateId])),
|
||||
);
|
||||
}
|
||||
|
||||
saveEntries(
|
||||
@ -134,14 +111,15 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
const invalidRowsExist = entriesToAdd.filter(e => e.length < MIN_WORD_LENGTH);
|
||||
if (invalidRowsExist.length === 0) {
|
||||
// can add at least 1 - block UI
|
||||
let obs: Observable<any>;
|
||||
let obs: Observable<IDictionary>;
|
||||
if (entriesToAdd.length > 0) {
|
||||
obs = this.addEntry(entriesToAdd, dossierTemplateId, type, dossierId, true);
|
||||
obs = this._addEntry(entriesToAdd, dossierTemplateId, type, dossierId, true);
|
||||
} else {
|
||||
obs = this.deleteEntries(initialEntries, dossierTemplateId, type, dossierId);
|
||||
obs = this._deleteEntries(initialEntries, dossierTemplateId, type, dossierId);
|
||||
}
|
||||
|
||||
return obs.pipe(
|
||||
switchMap(dictionary => this._dossierTemplateStatsService.getFor([dossierTemplateId]).pipe(mapTo(dictionary))),
|
||||
tap(
|
||||
() => {
|
||||
if (showToast) {
|
||||
@ -157,4 +135,38 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
return throwError('Entries too short');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add dictionary entries with entry type.
|
||||
*/
|
||||
@Validate()
|
||||
private _addEntry(
|
||||
@RequiredParam() body: List,
|
||||
@RequiredParam() dossierTemplateId: string,
|
||||
@RequiredParam() type: string,
|
||||
dossierId?: string,
|
||||
removeCurrent?: boolean,
|
||||
) {
|
||||
const queryParams: List<QueryParam> = [
|
||||
{ key: 'dossierId', value: dossierId },
|
||||
{ key: 'removeCurrent', value: removeCurrent },
|
||||
];
|
||||
const url = `${this._defaultModelPath}/${type}/${dossierTemplateId}`;
|
||||
return this._post(body, url, queryParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete dictionary entries with entry type.
|
||||
*/
|
||||
@Validate()
|
||||
private _deleteEntries(
|
||||
@RequiredParam() body: List,
|
||||
@RequiredParam() dossierTemplateId: string,
|
||||
@RequiredParam() type: string,
|
||||
@RequiredParam() dossierId?: string,
|
||||
) {
|
||||
const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined;
|
||||
const url = `${this._defaultModelPath}/delete/${type}/${dossierTemplateId}`;
|
||||
return this._post(body, url, queryParams);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,52 +1,12 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HeadersConfiguration, mapEach, RequiredParam, Validate } from '@iqser/common-ui';
|
||||
import { BehaviorSubject, Observable, of } from 'rxjs';
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { StatsService } from '@iqser/common-ui';
|
||||
import { DossierStats, IDossierStats } from '@red/domain';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { UserService } from '@services/user.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DossierStatsService {
|
||||
private readonly _map = new Map<string, BehaviorSubject<DossierStats>>();
|
||||
|
||||
constructor(private readonly _http: HttpClient, private readonly _userService: UserService) {}
|
||||
|
||||
@Validate()
|
||||
getFor(@RequiredParam() dossierIds: string[]): Observable<DossierStats[]> {
|
||||
if (!this._userService.currentUser.isUser) {
|
||||
return of([]);
|
||||
}
|
||||
const request = this._http.post<IDossierStats[]>(`/${encodeURI('dossier-stats')}`, dossierIds, {
|
||||
headers: HeadersConfiguration.getHeaders(),
|
||||
observe: 'body',
|
||||
});
|
||||
|
||||
return request.pipe(
|
||||
mapEach(entity => new DossierStats(entity)),
|
||||
tap(entities => entities.forEach(entity => this.set(entity))),
|
||||
);
|
||||
}
|
||||
|
||||
get(key: string): DossierStats {
|
||||
return this._map.get(key)?.value;
|
||||
}
|
||||
|
||||
set(stats: DossierStats): void {
|
||||
if (!this._map.has(stats.dossierId)) {
|
||||
this._map.set(stats.dossierId, new BehaviorSubject<DossierStats>(stats));
|
||||
return;
|
||||
}
|
||||
|
||||
const old = this.get(stats.dossierId);
|
||||
if (JSON.stringify(old) !== JSON.stringify(stats)) {
|
||||
this._map.get(stats.dossierId).next(stats);
|
||||
}
|
||||
}
|
||||
|
||||
watch$(key: string): Observable<DossierStats> {
|
||||
return this._map.get(key)?.asObservable();
|
||||
export class DossierStatsService extends StatsService<DossierStats, IDossierStats> {
|
||||
constructor(protected readonly _injector: Injector) {
|
||||
super(_injector, 'dossierId', DossierStats, 'dossier-stats');
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,12 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { StatsService } from '@iqser/common-ui';
|
||||
import { DossierTemplateStats, IDossierTemplateStats } from '@red/domain';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class DossierTemplateStatsService extends StatsService<DossierTemplateStats, IDossierTemplateStats> {
|
||||
constructor(protected readonly _injector: Injector) {
|
||||
super(_injector, 'dossierTemplateId', DossierTemplateStats, 'dossier-template-stats');
|
||||
}
|
||||
}
|
||||
@ -1,11 +1,12 @@
|
||||
import { EntitiesService, List, RequiredParam, Validate } from '@iqser/common-ui';
|
||||
import { EntitiesService, List, mapEach, RequiredParam, Validate } from '@iqser/common-ui';
|
||||
import { DossierTemplate, IDossierTemplate } from '@red/domain';
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { BehaviorSubject, forkJoin, Observable } from 'rxjs';
|
||||
import { FileAttributesService } from './file-attributes.service';
|
||||
import { ActivationEnd, Router } from '@angular/router';
|
||||
import { currentComponentRoute } from '@utils/functions';
|
||||
import { map, switchMap } from 'rxjs/operators';
|
||||
import { mapTo, switchMap, tap } from 'rxjs/operators';
|
||||
import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
@ -18,6 +19,7 @@ export class DossierTemplatesService extends EntitiesService<DossierTemplate, ID
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _fileAttributesService: FileAttributesService,
|
||||
private readonly _router: Router,
|
||||
private readonly _dossierTemplateStatsService: DossierTemplateStatsService,
|
||||
) {
|
||||
super(_injector, DossierTemplate, 'dossier-template');
|
||||
this.activeDossierTemplate$ = this._activeDossierTemplate$.asObservable();
|
||||
@ -53,18 +55,25 @@ export class DossierTemplatesService extends EntitiesService<DossierTemplate, ID
|
||||
|
||||
loadAll(): Observable<DossierTemplate[]> {
|
||||
const getAttributes = (entities: DossierTemplate[]) => entities.map(e => this._fileAttributesService.getFileAttributesConfig(e.id));
|
||||
return super.loadAll().pipe(
|
||||
switchMap(entities => forkJoin(getAttributes(entities))),
|
||||
map(() => this.all),
|
||||
const dossierTemplateIds = (templates: DossierTemplate[]) => templates.map(d => d.id);
|
||||
return this.getAll().pipe(
|
||||
mapEach(entity => new DossierTemplate(entity)),
|
||||
/* Load stats before updating entities */
|
||||
switchMap(templates =>
|
||||
forkJoin([this._dossierTemplateStatsService.getFor(dossierTemplateIds(templates)), ...getAttributes(templates)]).pipe(
|
||||
mapTo(templates),
|
||||
),
|
||||
),
|
||||
tap(templates => this.setEntities(templates)),
|
||||
);
|
||||
}
|
||||
|
||||
delete(body: List): Observable<unknown> {
|
||||
return super._post(body, `${this._defaultModelPath}/delete`);
|
||||
return super._post(body, `${this._defaultModelPath}/delete`).pipe(switchMap(() => this.loadAll()));
|
||||
}
|
||||
|
||||
@Validate()
|
||||
createOrUpdate(@RequiredParam() body: IDossierTemplate) {
|
||||
return this._post(body);
|
||||
return this._post(body).pipe(switchMap(() => this.loadAll()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -49,7 +49,7 @@ export class DossiersService extends EntitiesService<Dossier, IDossier> {
|
||||
}
|
||||
|
||||
loadAll(): Observable<Dossier[]> {
|
||||
const dossierIds = (dossiers: Dossier[]) => dossiers.map(d => d.dossierId);
|
||||
const dossierIds = (dossiers: Dossier[]) => dossiers.map(d => d.id);
|
||||
return this.getAll().pipe(
|
||||
mapEach(entity => new Dossier(entity)),
|
||||
/* Load stats before updating entities */
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"ADMIN_CONTACT_NAME": null,
|
||||
"ADMIN_CONTACT_URL": null,
|
||||
"API_URL": "https://aks-staging.iqser.cloud/redaction-gateway-v1",
|
||||
"API_URL": "https://dev-04.iqser.cloud/redaction-gateway-v1",
|
||||
"APP_NAME": "RedactManager",
|
||||
"AUTO_READ_TIME": 3,
|
||||
"BACKEND_APP_VERSION": "4.4.40",
|
||||
@ -17,7 +17,7 @@
|
||||
"MAX_RETRIES_ON_SERVER_ERROR": 3,
|
||||
"OAUTH_CLIENT_ID": "redaction",
|
||||
"OAUTH_IDP_HINT": null,
|
||||
"OAUTH_URL": "https://aks-staging.iqser.cloud/auth/realms/redaction",
|
||||
"OAUTH_URL": "https://dev-04.iqser.cloud/auth/realms/redaction",
|
||||
"RECENT_PERIOD_IN_HOURS": 24,
|
||||
"SELECTION_MODE": "structural",
|
||||
"USE_SESSION_FOR_DOWNLOAD": false
|
||||
|
||||
@ -789,6 +789,15 @@
|
||||
"under-review": "Under Review",
|
||||
"upload-files": "Drag & drop files anywhere..."
|
||||
},
|
||||
"dossier-template-info": "Info",
|
||||
"dossier-template-info-screen": {
|
||||
"created-by": "Created by",
|
||||
"created-on": "Created on: {date}",
|
||||
"description": "Description",
|
||||
"dictionaries": "{count} {count, plural, one{dictionary} other{dictionaries}}",
|
||||
"entries": "{count} {count, plural, one{entry} other{entries}}",
|
||||
"modified-on": "Modified on: {date}"
|
||||
},
|
||||
"dossier-templates": "Dossier Templates",
|
||||
"dossier-templates-listing": {
|
||||
"action": {
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 95644f59e4e32517d76e0bd9267805a88ebdd8d1
|
||||
Subproject commit 650c16b80387943f1de0efa876215559f56d123b
|
||||
@ -0,0 +1,23 @@
|
||||
import { DictionarySummary, IDossierTemplateStats } from './dossier-template-stats';
|
||||
|
||||
export class DossierTemplateStats implements IDossierTemplateStats {
|
||||
readonly dossierTemplateId: string;
|
||||
readonly dictionarySummaryList: DictionarySummary[];
|
||||
readonly numberOfDictionaries: number;
|
||||
|
||||
readonly numberOfEntries: number;
|
||||
private readonly _dictionarySummaryMap = new Map<string, DictionarySummary>();
|
||||
|
||||
constructor(stats: IDossierTemplateStats) {
|
||||
this.dossierTemplateId = stats.dossierTemplateId;
|
||||
this.dictionarySummaryList = stats.dictionarySummaryList;
|
||||
this.numberOfDictionaries = stats.numberOfDictionaries;
|
||||
|
||||
this.numberOfEntries = this.dictionarySummaryList.reduce((counter, summary) => counter + summary.entriesCount, 0);
|
||||
this.dictionarySummaryList.forEach(summary => this._dictionarySummaryMap.set(summary.type, summary));
|
||||
}
|
||||
|
||||
dictionarySummary(type: string): DictionarySummary | undefined {
|
||||
return this._dictionarySummaryMap.get(type);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
export interface DictionarySummary {
|
||||
readonly entriesCount: number;
|
||||
readonly id: string;
|
||||
readonly name: string;
|
||||
readonly type: string;
|
||||
}
|
||||
|
||||
export interface IDossierTemplateStats {
|
||||
readonly dossierTemplateId: string;
|
||||
readonly dictionarySummaryList: DictionarySummary[];
|
||||
readonly numberOfDictionaries: number;
|
||||
}
|
||||
@ -14,8 +14,6 @@ export class DossierTemplate implements IDossierTemplate, IListable {
|
||||
readonly reportTemplateIds?: List;
|
||||
readonly validFrom?: string;
|
||||
readonly validTo?: string;
|
||||
dictionariesCount = 0;
|
||||
totalDictionaryEntries = 0;
|
||||
|
||||
constructor(dossierTemplate: IDossierTemplate) {
|
||||
this.createdBy = dossierTemplate.createdBy;
|
||||
@ -40,6 +38,6 @@ export class DossierTemplate implements IDossierTemplate, IListable {
|
||||
}
|
||||
|
||||
get routerLink(): string {
|
||||
return `/main/admin/dossier-templates/${this.dossierTemplateId}/dictionaries`;
|
||||
return `/main/admin/dossier-templates/${this.dossierTemplateId}`;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,2 +1,4 @@
|
||||
export * from './dossier-template';
|
||||
export * from './dossier-template.model';
|
||||
export * from './dossier-template-stats';
|
||||
export * from './dossier-template-stats.model';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user