Dictionary technical name

This commit is contained in:
Adina Țeudan 2021-08-16 10:48:25 +03:00
parent 69620b0b7e
commit 2f45fe631e
10 changed files with 80 additions and 44 deletions

View File

@ -5,6 +5,11 @@
<form (submit)="saveDictionary()" [formGroup]="dictionaryForm"> <form (submit)="saveDictionary()" [formGroup]="dictionaryForm">
<div class="dialog-content"> <div class="dialog-content">
<div class="red-input-group mb-14">
<label translate="add-edit-dictionary.form.technical-name"></label>
<div class="technical-name">{{ dictionary?.type || technicalName || '-' }}</div>
</div>
<div *ngIf="!!dictionary" class="red-input-group mb-14"> <div *ngIf="!!dictionary" class="red-input-group mb-14">
<label translate="add-edit-dictionary.form.name"></label> <label translate="add-edit-dictionary.form.name"></label>
{{ dictionary.label }} {{ dictionary.label }}
@ -15,8 +20,8 @@
<label translate="add-edit-dictionary.form.name"></label> <label translate="add-edit-dictionary.form.name"></label>
<input <input
[placeholder]="'add-edit-dictionary.form.name-placeholder' | translate" [placeholder]="'add-edit-dictionary.form.name-placeholder' | translate"
formControlName="type" formControlName="label"
name="type" name="label"
type="text" type="text"
/> />
<span class="hint" translate="add-edit-dictionary.form.name-hint"></span> <span class="hint" translate="add-edit-dictionary.form.name-hint"></span>

View File

@ -15,3 +15,7 @@
.mb-14 { .mb-14 {
margin-bottom: 14px; margin-bottom: 14px;
} }
.technical-name {
font-weight: 600;
}

View File

