Permissions
This commit is contained in:
parent
ed84299160
commit
c93eabbdc2
@ -2,6 +2,7 @@
|
||||
<ng-container *ngFor="let item of items[type]">
|
||||
<a
|
||||
*ngIf="!item.hideIf"
|
||||
[class.disabled]="isDisabled(item.screen)"
|
||||
[routerLinkActiveOptions]="{ exact: false }"
|
||||
[routerLink]="prefix + item.screen"
|
||||
class="item"
|
||||
|
||||
@ -20,6 +20,7 @@ interface NavItem {
|
||||
})
|
||||
export class AdminSideNavComponent implements OnInit {
|
||||
@Input() type: AdminSideNavType;
|
||||
@Input() disabledItems: string[] = [];
|
||||
readonly translations = adminSideNavTranslations;
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
prefix: string;
|
||||
@ -89,4 +90,8 @@ export class AdminSideNavComponent implements OnInit {
|
||||
ngOnInit(): void {
|
||||
this.prefix = this._route.snapshot.paramMap.get(ENTITY_TYPE) ? '' : '../';
|
||||
}
|
||||
|
||||
isDisabled(screen: string): boolean {
|
||||
return this.disabledItems.includes(screen);
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,7 @@ import { DossierTemplateBreadcrumbsComponent } from './components/dossier-templa
|
||||
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';
|
||||
import { AddEditDictionaryDialogComponent } from './dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component';
|
||||
import { AddEntityDialogComponent } from './dialogs/add-entity-dialog/add-entity-dialog.component';
|
||||
import { EditColorDialogComponent } from './dialogs/edit-color-dialog/edit-color-dialog.component';
|
||||
import { ComboChartComponent, ComboSeriesVerticalComponent } from './components/combo-chart';
|
||||
import { NgxChartsModule } from '@swimlane/ngx-charts';
|
||||
@ -51,7 +51,7 @@ import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-scre
|
||||
|
||||
const dialogs = [
|
||||
AddEditDossierTemplateDialogComponent,
|
||||
AddEditDictionaryDialogComponent,
|
||||
AddEntityDialogComponent,
|
||||
AddEditFileAttributeDialogComponent,
|
||||
EditColorDialogComponent,
|
||||
SmtpAuthDialogComponent,
|
||||
|
||||
@ -22,7 +22,7 @@
|
||||
<div class="content-inner">
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
<redaction-admin-side-nav type="entities"></redaction-admin-side-nav>
|
||||
<redaction-admin-side-nav [disabledItems]="disabledItems$ | async" type="entities"></redaction-admin-side-nav>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
|
||||
@ -1,12 +1,14 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@utils/constants';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
import { AdminDialogService } from '../services/admin-dialog.service';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { LoadingService } from '@iqser/common-ui';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
templateUrl: './base-entity-screen.component.html',
|
||||
@ -14,6 +16,7 @@ import { DossierTemplatesService } from '@services/entity-services/dossier-templ
|
||||
})
|
||||
export class BaseEntityScreenComponent {
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
readonly disabledItems$: Observable<string[]>;
|
||||
readonly #dossierTemplateId: string;
|
||||
readonly #entityType: string;
|
||||
|
||||
@ -23,11 +26,15 @@ export class BaseEntityScreenComponent {
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _dictionaryMapService: DictionariesMapService,
|
||||
private readonly _dossierTemplatesService: DossierTemplatesService,
|
||||
private readonly _router: Router,
|
||||
) {
|
||||
this.#dossierTemplateId = this._route.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID);
|
||||
this.#entityType = this._route.snapshot.paramMap.get(ENTITY_TYPE);
|
||||
this.disabledItems$ = this._dictionaryMapService
|
||||
.watch$(this.#dossierTemplateId, this.#entityType)
|
||||
.pipe(map(entity => (entity.hasDictionary ? [] : ['dictionary', 'false-positive', 'false-recommendations'])));
|
||||
}
|
||||
|
||||
openDeleteDictionariesDialog() {
|
||||
|
||||
@ -6,31 +6,31 @@
|
||||
<form [formGroup]="form">
|
||||
<div class="dialog-content">
|
||||
<div class="iqser-input-group mb-14">
|
||||
<label translate="add-edit-dictionary.form.technical-name"></label>
|
||||
<label translate="add-entity.form.technical-name"></label>
|
||||
<div class="technical-name">{{ dictionary?.type || (technicalName$ | async) || '-' }}</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="(canEditLabel$ | async) === false" class="iqser-input-group mb-14">
|
||||
<label translate="add-edit-dictionary.form.name"></label>
|
||||
<label translate="add-entity.form.name"></label>
|
||||
{{ dictionary.label }}
|
||||
</div>
|
||||
|
||||
<div class="first-row">
|
||||
<div *ngIf="canEditLabel$ | async" class="iqser-input-group required">
|
||||
<label translate="add-edit-dictionary.form.name"></label>
|
||||
<label translate="add-entity.form.name"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-dictionary.form.name-placeholder' | translate"
|
||||
[placeholder]="'add-entity.form.name-placeholder' | translate"
|
||||
formControlName="label"
|
||||
name="label"
|
||||
type="text"
|
||||
/>
|
||||
<span class="hint" translate="add-edit-dictionary.form.name-hint"></span>
|
||||
<span class="hint" translate="add-entity.form.name-hint"></span>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group required w-75">
|
||||
<label translate="add-edit-dictionary.form.rank"></label>
|
||||
<label translate="add-entity.form.rank"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-dictionary.form.rank-placeholder' | translate"
|
||||
[placeholder]="'add-entity.form.rank-placeholder' | translate"
|
||||
formControlName="rank"
|
||||
name="rank"
|
||||
type="number"
|
||||
@ -38,9 +38,9 @@
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group required">
|
||||
<label translate="add-edit-dictionary.form.color"></label>
|
||||
<label translate="add-entity.form.color"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-dictionary.form.color-placeholder' | translate"
|
||||
[placeholder]="'add-entity.form.color-placeholder' | translate"
|
||||
class="hex-color-input"
|
||||
formControlName="hexColor"
|
||||
name="hexColor"
|
||||
@ -59,9 +59,9 @@
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group w-450">
|
||||
<label translate="add-edit-dictionary.form.description"></label>
|
||||
<label translate="add-entity.form.description"></label>
|
||||
<textarea
|
||||
[placeholder]="'add-edit-dictionary.form.description-placeholder' | translate"
|
||||
[placeholder]="'add-entity.form.description-placeholder' | translate"
|
||||
formControlName="description"
|
||||
iqserHasScrollbar
|
||||
name="description"
|
||||
@ -73,30 +73,30 @@
|
||||
<div class="iqser-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 }}
|
||||
{{ 'add-entity.form.redaction' | translate }}
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle [value]="true">
|
||||
{{ 'add-edit-dictionary.form.hint' | translate }}
|
||||
{{ 'add-entity.form.hint' | translate }}
|
||||
</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<mat-checkbox color="primary" formControlName="caseSensitive" name="caseSensitive">
|
||||
{{ 'add-edit-dictionary.form.case-sensitive' | translate }}
|
||||
{{ 'add-entity.form.case-sensitive' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<mat-checkbox color="primary" formControlName="addToDictionaryAction" name="addToDictionaryAction">
|
||||
{{ 'add-edit-dictionary.form.add-to-dictionary-action' | translate }}
|
||||
{{ 'add-entity.form.add-to-dictionary-action' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button type="button">
|
||||
{{ 'add-edit-dictionary.save' | translate }}
|
||||
{{ 'add-entity.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@ -13,19 +13,15 @@ import { map } from 'rxjs/operators';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-add-edit-dictionary-dialog',
|
||||
templateUrl: './add-edit-dictionary-dialog.component.html',
|
||||
styleUrls: ['./add-edit-dictionary-dialog.component.scss'],
|
||||
templateUrl: './add-entity-dialog.component.html',
|
||||
styleUrls: ['./add-entity-dialog.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AddEditDictionaryDialogComponent extends BaseDialogComponent {
|
||||
export class AddEntityDialogComponent extends BaseDialogComponent {
|
||||
readonly dictionary = this._data.dictionary;
|
||||
readonly canEditLabel$ = this._canEditLabel$;
|
||||
readonly technicalName$: Observable<string>;
|
||||
readonly dialogHeader = this._translateService.instant('add-edit-dictionary.title', {
|
||||
type: this._data.dictionary ? 'edit' : 'create',
|
||||
name: this._data.dictionary?.label,
|
||||
});
|
||||
readonly dialogHeader = this._translateService.instant('add-entity.title');
|
||||
readonly hasColor$: Observable<boolean>;
|
||||
private readonly _dossierTemplateId = this._data.dossierTemplateId;
|
||||
|
||||
@ -38,7 +34,7 @@ export class AddEditDictionaryDialogComponent extends BaseDialogComponent {
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
protected readonly _injector: Injector,
|
||||
protected readonly _dialogRef: MatDialogRef<AddEditDictionaryDialogComponent>,
|
||||
protected readonly _dialogRef: MatDialogRef<AddEntityDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
private readonly _data: { readonly dictionary: Dictionary; readonly dossierTemplateId: string },
|
||||
) {
|
||||
@ -73,11 +69,11 @@ export class AddEditDictionaryDialogComponent extends BaseDialogComponent {
|
||||
if (this.dictionary) {
|
||||
// edit mode
|
||||
await firstValueFrom(this._dictionaryService.updateDictionary(dictionary, dossierTemplateId, dictionary.type));
|
||||
this._toaster.success(_('add-edit-dictionary.success.edit'));
|
||||
this._toaster.success(_('add-entity.success.edit'));
|
||||
} else {
|
||||
// create mode
|
||||
await firstValueFrom(this._dictionaryService.addDictionary({ ...dictionary, dossierTemplateId }));
|
||||
this._toaster.success(_('add-edit-dictionary.success.create'));
|
||||
this._toaster.success(_('add-entity.success.create'));
|
||||
}
|
||||
this._dialogRef.close(true);
|
||||
} catch (e) {}
|
||||
@ -21,15 +21,16 @@
|
||||
|
||||
<div class="content-container">
|
||||
<iqser-table
|
||||
(noDataAction)="openAddEditDictionaryDialog()"
|
||||
(noDataAction)="openAddEntityDialog()"
|
||||
[bulkActions]="bulkActions"
|
||||
[headerTemplate]="headerTemplate"
|
||||
[itemSize]="80"
|
||||
[noDataButtonIcon]="'iqser:plus'"
|
||||
[noDataButtonLabel]="'entities-listing.no-data.action' | translate"
|
||||
[noDataText]="'entities-listing.no-data.title' | translate"
|
||||
[noMatchText]="'entities-listing.no-match.title' | translate"
|
||||
[selectionEnabled]="true"
|
||||
[showNoDataButton]="currentUser.isAdmin"
|
||||
[showNoDataButton]="permissionsService.canEditEntities()"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
noDataIcon="red:dictionary"
|
||||
></iqser-table>
|
||||
@ -39,8 +40,8 @@
|
||||
|
||||
<ng-template #bulkActions>
|
||||
<iqser-circle-button
|
||||
(action)="openDeleteDictionariesDialog($event)"
|
||||
*ngIf="currentUser.isAdmin && (listingService.areSomeSelected$ | async)"
|
||||
(action)="openDeleteEntitiesDialog($event)"
|
||||
*ngIf="permissionsService.canEditEntities() && (listingService.areSomeSelected$ | async)"
|
||||
[tooltip]="'entities-listing.bulk.delete' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:trash"
|
||||
@ -55,8 +56,8 @@
|
||||
></iqser-input-with-action>
|
||||
<div class="actions">
|
||||
<iqser-icon-button
|
||||
(action)="openAddEditDictionaryDialog()"
|
||||
*ngIf="currentUser.isAdmin"
|
||||
(action)="openAddEntityDialog()"
|
||||
*ngIf="permissionsService.canEditEntities()"
|
||||
[label]="'entities-listing.add-new' | translate"
|
||||
[type]="iconButtonTypes.primary"
|
||||
icon="iqser:plus"
|
||||
@ -90,9 +91,9 @@
|
||||
{{ templateStats.dictionarySummary(dict.type)?.entriesCount || 0 }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="currentUser.isAdmin" class="action-buttons">
|
||||
<div *ngIf="permissionsService.canEditEntities()" class="action-buttons">
|
||||
<iqser-circle-button
|
||||
(action)="openDeleteDictionariesDialog($event, [dict])"
|
||||
(action)="openDeleteEntitiesDialog($event, [dict])"
|
||||
[tooltip]="'entities-listing.action.delete' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:trash"
|
||||
|
||||
@ -9,7 +9,6 @@ import {
|
||||
} from '@iqser/common-ui';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { Dictionary, DossierTemplateStats } from '@red/domain';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
@ -18,6 +17,7 @@ import { ActivatedRoute } from '@angular/router';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { DOSSIER_TEMPLATE_ID } from '@utils/constants';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './entities-listing-screen.component.html',
|
||||
@ -27,7 +27,6 @@ import { DOSSIER_TEMPLATE_ID } from '@utils/constants';
|
||||
export class EntitiesListingScreenComponent extends ListingComponent<Dictionary> {
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
readonly tableHeaderLabel = _('entities-listing.table-header.title');
|
||||
readonly tableColumnConfigs: TableColumnConfig<Dictionary>[] = [
|
||||
{ label: _('entities-listing.table-col-names.type'), sortByKey: 'searchKey', width: '2fr' },
|
||||
@ -40,20 +39,20 @@ export class EntitiesListingScreenComponent extends ListingComponent<Dictionary>
|
||||
|
||||
constructor(
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _dictionariesMapService: DictionariesMapService,
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _dossierTemplateStatsService: DossierTemplateStatsService,
|
||||
private readonly _route: ActivatedRoute,
|
||||
readonly permissionsService: PermissionsService,
|
||||
) {
|
||||
super(_injector);
|
||||
this.#dossierTemplateId = _route.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID);
|
||||
this.templateStats$ = this._dossierTemplateStatsService.watch$(this.#dossierTemplateId).pipe(tap(() => this._loadDictionaryData()));
|
||||
}
|
||||
|
||||
openDeleteDictionariesDialog($event?: MouseEvent, types = this.listingService.selected) {
|
||||
openDeleteEntitiesDialog($event?: MouseEvent, types = this.listingService.selected) {
|
||||
this._dialogService.openDialog('confirm', $event, null, async () => {
|
||||
this._loadingService.start();
|
||||
await firstValueFrom(
|
||||
@ -66,11 +65,8 @@ export class EntitiesListingScreenComponent extends ListingComponent<Dictionary>
|
||||
});
|
||||
}
|
||||
|
||||
openAddEditDictionaryDialog($event?: MouseEvent, dictionary?: Dictionary) {
|
||||
this._dialogService.openDialog('addEditDictionary', $event, {
|
||||
dictionary,
|
||||
dossierTemplateId: this.#dossierTemplateId,
|
||||
});
|
||||
openAddEntityDialog($event?: MouseEvent) {
|
||||
this._dialogService.openDialog('addEntity', $event, { dossierTemplateId: this.#dossierTemplateId });
|
||||
}
|
||||
|
||||
private _loadDictionaryData(): void {
|
||||
|
||||
@ -2,6 +2,11 @@
|
||||
<div class="dialog">
|
||||
<div class="dialog-header">
|
||||
<div [translate]="'entity.info.heading'" class="heading-l"></div>
|
||||
|
||||
<div *ngIf="!permissionsService.canEditEntities()" class="read-only-indicator all-caps-label primary">
|
||||
<mat-icon class="mr-8" svgIcon="red:read-only"></mat-icon>
|
||||
{{ 'readonly' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-content">
|
||||
@ -41,6 +46,7 @@
|
||||
<div
|
||||
(colorPickerChange)="form.get('hexColor').setValue($event)"
|
||||
[colorPicker]="form.get('hexColor').value"
|
||||
[cpDisabled]="form.get('hexColor').disabled"
|
||||
[cpOutputFormat]="'hex'"
|
||||
[style.background]="form.get('hexColor').value"
|
||||
class="input-icon"
|
||||
@ -61,6 +67,7 @@
|
||||
<div
|
||||
(colorPickerChange)="form.get('recommendationHexColor').setValue($event)"
|
||||
[colorPicker]="form.get('recommendationHexColor').value"
|
||||
[cpDisabled]="form.get('recommendationHexColor').disabled"
|
||||
[cpOutputFormat]="'hex'"
|
||||
[style.background]="form.get('recommendationHexColor').value"
|
||||
class="input-icon"
|
||||
@ -72,7 +79,7 @@
|
||||
|
||||
<div class="iqser-input-group mb-14">
|
||||
<label translate="entity.info.form.technical-name"></label>
|
||||
<div class="technical-name">{{ entity.type }}</div>
|
||||
<div class="technical-name">{{ initialFormValue.type }}</div>
|
||||
<span class="hint" translate="entity.info.form.technical-name-hint"></span>
|
||||
</div>
|
||||
|
||||
@ -87,7 +94,7 @@
|
||||
</mat-button-toggle-group>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group w-400">
|
||||
<div *ngIf="form.get('defaultReason')" class="iqser-input-group w-400">
|
||||
<label translate="entity.info.form.default-reason"></label>
|
||||
<mat-select
|
||||
[placeholder]="'entity.info.form.default-reason-placeholder' | translate"
|
||||
@ -108,18 +115,18 @@
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<mat-slide-toggle color="primary" formControlName="hasDictionary">{{
|
||||
'entity.info.form.has-dictionary' | translate
|
||||
}}</mat-slide-toggle>
|
||||
<mat-slide-toggle color="primary" formControlName="hasDictionary">
|
||||
{{ 'entity.info.form.has-dictionary' | translate }}
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<div *ngIf="form.get('caseSensitive')" class="iqser-input-group">
|
||||
<mat-checkbox color="primary" formControlName="caseSensitive" name="caseSensitive">
|
||||
{{ 'entity.info.form.case-sensitive' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<div *ngIf="form.get('addToDictionaryAction')" class="iqser-input-group">
|
||||
<mat-checkbox color="primary" formControlName="addToDictionaryAction" name="addToDictionaryAction">
|
||||
{{ 'entity.info.form.add-to-dictionary-action' | translate }}
|
||||
</mat-checkbox>
|
||||
@ -127,7 +134,7 @@
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<div *ngIf="permissionsService.canEditEntities()" class="dialog-actions">
|
||||
<button (click)="save()" [disabled]="form.invalid || !changed" color="primary" mat-flat-button>
|
||||
{{ 'entity.info.actions.save' | translate }}
|
||||
</button>
|
||||
|
||||
@ -6,6 +6,12 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
padding-right: 32px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.content-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core';
|
||||
import { BaseFormComponent, LoadingService, Toaster } from '@iqser/common-ui';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
|
||||
import { Dictionary, IDictionary } from '@red/domain';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@utils/constants';
|
||||
@ -10,6 +10,9 @@ import { firstValueFrom, Observable } from 'rxjs';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
|
||||
const REDACTION_FIELDS = ['defaultReason', 'caseSensitive', 'addToDictionaryAction'];
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-info',
|
||||
@ -18,10 +21,10 @@ import { DictionaryService } from '@services/entity-services/dictionary.service'
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class InfoComponent extends BaseFormComponent {
|
||||
entity: Dictionary;
|
||||
readonly hasHexColor$: Observable<boolean>;
|
||||
readonly hasRecommendationHexColor$: Observable<boolean>;
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
entity: Dictionary;
|
||||
readonly #dossierTemplateId: string;
|
||||
|
||||
constructor(
|
||||
@ -33,13 +36,11 @@ export class InfoComponent extends BaseFormComponent {
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _changeRef: ChangeDetectorRef,
|
||||
readonly permissionsService: PermissionsService,
|
||||
) {
|
||||
super();
|
||||
this.#dossierTemplateId = this._route.parent.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID);
|
||||
const entityType = this._route.parent.snapshot.paramMap.get(ENTITY_TYPE);
|
||||
this.entity = this._dictionariesMapService.getDictionary(entityType, this.#dossierTemplateId);
|
||||
this.form = this._getForm();
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
this.form = this._initializeForm();
|
||||
this.hasHexColor$ = this._colorEmpty$('hexColor');
|
||||
this.hasRecommendationHexColor$ = this._colorEmpty$('recommendationHexColor');
|
||||
}
|
||||
@ -53,18 +54,21 @@ export class InfoComponent extends BaseFormComponent {
|
||||
this._toaster.success(_('entity.info.actions.save-success'));
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
this._changeRef.markForCheck();
|
||||
} catch (e) {}
|
||||
} catch (e) {
|
||||
this._toaster.error(_('entity.info.actions.save-failed'));
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
this._loadingService.stop();
|
||||
}
|
||||
|
||||
revert(): void {
|
||||
this.form = this._getForm();
|
||||
this.form = this._initializeForm();
|
||||
}
|
||||
|
||||
private _colorEmpty$(field: string) {
|
||||
return this.form.get(field).valueChanges.pipe(
|
||||
startWith(''),
|
||||
startWith(this.form.get(field).value),
|
||||
map((value: string) => !value || value?.length === 0),
|
||||
);
|
||||
}
|
||||
@ -73,30 +77,63 @@ export class InfoComponent extends BaseFormComponent {
|
||||
return {
|
||||
type: this.entity.type,
|
||||
label: this.form.get('label').value,
|
||||
caseInsensitive: !this.form.get('caseSensitive').value,
|
||||
caseInsensitive: !this.form.get('caseSensitive')?.value,
|
||||
description: this.form.get('description').value,
|
||||
hexColor: this.form.get('hexColor').value,
|
||||
recommendationHexColor: this.form.get('recommendationHexColor').value,
|
||||
hint: this.form.get('hint').value,
|
||||
rank: this.form.get('rank').value,
|
||||
addToDictionaryAction: this.form.get('addToDictionaryAction').value,
|
||||
addToDictionaryAction: this.form.get('addToDictionaryAction')?.value,
|
||||
dossierTemplateId: this.#dossierTemplateId,
|
||||
hasDictionary: this.form.get('hasDictionary').value,
|
||||
};
|
||||
}
|
||||
|
||||
private _getForm(): FormGroup {
|
||||
return this._formBuilder.group({
|
||||
label: [{ value: this.entity.label, disabled: !this.currentUser.isAdmin }, [Validators.required, Validators.minLength(3)]],
|
||||
private _initializeForm(): FormGroup {
|
||||
const entityType = this._route.parent.snapshot.paramMap.get(ENTITY_TYPE);
|
||||
this.entity = this._dictionariesMapService.getDictionary(entityType, this.#dossierTemplateId);
|
||||
|
||||
const controlsConfig = {
|
||||
label: [
|
||||
{
|
||||
value: this.entity.label,
|
||||
disabled: !this.currentUser.isAdmin,
|
||||
},
|
||||
[Validators.required, Validators.minLength(3)],
|
||||
],
|
||||
description: [this.entity.description],
|
||||
rank: [this.entity.rank, Validators.required],
|
||||
hexColor: [this.entity.hexColor, [Validators.required, Validators.minLength(7)]],
|
||||
recommendationHexColor: [this.entity.recommendationHexColor, [Validators.required, Validators.minLength(7)]],
|
||||
hint: [this.entity.hint],
|
||||
addToDictionaryAction: [this.entity.addToDictionaryAction],
|
||||
caseSensitive: [!this.entity.caseInsensitive],
|
||||
defaultReason: [{ value: null, disabled: true }],
|
||||
hasDictionary: [this.entity.hasDictionary],
|
||||
};
|
||||
|
||||
if (!this.entity.hint) {
|
||||
Object.assign(controlsConfig, {
|
||||
defaultReason: [{ value: null, disabled: true }],
|
||||
caseSensitive: [!this.entity.caseInsensitive],
|
||||
addToDictionaryAction: [this.entity.addToDictionaryAction],
|
||||
});
|
||||
}
|
||||
const form = this._formBuilder.group(controlsConfig);
|
||||
|
||||
this.initialFormValue = form.getRawValue();
|
||||
|
||||
form.get('hint').valueChanges.subscribe(isHint => {
|
||||
if (isHint) {
|
||||
REDACTION_FIELDS.forEach(field => this.form.removeControl(field));
|
||||
} else {
|
||||
form.addControl('addToDictionaryAction', new FormControl(this.entity.addToDictionaryAction));
|
||||
form.addControl('caseSensitive', new FormControl(!this.entity.caseInsensitive));
|
||||
form.addControl('defaultReason', new FormControl({ value: null, disabled: true }));
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.permissionsService.canEditEntities()) {
|
||||
form.disable();
|
||||
}
|
||||
|
||||
return form;
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,7 +56,7 @@
|
||||
<div class="iqser-input-group w-150">
|
||||
<label class="all-caps-label mb-5" translate="watermark-screen.form.color"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-dictionary.form.color-placeholder' | translate"
|
||||
[placeholder]="'add-entity.form.color-placeholder' | translate"
|
||||
class="hex-color-input"
|
||||
formControlName="hexColor"
|
||||
name="hexColor"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Injectable, TemplateRef } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
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 { AddEntityDialogComponent } from '../dialogs/add-entity-dialog/add-entity-dialog.component';
|
||||
import { AddEditDossierTemplateDialogComponent } from '../dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component';
|
||||
import { EditColorDialogComponent } from '../dialogs/edit-color-dialog/edit-color-dialog.component';
|
||||
import { SmtpAuthDialogComponent } from '../dialogs/smtp-auth-dialog/smtp-auth-dialog.component';
|
||||
@ -27,11 +27,11 @@ import { firstValueFrom, forkJoin } from 'rxjs';
|
||||
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { IDossierAttributeConfig, IFileAttributeConfig, IReportTemplate } from '@red/domain';
|
||||
import { ReportTemplateService } from '../../../services/report-template.service';
|
||||
import { ReportTemplateService } from '@services/report-template.service';
|
||||
|
||||
type DialogType =
|
||||
| 'confirm'
|
||||
| 'addEditDictionary'
|
||||
| 'addEntity'
|
||||
| 'editColor'
|
||||
| 'addEditFileAttribute'
|
||||
| 'importFileAttributes'
|
||||
@ -51,8 +51,8 @@ export class AdminDialogService extends DialogService<DialogType> {
|
||||
component: ConfirmationDialogComponent,
|
||||
dialogConfig: { disableClose: false },
|
||||
},
|
||||
addEditDictionary: {
|
||||
component: AddEditDictionaryDialogComponent,
|
||||
addEntity: {
|
||||
component: AddEntityDialogComponent,
|
||||
dialogConfig: { autoFocus: true },
|
||||
},
|
||||
editColor: {
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
<form *ngIf="form" [formGroup]="form">
|
||||
<div class="iqser-input-group">
|
||||
<mat-checkbox color="primary" formControlName="addToDictionaryAction" name="addToDictionaryAction">
|
||||
{{ 'add-edit-dictionary.form.add-to-dictionary-action' | translate }}
|
||||
{{ 'add-entity.form.add-to-dictionary-action' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
{{ activeNavItem.title | translate }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="activeNavItem.readonly" class="read-only all-caps-label primary">
|
||||
<div *ngIf="activeNavItem.readonly" class="read-only-indicator all-caps-label primary">
|
||||
<mat-icon class="mr-8" svgIcon="red:read-only"></mat-icon>
|
||||
{{ 'readonly' | translate }}
|
||||
</div>
|
||||
|
||||
@ -42,14 +42,8 @@ redaction-edit-dossier-dictionary {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.read-only {
|
||||
display: flex;
|
||||
.read-only-indicator {
|
||||
position: absolute;
|
||||
right: 32px;
|
||||
top: 108px;
|
||||
|
||||
mat-icon {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,12 +16,12 @@ import { RedactionLogEntry } from '../../../models/file/redaction-log.entry';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { FilePreviewStateService } from './file-preview-state.service';
|
||||
import { ViewedPagesService } from '@services/entity-services/viewed-pages.service';
|
||||
import { UserPreferenceService } from '../../../services/user-preference.service';
|
||||
import { UserPreferenceService } from '@services/user-preference.service';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { map, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { PermissionsService } from '../../../services/permissions.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { shareDistinctLast, shareLast, Toaster } from '../../../../../../../libs/common-ui/src';
|
||||
import { shareDistinctLast, shareLast, Toaster } from '@iqser/common-ui';
|
||||
import { RedactionLogService } from '../../dossier/services/redaction-log.service';
|
||||
import { TextHighlightService } from '../../dossier/services/text-highlight.service';
|
||||
import { ViewModeService } from './view-mode.service';
|
||||
|
||||
@ -10,7 +10,7 @@ import { DISABLED_HOTKEYS } from '../shared/constants';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { shareLast } from '../../../../../../../libs/common-ui/src';
|
||||
import { shareLast } from '@iqser/common-ui';
|
||||
import Annotation = Core.Annotations.Annotation;
|
||||
|
||||
@Injectable()
|
||||
|
||||
@ -274,11 +274,11 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
|
||||
#addUpdateDictionaryErrorToast(error: HttpErrorResponse): Observable<never> {
|
||||
if (error.status === HttpStatusCode.Conflict) {
|
||||
this._toaster.error(_('add-edit-dictionary.error.dictionary-already-exists'));
|
||||
this._toaster.error(_('add-entity.error.entity-already-exists'));
|
||||
} else if (error.status === HttpStatusCode.BadRequest) {
|
||||
this._toaster.error(_('add-edit-dictionary.error.invalid-color-or-rank'));
|
||||
this._toaster.error(_('add-entity.error.invalid-color-or-rank'));
|
||||
} else {
|
||||
this._toaster.error(_('add-edit-dictionary.error.generic'));
|
||||
this._toaster.error(_('add-entity.error.generic'));
|
||||
}
|
||||
return throwError(() => error);
|
||||
}
|
||||
|
||||
@ -13,6 +13,10 @@ export class PermissionsService {
|
||||
private readonly _featuresService: FeaturesService,
|
||||
) {}
|
||||
|
||||
canEditEntities(user = this._userService.currentUser): boolean {
|
||||
return user.isAdmin;
|
||||
}
|
||||
|
||||
canPerformDossierStatesActions(user = this._userService.currentUser): boolean {
|
||||
return user.isAdmin;
|
||||
}
|
||||
|
||||
@ -36,9 +36,9 @@
|
||||
},
|
||||
"header-new": "Dossier erstellen"
|
||||
},
|
||||
"add-edit-dictionary": {
|
||||
"add-entity": {
|
||||
"error": {
|
||||
"dictionary-already-exists": "Ein Wörterbuch mit diesem Namen existiert bereits!",
|
||||
"entity-already-exists": "Ein Wörterbuch mit diesem Namen existiert bereits!",
|
||||
"generic": "Wörterbuch konnte nicht gespeichert werden!",
|
||||
"invalid-color-or-rank": "Ungültige Farbe oder Rang! Der Rang wird bereits von einem anderen Wörterbuch verwendet oder die Farbe ist kein gültiger Hex-Farbcode!"
|
||||
},
|
||||
@ -63,7 +63,7 @@
|
||||
"create": "",
|
||||
"edit": ""
|
||||
},
|
||||
"title": "{type, select, edit{Wörterbuch {name} bearbeiten} create{Wörterbuch erstellen} other{}}"
|
||||
"title": "Wörterbuch erstellen"
|
||||
},
|
||||
"add-edit-dossier-attribute": {
|
||||
"error": {
|
||||
|
||||
@ -36,11 +36,11 @@
|
||||
},
|
||||
"header-new": "Create Dossier"
|
||||
},
|
||||
"add-edit-dictionary": {
|
||||
"add-entity": {
|
||||
"error": {
|
||||
"dictionary-already-exists": "Dictionary with this name already exists!",
|
||||
"generic": "Failed to save dictionary!",
|
||||
"invalid-color-or-rank": "Invalid color or rank! Rank is already used by another dictionary or the color is not a valid hexColor!"
|
||||
"entity-already-exists": "Entity with this name already exists!",
|
||||
"generic": "Failed to save entity!",
|
||||
"invalid-color-or-rank": "Invalid color or rank! Rank is already used by another entity or the color is not a valid hexColor!"
|
||||
},
|
||||
"form": {
|
||||
"add-to-dictionary-action": "Enable 'Add to dictionary'",
|
||||
@ -58,12 +58,12 @@
|
||||
"redaction": "Redaction",
|
||||
"technical-name": "Technical Name"
|
||||
},
|
||||
"save": "Save Dictionary",
|
||||
"save": "Save Entity",
|
||||
"success": {
|
||||
"create": "Dictionary added!",
|
||||
"edit": "Dictionary updated!"
|
||||
"create": "Entity added!",
|
||||
"edit": "Entity updated!"
|
||||
},
|
||||
"title": "{type, select, edit{Edit {name}} create{Create} other{}} Dictionary"
|
||||
"title": "Create Entity"
|
||||
},
|
||||
"add-edit-dossier-attribute": {
|
||||
"error": {
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 9463df1a16ab52fe12b882a401eb56b04ffff010
|
||||
Subproject commit 22434a2627d71f7cddc8bdd7d9adab9762c41e4c
|
||||
Loading…
x
Reference in New Issue
Block a user