Entities WIP

This commit is contained in:
Adina Țeudan 2022-03-22 19:17:03 +02:00
parent 9af978fcb0
commit e5686441cf
51 changed files with 783 additions and 570 deletions

View File

@ -1,21 +0,0 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
import { DICTIONARY_TYPE, DOSSIER_TEMPLATE_ID } from '@utils/constants';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
@Injectable({ providedIn: 'root' })
export class DictionaryExistsGuard implements CanActivate {
constructor(private readonly _dictionariesMapService: DictionariesMapService, private readonly _router: Router) {}
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
const dossierTemplateId: string = route.paramMap.get(DOSSIER_TEMPLATE_ID);
const type: string = route.paramMap.get(DICTIONARY_TYPE);
if (!this._dictionariesMapService.get(dossierTemplateId, type)) {
await this._router.navigate(['main', 'admin', 'dossier-templates', dossierTemplateId, 'dictionaries']);
return false;
}
return true;
}
}

View File

@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { CanActivate } from '@angular/router';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { firstValueFrom } from 'rxjs';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
@Injectable({ providedIn: 'root' })
export class DossierTemplatesGuard implements CanActivate {

View File

@ -0,0 +1,27 @@
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@utils/constants';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
@Injectable({ providedIn: 'root' })
export class EntityExistsGuard implements CanActivate {
constructor(
private readonly _dictionariesMapService: DictionariesMapService,
private readonly _router: Router,
private readonly _dossierTemplatesService: DossierTemplatesService,
) {}
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
const dossierTemplateId: string = route.paramMap.get(DOSSIER_TEMPLATE_ID);
const type: string = route.paramMap.get(ENTITY_TYPE);
if (!this._dictionariesMapService.get(dossierTemplateId, type)) {
const dossierTemplate = this._dossierTemplatesService.find(dossierTemplateId);
await this._router.navigate([`${dossierTemplate.routerLink}/entities`]);
return false;
}
return true;
}
}

View File

