diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.html b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.html index 91b00e51d..d8f2bb043 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.html +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.html @@ -5,6 +5,11 @@
+
+ +
{{ dictionary?.type || technicalName || '-' }}
+
+
{{ dictionary.label }} @@ -15,8 +20,8 @@ diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.scss b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.scss index ee380a74f..b1dd35aef 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.scss +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.scss @@ -15,3 +15,7 @@ .mb-14 { margin-bottom: 14px; } + +.technical-name { + font-weight: 600; +} diff --git a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.ts b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.ts index 88ce6e0e5..e0ad040e5 100644 --- a/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.ts +++ b/apps/red-ui/src/app/modules/admin/dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component.ts @@ -7,7 +7,8 @@ import { Toaster } from '@services/toaster.service'; import { TranslateService } from '@ngx-translate/core'; import { TypeValueWrapper } from '@models/file/type-value.wrapper'; 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({ selector: 'redaction-add-edit-dictionary-dialog', @@ -17,10 +18,12 @@ import { humanize } from '@iqser/common-ui'; export class AddEditDictionaryDialogComponent { dictionaryForm: FormGroup; readonly dictionary: TypeValueWrapper; + technicalName = ''; private readonly _dossierTemplateId: string; constructor( private readonly _dictionaryControllerService: DictionaryControllerService, + private readonly _appStateService: AppStateService, private readonly _formBuilder: FormBuilder, private readonly _toaster: Toaster, private readonly _translateService: TranslateService, @@ -31,7 +34,7 @@ export class AddEditDictionaryDialogComponent { this.dictionary = _data.dictionary; this._dossierTemplateId = _data.dossierTemplateId; 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], rank: [this.dictionary?.rank, Validators.required], hexColor: [this.dictionary?.hexColor, [Validators.required, Validators.minLength(7)]], @@ -39,12 +42,15 @@ export class AddEditDictionaryDialogComponent { addToDictionaryAction: [!!this.dictionary?.addToDictionaryAction], caseSensitive: [this.dictCaseSensitive] }); + this.dictionaryForm.get('label').valueChanges.subscribe(() => { + this._updateTechnicalName(); + }); } get dialogHeader(): string { return this._translateService.instant('add-edit-dictionary.title', { 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 { return { + type: this.dictionary?.type || this.technicalName, + label: this.dictionaryForm.get('label').value, caseInsensitive: !this.dictionaryForm.get('caseSensitive').value, description: this.dictionaryForm.get('description').value, hexColor: this.dictionaryForm.get('hexColor').value, hint: this.dictionaryForm.get('hint').value, - type: this.dictionaryForm.get('type').value, rank: this.dictionaryForm.get('rank').value, addToDictionaryAction: this.dictionaryForm.get('addToDictionaryAction').value, dossierTemplateId: this._dossierTemplateId diff --git a/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.ts index f9eee1500..1823bbc3d 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dictionary-listing/dictionary-listing-screen.component.ts @@ -26,7 +26,6 @@ const toChartConfig = (dict: TypeValueWrapper): DoughnutChartConfig => ({ providers: [...DefaultListingServices] }) export class DictionaryListingScreenComponent extends ListingComponent implements OnInit { - protected readonly _primaryKey = 'label'; readonly iconButtonTypes = IconButtonTypes; readonly circleButtonTypes = CircleButtonTypes; readonly currentUser = this._userService.currentUser; @@ -46,8 +45,8 @@ export class DictionaryListingScreenComponent extends ListingComponent -
+
- {{ dictionary.type | humanize }} + {{ dictionary.label }}
diff --git a/apps/red-ui/src/app/modules/admin/screens/dictionary-overview/dictionary-overview-screen.component.ts b/apps/red-ui/src/app/modules/admin/screens/dictionary-overview/dictionary-overview-screen.component.ts index 5b1a1c4e8..99a30e680 100644 --- a/apps/red-ui/src/app/modules/admin/screens/dictionary-overview/dictionary-overview-screen.component.ts +++ b/apps/red-ui/src/app/modules/admin/screens/dictionary-overview/dictionary-overview-screen.component.ts @@ -40,18 +40,18 @@ export class DictionaryOverviewScreenComponent extends ComponentHasChanges imple private readonly _dictionaryControllerService: DictionaryControllerService ) { super(_translateService); - this._appStateService.activateDictionary( - this._activatedRoute.snapshot.params.type, - this._activatedRoute.snapshot.params.dossierTemplateId - ); - this.dictionary = this._appStateService.activeDictionary; } get 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(); } diff --git a/apps/red-ui/src/app/state/app-state.service.ts b/apps/red-ui/src/app/state/app-state.service.ts index 266d0166f..5f0016685 100644 --- a/apps/red-ui/src/app/state/app-state.service.ts +++ b/apps/red-ui/src/app/state/app-state.service.ts @@ -22,7 +22,6 @@ import { TypeValueWrapper } from '@models/file/type-value.wrapper'; import { DossierTemplateModelWrapper } from '@models/file/dossier-template-model.wrapper'; import { DossiersService } from '../modules/dossier/services/dossiers.service'; import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker'; -import { humanize } from '@iqser/common-ui'; import { UserPreferenceService } from '@services/user-preference.service'; export interface AppState { @@ -193,7 +192,7 @@ export class AppStateService { return this.dossierTemplates.find(rs => rs.dossierTemplateId === id); } - getDictionaryTypeValue(key: string, dossierTemplateId?: string) { + getDictionaryTypeValue(key: string, dossierTemplateId?: string): TypeValueWrapper { if (!dossierTemplateId && this.activeDossier) { dossierTemplateId = this.activeDossier.dossierTemplateId; } @@ -401,12 +400,32 @@ export class AppStateService { } } - getDictionaryDataForDossierTemplateObservables(dossierTemplateId: string, dictionaryData: { [key: string]: any }): Observable[] { + async loadDictionaryData(): Promise { + 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[] { const typeObs = this._dictionaryControllerService.getAllTypes(dossierTemplateId).pipe( tap(typesResponse => { for (const type of typesResponse.types) { dictionaryData[type.type] = type; - dictionaryData[type.type].label = humanize(type.type, false); } }) ); @@ -634,24 +653,6 @@ export class AppStateService { return [typeObs, colorsObs]; } - async loadDictionaryData(): Promise { - 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) { this.activeDossier.files.forEach(f => { f.lastOpened = f.fileId === fileId; diff --git a/apps/red-ui/src/app/utils/functions.ts b/apps/red-ui/src/app/utils/functions.ts index c4a95a2c1..76285fc64 100644 --- a/apps/red-ui/src/app/utils/functions.ts +++ b/apps/red-ui/src/app/utils/functions.ts @@ -89,3 +89,10 @@ export function getLeftDateTime(ISOString: string) { export function removeBraces(str: any): string { return str.replace(/[{}]/g, ''); } + +export function toKebabCase(str: string): string { + return str + .replace(/([a-z])([A-Z])/g, '$1-$2') + .replace(/[\s_]+/g, '-') + .toLowerCase(); +} diff --git a/apps/red-ui/src/assets/i18n/en.json b/apps/red-ui/src/assets/i18n/en.json index 28dcb4f5a..eebe07d84 100644 --- a/apps/red-ui/src/assets/i18n/en.json +++ b/apps/red-ui/src/assets/i18n/en.json @@ -42,12 +42,13 @@ "description": "Description", "description-placeholder": "Enter Description", "hint": "Hint", - "name": "Dictionary Name", + "name": "Display Name", "name-hint": "Cannot be edited after saving.", "name-placeholder": "Enter Name", "rank": "Rank", "rank-placeholder": "1000", - "redaction": "Redaction" + "redaction": "Redaction", + "technical-name": "Technical Name" }, "save": "Save Dictionary", "title": "{type, select, edit{Edit {name}} create{Create} other{}} Dictionary" diff --git a/apps/red-ui/src/assets/styles/red-input.scss b/apps/red-ui/src/assets/styles/red-input.scss index f9607a98e..d619e8eca 100644 --- a/apps/red-ui/src/assets/styles/red-input.scss +++ b/apps/red-ui/src/assets/styles/red-input.scss @@ -23,8 +23,8 @@ form .red-input-group:not(first-of-type) { right: 1px; bottom: 1px; background: $grey-5; - height: 32px; - width: 32px; + height: 34px; + width: 34px; border-left: 1px solid $grey-5; border-top-right-radius: 7px; border-bottom-right-radius: 7px;