Pull request #220: RED-1635
Merge in RED/ui from RED-1635 to master * commit '8e995e2afed97cc82010c3765ee83549b7f59477': add min loading time to loading service recalculate data on edit and on delete skip requests for entries, show loading indicator when action finished refactor appLoadStateService update dialogs fix dictionary update
This commit is contained in:
commit
a0e02acca3
@ -1,4 +1,4 @@
|
||||
<router-outlet></router-outlet>
|
||||
<redaction-full-page-loading-indicator
|
||||
[displayed]="appLoadStateService.loading | async"
|
||||
[displayed]="loadingService.isLoading | async"
|
||||
></redaction-full-page-loading-indicator>
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { AppLoadStateService } from '@services/app-load-state.service';
|
||||
import { RouterHistoryService } from '@services/router-history.service';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-root',
|
||||
@ -8,8 +7,5 @@ import { RouterHistoryService } from '@services/router-history.service';
|
||||
styleUrls: ['./app.component.scss']
|
||||
})
|
||||
export class AppComponent {
|
||||
constructor(
|
||||
public appLoadStateService: AppLoadStateService,
|
||||
private readonly _routerHistoryService: RouterHistoryService
|
||||
) {}
|
||||
constructor(readonly loadingService: LoadingService) {}
|
||||
}
|
||||
|
||||
@ -1,26 +1,19 @@
|
||||
import {
|
||||
ActivatedRouteSnapshot,
|
||||
CanActivate,
|
||||
Router,
|
||||
RouterStateSnapshot,
|
||||
UrlTree
|
||||
} from '@angular/router';
|
||||
import { ActivatedRouteSnapshot, CanActivate, RouterStateSnapshot, UrlTree } from '@angular/router';
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { from, of } from 'rxjs';
|
||||
import { AppLoadStateService } from '@services/app-load-state.service';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class CompositeRouteGuard implements CanActivate {
|
||||
constructor(
|
||||
protected readonly _router: Router,
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _appLoadStateService: AppLoadStateService
|
||||
private readonly _loadingService: LoadingService
|
||||
) {}
|
||||
|
||||
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean> {
|
||||
this._appLoadStateService.pushLoadingEvent(true);
|
||||
this._loadingService.start();
|
||||
|
||||
const routeGuards = route.data.routeGuards;
|
||||
|
||||
@ -40,13 +33,13 @@ export class CompositeRouteGuard implements CanActivate {
|
||||
|
||||
const result = await canActivateResult.toPromise();
|
||||
if (!result) {
|
||||
this._appLoadStateService.pushLoadingEvent(false);
|
||||
this._loadingService.stop();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._appLoadStateService.pushLoadingEvent(false);
|
||||
this._loadingService.stop();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -40,18 +40,16 @@ export class DossierTemplateActionsComponent {
|
||||
);
|
||||
}
|
||||
|
||||
openDeleteDossierTemplateDialog($event: any) {
|
||||
this._dialogService.openDeleteDossierTemplateDialog(
|
||||
$event,
|
||||
this.dossierTemplate,
|
||||
async () => {
|
||||
await this._appStateService.loadAllDossierTemplates();
|
||||
await this._appStateService.loadDictionaryData();
|
||||
await this._router.navigate(['main', 'admin']);
|
||||
if (this.loadDossierTemplatesData) {
|
||||
this.loadDossierTemplatesData.emit();
|
||||
}
|
||||
openDeleteDossierTemplateDialog($event?: MouseEvent) {
|
||||
$event?.stopPropagation();
|
||||
|
||||
this._dialogService.openDeleteDossierTemplateDialog(this.dossierTemplate, async () => {
|
||||
await this._appStateService.loadAllDossierTemplates();
|
||||
await this._appStateService.loadDictionaryData();
|
||||
await this._router.navigate(['main', 'admin']);
|
||||
if (this.loadDossierTemplatesData) {
|
||||
this.loadDossierTemplatesData.emit();
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,19 +1,14 @@
|
||||
<section class="dialog">
|
||||
<div class="dialog-header heading-l">
|
||||
{{
|
||||
(dictionary ? 'add-edit-dictionary.title.edit' : 'add-edit-dictionary.title.new')
|
||||
| translate: { name: dictionary?.type | humanize }
|
||||
}}
|
||||
{{ dialogHeader }}
|
||||
</div>
|
||||
|
||||
<form (submit)="saveDictionary()" [formGroup]="dictionaryForm">
|
||||
<div class="dialog-content">
|
||||
<ng-container *ngIf="!!dictionary">
|
||||
<div class="red-input-group mb-14">
|
||||
<label translate="add-edit-dictionary.form.name"></label>
|
||||
{{ dictionary.label }}
|
||||
</div>
|
||||
</ng-container>
|
||||
<div class="red-input-group mb-14" *ngIf="!!dictionary">
|
||||
<label translate="add-edit-dictionary.form.name"></label>
|
||||
{{ dictionary.label }}
|
||||
</div>
|
||||
|
||||
<div class="first-row">
|
||||
<div *ngIf="!dictionary" class="red-input-group required">
|
||||
@ -53,13 +48,7 @@
|
||||
[style.background]="dictionaryForm.get('hexColor').value"
|
||||
class="input-icon"
|
||||
>
|
||||
<mat-icon
|
||||
*ngIf="
|
||||
!dictionaryForm.get('hexColor').value ||
|
||||
dictionaryForm.get('hexColor').value?.length === 0
|
||||
"
|
||||
svgIcon="red:color-picker"
|
||||
></mat-icon>
|
||||
<mat-icon *ngIf="hasColor" svgIcon="red:color-picker"></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -81,11 +70,11 @@
|
||||
<div class="red-input-group slider-row">
|
||||
<mat-button-toggle-group appearance="legacy" formControlName="hint" name="hint">
|
||||
<mat-button-toggle [value]="false">
|
||||
{{ 'add-edit-dictionary.form.redaction' | translate }}</mat-button-toggle
|
||||
>
|
||||
{{ 'add-edit-dictionary.form.redaction' | translate }}
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle [value]="true">
|
||||
{{ 'add-edit-dictionary.form.hint' | translate }}</mat-button-toggle
|
||||
>
|
||||
{{ 'add-edit-dictionary.form.hint' | translate }}
|
||||
</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { DictionaryControllerService, TypeValue } from '@redaction/red-ui-http';
|
||||
@ -7,6 +6,7 @@ import { Observable } from 'rxjs';
|
||||
import { NotificationService, NotificationType } from '@services/notification.service';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { TypeValueWrapper } from '../../../../models/file/type-value.wrapper';
|
||||
import { humanize } from '../../../../utils/functions';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-add-edit-dictionary-dialog',
|
||||
@ -20,17 +20,16 @@ export class AddEditDictionaryDialogComponent {
|
||||
|
||||
constructor(
|
||||
private readonly _dictionaryControllerService: DictionaryControllerService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _notificationService: NotificationService,
|
||||
private readonly _translateService: TranslateService,
|
||||
public dialogRef: MatDialogRef<AddEditDictionaryDialogComponent>,
|
||||
private readonly _dialogRef: MatDialogRef<AddEditDictionaryDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
public data: { dictionary: TypeValueWrapper; dossierTemplateId: string }
|
||||
private readonly _data: { dictionary: TypeValueWrapper; dossierTemplateId: string }
|
||||
) {
|
||||
this.dictionary = data.dictionary;
|
||||
this._dossierTemplateId = data.dossierTemplateId;
|
||||
this.dictionaryForm = this._formBuilder.group({
|
||||
this.dictionary = _data.dictionary;
|
||||
this._dossierTemplateId = _data.dossierTemplateId;
|
||||
this.dictionaryForm = _formBuilder.group({
|
||||
type: [this.dictionary?.type, [Validators.required, Validators.minLength(3)]],
|
||||
description: [this.dictionary?.description],
|
||||
rank: [this.dictionary?.rank, Validators.required],
|
||||
@ -41,7 +40,19 @@ export class AddEditDictionaryDialogComponent {
|
||||
});
|
||||
}
|
||||
|
||||
get dictCaseSensitive() {
|
||||
get dialogHeader(): string {
|
||||
const i18nString = 'add-edit-dictionary.title.' + (this.dictionary ? 'edit' : 'new');
|
||||
return this._translateService.instant(i18nString, {
|
||||
name: humanize(this.dictionary?.type)
|
||||
});
|
||||
}
|
||||
|
||||
get hasColor(): boolean {
|
||||
const hexColorValue = this.dictionaryForm.get('hexColor').value;
|
||||
return !hexColorValue || hexColorValue?.length === 0;
|
||||
}
|
||||
|
||||
get dictCaseSensitive(): boolean {
|
||||
return this.dictionary ? !this.dictionary.caseInsensitive : false;
|
||||
}
|
||||
|
||||
@ -63,14 +74,14 @@ export class AddEditDictionaryDialogComponent {
|
||||
|
||||
async saveDictionary() {
|
||||
const typeValue: TypeValue = this._formToObject();
|
||||
|
||||
let observable: Observable<any>;
|
||||
|
||||
if (this.dictionary) {
|
||||
// edit mode
|
||||
observable = this._dictionaryControllerService.updateType(
|
||||
typeValue,
|
||||
typeValue.type,
|
||||
this._dossierTemplateId
|
||||
this._dossierTemplateId,
|
||||
typeValue.type
|
||||
);
|
||||
} else {
|
||||
// create mode
|
||||
@ -79,9 +90,7 @@ export class AddEditDictionaryDialogComponent {
|
||||
}
|
||||
|
||||
observable.subscribe(
|
||||
() => {
|
||||
this.dialogRef.close({ dictionary: this.dictionary ? null : typeValue });
|
||||
},
|
||||
() => this._dialogRef.close(this.dictionary ? null : typeValue),
|
||||
error => {
|
||||
if (error.status === 409) {
|
||||
this._notifyError('add-edit-dictionary.error.dictionary-already-exists');
|
||||
|
||||
@ -115,7 +115,7 @@ export class AddEditDossierTemplateDialogComponent {
|
||||
.toPromise();
|
||||
await this._appStateService.loadAllDossierTemplates();
|
||||
await this._appStateService.loadDictionaryData();
|
||||
this.dialogRef.close({ dossierTemplate });
|
||||
this.dialogRef.close(dossierTemplate);
|
||||
}
|
||||
|
||||
private _applyValidityIntervalConstraints(value): boolean {
|
||||
|
||||
@ -22,14 +22,14 @@ export class EditColorDialogComponent {
|
||||
private readonly _dictionaryControllerService: DictionaryControllerService,
|
||||
private readonly _notificationService: NotificationService,
|
||||
private readonly _translateService: TranslateService,
|
||||
public dialogRef: MatDialogRef<EditColorDialogComponent>,
|
||||
private readonly _dialogRef: MatDialogRef<EditColorDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
public data: { colors: Colors; colorKey: string; dossierTemplateId: string }
|
||||
private readonly _data: { colors: Colors; colorKey: string; dossierTemplateId: string }
|
||||
) {
|
||||
this.colors = data.colors;
|
||||
this.colorKey = data.colorKey;
|
||||
this._dossierTemplateId = data.dossierTemplateId;
|
||||
this._initialColor = data.colors[this.colorKey];
|
||||
this.colors = _data.colors;
|
||||
this.colorKey = _data.colorKey;
|
||||
this._dossierTemplateId = _data.dossierTemplateId;
|
||||
this._initialColor = _data.colors[this.colorKey];
|
||||
|
||||
this.colorForm = this._formBuilder.group({
|
||||
color: [this.colors[this.colorKey], [Validators.required, Validators.minLength(7)]]
|
||||
@ -50,7 +50,7 @@ export class EditColorDialogComponent {
|
||||
await this._dictionaryControllerService
|
||||
.setColors(colors, this._dossierTemplateId)
|
||||
.toPromise();
|
||||
this.dialogRef.close(true);
|
||||
this._dialogRef.close(true);
|
||||
this._notificationService.showToastNotification(
|
||||
this._translateService.instant('edit-color-dialog.success', {
|
||||
color: this._translateService.instant(
|
||||
|
||||
@ -28,25 +28,17 @@ export class DefaultColorsScreenComponent extends BaseListingComponent<{
|
||||
protected readonly _injector: Injector
|
||||
) {
|
||||
super(_injector);
|
||||
this._appStateService.activateDossierTemplate(
|
||||
_activatedRoute.snapshot.params.dossierTemplateId
|
||||
);
|
||||
_appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId);
|
||||
this._loadColors();
|
||||
}
|
||||
|
||||
async loadDossierTemplatesData(): Promise<void> {
|
||||
await this._appStateService.loadAllDossierTemplates();
|
||||
}
|
||||
|
||||
openEditColorDialog($event: any, color: { key: string; value: string }) {
|
||||
$event.stopPropagation();
|
||||
this._dialogService.openEditColorsDialog(
|
||||
this._colorsObj,
|
||||
color.key,
|
||||
this._appStateService.activeDossierTemplateId,
|
||||
async () => {
|
||||
this._loadColors();
|
||||
}
|
||||
async () => this._loadColors()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -30,23 +30,16 @@
|
||||
</div>
|
||||
|
||||
<span class="all-caps-label">
|
||||
{{
|
||||
'dictionary-listing.table-header.title'
|
||||
| translate: { length: displayedEntities.length }
|
||||
}}
|
||||
{{ tableHeader }}
|
||||
</span>
|
||||
|
||||
<ng-container *ngIf="areSomeEntitiesSelected && !loading">
|
||||
<redaction-circle-button
|
||||
(action)="openDeleteDictionariesDialog($event)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
icon="red:trash"
|
||||
tooltip="dictionary-listing.bulk.delete"
|
||||
type="dark-bg"
|
||||
></redaction-circle-button>
|
||||
</ng-container>
|
||||
|
||||
<mat-spinner *ngIf="loading" diameter="15"></mat-spinner>
|
||||
<redaction-circle-button
|
||||
(action)="openDeleteDictionariesDialog($event)"
|
||||
*ngIf="areSomeEntitiesSelected && permissionsService.isAdmin()"
|
||||
icon="red:trash"
|
||||
tooltip="dictionary-listing.bulk.delete"
|
||||
type="dark-bg"
|
||||
></redaction-circle-button>
|
||||
|
||||
<div class="attributes-actions-container">
|
||||
<redaction-input-with-action
|
||||
@ -160,25 +153,21 @@
|
||||
></redaction-annotation-icon>
|
||||
</div>
|
||||
|
||||
<div class="actions-container">
|
||||
<div class="actions-container" *ngIf="permissionsService.isAdmin()">
|
||||
<div class="action-buttons">
|
||||
<redaction-circle-button
|
||||
(action)="openDeleteDictionariesDialog($event, [dict.type])"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
icon="red:trash"
|
||||
tooltip="dictionary-listing.action.delete"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="openAddEditDictionaryDialog($event, dict)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
icon="red:edit"
|
||||
tooltip="dictionary-listing.action.edit"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="scrollbar-placeholder"></div>
|
||||
@ -199,7 +188,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<redaction-full-page-loading-indicator
|
||||
[displayed]="!viewReady"
|
||||
></redaction-full-page-loading-indicator>
|
||||
|
||||
@ -9,6 +9,15 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { BaseListingComponent } from '@shared/base/base-listing.component';
|
||||
import { TypeValueWrapper } from '../../../../models/file/type-value.wrapper';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { LoadingService } from '../../../../services/loading.service';
|
||||
|
||||
const toChartConfig = (dict: TypeValueWrapper): DoughnutChartConfig => ({
|
||||
value: dict.entries ? dict.entries.length : 0,
|
||||
color: dict.hexColor,
|
||||
label: dict.label,
|
||||
key: dict.type
|
||||
});
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-dictionary-listing-screen',
|
||||
@ -19,9 +28,7 @@ export class DictionaryListingScreenComponent
|
||||
extends BaseListingComponent<TypeValueWrapper>
|
||||
implements OnInit
|
||||
{
|
||||
viewReady = false;
|
||||
chartData: DoughnutChartConfig[] = [];
|
||||
loading = false;
|
||||
protected readonly _searchKey = 'label';
|
||||
protected readonly _selectionKey = 'type';
|
||||
protected readonly _sortKey = 'dictionary-listing';
|
||||
@ -31,13 +38,20 @@ export class DictionaryListingScreenComponent
|
||||
private readonly _dictionaryControllerService: DictionaryControllerService,
|
||||
private readonly _activatedRoute: ActivatedRoute,
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _translateService: TranslateService,
|
||||
readonly permissionsService: PermissionsService,
|
||||
protected readonly _injector: Injector
|
||||
) {
|
||||
super(_injector);
|
||||
this._appStateService.activateDossierTemplate(
|
||||
_activatedRoute.snapshot.params.dossierTemplateId
|
||||
);
|
||||
_loadingService.start();
|
||||
_appStateService.activateDossierTemplate(_activatedRoute.snapshot.params.dossierTemplateId);
|
||||
}
|
||||
|
||||
get tableHeader(): string {
|
||||
return this._translateService.instant('dictionary-listing.table-header.title', {
|
||||
length: this.displayedEntities.length
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -47,15 +61,15 @@ export class DictionaryListingScreenComponent
|
||||
openDeleteDictionariesDialog($event?: MouseEvent, types = this.selectedEntitiesIds) {
|
||||
$event?.stopPropagation();
|
||||
this._dialogService.openDeleteDictionariesDialog(
|
||||
$event,
|
||||
types,
|
||||
this._appStateService.activeDossierTemplateId,
|
||||
async () => {
|
||||
this.selectedEntitiesIds = [];
|
||||
this.loading = true;
|
||||
this._loadingService.start();
|
||||
await this._appStateService.loadDictionaryData();
|
||||
this._loadDictionaryData();
|
||||
this.loading = false;
|
||||
this._loadDictionaryData(false);
|
||||
this._calculateData();
|
||||
this._loadingService.stop();
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -67,27 +81,37 @@ export class DictionaryListingScreenComponent
|
||||
this._appStateService.activeDossierTemplateId,
|
||||
async newDictionary => {
|
||||
if (newDictionary) {
|
||||
this._loadingService.start();
|
||||
await this._appStateService.loadDictionaryData();
|
||||
this._loadDictionaryData();
|
||||
this._loadDictionaryData(false);
|
||||
this._calculateData();
|
||||
this._loadingService.stop();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private _loadDictionaryData() {
|
||||
private _loadDictionaryData(loadEntries = true): void {
|
||||
const appStateDictionaryData =
|
||||
this._appStateService.dictionaryData[this._appStateService.activeDossierTemplateId];
|
||||
this.allEntities = Object.keys(appStateDictionaryData)
|
||||
.map(key => appStateDictionaryData[key])
|
||||
.filter(d => !d.virtual);
|
||||
const entities = Object.values(appStateDictionaryData).filter(d => !d.virtual);
|
||||
|
||||
if (!loadEntries)
|
||||
this.allEntities = entities.map(dict => {
|
||||
dict.entries = this.allEntities.find(d => d.type === dict.type)?.entries || [];
|
||||
return dict;
|
||||
});
|
||||
else this.allEntities = entities;
|
||||
|
||||
this.displayedEntities = [...this.allEntities];
|
||||
|
||||
if (!loadEntries) return;
|
||||
|
||||
const dataObs = this.allEntities.map(dict =>
|
||||
this._dictionaryControllerService
|
||||
.getDictionaryForType(this._appStateService.activeDossierTemplateId, dict.type)
|
||||
.pipe(
|
||||
tap(values => {
|
||||
dict.entries = values.entries ? values.entries : [];
|
||||
}),
|
||||
tap(values => (dict.entries = values.entries ?? [])),
|
||||
catchError(() => {
|
||||
console.log('error');
|
||||
dict.entries = [];
|
||||
@ -95,24 +119,15 @@ export class DictionaryListingScreenComponent
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
forkJoin(dataObs)
|
||||
.pipe(defaultIfEmpty(null))
|
||||
.subscribe(() => {
|
||||
this._calculateData();
|
||||
});
|
||||
.subscribe(() => this._calculateData());
|
||||
}
|
||||
|
||||
private _calculateData() {
|
||||
this.chartData = [];
|
||||
for (const dict of this.allEntities) {
|
||||
this.chartData.push({
|
||||
value: dict.entries ? dict.entries.length : 0,
|
||||
color: dict.hexColor,
|
||||
label: dict.label,
|
||||
key: dict.type
|
||||
});
|
||||
}
|
||||
private _calculateData(): void {
|
||||
this.chartData = this.allEntities.map(dict => toChartConfig(dict));
|
||||
this.chartData.sort((a, b) => (a.label < b.label ? -1 : 1));
|
||||
this.viewReady = true;
|
||||
this._loadingService.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,8 +10,7 @@
|
||||
tooltip="dictionary-overview.action.delete"
|
||||
tooltipPosition="below"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="openEditDictionaryDialog($event)"
|
||||
@ -20,8 +19,7 @@
|
||||
tooltip="dictionary-overview.action.edit"
|
||||
tooltipPosition="below"
|
||||
type="dark-bg"
|
||||
>
|
||||
</redaction-circle-button>
|
||||
></redaction-circle-button>
|
||||
|
||||
<redaction-circle-button
|
||||
(action)="download()"
|
||||
|
||||
@ -64,14 +64,15 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple
|
||||
);
|
||||
}
|
||||
|
||||
openDeleteDictionaryDialog($event: any) {
|
||||
openDeleteDictionaryDialog($event?: MouseEvent) {
|
||||
$event?.stopPropagation();
|
||||
|
||||
this._dialogService.openDeleteDictionariesDialog(
|
||||
$event,
|
||||
[this.dictionary.type],
|
||||
this.dictionary.dossierTemplateId,
|
||||
async () => {
|
||||
await this._appStateService.loadDictionaryData();
|
||||
this._router.navigate([
|
||||
await this._router.navigate([
|
||||
'/main',
|
||||
'admin',
|
||||
'dossier-templates',
|
||||
|
||||
@ -36,8 +36,8 @@ export class DossierTemplatesListingScreenComponent
|
||||
|
||||
openDeleteTemplatesDialog($event?: MouseEvent) {
|
||||
$event?.stopPropagation();
|
||||
|
||||
this._dialogService.openBulkDeleteDossierTemplatesDialog(
|
||||
$event,
|
||||
this.selectedEntitiesIds,
|
||||
async () => {
|
||||
this.selectedEntitiesIds = [];
|
||||
|
||||
@ -7,20 +7,16 @@ import {
|
||||
DossierTemplateModel,
|
||||
FileAttributeConfig,
|
||||
FileAttributesConfig,
|
||||
FileManagementControllerService,
|
||||
ManualRedactionControllerService,
|
||||
SMTPConfigurationModel,
|
||||
TypeValue,
|
||||
User
|
||||
} from '@redaction/red-ui-http';
|
||||
import { AddEditFileAttributeDialogComponent } from '../dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component';
|
||||
import { AddEditDictionaryDialogComponent } from '../dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component';
|
||||
import { AddEditDossierTemplateDialogComponent } from '../dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component';
|
||||
import { NotificationService } from '@services/notification.service';
|
||||
import { ConfirmationDialogComponent } from '@shared/dialogs/confirmation-dialog/confirmation-dialog.component';
|
||||
import { AppStateService } from '@state/app-state.service';
|
||||
import { ConfirmDeleteFileAttributeDialogComponent } from '../dialogs/confirm-delete-file-attribute-dialog/confirm-delete-file-attribute-dialog.component';
|
||||
import { EditColorDialogComponent } from '../dialogs/edit-color-dialog/edit-color-dialog.component';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { SmtpAuthDialogComponent } from '../dialogs/smtp-auth-dialog/smtp-auth-dialog.component';
|
||||
import { AddEditUserDialogComponent } from '../dialogs/add-edit-user-dialog/add-edit-user-dialog.component';
|
||||
import { ConfirmDeleteUsersDialogComponent } from '../dialogs/confirm-delete-users-dialog/confirm-delete-users-dialog.component';
|
||||
@ -44,22 +40,15 @@ const dialogConfig = {
|
||||
export class AdminDialogService {
|
||||
constructor(
|
||||
private readonly _dialog: MatDialog,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
private readonly _dossierTemplateControllerService: DossierTemplateControllerService,
|
||||
private readonly _dictionaryControllerService: DictionaryControllerService,
|
||||
private readonly _fileManagementControllerService: FileManagementControllerService,
|
||||
private readonly _notificationService: NotificationService,
|
||||
private readonly _manualRedactionControllerService: ManualRedactionControllerService
|
||||
private readonly _dictionaryControllerService: DictionaryControllerService
|
||||
) {}
|
||||
|
||||
openDeleteDictionariesDialog(
|
||||
$event: MouseEvent,
|
||||
dictionaryTypes: string[],
|
||||
dossierTemplateId: string,
|
||||
cb?: Function
|
||||
cb?: () => void
|
||||
): MatDialogRef<ConfirmationDialogComponent> {
|
||||
$event.stopPropagation();
|
||||
const ref = this._dialog.open(ConfirmationDialogComponent, dialogConfig);
|
||||
ref.afterClosed().subscribe(async result => {
|
||||
if (result) {
|
||||
@ -73,11 +62,9 @@ export class AdminDialogService {
|
||||
}
|
||||
|
||||
openDeleteDossierTemplateDialog(
|
||||
$event: MouseEvent,
|
||||
dossierTemplate: DossierTemplateModel,
|
||||
cb?: Function
|
||||
cb?: () => void
|
||||
): MatDialogRef<ConfirmationDialogComponent> {
|
||||
$event.stopPropagation();
|
||||
const ref = this._dialog.open(ConfirmationDialogComponent, dialogConfig);
|
||||
ref.afterClosed().subscribe(async result => {
|
||||
if (result) {
|
||||
@ -88,11 +75,9 @@ export class AdminDialogService {
|
||||
}
|
||||
|
||||
openBulkDeleteDossierTemplatesDialog(
|
||||
$event: MouseEvent,
|
||||
dossierTemplateIds: string[],
|
||||
cb?: Function
|
||||
): MatDialogRef<ConfirmationDialogComponent> {
|
||||
$event.stopPropagation();
|
||||
const ref = this._dialog.open(ConfirmationDialogComponent, dialogConfig);
|
||||
ref.afterClosed().subscribe(async result => {
|
||||
if (result) {
|
||||
@ -105,7 +90,7 @@ export class AdminDialogService {
|
||||
openAddEditDictionaryDialog(
|
||||
dictionary: TypeValueWrapper,
|
||||
dossierTemplateId: string,
|
||||
cb?: Function
|
||||
cb?: (newDictionary: TypeValue | null) => void
|
||||
): MatDialogRef<AddEditDictionaryDialogComponent> {
|
||||
const ref = this._dialog.open(AddEditDictionaryDialogComponent, {
|
||||
...dialogConfig,
|
||||
@ -113,10 +98,9 @@ export class AdminDialogService {
|
||||
autoFocus: true
|
||||
});
|
||||
|
||||
ref.afterClosed().subscribe(result => {
|
||||
if (result && cb) {
|
||||
cb(result);
|
||||
}
|
||||
ref.afterClosed().subscribe((newDictionary: TypeValue) => {
|
||||
if (newDictionary && cb) cb(newDictionary);
|
||||
else if (cb) cb(null);
|
||||
});
|
||||
|
||||
return ref;
|
||||
@ -126,7 +110,7 @@ export class AdminDialogService {
|
||||
colors: Colors,
|
||||
colorKey: string,
|
||||
dossierTemplateId: string,
|
||||
cb?: Function
|
||||
cb?: (result: boolean) => void
|
||||
): MatDialogRef<EditColorDialogComponent> {
|
||||
const ref = this._dialog.open(EditColorDialogComponent, {
|
||||
...dialogConfig,
|
||||
@ -134,7 +118,7 @@ export class AdminDialogService {
|
||||
autoFocus: true
|
||||
});
|
||||
|
||||
ref.afterClosed().subscribe(result => {
|
||||
ref.afterClosed().subscribe((result: boolean) => {
|
||||
if (result && cb) {
|
||||
cb(result);
|
||||
}
|
||||
|
||||
@ -2,7 +2,6 @@ import { Inject, Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { KeycloakAuthGuard, KeycloakService } from 'keycloak-angular';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { AppLoadStateService } from '@services/app-load-state.service';
|
||||
import { AppConfigKey, AppConfigService } from '@app-config/app-config.service';
|
||||
import { BASE_HREF } from '../../tokens';
|
||||
|
||||
@ -15,7 +14,6 @@ export class AuthGuard extends KeycloakAuthGuard {
|
||||
protected readonly _router: Router,
|
||||
protected readonly _keycloak: KeycloakService,
|
||||
private readonly _appConfigService: AppConfigService,
|
||||
private readonly _appLoadStateService: AppLoadStateService,
|
||||
private readonly _userService: UserService
|
||||
) {
|
||||
super(_router, _keycloak);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { AppLoadStateService } from '@services/app-load-state.service';
|
||||
import { LoadingService } from '@services/loading.service';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
@ -10,7 +10,7 @@ import { Observable } from 'rxjs';
|
||||
export class RedRoleGuard implements CanActivate {
|
||||
constructor(
|
||||
protected readonly _router: Router,
|
||||
private readonly _appLoadStateService: AppLoadStateService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _userService: UserService
|
||||
) {}
|
||||
|
||||
@ -18,7 +18,7 @@ export class RedRoleGuard implements CanActivate {
|
||||
return new Observable(obs => {
|
||||
if (!this._userService.user.hasAnyREDRoles) {
|
||||
this._router.navigate(['/auth-error']);
|
||||
this._appLoadStateService.pushLoadingEvent(false);
|
||||
this._loadingService.stop();
|
||||
obs.next(false);
|
||||
obs.complete();
|
||||
} else {
|
||||
|
||||
@ -162,14 +162,13 @@ export class DictionaryManagerComponent implements OnChanges, OnInit {
|
||||
}
|
||||
|
||||
private _applySearchDecorations() {
|
||||
this._searchDecorations = this._codeEditor?.deltaDecorations(this._searchDecorations, []);
|
||||
this._searchDecorations =
|
||||
this._codeEditor?.deltaDecorations(this._searchDecorations, []) || [];
|
||||
|
||||
const decorations = this.findMatches.map(match => this._getSearchDecoration(match));
|
||||
|
||||
this._searchDecorations = this._codeEditor?.deltaDecorations(
|
||||
this._searchDecorations,
|
||||
decorations
|
||||
);
|
||||
this._searchDecorations =
|
||||
this._codeEditor?.deltaDecorations(this._searchDecorations, decorations) || [];
|
||||
}
|
||||
|
||||
private _getMatches(text: string): FindMatch[] {
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
import { EventEmitter, Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class AppLoadStateService {
|
||||
private _loadingEvent = new EventEmitter();
|
||||
|
||||
get loading(): Observable<boolean> {
|
||||
return this._loadingEvent;
|
||||
}
|
||||
|
||||
pushLoadingEvent(event: boolean) {
|
||||
this._loadingEvent.next(event);
|
||||
}
|
||||
}
|
||||
33
apps/red-ui/src/app/services/loading.service.ts
Normal file
33
apps/red-ui/src/app/services/loading.service.ts
Normal file
@ -0,0 +1,33 @@
|
||||
import { EventEmitter, Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
const MIN_LOADING_TIME = 300;
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class LoadingService {
|
||||
private readonly _loadingEvent = new EventEmitter();
|
||||
private _loadingStarted: number;
|
||||
|
||||
get isLoading(): Observable<boolean> {
|
||||
return this._loadingEvent;
|
||||
}
|
||||
|
||||
start(): void {
|
||||
this._loadingEvent.next(true);
|
||||
this._loadingStarted = new Date().getTime();
|
||||
}
|
||||
|
||||
stop(): void {
|
||||
const timeDelta = new Date().getTime() - this._loadingStarted;
|
||||
if (timeDelta < MIN_LOADING_TIME) {
|
||||
setTimeout(() => {
|
||||
this._loadingEvent.next(false);
|
||||
}, MIN_LOADING_TIME - timeDelta);
|
||||
return;
|
||||
}
|
||||
|
||||
this._loadingEvent.next(false);
|
||||
}
|
||||
}
|
||||
@ -17,7 +17,7 @@ export type ScreenName =
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SortingService {
|
||||
private _options: { [key: string]: SortingOption } = {
|
||||
private readonly _options: { [key: string]: SortingOption } = {
|
||||
'dossier-listing': { column: 'dossier.dossierName', order: 'asc' },
|
||||
'dossier-overview': { column: 'filename', order: 'asc' },
|
||||
'dictionary-listing': { column: 'label', order: 'asc' },
|
||||
@ -26,8 +26,6 @@ export class SortingService {
|
||||
'file-attributes-listing': { column: 'label', order: 'asc' }
|
||||
};
|
||||
|
||||
constructor() {}
|
||||
|
||||
toggleSort(screen: ScreenName, column: string) {
|
||||
if (this._options[screen].column === column) {
|
||||
const currentOrder = this._options[screen].order;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user