Merge branch 'entities'
This commit is contained in:
commit
9dffe3ceed
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
27
apps/red-ui/src/app/guards/entity-exists-guard.service.ts
Normal file
27
apps/red-ui/src/app/guards/entity-exists-guard.service.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import { AnnotationWrapper } from './annotation.wrapper';
|
||||
import { User } from '@red/domain';
|
||||
import { Dictionary, User } from '@red/domain';
|
||||
import { isArray } from 'lodash-es';
|
||||
|
||||
export class AnnotationPermissions {
|
||||
@ -16,7 +16,7 @@ export class AnnotationPermissions {
|
||||
canRecategorizeImage = true;
|
||||
canForceHint = true;
|
||||
|
||||
static forUser(isApprover: boolean, user: User, annotations: AnnotationWrapper | AnnotationWrapper[]) {
|
||||
static forUser(isApprover: boolean, user: User, annotations: AnnotationWrapper | AnnotationWrapper[], entities: Dictionary[]) {
|
||||
if (!isArray(annotations)) {
|
||||
annotations = [annotations];
|
||||
}
|
||||
@ -34,7 +34,8 @@ export class AnnotationPermissions {
|
||||
permissions.canForceRedaction = annotation.isSkipped && !annotation.isFalsePositive && !annotation.pending;
|
||||
permissions.canAcceptRecommendation = annotation.isRecommendation && !annotation.pending;
|
||||
|
||||
permissions.canMarkAsFalsePositive = annotation.canBeMarkedAsFalsePositive && !annotation.imported && !annotation.pending;
|
||||
const annotationEntity = entities.find(entity => entity.type === annotation.type);
|
||||
permissions.canMarkAsFalsePositive = annotation.canBeMarkedAsFalsePositive && annotationEntity.hasDictionary;
|
||||
|
||||
permissions.canRemoveOrSuggestToRemoveOnlyHere = (annotation.isRedacted || annotation.isHint) && !annotation.pending;
|
||||
permissions.canRemoveOrSuggestToRemoveFromDictionary =
|
||||
|
||||
@ -79,7 +79,7 @@ export class AnnotationWrapper implements Record<string, unknown> {
|
||||
}
|
||||
|
||||
get canBeMarkedAsFalsePositive() {
|
||||
return (this.isRecommendation || this.superType === SuperTypes.Redaction) && !this.isImage;
|
||||
return (this.isRecommendation || this.superType === SuperTypes.Redaction) && !this.isImage && !this.imported && !this.pending;
|
||||
}
|
||||
|
||||
get isSuperTypeBasedColor() {
|
||||
@ -294,7 +294,7 @@ export class AnnotationWrapper implements Record<string, unknown> {
|
||||
|
||||
private static _handleRecommendations(annotationWrapper: AnnotationWrapper, redactionLogEntry: RedactionLogEntry) {
|
||||
if (annotationWrapper.superType === SuperTypes.Recommendation) {
|
||||
annotationWrapper.recommendationType = redactionLogEntry.type.substr('recommendation_'.length);
|
||||
annotationWrapper.recommendationType = redactionLogEntry.type;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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],
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
<ng-container *ngFor="let item of items[type]">
|
||||
<a
|
||||
*ngIf="!item.hideIf"
|
||||
[class.disabled]="isDisabled(item.screen)"
|
||||
[routerLinkActiveOptions]="{ exact: false }"
|
||||
[routerLink]="prefix + item.screen"
|
||||
class="item"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
:host {
|
||||
height: calc(100vh - 61px);
|
||||
|
||||
&.dossier-templates {
|
||||
&.smaller {
|
||||
height: calc(100vh - 111px);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,66 @@ 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;
|
||||
@Input() disabledItems: string[] = [];
|
||||
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 +83,15 @@ 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) ? '' : '../';
|
||||
}
|
||||
|
||||
isDisabled(screen: string): boolean {
|
||||
return this.disabledItems.includes(screen);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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';
|
||||
@ -14,7 +13,7 @@ import { DossierTemplateBreadcrumbsComponent } from './components/dossier-templa
|
||||
import { ColorPickerModule } from 'ngx-color-picker';
|
||||
import { AddEditFileAttributeDialogComponent } from './dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component';
|
||||
import { AddEditDossierTemplateDialogComponent } from './dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component';
|
||||
import { AddEditDictionaryDialogComponent } from './dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component';
|
||||
import { AddEntityDialogComponent } from './dialogs/add-entity-dialog/add-entity-dialog.component';
|
||||
import { EditColorDialogComponent } from './dialogs/edit-color-dialog/edit-color-dialog.component';
|
||||
import { ComboChartComponent, ComboSeriesVerticalComponent } from './components/combo-chart';
|
||||
import { NgxChartsModule } from '@swimlane/ngx-charts';
|
||||
@ -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,10 +47,11 @@ 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,
|
||||
AddEditDictionaryDialogComponent,
|
||||
AddEntityDialogComponent,
|
||||
AddEditFileAttributeDialogComponent,
|
||||
EditColorDialogComponent,
|
||||
SmtpAuthDialogComponent,
|
||||
@ -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 {}
|
||||
|
||||
@ -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 [disabledItems]="disabledItems$ | async" type="entities"></redaction-admin-side-nav>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</section>
|
||||
@ -0,0 +1,49 @@
|
||||
import { ChangeDetectionStrategy, Component } from '@angular/core';
|
||||
import { DOSSIER_TEMPLATE_ID, ENTITY_TYPE } from '@utils/constants';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
import { AdminDialogService } from '../services/admin-dialog.service';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { LoadingService } from '@iqser/common-ui';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
templateUrl: './base-entity-screen.component.html',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class BaseEntityScreenComponent {
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
readonly disabledItems$: Observable<string[]>;
|
||||
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 _dictionaryMapService: DictionariesMapService,
|
||||
private readonly _dossierTemplatesService: DossierTemplatesService,
|
||||
private readonly _router: Router,
|
||||
) {
|
||||
this.#dossierTemplateId = this._route.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID);
|
||||
this.#entityType = this._route.snapshot.paramMap.get(ENTITY_TYPE);
|
||||
this.disabledItems$ = this._dictionaryMapService
|
||||
.watch$(this.#dossierTemplateId, this.#entityType)
|
||||
.pipe(map(entity => (entity.hasDictionary ? [] : ['dictionary', 'false-positive', 'false-recommendations'])));
|
||||
}
|
||||
|
||||
openDeleteDictionariesDialog() {
|
||||
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();
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -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),
|
||||
),
|
||||
|
||||
@ -1,105 +0,0 @@
|
||||
<section class="dialog">
|
||||
<div class="dialog-header heading-l">
|
||||
{{ dialogHeader }}
|
||||
</div>
|
||||
|
||||
<form [formGroup]="form">
|
||||
<div class="dialog-content">
|
||||
<div class="iqser-input-group mb-14">
|
||||
<label translate="add-edit-dictionary.form.technical-name"></label>
|
||||
<div class="technical-name">{{ dictionary?.type || (technicalName$ | async) || '-' }}</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="(canEditLabel$ | async) === false" class="iqser-input-group mb-14">
|
||||
<label translate="add-edit-dictionary.form.name"></label>
|
||||
{{ dictionary.label }}
|
||||
</div>
|
||||
|
||||
<div class="first-row">
|
||||
<div *ngIf="canEditLabel$ | async" class="iqser-input-group required">
|
||||
<label translate="add-edit-dictionary.form.name"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-dictionary.form.name-placeholder' | translate"
|
||||
formControlName="label"
|
||||
name="label"
|
||||
type="text"
|
||||
/>
|
||||
<span class="hint" translate="add-edit-dictionary.form.name-hint"></span>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group required w-75">
|
||||
<label translate="add-edit-dictionary.form.rank"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-dictionary.form.rank-placeholder' | translate"
|
||||
formControlName="rank"
|
||||
name="rank"
|
||||
type="number"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group required">
|
||||
<label translate="add-edit-dictionary.form.color"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-dictionary.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="hasColor$ | async" svgIcon="red:color-picker"></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group w-450">
|
||||
<label translate="add-edit-dictionary.form.description"></label>
|
||||
<textarea
|
||||
[placeholder]="'add-edit-dictionary.form.description-placeholder' | translate"
|
||||
formControlName="description"
|
||||
iqserHasScrollbar
|
||||
name="description"
|
||||
rows="4"
|
||||
type="text"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group slider-row">
|
||||
<mat-button-toggle-group appearance="legacy" formControlName="hint" name="hint">
|
||||
<mat-button-toggle [value]="false">
|
||||
{{ 'add-edit-dictionary.form.redaction' | translate }}
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle [value]="true">
|
||||
{{ 'add-edit-dictionary.form.hint' | translate }}
|
||||
</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<mat-checkbox color="primary" formControlName="caseSensitive" name="caseSensitive">
|
||||
{{ 'add-edit-dictionary.form.case-sensitive' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<mat-checkbox color="primary" formControlName="addToDictionaryAction" name="addToDictionaryAction">
|
||||
{{ 'add-edit-dictionary.form.add-to-dictionary-action' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button type="button">
|
||||
{{ 'add-edit-dictionary.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<iqser-circle-button (action)="close()" class="dialog-close" icon="iqser:close"></iqser-circle-button>
|
||||
</section>
|
||||
@ -1,124 +0,0 @@
|
||||
import { ChangeDetectionStrategy, Component, Inject, Injector } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
import { BaseDialogComponent, LoadingService, shareDistinctLast, Toaster } from '@iqser/common-ui';
|
||||
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 { Dictionary, IDictionary } from '@red/domain';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-add-edit-dictionary-dialog',
|
||||
templateUrl: './add-edit-dictionary-dialog.component.html',
|
||||
styleUrls: ['./add-edit-dictionary-dialog.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AddEditDictionaryDialogComponent extends BaseDialogComponent {
|
||||
readonly dictionary = this._data.dictionary;
|
||||
readonly canEditLabel$ = this._canEditLabel$;
|
||||
readonly technicalName$: Observable<string>;
|
||||
readonly dialogHeader = this._translateService.instant('add-edit-dictionary.title', {
|
||||
type: this._data.dictionary ? 'edit' : 'create',
|
||||
name: this._data.dictionary?.label,
|
||||
});
|
||||
readonly hasColor$: Observable<boolean>;
|
||||
private readonly _dossierTemplateId = this._data.dossierTemplateId;
|
||||
|
||||
constructor(
|
||||
readonly userService: UserService,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _dictionariesMapService: DictionariesMapService,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
protected readonly _injector: Injector,
|
||||
protected readonly _dialogRef: MatDialogRef<AddEditDictionaryDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
private readonly _data: { readonly dictionary: Dictionary; readonly dossierTemplateId: string },
|
||||
) {
|
||||
super(_injector, _dialogRef, !!_data.dictionary);
|
||||
this.form = this._getForm(this.dictionary);
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
this.hasColor$ = this._colorEmpty$;
|
||||
this.technicalName$ = this.form.get('label').valueChanges.pipe(map(value => this._toTechnicalName(value)));
|
||||
}
|
||||
|
||||
private get _canEditLabel$() {
|
||||
return this.userService.currentUser$.pipe(
|
||||
map(user => user.isAdmin || !this._data.dictionary),
|
||||
shareDistinctLast(),
|
||||
);
|
||||
}
|
||||
|
||||
private get _colorEmpty$() {
|
||||
return this.form.get('hexColor').valueChanges.pipe(map((value: string) => !value || value?.length === 0));
|
||||
}
|
||||
|
||||
getDictCaseSensitive(dictionary: Dictionary): boolean {
|
||||
return dictionary ? !dictionary.caseInsensitive : false;
|
||||
}
|
||||
|
||||
async save(): Promise<void> {
|
||||
this._loadingService.start();
|
||||
const dictionary = this._formToObject();
|
||||
const dossierTemplateId = this._data.dossierTemplateId;
|
||||
|
||||
try {
|
||||
if (this.dictionary) {
|
||||
// edit mode
|
||||
await firstValueFrom(this._dictionaryService.updateDictionary(dictionary, dossierTemplateId, dictionary.type));
|
||||
this._toaster.success(_('add-edit-dictionary.success.edit'));
|
||||
} else {
|
||||
// create mode
|
||||
await firstValueFrom(this._dictionaryService.addDictionary({ ...dictionary, dossierTemplateId }));
|
||||
this._toaster.success(_('add-edit-dictionary.success.create'));
|
||||
}
|
||||
this._dialogRef.close(true);
|
||||
} catch (e) {}
|
||||
|
||||
this._loadingService.stop();
|
||||
}
|
||||
|
||||
private _getForm(dictionary: Dictionary): FormGroup {
|
||||
return this._formBuilder.group({
|
||||
label: [dictionary?.label, [Validators.required, Validators.minLength(3)]],
|
||||
description: [dictionary?.description],
|
||||
rank: [dictionary?.rank, Validators.required],
|
||||
hexColor: [dictionary?.hexColor, [Validators.required, Validators.minLength(7)]],
|
||||
hint: [!!dictionary?.hint],
|
||||
addToDictionaryAction: [!!dictionary?.addToDictionaryAction],
|
||||
caseSensitive: [this.getDictCaseSensitive(dictionary)],
|
||||
});
|
||||
}
|
||||
|
||||
private _toTechnicalName(value: string) {
|
||||
const existingTechnicalNames = this._dictionariesMapService.get(this._dossierTemplateId).map(dict => dict.type);
|
||||
const baseTechnicalName = toSnakeCase(value.trim());
|
||||
let technicalName = baseTechnicalName;
|
||||
let suffix = 1;
|
||||
while (existingTechnicalNames.includes(technicalName)) {
|
||||
technicalName = [baseTechnicalName, suffix++].join('_');
|
||||
}
|
||||
return technicalName;
|
||||
}
|
||||
|
||||
private _formToObject(): IDictionary {
|
||||
return {
|
||||
type: this.dictionary?.type || this._toTechnicalName(this.form.get('label').value),
|
||||
label: this.form.get('label').value,
|
||||
caseInsensitive: !this.form.get('caseSensitive').value,
|
||||
description: this.form.get('description').value,
|
||||
hexColor: this.form.get('hexColor').value,
|
||||
hint: this.form.get('hint').value,
|
||||
rank: this.form.get('rank').value,
|
||||
addToDictionaryAction: this.form.get('addToDictionaryAction').value,
|
||||
dossierTemplateId: this._data.dossierTemplateId,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -0,0 +1,19 @@
|
||||
<section class="dialog">
|
||||
<div class="dialog-header heading-l">
|
||||
{{ dialogHeader }}
|
||||
</div>
|
||||
|
||||
<form [formGroup]="form">
|
||||
<div class="dialog-content">
|
||||
<redaction-add-edit-entity [dossierTemplateId]="dossierTemplateId" [entity]="entity" [form]="form"></redaction-add-edit-entity>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<button (click)="save()" [disabled]="disabled" color="primary" mat-flat-button type="button">
|
||||
{{ 'add-entity.save' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<iqser-circle-button (action)="close()" class="dialog-close" icon="iqser:close"></iqser-circle-button>
|
||||
</section>
|
||||
@ -0,0 +1,64 @@
|
||||
import { ChangeDetectionStrategy, Component, Inject, Injector, ViewChild } from '@angular/core';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { BaseDialogComponent } from '@iqser/common-ui';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { Dictionary } from '@red/domain';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { AddEditEntityComponent } from '../../shared/components/add-edit-entity/add-edit-entity.component';
|
||||
|
||||
@Component({
|
||||
templateUrl: './add-entity-dialog.component.html',
|
||||
styleUrls: ['./add-entity-dialog.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AddEntityDialogComponent extends BaseDialogComponent {
|
||||
readonly entity = this._data.dictionary;
|
||||
readonly dialogHeader = this._translateService.instant('add-entity.title');
|
||||
readonly dossierTemplateId = this._data.dossierTemplateId;
|
||||
|
||||
@ViewChild(AddEditEntityComponent) private readonly _addEditEntityComponent: AddEditEntityComponent;
|
||||
|
||||
constructor(
|
||||
readonly userService: UserService,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _dictionariesMapService: DictionariesMapService,
|
||||
private readonly _translateService: TranslateService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
protected readonly _injector: Injector,
|
||||
protected readonly _dialogRef: MatDialogRef<AddEntityDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
private readonly _data: { readonly dictionary: Dictionary; readonly dossierTemplateId: string },
|
||||
) {
|
||||
super(_injector, _dialogRef, !!_data.dictionary);
|
||||
this.form = this._getForm(this.entity);
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
}
|
||||
|
||||
async save(): Promise<void> {
|
||||
try {
|
||||
await this._addEditEntityComponent.save();
|
||||
this._dialogRef.close(true);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private _getForm(entity: Dictionary): FormGroup {
|
||||
return this._formBuilder.group({
|
||||
type: [entity?.label],
|
||||
label: [entity?.label, [Validators.required, Validators.minLength(3)]],
|
||||
description: [entity?.description],
|
||||
rank: [entity?.rank, Validators.required],
|
||||
hexColor: [entity?.hexColor, [Validators.required, Validators.minLength(7)]],
|
||||
hint: [!!entity?.hint],
|
||||
addToDictionaryAction: [!!entity?.addToDictionaryAction],
|
||||
caseSensitive: [entity ? !entity.caseInsensitive : false],
|
||||
recommendationHexColor: [this.entity?.recommendationHexColor, [Validators.required, Validators.minLength(7)]],
|
||||
hasDictionary: [this.entity?.hasDictionary],
|
||||
defaultReason: [{ value: null, disabled: true }],
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -1,101 +0,0 @@
|
||||
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,
|
||||
IconButtonTypes,
|
||||
ListingComponent,
|
||||
LoadingService,
|
||||
TableColumnConfig,
|
||||
} from '@iqser/common-ui';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { DictionaryService } from '@shared/services/dictionary.service';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { Dictionary, DossierTemplateStats } from '@red/domain';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
import { DossierTemplateStatsService } from '@services/entity-services/dossier-template-stats.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { DOSSIER_TEMPLATE_ID } from '@utils/constants';
|
||||
|
||||
@Component({
|
||||
templateUrl: './dictionary-listing-screen.component.html',
|
||||
styleUrls: ['./dictionary-listing-screen.component.scss'],
|
||||
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => DictionaryListingScreenComponent) }],
|
||||
})
|
||||
export class DictionaryListingScreenComponent extends ListingComponent<Dictionary> {
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
readonly tableHeaderLabel = _('dictionary-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' },
|
||||
];
|
||||
chartData: DoughnutChartConfig[] = [];
|
||||
readonly templateStats$: Observable<DossierTemplateStats>;
|
||||
readonly #dossierTemplateId: string;
|
||||
|
||||
constructor(
|
||||
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)));
|
||||
}
|
||||
|
||||
openDeleteDictionariesDialog($event?: MouseEvent, types = this.listingService.selected) {
|
||||
this._dialogService.openDialog('confirm', $event, null, async () => {
|
||||
this._loadingService.start();
|
||||
await firstValueFrom(
|
||||
this._dictionaryService.deleteDictionaries(
|
||||
types.map(t => t.type),
|
||||
this.#dossierTemplateId,
|
||||
),
|
||||
);
|
||||
this._loadingService.stop();
|
||||
});
|
||||
}
|
||||
|
||||
openAddEditDictionaryDialog($event?: MouseEvent, dictionary?: Dictionary) {
|
||||
this._dialogService.openDialog('addEditDictionary', $event, {
|
||||
dictionary,
|
||||
dossierTemplateId: this.#dossierTemplateId,
|
||||
});
|
||||
}
|
||||
|
||||
private _loadDictionaryData(templateStats: DossierTemplateStats): 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();
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
|
||||
@ -21,40 +21,28 @@
|
||||
|
||||
<div class="content-container">
|
||||
<iqser-table
|
||||
(noDataAction)="openAddEditDictionaryDialog()"
|
||||
(noDataAction)="openAddEntityDialog()"
|
||||
[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"
|
||||
[noDataButtonIcon]="'iqser:plus'"
|
||||
[noDataButtonLabel]="'entities-listing.no-data.action' | translate"
|
||||
[noDataText]="'entities-listing.no-data.title' | translate"
|
||||
[noMatchText]="'entities-listing.no-match.title' | translate"
|
||||
[selectionEnabled]="true"
|
||||
[showNoDataButton]="currentUser.isAdmin"
|
||||
[showNoDataButton]="permissionsService.canEditEntities()"
|
||||
[tableColumnConfigs]="tableColumnConfigs"
|
||||
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>
|
||||
|
||||
<ng-template #bulkActions>
|
||||
<iqser-circle-button
|
||||
(action)="openDeleteDictionariesDialog($event)"
|
||||
*ngIf="currentUser.isAdmin && (listingService.areSomeSelected$ | async)"
|
||||
[tooltip]="'dictionary-listing.bulk.delete' | translate"
|
||||
(action)="openDeleteEntitiesDialog($event)"
|
||||
*ngIf="permissionsService.canEditEntities() && (listingService.areSomeSelected$ | async)"
|
||||
[tooltip]="'entities-listing.bulk.delete' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:trash"
|
||||
></iqser-circle-button>
|
||||
@ -64,13 +52,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"
|
||||
(action)="openAddEntityDialog()"
|
||||
*ngIf="permissionsService.canEditEntities()"
|
||||
[label]="'entities-listing.add-new' | translate"
|
||||
[type]="iconButtonTypes.primary"
|
||||
icon="iqser:plus"
|
||||
></iqser-icon-button>
|
||||
@ -87,16 +75,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 +87,21 @@
|
||||
</div>
|
||||
|
||||
<div class="cell">
|
||||
<div *ngIf="currentUser.isAdmin" class="action-buttons">
|
||||
<div class="small-label">
|
||||
{{ templateStats.dictionarySummary(dict.type)?.entriesCount || 0 }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="permissionsService.canEditEntities()" class="action-buttons">
|
||||
<iqser-circle-button
|
||||
(action)="openDeleteDictionariesDialog($event, [dict])"
|
||||
[tooltip]="'dictionary-listing.action.delete' | translate"
|
||||
(action)="openDeleteEntitiesDialog($event, [dict])"
|
||||
[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>
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
import { Component, forwardRef, Injector } from '@angular/core';
|
||||
import {
|
||||
CircleButtonTypes,
|
||||
DefaultListingServices,
|
||||
IconButtonTypes,
|
||||
ListingComponent,
|
||||
LoadingService,
|
||||
TableColumnConfig,
|
||||
} from '@iqser/common-ui';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
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';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { DOSSIER_TEMPLATE_ID } from '@utils/constants';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
|
||||
@Component({
|
||||
templateUrl: './entities-listing-screen.component.html',
|
||||
styleUrls: ['./entities-listing-screen.component.scss'],
|
||||
providers: [...DefaultListingServices, { provide: ListingComponent, useExisting: forwardRef(() => EntitiesListingScreenComponent) }],
|
||||
})
|
||||
export class EntitiesListingScreenComponent extends ListingComponent<Dictionary> {
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
readonly circleButtonTypes = CircleButtonTypes;
|
||||
readonly tableHeaderLabel = _('entities-listing.table-header.title');
|
||||
readonly tableColumnConfigs: TableColumnConfig<Dictionary>[] = [
|
||||
{ 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') },
|
||||
];
|
||||
readonly templateStats$: Observable<DossierTemplateStats>;
|
||||
readonly #dossierTemplateId: string;
|
||||
|
||||
constructor(
|
||||
protected readonly _injector: Injector,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _dictionariesMapService: DictionariesMapService,
|
||||
private readonly _dialogService: AdminDialogService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _dossierTemplateStatsService: DossierTemplateStatsService,
|
||||
private readonly _route: ActivatedRoute,
|
||||
readonly permissionsService: PermissionsService,
|
||||
) {
|
||||
super(_injector);
|
||||
this.#dossierTemplateId = _route.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID);
|
||||
this.templateStats$ = this._dossierTemplateStatsService.watch$(this.#dossierTemplateId).pipe(tap(() => this._loadDictionaryData()));
|
||||
}
|
||||
|
||||
openDeleteEntitiesDialog($event?: MouseEvent, types = this.listingService.selected) {
|
||||
this._dialogService.openDialog('confirm', $event, null, async () => {
|
||||
this._loadingService.start();
|
||||
await firstValueFrom(
|
||||
this._dictionaryService.deleteDictionaries(
|
||||
types.map(t => t.type),
|
||||
this.#dossierTemplateId,
|
||||
),
|
||||
);
|
||||
this._loadingService.stop();
|
||||
});
|
||||
}
|
||||
|
||||
openAddEntityDialog($event?: MouseEvent) {
|
||||
this._dialogService.openDialog('addEntity', $event, { dossierTemplateId: this.#dossierTemplateId });
|
||||
}
|
||||
|
||||
private _loadDictionaryData(): void {
|
||||
const entities: Dictionary[] = this._dictionariesMapService.get(this.#dossierTemplateId).filter(d => !d.virtual);
|
||||
this.entitiesService.setEntities(entities);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
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 { SharedAdminModule } from '../../shared/shared-admin.module';
|
||||
|
||||
const routes = [
|
||||
{ path: '', redirectTo: 'info', pathMatch: 'full' },
|
||||
{
|
||||
path: 'info',
|
||||
component: InfoComponent,
|
||||
},
|
||||
{
|
||||
path: 'dictionary',
|
||||
component: DictionaryScreenComponent,
|
||||
canDeactivate: [PendingChangesGuard],
|
||||
},
|
||||
{
|
||||
path: 'false-positive',
|
||||
component: DictionaryScreenComponent,
|
||||
canDeactivate: [PendingChangesGuard],
|
||||
},
|
||||
{
|
||||
path: 'false-recommendations',
|
||||
component: DictionaryScreenComponent,
|
||||
canDeactivate: [PendingChangesGuard],
|
||||
},
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
declarations: [DictionaryScreenComponent, InfoComponent],
|
||||
imports: [RouterModule.forChild(routes), SharedAdminModule, CommonModule, SharedModule, MonacoEditorModule],
|
||||
})
|
||||
export class EntitiesModule {}
|
||||
@ -0,0 +1,9 @@
|
||||
<redaction-dictionary-manager
|
||||
#dictionaryManager
|
||||
(saveDictionary)="save()"
|
||||
[canEdit]="currentUser.isAdmin"
|
||||
[filterByDossierTemplate]="true"
|
||||
[initialEntries]="initialEntries$ | async"
|
||||
[isLeavingPage]="isLeavingPage"
|
||||
[type]="type"
|
||||
></redaction-dictionary-manager>
|
||||
@ -1,7 +1,6 @@
|
||||
.right-container {
|
||||
width: 353px;
|
||||
min-width: 353px;
|
||||
padding: 24px;
|
||||
:host {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.dictionary-header {
|
||||
@ -0,0 +1,79 @@
|
||||
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 { List, 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';
|
||||
import { DICTIONARY_TO_ENTRY_TYPE_MAP, DICTIONARY_TYPE_KEY_MAP, DictionaryType } from '@red/domain';
|
||||
|
||||
@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 type: DictionaryType;
|
||||
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);
|
||||
this.type = this._route.snapshot.routeConfig.path as DictionaryType;
|
||||
}
|
||||
|
||||
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,
|
||||
true,
|
||||
DICTIONARY_TO_ENTRY_TYPE_MAP[this.type],
|
||||
),
|
||||
);
|
||||
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));
|
||||
const entries: List = data[DICTIONARY_TYPE_KEY_MAP[this.type]];
|
||||
this.initialEntries$.next([...entries].sort((str1, str2) => str1.localeCompare(str2, undefined, { sensitivity: 'accent' })));
|
||||
this._loadingService.stop();
|
||||
} catch (e) {
|
||||
this._loadingService.stop();
|
||||
this.initialEntries$.next([]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
<div class="content-container" iqserHasScrollbar>
|
||||
<div class="dialog">
|
||||
<div class="dialog-header">
|
||||
<div [translate]="'entity.info.heading'" class="heading-l"></div>
|
||||
|
||||
<div *ngIf="!permissionsService.canEditEntities()" class="read-only-indicator all-caps-label primary">
|
||||
<mat-icon class="mr-8" svgIcon="red:read-only"></mat-icon>
|
||||
{{ 'readonly' | translate }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="dialog-content">
|
||||
<redaction-add-edit-entity [dossierTemplateId]="dossierTemplateId" [entity]="entity" [form]="form"></redaction-add-edit-entity>
|
||||
</div>
|
||||
|
||||
<div *ngIf="permissionsService.canEditEntities()" class="dialog-actions">
|
||||
<button (click)="save()" [disabled]="form.invalid || !changed" color="primary" mat-flat-button>
|
||||
{{ 'entity.info.actions.save' | translate }}
|
||||
</button>
|
||||
|
||||
<div (click)="revert()" class="all-caps-label cancel" translate="entity.info.actions.revert"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -0,0 +1,28 @@
|
||||
@use 'common-mixins';
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.dialog-header {
|
||||
padding-right: 32px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ViewChild } from '@angular/core';
|
||||
import { BaseFormComponent } from '@iqser/common-ui';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { Dictionary } 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 { UserService } from '@services/user.service';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { AddEditEntityComponent } from '../../../../shared/components/add-edit-entity/add-edit-entity.component';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-info',
|
||||
templateUrl: './info.component.html',
|
||||
styleUrls: ['./info.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class InfoComponent extends BaseFormComponent {
|
||||
readonly currentUser = this._userService.currentUser;
|
||||
entity: Dictionary;
|
||||
readonly dossierTemplateId: string;
|
||||
@ViewChild(AddEditEntityComponent) private readonly _addEditEntityComponent: AddEditEntityComponent;
|
||||
|
||||
constructor(
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _dictionariesMapService: DictionariesMapService,
|
||||
private readonly _route: ActivatedRoute,
|
||||
private readonly _userService: UserService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _changeRef: ChangeDetectorRef,
|
||||
readonly permissionsService: PermissionsService,
|
||||
) {
|
||||
super();
|
||||
this.dossierTemplateId = this._route.parent.snapshot.paramMap.get(DOSSIER_TEMPLATE_ID);
|
||||
this.form = this._initializeForm();
|
||||
}
|
||||
|
||||
async save(): Promise<void> {
|
||||
try {
|
||||
await this._addEditEntityComponent.save();
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
this._changeRef.markForCheck();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
revert(): void {
|
||||
this.form = this._initializeForm();
|
||||
}
|
||||
|
||||
private _initializeForm(): FormGroup {
|
||||
const entityType = this._route.parent.snapshot.paramMap.get(ENTITY_TYPE);
|
||||
this.entity = this._dictionariesMapService.getDictionary(entityType, this.dossierTemplateId);
|
||||
|
||||
const controlsConfig = {
|
||||
type: [this.entity.type],
|
||||
label: [
|
||||
{
|
||||
value: this.entity.label,
|
||||
disabled: !this.currentUser.isAdmin,
|
||||
},
|
||||
[Validators.required, Validators.minLength(3)],
|
||||
],
|
||||
description: [this.entity.description],
|
||||
rank: [this.entity.rank, Validators.required],
|
||||
hexColor: [this.entity.hexColor, [Validators.required, Validators.minLength(7)]],
|
||||
recommendationHexColor: [this.entity.recommendationHexColor, [Validators.required, Validators.minLength(7)]],
|
||||
hint: [this.entity.hint],
|
||||
hasDictionary: [this.entity.hasDictionary],
|
||||
};
|
||||
|
||||
if (!this.entity.hint) {
|
||||
Object.assign(controlsConfig, {
|
||||
defaultReason: [{ value: null, disabled: true }],
|
||||
caseSensitive: [!this.entity.caseInsensitive],
|
||||
addToDictionaryAction: [this.entity.addToDictionaryAction],
|
||||
});
|
||||
}
|
||||
const form = this._formBuilder.group(controlsConfig);
|
||||
|
||||
this.initialFormValue = form.getRawValue();
|
||||
|
||||
return form;
|
||||
}
|
||||
}
|
||||
@ -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">
|
||||
|
||||
@ -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] }];
|
||||
|
||||
|
||||
@ -56,7 +56,7 @@
|
||||
<div class="iqser-input-group w-150">
|
||||
<label class="all-caps-label mb-5" translate="watermark-screen.form.color"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-dictionary.form.color-placeholder' | translate"
|
||||
[placeholder]="'watermark-screen.form.color-placeholder' | translate"
|
||||
class="hex-color-input"
|
||||
formControlName="hexColor"
|
||||
name="hexColor"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { Injectable, TemplateRef } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { AddEditFileAttributeDialogComponent } from '../dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component';
|
||||
import { AddEditDictionaryDialogComponent } from '../dialogs/add-edit-dictionary-dialog/add-edit-dictionary-dialog.component';
|
||||
import { AddEntityDialogComponent } from '../dialogs/add-entity-dialog/add-entity-dialog.component';
|
||||
import { AddEditDossierTemplateDialogComponent } from '../dialogs/add-edit-dossier-template-dialog/add-edit-dossier-template-dialog.component';
|
||||
import { EditColorDialogComponent } from '../dialogs/edit-color-dialog/edit-color-dialog.component';
|
||||
import { SmtpAuthDialogComponent } from '../dialogs/smtp-auth-dialog/smtp-auth-dialog.component';
|
||||
@ -27,11 +27,11 @@ import { firstValueFrom, forkJoin } from 'rxjs';
|
||||
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { IDossierAttributeConfig, IFileAttributeConfig, IReportTemplate } from '@red/domain';
|
||||
import { ReportTemplateService } from '../../../services/report-template.service';
|
||||
import { ReportTemplateService } from '@services/report-template.service';
|
||||
|
||||
type DialogType =
|
||||
| 'confirm'
|
||||
| 'addEditDictionary'
|
||||
| 'addEntity'
|
||||
| 'editColor'
|
||||
| 'addEditFileAttribute'
|
||||
| 'importFileAttributes'
|
||||
@ -51,8 +51,8 @@ export class AdminDialogService extends DialogService<DialogType> {
|
||||
component: ConfirmationDialogComponent,
|
||||
dialogConfig: { disableClose: false },
|
||||
},
|
||||
addEditDictionary: {
|
||||
component: AddEditDictionaryDialogComponent,
|
||||
addEntity: {
|
||||
component: AddEntityDialogComponent,
|
||||
dialogConfig: { autoFocus: true },
|
||||
},
|
||||
editColor: {
|
||||
|
||||
@ -0,0 +1,116 @@
|
||||
<form [formGroup]="form">
|
||||
<div class="row">
|
||||
<div class="iqser-input-group required">
|
||||
<label translate="add-edit-entity.form.name"></label>
|
||||
<input [placeholder]="'add-edit-entity.form.name-placeholder' | translate" formControlName="label" name="label" type="text" />
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group required w-75">
|
||||
<label translate="add-edit-entity.form.rank"></label>
|
||||
<input [placeholder]="'add-edit-entity.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="add-edit-entity.form.color"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-entity.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"
|
||||
[cpDisabled]="form.get('hexColor').disabled"
|
||||
[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="add-edit-entity.form.recommendation-color"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-entity.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"
|
||||
[cpDisabled]="form.get('recommendationHexColor').disabled"
|
||||
[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="add-edit-entity.form.technical-name"></label>
|
||||
<div class="technical-name">{{ this.form.get('type').value || '-' }}</div>
|
||||
<span
|
||||
[translateParams]="{ type: entity ? 'edit' : 'create' }"
|
||||
[translate]="'add-edit-entity.form.technical-name-hint'"
|
||||
class="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">
|
||||
{{ 'add-edit-entity.form.redaction' | translate }}
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle [value]="true">
|
||||
{{ 'add-edit-entity.form.hint' | translate }}
|
||||
</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
</div>
|
||||
|
||||
<div *ngIf="form.get('defaultReason')" class="iqser-input-group w-400">
|
||||
<label translate="add-edit-entity.form.default-reason"></label>
|
||||
<mat-select
|
||||
[placeholder]="'add-edit-entity.form.default-reason-placeholder' | translate"
|
||||
formControlName="defaultReason"
|
||||
></mat-select>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group w-400">
|
||||
<label translate="add-edit-entity.form.description"></label>
|
||||
<textarea
|
||||
[placeholder]="'add-edit-entity.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">
|
||||
{{ 'add-edit-entity.form.has-dictionary' | translate }}
|
||||
</mat-slide-toggle>
|
||||
</div>
|
||||
|
||||
<div *ngIf="form.get('caseSensitive')" class="iqser-input-group">
|
||||
<mat-checkbox color="primary" formControlName="caseSensitive" name="caseSensitive">
|
||||
{{ 'add-edit-entity.form.case-sensitive' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<div *ngIf="form.get('addToDictionaryAction')" class="iqser-input-group">
|
||||
<mat-checkbox color="primary" formControlName="addToDictionaryAction" name="addToDictionaryAction">
|
||||
{{ 'add-edit-entity.form.add-to-dictionary-action' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</form>
|
||||
@ -0,0 +1,11 @@
|
||||
.row {
|
||||
display: flex;
|
||||
|
||||
> *:not(:last-child) {
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
.iqser-input-group {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,122 @@
|
||||
import { ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
|
||||
import { Dictionary, IDictionary } from '@red/domain';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { map, startWith } from 'rxjs/operators';
|
||||
import { firstValueFrom, Observable } from 'rxjs';
|
||||
import { toSnakeCase } from '@utils/functions';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||
import { LoadingService, Toaster } from '@iqser/common-ui';
|
||||
|
||||
const REDACTION_FIELDS = ['defaultReason', 'caseSensitive', 'addToDictionaryAction'];
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-add-edit-entity [entity] [dossierTemplateId]',
|
||||
templateUrl: './add-edit-entity.component.html',
|
||||
styleUrls: ['./add-edit-entity.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class AddEditEntityComponent implements OnInit, OnChanges {
|
||||
@Input() dossierTemplateId: string;
|
||||
@Input() entity: Dictionary;
|
||||
@Input() form: FormGroup;
|
||||
|
||||
hasHexColor$: Observable<boolean>;
|
||||
hasRecommendationHexColor$: Observable<boolean>;
|
||||
technicalName$: Observable<string>;
|
||||
|
||||
constructor(
|
||||
private readonly _dictionariesMapService: DictionariesMapService,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _loadingService: LoadingService,
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
this.hasHexColor$ = this._colorEmpty$('hexColor');
|
||||
this.hasRecommendationHexColor$ = this._colorEmpty$('recommendationHexColor');
|
||||
this.technicalName$ = this.form.get('label').valueChanges.pipe(map((value: string) => this._toTechnicalName(value)));
|
||||
}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.form) {
|
||||
this.form.get('hint').valueChanges.subscribe(isHint => {
|
||||
if (isHint) {
|
||||
REDACTION_FIELDS.forEach(field => this.form.removeControl(field));
|
||||
} else {
|
||||
this.form.addControl('addToDictionaryAction', new FormControl(this.entity?.addToDictionaryAction));
|
||||
this.form.addControl('caseSensitive', new FormControl(!this.entity?.caseInsensitive));
|
||||
this.form.addControl('defaultReason', new FormControl({ value: null, disabled: true }));
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.entity) {
|
||||
this.form.get('label').valueChanges.subscribe((label: string) => {
|
||||
this.form.get('type').setValue(this._toTechnicalName(label));
|
||||
});
|
||||
}
|
||||
|
||||
if (!this._permissionsService.canEditEntities()) {
|
||||
this.form.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async save(): Promise<void> {
|
||||
this._loadingService.start();
|
||||
const dictionary = this._formToObject();
|
||||
|
||||
try {
|
||||
if (this.entity) {
|
||||
// edit mode
|
||||
await firstValueFrom(this._dictionaryService.updateDictionary(dictionary, this.dossierTemplateId, dictionary.type));
|
||||
this._toaster.success(_('add-edit-entity.success.edit'));
|
||||
} else {
|
||||
// create mode
|
||||
await firstValueFrom(this._dictionaryService.addDictionary({ ...dictionary, dossierTemplateId: this.dossierTemplateId }));
|
||||
this._toaster.success(_('add-edit-entity.success.create'));
|
||||
}
|
||||
this._loadingService.stop();
|
||||
} catch (e) {
|
||||
this._loadingService.stop();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private _toTechnicalName(value: string) {
|
||||
const existingTechnicalNames = this._dictionariesMapService.get(this.dossierTemplateId).map(dict => dict.type);
|
||||
const baseTechnicalName = toSnakeCase(value.trim());
|
||||
let technicalName = baseTechnicalName;
|
||||
let suffix = 1;
|
||||
while (existingTechnicalNames.includes(technicalName)) {
|
||||
technicalName = [baseTechnicalName, suffix++].join('_');
|
||||
}
|
||||
return technicalName;
|
||||
}
|
||||
|
||||
private _colorEmpty$(field: string) {
|
||||
return this.form.get(field).valueChanges.pipe(
|
||||
startWith(this.form.get(field).value),
|
||||
map((value: string) => !value || value?.length === 0),
|
||||
);
|
||||
}
|
||||
|
||||
private _formToObject(): IDictionary {
|
||||
return {
|
||||
type: this.form.get('type').value,
|
||||
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,
|
||||
hasDictionary: !!this.form.get('hasDictionary').value,
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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({
|
||||
|
||||
@ -2,13 +2,15 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SharedModule } from '@shared/shared.module';
|
||||
import { DossierTemplateActionsComponent } from './components/dossier-template-actions/dossier-template-actions.component';
|
||||
import { AddEditEntityComponent } from './components/add-edit-entity/add-edit-entity.component';
|
||||
import { ColorPickerModule } from 'ngx-color-picker';
|
||||
|
||||
const components = [DossierTemplateActionsComponent];
|
||||
const components = [DossierTemplateActionsComponent, AddEditEntityComponent];
|
||||
|
||||
@NgModule({
|
||||
declarations: [...components],
|
||||
exports: [...components],
|
||||
providers: [],
|
||||
imports: [CommonModule, SharedModule],
|
||||
imports: [CommonModule, SharedModule, ColorPickerModule],
|
||||
})
|
||||
export class SharedAdminModule {}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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 = [
|
||||
{
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
<form *ngIf="form" [formGroup]="form">
|
||||
<div class="iqser-input-group">
|
||||
<mat-checkbox color="primary" formControlName="addToDictionaryAction" name="addToDictionaryAction">
|
||||
{{ 'add-edit-dictionary.form.add-to-dictionary-action' | translate }}
|
||||
{{ 'edit-dossier-dialog.dictionary.add-to-dictionary-action' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@ -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';
|
||||
@ -85,6 +85,7 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
|
||||
const dictionary: IDictionary = {
|
||||
...this.dossierDictionary,
|
||||
type: 'dossier_redaction',
|
||||
hasDictionary: true,
|
||||
addToDictionaryAction: this.form.get('addToDictionaryAction').value,
|
||||
};
|
||||
await firstValueFrom(
|
||||
|
||||
@ -17,7 +17,7 @@
|
||||
{{ activeNavItem.title | translate }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="activeNavItem.readonly" class="read-only all-caps-label primary">
|
||||
<div *ngIf="activeNavItem.readonly" class="read-only-indicator all-caps-label primary">
|
||||
<mat-icon class="mr-8" svgIcon="red:read-only"></mat-icon>
|
||||
{{ 'readonly' | translate }}
|
||||
</div>
|
||||
|
||||
@ -42,14 +42,8 @@ redaction-edit-dossier-dictionary {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.read-only {
|
||||
display: flex;
|
||||
.read-only-indicator {
|
||||
position: absolute;
|
||||
right: 32px;
|
||||
top: 108px;
|
||||
|
||||
mat-icon {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
@ -28,7 +28,3 @@
|
||||
iqser-status-bar {
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.spinning-icon {
|
||||
margin: 0 12px 0 11px;
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ import { FilePreviewStateService } from '../../services/file-preview-state.servi
|
||||
import { HelpModeService, ScrollableParentView, ScrollableParentViews } from '@iqser/common-ui';
|
||||
import { PdfViewer } from '../../services/pdf-viewer.service';
|
||||
import { FileDataService } from '../../services/file-data.service';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
|
||||
export const AnnotationButtonTypes = {
|
||||
dark: 'dark',
|
||||
@ -41,6 +42,7 @@ export class AnnotationActionsComponent implements OnChanges {
|
||||
private readonly _state: FilePreviewStateService,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _fileDataService: FileDataService,
|
||||
private readonly _dictionariesMapService: DictionariesMapService,
|
||||
) {}
|
||||
|
||||
private _annotations: AnnotationWrapper[];
|
||||
@ -131,6 +133,7 @@ export class AnnotationActionsComponent implements OnChanges {
|
||||
this._permissionsService.isApprover(dossier),
|
||||
this._userService.currentUser,
|
||||
this.annotations,
|
||||
this._dictionariesMapService.get(dossier.dossierTemplateId),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,10 +30,9 @@ export class TypeAnnotationIconComponent implements OnChanges {
|
||||
|
||||
if (isHighlight) {
|
||||
this.color = this.annotation.color;
|
||||
} else if (this.annotation.isSuperTypeBasedColor) {
|
||||
this.color = this._dictionariesMapService.getDictionaryColor(this.annotation.superType, this._dossierTemplateId);
|
||||
} else {
|
||||
this.color = this._dictionariesMapService.getDictionaryColor(this.annotation.type, this._dossierTemplateId);
|
||||
const type = this.annotation.isSuperTypeBasedColor ? this.annotation.superType : this.annotation.type;
|
||||
this.color = this._dictionariesMapService.getDictionaryColor(type, this._dossierTemplateId, this.annotation.isRecommendation);
|
||||
}
|
||||
|
||||
this.type =
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -9,7 +9,7 @@ import { AnnotationPermissions } from '@models/file/annotation.permissions';
|
||||
import { BASE_HREF } from '../../../tokens';
|
||||
import { UserService } from '@services/user.service';
|
||||
import { Core } from '@pdftron/webviewer';
|
||||
import { Dossier, IAddRedactionRequest, ILegalBasisChangeRequest, IRectangle, IResizeRequest } from '@red/domain';
|
||||
import { DictionaryEntryTypes, Dossier, IAddRedactionRequest, ILegalBasisChangeRequest, IRectangle, IResizeRequest } from '@red/domain';
|
||||
import { toPosition } from '../../dossier/utils/pdf-calculation.utils';
|
||||
import { AnnotationDrawService } from './annotation-draw.service';
|
||||
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
|
||||
@ -24,6 +24,7 @@ import { MatDialog } from '@angular/material/dialog';
|
||||
import { FilePreviewStateService } from './file-preview-state.service';
|
||||
import { PdfViewer } from './pdf-viewer.service';
|
||||
import { FilePreviewDialogService } from './file-preview-dialog.service';
|
||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||
import Quad = Core.Math.Quad;
|
||||
|
||||
@Injectable()
|
||||
@ -41,6 +42,7 @@ export class AnnotationActionsService {
|
||||
private readonly _annotationDrawService: AnnotationDrawService,
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _screenStateService: FilePreviewStateService,
|
||||
private readonly _dictionariesMapService: DictionariesMapService,
|
||||
) {}
|
||||
|
||||
private get _dossier(): Dossier {
|
||||
@ -223,6 +225,7 @@ export class AnnotationActionsService {
|
||||
this._permissionsService.isApprover(dossier),
|
||||
this._userService.currentUser,
|
||||
annotation,
|
||||
this._dictionariesMapService.get(dossier.dossierTemplateId),
|
||||
),
|
||||
}));
|
||||
|
||||
@ -500,13 +503,17 @@ export class AnnotationActionsService {
|
||||
) {
|
||||
$event?.stopPropagation();
|
||||
|
||||
const falsePositiveRequest: IAddRedactionRequest = {};
|
||||
falsePositiveRequest.reason = annotation.id;
|
||||
falsePositiveRequest.value = text;
|
||||
falsePositiveRequest.type = 'false_positive';
|
||||
falsePositiveRequest.positions = annotation.positions;
|
||||
falsePositiveRequest.addToDictionary = true;
|
||||
falsePositiveRequest.comment = { text: 'False Positive' };
|
||||
const falsePositiveRequest: IAddRedactionRequest = {
|
||||
reason: annotation.id,
|
||||
value: text,
|
||||
type: annotation.type,
|
||||
positions: annotation.positions,
|
||||
addToDictionary: true,
|
||||
comment: { text: 'False Positive' },
|
||||
dictionaryEntryType: annotation.isRecommendation
|
||||
? DictionaryEntryTypes.FALSE_RECOMMENDATION
|
||||
: DictionaryEntryTypes.FALSE_POSITIVE,
|
||||
};
|
||||
const { dossierId, fileId } = this._screenStateService;
|
||||
|
||||
this._processObsAndEmit(
|
||||
|
||||
@ -46,9 +46,11 @@ export class AnnotationDrawService {
|
||||
switch (superType) {
|
||||
case SuperTypes.Hint:
|
||||
case SuperTypes.Redaction:
|
||||
case SuperTypes.Recommendation:
|
||||
color = this._dictionariesMapService.getDictionaryColor(dictionary, this._state.dossierTemplateId);
|
||||
break;
|
||||
case SuperTypes.Recommendation:
|
||||
color = this._dictionariesMapService.getDictionaryColor(dictionary, this._state.dossierTemplateId, true);
|
||||
break;
|
||||
case SuperTypes.Skipped:
|
||||
color = this._dictionariesMapService.getDictionaryColor(superType, this._state.dossierTemplateId);
|
||||
break;
|
||||
|
||||
@ -15,13 +15,13 @@ 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 { UserPreferenceService } from '../../../services/user-preference.service';
|
||||
import { DictionariesMapService } from '../../../services/entity-services/dictionaries-map.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 { map, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { PermissionsService } from '../../../services/permissions.service';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { shareDistinctLast, shareLast, Toaster } from '../../../../../../../libs/common-ui/src';
|
||||
import { shareDistinctLast, shareLast, Toaster } from '@iqser/common-ui';
|
||||
import { RedactionLogService } from '../../dossier/services/redaction-log.service';
|
||||
import { TextHighlightService } from '../../dossier/services/text-highlight.service';
|
||||
import { ViewModeService } from './view-mode.service';
|
||||
|
||||
@ -10,7 +10,7 @@ import { DISABLED_HOTKEYS } from '../shared/constants';
|
||||
import { Observable, Subject } from 'rxjs';
|
||||
import { NGXLogger } from 'ngx-logger';
|
||||
import { tap } from 'rxjs/operators';
|
||||
import { shareLast } from '../../../../../../../libs/common-ui/src';
|
||||
import { shareLast } from '@iqser/common-ui';
|
||||
import Annotation = Core.Annotations.Annotation;
|
||||
|
||||
@Injectable()
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group w-200 mt-0">
|
||||
<mat-select [(ngModel)]="dictionary" [disabled]="!compare || dossierTemplateIsNotSelected">
|
||||
<mat-select [(ngModel)]="compareDictionary" [disabled]="!compare || dossierTemplateIsNotSelected">
|
||||
<mat-option [value]="selectDictionary">{{ selectDictionary.label | translate }}</mat-option>
|
||||
<mat-option *ngFor="let dictionary of dictionaries" [value]="dictionary">
|
||||
{{ dictionary.label }}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { Debounce, IconButtonTypes, List } from '@iqser/common-ui';
|
||||
import { ChangeDetectorRef, Component, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core';
|
||||
import { Debounce, IconButtonTypes, List, LoadingService } from '@iqser/common-ui';
|
||||
import { firstValueFrom, Observable, of } from 'rxjs';
|
||||
import { catchError, map, take, tap } from 'rxjs/operators';
|
||||
import { Dictionary, Dossier, DossierTemplate } from '@red/domain';
|
||||
import { Dictionary, DICTIONARY_TYPE_KEY_MAP, DictionaryType, 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';
|
||||
@ -22,6 +22,7 @@ const SMOOTH_SCROLL = 0;
|
||||
export class DictionaryManagerComponent implements OnChanges {
|
||||
readonly iconButtonTypes = IconButtonTypes;
|
||||
|
||||
@Input() type: DictionaryType = 'dictionary';
|
||||
@Input() withFloatingActions = true;
|
||||
@Input() filterByDossierTemplate = false;
|
||||
@Input() initialEntries: List;
|
||||
@ -47,6 +48,8 @@ export class DictionaryManagerComponent implements OnChanges {
|
||||
constructor(
|
||||
private readonly _dictionaryService: DictionaryService,
|
||||
private readonly _dictionariesMapService: DictionariesMapService,
|
||||
private readonly _loadingService: LoadingService,
|
||||
private readonly _changeRef: ChangeDetectorRef,
|
||||
readonly activeDossiersService: ActiveDossiersService,
|
||||
readonly dossierTemplatesService: DossierTemplatesService,
|
||||
) {}
|
||||
@ -60,7 +63,7 @@ export class DictionaryManagerComponent implements OnChanges {
|
||||
set dossierTemplate(value) {
|
||||
this._dossierTemplate = value;
|
||||
this.dictionaries = this._dictionaries;
|
||||
this._dictionary = this.selectDictionary;
|
||||
this._compareDictionary = this.selectDictionary;
|
||||
this.showDiffEditor = false;
|
||||
}
|
||||
|
||||
@ -87,14 +90,15 @@ export class DictionaryManagerComponent implements OnChanges {
|
||||
});
|
||||
}
|
||||
|
||||
private _dictionary = this.selectDictionary;
|
||||
private _compareDictionary = this.selectDictionary;
|
||||
|
||||
get dictionary() {
|
||||
return this._dictionary;
|
||||
get compareDictionary() {
|
||||
return this._compareDictionary;
|
||||
}
|
||||
|
||||
set dictionary(dictionary: Dictionary) {
|
||||
this._dictionary = dictionary;
|
||||
set compareDictionary(dictionary: Dictionary) {
|
||||
this._loadingService.start();
|
||||
this._compareDictionary = dictionary;
|
||||
|
||||
if (dictionary.label === this.selectDictionary.label) {
|
||||
this.showDiffEditor = false;
|
||||
@ -102,7 +106,8 @@ export class DictionaryManagerComponent implements OnChanges {
|
||||
return;
|
||||
}
|
||||
const entries: List =
|
||||
this._dictionary.entries ?? this._dictionariesMapService.get(this._dictionary.dossierTemplateId, this._dictionary.type).entries;
|
||||
this._compareDictionary.getEntries(this.type) ??
|
||||
this._dictionariesMapService.get(this._compareDictionary.dossierTemplateId, this._compareDictionary.type).getEntries(this.type);
|
||||
|
||||
if (entries.length) {
|
||||
this.diffEditorText = this._toString([...entries]);
|
||||
@ -111,16 +116,20 @@ export class DictionaryManagerComponent implements OnChanges {
|
||||
}
|
||||
|
||||
firstValueFrom(
|
||||
this._dictionaryService.getForType(this._dictionary.dossierTemplateId, this._dictionary.type).pipe(
|
||||
tap(values => (this._dictionary.entries = [...values.entries] ?? [])),
|
||||
this._dictionaryService.getForType(this._compareDictionary.dossierTemplateId, this._compareDictionary.type).pipe(
|
||||
tap(values => {
|
||||
this._compareDictionary.setEntries([...values[DICTIONARY_TYPE_KEY_MAP[this.type]]] ?? [], this.type);
|
||||
}),
|
||||
catchError(() => {
|
||||
this._dictionary.entries = [];
|
||||
this._compareDictionary.setEntries([], this.type);
|
||||
return of({});
|
||||
}),
|
||||
),
|
||||
).then(() => {
|
||||
this.diffEditorText = this._toString([...this._dictionary.entries]);
|
||||
this.diffEditorText = this._toString([...(this._compareDictionary.getEntries(this.type) as string[])]);
|
||||
this.showDiffEditor = true;
|
||||
this._changeRef.markForCheck();
|
||||
this._loadingService.stop();
|
||||
});
|
||||
}
|
||||
|
||||
@ -137,7 +146,7 @@ export class DictionaryManagerComponent implements OnChanges {
|
||||
|
||||
get optionNotSelected() {
|
||||
if (this.filterByDossierTemplate) {
|
||||
return this.selectDictionary.label === this._dictionary.label;
|
||||
return this.selectDictionary.label === this._compareDictionary.label;
|
||||
}
|
||||
return this.dossier.dossierName === this.selectDossier.dossierName;
|
||||
}
|
||||
@ -207,7 +216,6 @@ export class DictionaryManagerComponent implements OnChanges {
|
||||
|
||||
private _onDossierChanged(dossierTemplateId: string, dossierId?: string, type = 'dossier_redaction'): Observable<string> {
|
||||
const dictionary$ = this._dictionaryService.getForType(dossierTemplateId, type, dossierId);
|
||||
|
||||
return dictionary$.pipe(map(data => this._toString([...data.entries])));
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,18 @@ export class DictionariesMapService extends EntitiesMapService<Dictionary, IDict
|
||||
return this.get(dossierTemplateId, type) || this.get(dossierTemplateId, 'default');
|
||||
}
|
||||
|
||||
getDictionaryColor(type: string, dossierTemplateId: string) {
|
||||
return !this.get(dossierTemplateId) ? '#cccccc' : this.getDictionary(type, dossierTemplateId)?.hexColor || '#cccccc';
|
||||
getDictionaryColor(type: string, dossierTemplateId: string, isRecommendation = false) {
|
||||
const defaultColor = '#CCCCCC';
|
||||
if (!this.get(dossierTemplateId)) {
|
||||
return defaultColor;
|
||||
}
|
||||
|
||||
const dictionary = this.getDictionary(type, dossierTemplateId);
|
||||
const colorKey = isRecommendation ? 'recommendationHexColor' : 'hexColor';
|
||||
if (dictionary && dictionary[colorKey]) {
|
||||
return dictionary[colorKey];
|
||||
}
|
||||
|
||||
return defaultColor;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import { Injectable, Injector } from '@angular/core';
|
||||
import { firstValueFrom, forkJoin, Observable, of, throwError } from 'rxjs';
|
||||
import { EntitiesService, List, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
|
||||
import { Dictionary, IColors, IDictionary, IUpdateDictionary } from '@red/domain';
|
||||
import { Dictionary, DictionaryEntryType, DictionaryEntryTypes, 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';
|
||||
|
||||
@ -32,7 +32,7 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
* Retrieves all dictionary entries of an entry type
|
||||
*/
|
||||
@Validate()
|
||||
getForType(@RequiredParam() dossierTemplateId: string, @RequiredParam() type: string, dossierId?: string) {
|
||||
getForType(@RequiredParam() dossierTemplateId: string, @RequiredParam() type: string, dossierId?: string): Observable<IDictionary> {
|
||||
const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined;
|
||||
return this._getOne([type, dossierTemplateId], this._defaultModelPath, queryParams);
|
||||
}
|
||||
@ -144,6 +144,7 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
type: string,
|
||||
dossierId: string,
|
||||
showToast = true,
|
||||
dictionaryEntryType = DictionaryEntryTypes.ENTRY,
|
||||
): Observable<unknown> {
|
||||
let entriesToAdd = [];
|
||||
entries.forEach(currentEntry => {
|
||||
@ -156,13 +157,13 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
// can add at least 1 - block UI
|
||||
let obs: Observable<IDictionary>;
|
||||
if (entriesToAdd.length > 0) {
|
||||
obs = this._addEntry(entriesToAdd, dossierTemplateId, type, dossierId, true);
|
||||
obs = this._addEntries(entriesToAdd, dossierTemplateId, type, dictionaryEntryType, dossierId);
|
||||
} else {
|
||||
obs = this._deleteEntries(initialEntries, dossierTemplateId, type, dossierId);
|
||||
obs = this._deleteEntries(initialEntries, dossierTemplateId, type, dictionaryEntryType, dossierId);
|
||||
}
|
||||
|
||||
return obs.pipe(
|
||||
switchMap(dictionary => this._dossierTemplateStatsService.getFor([dossierTemplateId]).pipe(mapTo(dictionary))),
|
||||
switchMap(dictionary => this._dossierTemplateStatsService.getFor([dossierTemplateId]).pipe(map(() => dictionary))),
|
||||
tap(
|
||||
() => {
|
||||
if (showToast) {
|
||||
@ -216,7 +217,7 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
const virtualTypes$: Observable<Dictionary[]> = this.getColors(dossierTemplateId).pipe(
|
||||
tap(colors => {
|
||||
for (const key of Object.keys(colors)) {
|
||||
const color = colors[key];
|
||||
const color: string = colors[key];
|
||||
try {
|
||||
const rgbValue = hexToRgb(color);
|
||||
if (!rgbValue) {
|
||||
@ -273,11 +274,11 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
|
||||
#addUpdateDictionaryErrorToast(error: HttpErrorResponse): Observable<never> {
|
||||
if (error.status === HttpStatusCode.Conflict) {
|
||||
this._toaster.error(_('add-edit-dictionary.error.dictionary-already-exists'));
|
||||
this._toaster.error(_('add-edit-entity.error.entity-already-exists'));
|
||||
} else if (error.status === HttpStatusCode.BadRequest) {
|
||||
this._toaster.error(_('add-edit-dictionary.error.invalid-color-or-rank'));
|
||||
this._toaster.error(_('add-edit-entity.error.invalid-color-or-rank'));
|
||||
} else {
|
||||
this._toaster.error(_('add-edit-dictionary.error.generic'));
|
||||
this._toaster.error(_('add-edit-entity.error.generic'));
|
||||
}
|
||||
return throwError(() => error);
|
||||
}
|
||||
@ -286,19 +287,20 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
* Add dictionary entries with entry type.
|
||||
*/
|
||||
@Validate()
|
||||
private _addEntry(
|
||||
@RequiredParam() body: List,
|
||||
@RequiredParam() dossierTemplateId: string,
|
||||
@RequiredParam() type: string,
|
||||
dossierId?: string,
|
||||
removeCurrent?: boolean,
|
||||
private _addEntries(
|
||||
entries: List,
|
||||
dossierTemplateId: string,
|
||||
type: string,
|
||||
dictionaryEntryType: DictionaryEntryType,
|
||||
dossierId: string,
|
||||
) {
|
||||
const queryParams: List<QueryParam> = [
|
||||
{ key: 'dossierId', value: dossierId },
|
||||
{ key: 'removeCurrent', value: removeCurrent },
|
||||
{ key: 'dictionaryEntryType', value: dictionaryEntryType },
|
||||
{ key: 'removeCurrent', value: true },
|
||||
];
|
||||
const url = `${this._defaultModelPath}/${type}/${dossierTemplateId}`;
|
||||
return this._post(body, url, queryParams);
|
||||
return this._post(entries, url, queryParams);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -306,13 +308,16 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
||||
*/
|
||||
@Validate()
|
||||
private _deleteEntries(
|
||||
@RequiredParam() body: List,
|
||||
@RequiredParam() dossierTemplateId: string,
|
||||
@RequiredParam() type: string,
|
||||
@RequiredParam() dossierId?: string,
|
||||
entries: List,
|
||||
dossierTemplateId: string,
|
||||
type: string,
|
||||
dictionaryEntryType: DictionaryEntryType,
|
||||
dossierId: string,
|
||||
) {
|
||||
const queryParams = dossierId ? [{ key: 'dossierId', value: dossierId }] : undefined;
|
||||
const queryParams = dossierId
|
||||
? [{ key: 'dossierId', value: dossierId }]
|
||||
: [{ key: 'dictionaryEntryType', value: dictionaryEntryType }];
|
||||
const url = `${this._defaultModelPath}/delete/${type}/${dossierTemplateId}`;
|
||||
return this._post(body, url, queryParams);
|
||||
return this._post(entries, url, queryParams);
|
||||
}
|
||||
}
|
||||
@ -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');
|
||||
|
||||
@ -101,14 +101,15 @@ export class ManualAnnotationService extends GenericService<IManualAddResponse>
|
||||
}
|
||||
|
||||
addRecommendation(annotation: AnnotationWrapper, dossierId: string, fileId: string, comment = { text: 'Accepted Recommendation' }) {
|
||||
const manualRedactionEntry: IAddRedactionRequest = {};
|
||||
manualRedactionEntry.addToDictionary = true;
|
||||
// set the ID as reason, so we can hide the suggestion
|
||||
manualRedactionEntry.reason = annotation.annotationId;
|
||||
manualRedactionEntry.value = annotation.value;
|
||||
manualRedactionEntry.positions = annotation.positions;
|
||||
manualRedactionEntry.type = annotation.recommendationType;
|
||||
manualRedactionEntry.comment = comment;
|
||||
const manualRedactionEntry: IAddRedactionRequest = {
|
||||
addToDictionary: true,
|
||||
// set the ID as reason, so we can hide the suggestion
|
||||
reason: annotation.annotationId,
|
||||
value: annotation.value,
|
||||
positions: annotation.positions,
|
||||
type: annotation.recommendationType,
|
||||
comment: comment,
|
||||
};
|
||||
return this.addAnnotation(manualRedactionEntry, dossierId, fileId);
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,10 @@ export class PermissionsService {
|
||||
private readonly _featuresService: FeaturesService,
|
||||
) {}
|
||||
|
||||
canEditEntities(user = this._userService.currentUser): boolean {
|
||||
return user.isAdmin;
|
||||
}
|
||||
|
||||
canPerformDossierStatesActions(user = this._userService.currentUser): boolean {
|
||||
return user.isAdmin;
|
||||
}
|
||||
|
||||
@ -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';
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"ADMIN_CONTACT_NAME": null,
|
||||
"ADMIN_CONTACT_URL": null,
|
||||
"API_URL": "https://dev-08.iqser.cloud/redaction-gateway-v1",
|
||||
"API_URL": "https://dev-05.iqser.cloud/redaction-gateway-v1",
|
||||
"APP_NAME": "RedactManager",
|
||||
"AUTO_READ_TIME": 3,
|
||||
"BACKEND_APP_VERSION": "4.4.40",
|
||||
@ -17,7 +17,7 @@
|
||||
"MAX_RETRIES_ON_SERVER_ERROR": 3,
|
||||
"OAUTH_CLIENT_ID": "redaction",
|
||||
"OAUTH_IDP_HINT": null,
|
||||
"OAUTH_URL": "https://dev-08.iqser.cloud/auth/realms/redaction",
|
||||
"OAUTH_URL": "https://dev-05.iqser.cloud/auth/realms/redaction",
|
||||
"RECENT_PERIOD_IN_HOURS": 24,
|
||||
"SELECTION_MODE": "structural",
|
||||
"MANUAL_BASE_URL": "https://docs.redactmanager.com/preview"
|
||||
|
||||
@ -36,35 +36,6 @@
|
||||
},
|
||||
"header-new": "Dossier erstellen"
|
||||
},
|
||||
"add-edit-dictionary": {
|
||||
"error": {
|
||||
"dictionary-already-exists": "Ein Wörterbuch mit diesem Namen existiert bereits!",
|
||||
"generic": "Wörterbuch konnte nicht gespeichert werden!",
|
||||
"invalid-color-or-rank": "Ungültige Farbe oder Rang! Der Rang wird bereits von einem anderen Wörterbuch verwendet oder die Farbe ist kein gültiger Hex-Farbcode!"
|
||||
},
|
||||
"form": {
|
||||
"add-to-dictionary-action": "Anwender können Einträge hinzufügen",
|
||||
"case-sensitive": "Groß-/Kleinschreibung berücksichtigen",
|
||||
"color": "Hex-Farbcode",
|
||||
"color-placeholder": "#",
|
||||
"description": "Beschreibung",
|
||||
"description-placeholder": "Beschreibung eingeben",
|
||||
"hint": "Hinweis",
|
||||
"name": "Name des Wörterbuches",
|
||||
"name-hint": "Kann nach dem Speichern nicht mehr bearbeitet werden.",
|
||||
"name-placeholder": "Namen eingeben",
|
||||
"rank": "Rang",
|
||||
"rank-placeholder": "1000",
|
||||
"redaction": "Schwärzung",
|
||||
"technical-name": "Technischer Name"
|
||||
},
|
||||
"save": "Wörterbuch speichern",
|
||||
"success": {
|
||||
"create": "",
|
||||
"edit": ""
|
||||
},
|
||||
"title": "{type, select, edit{Wörterbuch {name} bearbeiten} create{Wörterbuch erstellen} other{}}"
|
||||
},
|
||||
"add-edit-dossier-attribute": {
|
||||
"error": {
|
||||
"generic": "Attribut konnte nicht gespeichert werden!"
|
||||
@ -106,6 +77,38 @@
|
||||
"save": "Dossier-Vorlage speichern",
|
||||
"title": "{type, select, edit{Dossier-Vorlage {name} bearbeiten} create{Dossier-Vorlage erstellen} other{}}"
|
||||
},
|
||||
"add-edit-entity": {
|
||||
"error": {
|
||||
"entity-already-exists": "",
|
||||
"generic": "",
|
||||
"invalid-color-or-rank": ""
|
||||
},
|
||||
"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": ""
|
||||
},
|
||||
"success": {
|
||||
"create": "",
|
||||
"edit": ""
|
||||
}
|
||||
},
|
||||
"add-edit-file-attribute": {
|
||||
"form": {
|
||||
"column-header": "CSV-Spaltenüberschrift",
|
||||
@ -158,9 +161,32 @@
|
||||
},
|
||||
"title": "{type, select, edit{Benutzer bearbeiten} create{Neuen Benutzer hinzufügen} other{}}"
|
||||
},
|
||||
"add-entity": {
|
||||
"save": "Wörterbuch speichern",
|
||||
"title": "Wörterbuch erstellen"
|
||||
},
|
||||
"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 +347,9 @@
|
||||
"suggestion-resize": "Vorgeschlagene Größenänderung",
|
||||
"text-highlight": ""
|
||||
},
|
||||
"annotation": {
|
||||
"pending": ""
|
||||
},
|
||||
"archived-dossiers-listing": {
|
||||
"no-data": {
|
||||
"title": ""
|
||||
@ -549,7 +578,6 @@
|
||||
}
|
||||
},
|
||||
"content": "Begründung",
|
||||
"default-colors": "Farbeinstellungen",
|
||||
"default-colors-screen": {
|
||||
"action": {
|
||||
"edit": "Farbe bearbeiten"
|
||||
@ -575,57 +603,14 @@
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"select-dossier": "Dossier auswählen",
|
||||
"select-dossier-template": "Dossiervorlage auswählen"
|
||||
},
|
||||
"dictionary-details": {
|
||||
"description": "Beschreibung"
|
||||
},
|
||||
"error": {
|
||||
"entries-too-short": "Einige Einträge im Wörterbuch unterschreiten die Mindestlänge von 2 Zeichen. Diese sind rot markiert.",
|
||||
"generic": "Es ist ein Fehler aufgetreten ... Das Wörterbuch konnte nicht aktualisiert werden!"
|
||||
@ -686,7 +671,6 @@
|
||||
"number": "Nummer",
|
||||
"text": "Text"
|
||||
},
|
||||
"dossier-attributes": "Dossier-Attribut",
|
||||
"dossier-attributes-listing": {
|
||||
"action": {
|
||||
"delete": "Attribut löschen",
|
||||
@ -880,7 +864,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 +893,11 @@
|
||||
"title": ""
|
||||
}
|
||||
},
|
||||
"dossier-template-info": "",
|
||||
"dossier-template-info-screen": {
|
||||
"created-by": "",
|
||||
"created-on": "",
|
||||
"description": "",
|
||||
"dictionaries": "",
|
||||
"entities": "",
|
||||
"entries": "",
|
||||
"modified-on": "",
|
||||
"valid-from": "",
|
||||
@ -930,7 +912,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!"
|
||||
@ -1026,6 +1008,7 @@
|
||||
"change-successful": "Dossier wurde aktualisiert.",
|
||||
"delete-successful": "Dossier wurde gelöscht.",
|
||||
"dictionary": {
|
||||
"add-to-dictionary-action": "",
|
||||
"display-name": {
|
||||
"cancel": "Abbrechen",
|
||||
"edit": "Anzeigenamen bearbeiten",
|
||||
@ -1072,6 +1055,42 @@
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"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": ""
|
||||
},
|
||||
"heading": ""
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"deleted-entity": {
|
||||
"dossier": {
|
||||
@ -1108,7 +1127,6 @@
|
||||
"number": "Nummer",
|
||||
"text": "Freier Text"
|
||||
},
|
||||
"file-attributes": "Datei-Attribute",
|
||||
"file-attributes-configurations": {
|
||||
"cancel": "",
|
||||
"form": {
|
||||
@ -1297,6 +1315,7 @@
|
||||
"approved": "Genehmigt",
|
||||
"deleted": "Gelöscht",
|
||||
"error": "Reanalyse erforderlich",
|
||||
"full-processing": "",
|
||||
"full-reprocess": "Wird analysiert",
|
||||
"image-analyzing": "Bildanalyse",
|
||||
"indexing": "Wird analysiert",
|
||||
@ -1417,7 +1436,6 @@
|
||||
"success": ""
|
||||
},
|
||||
"highlights": "",
|
||||
"hint": "Hinweis",
|
||||
"image-category": {
|
||||
"formula": "Formel",
|
||||
"image": "Bild",
|
||||
@ -1428,7 +1446,6 @@
|
||||
"unassigned": "Unbekannt",
|
||||
"you": "Sie"
|
||||
},
|
||||
"justifications": "Begründungen",
|
||||
"justifications-listing": {
|
||||
"actions": {
|
||||
"delete": "Begründung löschen",
|
||||
@ -1511,20 +1528,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 +1626,10 @@
|
||||
"processed": "",
|
||||
"processing": ""
|
||||
},
|
||||
"processing": {
|
||||
"basic": "",
|
||||
"ocr": ""
|
||||
},
|
||||
"readonly": "Lesemodus",
|
||||
"readonly-archived": "",
|
||||
"recategorize-image-dialog": {
|
||||
@ -1637,7 +1644,6 @@
|
||||
},
|
||||
"header": "Bildtypen bearbeiten"
|
||||
},
|
||||
"redaction": "Schwärzung",
|
||||
"references": "",
|
||||
"remove-annotations-dialog": {
|
||||
"cancel": "Abbrechen",
|
||||
@ -1657,7 +1663,6 @@
|
||||
"report-type": {
|
||||
"label": "{length} {length, plural, one{Berichtstyp} other{Berichtstypen}}"
|
||||
},
|
||||
"reports": "Berichte",
|
||||
"reports-screen": {
|
||||
"description": "",
|
||||
"descriptions": {
|
||||
@ -1733,7 +1738,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 +1919,6 @@
|
||||
"view-as": "Ansicht als:",
|
||||
"workflow": "Arbeitsablauf"
|
||||
},
|
||||
"watermark": "Wasserzeichen",
|
||||
"watermark-screen": {
|
||||
"action": {
|
||||
"change-success": "Das Wasserzeichen wurde aktualisiert!",
|
||||
@ -1926,6 +1929,7 @@
|
||||
},
|
||||
"form": {
|
||||
"color": "Farbe",
|
||||
"color-placeholder": "",
|
||||
"font-size": "Schriftgröße",
|
||||
"font-type": "Schriftart",
|
||||
"opacity": "Deckkraft",
|
||||
|
||||
@ -36,35 +36,6 @@
|
||||
},
|
||||
"header-new": "Create Dossier"
|
||||
},
|
||||
"add-edit-dictionary": {
|
||||
"error": {
|
||||
"dictionary-already-exists": "Dictionary with this name already exists!",
|
||||
"generic": "Failed to save dictionary!",
|
||||
"invalid-color-or-rank": "Invalid color or rank! Rank is already used by another dictionary or the color is not a valid hexColor!"
|
||||
},
|
||||
"form": {
|
||||
"add-to-dictionary-action": "Enable 'Add to dictionary'",
|
||||
"case-sensitive": "Case Sensitive",
|
||||
"color": "Hex Color",
|
||||
"color-placeholder": "#",
|
||||
"description": "Description",
|
||||
"description-placeholder": "Enter Description",
|
||||
"hint": "Hint",
|
||||
"name": "Display Name",
|
||||
"name-hint": "Cannot be edited after saving.",
|
||||
"name-placeholder": "Enter Name",
|
||||
"rank": "Rank",
|
||||
"rank-placeholder": "1000",
|
||||
"redaction": "Redaction",
|
||||
"technical-name": "Technical Name"
|
||||
},
|
||||
"save": "Save Dictionary",
|
||||
"success": {
|
||||
"create": "Dictionary added!",
|
||||
"edit": "Dictionary updated!"
|
||||
},
|
||||
"title": "{type, select, edit{Edit {name}} create{Create} other{}} Dictionary"
|
||||
},
|
||||
"add-edit-dossier-attribute": {
|
||||
"error": {
|
||||
"generic": "Failed to save attribute!"
|
||||
@ -106,6 +77,38 @@
|
||||
"save": "Save Dossier Template",
|
||||
"title": "{type, select, edit{Edit {name}} create{Create} other{}} Dossier Template"
|
||||
},
|
||||
"add-edit-entity": {
|
||||
"error": {
|
||||
"entity-already-exists": "Entity with this name already exists!",
|
||||
"generic": "Failed to save entity!",
|
||||
"invalid-color-or-rank": "Invalid color or rank! Rank is already used by another entity or the color is not a valid hexColor!"
|
||||
},
|
||||
"form": {
|
||||
"add-to-dictionary-action": "Enable 'Add to dictionary'",
|
||||
"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": "{type, select, edit{Autogenerated based on the initial display name.} create{Autogenerates based on the display name and cannot be edited after saving.} other{}}"
|
||||
},
|
||||
"success": {
|
||||
"create": "Entity added!",
|
||||
"edit": "Entity updated!"
|
||||
}
|
||||
},
|
||||
"add-edit-file-attribute": {
|
||||
"form": {
|
||||
"column-header": "CSV Column Header",
|
||||
@ -158,12 +161,32 @@
|
||||
},
|
||||
"title": "{type, select, edit{Edit} create{Add New} other{}} User"
|
||||
},
|
||||
"admin-side-nav": {
|
||||
"dossier-templates": "Dossier Templates",
|
||||
"settings": "Settings"
|
||||
"add-entity": {
|
||||
"save": "Save Entity",
|
||||
"title": "Create Entity"
|
||||
},
|
||||
"annotation": {
|
||||
"pending": "(Pending Analysis)"
|
||||
"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",
|
||||
"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 +347,9 @@
|
||||
"suggestion-resize": "Suggested Resize",
|
||||
"text-highlight": "Highlight"
|
||||
},
|
||||
"annotation": {
|
||||
"pending": "(Pending Analysis)"
|
||||
},
|
||||
"archived-dossiers-listing": {
|
||||
"no-data": {
|
||||
"title": "No archived dossiers."
|
||||
@ -552,7 +578,6 @@
|
||||
}
|
||||
},
|
||||
"content": "Reason",
|
||||
"default-colors": "Default Colors",
|
||||
"default-colors-screen": {
|
||||
"action": {
|
||||
"edit": "Edit Color"
|
||||
@ -578,57 +603,14 @@
|
||||
}
|
||||
},
|
||||
"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",
|
||||
"select-dossier": "Select Dossier",
|
||||
"select-dossier-template": "Select Dossier Template"
|
||||
},
|
||||
"dictionary-details": {
|
||||
"description": "Description"
|
||||
},
|
||||
"error": {
|
||||
"entries-too-short": "Some entries of the dictionary are below the minimum length of 2. These are highlighted with red!",
|
||||
"generic": "Something went wrong... Dictionary update failed!"
|
||||
@ -689,7 +671,6 @@
|
||||
"number": "Number",
|
||||
"text": "Free Text"
|
||||
},
|
||||
"dossier-attributes": "Dossier Attributes",
|
||||
"dossier-attributes-listing": {
|
||||
"action": {
|
||||
"delete": "Delete Attribute",
|
||||
@ -883,7 +864,6 @@
|
||||
"under-review": "Under Review",
|
||||
"upload-files": "Drag & drop files anywhere..."
|
||||
},
|
||||
"dossier-states": "Dossier States",
|
||||
"dossier-states-listing": {
|
||||
"action": {
|
||||
"delete": "Delete State",
|
||||
@ -913,12 +893,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 +912,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!"
|
||||
@ -1029,6 +1008,7 @@
|
||||
"change-successful": "Dossier {dossierName} was updated.",
|
||||
"delete-successful": "Dossier {dossierName} was deleted.",
|
||||
"dictionary": {
|
||||
"add-to-dictionary-action": "Available for add to dictionary",
|
||||
"display-name": {
|
||||
"cancel": "Cancel",
|
||||
"edit": "Edit Display Name",
|
||||
@ -1075,6 +1055,42 @@
|
||||
},
|
||||
"side-nav-title": "Configurations"
|
||||
},
|
||||
"entities-listing": {
|
||||
"action": {
|
||||
"delete": "Delete Entity",
|
||||
"edit": "Edit Entity"
|
||||
},
|
||||
"add-new": "New Entity",
|
||||
"bulk": {
|
||||
"delete": "Delete Selected Entities"
|
||||
},
|
||||
"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"
|
||||
},
|
||||
"heading": "Edit Entity"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"deleted-entity": {
|
||||
"dossier": {
|
||||
@ -1111,7 +1127,6 @@
|
||||
"number": "Number",
|
||||
"text": "Free Text"
|
||||
},
|
||||
"file-attributes": "File Attributes",
|
||||
"file-attributes-configurations": {
|
||||
"cancel": "Cancel",
|
||||
"form": {
|
||||
@ -1295,17 +1310,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...",
|
||||
@ -1425,7 +1436,6 @@
|
||||
"success": "{operation, select, CONVERT{Converting} REMOVE{Removing} other{}} highlights in progress..."
|
||||
},
|
||||
"highlights": "{color} - {length} {length, plural, one{highlight} other{highlights}}",
|
||||
"hint": "Hint",
|
||||
"image-category": {
|
||||
"formula": "Formula",
|
||||
"image": "Image",
|
||||
@ -1436,7 +1446,6 @@
|
||||
"unassigned": "Unassigned",
|
||||
"you": "You"
|
||||
},
|
||||
"justifications": "Justifications",
|
||||
"justifications-listing": {
|
||||
"actions": {
|
||||
"delete": "Delete Justification",
|
||||
@ -1519,20 +1528,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 +1626,10 @@
|
||||
"processed": "Processed",
|
||||
"processing": "Processing"
|
||||
},
|
||||
"processing": {
|
||||
"basic": "Processing",
|
||||
"ocr": "OCR"
|
||||
},
|
||||
"readonly": "Read only",
|
||||
"readonly-archived": "Read only (archived)",
|
||||
"recategorize-image-dialog": {
|
||||
@ -1645,7 +1644,6 @@
|
||||
},
|
||||
"header": "Edit Image Type"
|
||||
},
|
||||
"redaction": "Redaction",
|
||||
"references": "{count} {count, plural, one{reference} other{references}}",
|
||||
"remove-annotations-dialog": {
|
||||
"cancel": "Cancel",
|
||||
@ -1665,7 +1663,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 +1738,6 @@
|
||||
"red-user-admin": "Users Admin",
|
||||
"regular": "Regular"
|
||||
},
|
||||
"rule-editor": "Rule Editor",
|
||||
"rules-screen": {
|
||||
"error": {
|
||||
"generic": "Something went wrong... Rules update failed!"
|
||||
@ -1923,7 +1919,6 @@
|
||||
"view-as": "View as:",
|
||||
"workflow": "Workflow"
|
||||
},
|
||||
"watermark": "Watermark",
|
||||
"watermark-screen": {
|
||||
"action": {
|
||||
"change-success": "Watermark updated!",
|
||||
@ -1934,6 +1929,7 @@
|
||||
},
|
||||
"form": {
|
||||
"color": "Color",
|
||||
"color-placeholder": "#",
|
||||
"font-size": "Font Size",
|
||||
"font-type": "Font Type",
|
||||
"opacity": "Opacity",
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 08737703e46fd0a8366bdf0c4241772d7ac8e2bb
|
||||
Subproject commit 22434a2627d71f7cddc8bdd7d9adab9762c41e4c
|
||||
@ -1,32 +1,44 @@
|
||||
import { Entity, List } from '@iqser/common-ui';
|
||||
import { IDictionary } from './dictionary';
|
||||
import { DICTIONARY_TYPE_KEY_MAP, DictionaryType } from '../redaction-log';
|
||||
|
||||
export class Dictionary extends Entity<IDictionary> implements IDictionary {
|
||||
readonly addToDictionaryAction: boolean;
|
||||
readonly caseInsensitive: boolean;
|
||||
readonly description: string;
|
||||
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;
|
||||
readonly hasDictionary?: boolean;
|
||||
|
||||
constructor(dictionary: IDictionary, readonly virtual = false) {
|
||||
super(dictionary);
|
||||
this.addToDictionaryAction = !!dictionary.addToDictionaryAction;
|
||||
this.caseInsensitive = !!dictionary.caseInsensitive;
|
||||
this.description = dictionary.description ?? '';
|
||||
this.dossierTemplateId = dictionary.dossierTemplateId;
|
||||
this.entries = dictionary.entries ?? [];
|
||||
this.hexColor = dictionary.hexColor;
|
||||
this.hint = !!dictionary.hint;
|
||||
this.label = dictionary.label ?? dictionary.type;
|
||||
this.rank = dictionary.rank;
|
||||
this.recommendation = !!dictionary.recommendation;
|
||||
this.type = dictionary.type;
|
||||
entries: List;
|
||||
falsePositiveEntries: List;
|
||||
falseRecommendationEntries: List;
|
||||
|
||||
constructor(entity: IDictionary, readonly virtual = false) {
|
||||
super(entity);
|
||||
this.addToDictionaryAction = !!entity.addToDictionaryAction;
|
||||
this.caseInsensitive = !!entity.caseInsensitive;
|
||||
this.description = entity.description ?? '';
|
||||
this.dossierTemplateId = entity.dossierTemplateId;
|
||||
this.entries = entity.entries ?? [];
|
||||
this.falsePositiveEntries = entity.falsePositiveEntries ?? [];
|
||||
this.falseRecommendationEntries = entity.falseRecommendationEntries ?? [];
|
||||
this.hexColor = entity.hexColor;
|
||||
this.recommendationHexColor = entity.recommendationHexColor;
|
||||
this.hint = !!entity.hint;
|
||||
this.label = entity.label ?? entity.type;
|
||||
this.rank = entity.rank;
|
||||
this.recommendation = !!entity.recommendation;
|
||||
this.type = entity.type;
|
||||
this.typeId = entity.typeId;
|
||||
this.hasDictionary = entity.hasDictionary;
|
||||
}
|
||||
|
||||
get id(): string {
|
||||
@ -38,6 +50,14 @@ 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}`;
|
||||
}
|
||||
|
||||
setEntries(entries: List, type: DictionaryType): void {
|
||||
this[DICTIONARY_TYPE_KEY_MAP[type]] = entries;
|
||||
}
|
||||
|
||||
getEntries(type: DictionaryType): List {
|
||||
return this[DICTIONARY_TYPE_KEY_MAP[type]];
|
||||
}
|
||||
}
|
||||
|
||||
@ -24,10 +24,13 @@ export interface IDictionary {
|
||||
* The nonnull entry type.
|
||||
*/
|
||||
readonly type: string;
|
||||
readonly typeId?: string;
|
||||
/**
|
||||
* The list of dictionary entries of an entry type.
|
||||
*/
|
||||
readonly entries?: List;
|
||||
readonly falsePositiveEntries?: List;
|
||||
readonly falseRecommendationEntries?: List;
|
||||
/**
|
||||
* The value of color must be a correct hex color
|
||||
*/
|
||||
@ -48,4 +51,8 @@ export interface IDictionary {
|
||||
* True if the type just for recommendations, not for redaction, default is false.
|
||||
*/
|
||||
readonly recommendation?: boolean;
|
||||
|
||||
readonly recommendationHexColor?: string;
|
||||
|
||||
readonly hasDictionary?: boolean;
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -39,6 +39,7 @@ export const isProcessingStatuses: List<ProcessingFileStatus> = [
|
||||
ProcessingFileStatuses.INDEXING,
|
||||
ProcessingFileStatuses.PROCESSING,
|
||||
ProcessingFileStatuses.ANALYSE,
|
||||
ProcessingFileStatuses.FULL_PROCESSING,
|
||||
] as const;
|
||||
|
||||
export const isFullProcessingStatuses: List<ProcessingFileStatus> = [
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
import { IRectangle } from '../geometry';
|
||||
import { List } from '@iqser/common-ui';
|
||||
import { DictionaryEntryType } from './dictionary-entry-types';
|
||||
|
||||
export interface IAddRedactionRequest {
|
||||
addToDictionary?: boolean;
|
||||
addToDossierDictionary?: boolean;
|
||||
dictionaryEntryType?: DictionaryEntryType;
|
||||
comment?: { text: string };
|
||||
legalBasis?: string;
|
||||
positions?: List<IRectangle>;
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
export type DictionaryEntryType = 'ENTRY' | 'FALSE_POSITIVE' | 'FALSE_RECOMMENDATION';
|
||||
|
||||
export const DictionaryEntryTypes = {
|
||||
ENTRY: 'ENTRY' as DictionaryEntryType,
|
||||
FALSE_POSITIVE: 'FALSE_POSITIVE' as DictionaryEntryType,
|
||||
FALSE_RECOMMENDATION: 'FALSE_RECOMMENDATION' as DictionaryEntryType,
|
||||
};
|
||||
|
||||
export type DictionaryType = 'dictionary' | 'false-positive' | 'false-recommendations';
|
||||
|
||||
export const DICTIONARY_TYPE_KEY_MAP: { [key in DictionaryType]: 'entries' | 'falsePositiveEntries' | 'falseRecommendationEntries' } = {
|
||||
dictionary: 'entries',
|
||||
'false-positive': 'falsePositiveEntries',
|
||||
'false-recommendations': 'falseRecommendationEntries',
|
||||
};
|
||||
|
||||
export const DICTIONARY_TO_ENTRY_TYPE_MAP: { [key in DictionaryType]: DictionaryEntryType } = {
|
||||
dictionary: DictionaryEntryTypes.ENTRY,
|
||||
'false-positive': DictionaryEntryTypes.FALSE_POSITIVE,
|
||||
'false-recommendations': DictionaryEntryTypes.FALSE_RECOMMENDATION,
|
||||
};
|
||||
@ -11,3 +11,4 @@ export * from './approve-request';
|
||||
export * from './image-recategorization.request';
|
||||
export * from './resize.request';
|
||||
export * from './manual-change';
|
||||
export * from './dictionary-entry-types';
|
||||
|
||||
7
libs/red-domain/src/lib/shared/admin-side-nav-types.ts
Normal file
7
libs/red-domain/src/lib/shared/admin-side-nav-types.ts
Normal 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,
|
||||
};
|
||||
@ -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';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user