Permissions

This commit is contained in:
Adina Țeudan 2022-03-24 01:02:07 +02:00
parent ed84299160
commit c93eabbdc2
25 changed files with 161 additions and 107 deletions

View File

@ -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"

View File

@ -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);
}
}

View File

@ -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,

View File

@ -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>

View File

@ -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() {

View File

@ -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>

View File

@ -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) {}

View File

@ -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"

View File

@ -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 {

View File

@ -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>

View File

@ -6,6 +6,12 @@
overflow: hidden;
}
.dialog-header {
padding-right: 32px;
display: flex;
justify-content: space-between;
}
.content-container {
flex: 1;
display: flex;

View File

@ -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;
}
}

View File

@ -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"

View File

@ -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: {

View File

@ -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>

View File

@ -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>

View File

@ -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;
}
}

View File

@ -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';

View File

@ -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()

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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": {

View File

@ -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