@ -7,7 +7,8 @@ import { Toaster } from '@services/toaster.service';
import { TranslateService } from '@ngx-translate/core'; import { TranslateService } from '@ngx-translate/core';
import { TypeValueWrapper } from '@models/file/type-value.wrapper'; import { TypeValueWrapper } from '@models/file/type-value.wrapper';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { humanize } from '@iqser/common-ui'; import { AppStateService } from '@state/app-state.service';
import { toKebabCase } from '@utils/functions';
@Component({ @Component({
selector: 'redaction-add-edit-dictionary-dialog', selector: 'redaction-add-edit-dictionary-dialog',
@ -17,10 +18,12 @@ import { humanize } from '@iqser/common-ui';
export class AddEditDictionaryDialogComponent { export class AddEditDictionaryDialogComponent {
dictionaryForm: FormGroup; dictionaryForm: FormGroup;
readonly dictionary: TypeValueWrapper; readonly dictionary: TypeValueWrapper;
technicalName = '';
private readonly _dossierTemplateId: string; private readonly _dossierTemplateId: string;
constructor( constructor(
private readonly _dictionaryControllerService: DictionaryControllerService, private readonly _dictionaryControllerService: DictionaryControllerService,
private readonly _appStateService: AppStateService,
private readonly _formBuilder: FormBuilder, private readonly _formBuilder: FormBuilder,
private readonly _toaster: Toaster, private readonly _toaster: Toaster,
private readonly _translateService: TranslateService, private readonly _translateService: TranslateService,
@ -31,7 +34,7 @@ export class AddEditDictionaryDialogComponent {
this.dictionary = _data.dictionary; this.dictionary = _data.dictionary;
this._dossierTemplateId = _data.dossierTemplateId; this._dossierTemplateId = _data.dossierTemplateId;
this.dictionaryForm = _formBuilder.group({ this.dictionaryForm = _formBuilder.group({
type: [this.dictionary?.type, [Validators.required, Validators.minLength(3)]], label: [this.dictionary?.label, [Validators.required, Validators.minLength(3)]],
description: [this.dictionary?.description], description: [this.dictionary?.description],
rank: [this.dictionary?.rank, Validators.required], rank: [this.dictionary?.rank, Validators.required],
hexColor: [this.dictionary?.hexColor, [Validators.required, Validators.minLength(7)]], hexColor: [this.dictionary?.hexColor, [Validators.required, Validators.minLength(7)]],
@ -39,12 +42,15 @@ export class AddEditDictionaryDialogComponent {
addToDictionaryAction: [!!this.dictionary?.addToDictionaryAction], addToDictionaryAction: [!!this.dictionary?.addToDictionaryAction],
caseSensitive: [this.dictCaseSensitive] caseSensitive: [this.dictCaseSensitive]
}); });
this.dictionaryForm.get('label').valueChanges.subscribe(() => {
this._updateTechnicalName();
});
} }
get dialogHeader(): string { get dialogHeader(): string {
return this._translateService.instant('add-edit-dictionary.title', { return this._translateService.instant('add-edit-dictionary.title', {
type: this.dictionary ? 'edit' : 'create', type: this.dictionary ? 'edit' : 'create',
name: humanize(this.dictionary?.type) name: this.dictionary?.label
}); });
} }
@ -100,13 +106,26 @@ export class AddEditDictionaryDialogComponent {
); );
} }
private _updateTechnicalName() {
const displayName = this.dictionaryForm.get('label').value.trim();
const existingTechnicalNames = Object.keys(this._appStateService.dictionaryData[this._dossierTemplateId]);
const baseTechnicalName: string = toKebabCase(displayName);
let technicalName = baseTechnicalName;
let suffix = 1;
while (existingTechnicalNames.includes(technicalName)) {
technicalName = [baseTechnicalName, suffix++].join('-');
}
this.technicalName = technicalName;
}
private _formToObject(): TypeValue { private _formToObject(): TypeValue {
return { return {
type: this.dictionary?.type || this.technicalName,
label: this.dictionaryForm.get('label').value,
caseInsensitive: !this.dictionaryForm.get('caseSensitive').value, caseInsensitive: !this.dictionaryForm.get('caseSensitive').value,
description: this.dictionaryForm.get('description').value, description: this.dictionaryForm.get('description').value,
hexColor: this.dictionaryForm.get('hexColor').value, hexColor: this.dictionaryForm.get('hexColor').value,
hint: this.dictionaryForm.get('hint').value, hint: this.dictionaryForm.get('hint').value,
type: this.dictionaryForm.get('type').value,
rank: this.dictionaryForm.get('rank').value, rank: this.dictionaryForm.get('rank').value,
addToDictionaryAction: this.dictionaryForm.get('addToDictionaryAction').value, addToDictionaryAction: this.dictionaryForm.get('addToDictionaryAction').value,
dossierTemplateId: this._dossierTemplateId dossierTemplateId: this._dossierTemplateId

View File

@ -26,7 +26,6 @@ const toChartConfig = (dict: TypeValueWrapper): DoughnutChartConfig => ({
providers: [...DefaultListingServices] providers: [...DefaultListingServices]
}) })
export class DictionaryListingScreenComponent extends ListingComponent<TypeValueWrapper> implements OnInit { export class DictionaryListingScreenComponent extends ListingComponent<TypeValueWrapper> implements OnInit {
protected readonly _primaryKey = 'label';
readonly iconButtonTypes = IconButtonTypes; readonly iconButtonTypes = IconButtonTypes;
readonly circleButtonTypes = CircleButtonTypes; readonly circleButtonTypes = CircleButtonTypes;
readonly currentUser = this._userService.currentUser; readonly currentUser = this._userService.currentUser;
@ -46,8 +45,8 @@ export class DictionaryListingScreenComponent extends ListingComponent<TypeValue
class: 'flex-center' class: 'flex-center'
} }
]; ];
chartData: DoughnutChartConfig[] = []; chartData: DoughnutChartConfig[] = [];
protected readonly _primaryKey = 'type';
constructor( constructor(
protected readonly _injector: Injector, protected readonly _injector: Injector,

View File

@ -7,18 +7,18 @@
(action)="openDeleteDictionaryDialog($event)" (action)="openDeleteDictionaryDialog($event)"
*ngIf="currentUser.isAdmin" *ngIf="currentUser.isAdmin"
[tooltip]="'dictionary-overview.action.delete' | translate" [tooltip]="'dictionary-overview.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="red:trash" icon="red:trash"
tooltipPosition="below" tooltipPosition="below"
[type]="circleButtonTypes.dark"
></iqser-circle-button> ></iqser-circle-button>
<iqser-circle-button <iqser-circle-button
(action)="openEditDictionaryDialog($event)" (action)="openEditDictionaryDialog($event)"
*ngIf="currentUser.isAdmin" *ngIf="currentUser.isAdmin"
[tooltip]="'dictionary-overview.action.edit' | translate" [tooltip]="'dictionary-overview.action.edit' | translate"
[type]="circleButtonTypes.dark"
icon="red:edit" icon="red:edit"
tooltipPosition="below" tooltipPosition="below"
[type]="circleButtonTypes.dark"
></iqser-circle-button> ></iqser-circle-button>
<iqser-circle-button <iqser-circle-button
@ -60,11 +60,11 @@
[initialEntries]="entries" [initialEntries]="entries"
></redaction-dictionary-manager> ></redaction-dictionary-manager>
<div class="right-container"> <div *ngIf="!!dictionary" class="right-container">
<div class="dictionary-header"> <div class="dictionary-header">
<div [style.backgroundColor]="dictionary.hexColor" class="color-box"></div> <div [style.backgroundColor]="dictionary.hexColor" class="color-box"></div>
<div class="heading-xl"> <div class="heading-xl">
{{ dictionary.type | humanize }} {{ dictionary.label }}
</div> </div>
</div> </div>
<div class="small-label stats-subtitle"> <div class="small-label stats-subtitle">

View File

@ -40,18 +40,18 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple
private readonly _dictionaryControllerService: DictionaryControllerService private readonly _dictionaryControllerService: DictionaryControllerService
) { ) {
super(_translateService); super(_translateService);
this._appStateService.activateDictionary(
this._activatedRoute.snapshot.params.type,
this._activatedRoute.snapshot.params.dossierTemplateId
);
this.dictionary = this._appStateService.activeDictionary;
} }
get hasChanges() { get hasChanges() {
return this._dictionaryManager.hasChanges; return this._dictionaryManager.hasChanges;
} }
ngOnInit(): void { async ngOnInit() {
await this._appStateService.activateDictionary(
this._activatedRoute.snapshot.params.type,
this._activatedRoute.snapshot.params.dossierTemplateId
);
this.dictionary = this._appStateService.activeDictionary;
this._loadEntries(); this._loadEntries();
} }

View File

@ -22,7 +22,6 @@ import { TypeValueWrapper } from '@models/file/type-value.wrapper';
import { DossierTemplateModelWrapper } from '@models/file/dossier-template-model.wrapper'; import { DossierTemplateModelWrapper } from '@models/file/dossier-template-model.wrapper';
import { DossiersService } from '../modules/dossier/services/dossiers.service'; import { DossiersService } from '../modules/dossier/services/dossiers.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { humanize } from '@iqser/common-ui';
import { UserPreferenceService } from '@services/user-preference.service'; import { UserPreferenceService } from '@services/user-preference.service';
export interface AppState { export interface AppState {
@ -193,7 +192,7 @@ export class AppStateService {
return this.dossierTemplates.find(rs => rs.dossierTemplateId === id); return this.dossierTemplates.find(rs => rs.dossierTemplateId === id);
} }
getDictionaryTypeValue(key: string, dossierTemplateId?: string) { getDictionaryTypeValue(key: string, dossierTemplateId?: string): TypeValueWrapper {
if (!dossierTemplateId && this.activeDossier) { if (!dossierTemplateId && this.activeDossier) {
dossierTemplateId = this.activeDossier.dossierTemplateId; dossierTemplateId = this.activeDossier.dossierTemplateId;
} }
@ -401,12 +400,32 @@ export class AppStateService {
} }
} }
getDictionaryDataForDossierTemplateObservables(dossierTemplateId: string, dictionaryData: { [key: string]: any }): Observable<any>[] { async loadDictionaryData(): Promise<void> {
const obj = {};
const observables = [];
for (const dossierTemplate of this.dossierTemplates) {
obj[dossierTemplate.dossierTemplateId] = {};
observables.push(
...this._getDictionaryDataForDossierTemplateObservables(
dossierTemplate.dossierTemplateId,
obj[dossierTemplate.dossierTemplateId]
)
);
}
await forkJoin(observables).toPromise();
this._dictionaryData = obj;
}
private _getDictionaryDataForDossierTemplateObservables(
dossierTemplateId: string,
dictionaryData: { [key: string]: any }
): Observable<any>[] {
const typeObs = this._dictionaryControllerService.getAllTypes(dossierTemplateId).pipe( const typeObs = this._dictionaryControllerService.getAllTypes(dossierTemplateId).pipe(
tap(typesResponse => { tap(typesResponse => {
for (const type of typesResponse.types) { for (const type of typesResponse.types) {
dictionaryData[type.type] = type; dictionaryData[type.type] = type;
dictionaryData[type.type].label = humanize(type.type, false);
} }
}) })
); );
@ -634,24 +653,6 @@ export class AppStateService {
return [typeObs, colorsObs]; return [typeObs, colorsObs];
} }
async loadDictionaryData(): Promise<void> {
const obj = {};
const observables = [];
for (const dossierTemplate of this.dossierTemplates) {
obj[dossierTemplate.dossierTemplateId] = {};
observables.push(
...this.getDictionaryDataForDossierTemplateObservables(
dossierTemplate.dossierTemplateId,
obj[dossierTemplate.dossierTemplateId]
)
);
}
await forkJoin(observables).toPromise();
this._dictionaryData = obj;
}
private async _updateLastActiveFileForDossier(dossierId: string, fileId: string) { private async _updateLastActiveFileForDossier(dossierId: string, fileId: string) {
this.activeDossier.files.forEach(f => { this.activeDossier.files.forEach(f => {
f.lastOpened = f.fileId === fileId; f.lastOpened = f.fileId === fileId;

View File

@ -89,3 +89,10 @@ export function getLeftDateTime(ISOString: string) {
export function removeBraces(str: any): string { export function removeBraces(str: any): string {
return str.replace(/[{}]/g, ''); return str.replace(/[{}]/g, '');
} }
export function toKebabCase(str: string): string {
return str
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/[\s_]+/g, '-')
.toLowerCase();
}

View File

@ -42,12 +42,13 @@
"description": "Description", "description": "Description",
"description-placeholder": "Enter Description", "description-placeholder": "Enter Description",
"hint": "Hint", "hint": "Hint",
"name": "Dictionary Name", "name": "Display Name",
"name-hint": "Cannot be edited after saving.", "name-hint": "Cannot be edited after saving.",
"name-placeholder": "Enter Name", "name-placeholder": "Enter Name",
"rank": "Rank", "rank": "Rank",
"rank-placeholder": "1000", "rank-placeholder": "1000",
"redaction": "Redaction" "redaction": "Redaction",
"technical-name": "Technical Name"
}, },
"save": "Save Dictionary", "save": "Save Dictionary",
"title": "{type, select, edit{Edit {name}} create{Create} other{}} Dictionary" "title": "{type, select, edit{Edit {name}} create{Create} other{}} Dictionary"

View File

@ -23,8 +23,8 @@ form .red-input-group:not(first-of-type) {
right: 1px; right: 1px;
bottom: 1px; bottom: 1px;
background: $grey-5; background: $grey-5;
height: 32px; height: 34px;
width: 32px; width: 34px;
border-left: 1px solid $grey-5; border-left: 1px solid $grey-5;
border-top-right-radius: 7px; border-top-right-radius: 7px;
border-bottom-right-radius: 7px; border-bottom-right-radius: 7px;