@ -2,8 +2,7 @@ import { NgModule } from '@angular/core';
import { AuthGuard } from '../auth/auth.guard';
import { CompositeRouteGuard } from '@iqser/common-ui';
import { RedRoleGuard } from '../auth/red-role.guard';
import { DictionaryListingScreenComponent } from './screens/dictionary-listing/dictionary-listing-screen.component';
import { DictionaryOverviewScreenComponent } from './screens/dictionary-overview/dictionary-overview-screen.component';
import { EntitiesListingScreenComponent } from './screens/entities-listing/entities-listing-screen.component';
import { PendingChangesGuard } from '@guards/can-deactivate.guard';
import { FileAttributesListingScreenComponent } from './screens/file-attributes-listing/file-attributes-listing-screen.component';
import { DefaultColorsScreenComponent } from './screens/default-colors/default-colors-screen.component';
@ -18,12 +17,13 @@ import { GeneralConfigScreenComponent } from './screens/general-config/general-c
import { BaseAdminScreenComponent } from './base-admin-screen/base-admin-screen.component';
import { BaseDossierTemplateScreenComponent } from './base-dossier-templates-screen/base-dossier-template-screen.component';
import { DossierTemplatesGuard } from '@guards/dossier-templates.guard';
import { DICTIONARY_TYPE, DOSSIER_TEMPLATE_ID } from '@utils/constants';
import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@utils/constants';
import { DossierTemplateExistsGuard } from '@guards/dossier-template-exists.guard';
import { DictionaryExistsGuard } from '@guards/dictionary-exists.guard';
import { EntityExistsGuard } from '@guards/entity-exists-guard.service';
import { DossierStatesListingScreenComponent } from './screens/dossier-states-listing/dossier-states-listing-screen.component';
import { DossiersGuard } from '@guards/dossiers.guard';
import { ACTIVE_DOSSIERS_SERVICE } from '../../tokens';
import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-screen.component';
const routes: Routes = [
{ path: '', redirectTo: 'dossier-templates', pathMatch: 'full' },
@ -52,23 +52,23 @@ const routes: Routes = [
loadChildren: () => import('./screens/info/dossier-template-info.module').then(m => m.DossierTemplateInfoModule),
},
{
path: 'dictionaries',
path: 'entities',
children: [
{
path: '',
component: DictionaryListingScreenComponent,
component: EntitiesListingScreenComponent,
canActivate: [CompositeRouteGuard],
data: {
routeGuards: [AuthGuard, RedRoleGuard],
},
},
{
path: `:${DICTIONARY_TYPE}`,
component: DictionaryOverviewScreenComponent,
path: `:${ENTITY_TYPE}`,
component: BaseEntityScreenComponent,
canActivate: [CompositeRouteGuard],
canDeactivate: [PendingChangesGuard],
loadChildren: () => import('./screens/entities/entities.module').then(m => m.EntitiesModule),
data: {
routeGuards: [AuthGuard, RedRoleGuard, DictionaryExistsGuard],
routeGuards: [AuthGuard, RedRoleGuard, EntityExistsGuard],
},
},
],

View File

@ -1,7 +1,7 @@
:host {
height: calc(100vh - 61px);
&.dossier-templates {
&.smaller {
height: calc(100vh - 111px);
}
}

View File

@ -4,9 +4,8 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { adminSideNavTranslations } from '../translations/admin-side-nav-translations';
import { UserService } from '@services/user.service';
import { ActivatedRoute } from '@angular/router';
import { DICTIONARY_TYPE } from '@utils/constants';
type Type = 'settings' | 'dossierTemplates';
import { ENTITY_TYPE } from '@utils/constants';
import { AdminSideNavType, AdminSideNavTypes } from '@red/domain';
interface NavItem {
readonly label: string;
@ -15,56 +14,65 @@ interface NavItem {
}
@Component({
selector: 'redaction-admin-side-nav',
selector: 'redaction-admin-side-nav [type]',
templateUrl: './admin-side-nav.component.html',
styleUrls: ['./admin-side-nav.component.scss'],
})
export class AdminSideNavComponent implements OnInit {
@Input() type: Type;
@Input() type: AdminSideNavType;
readonly translations = adminSideNavTranslations;
readonly currentUser = this._userService.currentUser;
prefix: string;
readonly items: { readonly [key in Type]: NavItem[] } = {
readonly items: { readonly [key in AdminSideNavType]: NavItem[] } = {
settings: [
{
screen: 'dossier-templates',
label: _('dossier-templates.label'),
label: _('admin-side-nav.dossier-templates'),
hideIf: !this.currentUser.isManager && !this.currentUser.isAdmin,
},
{
screen: 'digital-signature',
label: _('digital-signature'),
label: _('admin-side-nav.digital-signature'),
hideIf: !this.currentUser.isAdmin,
},
{
screen: 'license-info',
label: _('license-information'),
label: _('admin-side-nav.license-information'),
hideIf: !this.currentUser.isAdmin,
},
{ screen: 'audit', label: _('audit'), hideIf: !this.currentUser.isAdmin },
{ screen: 'users', label: _('user-management'), hideIf: !this.currentUser.isUserAdmin },
{ screen: 'audit', label: _('admin-side-nav.audit'), hideIf: !this.currentUser.isAdmin },
{ screen: 'users', label: _('admin-side-nav.user-management'), hideIf: !this.currentUser.isUserAdmin },
{
screen: 'general-config',
label: _('configurations'),
label: _('admin-side-nav.configurations'),
hideIf: !this.currentUser.isAdmin,
},
],
dossierTemplates: [
{ screen: 'info', label: _('dossier-template-info') },
{ screen: 'dictionaries', label: _('dictionaries') },
{ screen: 'info', label: _('admin-side-nav.dossier-template-info') },
{ screen: 'entities', label: _('admin-side-nav.entities') },
{
screen: 'rules',
label: _('rule-editor'),
label: _('admin-side-nav.rule-editor'),
hideIf: !this.userPreferenceService.areDevFeaturesEnabled,
},
{ screen: 'default-colors', label: _('default-colors') },
{ screen: 'watermark', label: _('watermark') },
{ screen: 'file-attributes', label: _('file-attributes') },
{ screen: 'dossier-attributes', label: _('dossier-attributes') },
{ screen: 'dossier-states', label: _('dossier-states') },
{ screen: 'reports', label: _('reports') },
{ screen: 'justifications', label: _('justifications') },
{ screen: 'default-colors', label: _('admin-side-nav.default-colors') },
{ screen: 'watermark', label: _('admin-side-nav.watermark') },
{ screen: 'file-attributes', label: _('admin-side-nav.file-attributes') },
{ screen: 'dossier-attributes', label: _('admin-side-nav.dossier-attributes') },
{ screen: 'dossier-states', label: _('admin-side-nav.dossier-states') },
{ screen: 'reports', label: _('admin-side-nav.reports') },
{ screen: 'justifications', label: _('admin-side-nav.justifications') },
],
entities: [
{
screen: 'info',
label: _('admin-side-nav.entity-info'),
},
{ screen: 'dictionary', label: _('admin-side-nav.dictionary') },
{ screen: 'false-positive', label: _('admin-side-nav.false-positive') },
{ screen: 'false-recommendations', label: _('admin-side-nav.false-recommendations') },
],
};
@ -74,11 +82,11 @@ export class AdminSideNavComponent implements OnInit {
readonly userPreferenceService: UserPreferenceService,
) {}
@HostBinding('class.dossier-templates') get isDossierTemplates(): boolean {
return this.type === 'dossierTemplates';
@HostBinding('class.smaller') get isSmaller(): boolean {
return [AdminSideNavTypes.dossierTemplates, AdminSideNavTypes.entities].includes(this.type);
}
ngOnInit(): void {
this.prefix = this._route.snapshot.paramMap.get(DICTIONARY_TYPE) ? '../../' : '../';
this.prefix = this._route.snapshot.paramMap.get(ENTITY_TYPE) ? '' : '../';
}
}

View File

@ -4,8 +4,7 @@ import { AdminRoutingModule } from './admin-routing.module';
import { SharedModule } from '@shared/shared.module';
import { AuditScreenComponent } from './screens/audit/audit-screen.component';
import { DefaultColorsScreenComponent } from './screens/default-colors/default-colors-screen.component';
import { DictionaryListingScreenComponent } from './screens/dictionary-listing/dictionary-listing-screen.component';
import { DictionaryOverviewScreenComponent } from './screens/dictionary-overview/dictionary-overview-screen.component';
import { EntitiesListingScreenComponent } from './screens/entities-listing/entities-listing-screen.component';
import { DigitalSignatureScreenComponent } from './screens/digital-signature/digital-signature-screen.component';
import { FileAttributesListingScreenComponent } from './screens/file-attributes-listing/file-attributes-listing-screen.component';
import { LicenseInformationScreenComponent } from './screens/license-information/license-information-screen.component';
@ -26,7 +25,6 @@ import { UsersStatsComponent } from './components/users-stats/users-stats.compon
import { FileAttributesCsvImportDialogComponent } from './dialogs/file-attributes-csv-import-dialog/file-attributes-csv-import-dialog.component';
import { ActiveFieldsListingComponent } from './dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component';
import { AdminSideNavComponent } from './admin-side-nav/admin-side-nav.component';
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
import { ResetPasswordComponent } from './dialogs/add-edit-user-dialog/reset-password/reset-password.component';
import { UserDetailsComponent } from './dialogs/add-edit-user-dialog/user-details/user-details.component';
import { AddEditDossierAttributeDialogComponent } from './dialogs/add-edit-dossier-attribute-dialog/add-edit-dossier-attribute-dialog.component';
@ -49,6 +47,7 @@ import { AddEditDossierStateDialogComponent } from './dialogs/add-edit-dossier-s
import { A11yModule } from '@angular/cdk/a11y';
import { ConfirmDeleteDossierStateDialogComponent } from './dialogs/confirm-delete-dossier-state-dialog/confirm-delete-dossier-state-dialog.component';
import { TrashTableItemComponent } from './screens/trash/trash-table-item/trash-table-item.component';
import { BaseEntityScreenComponent } from './base-entity-screen/base-entity-screen.component';
const dialogs = [
AddEditDossierTemplateDialogComponent,
@ -66,8 +65,7 @@ const dialogs = [
const screens = [
AuditScreenComponent,
DefaultColorsScreenComponent,
DictionaryListingScreenComponent,
DictionaryOverviewScreenComponent,
EntitiesListingScreenComponent,
DigitalSignatureScreenComponent,
FileAttributesListingScreenComponent,
LicenseInformationScreenComponent,
@ -88,6 +86,7 @@ const components = [
UserDetailsComponent,
BaseAdminScreenComponent,
BaseDossierTemplateScreenComponent,
BaseEntityScreenComponent,
GeneralConfigFormComponent,
SmtpFormComponent,
@ -104,15 +103,6 @@ const components = [
TrashTableItemComponent,
],
providers: [AdminDialogService, AuditService, DigitalSignatureService, LicenseReportService, RulesService, SmtpConfigService],
imports: [
CommonModule,
SharedModule,
AdminRoutingModule,
SharedAdminModule,
NgxChartsModule,
ColorPickerModule,
MonacoEditorModule,
A11yModule,
],
imports: [CommonModule, SharedModule, AdminRoutingModule, SharedAdminModule, NgxChartsModule, ColorPickerModule, A11yModule],
})
export class AdminModule {}

View File

@ -0,0 +1,29 @@
<section>
<div class="page-header">
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
<div class="flex-1 actions">
<iqser-circle-button
(action)="openDeleteDictionariesDialog()"
*ngIf="currentUser.isAdmin"
[tooltip]="'entities-listing.action.delete' | translate"
icon="iqser:trash"
></iqser-circle-button>
<iqser-circle-button
[routerLink]="['../../entities']"
[tooltip]="'common.close' | translate"
icon="iqser:close"
tooltipPosition="below"
></iqser-circle-button>
</div>
</div>
<div class="content-inner">
<div class="overlay-shadow"></div>
<redaction-admin-side-nav type="entities"></redaction-admin-side-nav>
<router-outlet></router-outlet>
</div>
</section>

View File

@ -0,0 +1,42 @@
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 { 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';
@Component({
templateUrl: './base-entity-screen.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class BaseEntityScreenComponent {
readonly currentUser = this._userService.currentUser;
readonly #dossierTemplateId: string;
readonly #entityType: string;
constructor(
private readonly _route: ActivatedRoute,
private readonly _userService: UserService,
private readonly _loadingService: LoadingService,
private readonly _dialogService: AdminDialogService,
private readonly _dictionaryService: DictionaryService,
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);
}
openDeleteDictionariesDialog() {
this._dialogService.openDialog('confirm', null, null, async () => {
this._loadingService.start();
const dossierTemplate = this._dossierTemplatesService.find(this.#dossierTemplateId);
await firstValueFrom(this._dictionaryService.deleteDictionaries([this.#entityType], this.#dossierTemplateId));
await this._router.navigate([`${dossierTemplate.routerLink}/entities`]);
this._loadingService.stop();
});
}
}

View File

@ -5,7 +5,7 @@ import { map, switchMap } from 'rxjs/operators';
import { ActivatedRoute } from '@angular/router';
import { Dictionary, DossierTemplate } from '@red/domain';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
import { DOSSIER_TEMPLATE_ID } from '@utils/constants';
import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@utils/constants';
@Component({
selector: 'redaction-dossier-template-breadcrumbs',
@ -27,7 +27,7 @@ export class DossierTemplateBreadcrumbsComponent {
switchMap((dossierTemplateId: string) => this._dossierTemplatesService.getEntityChanged$(dossierTemplateId)),
);
this.activeDictionary$ = _route.paramMap.pipe(
map(params => [params.get(DOSSIER_TEMPLATE_ID), params.get('dictionary')]),
map(params => [params.get(DOSSIER_TEMPLATE_ID), params.get(ENTITY_TYPE)]),
switchMap(([dossierTemplateId, dictionary]: [string, string]) =>
dictionary ? this._dictionariesMapService.watch$(dossierTemplateId, dictionary) : of(undefined),
),

View File

@ -6,7 +6,7 @@ import { BaseDialogComponent, LoadingService, shareDistinctLast, Toaster } from
import { TranslateService } from '@ngx-translate/core';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { toSnakeCase } from '@utils/functions';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { Dictionary, IDictionary } from '@red/domain';
import { UserService } from '@services/user.service';
import { map } from 'rxjs/operators';

View File

@ -8,7 +8,7 @@ import { BaseDialogComponent, LoadingService, Toaster } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { DossierTemplate, DownloadFileType, IDossierTemplate } from '@red/domain';
import { HttpStatusCode } from '@angular/common/http';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { firstValueFrom } from 'rxjs';
import dayjs, { Dayjs } from 'dayjs';

View File

@ -6,7 +6,7 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { defaultColorsTranslations } from '../../translations/default-colors-translations';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { firstValueFrom } from 'rxjs';
interface IEditColorData {

View File

@ -12,7 +12,7 @@ import {
import { defaultColorsTranslations } from '../../translations/default-colors-translations';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { UserService } from '@services/user.service';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { firstValueFrom } from 'rxjs';
import { ActivatedRoute } from '@angular/router';

View File

@ -1,101 +0,0 @@
<section *ngIf="dictionary$ | async as dictionary">
<div class="page-header">
<redaction-dossier-template-breadcrumbs></redaction-dossier-template-breadcrumbs>
<div class="actions">
<iqser-circle-button
(action)="openDeleteDictionaryDialog(dictionary, $event)"
*ngIf="currentUser.isAdmin"
[tooltip]="'dictionary-overview.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:trash"
tooltipPosition="below"
></iqser-circle-button>
<iqser-circle-button
(action)="openEditDictionaryDialog(dictionary, $event)"
*ngIf="currentUser.isAdmin"
[tooltip]="'dictionary-overview.action.edit' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:edit"
tooltipPosition="below"
></iqser-circle-button>
<iqser-circle-button
(action)="download(dictionary)"
[tooltip]="'dictionary-overview.action.download' | translate"
icon="iqser:download"
tooltipPosition="below"
></iqser-circle-button>
<iqser-circle-button
(action)="fileInput.click()"
*ngIf="currentUser.isAdmin"
[tooltip]="'dictionary-overview.action.upload' | translate"
icon="iqser:upload"
tooltipPosition="below"
></iqser-circle-button>
<input #fileInput (change)="upload($event)" accept="text/plain" class="file-upload-input" hidden type="file" />
<iqser-circle-button
[routerLink]="['..']"
[tooltip]="'common.close' | translate"
class="ml-6"
icon="iqser:close"
tooltipPosition="below"
></iqser-circle-button>
</div>
</div>
<div class="flex content-inner">
<div class="overlay-shadow"></div>
<redaction-admin-side-nav type="dossierTemplates"></redaction-admin-side-nav>
<redaction-dictionary-manager
#dictionaryManager
(saveDictionary)="save(dictionary)"
[canEdit]="currentUser.isAdmin"
[filterByDossierTemplate]="true"
[initialEntries]="initialEntries"
[isLeavingPage]="isLeavingPage"
></redaction-dictionary-manager>
<div *ngIf="!!dictionary" class="right-container">
<div class="dictionary-header">
<div [style.backgroundColor]="dictionary.hexColor" class="color-box"></div>
<div class="heading-xl">
{{ dictionary.label }}
</div>
</div>
<div class="small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:entries"></mat-icon>
{{ dictionaryManager.initialEntries?.length }}
</div>
</div>
<div class="small-label stats-subtitle">
<div *ngIf="!dictionary.caseInsensitive">
<mat-icon svgIcon="red:case-sensitive"></mat-icon>
{{ 'dictionary-listing.case-sensitive' | translate }}
</div>
</div>
<div class="indicator">
<redaction-dictionary-annotation-icon
[dictionaryKey]="dictionary.hint ? 'hint' : 'redaction'"
[dossierTemplateId]="dictionary.dossierTemplateId"
></redaction-dictionary-annotation-icon>
<div class="large-label">
{{ (dictionary.hint ? 'hint' : 'redaction') | translate }}
</div>
</div>
<div *ngIf="!!dictionary.description" class="pb-32 mt-20">
<div class="heading" translate="dictionary-overview.dictionary-details.description"></div>
<div class="mt-8">{{ dictionary.description }}</div>
</div>
</div>
</div>
</section>

View File

@ -1,144 +0,0 @@
import { Component, ElementRef, ViewChild } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { TranslateService } from '@ngx-translate/core';
import { saveAs } from 'file-saver';
import { AdminDialogService } from '../../services/admin-dialog.service';
import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
import { DictionaryService } from '@shared/services/dictionary.service';
import { CircleButtonTypes, LoadingService } from '@iqser/common-ui';
import { UserService } from '@services/user.service';
import { Dictionary } from '@red/domain';
import { firstValueFrom, Observable, of } from 'rxjs';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
import { map, switchMap } from 'rxjs/operators';
import { DOSSIER_TEMPLATE_ID } from '@utils/constants';
@Component({
templateUrl: './dictionary-overview-screen.component.html',
styleUrls: ['./dictionary-overview-screen.component.scss'],
})
export class DictionaryOverviewScreenComponent {
readonly circleButtonTypes = CircleButtonTypes;
readonly currentUser = this._userService.currentUser;
initialEntries: string[] = [];
isLeavingPage = false;
readonly dictionary$: Observable<Dictionary>;
@ViewChild('dictionaryManager', { static: false })
private readonly _dictionaryManager: DictionaryManagerComponent;
@ViewChild('fileInput') private readonly _fileInput: ElementRef;
constructor(
private readonly _router: Router,
private readonly _userService: UserService,
private readonly _activatedRoute: ActivatedRoute,
private readonly _loadingService: LoadingService,
private readonly _dialogService: AdminDialogService,
protected readonly _translateService: TranslateService,
private readonly _dictionaryService: DictionaryService,
private readonly _dictionariesMapService: DictionariesMapService,
private readonly _route: ActivatedRoute,
) {
this.dictionary$ = _route.paramMap.pipe(
map(params => [params.get(DOSSIER_TEMPLATE_ID), params.get('dictionary')]),
switchMap(([dossierTemplateId, dictionary]: [string, string]) =>
dossierTemplateId ? this._dictionariesMapService.watch$(dossierTemplateId, dictionary) : of(undefined),
),
switchMap(dictionary => this._loadEntries(dictionary)),
);
}
get changed() {
return this._dictionaryManager.editor.hasChanges;
}
openEditDictionaryDialog(dictionary: Dictionary, $event: MouseEvent) {
this._dialogService.openDialog('addEditDictionary', $event, {
dictionary,
dossierTemplateId: dictionary.dossierTemplateId,
});
}
openDeleteDictionaryDialog(dictionary: Dictionary, $event?: MouseEvent) {
$event?.stopPropagation();
this._dialogService.openDialog('confirm', $event, null, async () => {
await firstValueFrom(this._dictionaryService.deleteDictionaries([dictionary.type], dictionary.dossierTemplateId));
await this._router.navigate(['/main', 'admin', 'dossier-templates', dictionary.dossierTemplateId, 'dictionaries']);
});
}
download(dictionary: Dictionary): void {
const content = this._dictionaryManager.editor.value;
const blob = new Blob([content], {
type: 'text/plain;charset=utf-8',
});
saveAs(blob, `${dictionary.label}.txt`);
}
upload($event): void {
const file: File = $event.target.files[0];
const fileReader = new FileReader();
if (file) {
fileReader.onload = () => {
const fileContent = fileReader.result as string;
if (this._dictionaryManager.editor.value) {
this._dialogService.openDialog('uploadDictionary', null, null, ({ option }) => {
if (option === 'overwrite') {
this._overwrite(fileContent);
} else if (option === 'merge') {
this._merge(fileContent);
}
});
} else {
this._overwrite(fileContent);
}
this._fileInput.nativeElement.value = null;
};
fileReader.readAsText(file);
}
}
async save(dictionary: Dictionary) {
const entries = this._dictionaryManager.editor?.currentEntries;
this._loadingService.start();
try {
await firstValueFrom(
this._dictionaryService.saveEntries(entries, this.initialEntries, dictionary.dossierTemplateId, dictionary.type, null),
);
await this._loadEntries(dictionary);
} catch (e) {
this._loadingService.stop();
}
}
private _overwrite(fileContent: string): void {
this._dictionaryManager.editor.value = fileContent;
}
private _merge(fileContent: string): void {
const currentEntries = this._dictionaryManager.editor.value.split('\n');
fileContent
.split('\n')
.filter(entry => !currentEntries.includes(entry))
.forEach(entry => currentEntries.push(entry));
this._dictionaryManager.editor.value = currentEntries.join('\n');
}
private async _loadEntries(dictionary: Dictionary) {
this._loadingService.start();
try {
const data = await firstValueFrom(this._dictionaryService.getForType(dictionary.dossierTemplateId, dictionary.type));
this._loadingService.stop();
this.initialEntries = [...data.entries].sort((str1, str2) => str1.localeCompare(str2, undefined, { sensitivity: 'accent' }));
} catch (e) {
this._loadingService.stop();
this.initialEntries = [];
}
return dictionary;
}
}

View File

@ -5,7 +5,7 @@
<div class="small-label stats-subtitle">
<div *ngIf="stats$ | async as stats">
<mat-icon svgIcon="red:dictionary"></mat-icon>
{{ 'dossier-templates-listing.dictionaries' | translate: { length: stats.numberOfDictionaries } }}
{{ 'dossier-templates-listing.entities' | translate: { length: stats.numberOfDictionaries } }}
</div>
</div>
</div>

View File

@ -25,28 +25,15 @@
[bulkActions]="bulkActions"
[headerTemplate]="headerTemplate"
[itemSize]="80"
[noDataButtonLabel]="'dictionary-listing.no-data.action' | translate"
[noDataText]="'dictionary-listing.no-data.title' | translate"
[noMatchText]="'dictionary-listing.no-match.title' | translate"
[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"
[tableColumnConfigs]="tableColumnConfigs"
emptyColumnWidth="1fr"
noDataIcon="red:dictionary"
></iqser-table>
</div>
<div class="right-container" iqserHasScrollbar>
<redaction-simple-doughnut-chart
*ngIf="(entitiesService.noData$ | async) === false"
[config]="chartData"
[counterText]="'dictionary-listing.stats.charts.entries' | translate"
[radius]="82"
[strokeWidth]="15"
[subtitle]="'dictionary-listing.stats.charts.types' | translate"
totalType="count"
></redaction-simple-doughnut-chart>
</div>
</div>
</section>
@ -54,7 +41,7 @@
<iqser-circle-button
(action)="openDeleteDictionariesDialog($event)"
*ngIf="currentUser.isAdmin && (listingService.areSomeSelected$ | async)"
[tooltip]="'dictionary-listing.bulk.delete' | translate"
[tooltip]="'entities-listing.bulk.delete' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:trash"
></iqser-circle-button>
@ -64,13 +51,13 @@
<div class="table-header-actions">
<iqser-input-with-action
[(value)]="searchService.searchValue"
[placeholder]="'dictionary-listing.search' | translate"
[placeholder]="'entities-listing.search' | translate"
></iqser-input-with-action>
<div class="actions">
<iqser-icon-button
(action)="openAddEditDictionaryDialog()"
*ngIf="currentUser.isAdmin"
[label]="'dictionary-listing.add-new' | translate"
[label]="'entities-listing.add-new' | translate"
[type]="iconButtonTypes.primary"
icon="iqser:plus"
></iqser-icon-button>
@ -87,16 +74,6 @@
<div class="table-item-title heading">
{{ dict.label }}
</div>
<div class="small-label stats-subtitle">
<div>
<mat-icon svgIcon="red:entries"></mat-icon>
{{ templateStats.dictionarySummary(dict.type)?.entriesCount || 0 }}
</div>
<div *ngIf="!dict.caseInsensitive">
<mat-icon svgIcon="red:case-sensitive"></mat-icon>
{{ 'dictionary-listing.case-sensitive' | translate }}
</div>
</div>
</div>
</div>
@ -109,17 +86,21 @@
</div>
<div class="cell">
<div class="small-label">
{{ templateStats.dictionarySummary(dict.type)?.entriesCount || 0 }}
</div>
<div *ngIf="currentUser.isAdmin" class="action-buttons">
<iqser-circle-button
(action)="openDeleteDictionariesDialog($event, [dict])"
[tooltip]="'dictionary-listing.action.delete' | translate"
[tooltip]="'entities-listing.action.delete' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:trash"
></iqser-circle-button>
<iqser-circle-button
(action)="openAddEditDictionaryDialog($event, dict)"
[tooltip]="'dictionary-listing.action.edit' | translate"
[routerLink]="dict.routerLink"
[tooltip]="'entities-listing.action.edit' | translate"
[type]="circleButtonTypes.dark"
icon="iqser:edit"
></iqser-circle-button>

View File

@ -14,19 +14,6 @@
}
.dict-name {
z-index: 1;
max-width: 100%;
}
}
.right-container {
display: flex;
width: 353px;
min-width: 353px;
justify-content: center;
padding: 50px 20px 30px 20px;
&.has-scrollbar:hover {
padding-right: 9px;
}
}

View File

@ -1,6 +1,4 @@
import { Component, forwardRef, Injector } from '@angular/core';
import { DoughnutChartConfig } from '@shared/components/simple-doughnut-chart/simple-doughnut-chart.component';
import { TranslateService } from '@ngx-translate/core';
import {
CircleButtonTypes,
DefaultListingServices,
@ -12,8 +10,7 @@ import {
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 '@shared/services/dictionary.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { Dictionary, DossierTemplateStats } from '@red/domain';
import { firstValueFrom, Observable } from 'rxjs';
import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service';
@ -23,21 +20,21 @@ import { DictionariesMapService } from '@services/entity-services/dictionaries-m
import { DOSSIER_TEMPLATE_ID } from '@utils/constants';
@Component({
templateUrl: './dictionary-listing-screen.component.html',
styleUrls: ['./dictionary-listing-screen.component.scss'],
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DictionaryListingScreenComponent) }],
templateUrl: './entities-listing-screen.component.html',
styleUrls: ['./entities-listing-screen.component.scss'],
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => EntitiesListingScreenComponent) }],
})
export class DictionaryListingScreenComponent extends ListingComponent<Dictionary> {
export class EntitiesListingScreenComponent extends ListingComponent<Dictionary> {
readonly iconButtonTypes = IconButtonTypes;
readonly circleButtonTypes = CircleButtonTypes;
readonly currentUser = this._userService.currentUser;
readonly tableHeaderLabel = _('dictionary-listing.table-header.title');
readonly tableHeaderLabel = _('entities-listing.table-header.title');
readonly tableColumnConfigs: TableColumnConfig<Dictionary>[] = [
{ label: _('dictionary-listing.table-col-names.type'), sortByKey: 'searchKey', width: '2fr' },
{ label: _('dictionary-listing.table-col-names.rank'), sortByKey: 'rank', class: 'flex-center' },
{ label: _('dictionary-listing.table-col-names.hint-redaction'), class: 'flex-center' },
{ label: _('entities-listing.table-col-names.type'), sortByKey: 'searchKey', width: '2fr' },
{ label: _('entities-listing.table-col-names.rank'), sortByKey: 'rank', class: 'flex-center' },
{ label: _('entities-listing.table-col-names.hint-redaction'), class: 'flex-center' },
{ label: _('entities-listing.table-col-names.dictionary-entries') },
];
chartData: DoughnutChartConfig[] = [];
readonly templateStats$: Observable<DossierTemplateStats>;
readonly #dossierTemplateId: string;
@ -45,20 +42,15 @@ export class DictionaryListingScreenComponent extends ListingComponent<Dictionar
protected readonly _injector: Injector,
private readonly _userService: UserService,
private readonly _loadingService: LoadingService,
private readonly _dossierTemplatesService: DossierTemplatesService,
private readonly _dictionariesMapService: DictionariesMapService,
private readonly _dialogService: AdminDialogService,
private readonly _translateService: TranslateService,
private readonly _dictionaryService: DictionaryService,
private readonly _dossierTemplateStatsService: DossierTemplateStatsService,
private readonly _route: ActivatedRoute,
) {
super(_injector);
_loadingService.start();
this.#dossierTemplateId = _route.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID);
this.templateStats$ = this._dossierTemplateStatsService
.watch$(this.#dossierTemplateId)
.pipe(tap(templateStats => this._loadDictionaryData(templateStats)));
this.templateStats$ = this._dossierTemplateStatsService.watch$(this.#dossierTemplateId).pipe(tap(() => this._loadDictionaryData()));
}
openDeleteDictionariesDialog($event?: MouseEvent, types = this.listingService.selected) {
@ -81,21 +73,8 @@ export class DictionaryListingScreenComponent extends ListingComponent<Dictionar
});
}
private _loadDictionaryData(templateStats: DossierTemplateStats): void {
private _loadDictionaryData(): void {
const entities: Dictionary[] = this._dictionariesMapService.get(this.#dossierTemplateId).filter(d => !d.virtual);
this.entitiesService.setEntities(entities);
this._calculateData(templateStats);
}
private _calculateData(templateStats: DossierTemplateStats): void {
this.chartData = this.allEntities.map(dict => ({
value: templateStats.dictionarySummary(dict.type).entriesCount ?? 0,
color: dict.hexColor,
label: dict.label,
key: dict.type,
}));
this.chartData.sort((a, b) => (a.label < b.label ? -1 : 1));
this._loadingService.stop();
}
}

View File

@ -0,0 +1,28 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { SharedModule } from '@shared/shared.module';
import { DictionaryScreenComponent } from './screens/dictionary/dictionary-screen.component';
import { PendingChangesGuard } from '@guards/can-deactivate.guard';
import { InfoComponent } from './screens/info/info.component';
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
import { ColorPickerModule } from 'ngx-color-picker';
const routes = [
{ path: '', redirectTo: 'info', pathMatch: 'full' },
{
path: 'info',
component: InfoComponent,
},
{
path: 'dictionary',
component: DictionaryScreenComponent,
canDeactivate: [PendingChangesGuard],
},
];
@NgModule({
declarations: [DictionaryScreenComponent, InfoComponent],
imports: [RouterModule.forChild(routes), CommonModule, SharedModule, MonacoEditorModule, ColorPickerModule],
})
export class EntitiesModule {}

View File

@ -0,0 +1,8 @@
<redaction-dictionary-manager
#dictionaryManager
(saveDictionary)="save()"
[canEdit]="currentUser.isAdmin"
[filterByDossierTemplate]="true"
[initialEntries]="initialEntries$ | async"
[isLeavingPage]="isLeavingPage"
></redaction-dictionary-manager>

View File

@ -1,7 +1,6 @@
.right-container {
width: 353px;
min-width: 353px;
padding: 24px;
:host {
display: flex;
flex: 1;
}
.dictionary-header {

View File

@ -0,0 +1,69 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { LoadingService } from '@iqser/common-ui';
import { UserService } from '@services/user.service';
import { BehaviorSubject, firstValueFrom } from 'rxjs';
import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@utils/constants';
@Component({
templateUrl: './dictionary-screen.component.html',
styleUrls: ['./dictionary-screen.component.scss'],
})
export class DictionaryScreenComponent implements OnInit {
readonly currentUser = this._userService.currentUser;
initialEntries$ = new BehaviorSubject<string[]>([]);
isLeavingPage = false;
readonly #dossierTemplateId: string;
readonly #entityType: string;
@ViewChild('dictionaryManager', { static: false })
private readonly _dictionaryManager: DictionaryManagerComponent;
@ViewChild('fileInput') private readonly _fileInput: ElementRef;
constructor(
private readonly _userService: UserService,
private readonly _loadingService: LoadingService,
private readonly _dictionaryService: DictionaryService,
private readonly _route: ActivatedRoute,
) {
this.#dossierTemplateId = _route.parent.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID);
this.#entityType = _route.parent.snapshot.paramMap.get(ENTITY_TYPE);
}
get changed() {
return this._dictionaryManager.editor.hasChanges;
}
async ngOnInit(): Promise<void> {
await this._loadEntries();
}
async save() {
const entries = this._dictionaryManager.editor?.currentEntries;
this._loadingService.start();
try {
await firstValueFrom(
this._dictionaryService.saveEntries(entries, this.initialEntries$.value, this.#dossierTemplateId, this.#entityType, null),
);
await this._loadEntries();
} catch (e) {
this._loadingService.stop();
}
}
private async _loadEntries() {
this._loadingService.start();
try {
const data = await firstValueFrom(this._dictionaryService.getForType(this.#dossierTemplateId, this.#entityType));
this.initialEntries$.next(
[...data.entries].sort((str1, str2) => str1.localeCompare(str2, undefined, { sensitivity: 'accent' })),
);
this._loadingService.stop();
} catch (e) {
this._loadingService.stop();
this.initialEntries$.next([]);
}
}
}

View File

@ -0,0 +1,138 @@
<div class="content-container" iqserHasScrollbar>
<div class="dialog">
<div class="dialog-header">
<div [translate]="'entity.info.heading'" class="heading-l"></div>
</div>
<div class="dialog-content">
<form [formGroup]="form">
<div class="row">
<div class="iqser-input-group required">
<label translate="entity.info.form.name"></label>
<input
[placeholder]="'entity.info.form.name-placeholder' | translate"
formControlName="label"
name="label"
type="text"
/>
</div>
<div class="iqser-input-group required w-75">
<label translate="entity.info.form.rank"></label>
<input
[placeholder]="'entity.info.form.rank-placeholder' | translate"
formControlName="rank"
name="rank"
type="number"
/>
</div>
</div>
<div class="row mt-14">
<div class="iqser-input-group required">
<label translate="entity.info.form.color"></label>
<input
[placeholder]="'entity.info.form.color-placeholder' | translate"
class="hex-color-input"
formControlName="hexColor"
name="hexColor"
type="text"
/>
<div
(colorPickerChange)="form.get('hexColor').setValue($event)"
[colorPicker]="form.get('hexColor').value"
[cpOutputFormat]="'hex'"
[style.background]="form.get('hexColor').value"
class="input-icon"
>
<mat-icon *ngIf="hasHexColor$ | async" svgIcon="red:color-picker"></mat-icon>
</div>
</div>
<div class="iqser-input-group required">
<label translate="entity.info.form.recommendation-color"></label>
<input
[placeholder]="'entity.info.form.recommendation-color-placeholder' | translate"
class="hex-color-input"
formControlName="recommendationHexColor"
name="recommendationHexColor"
type="text"
/>
<div
(colorPickerChange)="form.get('recommendationHexColor').setValue($event)"
[colorPicker]="form.get('recommendationHexColor').value"
[cpOutputFormat]="'hex'"
[style.background]="form.get('recommendationHexColor').value"
class="input-icon"
>
<mat-icon *ngIf="hasRecommendationHexColor$ | async" svgIcon="red:color-picker"></mat-icon>
</div>
</div>
</div>
<div class="iqser-input-group mb-14">
<label translate="entity.info.form.technical-name"></label>
<div class="technical-name">{{ dictionary.type }}</div>
<span class="hint" translate="entity.info.form.technical-name-hint"></span>
</div>
<div class="iqser-input-group slider-row">
<mat-button-toggle-group appearance="legacy" formControlName="hint" name="hint">
<mat-button-toggle [value]="false">
{{ 'entity.info.form.redaction' | translate }}
</mat-button-toggle>
<mat-button-toggle [value]="true">
{{ 'entity.info.form.hint' | translate }}
</mat-button-toggle>
</mat-button-toggle-group>
</div>
<div class="iqser-input-group w-400">
<label translate="entity.info.form.default-reason"></label>
<mat-select
[placeholder]="'entity.info.form.default-reason-placeholder' | translate"
formControlName="defaultReason"
></mat-select>
</div>
<div class="iqser-input-group w-400">
<label translate="entity.info.form.description"></label>
<textarea
[placeholder]="'entity.info.form.description-placeholder' | translate"
formControlName="description"
iqserHasScrollbar
name="description"
rows="4"
type="text"
></textarea>
</div>
<div class="iqser-input-group">
<mat-slide-toggle color="primary" formControlName="hasDictionary">{{
'entity.info.form.has-dictionary' | translate
}}</mat-slide-toggle>
</div>
<div 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">
<mat-checkbox color="primary" formControlName="addToDictionaryAction" name="addToDictionaryAction">
{{ 'entity.info.form.add-to-dictionary-action' | translate }}
</mat-checkbox>
</div>
</form>
</div>
<div class="dialog-actions">
<button (click)="save()" [disabled]="form.invalid || !changed" color="primary" mat-flat-button>
{{ 'entity.info.actions.save' | translate }}
</button>
<div (click)="revert()" class="all-caps-label cancel" translate="entity.info.actions.revert"></div>
</div>
</div>
</div>

View File

@ -0,0 +1,34 @@
@use 'common-mixins';
:host {
display: flex;
flex-grow: 1;
overflow: hidden;
}
.content-container {
flex: 1;
display: flex;
padding: 30px;
overflow: auto;
@include common-mixins.scroll-bar;
background-color: var(--iqser-grey-2);
justify-content: center;
.dialog {
width: 100%;
min-height: unset;
}
}
.row {
display: flex;
> *:not(:last-child) {
margin-right: 16px;
}
.iqser-input-group {
margin-top: 0;
}
}

View File

@ -0,0 +1,101 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component } from '@angular/core';
import { BaseFormComponent, LoadingService, Toaster } from '@iqser/common-ui';
import { FormBuilder, 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';
import { ActivatedRoute } from '@angular/router';
import { map, startWith } from 'rxjs/operators';
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';
@Component({
selector: 'redaction-info',
templateUrl: './info.component.html',
styleUrls: ['./info.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class InfoComponent extends BaseFormComponent {
dictionary: Dictionary;
readonly hasHexColor$: Observable<boolean>;
readonly hasRecommendationHexColor$: Observable<boolean>;
readonly currentUser = this._userService.currentUser;
readonly #dossierTemplateId: string;
constructor(
private readonly _formBuilder: FormBuilder,
private readonly _dictionariesMapService: DictionariesMapService,
private readonly _route: ActivatedRoute,
private readonly _userService: UserService,
private readonly _toaster: Toaster,
private readonly _loadingService: LoadingService,
private readonly _dictionaryService: DictionaryService,
private readonly _changeRef: ChangeDetectorRef,
) {
super();
this.#dossierTemplateId = this._route.parent.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID);
const entityType = this._route.parent.snapshot.paramMap.get(ENTITY_TYPE);
this.dictionary = this._dictionariesMapService.getDictionary(entityType, this.#dossierTemplateId);
this.form = this._getForm();
this.initialFormValue = this.form.getRawValue();
this.hasHexColor$ = this._colorEmpty$('hexColor');
this.hasRecommendationHexColor$ = this._colorEmpty$('recommendationHexColor');
}
async save(): Promise<void> {
this._loadingService.start();
const dictionary = this._formToObject();
try {
await firstValueFrom(this._dictionaryService.updateDictionary(dictionary, this.#dossierTemplateId, dictionary.type));
this._toaster.success(_('entity.info.actions.save-success'));
this.initialFormValue = this.form.getRawValue();
this._changeRef.markForCheck();
} catch (e) {}
this._loadingService.stop();
}
revert(): void {
this.form = this._getForm();
}
private _colorEmpty$(field: string) {
return this.form.get(field).valueChanges.pipe(
startWith(''),
map((value: string) => !value || value?.length === 0),
);
}
private _formToObject(): IDictionary {
return {
type: this.dictionary.type,
label: this.form.get('label').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,
dossierTemplateId: this.#dossierTemplateId,
};
}
private _getForm(): FormGroup {
return this._formBuilder.group({
label: [{ value: this.dictionary.label, disabled: !this.currentUser.isAdmin }, [Validators.required, Validators.minLength(3)]],
description: [this.dictionary.description],
rank: [this.dictionary.rank, Validators.required],
hexColor: [this.dictionary.hexColor, [Validators.required, Validators.minLength(7)]],
recommendationHexColor: [this.dictionary.recommendationHexColor, [Validators.required, Validators.minLength(7)]],
hint: [this.dictionary.hint],
addToDictionaryAction: [this.dictionary.addToDictionaryAction],
caseSensitive: [!this.dictionary.caseInsensitive],
defaultReason: [{ value: null, disabled: true }],
hasDictionary: [false],
});
}
}

View File

@ -18,7 +18,7 @@
<div>
<mat-icon svgIcon="red:dictionary"></mat-icon>
{{ 'dossier-template-info-screen.dictionaries' | translate: { count: stats.numberOfDictionaries } }}
{{ 'dossier-template-info-screen.entities' | translate: { count: stats.numberOfDictionaries } }}
</div>
<div *ngIf="dossierTemplate.validTo && dossierTemplate.validFrom">

View File

@ -4,7 +4,7 @@ import { RouterModule } from '@angular/router';
import { SharedModule } from '@shared/shared.module';
import { RulesScreenComponent } from './rules-screen/rules-screen.component';
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
import { PendingChangesGuard } from '../../../../guards/can-deactivate.guard';
import { PendingChangesGuard } from '@guards/can-deactivate.guard';
const routes = [{ path: '', component: RulesScreenComponent, canDeactivate: [PendingChangesGuard] }];

View File

@ -5,7 +5,7 @@ import { CircleButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
import { UserService } from '@services/user.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { firstValueFrom } from 'rxjs';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { DOSSIER_TEMPLATE_ID } from '@utils/constants';
@Component({

View File

@ -1,6 +1,8 @@
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { AdminSideNavType } from '@red/domain';
export const adminSideNavTranslations = {
export const adminSideNavTranslations: { [key in AdminSideNavType]: string } = {
settings: _('admin-side-nav.settings'),
dossierTemplates: _('admin-side-nav.dossier-templates'),
entities: _('admin-side-nav.entities'),
} as const;

View File

@ -6,7 +6,7 @@ import { DOSSIER_ID, FILE_ID } from '@utils/constants';
import { CompositeRouteGuard } from '@iqser/common-ui';
import { ARCHIVED_DOSSIERS_SERVICE } from '../../tokens';
import { DossierFilesGuard } from '@guards/dossier-files-guard';
import { FilePreviewGuard } from '../../guards/file-preview.guard';
import { FilePreviewGuard } from '@guards/file-preview.guard';
const routes: Routes = [
{

View File

@ -3,7 +3,7 @@ import { Dossier, IDictionary } from '@red/domain';
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { PermissionsService } from '@services/permissions.service';
import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { CircleButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { FormBuilder, FormGroup } from '@angular/forms';

View File

@ -5,7 +5,7 @@ import { PermissionsService } from '@services/permissions.service';
import { Dictionary, Dossier } from '@red/domain';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
import { BaseDialogComponent } from '@iqser/common-ui';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { ManualAnnotationService } from '@services/manual-annotation.service';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';

View File

@ -7,7 +7,7 @@ import { PermissionsService } from '@services/permissions.service';
import { JustificationsService } from '@services/entity-services/justifications.service';
import { Dictionary, Dossier, IAddRedactionRequest } from '@red/domain';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { BaseDialogComponent, CircleButtonTypes } from '@iqser/common-ui';
import { firstValueFrom } from 'rxjs';

View File

@ -44,7 +44,7 @@ import { filePreviewScreenProviders } from './file-preview-providers';
import { ManualAnnotationService } from '@services/manual-annotation.service';
import { DossiersService } from '@services/dossiers/dossiers.service';
import { PageRotationService } from './services/page-rotation.service';
import { ComponentCanDeactivate } from '../../guards/can-deactivate.guard';
import { ComponentCanDeactivate } from '@guards/can-deactivate.guard';
import { PdfViewer } from './services/pdf-viewer.service';
import { FilePreviewDialogService } from './services/file-preview-dialog.service';
import { FileDataService } from './services/file-data.service';

View File

@ -24,7 +24,7 @@ import { AcceptRecommendationDialogComponent } from './dialogs/accept-recommenda
import { AnnotationCardComponent } from './components/annotation-card/annotation-card.component';
import { AnnotationReferencesPageIndicatorComponent } from './components/annotation-references-page-indicator/annotation-references-page-indicator.component';
import { HighlightsSeparatorComponent } from './components/highlights-separator/highlights-separator.component';
import { PendingChangesGuard } from '../../guards/can-deactivate.guard';
import { PendingChangesGuard } from '@guards/can-deactivate.guard';
import { ManualAnnotationDialogComponent } from './dialogs/manual-redaction-dialog/manual-annotation-dialog.component';
import { ForceAnnotationDialogComponent } from './dialogs/force-redaction-dialog/force-annotation-dialog.component';
import { RemoveAnnotationsDialogComponent } from './dialogs/remove-annotations-dialog/remove-annotations-dialog.component';

View File

@ -15,9 +15,9 @@ import { BehaviorSubject, firstValueFrom, iif, Observable, Subject } from 'rxjs'
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 { ViewedPagesService } from '@services/entity-services/viewed-pages.service';
import { UserPreferenceService } from '../../../services/user-preference.service';
import { DictionariesMapService } from '../../../services/entity-services/dictionaries-map.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 { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';

View File

@ -76,7 +76,7 @@
<div class="cell small-label stats-subtitle">
<div>
<mat-icon *ngIf="item.dossierStatus === 'ARCHIVED'" svgIcon="red:archive"></mat-icon>
<mat-icon *ngIf="item.isArchived" svgIcon="red:archive"></mat-icon>
{{ item.dossierName }}
</div>
</div>

View File

@ -4,7 +4,7 @@ import { firstValueFrom, Observable, of } from 'rxjs';
import { catchError, map, take, tap } from 'rxjs/operators';
import { Dictionary, Dossier, DossierTemplate } from '@red/domain';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { EditorComponent } from '@shared/components/editor/editor.component';

View File

@ -4,11 +4,11 @@ import { EntitiesService, List, QueryParam, RequiredParam, Toaster, Validate } f
import { Dictionary, IColors, IDictionary, IUpdateDictionary } from '@red/domain';
import { catchError, map, mapTo, switchMap, tap } from 'rxjs/operators';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service';
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
import { DossierTemplateStatsService } from './dossier-template-stats.service';
import { DictionariesMapService } from './dictionaries-map.service';
import { FALLBACK_COLOR } from '@utils/constants';
import { hexToRgb } from '@utils/functions';
import { FileAttributesService } from '@services/entity-services/file-attributes.service';
import { FileAttributesService } from './file-attributes.service';
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
import { SuperTypes } from '@models/file/super-types';

View File

@ -1,13 +1,13 @@
import { EntitiesService, List, mapEach, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
import { DossierTemplate, IDossierTemplate } from '@red/domain';
import { Injectable, Injector } from '@angular/core';
import { forkJoin, Observable, of, throwError } from 'rxjs';
import { forkJoin, Observable, of } from 'rxjs';
import { FileAttributesService } from './file-attributes.service';
import { catchError, mapTo, switchMap, tap } from 'rxjs/operators';
import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service';
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DictionaryService } from '@services/entity-services/dictionary.service';
const DOSSIER_TEMPLATE_CONFLICT_MSG = _('dossier-templates-listing.error.conflict');
const GENERIC_MSG = _('dossier-templates-listing.error.generic');

View File

@ -3,5 +3,5 @@ export const FALLBACK_COLOR = '#CCCCCC';
export const DOSSIER_ID = 'dossierId';
export const FILE_ID = 'fileId';
export const DOSSIER_TEMPLATE_ID = 'dossierTemplateId';
export const DICTIONARY_TYPE = 'dictionary';
export const ENTITY_TYPE = 'entity';
export const DOSSIERS_ARCHIVE = 'DOSSIERS_ARCHIVE';

View File

@ -159,8 +159,27 @@
"title": "{type, select, edit{Benutzer bearbeiten} create{Neuen Benutzer hinzufügen} other{}}"
},
"admin-side-nav": {
"audit": "",
"configurations": "",
"default-colors": "",
"dictionary": "",
"digital-signature": "",
"dossier-attributes": "",
"dossier-states": "",
"dossier-template-info": "",
"dossier-templates": "Dossier-Vorlage",
"settings": "Einstellungen"
"entities": "",
"entity-info": "",
"false-positive": "",
"false-recommendations": "",
"file-attributes": "",
"justifications": "",
"license-information": "",
"reports": "",
"rule-editor": "",
"settings": "Einstellungen",
"user-management": "",
"watermark": ""
},
"annotation-actions": {
"accept-recommendation": {
@ -321,6 +340,9 @@
"suggestion-resize": "Vorgeschlagene Größenänderung",
"text-highlight": ""
},
"annotation": {
"pending": ""
},
"archived-dossiers-listing": {
"no-data": {
"title": ""
@ -549,7 +571,6 @@
}
},
"content": "Begründung",
"default-colors": "Farbeinstellungen",
"default-colors-screen": {
"action": {
"edit": "Farbe bearbeiten"
@ -575,48 +596,8 @@
}
},
"dev-mode": "DEV",
"dictionaries": "Wörterbücher",
"dictionary": "Wörterbuch",
"dictionary-listing": {
"action": {
"delete": "Wörterbuch löschen",
"edit": "Wörterbuch bearbeiten"
},
"add-new": "Neues Wörterbuch",
"bulk": {
"delete": "Ausgewählte Wörterbücher löschen"
},
"case-sensitive": "Klein-/Großschreibung berücksichtigen",
"no-data": {
"action": "Neues Wörterbuch",
"title": "Es gibt noch keine Wörterbücher."
},
"no-match": {
"title": "Die ausgewählten Filter treffen auf kein Wörterbuch zu."
},
"search": "Suche ...",
"stats": {
"charts": {
"entries": "Einträge",
"types": "Typen"
}
},
"table-col-names": {
"hint-redaction": "Hinweis/Schwärzung",
"rank": "Rang",
"type": "Typ"
},
"table-header": {
"title": "{length} {length, plural, one{Wörterbuch} other{Wörterbücher}}"
}
},
"dictionary-overview": {
"action": {
"delete": "Wörterbuch löschen",
"download": "Wörterbuch herunterladen",
"edit": "Wörterbuch bearbeiten",
"upload": "Wörterbuch hochladen"
},
"compare": {
"compare": "Vergleichen",
"select-dictionary": "Wörterbuch auswählen",
@ -686,7 +667,6 @@
"number": "Nummer",
"text": "Text"
},
"dossier-attributes": "Dossier-Attribut",
"dossier-attributes-listing": {
"action": {
"delete": "Attribut löschen",
@ -880,7 +860,6 @@
"under-review": "In Review",
"upload-files": "Sie können Dateien überall per Drag and Drop platzieren..."
},
"dossier-states": "",
"dossier-states-listing": {
"action": {
"delete": "",
@ -910,12 +889,11 @@
"title": ""
}
},
"dossier-template-info": "",
"dossier-template-info-screen": {
"created-by": "",
"created-on": "",
"description": "",
"dictionaries": "",
"entities": "",
"entries": "",
"modified-on": "",
"valid-from": "",
@ -930,7 +908,7 @@
"bulk": {
"delete": "Ausgewählte Dossier-Vorlagen löschen"
},
"dictionaries": "{length} {length, plural, one{dictionary} other{dictionaries}}",
"entities": "{length} {length, plural, one{entity} other{entities}}",
"error": {
"conflict": "Dieses DossierTemplate kann nicht gelöscht werden! Zumindest auf Dossier wird diese Vorlage verwendet!",
"generic": "Dieses DossierTemplate kann nicht gelöscht werden!"
@ -1072,6 +1050,65 @@
},
"side-nav-title": "Konfiguration"
},
"entities-listing": {
"action": {
"delete": "Wörterbuch löschen",
"edit": "Wörterbuch bearbeiten"
},
"add-new": "Neues Wörterbuch",
"bulk": {
"delete": "Ausgewählte Wörterbücher löschen"
},
"case-sensitive": "Klein-/Großschreibung berücksichtigen",
"no-data": {
"action": "Neues Wörterbuch",
"title": "Es gibt noch keine Wörterbücher."
},
"no-match": {
"title": "Die ausgewählten Filter treffen auf kein Wörterbuch zu."
},
"search": "Suche ...",
"table-col-names": {
"dictionary-entries": "",
"hint-redaction": "Hinweis/Schwärzung",
"rank": "Rang",
"type": "Typ"
},
"table-header": {
"title": "{length} {length, plural, one{Wörterbuch} other{Wörterbücher}}"
}
},
"entity": {
"info": {
"actions": {
"revert": "",
"save": "",
"save-success": ""
},
"form": {
"add-to-dictionary-action": "",
"case-sensitive": "",
"color": "",
"color-placeholder": "",
"default-reason": "",
"default-reason-placeholder": "",
"description": "",
"description-placeholder": "",
"has-dictionary": "",
"hint": "",
"name": "",
"name-placeholder": "",
"rank": "",
"rank-placeholder": "",
"recommendation-color": "",
"recommendation-color-placeholder": "",
"redaction": "",
"technical-name": "",
"technical-name-hint": ""
},
"heading": ""
}
},
"error": {
"deleted-entity": {
"dossier": {
@ -1108,7 +1145,6 @@
"number": "Nummer",
"text": "Freier Text"
},
"file-attributes": "Datei-Attribute",
"file-attributes-configurations": {
"cancel": "",
"form": {
@ -1297,6 +1333,7 @@
"approved": "Genehmigt",
"deleted": "Gelöscht",
"error": "Reanalyse erforderlich",
"full-processing": "",
"full-reprocess": "Wird analysiert",
"image-analyzing": "Bildanalyse",
"indexing": "Wird analysiert",
@ -1428,7 +1465,6 @@
"unassigned": "Unbekannt",
"you": "Sie"
},
"justifications": "Begründungen",
"justifications-listing": {
"actions": {
"delete": "Begründung löschen",
@ -1511,20 +1547,6 @@
}
}
},
"months": {
"apr": "Apr.",
"aug": "August",
"dec": "Dez.",
"feb": "Feb.",
"jan": "Jan.",
"jul": "Jul.",
"jun": "März",
"mar": "März",
"may": "Nov.",
"nov": "Nov.",
"oct": "Okt.",
"sep": "Sept."
},
"notification": {
"assign-approver": "Sie wurden dem Dokument <b><a href=\"{fileHref}\" target=\"_blank\">{fileName}</a></b> im Dossier <b><a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a><b> als Genehmiger zugewiesen!",
"assign-reviewer": "Sie wurden dem Dokument <b><a href=\"{fileHref}\" target=\"_blank\">{fileName}</a></b> im Dossier <b><a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a><b> als Reviewer zugewiesen!",
@ -1623,6 +1645,10 @@
"processed": "",
"processing": ""
},
"processing": {
"basic": "",
"ocr": ""
},
"readonly": "Lesemodus",
"readonly-archived": "",
"recategorize-image-dialog": {
@ -1657,7 +1683,6 @@
"report-type": {
"label": "{length} {length, plural, one{Berichtstyp} other{Berichtstypen}}"
},
"reports": "Berichte",
"reports-screen": {
"description": "",
"descriptions": {
@ -1733,7 +1758,6 @@
"red-user-admin": "Benutzer-Admin",
"regular": "Regulär"
},
"rule-editor": "Regel-Editor",
"rules-screen": {
"error": {
"generic": "Es ist ein Fehler aufgetreten ... Die Regeln konnten nicht aktualisiert werden!"
@ -1915,7 +1939,6 @@
"view-as": "Ansicht als:",
"workflow": "Arbeitsablauf"
},
"watermark": "Wasserzeichen",
"watermark-screen": {
"action": {
"change-success": "Das Wasserzeichen wurde aktualisiert!",

View File

@ -159,11 +159,27 @@
"title": "{type, select, edit{Edit} create{Add New} other{}} User"
},
"admin-side-nav": {
"audit": "Audit",
"configurations": "Configurations",
"default-colors": "Default Colors",
"dictionary": "Dictionary",
"digital-signature": "Digital Signature",
"dossier-attributes": "Dossier Attributes",
"dossier-states": "Dossier States",
"dossier-template-info": "Info",
"dossier-templates": "Dossier Templates",
"settings": "Settings"
},
"annotation": {
"pending": "(Pending Analysis)"
"entities": "Entities",
"entity-info": "Info",
"false-positive": "False Positive",
"false-recommendations": "False Recommendations",
"file-attributes": "File Attributes",
"justifications": "Justifications",
"license-information": "License Information",
"reports": "Reports",
"rule-editor": "Rule Editor",
"settings": "Settings",
"user-management": "User Management",
"watermark": "Watermark"
},
"annotation-actions": {
"accept-recommendation": {
@ -324,6 +340,9 @@
"suggestion-resize": "Suggested Resize",
"text-highlight": "Highlight"
},
"annotation": {
"pending": "(Pending Analysis)"
},
"archived-dossiers-listing": {
"no-data": {
"title": "No archived dossiers."
@ -552,7 +571,6 @@
}
},
"content": "Reason",
"default-colors": "Default Colors",
"default-colors-screen": {
"action": {
"edit": "Edit Color"
@ -578,48 +596,8 @@
}
},
"dev-mode": "DEV",
"dictionaries": "Dictionaries",
"dictionary": "Dictionary",
"dictionary-listing": {
"action": {
"delete": "Delete Dictionary",
"edit": "Edit Dictionary"
},
"add-new": "New Dictionary",
"bulk": {
"delete": "Delete Selected Dictionaries"
},
"case-sensitive": "Case Sensitive",
"no-data": {
"action": "New Dictionary",
"title": "There are no dictionaries yet."
},
"no-match": {
"title": "No dictionaries match your current filters."
},
"search": "Search...",
"stats": {
"charts": {
"entries": "Entries",
"types": "Types"
}
},
"table-col-names": {
"hint-redaction": "Hint/Redaction",
"rank": "Rank",
"type": "Type"
},
"table-header": {
"title": "{length} {length, plural, one{dictionary} other{dictionaries}}"
}
},
"dictionary-overview": {
"action": {
"delete": "Delete Dictionary",
"download": "Download Dictionary",
"edit": "Edit Dictionary",
"upload": "Upload Dictionary"
},
"compare": {
"compare": "Compare",
"select-dictionary": "Select Dictionary",
@ -689,7 +667,6 @@
"number": "Number",
"text": "Free Text"
},
"dossier-attributes": "Dossier Attributes",
"dossier-attributes-listing": {
"action": {
"delete": "Delete Attribute",
@ -883,7 +860,6 @@
"under-review": "Under Review",
"upload-files": "Drag & drop files anywhere..."
},
"dossier-states": "Dossier States",
"dossier-states-listing": {
"action": {
"delete": "Delete State",
@ -913,12 +889,11 @@
"title": "{length} dossier {length, plural, one{state} other{states}}"
}
},
"dossier-template-info": "Info",
"dossier-template-info-screen": {
"created-by": "Created by",
"created-on": "Created on: {date}",
"description": "Description",
"dictionaries": "{count} {count, plural, one{dictionary} other{dictionaries}}",
"entities": "{count} {count, plural, one{entity} other{entities}}",
"entries": "{count} {count, plural, one{entry} other{entries}}",
"modified-on": "Modified on: {date}",
"valid-from": "Valid from: {date}",
@ -933,7 +908,7 @@
"bulk": {
"delete": "Delete Selected Dossier Templates"
},
"dictionaries": "{length} {length, plural, one{dictionary} other{dictionaries}}",
"entities": "{length} {length, plural, one{entity} other{entities}}",
"error": {
"conflict": "Cannot delete this DossierTemplate! At least one Dossier uses this template!",
"generic": "Cannot delete this DossierTemplate!"
@ -1075,6 +1050,65 @@
},
"side-nav-title": "Configurations"
},
"entities-listing": {
"action": {
"delete": "Delete Entity",
"edit": "Edit Entity"
},
"add-new": "New Entity",
"bulk": {
"delete": "Delete Selected Entities"
},
"case-sensitive": "Case Sensitive",
"no-data": {
"action": "New Entity",
"title": "There are no entities yet."
},
"no-match": {
"title": "No entities match your current filters."
},
"search": "Search...",
"table-col-names": {
"dictionary-entries": "Dictionary entries",
"hint-redaction": "Hint/Redaction",
"rank": "Rank",
"type": "Name"
},
"table-header": {
"title": "{length} {length, plural, one{entity} other{entities}}"
}
},
"entity": {
"info": {
"actions": {
"revert": "Revert",
"save": "Save Changes",
"save-success": "Entity updated!"
},
"form": {
"add-to-dictionary-action": "Available for add to dictionary",
"case-sensitive": "Case sensitive",
"color": "Hex Color",
"color-placeholder": "#",
"default-reason": "Default Reason",
"default-reason-placeholder": "No Default Reason",
"description": "Description",
"description-placeholder": "Enter Description",
"has-dictionary": "Has dictionary",
"hint": "Hint",
"name": "Display Name",
"name-placeholder": "Enter Name",
"rank": "Rank",
"rank-placeholder": "1000",
"recommendation-color": "Recommendation Hex Color",
"recommendation-color-placeholder": "#",
"redaction": "Redaction",
"technical-name": "Technical Name",
"technical-name-hint": "Autogenerated based on the initial display name."
},
"heading": "Edit Entity"
}
},
"error": {
"deleted-entity": {
"dossier": {
@ -1111,7 +1145,6 @@
"number": "Number",
"text": "Free Text"
},
"file-attributes": "File Attributes",
"file-attributes-configurations": {
"cancel": "Cancel",
"form": {
@ -1295,17 +1328,13 @@
"only-managers": "Enabling / disabling is permitted only for managers"
}
},
"processing": {
"ocr": "OCR",
"basic": "Processing"
},
"file-status": {
"analyse": "Analyzing",
"approved": "Approved",
"deleted": "Deleted",
"error": "Re-processing required",
"full-reprocess": "Processing",
"full-processing": "Processing",
"full-reprocess": "Processing",
"image-analyzing": "Image Analyzing",
"indexing": "Processing",
"initial-processing": "Initial processing...",
@ -1436,7 +1465,6 @@
"unassigned": "Unassigned",
"you": "You"
},
"justifications": "Justifications",
"justifications-listing": {
"actions": {
"delete": "Delete Justification",
@ -1519,20 +1547,6 @@
}
}
},
"months": {
"apr": "Apr.",
"aug": "Aug.",
"dec": "Dec.",
"feb": "Feb.",
"jan": "Jan.",
"jul": "Jul.",
"jun": "Jun.",
"mar": "Mar.",
"may": "May",
"nov": "Nov.",
"oct": "Oct.",
"sep": "Sep."
},
"notification": {
"assign-approver": "You have been assigned as approver for <b><a href=\"{fileHref}\" target=\"_blank\">{fileName}</a></b> in dossier: <b><a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a><b>!",
"assign-reviewer": "You have been assigned as reviewer for <b><a href=\"{fileHref}\" target=\"_blank\">{fileName}</a></b> in dossier: <b><a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a><b>!",
@ -1631,6 +1645,10 @@
"processed": "Processed",
"processing": "Processing"
},
"processing": {
"basic": "Processing",
"ocr": "OCR"
},
"readonly": "Read only",
"readonly-archived": "Read only (archived)",
"recategorize-image-dialog": {
@ -1665,7 +1683,6 @@
"report-type": {
"label": "{length} report {length, plural, one{type} other{types}}"
},
"reports": "Reports",
"reports-screen": {
"description": "Below, you will find a list of placeholders for dossier- and document-specific information. You can include these placeholders in your report templates.",
"descriptions": {
@ -1741,7 +1758,6 @@
"red-user-admin": "Users Admin",
"regular": "Regular"
},
"rule-editor": "Rule Editor",
"rules-screen": {
"error": {
"generic": "Something went wrong... Rules update failed!"
@ -1923,7 +1939,6 @@
"view-as": "View as:",
"workflow": "Workflow"
},
"watermark": "Watermark",
"watermark-screen": {
"action": {
"change-success": "Watermark updated!",

@ -1 +1 @@
Subproject commit 08737703e46fd0a8366bdf0c4241772d7ac8e2bb
Subproject commit 9463df1a16ab52fe12b882a401eb56b04ffff010

View File

@ -8,11 +8,13 @@ export class Dictionary extends Entity<IDictionary> implements IDictionary {
readonly dossierTemplateId?: string;
entries: List;
readonly hexColor?: string;
readonly recommendationHexColor?: string;
readonly hint: boolean;
readonly label: string;
readonly rank?: number;
readonly recommendation: boolean;
readonly type: string;
readonly typeId: string;
constructor(dictionary: IDictionary, readonly virtual = false) {
super(dictionary);
@ -22,11 +24,13 @@ export class Dictionary extends Entity<IDictionary> implements IDictionary {
this.dossierTemplateId = dictionary.dossierTemplateId;
this.entries = dictionary.entries ?? [];
this.hexColor = dictionary.hexColor;
this.recommendationHexColor = dictionary.recommendationHexColor;
this.hint = !!dictionary.hint;
this.label = dictionary.label ?? dictionary.type;
this.rank = dictionary.rank;
this.recommendation = !!dictionary.recommendation;
this.type = dictionary.type;
this.typeId = dictionary.typeId;
}
get id(): string {
@ -38,6 +42,6 @@ export class Dictionary extends Entity<IDictionary> implements IDictionary {
}
get routerLink(): string {
return `/main/admin/dossier-templates/${this.dossierTemplateId}/dictionaries/${this.type}`;
return `/main/admin/dossier-templates/${this.dossierTemplateId}/entities/${this.type}`;
}
}

View File

@ -24,6 +24,7 @@ export interface IDictionary {
* The nonnull entry type.
*/
readonly type: string;
readonly typeId?: string;
/**
* The list of dictionary entries of an entry type.
*/
@ -48,4 +49,6 @@ export interface IDictionary {
* True if the type just for recommendations, not for redaction, default is false.
*/
readonly recommendation?: boolean;
readonly recommendationHexColor?: string;
}

View File

@ -58,7 +58,11 @@ export class Dossier implements IDossier, IListable, IRouterPath {
}
get isActive(): boolean {
return this.softDeletedTime == null && this.archivedTime == null;
return !this.isSoftDeleted && !this.isArchived;
}
get isArchived(): boolean {
return this.archivedTime !== null;
}
get isSoftDeleted(): boolean {

View File

@ -0,0 +1,7 @@
export type AdminSideNavType = 'settings' | 'dossierTemplates' | 'entities';
export const AdminSideNavTypes = {
settings: 'settings' as AdminSideNavType,
dossierTemplates: 'dossierTemplates' as AdminSideNavType,
entities: 'entities' as AdminSideNavType,
};

View File

@ -9,3 +9,4 @@ export * from './view-mode';
export * from './expandable-file-actions';
export * from './pdf.types';
export * from './logger-config';
export * from './admin-side-nav-types';