Compare commits
39 Commits
master
...
release/4.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79149ea45f | ||
|
|
06a5d2a844 | ||
|
|
db1a618061 | ||
|
|
1d68267288 | ||
|
|
73f6ad7321 | ||
|
|
1eb1512d67 | ||
|
|
ee0d544d94 | ||
|
|
843dcde601 | ||
|
|
8ba4721828 | ||
|
|
0bb0d2591f | ||
|
|
c70d8d75c0 | ||
|
|
23a0c0940d | ||
|
|
14e5c53272 | ||
|
|
9e797e6398 | ||
|
|
551445c522 | ||
|
|
53f64d0279 | ||
|
|
d073980d41 | ||
|
|
de31be252b | ||
|
|
f1f3bffcf1 | ||
|
|
0ad2966a5c | ||
|
|
5d97da46cb | ||
|
|
e8fe6f37de | ||
|
|
0d7c5efd7d | ||
|
|
6493422688 | ||
|
|
44dc6519d3 | ||
|
|
9c951712ae | ||
|
|
9bdacfcfdb | ||
|
|
643541d20c | ||
|
|
e7001e1e2b | ||
|
|
19c3154130 | ||
|
|
52dfb13a15 | ||
|
|
534f84bdba | ||
|
|
a7be372068 | ||
|
|
28cdf481ea | ||
|
|
64a446ebaf | ||
|
|
7afbc38e03 | ||
|
|
a881da891d | ||
|
|
9e6c466c4b | ||
|
|
db294fc909 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -48,3 +48,5 @@ migrations.json
|
|||||||
*.iml
|
*.iml
|
||||||
|
|
||||||
docker-compose.yml
|
docker-compose.yml
|
||||||
|
|
||||||
|
.nx/cache/
|
||||||
|
|||||||
@ -40,7 +40,7 @@
|
|||||||
{
|
{
|
||||||
"glob": "**/*",
|
"glob": "**/*",
|
||||||
"input": "node_modules/@pdftron/webviewer/public/",
|
"input": "node_modules/@pdftron/webviewer/public/",
|
||||||
"output": "/assets/wv-resources/"
|
"output": "/assets/wv-resources/10.9.0"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"glob": "**/*",
|
"glob": "**/*",
|
||||||
@ -67,7 +67,7 @@
|
|||||||
"vendorChunk": true,
|
"vendorChunk": true,
|
||||||
"extractLicenses": false,
|
"extractLicenses": false,
|
||||||
"buildOptimizer": false,
|
"buildOptimizer": false,
|
||||||
"sourceMap": true,
|
"sourceMap": false,
|
||||||
"optimization": false,
|
"optimization": false,
|
||||||
"namedChunks": true
|
"namedChunks": true
|
||||||
},
|
},
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import { ifNotLoggedIn } from '@guards/if-not-logged-in.guard';
|
|||||||
import { TrashGuard } from '@guards/trash.guard';
|
import { TrashGuard } from '@guards/trash.guard';
|
||||||
import { CompositeRouteGuard, DEFAULT_REDIRECT_KEY, IqserPermissionsGuard, IqserRoutes, orderedAsyncGuards } from '@iqser/common-ui';
|
import { CompositeRouteGuard, DEFAULT_REDIRECT_KEY, IqserPermissionsGuard, IqserRoutes, orderedAsyncGuards } from '@iqser/common-ui';
|
||||||
import { TenantSelectComponent } from '@iqser/common-ui/lib/tenants';
|
import { TenantSelectComponent } from '@iqser/common-ui/lib/tenants';
|
||||||
import { hasAnyRoleGuard, IqserAuthGuard } from '@iqser/common-ui/lib/users';
|
import { doesNotHaveAnyRole, hasAnyRole, IqserAuthGuard } from '@iqser/common-ui/lib/users';
|
||||||
import { CustomRouteReuseStrategy } from '@iqser/common-ui/lib/utils';
|
import { CustomRouteReuseStrategy } from '@iqser/common-ui/lib/utils';
|
||||||
import { ARCHIVE_ROUTE, BreadcrumbTypes, DOSSIER_ID, DOSSIER_TEMPLATE_ID, DOSSIERS_ARCHIVE, DOSSIERS_ROUTE, FILE_ID } from '@red/domain';
|
import { ARCHIVE_ROUTE, BreadcrumbTypes, DOSSIER_ID, DOSSIER_TEMPLATE_ID, DOSSIERS_ARCHIVE, DOSSIERS_ROUTE, FILE_ID } from '@red/domain';
|
||||||
import { RedRoleGuard } from '@users/red-role.guard';
|
import { RedRoleGuard } from '@users/red-role.guard';
|
||||||
@ -211,14 +211,14 @@ const routes: IqserRoutes = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ':tenant/main',
|
path: ':tenant/main',
|
||||||
canActivate: [orderedAsyncGuards([ifLoggedIn(), mainGuard()])],
|
canActivate: [orderedAsyncGuards([ifLoggedIn(), hasAnyRole(), mainGuard()])],
|
||||||
component: BaseScreenComponent,
|
component: BaseScreenComponent,
|
||||||
children: mainRoutes,
|
children: mainRoutes,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: ':tenant/auth-error',
|
path: ':tenant/auth-error',
|
||||||
component: AuthErrorComponent,
|
component: AuthErrorComponent,
|
||||||
canActivate: [hasAnyRoleGuard()],
|
canActivate: [doesNotHaveAnyRole()],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: '**',
|
path: '**',
|
||||||
|
|||||||
@ -1,16 +1,19 @@
|
|||||||
import { Injectable, Injector, ProviderToken } from '@angular/core';
|
import { Injectable, Injector, ProviderToken } from '@angular/core';
|
||||||
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
|
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
|
||||||
import { FilesMapService } from '@services/files/files-map.service';
|
import { getConfig } from '@iqser/common-ui';
|
||||||
import { FilesService } from '@services/files/files.service';
|
import { TenantsService } from '@iqser/common-ui/lib/tenants';
|
||||||
import { firstValueFrom } from 'rxjs';
|
|
||||||
import { DOSSIER_ID, DOSSIER_TEMPLATE_ID } from '@red/domain';
|
import { DOSSIER_ID, DOSSIER_TEMPLATE_ID } from '@red/domain';
|
||||||
import { DossiersService } from '@services/dossiers/dossiers.service';
|
import { DossiersService } from '@services/dossiers/dossiers.service';
|
||||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||||
import { DossierDictionariesMapService } from '@services/entity-services/dossier-dictionaries-map.service';
|
import { DossierDictionariesMapService } from '@services/entity-services/dossier-dictionaries-map.service';
|
||||||
import { TenantsService } from '@iqser/common-ui/lib/tenants';
|
import { FilesMapService } from '@services/files/files-map.service';
|
||||||
|
import { FilesService } from '@services/files/files.service';
|
||||||
|
import { firstValueFrom } from 'rxjs';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class DossierFilesGuard implements CanActivate {
|
export class DossierFilesGuard implements CanActivate {
|
||||||
|
readonly isDocumine = getConfig().IS_DOCUMINE;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _injector: Injector,
|
private readonly _injector: Injector,
|
||||||
private readonly _tenantsService: TenantsService,
|
private readonly _tenantsService: TenantsService,
|
||||||
@ -45,7 +48,7 @@ export class DossierFilesGuard implements CanActivate {
|
|||||||
async loadDossierData(dossierId: string, dossierTemplateId: string) {
|
async loadDossierData(dossierId: string, dossierTemplateId: string) {
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
|
||||||
if (!this._dictionaryMapService.has(dossierId)) {
|
if (!this._dictionaryMapService.has(dossierId) && !this.isDocumine) {
|
||||||
const dictionaryPromise = this._dictionaryService.loadDossierDictionary(dossierTemplateId, dossierId);
|
const dictionaryPromise = this._dictionaryService.loadDossierDictionary(dossierTemplateId, dossierId);
|
||||||
promises.push(dictionaryPromise);
|
promises.push(dictionaryPromise);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,11 +37,12 @@ export const canRecategorizeAnnotation = (annotation: AnnotationWrapper, canReca
|
|||||||
((annotation.isImage && !annotation.isSuggestion) || annotation.isSuggestionRecategorizeImage || annotation.hintDictionary) &&
|
((annotation.isImage && !annotation.isSuggestion) || annotation.isSuggestionRecategorizeImage || annotation.hintDictionary) &&
|
||||||
!annotation.pending;
|
!annotation.pending;
|
||||||
|
|
||||||
export const canResizeAnnotation = (annotation: AnnotationWrapper, canAddRedaction: boolean) =>
|
export const canResizeAnnotation = (annotation: AnnotationWrapper, canAddRedaction: boolean, hasDictionary = false) =>
|
||||||
canAddRedaction &&
|
canAddRedaction &&
|
||||||
!annotation.isSkipped &&
|
!annotation.isSkipped &&
|
||||||
!annotation.pending &&
|
!annotation.pending &&
|
||||||
(((annotation.isRedacted || annotation.isImage) && !annotation.isSuggestion) ||
|
(((annotation.isRedacted || annotation.isImage) && !annotation.isSuggestion) ||
|
||||||
annotation.isSuggestionResize ||
|
annotation.isSuggestionResize ||
|
||||||
annotation.isDictBasedHint ||
|
annotation.isDictBasedHint ||
|
||||||
annotation.isRecommendation);
|
annotation.isRecommendation ||
|
||||||
|
(hasDictionary && annotation.isRuleBased));
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import { IqserPermissionsService } from '@iqser/common-ui';
|
|||||||
import { Dictionary } from '@red/domain';
|
import { Dictionary } from '@red/domain';
|
||||||
import { Roles } from '@users/roles';
|
import { Roles } from '@users/roles';
|
||||||
import { isArray } from 'lodash-es';
|
import { isArray } from 'lodash-es';
|
||||||
|
import { IMAGE_CATEGORIES } from '../../modules/file-preview/utils/constants';
|
||||||
import {
|
import {
|
||||||
canAcceptRecommendation,
|
canAcceptRecommendation,
|
||||||
canChangeLegalBasis,
|
canChangeLegalBasis,
|
||||||
@ -16,7 +17,6 @@ import {
|
|||||||
canUndo,
|
canUndo,
|
||||||
} from './annotation-permissions.utils';
|
} from './annotation-permissions.utils';
|
||||||
import { AnnotationWrapper } from './annotation.wrapper';
|
import { AnnotationWrapper } from './annotation.wrapper';
|
||||||
import { IMAGE_CATEGORIES } from '../../modules/file-preview/utils/constants';
|
|
||||||
|
|
||||||
export class AnnotationPermissions {
|
export class AnnotationPermissions {
|
||||||
canUndo = true;
|
canUndo = true;
|
||||||
@ -60,7 +60,7 @@ export class AnnotationPermissions {
|
|||||||
permissions.canRemoveRedaction = canRemoveRedaction(annotation, permissions);
|
permissions.canRemoveRedaction = canRemoveRedaction(annotation, permissions);
|
||||||
permissions.canChangeLegalBasis = canChangeLegalBasis(annotation, canAddRedaction);
|
permissions.canChangeLegalBasis = canChangeLegalBasis(annotation, canAddRedaction);
|
||||||
permissions.canRecategorizeAnnotation = canRecategorizeAnnotation(annotation, canAddRedaction);
|
permissions.canRecategorizeAnnotation = canRecategorizeAnnotation(annotation, canAddRedaction);
|
||||||
permissions.canResizeAnnotation = canResizeAnnotation(annotation, canAddRedaction);
|
permissions.canResizeAnnotation = canResizeAnnotation(annotation, canAddRedaction, annotationEntity.hasDictionary);
|
||||||
|
|
||||||
permissions.canEditAnnotations = (annotation.isSkipped || annotation.isRedacted) && !annotation.isImage;
|
permissions.canEditAnnotations = (annotation.isSkipped || annotation.isRedacted) && !annotation.isImage;
|
||||||
permissions.canEditHints =
|
permissions.canEditHints =
|
||||||
|
|||||||
@ -10,7 +10,6 @@ import {
|
|||||||
Dictionary,
|
Dictionary,
|
||||||
Earmark,
|
Earmark,
|
||||||
FalsePositiveSuperTypes,
|
FalsePositiveSuperTypes,
|
||||||
IComment,
|
|
||||||
ILegalBasis,
|
ILegalBasis,
|
||||||
IManualChange,
|
IManualChange,
|
||||||
IPoint,
|
IPoint,
|
||||||
@ -38,7 +37,7 @@ export class AnnotationWrapper implements IListable {
|
|||||||
recategorizationType: string;
|
recategorizationType: string;
|
||||||
color: string;
|
color: string;
|
||||||
entity: Dictionary;
|
entity: Dictionary;
|
||||||
comments: IComment[] = [];
|
numberOfComments = 0;
|
||||||
firstTopLeftPoint: IPoint;
|
firstTopLeftPoint: IPoint;
|
||||||
id: string;
|
id: string;
|
||||||
shortContent: string;
|
shortContent: string;
|
||||||
@ -197,6 +196,10 @@ export class AnnotationWrapper implements IListable {
|
|||||||
return !!SuggestionsSuperTypes[this.superType];
|
return !!SuggestionsSuperTypes[this.superType];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get isRuleBased() {
|
||||||
|
return this.engines.includes(LogEntryEngines.RULE);
|
||||||
|
}
|
||||||
|
|
||||||
get isSuggestionResize() {
|
get isSuggestionResize() {
|
||||||
return this.superType === SuperTypes.SuggestionResize;
|
return this.superType === SuperTypes.SuggestionResize;
|
||||||
}
|
}
|
||||||
@ -323,7 +326,6 @@ export class AnnotationWrapper implements IListable {
|
|||||||
annotationWrapper.image = redactionLogEntry.image;
|
annotationWrapper.image = redactionLogEntry.image;
|
||||||
annotationWrapper.imported = redactionLogEntry.imported;
|
annotationWrapper.imported = redactionLogEntry.imported;
|
||||||
annotationWrapper.legalBasisValue = redactionLogEntry.legalBasis;
|
annotationWrapper.legalBasisValue = redactionLogEntry.legalBasis;
|
||||||
annotationWrapper.comments = redactionLogEntry.comments || [];
|
|
||||||
annotationWrapper.manual = redactionLogEntry.manualChanges?.length > 0;
|
annotationWrapper.manual = redactionLogEntry.manualChanges?.length > 0;
|
||||||
annotationWrapper.engines = redactionLogEntry.engines;
|
annotationWrapper.engines = redactionLogEntry.engines;
|
||||||
annotationWrapper.section = redactionLogEntry.section;
|
annotationWrapper.section = redactionLogEntry.section;
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
<iqser-page-header
|
<iqser-page-header
|
||||||
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
|
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
|
||||||
[buttonConfigs]="buttonConfigs"
|
|
||||||
[pageLabel]="'license-information' | translate"
|
[pageLabel]="'license-information' | translate"
|
||||||
[showCloseButton]="currentUser.isUser && permissionsService.has$(roles.dossiers.read) | async"
|
[showCloseButton]="currentUser.isUser && permissionsService.has$(roles.dossiers.read) | async"
|
||||||
></iqser-page-header>
|
></iqser-page-header>
|
||||||
|
|||||||
@ -1,9 +1,6 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
import { getConfig, IqserPermissionsService } from '@iqser/common-ui';
|
||||||
import { List } from '@common-ui/utils';
|
|
||||||
import { ButtonConfig, getConfig, IconButtonTypes, IqserPermissionsService } from '@iqser/common-ui';
|
|
||||||
import { getCurrentUser } from '@iqser/common-ui/lib/users';
|
import { getCurrentUser } from '@iqser/common-ui/lib/users';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
|
||||||
import type { AppConfig, User } from '@red/domain';
|
import type { AppConfig, User } from '@red/domain';
|
||||||
import { LicenseService } from '@services/license.service';
|
import { LicenseService } from '@services/license.service';
|
||||||
import { RouterHistoryService } from '@services/router-history.service';
|
import { RouterHistoryService } from '@services/router-history.service';
|
||||||
@ -18,38 +15,10 @@ export class LicenseScreenComponent {
|
|||||||
protected readonly roles = Roles;
|
protected readonly roles = Roles;
|
||||||
protected readonly currentUser = getCurrentUser<User>();
|
protected readonly currentUser = getCurrentUser<User>();
|
||||||
protected readonly currentYear = new Date().getFullYear();
|
protected readonly currentYear = new Date().getFullYear();
|
||||||
protected readonly buttonConfigs: List<ButtonConfig> = [
|
|
||||||
{
|
|
||||||
label: _('license-info-screen.email-report'),
|
|
||||||
action: (): void => this.sendMail(),
|
|
||||||
type: IconButtonTypes.primary,
|
|
||||||
helpModeKey: 'license_information',
|
|
||||||
hide: !this.permissionsService.has(Roles.license.readReport),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly licenseService: LicenseService,
|
readonly licenseService: LicenseService,
|
||||||
readonly permissionsService: IqserPermissionsService,
|
readonly permissionsService: IqserPermissionsService,
|
||||||
readonly routerHistoryService: RouterHistoryService,
|
readonly routerHistoryService: RouterHistoryService,
|
||||||
private readonly _translateService: TranslateService,
|
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
sendMail(): void {
|
|
||||||
const licenseCustomer = this.licenseService.selectedLicense.licensedTo;
|
|
||||||
const subject = this._translateService.instant('license-info-screen.email.title', {
|
|
||||||
licenseCustomer,
|
|
||||||
}) as string;
|
|
||||||
const lineBreak = '%0D%0A';
|
|
||||||
const body = [
|
|
||||||
this._translateService.instant('license-info-screen.email.body.analyzed', {
|
|
||||||
pages: this.licenseService.selectedLicenseReport.numberOfAnalyzedPages,
|
|
||||||
}),
|
|
||||||
this._translateService.instant('license-info-screen.email.body.licensed', {
|
|
||||||
pages: this.licenseService.totalLicensedNumberOfPages,
|
|
||||||
}),
|
|
||||||
].join(lineBreak);
|
|
||||||
const mail = this.licenseService.selectedLicense.licensedToEmail;
|
|
||||||
window.location.href = `mailto:${mail}?subject=${subject}&body=${body}`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,14 @@
|
|||||||
import { ChangeDetectorRef, Component, ElementRef, inject, OnInit, ViewChild } from '@angular/core';
|
|
||||||
import WebViewer, { WebViewerInstance } from '@pdftron/webviewer';
|
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { ChangeDetectorRef, Component, ElementRef, inject, OnInit, ViewChild } from '@angular/core';
|
||||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||||
|
import { environment } from '@environments/environment';
|
||||||
import { getConfig, IconButtonTypes, IqserPermissionsService, LoadingService, Toaster } from '@iqser/common-ui';
|
import { getConfig, IconButtonTypes, IqserPermissionsService, LoadingService, Toaster } from '@iqser/common-ui';
|
||||||
|
import { TenantsService } from '@iqser/common-ui/lib/tenants';
|
||||||
|
import { getCurrentUser } from '@iqser/common-ui/lib/users';
|
||||||
|
import { AsControl, BASE_HREF_FN, Debounce, getParam, trackByFactory } from '@iqser/common-ui/lib/utils';
|
||||||
|
import WebViewer, { WebViewerInstance } from '@pdftron/webviewer';
|
||||||
import {
|
import {
|
||||||
AppConfig,
|
AppConfig,
|
||||||
DOSSIER_TEMPLATE_ID,
|
DOSSIER_TEMPLATE_ID,
|
||||||
@ -17,21 +23,15 @@ import {
|
|||||||
WatermarkOrientations,
|
WatermarkOrientations,
|
||||||
WatermarkVerticalAlignment,
|
WatermarkVerticalAlignment,
|
||||||
} from '@red/domain';
|
} from '@red/domain';
|
||||||
import { stampPDFPage } from '@utils/page-stamper';
|
|
||||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
|
||||||
import { WatermarkService } from '@services/entity-services/watermark.service';
|
import { WatermarkService } from '@services/entity-services/watermark.service';
|
||||||
import { BehaviorSubject, firstValueFrom, Observable, of } from 'rxjs';
|
|
||||||
import { LicenseService } from '@services/license.service';
|
|
||||||
import { UserPreferenceService } from '@users/user-preference.service';
|
|
||||||
import { Router } from '@angular/router';
|
|
||||||
import { WatermarksMapService } from '@services/entity-services/watermarks-map.service';
|
import { WatermarksMapService } from '@services/entity-services/watermarks-map.service';
|
||||||
import { Roles } from '@users/roles';
|
import { LicenseService } from '@services/license.service';
|
||||||
import { environment } from '@environments/environment';
|
|
||||||
import { tap } from 'rxjs/operators';
|
|
||||||
import { watermarkTranslations } from '@translations/watermark-translations';
|
import { watermarkTranslations } from '@translations/watermark-translations';
|
||||||
import { getCurrentUser } from '@iqser/common-ui/lib/users';
|
import { Roles } from '@users/roles';
|
||||||
import { AsControl, BASE_HREF_FN, Debounce, getParam, trackByFactory } from '@iqser/common-ui/lib/utils';
|
import { UserPreferenceService } from '@users/user-preference.service';
|
||||||
import { TenantsService } from '@iqser/common-ui/lib/tenants';
|
import { stampPDFPage } from '@utils/page-stamper';
|
||||||
|
import { BehaviorSubject, firstValueFrom, Observable, of } from 'rxjs';
|
||||||
|
import { tap } from 'rxjs/operators';
|
||||||
|
|
||||||
export const DEFAULT_WATERMARK: Partial<IWatermark> = {
|
export const DEFAULT_WATERMARK: Partial<IWatermark> = {
|
||||||
text: 'Watermark',
|
text: 'Watermark',
|
||||||
@ -222,7 +222,7 @@ export class WatermarkScreenComponent implements OnInit {
|
|||||||
this.instance = await WebViewer(
|
this.instance = await WebViewer(
|
||||||
{
|
{
|
||||||
licenseKey: this._licenseService.activeLicenseKey,
|
licenseKey: this._licenseService.activeLicenseKey,
|
||||||
path: this._convertPath('/assets/wv-resources'),
|
path: this._convertPath('/assets/wv-resources/10.9.0'),
|
||||||
css: this._convertPath('/assets/pdftron/stylesheet.css'),
|
css: this._convertPath('/assets/pdftron/stylesheet.css'),
|
||||||
fullAPI: true,
|
fullAPI: true,
|
||||||
isReadOnly: true,
|
isReadOnly: true,
|
||||||
|
|||||||
@ -132,7 +132,9 @@ export class DossierOverviewBulkActionsComponent implements OnChanges {
|
|||||||
action: () => this._bulkActionsService.reanalyse(this.selectedFiles),
|
action: () => this._bulkActionsService.reanalyse(this.selectedFiles),
|
||||||
tooltip: _('dossier-overview.bulk.reanalyse'),
|
tooltip: _('dossier-overview.bulk.reanalyse'),
|
||||||
icon: 'iqser:refresh',
|
icon: 'iqser:refresh',
|
||||||
show: this.#canReanalyse && (this.#analysisForced || this.#canEnableAutoAnalysis),
|
show:
|
||||||
|
this.#canReanalyse &&
|
||||||
|
(this.#analysisForced || this.#canEnableAutoAnalysis || this.selectedFiles.every(file => file.isError)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'stop-automatic-analysis-btn',
|
id: 'stop-automatic-analysis-btn',
|
||||||
|
|||||||
@ -6,10 +6,23 @@
|
|||||||
[viewModeSelection]="viewModeSelection"
|
[viewModeSelection]="viewModeSelection"
|
||||||
>
|
>
|
||||||
<ng-container slot="right">
|
<ng-container slot="right">
|
||||||
|
<iqser-circle-button
|
||||||
|
*allow="roles.getRss"
|
||||||
|
[attr.help-mode-key]="'component_download'"
|
||||||
|
[icon]="'red:extract'"
|
||||||
|
[tooltip]="
|
||||||
|
((downloadComponentLogsDisabled$ | async) ? 'component-download.disabled-tooltip' : 'component-download.tooltip')
|
||||||
|
| translate
|
||||||
|
"
|
||||||
|
[matMenuTriggerFor]="bulkComponentDownloadMenu"
|
||||||
|
[disabled]="downloadComponentLogsDisabled$ | async"
|
||||||
|
[dropdownButton]="true"
|
||||||
|
></iqser-circle-button>
|
||||||
|
|
||||||
<redaction-file-download-btn
|
<redaction-file-download-btn
|
||||||
[attr.help-mode-key]="'download_dossier_in_dossier'"
|
[attr.help-mode-key]="'download_dossier_in_dossier'"
|
||||||
[buttonId]="'download-files-btn'"
|
[buttonId]="'download-files-btn'"
|
||||||
[disabled]="downloadBtnDisabled$ | async"
|
[disabled]="downloadFilesDisabled$ | async"
|
||||||
[dossier]="dossier"
|
[dossier]="dossier"
|
||||||
[files]="entitiesService.all$ | async"
|
[files]="entitiesService.all$ | async"
|
||||||
></redaction-file-download-btn>
|
></redaction-file-download-btn>
|
||||||
@ -49,3 +62,8 @@
|
|||||||
<ng-template #viewModeSelection>
|
<ng-template #viewModeSelection>
|
||||||
<redaction-view-mode-selection iqserDisableStopPropagation></redaction-view-mode-selection>
|
<redaction-view-mode-selection iqserDisableStopPropagation></redaction-view-mode-selection>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
|
|
||||||
|
<mat-menu #bulkComponentDownloadMenu="matMenu">
|
||||||
|
<button [innerHTML]="'component-download.json' | translate" (click)="downloadComponentAsJSON()" mat-menu-item></button>
|
||||||
|
<button [innerHTML]="'component-download.xml' | translate" (click)="downloadComponentAsXML()" mat-menu-item></button>
|
||||||
|
</mat-menu>
|
||||||
|
|||||||
@ -14,6 +14,7 @@ import { Roles } from '@users/roles';
|
|||||||
import { SortingService } from '@iqser/common-ui/lib/sorting';
|
import { SortingService } from '@iqser/common-ui/lib/sorting';
|
||||||
import { List, some } from '@iqser/common-ui/lib/utils';
|
import { List, some } from '@iqser/common-ui/lib/utils';
|
||||||
import { TenantsService } from '@iqser/common-ui/lib/tenants';
|
import { TenantsService } from '@iqser/common-ui/lib/tenants';
|
||||||
|
import { ComponentLogService } from '@services/files/component-log.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-dossier-overview-screen-header [dossier] [upload]',
|
selector: 'redaction-dossier-overview-screen-header [dossier] [upload]',
|
||||||
@ -25,7 +26,8 @@ export class DossierOverviewScreenHeaderComponent implements OnInit {
|
|||||||
readonly circleButtonTypes = CircleButtonTypes;
|
readonly circleButtonTypes = CircleButtonTypes;
|
||||||
readonly roles = Roles;
|
readonly roles = Roles;
|
||||||
actionConfigs: List<ActionConfig>;
|
actionConfigs: List<ActionConfig>;
|
||||||
readonly downloadBtnDisabled$: Observable<boolean>;
|
readonly downloadFilesDisabled$: Observable<boolean>;
|
||||||
|
readonly downloadComponentLogsDisabled$: Observable<boolean>;
|
||||||
readonly isDocumine = getConfig().IS_DOCUMINE;
|
readonly isDocumine = getConfig().IS_DOCUMINE;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -41,11 +43,15 @@ export class DossierOverviewScreenHeaderComponent implements OnInit {
|
|||||||
private readonly _reanalysisService: ReanalysisService,
|
private readonly _reanalysisService: ReanalysisService,
|
||||||
private readonly _loadingService: LoadingService,
|
private readonly _loadingService: LoadingService,
|
||||||
private readonly _primaryFileAttributeService: PrimaryFileAttributeService,
|
private readonly _primaryFileAttributeService: PrimaryFileAttributeService,
|
||||||
|
private readonly _componentLogService: ComponentLogService,
|
||||||
) {
|
) {
|
||||||
const someNotProcessed$ = this.entitiesService.all$.pipe(some(file => !file.lastProcessed));
|
const someNotProcessed$ = this.entitiesService.all$.pipe(some(file => !file.lastProcessed));
|
||||||
this.downloadBtnDisabled$ = combineLatest([this.listingService.areSomeSelected$, someNotProcessed$]).pipe(
|
this.downloadFilesDisabled$ = combineLatest([this.listingService.areSomeSelected$, someNotProcessed$]).pipe(
|
||||||
map(([someSelected, someNotProcessed]) => someSelected || someNotProcessed),
|
map(([someSelected, someNotProcessed]) => someSelected || someNotProcessed),
|
||||||
);
|
);
|
||||||
|
this.downloadComponentLogsDisabled$ = combineLatest([this.entitiesService.allLength$, someNotProcessed$]).pipe(
|
||||||
|
map(([length, someNotProcessed]) => !length || someNotProcessed),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
@ -92,4 +98,12 @@ export class DossierOverviewScreenHeaderComponent implements OnInit {
|
|||||||
];
|
];
|
||||||
saveAsCSV(fileName, entities, fileFields, mapper);
|
saveAsCSV(fileName, entities, fileFields, mapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
downloadComponentAsJSON() {
|
||||||
|
return firstValueFrom(this._componentLogService.exportJSON(this.dossier.dossierTemplateId, this.dossier.dossierId));
|
||||||
|
}
|
||||||
|
|
||||||
|
async downloadComponentAsXML() {
|
||||||
|
return firstValueFrom(this._componentLogService.exportXML(this.dossier.dossierTemplateId, this.dossier.dossierId));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,7 +27,8 @@
|
|||||||
<ng-container *ngIf="!resizing">
|
<ng-container *ngIf="!resizing">
|
||||||
<iqser-circle-button
|
<iqser-circle-button
|
||||||
(action)="resize()"
|
(action)="resize()"
|
||||||
*ngIf="annotationPermissions.canResizeAnnotation && annotations.length === 1"
|
*ngIf="canResize"
|
||||||
|
[attr.help-mode-key]="helpModeKey('resize')"
|
||||||
[tooltipPosition]="tooltipPosition"
|
[tooltipPosition]="tooltipPosition"
|
||||||
[tooltip]="'annotation-actions.resize.label' | translate"
|
[tooltip]="'annotation-actions.resize.label' | translate"
|
||||||
[type]="buttonType"
|
[type]="buttonType"
|
||||||
@ -47,7 +48,7 @@
|
|||||||
|
|
||||||
<iqser-circle-button
|
<iqser-circle-button
|
||||||
(action)="acceptRecommendation()"
|
(action)="acceptRecommendation()"
|
||||||
*ngIf="annotationPermissions.canAcceptRecommendation"
|
*ngIf="canAcceptRecommendation"
|
||||||
[tooltipPosition]="tooltipPosition"
|
[tooltipPosition]="tooltipPosition"
|
||||||
[tooltip]="'annotation-actions.accept-recommendation.label' | translate"
|
[tooltip]="'annotation-actions.accept-recommendation.label' | translate"
|
||||||
[type]="buttonType"
|
[type]="buttonType"
|
||||||
@ -101,7 +102,7 @@
|
|||||||
|
|
||||||
<iqser-circle-button
|
<iqser-circle-button
|
||||||
(action)="annotationActionsService.forceAnnotation(annotations)"
|
(action)="annotationActionsService.forceAnnotation(annotations)"
|
||||||
*ngIf="annotationPermissions.canForceRedaction"
|
*ngIf="canForceRedaction"
|
||||||
[tooltipPosition]="tooltipPosition"
|
[tooltipPosition]="tooltipPosition"
|
||||||
[tooltip]="'annotation-actions.force-redaction.label' | translate"
|
[tooltip]="'annotation-actions.force-redaction.label' | translate"
|
||||||
[type]="buttonType"
|
[type]="buttonType"
|
||||||
@ -110,7 +111,7 @@
|
|||||||
|
|
||||||
<iqser-circle-button
|
<iqser-circle-button
|
||||||
(action)="annotationActionsService.forceAnnotation(annotations, true)"
|
(action)="annotationActionsService.forceAnnotation(annotations, true)"
|
||||||
*ngIf="annotationPermissions.canForceHint"
|
*ngIf="canForceHint"
|
||||||
[tooltipPosition]="tooltipPosition"
|
[tooltipPosition]="tooltipPosition"
|
||||||
[tooltip]="'annotation-actions.force-hint.label' | translate"
|
[tooltip]="'annotation-actions.force-hint.label' | translate"
|
||||||
[type]="buttonType"
|
[type]="buttonType"
|
||||||
|
|||||||
@ -61,17 +61,36 @@ export class AnnotationActionsComponent implements OnChanges {
|
|||||||
this.annotationPermissions.canRecategorizeAnnotation ||
|
this.annotationPermissions.canRecategorizeAnnotation ||
|
||||||
this.annotationPermissions.canForceHint ||
|
this.annotationPermissions.canForceHint ||
|
||||||
this.annotationPermissions.canForceRedaction;
|
this.annotationPermissions.canForceRedaction;
|
||||||
return this.annotations.length > 1
|
return (
|
||||||
? this.#isDocumine
|
this.#annotationChangesAllowed &&
|
||||||
? this.annotationPermissions.canEditAnnotations
|
(this.annotations.length > 1
|
||||||
: this.annotationPermissions.canEditHints ||
|
? this.#isDocumine
|
||||||
this.annotationPermissions.canEditImages ||
|
? this.annotationPermissions.canEditAnnotations
|
||||||
this.annotationPermissions.canEditAnnotations
|
: this.annotationPermissions.canEditHints ||
|
||||||
: canEditRedactions;
|
this.annotationPermissions.canEditImages ||
|
||||||
|
this.annotationPermissions.canEditAnnotations
|
||||||
|
: canEditRedactions)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
get canResize(): boolean {
|
||||||
|
return this.#annotationChangesAllowed && this.annotationPermissions.canResizeAnnotation && this.annotations.length === 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
get canRemoveRedaction(): boolean {
|
get canRemoveRedaction(): boolean {
|
||||||
return this.annotationPermissions.canRemoveRedaction && this.#sameType;
|
return this.#annotationChangesAllowed && this.annotationPermissions.canRemoveRedaction && this.#sameType;
|
||||||
|
}
|
||||||
|
|
||||||
|
get canForceRedaction() {
|
||||||
|
return this.#annotationChangesAllowed && this.annotationPermissions.canForceRedaction;
|
||||||
|
}
|
||||||
|
|
||||||
|
get canForceHint() {
|
||||||
|
return this.#annotationChangesAllowed && this.annotationPermissions.canForceHint;
|
||||||
|
}
|
||||||
|
|
||||||
|
get canAcceptRecommendation() {
|
||||||
|
return this.#annotationChangesAllowed && this.annotationPermissions.canAcceptRecommendation;
|
||||||
}
|
}
|
||||||
|
|
||||||
get viewerAnnotations() {
|
get viewerAnnotations() {
|
||||||
@ -148,4 +167,8 @@ export class AnnotationActionsComponent implements OnChanges {
|
|||||||
this._iqserPermissionsService,
|
this._iqserPermissionsService,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get #annotationChangesAllowed() {
|
||||||
|
return !this.#isDocumine || !this._state.file().excludedFromAutomaticAnalysis;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,14 +10,14 @@
|
|||||||
|
|
||||||
<div *ngIf="!annotation.item.isEarmark" class="actions-wrapper">
|
<div *ngIf="!annotation.item.isEarmark" class="actions-wrapper">
|
||||||
<div
|
<div
|
||||||
(click)="comments.toggleExpandComments()"
|
(click)="showComments = !showComments"
|
||||||
[matTooltip]="'comments.comments' | translate : { count: annotation.item.comments?.length }"
|
[matTooltip]="'comments.comments' | translate: { count: annotation.item.numberOfComments }"
|
||||||
class="comments-counter"
|
class="comments-counter"
|
||||||
iqserStopPropagation
|
iqserStopPropagation
|
||||||
matTooltipPosition="above"
|
matTooltipPosition="above"
|
||||||
>
|
>
|
||||||
<mat-icon svgIcon="red:comment"></mat-icon>
|
<mat-icon svgIcon="red:comment"></mat-icon>
|
||||||
{{ annotation.item.comments.length }}
|
{{ annotation.item.numberOfComments }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="_multiSelectService.inactive()" class="actions">
|
<div *ngIf="_multiSelectService.inactive()" class="actions">
|
||||||
@ -29,7 +29,16 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<redaction-comments #comments [annotation]="annotation.item"></redaction-comments>
|
<ng-container *ngIf="showComments">
|
||||||
|
<redaction-comments [annotation]="annotation.item"></redaction-comments>
|
||||||
|
|
||||||
|
<div
|
||||||
|
(click)="showComments = false"
|
||||||
|
class="all-caps-label pointer hide-comments"
|
||||||
|
iqserStopPropagation
|
||||||
|
translate="comments.hide-comments"
|
||||||
|
></div>
|
||||||
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<redaction-annotation-details [annotation]="annotation"></redaction-annotation-details>
|
<redaction-annotation-details [annotation]="annotation"></redaction-annotation-details>
|
||||||
|
|||||||
@ -5,6 +5,8 @@ import { ListItem } from '@models/file/list-item';
|
|||||||
import { MultiSelectService } from '../../services/multi-select.service';
|
import { MultiSelectService } from '../../services/multi-select.service';
|
||||||
import { PdfProxyService } from '../../services/pdf-proxy.service';
|
import { PdfProxyService } from '../../services/pdf-proxy.service';
|
||||||
import { ActionsHelpModeKeys } from '../../utils/constants';
|
import { ActionsHelpModeKeys } from '../../utils/constants';
|
||||||
|
import { CommentsApiService } from '@services/comments-api.service';
|
||||||
|
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-annotation-wrapper',
|
selector: 'redaction-annotation-wrapper',
|
||||||
@ -13,15 +15,22 @@ import { ActionsHelpModeKeys } from '../../utils/constants';
|
|||||||
})
|
})
|
||||||
export class AnnotationWrapperComponent implements OnChanges {
|
export class AnnotationWrapperComponent implements OnChanges {
|
||||||
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
||||||
|
readonly #commentsApiService = inject(CommentsApiService);
|
||||||
protected readonly _pdfProxyService = inject(PdfProxyService);
|
protected readonly _pdfProxyService = inject(PdfProxyService);
|
||||||
protected readonly _multiSelectService = inject(MultiSelectService);
|
protected readonly _multiSelectService = inject(MultiSelectService);
|
||||||
|
readonly state = inject(FilePreviewStateService);
|
||||||
|
actionsHelpModeKey?: string;
|
||||||
|
showComments = false;
|
||||||
@Input({ required: true }) annotation!: ListItem<AnnotationWrapper>;
|
@Input({ required: true }) annotation!: ListItem<AnnotationWrapper>;
|
||||||
@HostBinding('attr.annotation-id') annotationId: string;
|
@HostBinding('attr.annotation-id') annotationId: string;
|
||||||
@HostBinding('class.active') active = false;
|
@HostBinding('class.active') active = false;
|
||||||
actionsHelpModeKey?: string;
|
|
||||||
|
|
||||||
ngOnChanges() {
|
ngOnChanges() {
|
||||||
this.annotationId = this.annotation.item.id;
|
this.annotationId = this.annotation.item.id;
|
||||||
|
const request = this.#commentsApiService.fetch(this.state.dossierId, this.state.fileId, this.annotationId);
|
||||||
|
request.then(comments => {
|
||||||
|
this.annotation.item.numberOfComments = comments.length;
|
||||||
|
});
|
||||||
this.active = this.annotation.isSelected;
|
this.active = this.annotation.isSelected;
|
||||||
this.actionsHelpModeKey = this.#getActionsHelpModeKey();
|
this.actionsHelpModeKey = this.#getActionsHelpModeKey();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,39 +1,30 @@
|
|||||||
<ng-container *ngIf="componentContext$ | async as ctx">
|
<div *ngFor="let comment of comments(); trackBy: trackBy" class="comment">
|
||||||
<div *ngFor="let comment of annotation.comments; trackBy: trackBy" class="comment">
|
<div class="comment-details-wrapper">
|
||||||
<div class="comment-details-wrapper">
|
<div [matTooltipPosition]="'above'" [matTooltip]="comment.date | date: 'exactDate'" class="small-label">
|
||||||
<div [matTooltipPosition]="'above'" [matTooltip]="comment.date | date : 'exactDate'" class="small-label">
|
<strong> {{ comment.userId | name }} </strong>
|
||||||
<strong> {{ comment.user | name }} </strong>
|
{{ comment.date | date: 'sophisticatedDate' }}
|
||||||
{{ comment.date | date : 'sophisticatedDate' }}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="comment-actions">
|
|
||||||
<iqser-circle-button
|
|
||||||
(action)="deleteComment(comment)"
|
|
||||||
*ngIf="permissionsService.canDeleteComment(comment, _state.file(), _state.dossier())"
|
|
||||||
[iconSize]="10"
|
|
||||||
[size]="20"
|
|
||||||
class="pointer"
|
|
||||||
icon="iqser:trash"
|
|
||||||
></iqser-circle-button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>{{ comment.text }}</div>
|
<div class="comment-actions">
|
||||||
|
<iqser-circle-button
|
||||||
|
(action)="remove(comment)"
|
||||||
|
*ngIf="permissionsService.canDeleteComment(comment, state.file(), state.dossier())"
|
||||||
|
[iconSize]="10"
|
||||||
|
[size]="20"
|
||||||
|
class="pointer"
|
||||||
|
icon="iqser:trash"
|
||||||
|
></iqser-circle-button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<iqser-input-with-action
|
<div>{{ comment.text }}</div>
|
||||||
(action)="addComment($event)"
|
</div>
|
||||||
*ngIf="permissionsService.canAddComment(_state.file(), _state.dossier())"
|
|
||||||
[placeholder]="'comments.add-comment' | translate"
|
|
||||||
autocomplete="off"
|
|
||||||
icon="iqser:collapse"
|
|
||||||
width="full"
|
|
||||||
></iqser-input-with-action>
|
|
||||||
|
|
||||||
<div
|
<iqser-input-with-action
|
||||||
(click)="toggleExpandComments()"
|
(action)="add($event)"
|
||||||
class="all-caps-label pointer hide-comments"
|
*ngIf="permissionsService.canAddComment(state.file(), state.dossier())"
|
||||||
iqserStopPropagation
|
[placeholder]="'comments.add-comment' | translate"
|
||||||
translate="comments.hide-comments"
|
autocomplete="off"
|
||||||
></div>
|
icon="iqser:collapse"
|
||||||
</ng-container>
|
width="full"
|
||||||
|
></iqser-input-with-action>
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
.comment {
|
.comment {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
|
||||||
.comment-details-wrapper {
|
.comment-details-wrapper {
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
|
|||||||
@ -1,84 +1,75 @@
|
|||||||
import { ChangeDetectorRef, Component, HostBinding, Input, OnInit, ViewChild } from '@angular/core';
|
import { Component, inject, Input, OnChanges, signal, SimpleChanges, ViewChild } from '@angular/core';
|
||||||
import type { IComment, User } from '@red/domain';
|
|
||||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
|
||||||
import { PermissionsService } from '@services/permissions.service';
|
|
||||||
import { InputWithActionComponent, LoadingService } from '@iqser/common-ui';
|
import { InputWithActionComponent, LoadingService } from '@iqser/common-ui';
|
||||||
import { Observable } from 'rxjs';
|
|
||||||
import { CommentingService } from '../../services/commenting.service';
|
|
||||||
import { tap } from 'rxjs/operators';
|
|
||||||
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
|
||||||
import { ManualRedactionService } from '../../services/manual-redaction.service';
|
|
||||||
import { getCurrentUser } from '@iqser/common-ui/lib/users';
|
import { getCurrentUser } from '@iqser/common-ui/lib/users';
|
||||||
import { ContextComponent, trackByFactory } from '@iqser/common-ui/lib/utils';
|
import { trackByFactory } from '@iqser/common-ui/lib/utils';
|
||||||
|
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||||
interface CommentsContext {
|
import type { IComment, User } from '@red/domain';
|
||||||
hiddenComments: boolean;
|
import { CommentsApiService } from '@services/comments-api.service';
|
||||||
}
|
import { PermissionsService } from '@services/permissions.service';
|
||||||
|
import { NGXLogger } from 'ngx-logger';
|
||||||
|
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-comments',
|
selector: 'redaction-comments',
|
||||||
templateUrl: './comments.component.html',
|
templateUrl: './comments.component.html',
|
||||||
styleUrls: ['./comments.component.scss'],
|
styleUrls: ['./comments.component.scss'],
|
||||||
})
|
})
|
||||||
export class CommentsComponent extends ContextComponent<CommentsContext> implements OnInit {
|
export class CommentsComponent implements OnChanges {
|
||||||
@HostBinding('class.hidden') private _hidden = true;
|
readonly #commentsApiService = inject(CommentsApiService);
|
||||||
@ViewChild(InputWithActionComponent) private readonly _input: InputWithActionComponent;
|
readonly #logger = inject(NGXLogger);
|
||||||
@Input() annotation: AnnotationWrapper;
|
protected readonly trackBy = trackByFactory();
|
||||||
readonly trackBy = trackByFactory();
|
protected readonly currentUser = getCurrentUser<User>();
|
||||||
readonly currentUser = getCurrentUser<User>();
|
readonly comments = signal<IComment[]>([]);
|
||||||
hiddenComments$: Observable<boolean>;
|
@ViewChild(InputWithActionComponent) protected readonly input: InputWithActionComponent;
|
||||||
|
@Input({ required: true }) annotation: AnnotationWrapper;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly permissionsService: PermissionsService,
|
readonly permissionsService: PermissionsService,
|
||||||
private readonly _manualRedactionService: ManualRedactionService,
|
|
||||||
private readonly _commentingService: CommentingService,
|
|
||||||
private readonly _loadingService: LoadingService,
|
private readonly _loadingService: LoadingService,
|
||||||
private readonly _changeRef: ChangeDetectorRef,
|
protected readonly state: FilePreviewStateService,
|
||||||
protected readonly _state: FilePreviewStateService,
|
) {}
|
||||||
) {
|
|
||||||
super();
|
ngOnChanges(changes: SimpleChanges) {
|
||||||
|
const currentAnnotation: AnnotationWrapper = changes.annotation?.currentValue;
|
||||||
|
const previousAnnotation: AnnotationWrapper = changes.annotation?.previousValue;
|
||||||
|
const annotationChanged = currentAnnotation?.id !== previousAnnotation?.id;
|
||||||
|
const commentsChanged = currentAnnotation?.numberOfComments !== previousAnnotation?.numberOfComments;
|
||||||
|
if (annotationChanged || commentsChanged) {
|
||||||
|
this.#logger.info(`[COMMENTS] State of annotation ${this.annotation.value} changed. Fetch comments.`);
|
||||||
|
const request = this.#commentsApiService.fetch(this.state.dossierId, this.state.fileId, this.annotation.id);
|
||||||
|
request.then(comments => {
|
||||||
|
this.comments.set(comments);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
async add(value: string): Promise<void> {
|
||||||
this.hiddenComments$ = this._commentingService.isActive$(this.annotation.id).pipe(
|
|
||||||
tap(active => {
|
|
||||||
this._hidden = !active;
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
super._initContext({
|
|
||||||
hiddenComments: this.hiddenComments$,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async addComment(value: string): Promise<void> {
|
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._loadingService.start();
|
this._loadingService.start();
|
||||||
const { dossierId, fileId } = this._state;
|
const { dossierId, fileId } = this.state;
|
||||||
const commentId = await this._manualRedactionService.addComment(value, this.annotation.id, dossierId, fileId);
|
const commentId = await this.#commentsApiService.add(value, this.annotation.id, dossierId, fileId);
|
||||||
this.annotation.comments.push({
|
this.annotation.numberOfComments++;
|
||||||
text: value,
|
this.comments.update(current => [
|
||||||
id: commentId,
|
...current,
|
||||||
annotationId: this.annotation.id,
|
{
|
||||||
user: this.currentUser.id,
|
text: value,
|
||||||
});
|
id: commentId,
|
||||||
this._input.reset();
|
annotationId: this.annotation.id,
|
||||||
this._changeRef.markForCheck();
|
userId: this.currentUser.id,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
this.input.reset();
|
||||||
this._loadingService.stop();
|
this._loadingService.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleExpandComments(): void {
|
async remove(comment: IComment): Promise<void> {
|
||||||
this._commentingService.toggle(this.annotation.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
async deleteComment(comment: IComment): Promise<void> {
|
|
||||||
this._loadingService.start();
|
this._loadingService.start();
|
||||||
const { dossierId, fileId } = this._state;
|
const { dossierId, fileId } = this.state;
|
||||||
await this._manualRedactionService.deleteComment(comment.id, this.annotation.id, dossierId, fileId);
|
await this.#commentsApiService.remove(comment.id, this.annotation.id, dossierId, fileId);
|
||||||
this.annotation.comments.splice(this.annotation.comments.indexOf(comment), 1);
|
this.annotation.numberOfComments--;
|
||||||
this._changeRef.markForCheck();
|
this.comments.update(current => current.filter(c => c.id !== comment.id));
|
||||||
this._loadingService.stop();
|
this._loadingService.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -86,11 +86,7 @@
|
|||||||
<mat-icon svgIcon="iqser:nav-first"></mat-icon>
|
<mat-icon svgIcon="iqser:nav-first"></mat-icon>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<redaction-pages
|
<redaction-pages (click)="pagesPanelActive = true" [pages]="displayedPages"></redaction-pages>
|
||||||
(click)="pagesPanelActive = true"
|
|
||||||
[displayedAnnotations]="displayedAnnotations"
|
|
||||||
[pages]="displayedPages"
|
|
||||||
></redaction-pages>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
(click)="scrollQuickNavLast()"
|
(click)="scrollQuickNavLast()"
|
||||||
|
|||||||
@ -36,6 +36,7 @@ export class PageExclusionComponent {
|
|||||||
try {
|
try {
|
||||||
const pageRanges = extractPageRanges(inputValue, file);
|
const pageRanges = extractPageRanges(inputValue, file);
|
||||||
await this._reanalysisService.excludePages({ pageRanges }, file);
|
await this._reanalysisService.excludePages({ pageRanges }, file);
|
||||||
|
this._state.excludedPages.update(value => [...value, ...this._flattenPageRanges(pageRanges)]);
|
||||||
this._inputComponent.reset();
|
this._inputComponent.reset();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
this._toaster.error(_('file-preview.tabs.exclude-pages.error'));
|
this._toaster.error(_('file-preview.tabs.exclude-pages.error'));
|
||||||
@ -46,6 +47,7 @@ export class PageExclusionComponent {
|
|||||||
async includePagesRange(range: IPageRange): Promise<void> {
|
async includePagesRange(range: IPageRange): Promise<void> {
|
||||||
this._loadingService.start();
|
this._loadingService.start();
|
||||||
await this._reanalysisService.includePages({ pageRanges: [range] }, this._state.file());
|
await this._reanalysisService.includePages({ pageRanges: [range] }, this._state.file());
|
||||||
|
this._state.excludedPages.update(value => value.filter(page => !this._flattenPageRanges([range]).includes(page)));
|
||||||
this._inputComponent.reset();
|
this._inputComponent.reset();
|
||||||
this._loadingService.stop();
|
this._loadingService.stop();
|
||||||
}
|
}
|
||||||
@ -64,4 +66,15 @@ export class PageExclusionComponent {
|
|||||||
return ranges;
|
return ranges;
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _flattenPageRanges(ranges: IPageRange[]) {
|
||||||
|
const flattenedPages = [];
|
||||||
|
ranges.forEach(range => {
|
||||||
|
for (let page = range.startPage; page <= range.endPage; page++) {
|
||||||
|
flattenedPages.push(page);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return flattenedPages;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import { List } from '@iqser/common-ui/lib/utils';
|
|||||||
import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service';
|
import { PdfViewer } from '../../../pdf-viewer/services/pdf-viewer.service';
|
||||||
import { MultiSelectService } from '../../services/multi-select.service';
|
import { MultiSelectService } from '../../services/multi-select.service';
|
||||||
import { AnnotationsListingService } from '../../services/annotations-listing.service';
|
import { AnnotationsListingService } from '../../services/annotations-listing.service';
|
||||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
|
||||||
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
||||||
import { ViewedPagesMapService } from '@services/files/viewed-pages-map.service';
|
import { ViewedPagesMapService } from '@services/files/viewed-pages-map.service';
|
||||||
import { ViewedPage } from '@red/domain';
|
import { ViewedPage } from '@red/domain';
|
||||||
@ -20,7 +19,6 @@ export class PagesComponent implements AfterViewInit {
|
|||||||
readonly #listingService = inject(AnnotationsListingService);
|
readonly #listingService = inject(AnnotationsListingService);
|
||||||
protected readonly _pdf = inject(PdfViewer);
|
protected readonly _pdf = inject(PdfViewer);
|
||||||
@Input({ required: true }) pages: List<number>;
|
@Input({ required: true }) pages: List<number>;
|
||||||
@Input({ required: true }) displayedAnnotations: Map<number, AnnotationWrapper[]>;
|
|
||||||
readonly viewedPages$ = inject(ViewedPagesMapService).get$(this.#state.fileId);
|
readonly viewedPages$ = inject(ViewedPagesMapService).get$(this.#state.fileId);
|
||||||
|
|
||||||
ngAfterViewInit() {
|
ngAfterViewInit() {
|
||||||
@ -50,8 +48,7 @@ export class PagesComponent implements AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasOnlyManualRedactionsAndIsExcluded(pageNumber: number): boolean {
|
hasOnlyManualRedactionsAndIsExcluded(pageNumber: number): boolean {
|
||||||
const hasOnlyManualRedactions = this.displayedAnnotations.get(pageNumber)?.every(annotation => annotation.manual);
|
return this.#state.file().excludedPages.includes(pageNumber);
|
||||||
return hasOnlyManualRedactions && this.#state.file().excludedPages.includes(pageNumber);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getViewedPage(viewedPages: ViewedPage[], pageNumber: number) {
|
getViewedPage(viewedPages: ViewedPage[], pageNumber: number) {
|
||||||
|
|||||||
@ -13,6 +13,8 @@ export interface LegalBasisOption {
|
|||||||
description?: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DOCUMINE_LEGAL_BASIS = 'n-a.';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-force-annotation-dialog',
|
selector: 'redaction-force-annotation-dialog',
|
||||||
templateUrl: './force-annotation-dialog.component.html',
|
templateUrl: './force-annotation-dialog.component.html',
|
||||||
@ -41,22 +43,23 @@ export class ForceAnnotationDialogComponent extends BaseDialogComponent implemen
|
|||||||
}
|
}
|
||||||
|
|
||||||
async ngOnInit() {
|
async ngOnInit() {
|
||||||
const data = await firstValueFrom(this._justificationsService.getForDossierTemplate(this._data.dossier.dossierTemplateId));
|
if (!this.isDocumine) {
|
||||||
|
const data = await firstValueFrom(this._justificationsService.getForDossierTemplate(this._data.dossier.dossierTemplateId));
|
||||||
|
|
||||||
this.legalOptions = data.map(lbm => ({
|
this.legalOptions = data.map(lbm => ({
|
||||||
legalBasis: lbm.reason,
|
legalBasis: lbm.reason,
|
||||||
description: lbm.description,
|
description: lbm.description,
|
||||||
label: lbm.name,
|
label: lbm.name,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
this.legalOptions.sort((a, b) => a.label.localeCompare(b.label));
|
this.legalOptions.sort((a, b) => a.label.localeCompare(b.label));
|
||||||
|
|
||||||
// Set pre-existing reason if it exists
|
// Set pre-existing reason if it exists
|
||||||
const existingReason = this.legalOptions.find(option => option.legalBasis === this._data.annotations[0].legalBasis);
|
const existingReason = this.legalOptions.find(option => option.legalBasis === this._data.annotations[0].legalBasis);
|
||||||
if (!this._data.hint && existingReason) {
|
if (!this._data.hint && existingReason) {
|
||||||
this.form.patchValue({ reason: existingReason }, { emitEvent: false });
|
this.form.patchValue({ reason: existingReason }, { emitEvent: false });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.initialFormValue = this.form.getRawValue();
|
this.initialFormValue = this.form.getRawValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +69,7 @@ export class ForceAnnotationDialogComponent extends BaseDialogComponent implemen
|
|||||||
|
|
||||||
private _getForm(): UntypedFormGroup {
|
private _getForm(): UntypedFormGroup {
|
||||||
return this._formBuilder.group({
|
return this._formBuilder.group({
|
||||||
reason: this._data.hint ? ['Forced Hint'] : [null, Validators.required],
|
reason: this._data.hint ? ['Forced Hint'] : [null, !this.isDocumine ? Validators.required : null],
|
||||||
comment: [null],
|
comment: [null],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -74,9 +77,7 @@ export class ForceAnnotationDialogComponent extends BaseDialogComponent implemen
|
|||||||
private _createForceRedactionRequest(): ILegalBasisChangeRequest {
|
private _createForceRedactionRequest(): ILegalBasisChangeRequest {
|
||||||
const request: ILegalBasisChangeRequest = {};
|
const request: ILegalBasisChangeRequest = {};
|
||||||
|
|
||||||
const legalOption: LegalBasisOption = this.form.get('reason').value;
|
request.legalBasis = !this.isDocumine ? this.form.get('reason').value.legalBasis : DOCUMINE_LEGAL_BASIS;
|
||||||
|
|
||||||
request.legalBasis = legalOption.legalBasis;
|
|
||||||
request.comment = this.form.get('comment').value;
|
request.comment = this.form.get('comment').value;
|
||||||
|
|
||||||
return request;
|
return request;
|
||||||
|
|||||||
@ -11,34 +11,47 @@
|
|||||||
|
|
||||||
<ng-container *ngFor="let entry of componentLogEntries; let index = index">
|
<ng-container *ngFor="let entry of componentLogEntries; let index = index">
|
||||||
<div class="bold">{{ entry.name }}</div>
|
<div class="bold">{{ entry.name }}</div>
|
||||||
<div [id]="getValueCellId(index)">
|
<div [id]="getValueCellId(index)" class="component-value">
|
||||||
<iqser-editable-input
|
<div>
|
||||||
(save)="saveEdit($event, entry.name)"
|
<ng-container *ngFor="let componentValue of entry.componentValues">
|
||||||
[canEdit]="canEdit"
|
<iqser-editable-input
|
||||||
[cancelTooltip]="'component-log-dialog.actions.cancel-edit' | translate"
|
(save)="saveEdit($event, entry.originalKey)"
|
||||||
[editTooltip]="'component-log-dialog.actions.edit' | translate"
|
[canEdit]="canEdit && entry.componentValues.length === 1"
|
||||||
[id]="'value-' + index"
|
[cancelTooltip]="'component-log-dialog.actions.cancel-edit' | translate"
|
||||||
[parentId]="getValueCellId(index)"
|
[editTooltip]="'component-log-dialog.actions.edit' | translate"
|
||||||
[saveTooltip]="'component-log-dialog.actions.save' | translate"
|
[id]="'value-' + index"
|
||||||
[value]="entry.componentValues[0].value ?? entry.componentValues[0].originalValue"
|
[parentId]="getValueCellId(index)"
|
||||||
[attr.helpModeKey]="'scm_edit_DIALOG'"
|
[saveTooltip]="'component-log-dialog.actions.save' | translate"
|
||||||
>
|
[value]="componentValue.value ?? componentValue.originalValue"
|
||||||
<ng-container slot="editing">
|
[listValue]="entry.componentValues.length !== 1"
|
||||||
<iqser-circle-button
|
[attr.helpModeKey]="'scm_edit_DIALOG'"
|
||||||
(action)="undo(entry.name)"
|
[class.not-editable]="entry.componentValues.length !== 1"
|
||||||
*ngIf="entry.componentValues[0].value !== entry.componentValues[0].originalValue && canEdit"
|
>
|
||||||
[showDot]="true"
|
<ng-container slot="editing">
|
||||||
[tooltip]="
|
<iqser-circle-button
|
||||||
'component-log-dialog.actions.undo'
|
(action)="undo(entry.originalKey)"
|
||||||
| translate: { value: entry.componentValues[0].originalValue }
|
*ngIf="componentValue.value !== componentValue.originalValue && canEdit"
|
||||||
| replaceNbsp
|
[showDot]="true"
|
||||||
"
|
[tooltip]="
|
||||||
[attr.help-mode-key]="'scm_undo_DIALOG'"
|
'component-log-dialog.actions.undo'
|
||||||
class="ml-2"
|
| translate: { value: componentValue.originalValue }
|
||||||
icon="red:undo"
|
| replaceNbsp
|
||||||
></iqser-circle-button>
|
"
|
||||||
|
[attr.help-mode-key]="'scm_undo_DIALOG'"
|
||||||
|
class="ml-2"
|
||||||
|
icon="red:undo"
|
||||||
|
></iqser-circle-button>
|
||||||
|
</ng-container>
|
||||||
|
</iqser-editable-input>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</iqser-editable-input>
|
</div>
|
||||||
|
<iqser-circle-button
|
||||||
|
*ngIf="entry.componentValues.length !== 1"
|
||||||
|
[tooltip]="'component-log-dialog.actions.disabled-edit' | translate"
|
||||||
|
[disabled]="true"
|
||||||
|
class="edit-button"
|
||||||
|
icon="iqser:edit"
|
||||||
|
></iqser-circle-button>
|
||||||
</div>
|
</div>
|
||||||
<div>{{ entry.componentValues[0].valueDescription }}</div>
|
<div>{{ entry.componentValues[0].valueDescription }}</div>
|
||||||
<div>
|
<div>
|
||||||
|
|||||||
@ -59,3 +59,17 @@ ul {
|
|||||||
.ml-auto {
|
.ml-auto {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.component-value {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
div {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
.not-editable {
|
||||||
|
margin: 8px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -64,35 +64,21 @@ export class StructuredComponentManagementDialogComponent extends BaseDialogComp
|
|||||||
|
|
||||||
exportJSON() {
|
exportJSON() {
|
||||||
return firstValueFrom(
|
return firstValueFrom(
|
||||||
this._componentLogService.exportJSON(
|
this._componentLogService.exportJSON(this.data.file.dossierTemplateId, this.data.file.dossierId, this.data.file),
|
||||||
this.data.file.dossierTemplateId,
|
|
||||||
this.data.file.dossierId,
|
|
||||||
this.data.file.fileId,
|
|
||||||
this.data.file.filename,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
exportXML() {
|
exportXML() {
|
||||||
return firstValueFrom(
|
return firstValueFrom(
|
||||||
this._componentLogService.exportXML(
|
this._componentLogService.exportXML(this.data.file.dossierTemplateId, this.data.file.dossierId, this.data.file),
|
||||||
this.data.file.dossierTemplateId,
|
|
||||||
this.data.file.dossierId,
|
|
||||||
this.data.file.fileId,
|
|
||||||
this.data.file.filename,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async exportAllInDossier() {
|
async exportAllInDossier() {
|
||||||
const allFilesInDossier = this._filesMapService.get(this.data.file.dossierId);
|
const allFilesInDossier = this._filesMapService.get(this.data.file.dossierId);
|
||||||
for (const file of allFilesInDossier) {
|
for (const file of allFilesInDossier) {
|
||||||
await firstValueFrom(
|
await firstValueFrom(this._componentLogService.exportJSON(this.data.file.dossierTemplateId, file.dossierId, file));
|
||||||
this._componentLogService.exportJSON(this.data.file.dossierTemplateId, file.dossierId, file.fileId, file.filename),
|
await firstValueFrom(this._componentLogService.exportXML(this.data.file.dossierTemplateId, file.dossierId, file));
|
||||||
);
|
|
||||||
await firstValueFrom(
|
|
||||||
this._componentLogService.exportXML(this.data.file.dossierTemplateId, file.dossierId, file.fileId, file.filename),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -107,34 +107,6 @@ export class FilePreviewScreenComponent
|
|||||||
@ViewChild('actionsWrapper', { static: false }) private readonly _actionsWrapper: ElementRef;
|
@ViewChild('actionsWrapper', { static: false }) private readonly _actionsWrapper: ElementRef;
|
||||||
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
||||||
|
|
||||||
get changed() {
|
|
||||||
return this._pageRotationService.hasRotations();
|
|
||||||
}
|
|
||||||
|
|
||||||
get #earmarks$() {
|
|
||||||
const isEarmarksViewMode$ = this._viewModeService.viewMode$.pipe(filter(() => this._viewModeService.isEarmarks()));
|
|
||||||
|
|
||||||
const earmarks$ = isEarmarksViewMode$.pipe(
|
|
||||||
tap(() => this._loadingService.start()),
|
|
||||||
switchMap(() => this._fileDataService.loadEarmarks()),
|
|
||||||
tap(() => this.updateViewMode().then(() => this._loadingService.stop())),
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentPageIfEarmarksView$ = combineLatest([this.pdf.currentPage$, this._viewModeService.viewMode$]).pipe(
|
|
||||||
filter(() => this._viewModeService.isEarmarks()),
|
|
||||||
map(([page]) => page),
|
|
||||||
);
|
|
||||||
|
|
||||||
const currentPageEarmarks$ = combineLatest([currentPageIfEarmarksView$, earmarks$]).pipe(
|
|
||||||
map(([page, earmarks]) => earmarks.get(page)),
|
|
||||||
);
|
|
||||||
|
|
||||||
return currentPageEarmarks$.pipe(
|
|
||||||
map(earmarks => [earmarks, this._skippedService.hideSkipped(), this.state.dossierTemplateId] as const),
|
|
||||||
tap(args => this._annotationDrawService.draw(...args)),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
readonly pdf: PdfViewer,
|
readonly pdf: PdfViewer,
|
||||||
readonly state: FilePreviewStateService,
|
readonly state: FilePreviewStateService,
|
||||||
@ -195,21 +167,55 @@ export class FilePreviewScreenComponent
|
|||||||
);
|
);
|
||||||
|
|
||||||
effect(() => {
|
effect(() => {
|
||||||
this.state.shouldUpdate();
|
this.state.updateExcludedPagesStyle();
|
||||||
if (this._documentViewer.pageComplete()) {
|
if (this._documentViewer.pageComplete()) {
|
||||||
this.#setExcludedPageStyles();
|
this.#setExcludedPageStyles();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
effect(() => {
|
effect(() => {
|
||||||
if (this._viewModeService.viewMode()) {
|
this._viewModeService.viewMode();
|
||||||
this.updateViewMode().then();
|
this.updateViewMode().then();
|
||||||
|
});
|
||||||
|
|
||||||
|
effect(() => {
|
||||||
|
this.state.updateExcludedPagesStyle();
|
||||||
|
this._viewModeService.viewMode();
|
||||||
|
if (_documentViewer.loaded()) {
|
||||||
this._logger.info('[PDF] Stamp pdf');
|
this._logger.info('[PDF] Stamp pdf');
|
||||||
this._stampService.stampPDF().then();
|
this._stampService.stampPDF().then();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get changed() {
|
||||||
|
return this._pageRotationService.hasRotations();
|
||||||
|
}
|
||||||
|
|
||||||
|
get #earmarks$() {
|
||||||
|
const isEarmarksViewMode$ = this._viewModeService.viewMode$.pipe(filter(() => this._viewModeService.isEarmarks()));
|
||||||
|
|
||||||
|
const earmarks$ = isEarmarksViewMode$.pipe(
|
||||||
|
tap(() => this._loadingService.start()),
|
||||||
|
switchMap(() => this._fileDataService.loadEarmarks()),
|
||||||
|
tap(() => this.updateViewMode().then(() => this._loadingService.stop())),
|
||||||
|
);
|
||||||
|
|
||||||
|
const currentPageIfEarmarksView$ = combineLatest([this.pdf.currentPage$, this._viewModeService.viewMode$]).pipe(
|
||||||
|
filter(() => this._viewModeService.isEarmarks()),
|
||||||
|
map(([page]) => page),
|
||||||
|
);
|
||||||
|
|
||||||
|
const currentPageEarmarks$ = combineLatest([currentPageIfEarmarksView$, earmarks$]).pipe(
|
||||||
|
map(([page, earmarks]) => earmarks.get(page)),
|
||||||
|
);
|
||||||
|
|
||||||
|
return currentPageEarmarks$.pipe(
|
||||||
|
map(earmarks => [earmarks, this._skippedService.hideSkipped(), this.state.dossierTemplateId] as const),
|
||||||
|
tap(args => this._annotationDrawService.draw(...args)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
getLastAssignee() {
|
getLastAssignee() {
|
||||||
const { isApproved, lastReviewer, lastApprover } = this.state.file();
|
const { isApproved, lastReviewer, lastApprover } = this.state.file();
|
||||||
const isRss = this._iqserPermissionsService.has(this.roles.getRss);
|
const isRss = this._iqserPermissionsService.has(this.roles.getRss);
|
||||||
@ -760,11 +766,11 @@ export class FilePreviewScreenComponent
|
|||||||
.subscribe();
|
.subscribe();
|
||||||
|
|
||||||
const selectedTextEffect = this._documentViewer.selectedText$.pipe(
|
const selectedTextEffect = this._documentViewer.selectedText$.pipe(
|
||||||
tap(selectedText => {
|
tap(() => {
|
||||||
const canPerformActions = this.pdfProxyService.canPerformActions();
|
const canPerformActions = this.pdfProxyService.canPerformActions();
|
||||||
const isCurrentPageExcluded = this.state.file().isPageExcluded(this.pdf.currentPage());
|
const isCurrentPageExcluded = this.state.file().isPageExcluded(this.pdf.currentPage());
|
||||||
|
|
||||||
if ((selectedText.length > 2 || this._isJapaneseString(selectedText)) && canPerformActions && !isCurrentPageExcluded) {
|
if (canPerformActions && !isCurrentPageExcluded) {
|
||||||
this.pdf.enable(textActions);
|
this.pdf.enable(textActions);
|
||||||
} else {
|
} else {
|
||||||
this.pdf.disable(textActions);
|
this.pdf.disable(textActions);
|
||||||
@ -852,10 +858,6 @@ export class FilePreviewScreenComponent
|
|||||||
this._annotationManager.select(annotations);
|
this._annotationManager.select(annotations);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _isJapaneseString(text: string) {
|
|
||||||
return text.match(/[\u3000-\u303f\u3040-\u309f\u30a0-\u30ff\uff00-\uff9f\u4e00-\u9faf\u3400-\u4dbf]/);
|
|
||||||
}
|
|
||||||
|
|
||||||
#restoreOldFilters() {
|
#restoreOldFilters() {
|
||||||
combineLatest([
|
combineLatest([
|
||||||
this._filterService.getGroup$('primaryFilters').pipe(first(filterGroup => !!filterGroup?.filters.length)),
|
this._filterService.getGroup$('primaryFilters').pipe(first(filterGroup => !!filterGroup?.filters.length)),
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { IqserDialog } from '@common-ui/dialog/iqser-dialog.service';
|
import { IqserDialog } from '@common-ui/dialog/iqser-dialog.service';
|
||||||
import { getConfig, Toaster } from '@iqser/common-ui';
|
import { getConfig, Toaster } from '@iqser/common-ui';
|
||||||
import { List, log } from '@iqser/common-ui/lib/utils';
|
import { List, log } from '@iqser/common-ui/lib/utils';
|
||||||
@ -13,6 +13,7 @@ import {
|
|||||||
IRectangle,
|
IRectangle,
|
||||||
IResizeRequest,
|
IResizeRequest,
|
||||||
} from '@red/domain';
|
} from '@red/domain';
|
||||||
|
import { CommentsApiService } from '@services/comments-api.service';
|
||||||
import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service';
|
import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service';
|
||||||
import { PermissionsService } from '@services/permissions.service';
|
import { PermissionsService } from '@services/permissions.service';
|
||||||
import { firstValueFrom, Observable, zip } from 'rxjs';
|
import { firstValueFrom, Observable, zip } from 'rxjs';
|
||||||
@ -46,6 +47,7 @@ import { SkippedService } from './skipped.service';
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class AnnotationActionsService {
|
export class AnnotationActionsService {
|
||||||
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
||||||
|
readonly #commentsApiService = inject(CommentsApiService);
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _manualRedactionService: ManualRedactionService,
|
private readonly _manualRedactionService: ManualRedactionService,
|
||||||
@ -129,7 +131,7 @@ export class AnnotationActionsService {
|
|||||||
if (result.comment) {
|
if (result.comment) {
|
||||||
try {
|
try {
|
||||||
for (const a of annotations) {
|
for (const a of annotations) {
|
||||||
await this._manualRedactionService.addComment(result.comment, a.id, dossierId, fileId);
|
await this.#commentsApiService.add(result.comment, a.id, dossierId, fileId);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this._toaster.rawError(error.error.message);
|
this._toaster.rawError(error.error.message);
|
||||||
@ -259,8 +261,8 @@ export class AnnotationActionsService {
|
|||||||
comment: result.comment,
|
comment: result.comment,
|
||||||
positions: textAndPositions.positions,
|
positions: textAndPositions.positions,
|
||||||
value: text,
|
value: text,
|
||||||
updateDictionary: result.updateDictionary,
|
updateDictionary: !annotation.isRuleBased && result.updateDictionary,
|
||||||
addToAllDossiers: result.addToAllDossiers,
|
addToAllDossiers: !annotation.isRuleBased && result.addToAllDossiers,
|
||||||
};
|
};
|
||||||
|
|
||||||
await this.cancelResize(annotation);
|
await this.cancelResize(annotation);
|
||||||
|
|||||||
@ -42,7 +42,7 @@ export class AnnotationProcessingService {
|
|||||||
label: _('filter-menu.with-comments'),
|
label: _('filter-menu.with-comments'),
|
||||||
checked: false,
|
checked: false,
|
||||||
topLevelFilter: true,
|
topLevelFilter: true,
|
||||||
checker: (annotation: AnnotationWrapper) => annotation?.comments?.length > 0,
|
checker: (annotation: AnnotationWrapper) => annotation?.numberOfComments > 0,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'redaction-changes',
|
id: 'redaction-changes',
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { HttpEvent, HttpEventType, HttpProgressEvent, HttpResponse } from '@angular/common/http';
|
import { HttpEvent, HttpEventType, HttpProgressEvent, HttpResponse } from '@angular/common/http';
|
||||||
import { computed, effect, inject, Injectable, Signal } from '@angular/core';
|
import { computed, effect, inject, Injectable, signal, Signal, WritableSignal } from '@angular/core';
|
||||||
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
||||||
import { LoadingService, wipeCache } from '@iqser/common-ui';
|
import { LoadingService, wipeCache } from '@iqser/common-ui';
|
||||||
import { getParam } from '@iqser/common-ui/lib/utils';
|
import { getParam } from '@iqser/common-ui/lib/utils';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { Dictionary, Dossier, DOSSIER_ID, DOSSIER_TEMPLATE_ID, File, FILE_ID } from '@red/domain';
|
import { Dictionary, Dossier, DOSSIER_ID, DOSSIER_TEMPLATE_ID, File, FILE_ID, ViewModes } from '@red/domain';
|
||||||
import { DossiersService } from '@services/dossiers/dossiers.service';
|
import { DossiersService } from '@services/dossiers/dossiers.service';
|
||||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||||
import { DossierDictionariesMapService } from '@services/entity-services/dossier-dictionaries-map.service';
|
import { DossierDictionariesMapService } from '@services/entity-services/dossier-dictionaries-map.service';
|
||||||
@ -44,7 +44,8 @@ export class FilePreviewStateService {
|
|||||||
readonly dossierId = getParam(DOSSIER_ID);
|
readonly dossierId = getParam(DOSSIER_ID);
|
||||||
readonly dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID);
|
readonly dossierTemplateId = getParam(DOSSIER_TEMPLATE_ID);
|
||||||
readonly fileId = getParam(FILE_ID);
|
readonly fileId = getParam(FILE_ID);
|
||||||
readonly shouldUpdate = computed(() => this.file().excludedPages);
|
readonly excludedPages: WritableSignal<number[]>;
|
||||||
|
readonly updateExcludedPagesStyle = computed(() => this.excludedPages());
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly _permissionsService: PermissionsService,
|
private readonly _permissionsService: PermissionsService,
|
||||||
@ -60,6 +61,7 @@ export class FilePreviewStateService {
|
|||||||
this.dossier = toSignal(dossiersServiceResolver().getEntityChanged$(this.dossierId));
|
this.dossier = toSignal(dossiersServiceResolver().getEntityChanged$(this.dossierId));
|
||||||
this.file$ = inject(FilesMapService).watch$(this.dossierId, this.fileId);
|
this.file$ = inject(FilesMapService).watch$(this.dossierId, this.fileId);
|
||||||
this.file = toSignal(this.file$);
|
this.file = toSignal(this.file$);
|
||||||
|
this.excludedPages = signal(this.file().excludedPages);
|
||||||
this.isWritable = computed(() => {
|
this.isWritable = computed(() => {
|
||||||
const isWritable = this._permissionsService.canPerformAnnotationActions(this.file(), this.dossier());
|
const isWritable = this._permissionsService.canPerformAnnotationActions(this.file(), this.dossier());
|
||||||
this._logger.info('[FILE] Is writeable:', isWritable);
|
this._logger.info('[FILE] Is writeable:', isWritable);
|
||||||
@ -79,7 +81,9 @@ export class FilePreviewStateService {
|
|||||||
effect(
|
effect(
|
||||||
() => {
|
() => {
|
||||||
if (this._viewModeService.isEarmarks() && !this.file().hasHighlights) {
|
if (this._viewModeService.isEarmarks() && !this.file().hasHighlights) {
|
||||||
this._viewModeService.switchToStandard();
|
if (this._viewModeService.viewMode() !== ViewModes.STANDARD) {
|
||||||
|
this._viewModeService.switchToStandard();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ allowSignalWrites: true },
|
{ allowSignalWrites: true },
|
||||||
|
|||||||
@ -21,7 +21,7 @@ import { PermissionsService } from '@services/permissions.service';
|
|||||||
import { dictionaryActionsTranslations, manualRedactionActionsTranslations } from '@translations/annotation-actions-translations';
|
import { dictionaryActionsTranslations, manualRedactionActionsTranslations } from '@translations/annotation-actions-translations';
|
||||||
import { Roles } from '@users/roles';
|
import { Roles } from '@users/roles';
|
||||||
import { NGXLogger } from 'ngx-logger';
|
import { NGXLogger } from 'ngx-logger';
|
||||||
import { firstValueFrom, of } from 'rxjs';
|
import { of } from 'rxjs';
|
||||||
import { tap } from 'rxjs/operators';
|
import { tap } from 'rxjs/operators';
|
||||||
|
|
||||||
function getResponseType(error: boolean, isConflict: boolean) {
|
function getResponseType(error: boolean, isConflict: boolean) {
|
||||||
@ -54,17 +54,6 @@ export class ManualRedactionService extends GenericService<IManualAddResponse> {
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
async addComment(comment: string, annotationId: string, dossierId: string, fileId: string) {
|
|
||||||
const url = `${this._defaultModelPath}/comment/add/${dossierId}/${fileId}/${annotationId}`;
|
|
||||||
const request = await firstValueFrom(this._post<{ commentId: string }>({ text: comment }, url));
|
|
||||||
return request.commentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteComment(commentId: string, annotationId: string, dossierId: string, fileId: string) {
|
|
||||||
const url = `${this._defaultModelPath}/comment/undo/${dossierId}/${fileId}/${annotationId}/${commentId}`;
|
|
||||||
return firstValueFrom(super.delete({}, url));
|
|
||||||
}
|
|
||||||
|
|
||||||
addRecommendation(annotations: AnnotationWrapper[], redaction: IAddRedactionRequest, dossierId: string, fileId: string) {
|
addRecommendation(annotations: AnnotationWrapper[], redaction: IAddRedactionRequest, dossierId: string, fileId: string) {
|
||||||
const recommendations: List<IAddRedactionRequest> = annotations.map(annotation => ({
|
const recommendations: List<IAddRedactionRequest> = annotations.map(annotation => ({
|
||||||
addToDictionary: redaction.addToDictionary,
|
addToDictionary: redaction.addToDictionary,
|
||||||
|
|||||||
@ -23,13 +23,13 @@ export class PdfAnnotationActionsService {
|
|||||||
readonly #annotationManager = inject(REDAnnotationManager);
|
readonly #annotationManager = inject(REDAnnotationManager);
|
||||||
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
readonly #isDocumine = getConfig().IS_DOCUMINE;
|
||||||
|
|
||||||
get(annotations: AnnotationWrapper[]): IHeaderElement[] {
|
get(annotations: AnnotationWrapper[], annotationChangesAllowed: boolean): IHeaderElement[] {
|
||||||
const availableActions: IHeaderElement[] = [];
|
const availableActions: IHeaderElement[] = [];
|
||||||
const permissions = this.#getAnnotationsPermissions(annotations);
|
const permissions = this.#getAnnotationsPermissions(annotations);
|
||||||
const sameType = annotations.every(a => a.type === annotations[0].type);
|
const sameType = annotations.every(a => a.type === annotations[0].type);
|
||||||
|
|
||||||
// you can only resize one annotation at a time
|
// you can only resize one annotation at a time
|
||||||
if (permissions.canResizeAnnotation) {
|
if (permissions.canResizeAnnotation && annotationChangesAllowed) {
|
||||||
const firstAnnotation = annotations[0];
|
const firstAnnotation = annotations[0];
|
||||||
// if we already entered resize-mode previously
|
// if we already entered resize-mode previously
|
||||||
if (firstAnnotation.id === this.#annotationManager.resizingAnnotationId) {
|
if (firstAnnotation.id === this.#annotationManager.resizingAnnotationId) {
|
||||||
@ -61,11 +61,11 @@ export class PdfAnnotationActionsService {
|
|||||||
permissions.canForceHint ||
|
permissions.canForceHint ||
|
||||||
permissions.canForceRedaction;
|
permissions.canForceRedaction;
|
||||||
const canEdit =
|
const canEdit =
|
||||||
annotations.length > 1
|
(annotations.length > 1
|
||||||
? this.#isDocumine
|
? this.#isDocumine
|
||||||
? permissions.canEditAnnotations
|
? permissions.canEditAnnotations
|
||||||
: permissions.canEditHints || permissions.canEditImages || permissions.canEditAnnotations
|
: permissions.canEditHints || permissions.canEditImages || permissions.canEditAnnotations
|
||||||
: canEditRedactions;
|
: canEditRedactions) && annotationChangesAllowed;
|
||||||
if (canEdit) {
|
if (canEdit) {
|
||||||
const editButton = this.#getButton('edit', _('annotation-actions.edit-redaction.label'), () =>
|
const editButton = this.#getButton('edit', _('annotation-actions.edit-redaction.label'), () =>
|
||||||
this.#annotationActionsService.editRedaction(annotations),
|
this.#annotationActionsService.editRedaction(annotations),
|
||||||
@ -73,28 +73,28 @@ export class PdfAnnotationActionsService {
|
|||||||
availableActions.push(editButton);
|
availableActions.push(editButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (permissions.canAcceptRecommendation) {
|
if (permissions.canAcceptRecommendation && annotationChangesAllowed) {
|
||||||
const acceptRecommendationButton = this.#getButton('check', _('annotation-actions.accept-recommendation.label'), () =>
|
const acceptRecommendationButton = this.#getButton('check', _('annotation-actions.accept-recommendation.label'), () =>
|
||||||
this.#annotationActionsService.convertRecommendationToAnnotation(annotations),
|
this.#annotationActionsService.convertRecommendationToAnnotation(annotations),
|
||||||
);
|
);
|
||||||
availableActions.push(acceptRecommendationButton);
|
availableActions.push(acceptRecommendationButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (permissions.canForceRedaction) {
|
if (permissions.canForceRedaction && annotationChangesAllowed) {
|
||||||
const forceRedactionButton = this.#getButton('thumb-up', _('annotation-actions.force-redaction.label'), () =>
|
const forceRedactionButton = this.#getButton('thumb-up', _('annotation-actions.force-redaction.label'), () =>
|
||||||
this.#annotationActionsService.forceAnnotation(annotations),
|
this.#annotationActionsService.forceAnnotation(annotations),
|
||||||
);
|
);
|
||||||
availableActions.push(forceRedactionButton);
|
availableActions.push(forceRedactionButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (permissions.canForceHint) {
|
if (permissions.canForceHint && annotationChangesAllowed) {
|
||||||
const forceHintButton = this.#getButton('thumb-up', _('annotation-actions.force-hint.label'), () =>
|
const forceHintButton = this.#getButton('thumb-up', _('annotation-actions.force-hint.label'), () =>
|
||||||
this.#annotationActionsService.forceAnnotation(annotations, true),
|
this.#annotationActionsService.forceAnnotation(annotations, true),
|
||||||
);
|
);
|
||||||
availableActions.push(forceHintButton);
|
availableActions.push(forceHintButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (permissions.canRemoveRedaction && sameType) {
|
if (permissions.canRemoveRedaction && sameType && annotationChangesAllowed) {
|
||||||
const removeRedactionButton = this.#getButton('trash', _('annotation-actions.remove-annotation.remove-redaction'), () =>
|
const removeRedactionButton = this.#getButton('trash', _('annotation-actions.remove-annotation.remove-redaction'), () =>
|
||||||
this.#annotationActionsService.removeRedaction(annotations, permissions),
|
this.#annotationActionsService.removeRedaction(annotations, permissions),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -184,13 +184,15 @@ export class PdfProxyService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (this._iqserPermissionsService.has(Roles.redactions.write)) {
|
if (this._iqserPermissionsService.has(Roles.redactions.write)) {
|
||||||
popups.push({
|
if (!(this.#isDocumine && this._state.file().excludedFromAutomaticAnalysis)) {
|
||||||
type: 'actionButton',
|
popups.push({
|
||||||
dataElement: TextPopups.REDACT_TEXT,
|
type: 'actionButton',
|
||||||
img: this.#addRedactionIcon,
|
dataElement: TextPopups.REDACT_TEXT,
|
||||||
title: this.#getTitle(ManualRedactionEntryTypes.REDACT),
|
img: this.#addRedactionIcon,
|
||||||
onClick: () => this._ngZone.run(() => this.#redactText(ManualRedactionEntryTypes.REDACT)),
|
title: this.#getTitle(ManualRedactionEntryTypes.REDACT),
|
||||||
});
|
onClick: () => this._ngZone.run(() => this.#redactText(ManualRedactionEntryTypes.REDACT)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.#isDocumine) {
|
if (!this.#isDocumine) {
|
||||||
popups.push({
|
popups.push({
|
||||||
@ -253,10 +255,6 @@ export class PdfProxyService {
|
|||||||
this._pdf.instance.UI.enableTools([AnnotationToolNames.AnnotationCreateRectangle]);
|
this._pdf.instance.UI.enableTools([AnnotationToolNames.AnnotationCreateRectangle]);
|
||||||
this._pdf.enable(TEXT_POPUPS_TO_TOGGLE);
|
this._pdf.enable(TEXT_POPUPS_TO_TOGGLE);
|
||||||
this._viewerHeaderService.enable(HEADER_ITEMS_TO_TOGGLE);
|
this._viewerHeaderService.enable(HEADER_ITEMS_TO_TOGGLE);
|
||||||
|
|
||||||
if (this._documentViewer.selectedText.length > 2) {
|
|
||||||
this._pdf.enable([TextPopups.REDACT_TEXT, TextPopups.ADD_HINT, TextPopups.ADD_FALSE_POSITIVE]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#getManualRedaction(quads: Record<string, Quad[]>, text?: string, convertQuads = false): IManualRedactionEntry {
|
#getManualRedaction(quads: Record<string, Quad[]>, text?: string, convertQuads = false): IManualRedactionEntry {
|
||||||
@ -355,6 +353,7 @@ export class PdfProxyService {
|
|||||||
|
|
||||||
#configureAnnotationSpecificActions(viewerAnnotations: Annotation[]) {
|
#configureAnnotationSpecificActions(viewerAnnotations: Annotation[]) {
|
||||||
if (!this.canPerformActions()) {
|
if (!this.canPerformActions()) {
|
||||||
|
this._pdf.instance.UI.annotationPopup.update([]);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -390,7 +389,10 @@ export class PdfProxyService {
|
|||||||
actions.push(visibilityButton);
|
actions.push(visibilityButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
actions = this._multiSelectService.inactive() ? [...actions, ...this._pdfAnnotationActionsService.get(annotationWrappers)] : [];
|
const annotationChangesAllowed = !this.#isDocumine || !this._state.file().excludedFromAutomaticAnalysis;
|
||||||
|
actions = this._multiSelectService.inactive()
|
||||||
|
? [...actions, ...this._pdfAnnotationActionsService.get(annotationWrappers, annotationChangesAllowed)]
|
||||||
|
: [];
|
||||||
this._pdf.instance.UI.annotationPopup.update(actions);
|
this._pdf.instance.UI.annotationPopup.update(actions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -359,7 +359,7 @@ export class PdfViewer {
|
|||||||
const options: WebViewerOptions = {
|
const options: WebViewerOptions = {
|
||||||
licenseKey: this.#licenseKey,
|
licenseKey: this.#licenseKey,
|
||||||
fullAPI: true,
|
fullAPI: true,
|
||||||
path: this.#convertPath('/assets/wv-resources'),
|
path: this.#convertPath('/assets/wv-resources/10.9.0'),
|
||||||
css: this.#convertPath('/assets/pdftron/stylesheet.css'),
|
css: this.#convertPath('/assets/pdftron/stylesheet.css'),
|
||||||
backendType: 'ems',
|
backendType: 'ems',
|
||||||
};
|
};
|
||||||
|
|||||||
@ -146,10 +146,10 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit
|
|||||||
hint: [{ value: !!this.entity?.hint, disabled: this.#isSystemManaged }],
|
hint: [{ value: !!this.entity?.hint, disabled: this.#isSystemManaged }],
|
||||||
hasDictionary: [{ value: !!this.entity?.hasDictionary, disabled: this.#isSystemManaged }],
|
hasDictionary: [{ value: !!this.entity?.hasDictionary, disabled: this.#isSystemManaged }],
|
||||||
dossierDictionaryOnly: [{ value: !!this.entity?.dossierDictionaryOnly, disabled: this.#isSystemManaged || this.entity }],
|
dossierDictionaryOnly: [{ value: !!this.entity?.dossierDictionaryOnly, disabled: this.#isSystemManaged || this.entity }],
|
||||||
caseSensitive: [{ value: !!this.entity?.caseInsensitive, disabled: this.#isSystemManaged }],
|
caseSensitive: [{ value: !this.entity?.caseInsensitive, disabled: this.#isSystemManaged }],
|
||||||
manageEntriesInDictionaryEditorOnly: [
|
manageEntriesInDictionaryEditorOnly: [
|
||||||
{
|
{
|
||||||
value: !this.entity?.addToDictionaryAction,
|
value: this.entity?.addToDictionaryAction,
|
||||||
disabled: this.#isSystemManaged && !this.#isDossierRedaction,
|
disabled: this.#isSystemManaged && !this.#isDossierRedaction,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
@ -216,7 +216,7 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit
|
|||||||
|
|
||||||
#formToObject(): IDictionary {
|
#formToObject(): IDictionary {
|
||||||
// Fields which aren't set for hints, need additional check
|
// Fields which aren't set for hints, need additional check
|
||||||
const addToDictionaryAction = !this.form.get('manageEntriesInDictionaryEditorOnly')?.value;
|
const addToDictionaryAction = !!this.form.get('manageEntriesInDictionaryEditorOnly')?.value;
|
||||||
const hasDictionary = !!this.form.get('hasDictionary')?.value;
|
const hasDictionary = !!this.form.get('hasDictionary')?.value;
|
||||||
const dossierDictionaryOnly = !!this.form.get('dossierDictionaryOnly')?.value;
|
const dossierDictionaryOnly = !!this.form.get('dossierDictionaryOnly')?.value;
|
||||||
|
|
||||||
|
|||||||
@ -52,12 +52,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<redaction-watermark-selector
|
<redaction-watermark-selector
|
||||||
|
*ngIf="!config.IS_DOCUMINE"
|
||||||
[dossierTemplateId]="dossierTemplateId"
|
[dossierTemplateId]="dossierTemplateId"
|
||||||
[label]="'dossier-watermark-selector.watermark' | translate"
|
[label]="'dossier-watermark-selector.watermark' | translate"
|
||||||
formControlName="watermarkId"
|
formControlName="watermarkId"
|
||||||
></redaction-watermark-selector>
|
></redaction-watermark-selector>
|
||||||
|
|
||||||
<redaction-watermark-selector
|
<redaction-watermark-selector
|
||||||
|
*ngIf="!config.IS_DOCUMINE"
|
||||||
[dossierTemplateId]="dossierTemplateId"
|
[dossierTemplateId]="dossierTemplateId"
|
||||||
[label]="'dossier-watermark-selector.preview' | translate"
|
[label]="'dossier-watermark-selector.preview' | translate"
|
||||||
formControlName="previewWatermarkId"
|
formControlName="previewWatermarkId"
|
||||||
@ -83,7 +85,7 @@
|
|||||||
<div class="flex">
|
<div class="flex">
|
||||||
<redaction-select
|
<redaction-select
|
||||||
[height]="165"
|
[height]="165"
|
||||||
[label]="'report-type.label' | translate : { length: reportTemplateIdsLength }"
|
[label]="'report-type.label' | translate: { length: reportTemplateIdsLength }"
|
||||||
[optionTemplate]="reportTemplateOptionTemplate"
|
[optionTemplate]="reportTemplateOptionTemplate"
|
||||||
[options]="availableReportTypes"
|
[options]="availableReportTypes"
|
||||||
[valueMapper]="reportTemplateValueMapper"
|
[valueMapper]="reportTemplateValueMapper"
|
||||||
@ -94,7 +96,7 @@
|
|||||||
<redaction-select
|
<redaction-select
|
||||||
*deny="roles.getRss"
|
*deny="roles.getRss"
|
||||||
[height]="165"
|
[height]="165"
|
||||||
[label]="'download-type.label' | translate : { length: downloadFileTypesLength }"
|
[label]="'download-type.label' | translate: { length: downloadFileTypesLength }"
|
||||||
[options]="downloadTypes"
|
[options]="downloadTypes"
|
||||||
formControlName="downloadFileTypes"
|
formControlName="downloadFileTypes"
|
||||||
></redaction-select>
|
></redaction-select>
|
||||||
|
|||||||
28
apps/red-ui/src/app/services/comments-api.service.ts
Normal file
28
apps/red-ui/src/app/services/comments-api.service.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { Injectable, signal } from '@angular/core';
|
||||||
|
import { GenericService } from '@common-ui/services/generic.service';
|
||||||
|
import { IComment } from '@red/domain';
|
||||||
|
import { firstValueFrom, map } from 'rxjs';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class CommentsApiService extends GenericService<IComment> {
|
||||||
|
protected readonly _defaultModelPath = 'manualRedaction';
|
||||||
|
readonly comments = signal<Record<string, IComment[]>>({});
|
||||||
|
|
||||||
|
async add(comment: string, annotationId: string, dossierId: string, fileId: string) {
|
||||||
|
const url = `${this._defaultModelPath}/comment/add/${dossierId}/${fileId}/${annotationId}`;
|
||||||
|
const request = await firstValueFrom(this._post<{ commentId: string }>({ text: comment }, url));
|
||||||
|
return request.commentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(commentId: string, annotationId: string, dossierId: string, fileId: string) {
|
||||||
|
const url = `${this._defaultModelPath}/comment/undo/${dossierId}/${fileId}/${annotationId}/${commentId}`;
|
||||||
|
return firstValueFrom(super.delete({}, url));
|
||||||
|
}
|
||||||
|
|
||||||
|
fetch(dossierId: string, fileId: string, annotationId: string): Promise<IComment[]> {
|
||||||
|
const url = `${this._defaultModelPath}/comments/${dossierId}/${fileId}/${annotationId}`;
|
||||||
|
return firstValueFrom(super.getAll<{ comments: IComment[] }>(url).pipe(map(res => res.comments)));
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -12,7 +12,6 @@ import { DossierDictionariesMapService } from '@services/entity-services/dossier
|
|||||||
import { List } from '@iqser/common-ui/lib/utils';
|
import { List } from '@iqser/common-ui/lib/utils';
|
||||||
import { IMAGE_CATEGORIES } from '../../modules/file-preview/utils/constants';
|
import { IMAGE_CATEGORIES } from '../../modules/file-preview/utils/constants';
|
||||||
|
|
||||||
const MIN_WORD_LENGTH = 2;
|
|
||||||
const IMAGE_TYPES = ['image', 'formula', 'ocr'];
|
const IMAGE_TYPES = ['image', 'formula', 'ocr'];
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
@ -100,20 +99,13 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
|||||||
) {
|
) {
|
||||||
const entriesToAdd: Array<string> = [];
|
const entriesToAdd: Array<string> = [];
|
||||||
const initialEntriesSet = new Set(initialEntries);
|
const initialEntriesSet = new Set(initialEntries);
|
||||||
let hasInvalidRows = false;
|
|
||||||
for (let i = 0; i < entries.length; i++) {
|
for (let i = 0; i < entries.length; i++) {
|
||||||
const entry = entries.at(i);
|
const entry = entries.at(i);
|
||||||
if (!entry.trim() || initialEntriesSet.has(entry)) {
|
if (!entry.trim() || initialEntriesSet.has(entry)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
hasInvalidRows ||= entry.length < MIN_WORD_LENGTH;
|
|
||||||
entriesToAdd.push(entry);
|
entriesToAdd.push(entry);
|
||||||
}
|
}
|
||||||
if (hasInvalidRows) {
|
|
||||||
this._toaster.error(_('dictionary-overview.error.entries-too-short'));
|
|
||||||
|
|
||||||
throw new Error('Entries too short');
|
|
||||||
}
|
|
||||||
const deletedEntries: Array<string> = [];
|
const deletedEntries: Array<string> = [];
|
||||||
const entriesSet = new Set(entries);
|
const entriesSet = new Set(entries);
|
||||||
for (let i = 0; i < initialEntries.length; i++) {
|
for (let i = 0; i < initialEntries.length; i++) {
|
||||||
@ -260,7 +252,15 @@ export class DictionaryService extends EntitiesService<IDictionary, Dictionary>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!manualTypeExists) {
|
if (!manualTypeExists) {
|
||||||
dictionaries.push(new Dictionary({ hexColor: FALLBACK_COLOR, type: SuperTypes.ManualRedaction }, true));
|
dictionaries.push(
|
||||||
|
new Dictionary(
|
||||||
|
{
|
||||||
|
hexColor: FALLBACK_COLOR,
|
||||||
|
type: SuperTypes.ManualRedaction,
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return dictionaries;
|
return dictionaries;
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { catchError, map, tap } from 'rxjs/operators';
|
|||||||
import { Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { HttpHeaders } from '@angular/common/http';
|
import { HttpHeaders } from '@angular/common/http';
|
||||||
import { saveAs } from 'file-saver';
|
import { saveAs } from 'file-saver';
|
||||||
import { ComponentDetails, ComponentLogEntry, IComponentLogData, IComponentLogEntry } from '@red/domain';
|
import { ComponentDetails, ComponentLogEntry, IComponentLogData, IComponentLogEntry, IFile } from '@red/domain';
|
||||||
import { mapEach } from '@common-ui/utils';
|
import { mapEach } from '@common-ui/utils';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
@ -25,6 +25,15 @@ export class ComponentLogService extends GenericService<void> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#bulkComponentLogRequest(dossierTemplateId: string, dossierId: string, includeDetails = false): Observable<IComponentLogData> {
|
||||||
|
return this._http.get<IComponentLogData>(
|
||||||
|
`/api/dossier-templates/${dossierTemplateId}/dossiers/${dossierId}/files/bulk/get-components`,
|
||||||
|
{
|
||||||
|
params: { includeDetails },
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
getComponentLogData(dossierTemplateId: string, dossierId: string, fileId: string): Observable<ComponentLogEntry[]> {
|
getComponentLogData(dossierTemplateId: string, dossierId: string, fileId: string): Observable<ComponentLogEntry[]> {
|
||||||
return this.#componentLogRequest(dossierTemplateId, dossierId, fileId).pipe(
|
return this.#componentLogRequest(dossierTemplateId, dossierId, fileId).pipe(
|
||||||
map(data => data.componentDetails),
|
map(data => data.componentDetails),
|
||||||
@ -42,29 +51,34 @@ export class ComponentLogService extends GenericService<void> {
|
|||||||
return this._post({ components }, `componentLog/override/revert/${dossierId}/${fileId}`);
|
return this._post({ components }, `componentLog/override/revert/${dossierId}/${fileId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
exportJSON(dossierTemplateId: string, dossierId: string, fileId: string, name: string): Observable<IComponentLogData> {
|
exportJSON(dossierTemplateId: string, dossierId: string, file?: IFile): Observable<IComponentLogData> {
|
||||||
return this.#componentLogRequest(dossierTemplateId, dossierId, fileId, false).pipe(
|
const request$ = file?.fileId
|
||||||
|
? this.#componentLogRequest(dossierTemplateId, dossierId, file?.fileId, false)
|
||||||
|
: this.#bulkComponentLogRequest(dossierTemplateId, dossierId);
|
||||||
|
return request$.pipe(
|
||||||
tap(data => {
|
tap(data => {
|
||||||
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
|
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
|
||||||
saveAs(blob, name + '.component_log.json');
|
saveAs(blob, (file?.filename ? `${file.filename}.` : '') + 'component_log.json');
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
exportXML(dossierTemplateId, dossierId: string, fileId: string, name: string): Observable<string> {
|
exportXML(dossierTemplateId, dossierId: string, file?: IFile): Observable<string> {
|
||||||
return this.#getComponentLogDataAsXML(dossierTemplateId, dossierId, fileId).pipe(
|
return this.#getComponentLogDataAsXML(dossierTemplateId, dossierId, file).pipe(
|
||||||
tap(data => {
|
tap(data => {
|
||||||
const blob = new Blob([data], { type: 'application/xml' });
|
const blob = new Blob([data], { type: 'application/xml' });
|
||||||
saveAs(blob, name + '.component_log.xml');
|
saveAs(blob, (file?.filename ? `${file.filename}.` : '') + 'component_log.xml');
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#getComponentLogDataAsXML(dossierTemplateId: string, dossierId: string, fileId: string) {
|
#getComponentLogDataAsXML(dossierTemplateId: string, dossierId: string, file?: IFile) {
|
||||||
let headers = new HttpHeaders();
|
let headers = new HttpHeaders();
|
||||||
headers = headers.set('accept', 'application/xml');
|
headers = headers.set('accept', 'application/xml');
|
||||||
|
|
||||||
return this._http.get(`/api/dossier-templates/${dossierTemplateId}/dossiers/${dossierId}/files/${fileId}/components`, {
|
const pathSuffix = file?.fileId ? `${file.fileId}/components` : 'bulk/get-components';
|
||||||
|
|
||||||
|
return this._http.get(`/api/dossier-templates/${dossierTemplateId}/dossiers/${dossierId}/files/${pathSuffix}`, {
|
||||||
headers: headers,
|
headers: headers,
|
||||||
responseType: 'text',
|
responseType: 'text',
|
||||||
observe: 'body',
|
observe: 'body',
|
||||||
|
|||||||
@ -1,13 +1,15 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { inject, Injectable } from '@angular/core';
|
||||||
import { GenericService, QueryParam } from '@iqser/common-ui';
|
import { GenericService, isIqserDevMode, QueryParam, Toaster } from '@iqser/common-ui';
|
||||||
import { IRedactionLog, ISectionGrid } from '@red/domain';
|
import { IRedactionLog, ISectionGrid } from '@red/domain';
|
||||||
import { catchError } from 'rxjs/operators';
|
|
||||||
import { firstValueFrom, of } from 'rxjs';
|
import { firstValueFrom, of } from 'rxjs';
|
||||||
|
import { catchError } from 'rxjs/operators';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class RedactionLogService extends GenericService<unknown> {
|
export class RedactionLogService extends GenericService<unknown> {
|
||||||
|
readonly #isIqserDevMode = isIqserDevMode();
|
||||||
|
readonly #toaster = inject(Toaster);
|
||||||
protected readonly _defaultModelPath = '';
|
protected readonly _defaultModelPath = '';
|
||||||
|
|
||||||
async getRedactionLog(dossierId: string, fileId: string, withManualRedactions?: boolean) {
|
async getRedactionLog(dossierId: string, fileId: string, withManualRedactions?: boolean) {
|
||||||
@ -18,6 +20,18 @@ export class RedactionLogService extends GenericService<unknown> {
|
|||||||
|
|
||||||
const redactionLog$ = this._getOne<IRedactionLog>([dossierId, fileId], 'redactionLog', queryParams);
|
const redactionLog$ = this._getOne<IRedactionLog>([dossierId, fileId], 'redactionLog', queryParams);
|
||||||
const redactionLog = await firstValueFrom(redactionLog$.pipe(catchError(() => of({} as IRedactionLog))));
|
const redactionLog = await firstValueFrom(redactionLog$.pipe(catchError(() => of({} as IRedactionLog))));
|
||||||
|
redactionLog.redactionLogEntry = redactionLog.redactionLogEntry.filter(entry => {
|
||||||
|
const hasPositions = entry.positions && entry.positions.length;
|
||||||
|
if (!hasPositions && this.#isIqserDevMode) {
|
||||||
|
this.#toaster.info(`Entry ${entry.id} was skipped because has no positions`, {
|
||||||
|
timeOut: 10000,
|
||||||
|
easing: 'ease-in-out',
|
||||||
|
easeTime: 500,
|
||||||
|
useRaw: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return hasPositions;
|
||||||
|
});
|
||||||
redactionLog.redactionLogEntry.sort((a, b) => a.positions[0].page - b.positions[0].page);
|
redactionLog.redactionLogEntry.sort((a, b) => a.positions[0].page - b.positions[0].page);
|
||||||
return redactionLog;
|
return redactionLog;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -341,7 +341,7 @@ export class PermissionsService {
|
|||||||
canDeleteComment(comment: IComment, file: File, dossier: Dossier) {
|
canDeleteComment(comment: IComment, file: File, dossier: Dossier) {
|
||||||
return (
|
return (
|
||||||
this._iqserPermissionsService.has(Roles.comments.delete) &&
|
this._iqserPermissionsService.has(Roles.comments.delete) &&
|
||||||
(comment.user === this.#userId || this.isApprover(dossier)) &&
|
(comment.userId === this.#userId || this.isApprover(dossier)) &&
|
||||||
!file.isApproved
|
!file.isApproved
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -407,7 +407,11 @@ export class PermissionsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#canReanalyseFile(file: File, dossier: Dossier): boolean {
|
#canReanalyseFile(file: File, dossier: Dossier): boolean {
|
||||||
return dossier.isActive && this.isAssigneeOrApprover(file, dossier) && file.analysisRequired;
|
return (
|
||||||
|
dossier.isActive &&
|
||||||
|
((this.isAssigneeOrApprover(file, dossier) && file.analysisRequired) ||
|
||||||
|
(file.isError && (this.isOwner(dossier) || this.isFileAssignee(file))))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#canEnableAutoAnalysis(file: File, dossier: Dossier): boolean {
|
#canEnableAutoAnalysis(file: File, dossier: Dossier): boolean {
|
||||||
|
|||||||
@ -616,5 +616,9 @@
|
|||||||
{
|
{
|
||||||
"elementKey": "editor_exclude_pages",
|
"elementKey": "editor_exclude_pages",
|
||||||
"documentKey": "editor_exclude_pages"
|
"documentKey": "editor_exclude_pages"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"elementKey": "component_download",
|
||||||
|
"documentKey": "component_download"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -56,8 +56,7 @@
|
|||||||
},
|
},
|
||||||
"add-edit-clone-dossier-template": {
|
"add-edit-clone-dossier-template": {
|
||||||
"error": {
|
"error": {
|
||||||
"conflict": "Dossiervorlage konnte nicht erstellt werden: Es existiert bereits eine Dossiervorlage mit demselben Namen.",
|
"conflict": "Dossiervorlage konnte nicht erstellt werden: Es existiert bereits eine Dossiervorlage mit demselben Namen."
|
||||||
"generic": "Fehler beim Erstellen der Dossiervorlage."
|
|
||||||
},
|
},
|
||||||
"form": {
|
"form": {
|
||||||
"apply-updates-default": {
|
"apply-updates-default": {
|
||||||
@ -134,7 +133,7 @@
|
|||||||
"dossier-dictionary-only": "Dossier dictionary only",
|
"dossier-dictionary-only": "Dossier dictionary only",
|
||||||
"has-dictionary": "Has dictionary",
|
"has-dictionary": "Has dictionary",
|
||||||
"hint": "Hint",
|
"hint": "Hint",
|
||||||
"manage-entries-in-dictionary-editor-only": "Manage entries in Dictionary editor only",
|
"manage-entries-in-dictionary-editor-only": "Available in add/remove dialogs",
|
||||||
"name": "Display Name",
|
"name": "Display Name",
|
||||||
"name-placeholder": "Enter Name",
|
"name-placeholder": "Enter Name",
|
||||||
"rank": "Rank",
|
"rank": "Rank",
|
||||||
@ -256,9 +255,6 @@
|
|||||||
"user-management": "User Management",
|
"user-management": "User Management",
|
||||||
"watermarks": "Watermarks"
|
"watermarks": "Watermarks"
|
||||||
},
|
},
|
||||||
"annotation": {
|
|
||||||
"pending": "(Pending Analysis)"
|
|
||||||
},
|
|
||||||
"annotation-actions": {
|
"annotation-actions": {
|
||||||
"accept-recommendation": {
|
"accept-recommendation": {
|
||||||
"label": "Empfehlung annehmen"
|
"label": "Empfehlung annehmen"
|
||||||
@ -341,14 +337,14 @@
|
|||||||
"error": "Rekategorisierung des Bildes gescheitert: {error}",
|
"error": "Rekategorisierung des Bildes gescheitert: {error}",
|
||||||
"success": "Bild wurde einer neuen Kategorie zugeordnet."
|
"success": "Bild wurde einer neuen Kategorie zugeordnet."
|
||||||
},
|
},
|
||||||
"remove": {
|
|
||||||
"error": "Fehler beim Entfernen der Schwärzung: {error}",
|
|
||||||
"success": "Schwärzung entfernt!"
|
|
||||||
},
|
|
||||||
"remove-hint": {
|
"remove-hint": {
|
||||||
"error": "Failed to remove hint: {error}",
|
"error": "Failed to remove hint: {error}",
|
||||||
"success": "Hint removed!"
|
"success": "Hint removed!"
|
||||||
},
|
},
|
||||||
|
"remove": {
|
||||||
|
"error": "Fehler beim Entfernen der Schwärzung: {error}",
|
||||||
|
"success": "Schwärzung entfernt!"
|
||||||
|
},
|
||||||
"request-change-legal-basis": {
|
"request-change-legal-basis": {
|
||||||
"error": "Fehler beim Vorschlagen der Änderung der Begründung:",
|
"error": "Fehler beim Vorschlagen der Änderung der Begründung:",
|
||||||
"success": "Die Änderung der in der Anmerkung genannten Begründung wurde beantragt."
|
"success": "Die Änderung der in der Anmerkung genannten Begründung wurde beantragt."
|
||||||
@ -365,14 +361,14 @@
|
|||||||
"error": "Fehler beim Vorschlagen der Neukategorisierung des Bilds: {error}",
|
"error": "Fehler beim Vorschlagen der Neukategorisierung des Bilds: {error}",
|
||||||
"success": "Bild-Neuklassifizierung angefordert."
|
"success": "Bild-Neuklassifizierung angefordert."
|
||||||
},
|
},
|
||||||
"request-remove": {
|
|
||||||
"error": "Fehler beim Erstellen des Vorschlags für das Entfernen der Schwärzung: {error}",
|
|
||||||
"success": "Entfernen der Schwärzung wurde vorgeschlagen!"
|
|
||||||
},
|
|
||||||
"request-remove-hint": {
|
"request-remove-hint": {
|
||||||
"error": "Failed to request removal of hint: {error}",
|
"error": "Failed to request removal of hint: {error}",
|
||||||
"success": "Requested to remove hint!"
|
"success": "Requested to remove hint!"
|
||||||
},
|
},
|
||||||
|
"request-remove": {
|
||||||
|
"error": "Fehler beim Erstellen des Vorschlags für das Entfernen der Schwärzung: {error}",
|
||||||
|
"success": "Entfernen der Schwärzung wurde vorgeschlagen!"
|
||||||
|
},
|
||||||
"suggest": {
|
"suggest": {
|
||||||
"error": "Vorschlag einer Schwärzung wurde nicht gespeichert: {error}",
|
"error": "Vorschlag einer Schwärzung wurde nicht gespeichert: {error}",
|
||||||
"success": "Vorschlag einer Schwärzung gespeichert"
|
"success": "Vorschlag einer Schwärzung gespeichert"
|
||||||
@ -389,15 +385,15 @@
|
|||||||
"remove-highlights": {
|
"remove-highlights": {
|
||||||
"label": "Remove Selected Earmarks"
|
"label": "Remove Selected Earmarks"
|
||||||
},
|
},
|
||||||
"resize": {
|
|
||||||
"label": "Größe ändern"
|
|
||||||
},
|
|
||||||
"resize-accept": {
|
"resize-accept": {
|
||||||
"label": "Größe speichern"
|
"label": "Größe speichern"
|
||||||
},
|
},
|
||||||
"resize-cancel": {
|
"resize-cancel": {
|
||||||
"label": "Größenänderung abbrechen"
|
"label": "Größenänderung abbrechen"
|
||||||
},
|
},
|
||||||
|
"resize": {
|
||||||
|
"label": "Größe ändern"
|
||||||
|
},
|
||||||
"see-references": {
|
"see-references": {
|
||||||
"label": "See References"
|
"label": "See References"
|
||||||
},
|
},
|
||||||
@ -439,6 +435,9 @@
|
|||||||
"suggestion-resize": "Vorgeschlagene Größenänderung",
|
"suggestion-resize": "Vorgeschlagene Größenänderung",
|
||||||
"text-highlight": "Earmark"
|
"text-highlight": "Earmark"
|
||||||
},
|
},
|
||||||
|
"annotation": {
|
||||||
|
"pending": "(Pending Analysis)"
|
||||||
|
},
|
||||||
"archived-dossiers-listing": {
|
"archived-dossiers-listing": {
|
||||||
"no-data": {
|
"no-data": {
|
||||||
"title": "No archived dossiers."
|
"title": "No archived dossiers."
|
||||||
@ -558,10 +557,17 @@
|
|||||||
"title": "Aktion bestätigen"
|
"title": "Aktion bestätigen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"component-download": {
|
||||||
|
"disabled-tooltip": "",
|
||||||
|
"json": "",
|
||||||
|
"tooltip": "",
|
||||||
|
"xml": ""
|
||||||
|
},
|
||||||
"component-log-dialog": {
|
"component-log-dialog": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"cancel-edit": "Cancel",
|
"cancel-edit": "Cancel",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
|
"disabled-edit": "",
|
||||||
"display-by-default": "Display by default when opening documents",
|
"display-by-default": "Display by default when opening documents",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"export-json": "Export JSON",
|
"export-json": "Export JSON",
|
||||||
@ -638,18 +644,14 @@
|
|||||||
"warning": "Achtung: Diese Aktion kann nicht rückgängig gemacht werden!"
|
"warning": "Achtung: Diese Aktion kann nicht rückgängig gemacht werden!"
|
||||||
},
|
},
|
||||||
"confirmation-dialog": {
|
"confirmation-dialog": {
|
||||||
"approve-file": {
|
|
||||||
"question": "Dieses Dokument enthält ungesehene Änderungen. Möchten Sie es trotzdem genehmigen?",
|
|
||||||
"title": "Warnung!"
|
|
||||||
},
|
|
||||||
"approve-file-without-analysis": {
|
"approve-file-without-analysis": {
|
||||||
"confirmationText": "Approve without analysis",
|
"confirmationText": "Approve without analysis",
|
||||||
"denyText": "Cancel",
|
"denyText": "Cancel",
|
||||||
"question": "Analysis required to detect new redactions.",
|
"question": "Analysis required to detect new redactions.",
|
||||||
"title": "Warning!"
|
"title": "Warning!"
|
||||||
},
|
},
|
||||||
"approve-multiple-files": {
|
"approve-file": {
|
||||||
"question": "Mindestens eine der ausgewählten Dateien enthält ungesehene Änderungen. Möchten Sie sie trotzdem genehmigen?",
|
"question": "Dieses Dokument enthält ungesehene Änderungen. Möchten Sie es trotzdem genehmigen?",
|
||||||
"title": "Warnung!"
|
"title": "Warnung!"
|
||||||
},
|
},
|
||||||
"approve-multiple-files-without-analysis": {
|
"approve-multiple-files-without-analysis": {
|
||||||
@ -658,6 +660,10 @@
|
|||||||
"question": "Analysis required to detect new redactions for at least one file.",
|
"question": "Analysis required to detect new redactions for at least one file.",
|
||||||
"title": "Warning"
|
"title": "Warning"
|
||||||
},
|
},
|
||||||
|
"approve-multiple-files": {
|
||||||
|
"question": "Mindestens eine der ausgewählten Dateien enthält ungesehene Änderungen. Möchten Sie sie trotzdem genehmigen?",
|
||||||
|
"title": "Warnung!"
|
||||||
|
},
|
||||||
"assign-file-to-me": {
|
"assign-file-to-me": {
|
||||||
"question": {
|
"question": {
|
||||||
"multiple": "Dieses Dokument wird gerade von einer anderen Person geprüft. Möchten Sie Reviewer werden und sich selbst dem Dokument zuweisen?",
|
"multiple": "Dieses Dokument wird gerade von einer anderen Person geprüft. Möchten Sie Reviewer werden und sich selbst dem Dokument zuweisen?",
|
||||||
@ -758,7 +764,6 @@
|
|||||||
"download": "Download current entries",
|
"download": "Download current entries",
|
||||||
"error": {
|
"error": {
|
||||||
"400": "Cannot update dictionary because at least one of the newly added words where recognized as a general term that appear too often in texts.",
|
"400": "Cannot update dictionary because at least one of the newly added words where recognized as a general term that appear too often in texts.",
|
||||||
"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!"
|
"generic": "Es ist ein Fehler aufgetreten ... Das Wörterbuch konnte nicht aktualisiert werden!"
|
||||||
},
|
},
|
||||||
"revert-changes": "Rückgängig machen",
|
"revert-changes": "Rückgängig machen",
|
||||||
@ -1003,13 +1008,13 @@
|
|||||||
"recent": "Neu ({hours} h)",
|
"recent": "Neu ({hours} h)",
|
||||||
"unassigned": "Niemandem zugewiesen"
|
"unassigned": "Niemandem zugewiesen"
|
||||||
},
|
},
|
||||||
"reanalyse": {
|
|
||||||
"action": "Datei analysieren"
|
|
||||||
},
|
|
||||||
"reanalyse-dossier": {
|
"reanalyse-dossier": {
|
||||||
"error": "Die Dateien konnten nicht für eine Reanalyse eingeplant werden. Bitte versuchen Sie es erneut.",
|
"error": "Die Dateien konnten nicht für eine Reanalyse eingeplant werden. Bitte versuchen Sie es erneut.",
|
||||||
"success": "Dateien für Reanalyse vorgesehen."
|
"success": "Dateien für Reanalyse vorgesehen."
|
||||||
},
|
},
|
||||||
|
"reanalyse": {
|
||||||
|
"action": "Datei analysieren"
|
||||||
|
},
|
||||||
"start-auto-analysis": "Enable auto-analysis",
|
"start-auto-analysis": "Enable auto-analysis",
|
||||||
"stop-auto-analysis": "Stop auto-analysis",
|
"stop-auto-analysis": "Stop auto-analysis",
|
||||||
"table-col-names": {
|
"table-col-names": {
|
||||||
@ -1078,14 +1083,6 @@
|
|||||||
"total-documents": "Anzahl der Dokumente",
|
"total-documents": "Anzahl der Dokumente",
|
||||||
"total-people": "<strong>{count}</strong> {count, plural, one{User} other {Users}}"
|
"total-people": "<strong>{count}</strong> {count, plural, one{User} other {Users}}"
|
||||||
},
|
},
|
||||||
"dossier-templates": {
|
|
||||||
"label": "Dossier-Vorlagen",
|
|
||||||
"status": {
|
|
||||||
"active": "Active",
|
|
||||||
"inactive": "Inactive",
|
|
||||||
"incomplete": "Incomplete"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dossier-templates-listing": {
|
"dossier-templates-listing": {
|
||||||
"action": {
|
"action": {
|
||||||
"clone": "Clone Template",
|
"clone": "Clone Template",
|
||||||
@ -1121,6 +1118,14 @@
|
|||||||
"title": "{length} {length, plural, one{Dossier-Vorlage} other{Dossier-Vorlagen}}"
|
"title": "{length} {length, plural, one{Dossier-Vorlage} other{Dossier-Vorlagen}}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dossier-templates": {
|
||||||
|
"label": "Dossier-Vorlagen",
|
||||||
|
"status": {
|
||||||
|
"active": "Active",
|
||||||
|
"inactive": "Inactive",
|
||||||
|
"incomplete": "Incomplete"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dossier-watermark-selector": {
|
"dossier-watermark-selector": {
|
||||||
"heading": "Watermarks on documents",
|
"heading": "Watermarks on documents",
|
||||||
"no-watermark": "There is no watermark defined for the dossier template.<br>Contact your app admin to define one.",
|
"no-watermark": "There is no watermark defined for the dossier template.<br>Contact your app admin to define one.",
|
||||||
@ -1304,15 +1309,6 @@
|
|||||||
"title": "{length} {length, plural, one{Wörterbuch} other{Wörterbücher}}"
|
"title": "{length} {length, plural, one{Wörterbuch} other{Wörterbücher}}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"entity": {
|
|
||||||
"info": {
|
|
||||||
"actions": {
|
|
||||||
"revert": "Revert",
|
|
||||||
"save": "Save Changes"
|
|
||||||
},
|
|
||||||
"heading": "Edit Entity"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"entity-rules-screen": {
|
"entity-rules-screen": {
|
||||||
"error": {
|
"error": {
|
||||||
"generic": "Something went wrong... Entity rules update failed!"
|
"generic": "Something went wrong... Entity rules update failed!"
|
||||||
@ -1326,19 +1322,28 @@
|
|||||||
"title": "Entity Rule Editor",
|
"title": "Entity Rule Editor",
|
||||||
"warning-text": "Warning: experimental feature!"
|
"warning-text": "Warning: experimental feature!"
|
||||||
},
|
},
|
||||||
|
"entity": {
|
||||||
|
"info": {
|
||||||
|
"actions": {
|
||||||
|
"revert": "Revert",
|
||||||
|
"save": "Save Changes"
|
||||||
|
},
|
||||||
|
"heading": "Edit Entity"
|
||||||
|
}
|
||||||
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"deleted-entity": {
|
"deleted-entity": {
|
||||||
"dossier": {
|
"dossier": {
|
||||||
"action": "Zurück zur Übersicht",
|
"action": "Zurück zur Übersicht",
|
||||||
"label": "Dieses Dossier wurde gelöscht!"
|
"label": "Dieses Dossier wurde gelöscht!"
|
||||||
},
|
},
|
||||||
"file": {
|
|
||||||
"action": "Zurück zum Dossier",
|
|
||||||
"label": "Diese Datei wurde gelöscht!"
|
|
||||||
},
|
|
||||||
"file-dossier": {
|
"file-dossier": {
|
||||||
"action": "Zurück zur Übersicht",
|
"action": "Zurück zur Übersicht",
|
||||||
"label": "Das Dossier dieser Datei wurde gelöscht!"
|
"label": "Das Dossier dieser Datei wurde gelöscht!"
|
||||||
|
},
|
||||||
|
"file": {
|
||||||
|
"action": "Zurück zum Dossier",
|
||||||
|
"label": "Diese Datei wurde gelöscht!"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"file-preview": {
|
"file-preview": {
|
||||||
@ -1356,12 +1361,6 @@
|
|||||||
},
|
},
|
||||||
"exact-date": "{day} {month} {year} um {hour}:{minute} Uhr",
|
"exact-date": "{day} {month} {year} um {hour}:{minute} Uhr",
|
||||||
"file": "Datei",
|
"file": "Datei",
|
||||||
"file-attribute": {
|
|
||||||
"update": {
|
|
||||||
"error": "Failed to update file attribute value!",
|
|
||||||
"success": "File attribute value has been updated successfully!"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"file-attribute-encoding-types": {
|
"file-attribute-encoding-types": {
|
||||||
"ascii": "ASCII",
|
"ascii": "ASCII",
|
||||||
"iso": "ISO-8859-1",
|
"iso": "ISO-8859-1",
|
||||||
@ -1372,6 +1371,12 @@
|
|||||||
"number": "Nummer",
|
"number": "Nummer",
|
||||||
"text": "Freier Text"
|
"text": "Freier Text"
|
||||||
},
|
},
|
||||||
|
"file-attribute": {
|
||||||
|
"update": {
|
||||||
|
"error": "Failed to update file attribute value!",
|
||||||
|
"success": "File attribute value has been updated successfully!"
|
||||||
|
}
|
||||||
|
},
|
||||||
"file-attributes-configurations": {
|
"file-attributes-configurations": {
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
"form": {
|
"form": {
|
||||||
@ -1585,6 +1590,15 @@
|
|||||||
"csv": "File attributes were imported successfully from uploaded CSV file."
|
"csv": "File attributes were imported successfully from uploaded CSV file."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"filter-menu": {
|
||||||
|
"filter-options": "Filteroptionen",
|
||||||
|
"filter-types": "Filter",
|
||||||
|
"label": "Filter",
|
||||||
|
"pages-without-annotations": "Only pages without annotations",
|
||||||
|
"redaction-changes": "Nur Anmerkungen mit Schwärzungsänderungen",
|
||||||
|
"unseen-pages": "Nur Anmerkungen auf unsichtbaren Seiten",
|
||||||
|
"with-comments": "Nur Anmerkungen mit Kommentaren"
|
||||||
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"analysis": "Analyse erforderlich",
|
"analysis": "Analyse erforderlich",
|
||||||
"comment": "Kommentare",
|
"comment": "Kommentare",
|
||||||
@ -1595,15 +1609,6 @@
|
|||||||
"suggestion": "Vorgeschlagene Schwärzung",
|
"suggestion": "Vorgeschlagene Schwärzung",
|
||||||
"updated": "Aktualisiert"
|
"updated": "Aktualisiert"
|
||||||
},
|
},
|
||||||
"filter-menu": {
|
|
||||||
"filter-options": "Filteroptionen",
|
|
||||||
"filter-types": "Filter",
|
|
||||||
"label": "Filter",
|
|
||||||
"pages-without-annotations": "Only pages without annotations",
|
|
||||||
"redaction-changes": "Nur Anmerkungen mit Schwärzungsänderungen",
|
|
||||||
"unseen-pages": "Nur Anmerkungen auf unsichtbaren Seiten",
|
|
||||||
"with-comments": "Nur Anmerkungen mit Kommentaren"
|
|
||||||
},
|
|
||||||
"filters": {
|
"filters": {
|
||||||
"assigned-people": "Beauftragt",
|
"assigned-people": "Beauftragt",
|
||||||
"documents-status": "Documents State",
|
"documents-status": "Documents State",
|
||||||
@ -1671,13 +1676,6 @@
|
|||||||
},
|
},
|
||||||
"title": "SMTP-Konto konfigurieren"
|
"title": "SMTP-Konto konfigurieren"
|
||||||
},
|
},
|
||||||
"generic-errors": {
|
|
||||||
"400": "The sent request is not valid.",
|
|
||||||
"403": "Access to the requested resource is not allowed.",
|
|
||||||
"404": "The requested resource could not be found.",
|
|
||||||
"409": "The request is incompatible with the current state.",
|
|
||||||
"500": "The server encountered an unexpected condition that prevented it from fulfilling the request."
|
|
||||||
},
|
|
||||||
"help-mode": {
|
"help-mode": {
|
||||||
"bottom-text": "Hilfe-Modus",
|
"bottom-text": "Hilfe-Modus",
|
||||||
"button-text": "Help Mode (H)",
|
"button-text": "Help Mode (H)",
|
||||||
@ -1789,14 +1787,6 @@
|
|||||||
"copyright-claim-text": "Copyright © 2020 - {currentYear} knecon",
|
"copyright-claim-text": "Copyright © 2020 - {currentYear} knecon",
|
||||||
"copyright-claim-title": "Copyright",
|
"copyright-claim-title": "Copyright",
|
||||||
"custom-app-title": "Name der Anwendung",
|
"custom-app-title": "Name der Anwendung",
|
||||||
"email": {
|
|
||||||
"body": {
|
|
||||||
"analyzed": "Im aktuellen Lizenzzeitraum insgesamt analysierte Seiten: {pages}.",
|
|
||||||
"licensed": "Lizenzierte Seiten: {pages}."
|
|
||||||
},
|
|
||||||
"title": "Lizenzbericht {licenseCustomer}"
|
|
||||||
},
|
|
||||||
"email-report": "E-Mail-Bericht",
|
|
||||||
"end-user-license-text": "Die Nutzung dieses Produkts unterliegt den Bedingungen der Endbenutzer-Lizenzvereinbarung für den RedactManager, sofern darin nichts anderweitig festgelegt.",
|
"end-user-license-text": "Die Nutzung dieses Produkts unterliegt den Bedingungen der Endbenutzer-Lizenzvereinbarung für den RedactManager, sofern darin nichts anderweitig festgelegt.",
|
||||||
"end-user-license-title": "Endbenutzer-Lizenzvereinbarung",
|
"end-user-license-title": "Endbenutzer-Lizenzvereinbarung",
|
||||||
"licensing-details": {
|
"licensing-details": {
|
||||||
@ -1889,13 +1879,6 @@
|
|||||||
"user-promoted-to-approver": "<b>{user}</b> wurde im Dossier <b>{dossierHref, select, null{{dossierName}} other{<a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a>}}</b> zum Genehmiger ernannt!",
|
"user-promoted-to-approver": "<b>{user}</b> wurde im Dossier <b>{dossierHref, select, null{{dossierName}} other{<a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a>}}</b> zum Genehmiger ernannt!",
|
||||||
"user-removed-as-dossier-member": "<b>{user}</b> wurde als Mitglied von: <b>{dossierHref, select, null{{dossierName}} other{<a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a>}}</b> entfernt!"
|
"user-removed-as-dossier-member": "<b>{user}</b> wurde als Mitglied von: <b>{dossierHref, select, null{{dossierName}} other{<a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a>}}</b> entfernt!"
|
||||||
},
|
},
|
||||||
"notifications": {
|
|
||||||
"button-text": "Notifications",
|
|
||||||
"deleted-dossier": "Deleted Dossier",
|
|
||||||
"label": "Benachrichtigungen",
|
|
||||||
"mark-all-as-read": "Alle als gelesen markieren",
|
|
||||||
"mark-as": "Mark as {type, select, read{read} unread{unread} other{}}"
|
|
||||||
},
|
|
||||||
"notifications-screen": {
|
"notifications-screen": {
|
||||||
"category": {
|
"category": {
|
||||||
"email-notifications": "E-Mail Benachrichtigungen",
|
"email-notifications": "E-Mail Benachrichtigungen",
|
||||||
@ -1909,6 +1892,7 @@
|
|||||||
"dossier": "Dossierbezogene Benachrichtigungen",
|
"dossier": "Dossierbezogene Benachrichtigungen",
|
||||||
"other": "Andere Benachrichtigungen"
|
"other": "Andere Benachrichtigungen"
|
||||||
},
|
},
|
||||||
|
"options-title": "Wählen Sie aus, in welcher Kategorie Sie benachrichtigt werden möchten",
|
||||||
"options": {
|
"options": {
|
||||||
"ASSIGN_APPROVER": "Wenn ich einem Dokument als Genehmiger zugewiesen bin",
|
"ASSIGN_APPROVER": "Wenn ich einem Dokument als Genehmiger zugewiesen bin",
|
||||||
"ASSIGN_REVIEWER": "Wenn ich einem Dokument als Überprüfer zugewiesen bin",
|
"ASSIGN_REVIEWER": "Wenn ich einem Dokument als Überprüfer zugewiesen bin",
|
||||||
@ -1926,7 +1910,6 @@
|
|||||||
"USER_PROMOTED_TO_APPROVER": "Wenn ich Genehmiger in einem Dossier werde",
|
"USER_PROMOTED_TO_APPROVER": "Wenn ich Genehmiger in einem Dossier werde",
|
||||||
"USER_REMOVED_AS_DOSSIER_MEMBER": "Wenn ich die Dossier-Mitgliedschaft verliere"
|
"USER_REMOVED_AS_DOSSIER_MEMBER": "Wenn ich die Dossier-Mitgliedschaft verliere"
|
||||||
},
|
},
|
||||||
"options-title": "Wählen Sie aus, in welcher Kategorie Sie benachrichtigt werden möchten",
|
|
||||||
"schedule": {
|
"schedule": {
|
||||||
"daily": "Tägliche Zusammenfassung",
|
"daily": "Tägliche Zusammenfassung",
|
||||||
"instant": "Sofortig",
|
"instant": "Sofortig",
|
||||||
@ -1934,6 +1917,13 @@
|
|||||||
},
|
},
|
||||||
"title": "Benachrichtigungseinstellungen"
|
"title": "Benachrichtigungseinstellungen"
|
||||||
},
|
},
|
||||||
|
"notifications": {
|
||||||
|
"button-text": "Notifications",
|
||||||
|
"deleted-dossier": "Deleted Dossier",
|
||||||
|
"label": "Benachrichtigungen",
|
||||||
|
"mark-all-as-read": "Alle als gelesen markieren",
|
||||||
|
"mark-as": "Mark as {type, select, read{read} unread{unread} other{}}"
|
||||||
|
},
|
||||||
"ocr": {
|
"ocr": {
|
||||||
"confirmation-dialog": {
|
"confirmation-dialog": {
|
||||||
"cancel": "Cancel",
|
"cancel": "Cancel",
|
||||||
@ -2025,16 +2015,16 @@
|
|||||||
"warnings-subtitle": "Do not show again options",
|
"warnings-subtitle": "Do not show again options",
|
||||||
"warnings-title": "Prompts and Dialogs Settings"
|
"warnings-title": "Prompts and Dialogs Settings"
|
||||||
},
|
},
|
||||||
"processing": {
|
|
||||||
"basic": "Processing",
|
|
||||||
"ocr": "OCR"
|
|
||||||
},
|
|
||||||
"processing-status": {
|
"processing-status": {
|
||||||
"ocr": "OCR",
|
"ocr": "OCR",
|
||||||
"pending": "Pending",
|
"pending": "Pending",
|
||||||
"processed": "Processed",
|
"processed": "Processed",
|
||||||
"processing": "Processing"
|
"processing": "Processing"
|
||||||
},
|
},
|
||||||
|
"processing": {
|
||||||
|
"basic": "Processing",
|
||||||
|
"ocr": "OCR"
|
||||||
|
},
|
||||||
"readonly": "Lesemodus",
|
"readonly": "Lesemodus",
|
||||||
"readonly-archived": "Read only (archived)",
|
"readonly-archived": "Read only (archived)",
|
||||||
"redact-text": {
|
"redact-text": {
|
||||||
@ -2264,12 +2254,6 @@
|
|||||||
"red-user-admin": "Benutzer-Admin",
|
"red-user-admin": "Benutzer-Admin",
|
||||||
"regular": "Regulär"
|
"regular": "Regulär"
|
||||||
},
|
},
|
||||||
"search": {
|
|
||||||
"active-dossiers": "ganze Plattform",
|
|
||||||
"all-dossiers": "all documents",
|
|
||||||
"placeholder": "Nach Dokumenten oder Dokumenteninhalt suchen",
|
|
||||||
"this-dossier": "in diesem Dossier"
|
|
||||||
},
|
|
||||||
"search-screen": {
|
"search-screen": {
|
||||||
"cols": {
|
"cols": {
|
||||||
"assignee": "Bevollmächtigter",
|
"assignee": "Bevollmächtigter",
|
||||||
@ -2293,6 +2277,12 @@
|
|||||||
"no-match": "Keine Dokumente entsprechen Ihren aktuellen Filtern.",
|
"no-match": "Keine Dokumente entsprechen Ihren aktuellen Filtern.",
|
||||||
"table-header": "{length} {length, plural, one{Suchergebnis} other{Suchergebnisse}}"
|
"table-header": "{length} {length, plural, one{Suchergebnis} other{Suchergebnisse}}"
|
||||||
},
|
},
|
||||||
|
"search": {
|
||||||
|
"active-dossiers": "ganze Plattform",
|
||||||
|
"all-dossiers": "all documents",
|
||||||
|
"placeholder": "Nach Dokumenten oder Dokumenteninhalt suchen",
|
||||||
|
"this-dossier": "in diesem Dossier"
|
||||||
|
},
|
||||||
"seconds": "seconds",
|
"seconds": "seconds",
|
||||||
"size": "Size",
|
"size": "Size",
|
||||||
"smtp-auth-config": {
|
"smtp-auth-config": {
|
||||||
|
|||||||
@ -56,8 +56,7 @@
|
|||||||
},
|
},
|
||||||
"add-edit-clone-dossier-template": {
|
"add-edit-clone-dossier-template": {
|
||||||
"error": {
|
"error": {
|
||||||
"conflict": "Failed to create dossier template: a dossier template with the same name already exists.",
|
"conflict": "Failed to create dossier template: a dossier template with the same name already exists."
|
||||||
"generic": "Failed to create dossier template."
|
|
||||||
},
|
},
|
||||||
"form": {
|
"form": {
|
||||||
"apply-updates-default": {
|
"apply-updates-default": {
|
||||||
@ -134,7 +133,7 @@
|
|||||||
"dossier-dictionary-only": "Dossier dictionary only",
|
"dossier-dictionary-only": "Dossier dictionary only",
|
||||||
"has-dictionary": "Has dictionary",
|
"has-dictionary": "Has dictionary",
|
||||||
"hint": "Hint",
|
"hint": "Hint",
|
||||||
"manage-entries-in-dictionary-editor-only": "Manage entries in Dictionary editor only",
|
"manage-entries-in-dictionary-editor-only": "Available in add/remove dialogs",
|
||||||
"name": "Display Name",
|
"name": "Display Name",
|
||||||
"name-placeholder": "Enter Name",
|
"name-placeholder": "Enter Name",
|
||||||
"rank": "Rank",
|
"rank": "Rank",
|
||||||
@ -558,10 +557,17 @@
|
|||||||
"title": "Confirm Action"
|
"title": "Confirm Action"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"component-download": {
|
||||||
|
"disabled-tooltip": "You need to upload at least one file to be able to export the components as JSON or XML",
|
||||||
|
"json": "Download as JSON",
|
||||||
|
"tooltip": "Component Download",
|
||||||
|
"xml": "Download as XML"
|
||||||
|
},
|
||||||
"component-log-dialog": {
|
"component-log-dialog": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"cancel-edit": "Cancel",
|
"cancel-edit": "Cancel",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
|
"disabled-edit": "Multi-value component – Read-only",
|
||||||
"display-by-default": "Display by default when opening documents",
|
"display-by-default": "Display by default when opening documents",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"export-json": "Export JSON",
|
"export-json": "Export JSON",
|
||||||
@ -758,7 +764,6 @@
|
|||||||
"download": "Download current entries",
|
"download": "Download current entries",
|
||||||
"error": {
|
"error": {
|
||||||
"400": "Cannot update dictionary because at least one of the newly added words where recognized as a general term that appear too often in texts.",
|
"400": "Cannot update dictionary because at least one of the newly added words where recognized as a general term that appear too often in texts.",
|
||||||
"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!"
|
"generic": "Something went wrong... Dictionary update failed!"
|
||||||
},
|
},
|
||||||
"revert-changes": "Revert",
|
"revert-changes": "Revert",
|
||||||
@ -1782,14 +1787,6 @@
|
|||||||
"copyright-claim-text": "Copyright © 2020 - {currentYear} knecon",
|
"copyright-claim-text": "Copyright © 2020 - {currentYear} knecon",
|
||||||
"copyright-claim-title": "Copyright Claim",
|
"copyright-claim-title": "Copyright Claim",
|
||||||
"custom-app-title": "Custom Application Title",
|
"custom-app-title": "Custom Application Title",
|
||||||
"email-report": "Email Report",
|
|
||||||
"email": {
|
|
||||||
"body": {
|
|
||||||
"analyzed": "Total Analyzed Pages in current license period: {pages}.",
|
|
||||||
"licensed": "Licensed Pages: {pages}."
|
|
||||||
},
|
|
||||||
"title": "License Report {licenseCustomer}"
|
|
||||||
},
|
|
||||||
"end-user-license-text": "The use of this product is subject to the terms of the RedactManager End User License Agreement, unless otherwise specified therein.",
|
"end-user-license-text": "The use of this product is subject to the terms of the RedactManager End User License Agreement, unless otherwise specified therein.",
|
||||||
"end-user-license-title": "End User License Agreement",
|
"end-user-license-title": "End User License Agreement",
|
||||||
"licensing-details": {
|
"licensing-details": {
|
||||||
@ -2545,12 +2542,5 @@
|
|||||||
"select": "Select"
|
"select": "Select"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"yesterday": "Yesterday",
|
"yesterday": "Yesterday"
|
||||||
"generic-errors": {
|
|
||||||
"400": "The sent request is not valid.",
|
|
||||||
"403": "Access to the requested resource is not allowed.",
|
|
||||||
"404": "The requested resource could not be found.",
|
|
||||||
"409": "The request is incompatible with the current state.",
|
|
||||||
"500": "The server encountered an unexpected condition that prevented it from fulfilling the request."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,8 +56,7 @@
|
|||||||
},
|
},
|
||||||
"add-edit-clone-dossier-template": {
|
"add-edit-clone-dossier-template": {
|
||||||
"error": {
|
"error": {
|
||||||
"conflict": "Dossiervorlage konnte nicht erstellt werden: Es existiert bereits eine Dossiervorlage mit demselben Namen.",
|
"conflict": "Dossiervorlage konnte nicht erstellt werden: Es existiert bereits eine Dossiervorlage mit demselben Namen."
|
||||||
"generic": "Fehler beim Erstellen der Dossiervorlage."
|
|
||||||
},
|
},
|
||||||
"form": {
|
"form": {
|
||||||
"apply-updates-default": {
|
"apply-updates-default": {
|
||||||
@ -558,10 +557,17 @@
|
|||||||
"title": "Aktion bestätigen"
|
"title": "Aktion bestätigen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"component-download": {
|
||||||
|
"disabled-tooltip": "",
|
||||||
|
"json": "",
|
||||||
|
"tooltip": "",
|
||||||
|
"xml": ""
|
||||||
|
},
|
||||||
"component-log-dialog": {
|
"component-log-dialog": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"cancel-edit": "Cancel",
|
"cancel-edit": "Cancel",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
|
"disabled-edit": "",
|
||||||
"display-by-default": "",
|
"display-by-default": "",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"export-json": "Export JSON",
|
"export-json": "Export JSON",
|
||||||
@ -758,7 +764,6 @@
|
|||||||
"download": "",
|
"download": "",
|
||||||
"error": {
|
"error": {
|
||||||
"400": "",
|
"400": "",
|
||||||
"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!"
|
"generic": "Es ist ein Fehler aufgetreten ... Das Wörterbuch konnte nicht aktualisiert werden!"
|
||||||
},
|
},
|
||||||
"revert-changes": "Rückgängig machen",
|
"revert-changes": "Rückgängig machen",
|
||||||
@ -1782,14 +1787,6 @@
|
|||||||
"copyright-claim-text": "Copyright © 2020 - {currentYear} knecon AG (powered by IQSER)",
|
"copyright-claim-text": "Copyright © 2020 - {currentYear} knecon AG (powered by IQSER)",
|
||||||
"copyright-claim-title": "Copyright",
|
"copyright-claim-title": "Copyright",
|
||||||
"custom-app-title": "Name der Anwendung",
|
"custom-app-title": "Name der Anwendung",
|
||||||
"email-report": "E-Mail-Bericht",
|
|
||||||
"email": {
|
|
||||||
"body": {
|
|
||||||
"analyzed": "Im aktuellen Lizenzzeitraum insgesamt analysierte Seiten: {pages}.",
|
|
||||||
"licensed": "Lizenzierte Seiten: {pages}."
|
|
||||||
},
|
|
||||||
"title": "Lizenzbericht {licenseCustomer}"
|
|
||||||
},
|
|
||||||
"end-user-license-text": "Die Nutzung dieses Produkts unterliegt den Bedingungen der Endbenutzer-Lizenzvereinbarung für den RedactManager, sofern darin nichts anderweitig festgelegt.",
|
"end-user-license-text": "Die Nutzung dieses Produkts unterliegt den Bedingungen der Endbenutzer-Lizenzvereinbarung für den RedactManager, sofern darin nichts anderweitig festgelegt.",
|
||||||
"end-user-license-title": "Endbenutzer-Lizenzvereinbarung",
|
"end-user-license-title": "Endbenutzer-Lizenzvereinbarung",
|
||||||
"licensing-details": {
|
"licensing-details": {
|
||||||
@ -2545,12 +2542,5 @@
|
|||||||
"select": "Wählen"
|
"select": "Wählen"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"yesterday": "Gestern",
|
"yesterday": "Gestern"
|
||||||
"generic-errors": {
|
|
||||||
"400": "",
|
|
||||||
"403": "",
|
|
||||||
"404": "",
|
|
||||||
"409": "",
|
|
||||||
"500": ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,8 +56,7 @@
|
|||||||
},
|
},
|
||||||
"add-edit-clone-dossier-template": {
|
"add-edit-clone-dossier-template": {
|
||||||
"error": {
|
"error": {
|
||||||
"conflict": "Failed to create dossier template: a dossier template with the same name already exists.",
|
"conflict": "Failed to create dossier template: a dossier template with the same name already exists."
|
||||||
"generic": "Failed to create dossier template."
|
|
||||||
},
|
},
|
||||||
"form": {
|
"form": {
|
||||||
"apply-updates-default": {
|
"apply-updates-default": {
|
||||||
@ -558,10 +557,17 @@
|
|||||||
"title": "Confirm Action"
|
"title": "Confirm Action"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"component-download": {
|
||||||
|
"disabled-tooltip": "All files must be processed to be able to export the components as JSON or XML",
|
||||||
|
"json": "Download as JSON",
|
||||||
|
"tooltip": "Component Download",
|
||||||
|
"xml": "Download as XML"
|
||||||
|
},
|
||||||
"component-log-dialog": {
|
"component-log-dialog": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"cancel-edit": "Cancel",
|
"cancel-edit": "Cancel",
|
||||||
"close": "Close",
|
"close": "Close",
|
||||||
|
"disabled-edit": "Multi-value component – Read-only",
|
||||||
"display-by-default": "Display by default when opening documents",
|
"display-by-default": "Display by default when opening documents",
|
||||||
"edit": "Edit",
|
"edit": "Edit",
|
||||||
"export-json": "Export JSON",
|
"export-json": "Export JSON",
|
||||||
@ -747,7 +753,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dev-mode": "DEV",
|
"dev-mode": "DEV",
|
||||||
"dictionary": "Dictionary",
|
"dictionary": "Type",
|
||||||
"dictionary-overview": {
|
"dictionary-overview": {
|
||||||
"compare": {
|
"compare": {
|
||||||
"compare": "Compare",
|
"compare": "Compare",
|
||||||
@ -758,7 +764,6 @@
|
|||||||
"download": "Download current entries",
|
"download": "Download current entries",
|
||||||
"error": {
|
"error": {
|
||||||
"400": "Cannot update dictionary because at least one of the newly added words where recognized as a general term that appear too often in texts.",
|
"400": "Cannot update dictionary because at least one of the newly added words where recognized as a general term that appear too often in texts.",
|
||||||
"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!"
|
"generic": "Something went wrong... Dictionary update failed!"
|
||||||
},
|
},
|
||||||
"revert-changes": "Revert",
|
"revert-changes": "Revert",
|
||||||
@ -963,7 +968,7 @@
|
|||||||
"processing-documents": "{count} processing {count, plural, one{document} other{documents}}"
|
"processing-documents": "{count} processing {count, plural, one{document} other{documents}}"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"download-file": "Download",
|
"download-file": "Report Download",
|
||||||
"download-file-disabled": "You need to be approver in the dossier and the {count, plural, one{file needs} other{files need}} to be initially processed in order to download.",
|
"download-file-disabled": "You need to be approver in the dossier and the {count, plural, one{file needs} other{files need}} to be initially processed in order to download.",
|
||||||
"file-listing": {
|
"file-listing": {
|
||||||
"file-entry": {
|
"file-entry": {
|
||||||
@ -1782,14 +1787,6 @@
|
|||||||
"copyright-claim-text": "Copyright © 2020 - {currentYear} knecon",
|
"copyright-claim-text": "Copyright © 2020 - {currentYear} knecon",
|
||||||
"copyright-claim-title": "Copyright Claim",
|
"copyright-claim-title": "Copyright Claim",
|
||||||
"custom-app-title": "Custom Application Title",
|
"custom-app-title": "Custom Application Title",
|
||||||
"email-report": "Email Report",
|
|
||||||
"email": {
|
|
||||||
"body": {
|
|
||||||
"analyzed": "Total Analyzed Pages in current license period: {pages}.",
|
|
||||||
"licensed": "Licensed Pages: {pages}."
|
|
||||||
},
|
|
||||||
"title": "License Report {licenseCustomer}"
|
|
||||||
},
|
|
||||||
"end-user-license-text": "The use of this product is subject to the terms of the DocuMine End User License Agreement, unless otherwise specified therein.",
|
"end-user-license-text": "The use of this product is subject to the terms of the DocuMine End User License Agreement, unless otherwise specified therein.",
|
||||||
"end-user-license-title": "End User License Agreement",
|
"end-user-license-title": "End User License Agreement",
|
||||||
"licensing-details": {
|
"licensing-details": {
|
||||||
@ -2545,12 +2542,5 @@
|
|||||||
"select": "Select"
|
"select": "Select"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"yesterday": "Yesterday",
|
"yesterday": "Yesterday"
|
||||||
"generic-errors": {
|
|
||||||
"400": "The sent request is not valid.",
|
|
||||||
"403": "Access to the requested resource is not allowed.",
|
|
||||||
"404": "The requested resource could not be found.",
|
|
||||||
"409": "The request is incompatible with the current state.",
|
|
||||||
"500": "The server encountered an unexpected condition that prevented it from fulfilling the request."
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ server {
|
|||||||
root /usr/share/nginx/html;
|
root /usr/share/nginx/html;
|
||||||
# SSL stuff for cloudflare proxy-ing - ignores SSL certificate and uses SNI
|
# SSL stuff for cloudflare proxy-ing - ignores SSL certificate and uses SNI
|
||||||
|
|
||||||
add_header Content-Security-Policy "default-src 'self'; script-src 'self' blob: data: 'unsafe-eval' 'unsafe-inline'; script-src-elem 'self' data: blob: 'unsafe-inline'; script-src-attr 'self' data:; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:";
|
add_header Content-Security-Policy "frame-ancestors 'self'; default-src 'self'; script-src 'self' blob: data: 'unsafe-eval' 'unsafe-inline'; script-src-elem 'self' data: blob: 'unsafe-inline'; script-src-attr 'self' data:; style-src 'self' 'unsafe-inline'; img-src 'self' data:; font-src 'self' data:";
|
||||||
|
|
||||||
proxy_ssl_verify off;
|
proxy_ssl_verify off;
|
||||||
proxy_read_timeout 1m;
|
proxy_read_timeout 1m;
|
||||||
@ -32,4 +32,3 @@ server {
|
|||||||
gzip_types application/javascript text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
gzip_types application/javascript text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Subproject commit a6383c1dbc840115897a31567c3f5633ba78b43a
|
Subproject commit fd4580f60da3db4e847b711c5c1c4f388f26693a
|
||||||
@ -4,15 +4,18 @@ export type ComponentDetails = Record<string, Record<'componentValues', ICompone
|
|||||||
|
|
||||||
export interface IComponentLogEntry {
|
export interface IComponentLogEntry {
|
||||||
name: string;
|
name: string;
|
||||||
|
originalKey: string;
|
||||||
componentValues: IComponentValue[];
|
componentValues: IComponentValue[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ComponentLogEntry implements IComponentLogEntry {
|
export class ComponentLogEntry implements IComponentLogEntry {
|
||||||
readonly name: string;
|
readonly name: string;
|
||||||
|
readonly originalKey: string;
|
||||||
readonly componentValues: ComponentValue[];
|
readonly componentValues: ComponentValue[];
|
||||||
|
|
||||||
constructor(entry: IComponentLogEntry) {
|
constructor(entry: IComponentLogEntry) {
|
||||||
this.name = entry.name.replaceAll('_', ' ');
|
this.name = entry.name.replaceAll('_', ' ');
|
||||||
|
this.originalKey = entry.name;
|
||||||
this.componentValues = entry.componentValues;
|
this.componentValues = entry.componentValues;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
export interface IComment {
|
export interface IComment {
|
||||||
id: string;
|
id: string;
|
||||||
user: string;
|
userId: string;
|
||||||
date?: string;
|
date?: string;
|
||||||
text: string;
|
text: string;
|
||||||
annotationId?: string;
|
annotationId?: string;
|
||||||
|
|||||||
@ -39,7 +39,7 @@
|
|||||||
"@ngx-translate/core": "15.0.0",
|
"@ngx-translate/core": "15.0.0",
|
||||||
"@ngx-translate/http-loader": "8.0.0",
|
"@ngx-translate/http-loader": "8.0.0",
|
||||||
"@nx/angular": "16.10.0",
|
"@nx/angular": "16.10.0",
|
||||||
"@pdftron/webviewer": "10.5.0",
|
"@pdftron/webviewer": "10.9.0",
|
||||||
"chart.js": "4.4.0",
|
"chart.js": "4.4.0",
|
||||||
"dayjs": "1.11.10",
|
"dayjs": "1.11.10",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
|
|||||||
@ -3763,10 +3763,10 @@
|
|||||||
node-addon-api "^3.2.1"
|
node-addon-api "^3.2.1"
|
||||||
node-gyp-build "^4.3.0"
|
node-gyp-build "^4.3.0"
|
||||||
|
|
||||||
"@pdftron/webviewer@10.4.0":
|
"@pdftron/webviewer@10.9.0":
|
||||||
version "10.4.0"
|
version "10.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/@pdftron/webviewer/-/webviewer-10.4.0.tgz#9f59c38f0ec1b7cc08d446ca1a9abc94aa549c41"
|
resolved "https://registry.yarnpkg.com/@pdftron/webviewer/-/webviewer-10.9.0.tgz#c39105189c70cfaa0601dae02e688bb510f74e3b"
|
||||||
integrity sha512-aJOuAYEnkxn/tCaB1m548VfxILbBesLB7Fd1S15/KvjklM9nCQjwJv4+R99zL+WaxvVet9kem5LVPoiGXDHXmg==
|
integrity sha512-na6dQE1aFVc42zeRYjk0UDWKqdsI1PcQeQdAcwpNCKyND9W3s8iG8GLkZzfvP2CZjGhj47l28LkZ0NUBrq3weQ==
|
||||||
|
|
||||||
"@phenomnomnominal/tsquery@^4.1.1":
|
"@phenomnomnominal/tsquery@^4.1.1":
|
||||||
version "4.2.0"
|
version "4.2.0"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user