Merge branch 'master' into VM/RED-3332
This commit is contained in:
commit
35d3d58aa9
@ -31,7 +31,14 @@ import { SpotlightSearchComponent } from '@components/spotlight-search/spotlight
|
||||
import { PruningTranslationLoader } from '@utils/pruning-translation-loader';
|
||||
import { DatePipe } from '@shared/pipes/date.pipe';
|
||||
import * as links from '../assets/help-mode/links.json';
|
||||
import { HELP_DOCS, IqserHelpModeModule, MAX_RETRIES_ON_SERVER_ERROR, ServerErrorInterceptor, ToastComponent } from '@iqser/common-ui';
|
||||
import {
|
||||
HELP_DOCS,
|
||||
IqserHelpModeModule,
|
||||
MANUAL_BASE_URL,
|
||||
MAX_RETRIES_ON_SERVER_ERROR,
|
||||
ServerErrorInterceptor,
|
||||
ToastComponent,
|
||||
} from '@iqser/common-ui';
|
||||
import { KeycloakService } from 'keycloak-angular';
|
||||
import { GeneralSettingsService } from '@services/general-settings.service';
|
||||
import { BreadcrumbsComponent } from '@components/breadcrumbs/breadcrumbs.component';
|
||||
@ -127,6 +134,11 @@ const components = [AppComponent, AuthErrorComponent, NotificationsComponent, Sp
|
||||
provide: HELP_DOCS,
|
||||
useValue: links,
|
||||
},
|
||||
{
|
||||
provide: MANUAL_BASE_URL,
|
||||
useFactory: (configService: ConfigService) => configService.values.MANUAL_BASE_URL,
|
||||
deps: [ConfigService],
|
||||
},
|
||||
{
|
||||
provide: MAX_RETRIES_ON_SERVER_ERROR,
|
||||
useFactory: (configService: ConfigService) => configService.values.MAX_RETRIES_ON_SERVER_ERROR,
|
||||
|
||||
@ -16,19 +16,16 @@ import { RedactionLogEntry } from './redaction-log.entry';
|
||||
|
||||
export class FileDataModel {
|
||||
static readonly DELTA_VIEW_TIME = 10 * 60 * 1000; // 10 minutes;
|
||||
allAnnotations: AnnotationWrapper[];
|
||||
allAnnotations: AnnotationWrapper[] = [];
|
||||
readonly hasChangeLog$ = new BehaviorSubject<boolean>(false);
|
||||
readonly blob$ = new BehaviorSubject<Blob>(undefined);
|
||||
|
||||
constructor(
|
||||
private readonly _file: File,
|
||||
private readonly _blob: Blob,
|
||||
private _redactionLog: IRedactionLog,
|
||||
public viewedPages?: IViewedPage[],
|
||||
private _dictionaryData?: { [p: string]: Dictionary },
|
||||
private _areDevFeaturesEnabled?: boolean,
|
||||
) {
|
||||
this.blob$.next(_blob);
|
||||
this._buildAllAnnotations();
|
||||
}
|
||||
|
||||
@ -56,7 +53,7 @@ export class FileDataModel {
|
||||
private _buildAllAnnotations() {
|
||||
const entries: RedactionLogEntry[] = this._convertData();
|
||||
|
||||
const previousAnnotations = this.allAnnotations || [];
|
||||
const previousAnnotations = [...this.allAnnotations];
|
||||
this.allAnnotations = entries
|
||||
.map(entry => AnnotationWrapper.fromData(entry))
|
||||
.filter(ann => ann.manual || !this._file.excludedPages.includes(ann.pageNumber));
|
||||
|
||||
@ -28,21 +28,16 @@ export class RedactionLogEntry implements IRedactionLogEntry {
|
||||
readonly textBefore?: string;
|
||||
readonly type?: string;
|
||||
readonly value?: string;
|
||||
readonly changeLogType?: 'ADDED' | 'REMOVED' | 'CHANGED';
|
||||
readonly isChangeLogEntry?: boolean;
|
||||
readonly hidden?: boolean;
|
||||
readonly legalBasisList: ILegalBasis[];
|
||||
readonly hintDictionary: boolean;
|
||||
|
||||
reason?: string;
|
||||
|
||||
constructor(
|
||||
redactionLogEntry: IRedactionLogEntry,
|
||||
changeLogType: 'ADDED' | 'REMOVED' | 'CHANGED',
|
||||
isChangeLogEntry: boolean,
|
||||
hidden: boolean,
|
||||
hintDictionary: boolean,
|
||||
legalBasisList: ILegalBasis[],
|
||||
readonly changeLogType: 'ADDED' | 'REMOVED' | 'CHANGED',
|
||||
readonly isChangeLogEntry: boolean,
|
||||
readonly hidden: boolean,
|
||||
readonly hintDictionary: boolean,
|
||||
readonly legalBasisList: ILegalBasis[],
|
||||
) {
|
||||
this.changes = redactionLogEntry.changes;
|
||||
this.manualChanges = redactionLogEntry.manualChanges;
|
||||
@ -72,10 +67,5 @@ export class RedactionLogEntry implements IRedactionLogEntry {
|
||||
this.textBefore = redactionLogEntry.textBefore;
|
||||
this.type = redactionLogEntry.type;
|
||||
this.value = redactionLogEntry.value;
|
||||
this.changeLogType = changeLogType;
|
||||
this.isChangeLogEntry = isChangeLogEntry;
|
||||
this.hidden = hidden;
|
||||
this.hintDictionary = hintDictionary;
|
||||
this.legalBasisList = legalBasisList;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@use 'apps/red-ui/src/assets/styles/variables';
|
||||
@use 'libs/common-ui/src/assets/styles/common-mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
.content-container {
|
||||
background-color: variables.$grey-2;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@use 'variables';
|
||||
@use 'libs/common-ui/src/assets/styles/common-mixins';
|
||||
@use 'common-mixins';
|
||||
|
||||
.dialog-content {
|
||||
flex-direction: column;
|
||||
|
||||
@ -6,16 +6,13 @@ import { AppStateGuard } from '@state/app-state.guard';
|
||||
import { DictionaryListingScreenComponent } from './screens/dictionary-listing/dictionary-listing-screen.component';
|
||||
import { DictionaryOverviewScreenComponent } from './screens/dictionary-overview/dictionary-overview-screen.component';
|
||||
import { PendingChangesGuard } from '@guards/can-deactivate.guard';
|
||||
import { RulesScreenComponent } from './screens/rules/rules-screen.component';
|
||||
import { FileAttributesListingScreenComponent } from './screens/file-attributes-listing/file-attributes-listing-screen.component';
|
||||
import { WatermarkScreenComponent } from './screens/watermark/watermark-screen.component';
|
||||
import { DefaultColorsScreenComponent } from './screens/default-colors/default-colors-screen.component';
|
||||
import { UserListingScreenComponent } from './screens/user-listing/user-listing-screen.component';
|
||||
import { LicenseInformationScreenComponent } from './screens/license-information/license-information-screen.component';
|
||||
import { DigitalSignatureScreenComponent } from './screens/digital-signature/digital-signature-screen.component';
|
||||
import { AuditScreenComponent } from './screens/audit/audit-screen.component';
|
||||
import { RouterModule, Routes } from '@angular/router';
|
||||
import { ReportsScreenComponent } from './screens/reports/reports-screen.component';
|
||||
import { DossierAttributesListingScreenComponent } from './screens/dossier-attributes-listing/dossier-attributes-listing-screen.component';
|
||||
import { TrashScreenComponent } from './screens/trash/trash-screen.component';
|
||||
import { GeneralConfigScreenComponent } from './screens/general-config/general-config-screen.component';
|
||||
@ -72,12 +69,13 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'rules',
|
||||
component: RulesScreenComponent,
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
canDeactivate: [PendingChangesGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
|
||||
},
|
||||
loadChildren: () => import('./screens/rules/rules.module').then(m => m.RulesModule),
|
||||
},
|
||||
{
|
||||
path: 'file-attributes',
|
||||
@ -89,19 +87,21 @@ const routes: Routes = [
|
||||
},
|
||||
{
|
||||
path: 'watermark',
|
||||
component: WatermarkScreenComponent,
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
|
||||
},
|
||||
loadChildren: () => import('./screens/watermark/watermark.module').then(m => m.WatermarkModule),
|
||||
},
|
||||
{
|
||||
path: 'reports',
|
||||
component: ReportsScreenComponent,
|
||||
component: BaseDossierTemplateScreenComponent,
|
||||
canActivate: [CompositeRouteGuard],
|
||||
data: {
|
||||
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
|
||||
},
|
||||
loadChildren: () => import('./screens/reports/reports.module').then(m => m.ReportsModule),
|
||||
},
|
||||
{
|
||||
path: 'dossier-attributes',
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { AdminRoutingModule } from './admin-routing.module';
|
||||
import { RulesScreenComponent } from './screens/rules/rules-screen.component';
|
||||
import { SharedModule } from '@shared/shared.module';
|
||||
import { AuditScreenComponent } from './screens/audit/audit-screen.component';
|
||||
import { DefaultColorsScreenComponent } from './screens/default-colors/default-colors-screen.component';
|
||||
@ -11,7 +10,6 @@ import { DigitalSignatureScreenComponent } from './screens/digital-signature/dig
|
||||
import { FileAttributesListingScreenComponent } from './screens/file-attributes-listing/file-attributes-listing-screen.component';
|
||||
import { LicenseInformationScreenComponent } from './screens/license-information/license-information-screen.component';
|
||||
import { UserListingScreenComponent } from './screens/user-listing/user-listing-screen.component';
|
||||
import { WatermarkScreenComponent } from './screens/watermark/watermark-screen.component';
|
||||
import { DossierTemplateBreadcrumbsComponent } from './components/dossier-template-breadcrumbs/dossier-template-breadcrumbs.component';
|
||||
import { ColorPickerModule } from 'ngx-color-picker';
|
||||
import { AddEditFileAttributeDialogComponent } from './dialogs/add-edit-file-attribute-dialog/add-edit-file-attribute-dialog.component';
|
||||
@ -31,7 +29,6 @@ import { FileAttributesCsvImportDialogComponent } from './dialogs/file-attribute
|
||||
import { ActiveFieldsListingComponent } from './dialogs/file-attributes-csv-import-dialog/active-fields-listing/active-fields-listing.component';
|
||||
import { AdminSideNavComponent } from './admin-side-nav/admin-side-nav.component';
|
||||
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
|
||||
import { ReportsScreenComponent } from './screens/reports/reports-screen.component';
|
||||
import { ResetPasswordComponent } from './dialogs/add-edit-user-dialog/reset-password/reset-password.component';
|
||||
import { UserDetailsComponent } from './dialogs/add-edit-user-dialog/user-details/user-details.component';
|
||||
import { AddEditDossierAttributeDialogComponent } from './dialogs/add-edit-dossier-attribute-dialog/add-edit-dossier-attribute-dialog.component';
|
||||
@ -66,7 +63,6 @@ const dialogs = [
|
||||
];
|
||||
|
||||
const screens = [
|
||||
RulesScreenComponent,
|
||||
AuditScreenComponent,
|
||||
DefaultColorsScreenComponent,
|
||||
DictionaryListingScreenComponent,
|
||||
@ -75,9 +71,7 @@ const screens = [
|
||||
FileAttributesListingScreenComponent,
|
||||
LicenseInformationScreenComponent,
|
||||
UserListingScreenComponent,
|
||||
WatermarkScreenComponent,
|
||||
GeneralConfigScreenComponent,
|
||||
ReportsScreenComponent,
|
||||
DossierAttributesListingScreenComponent,
|
||||
TrashScreenComponent,
|
||||
];
|
||||
|
||||
@ -55,7 +55,7 @@ export class DefaultColorsScreenComponent extends ListingComponent<ListItem> imp
|
||||
await this._loadColors();
|
||||
}
|
||||
|
||||
openEditColorDialog($event: any, color: { key: DefaultColorType | string; value: string }) {
|
||||
openEditColorDialog($event: MouseEvent, color: { key: DefaultColorType | string; value: string }) {
|
||||
this._dialogService.openDialog(
|
||||
'editColor',
|
||||
$event,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<iqser-page-header
|
||||
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
|
||||
[pageLabel]="'dossier-templates' | translate"
|
||||
[pageLabel]="'dossier-templates.label' | translate"
|
||||
[showCloseButton]="currentUser.isUser"
|
||||
></iqser-page-header>
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@
|
||||
<div class="action-buttons">
|
||||
<iqser-circle-button
|
||||
(action)="openEditJustificationDialog()"
|
||||
*ngIf="userService.currentUser.isAdmin"
|
||||
*ngIf="userPreferenceService.areDevFeaturesEnabled && userService.currentUser.isAdmin"
|
||||
[tooltip]="'justifications-listing.actions.edit' | translate"
|
||||
[type]="circleButtonTypes.dark"
|
||||
icon="iqser:edit"
|
||||
|
||||
@ -1,88 +0,0 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
<div class="actions flex-1">
|
||||
<redaction-dossier-template-actions></redaction-dossier-template-actions>
|
||||
|
||||
<iqser-circle-button
|
||||
[routerLink]="['../..']"
|
||||
[tooltip]="'common.close' | translate"
|
||||
icon="iqser:close"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-inner">
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
<redaction-admin-side-nav type="dossierTemplates"></redaction-admin-side-nav>
|
||||
|
||||
<div class="content-container" iqserHasScrollbar>
|
||||
<div class="heading-xl" translate="reports-screen.title"></div>
|
||||
|
||||
<div class="description" translate="reports-screen.description"></div>
|
||||
|
||||
<div class="document-setup">
|
||||
<div class="all-caps-label" translate="reports-screen.document-setup-heading"></div>
|
||||
<div translate="reports-screen.document-setup-description"></div>
|
||||
</div>
|
||||
|
||||
<div class="placeholders">
|
||||
<div class="all-caps-label" translate="reports-screen.table-header.placeholders"></div>
|
||||
<div class="all-caps-label" translate="reports-screen.table-header.description"></div>
|
||||
<ng-container *ngFor="let placeholder of placeholders">
|
||||
<div class="placeholder">{{ placeholder.placeholder }}</div>
|
||||
<div
|
||||
[innerHTML]="placeholder.descriptionTranslation | translate: { attribute: placeholder.attributeName }"
|
||||
class="description"
|
||||
></div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right-container" iqserHasScrollbar>
|
||||
<div class="header">
|
||||
<div class="heading" translate="reports-screen.report-documents"></div>
|
||||
<iqser-circle-button
|
||||
(action)="fileInput.click()"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
[tooltip]="'reports-screen.upload-document' | translate"
|
||||
icon="iqser:upload"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
(click)="fileInput.click()"
|
||||
*ngIf="permissionsService.isAdmin() && !availableTemplates?.length"
|
||||
class="template upload-button"
|
||||
translate="reports-screen.upload-document"
|
||||
></div>
|
||||
|
||||
<div *ngFor="let template of availableTemplates" class="template">
|
||||
<div class="name">
|
||||
{{ template.fileName }} {{ template.multiFileReport ? ('reports-screen.multi-file-report' | translate) : '' }}
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<iqser-circle-button
|
||||
(action)="download(template)"
|
||||
[iconSize]="12"
|
||||
[size]="18"
|
||||
icon="iqser:download"
|
||||
></iqser-circle-button>
|
||||
<iqser-circle-button
|
||||
(action)="deleteTemplate(template)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
[iconSize]="12"
|
||||
[size]="18"
|
||||
icon="iqser:trash"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<input #fileInput (change)="uploadTemplate($event)" hidden type="file" />
|
||||
@ -0,0 +1,60 @@
|
||||
<div class="content-container" iqserHasScrollbar>
|
||||
<div class="heading-xl" translate="reports-screen.title"></div>
|
||||
|
||||
<div class="description" translate="reports-screen.description"></div>
|
||||
|
||||
<div class="document-setup">
|
||||
<div class="all-caps-label" translate="reports-screen.document-setup-heading"></div>
|
||||
<div translate="reports-screen.document-setup-description"></div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="placeholders$ | async as placeholders" class="placeholders">
|
||||
<div class="all-caps-label" translate="reports-screen.table-header.placeholders"></div>
|
||||
<div class="all-caps-label" translate="reports-screen.table-header.description"></div>
|
||||
<ng-container *ngFor="let placeholder of placeholders">
|
||||
<div class="placeholder">{{ placeholder.placeholder }}</div>
|
||||
<div
|
||||
[innerHTML]="placeholder.descriptionTranslation | translate: { attribute: placeholder.attributeName }"
|
||||
class="description"
|
||||
></div>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="availableTemplates$ | async as availableTemplates" class="right-container" iqserHasScrollbar>
|
||||
<div class="header">
|
||||
<div class="heading" translate="reports-screen.report-documents"></div>
|
||||
<iqser-circle-button
|
||||
(action)="fileInput.click()"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
[tooltip]="'reports-screen.upload-document' | translate"
|
||||
icon="iqser:upload"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
(click)="fileInput.click()"
|
||||
*ngIf="permissionsService.isAdmin() && !availableTemplates?.length"
|
||||
class="template upload-button"
|
||||
translate="reports-screen.upload-document"
|
||||
></div>
|
||||
|
||||
<div *ngFor="let template of availableTemplates" class="template">
|
||||
<div class="name">
|
||||
{{ template.fileName }} {{ template.multiFileReport ? ('reports-screen.multi-file-report' | translate) : '' }}
|
||||
</div>
|
||||
|
||||
<div class="actions">
|
||||
<iqser-circle-button (action)="download(template)" [iconSize]="12" [size]="18" icon="iqser:download"></iqser-circle-button>
|
||||
<iqser-circle-button
|
||||
(action)="deleteTemplate(template)"
|
||||
*ngIf="permissionsService.isAdmin()"
|
||||
[iconSize]="12"
|
||||
[size]="18"
|
||||
icon="iqser:trash"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input #fileInput (change)="uploadTemplate($event)" hidden type="file" />
|
||||
@ -1,6 +1,12 @@
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
:host {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.content-container,
|
||||
.right-container {
|
||||
flex: 1;
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, ElementRef, OnInit, ViewChild } from '@angular/core';
|
||||
import { IPlaceholdersResponse, IReportTemplate } from '@red/domain';
|
||||
import { download } from '@utils/file-download-utils';
|
||||
import { ConfirmationDialogInput, LoadingService, Toaster } from '@iqser/common-ui';
|
||||
@ -6,13 +6,13 @@ import { PermissionsService } from '@services/permissions.service';
|
||||
import {
|
||||
generalPlaceholdersDescriptionsTranslations,
|
||||
placeholdersDescriptionsTranslations,
|
||||
} from '../../translations/placeholders-descriptions-translations';
|
||||
} from '../../../translations/placeholders-descriptions-translations';
|
||||
import { removeBraces } from '@utils/functions';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { AdminDialogService } from '../../services/admin-dialog.service';
|
||||
import { AdminDialogService } from '../../../services/admin-dialog.service';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { ReportTemplateService } from '@services/report-template.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { BehaviorSubject, firstValueFrom } from 'rxjs';
|
||||
|
||||
interface Placeholder {
|
||||
placeholder: string;
|
||||
@ -27,10 +27,11 @@ const placeholderTypes: PlaceholderType[] = ['generalPlaceholders', 'fileAttribu
|
||||
selector: 'redaction-reports-screen',
|
||||
templateUrl: './reports-screen.component.html',
|
||||
styleUrls: ['./reports-screen.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ReportsScreenComponent implements OnInit {
|
||||
placeholders: Placeholder[];
|
||||
availableTemplates: IReportTemplate[];
|
||||
placeholders$ = new BehaviorSubject<Placeholder[]>([]);
|
||||
availableTemplates$ = new BehaviorSubject<IReportTemplate[]>([]);
|
||||
|
||||
@ViewChild('fileInput') private _fileInput: ElementRef;
|
||||
|
||||
@ -85,7 +86,7 @@ export class ReportsScreenComponent implements OnInit {
|
||||
}
|
||||
|
||||
private async _uploadTemplate($event) {
|
||||
const file = $event.target.files[0];
|
||||
const file: File = $event.target.files[0];
|
||||
|
||||
if (!this._isValidFile(file)) {
|
||||
this._toaster.error(_('reports-screen.invalid-upload'));
|
||||
@ -94,7 +95,7 @@ export class ReportsScreenComponent implements OnInit {
|
||||
|
||||
const dossierTemplateId = this._dossierTemplatesService.activeDossierTemplateId;
|
||||
|
||||
if (this.availableTemplates.some(template => template.fileName === file.name)) {
|
||||
if (this.availableTemplates$.value.some(template => template.fileName === file.name)) {
|
||||
const data = new ConfirmationDialogInput({
|
||||
title: _('confirmation-dialog.report-template-same-name.title'),
|
||||
question: _('confirmation-dialog.report-template-same-name.question'),
|
||||
@ -147,8 +148,10 @@ export class ReportsScreenComponent implements OnInit {
|
||||
}
|
||||
|
||||
private async _loadReportTemplates() {
|
||||
this.availableTemplates = await firstValueFrom(
|
||||
this._reportTemplateService.getAvailableReportTemplates(this._dossierTemplatesService.activeDossierTemplateId),
|
||||
this.availableTemplates$.next(
|
||||
await firstValueFrom(
|
||||
this._reportTemplateService.getAvailableReportTemplates(this._dossierTemplatesService.activeDossierTemplateId),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -156,12 +159,14 @@ export class ReportsScreenComponent implements OnInit {
|
||||
const placeholdersResponse: IPlaceholdersResponse = await firstValueFrom(
|
||||
this._reportTemplateService.getAvailablePlaceholders(this._dossierTemplatesService.activeDossierTemplateId),
|
||||
);
|
||||
this.placeholders = placeholderTypes.flatMap(type =>
|
||||
placeholdersResponse[type].map(placeholder => ({
|
||||
placeholder,
|
||||
descriptionTranslation: this._getPlaceholderDescriptionTranslation(type, placeholder),
|
||||
attributeName: this._getAttributeName(placeholder),
|
||||
})),
|
||||
this.placeholders$.next(
|
||||
placeholderTypes.flatMap(type =>
|
||||
placeholdersResponse[type].map(placeholder => ({
|
||||
placeholder,
|
||||
descriptionTranslation: this._getPlaceholderDescriptionTranslation(type, placeholder),
|
||||
attributeName: this._getAttributeName(placeholder),
|
||||
})),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { SharedModule } from '../../../shared/shared.module';
|
||||
import { ReportsScreenComponent } from './reports-screen/reports-screen.component';
|
||||
|
||||
const routes = [{ path: '', component: ReportsScreenComponent }];
|
||||
|
||||
@NgModule({
|
||||
declarations: [ReportsScreenComponent],
|
||||
imports: [RouterModule.forChild(routes), CommonModule, SharedModule],
|
||||
})
|
||||
export class ReportsModule {}
|
||||
@ -1,35 +0,0 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
<div class="flex-1 actions">
|
||||
<redaction-dossier-template-actions></redaction-dossier-template-actions>
|
||||
|
||||
<iqser-circle-button
|
||||
[routerLink]="['../..']"
|
||||
[tooltip]="'common.close' | translate"
|
||||
icon="iqser:close"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-inner">
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
<redaction-admin-side-nav type="dossierTemplates"></redaction-admin-side-nav>
|
||||
|
||||
<div class="editor-container">
|
||||
<ngx-monaco-editor (init)="onCodeEditorInit($event)" [(ngModel)]="codeEditorText" [options]="editorOptions"></ngx-monaco-editor>
|
||||
</div>
|
||||
<div *ngIf="changed && permissionsService.isAdmin() && !isLeaving" class="changes-box">
|
||||
<iqser-icon-button
|
||||
(action)="save()"
|
||||
[label]="'rules-screen.save-changes' | translate"
|
||||
[type]="iconButtonTypes.primary"
|
||||
icon="iqser:check"
|
||||
></iqser-icon-button>
|
||||
<div (click)="revert()" class="all-caps-label cancel" translate="rules-screen.revert-changes"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -1,10 +0,0 @@
|
||||
.editor-container {
|
||||
width: 100%;
|
||||
padding-top: 15px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
ngx-monaco-editor {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
<ngx-monaco-editor (init)="onCodeEditorInit($event)" [(ngModel)]="codeEditorText" [options]="editorOptions"></ngx-monaco-editor>
|
||||
|
||||
<div *ngIf="changed && permissionsService.isAdmin() && !isLeaving" class="changes-box">
|
||||
<iqser-icon-button
|
||||
(action)="save()"
|
||||
[label]="'rules-screen.save-changes' | translate"
|
||||
[type]="iconButtonTypes.primary"
|
||||
icon="iqser:check"
|
||||
></iqser-icon-button>
|
||||
<div (click)="revert()" class="all-caps-label cancel" translate="rules-screen.revert-changes"></div>
|
||||
</div>
|
||||
@ -0,0 +1,10 @@
|
||||
:host {
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
padding: 15px 0 0 15px;
|
||||
}
|
||||
|
||||
ngx-monaco-editor {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
@ -5,7 +5,7 @@ import { TranslateService } from '@ngx-translate/core';
|
||||
import { saveAs } from 'file-saver';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
import { RulesService } from '../../services/rules.service';
|
||||
import { RulesService } from '../../../services/rules.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import ICodeEditor = monaco.editor.ICodeEditor;
|
||||
import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
|
||||
@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { SharedModule } from '../../../shared/shared.module';
|
||||
import { RulesScreenComponent } from './rules-screen/rules-screen.component';
|
||||
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
|
||||
|
||||
const routes = [{ path: '', component: RulesScreenComponent }];
|
||||
|
||||
@NgModule({
|
||||
declarations: [RulesScreenComponent],
|
||||
imports: [RouterModule.forChild(routes), CommonModule, SharedModule, MonacoEditorModule],
|
||||
})
|
||||
export class RulesModule {}
|
||||
@ -1,127 +0,0 @@
|
||||
<section>
|
||||
<div class="page-header">
|
||||
<redaction-dossier-template-breadcrumbs class="flex-1"></redaction-dossier-template-breadcrumbs>
|
||||
|
||||
<div class="actions flex-1">
|
||||
<redaction-dossier-template-actions></redaction-dossier-template-actions>
|
||||
|
||||
<iqser-circle-button
|
||||
[routerLink]="['../..']"
|
||||
[tooltip]="'common.close' | translate"
|
||||
icon="iqser:close"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content-inner">
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
<redaction-admin-side-nav type="dossierTemplates"></redaction-admin-side-nav>
|
||||
|
||||
<div class="content-container">
|
||||
<div #viewer class="viewer"></div>
|
||||
<div *ngIf="changed && permissionsService.isAdmin()" class="changes-box">
|
||||
<iqser-icon-button
|
||||
(action)="save()"
|
||||
[disabled]="form.invalid"
|
||||
[label]="'watermark-screen.action.save' | translate"
|
||||
[type]="iconButtonTypes.primary"
|
||||
icon="iqser:check"
|
||||
></iqser-icon-button>
|
||||
<div (click)="revert()" class="all-caps-label cancel" translate="watermark-screen.action.revert"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right-container" iqserHasScrollbar>
|
||||
<div class="heading-xl" translate="watermark-screen.title"></div>
|
||||
<form (keyup)="configChanged()" [formGroup]="form">
|
||||
<div class="iqser-input-group w-300">
|
||||
<textarea
|
||||
(mousemove)="triggerChanges()"
|
||||
[placeholder]="'watermark-screen.form.text-placeholder' | translate"
|
||||
class="w-full"
|
||||
formControlName="text"
|
||||
iqserHasScrollbar
|
||||
name="text"
|
||||
rows="4"
|
||||
type="text"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<label class="all-caps-label mb-8" translate="watermark-screen.form.orientation"></label>
|
||||
<div class="square-options">
|
||||
<div
|
||||
(click)="setValue('orientation', option)"
|
||||
*ngFor="let option of ['VERTICAL', 'HORIZONTAL', 'DIAGONAL']"
|
||||
[class.active]="form.get('orientation').value === option"
|
||||
[class.disabled]="form.get('orientation').disabled"
|
||||
[ngClass]="option"
|
||||
>
|
||||
<span>ABC</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<label class="all-caps-label" translate="watermark-screen.form.font-size"></label>
|
||||
<mat-slider (change)="configChanged()" color="primary" formControlName="fontSize" max="50" min="5"></mat-slider>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<label class="all-caps-label" translate="watermark-screen.form.opacity"></label>
|
||||
<mat-slider (change)="configChanged()" color="primary" formControlName="opacity" min="1"></mat-slider>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group w-150">
|
||||
<label class="all-caps-label mb-5" translate="watermark-screen.form.color"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-dictionary.form.color-placeholder' | translate"
|
||||
class="hex-color-input"
|
||||
formControlName="hexColor"
|
||||
name="hexColor"
|
||||
type="text"
|
||||
/>
|
||||
<div
|
||||
(colorPickerChange)="setValue('hexColor', $event)"
|
||||
[class.disabled]="form.get('hexColor').disabled"
|
||||
[colorPicker]="form.get('hexColor').value"
|
||||
[cpDisabled]="form.get('hexColor').disabled"
|
||||
[cpOutputFormat]="'hex'"
|
||||
[cpPosition]="'top-right'"
|
||||
[cpUseRootViewContainer]="true"
|
||||
[style.background]="form.get('hexColor').value"
|
||||
class="input-icon"
|
||||
>
|
||||
<mat-icon
|
||||
*ngIf="!form.get('hexColor')?.value || form.get('hexColor').value?.length === 0"
|
||||
svgIcon="red:color-picker"
|
||||
></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<label class="all-caps-label mb-8" translate="watermark-screen.form.font-type"></label>
|
||||
<div class="square-options">
|
||||
<div
|
||||
(click)="setValue('fontType', option.value)"
|
||||
*ngFor="
|
||||
let option of [
|
||||
{ value: 'times-new-roman', display: 'Times' },
|
||||
{ value: 'helvetica', display: 'Helvetica' },
|
||||
{ value: 'courier', display: 'Courier' }
|
||||
]
|
||||
"
|
||||
[class.active]="form.get('fontType').value === option.value"
|
||||
[class.disabled]="form.get('fontType').disabled"
|
||||
[ngClass]="option.value"
|
||||
>
|
||||
{{ option.display }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
@ -0,0 +1,104 @@
|
||||
<div class="content-container">
|
||||
<div #viewer class="viewer"></div>
|
||||
<div *ngIf="changed && permissionsService.isAdmin()" class="changes-box">
|
||||
<iqser-icon-button
|
||||
(action)="save()"
|
||||
[disabled]="form.invalid"
|
||||
[label]="'watermark-screen.action.save' | translate"
|
||||
[type]="iconButtonTypes.primary"
|
||||
icon="iqser:check"
|
||||
></iqser-icon-button>
|
||||
<div (click)="revert()" class="all-caps-label cancel" translate="watermark-screen.action.revert"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="right-container" iqserHasScrollbar>
|
||||
<div class="heading-xl" translate="watermark-screen.title"></div>
|
||||
<form (keyup)="configChanged()" [formGroup]="form">
|
||||
<div class="iqser-input-group w-300">
|
||||
<textarea
|
||||
(mousemove)="triggerChanges()"
|
||||
[placeholder]="'watermark-screen.form.text-placeholder' | translate"
|
||||
class="w-full"
|
||||
formControlName="text"
|
||||
iqserHasScrollbar
|
||||
name="text"
|
||||
rows="4"
|
||||
type="text"
|
||||
></textarea>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<label class="all-caps-label mb-8" translate="watermark-screen.form.orientation"></label>
|
||||
<div class="square-options">
|
||||
<div
|
||||
(click)="setValue('orientation', option)"
|
||||
*ngFor="let option of ['VERTICAL', 'HORIZONTAL', 'DIAGONAL']"
|
||||
[class.active]="form.get('orientation').value === option"
|
||||
[class.disabled]="form.get('orientation').disabled"
|
||||
[ngClass]="option"
|
||||
>
|
||||
<span>ABC</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<label class="all-caps-label" translate="watermark-screen.form.font-size"></label>
|
||||
<mat-slider (change)="configChanged()" color="primary" formControlName="fontSize" max="50" min="5"></mat-slider>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<label class="all-caps-label" translate="watermark-screen.form.opacity"></label>
|
||||
<mat-slider (change)="configChanged()" color="primary" formControlName="opacity" min="1"></mat-slider>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group w-150">
|
||||
<label class="all-caps-label mb-5" translate="watermark-screen.form.color"></label>
|
||||
<input
|
||||
[placeholder]="'add-edit-dictionary.form.color-placeholder' | translate"
|
||||
class="hex-color-input"
|
||||
formControlName="hexColor"
|
||||
name="hexColor"
|
||||
type="text"
|
||||
/>
|
||||
<div
|
||||
(colorPickerChange)="setValue('hexColor', $event)"
|
||||
[class.disabled]="form.get('hexColor').disabled"
|
||||
[colorPicker]="form.get('hexColor').value"
|
||||
[cpDisabled]="form.get('hexColor').disabled"
|
||||
[cpOutputFormat]="'hex'"
|
||||
[cpPosition]="'top-right'"
|
||||
[cpUseRootViewContainer]="true"
|
||||
[style.background]="form.get('hexColor').value"
|
||||
class="input-icon"
|
||||
>
|
||||
<mat-icon
|
||||
*ngIf="!form.get('hexColor')?.value || form.get('hexColor').value?.length === 0"
|
||||
svgIcon="red:color-picker"
|
||||
></mat-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="iqser-input-group">
|
||||
<label class="all-caps-label mb-8" translate="watermark-screen.form.font-type"></label>
|
||||
<div class="square-options">
|
||||
<div
|
||||
(click)="setValue('fontType', option.value)"
|
||||
*ngFor="
|
||||
let option of [
|
||||
{ value: 'times-new-roman', display: 'Times' },
|
||||
{ value: 'helvetica', display: 'Helvetica' },
|
||||
{ value: 'courier', display: 'Courier' }
|
||||
]
|
||||
"
|
||||
[class.active]="form.get('fontType').value === option.value"
|
||||
[class.disabled]="form.get('fontType').disabled"
|
||||
[ngClass]="option.value"
|
||||
>
|
||||
{{ option.display }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
@ -1,5 +1,11 @@
|
||||
@use 'variables';
|
||||
|
||||
:host {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.content-container {
|
||||
order: 1;
|
||||
|
||||
@ -6,7 +6,7 @@ import { HttpClient } from '@angular/common/http';
|
||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { Debounce, IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
|
||||
import { IWatermark, WatermarkOrientation, WatermarkOrientations } from '@red/domain';
|
||||
import { BASE_HREF } from '../../../../tokens';
|
||||
import { BASE_HREF } from '../../../../../tokens';
|
||||
import { stampPDFPage } from '@utils/page-stamper';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
|
||||
@ -0,0 +1,14 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { SharedModule } from '@shared/shared.module';
|
||||
import { WatermarkScreenComponent } from './watermark-screen/watermark-screen.component';
|
||||
import { ColorPickerModule } from 'ngx-color-picker';
|
||||
|
||||
const routes = [{ path: '', component: WatermarkScreenComponent }];
|
||||
|
||||
@NgModule({
|
||||
declarations: [WatermarkScreenComponent],
|
||||
imports: [RouterModule.forChild(routes), CommonModule, SharedModule, ColorPickerModule],
|
||||
})
|
||||
export class WatermarkModule {}
|
||||
@ -57,7 +57,7 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
|
||||
|
||||
async ngOnInit() {
|
||||
this._loadingService.start();
|
||||
this.canEdit = this._permissionsService.isDossierMember(this.dossier);
|
||||
this.canEdit = this._permissionsService.canEditDossier(this.dossier);
|
||||
await this._updateDossierDictionary();
|
||||
this.form = this._getForm();
|
||||
this._loadingService.stop();
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<redaction-team-members
|
||||
(remove)="toggleSelected($event)"
|
||||
[canAdd]="false"
|
||||
[canRemove]="!disabled"
|
||||
[canRemove]="hasOwner"
|
||||
[dossierId]="dossier.dossierId"
|
||||
[largeSpacing]="true"
|
||||
[memberIds]="selectedApproversList"
|
||||
@ -29,7 +29,7 @@
|
||||
<redaction-team-members
|
||||
(remove)="toggleSelected($event)"
|
||||
[canAdd]="false"
|
||||
[canRemove]="!disabled"
|
||||
[canRemove]="hasOwner"
|
||||
[dossierId]="dossier.dossierId"
|
||||
[largeSpacing]="true"
|
||||
[memberIds]="selectedReviewers$ | async"
|
||||
@ -42,7 +42,7 @@
|
||||
<div class="info mt-4">{{ 'assign-dossier-owner.dialog.no-reviewers' | translate }}</div>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="!disabled">
|
||||
<ng-container *ngIf="hasOwner">
|
||||
<iqser-input-with-action
|
||||
(valueChange)="setMembersSelectOptions($event)"
|
||||
[(value)]="searchQuery"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@use 'libs/common-ui/src/assets/styles/common-mixins';
|
||||
@use 'apps/red-ui/src/assets/styles/variables';
|
||||
@use 'common-mixins';
|
||||
@use 'variables';
|
||||
|
||||
.search-container {
|
||||
margin-top: 16px;
|
||||
|
||||
@ -54,6 +54,10 @@ export class EditDossierTeamComponent extends AutoUnsubscribe implements EditDos
|
||||
return !this.userService.currentUser.isManager || !this.form.get('owner').value;
|
||||
}
|
||||
|
||||
get hasOwner() {
|
||||
return !!this.dossier.ownerId;
|
||||
}
|
||||
|
||||
get changed() {
|
||||
if (this.dossier.ownerId !== this.selectedOwnerId) {
|
||||
return true;
|
||||
@ -72,6 +76,14 @@ export class EditDossierTeamComponent extends AutoUnsubscribe implements EditDos
|
||||
}
|
||||
|
||||
async save(): EditDossierSaveResult {
|
||||
if (!this.hasOwner) {
|
||||
const owner = this.form.get('owner').value;
|
||||
if (!this.isApprover(owner)) {
|
||||
this.toggleApprover(owner);
|
||||
}
|
||||
this._updateLists();
|
||||
}
|
||||
|
||||
const dossier = {
|
||||
...this.dossier,
|
||||
memberIds: this.selectedMembersList,
|
||||
@ -160,11 +172,13 @@ export class EditDossierTeamComponent extends AutoUnsubscribe implements EditDos
|
||||
members: [[...this.dossier?.memberIds]],
|
||||
});
|
||||
this.addSubscription = this.form.get('owner').valueChanges.subscribe(owner => {
|
||||
if (!this.isApprover(owner)) {
|
||||
this.toggleApprover(owner);
|
||||
if (this.hasOwner) {
|
||||
if (!this.isApprover(owner)) {
|
||||
this.toggleApprover(owner);
|
||||
}
|
||||
// If it is an approver, it is already a member, no need to check
|
||||
this._updateLists();
|
||||
}
|
||||
// If it is an approver, it is already a member, no need to check
|
||||
this._updateLists();
|
||||
});
|
||||
this._updateLists();
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ export class FileWorkloadComponent {
|
||||
}
|
||||
|
||||
get redactionColor() {
|
||||
return this._getDictionaryColor('redaction');
|
||||
return this._getDictionaryColor('dossier_redaction');
|
||||
}
|
||||
|
||||
private _getDictionaryColor(type: string) {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@use 'apps/red-ui/src/assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.view-mode-selection {
|
||||
border-right: 1px solid variables.$separator;
|
||||
|
||||
@ -23,6 +23,6 @@ export class DossierWorkloadColumnComponent {
|
||||
}
|
||||
|
||||
get redactionColor() {
|
||||
return this._appStateService.getDictionaryColor('redaction', this.dossier.dossierTemplateId);
|
||||
return this._appStateService.getDictionaryColor('dossier_redaction', this.dossier.dossierTemplateId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@use 'apps/red-ui/src/assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.annotation-actions {
|
||||
display: none;
|
||||
|
||||
@ -8,7 +8,6 @@ import { UserService } from '@services/user.service';
|
||||
import { AnnotationReferencesService } from '../../services/annotation-references.service';
|
||||
import { MultiSelectService } from '../../services/multi-select.service';
|
||||
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
|
||||
export const AnnotationButtonTypes = {
|
||||
dark: 'dark',
|
||||
@ -34,9 +33,9 @@ export class AnnotationActionsComponent implements OnChanges {
|
||||
constructor(
|
||||
private readonly _userService: UserService,
|
||||
readonly multiSelectService: MultiSelectService,
|
||||
private readonly _state: FilePreviewStateService,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
readonly annotationActionsService: AnnotationActionsService,
|
||||
private readonly _screenStateService: FilePreviewStateService,
|
||||
readonly annotationReferencesService: AnnotationReferencesService,
|
||||
) {}
|
||||
|
||||
@ -115,7 +114,7 @@ export class AnnotationActionsComponent implements OnChanges {
|
||||
}
|
||||
|
||||
private async _setPermissions() {
|
||||
const dossier = await firstValueFrom(this._screenStateService.dossier$);
|
||||
const dossier = await this._state.dossier;
|
||||
this.annotationPermissions = AnnotationPermissions.forUser(
|
||||
this._permissionsService.isApprover(dossier),
|
||||
this._userService.currentUser,
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
<div *ngIf="hasChangesToShow" [matTooltip]="changesTooltip" class="chip" matTooltipClass="multiline" matTooltipPosition="above">
|
||||
<div
|
||||
*ngIf="hasChangesToShow && (!isSelected || (multiSelectService.inactive$ | async))"
|
||||
[matTooltip]="changesTooltip"
|
||||
class="chip"
|
||||
matTooltipClass="multiline"
|
||||
matTooltipPosition="above"
|
||||
>
|
||||
<mat-icon [svgIcon]="'red:redaction-changes'"></mat-icon>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="hasEnginesToShow && !isSelected">
|
||||
<ng-container *ngIf="hasEnginesToShow && (!isSelected || (multiSelectService.inactive$ | async))">
|
||||
<div #trigger="cdkOverlayOrigin" (mouseout)="isPopoverOpen = false" (mouseover)="isPopoverOpen = true" cdkOverlayOrigin class="chip">
|
||||
<ng-container *ngFor="let engine of engines">
|
||||
<mat-icon *ngIf="engine.show" [svgIcon]="engine.icon"></mat-icon>
|
||||
|
||||
@ -3,6 +3,7 @@ import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { annotationChangesTranslations } from '../../../../../../translations/annotation-changes-translations';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { MultiSelectService } from '../../services/multi-select.service';
|
||||
|
||||
interface Engine {
|
||||
readonly icon: string;
|
||||
@ -35,7 +36,7 @@ export class AnnotationDetailsComponent implements OnChanges {
|
||||
hasChangesToShow: boolean;
|
||||
changesTooltip: string;
|
||||
|
||||
constructor(private readonly _translateService: TranslateService) {}
|
||||
constructor(private readonly _translateService: TranslateService, readonly multiSelectService: MultiSelectService) {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes.annotation) {
|
||||
|
||||
@ -4,6 +4,8 @@ import { FilterService, HelpModeService, IqserEventTarget } from '@iqser/common-
|
||||
import { MultiSelectService } from '../../services/multi-select.service';
|
||||
import { AnnotationReferencesService } from '../../services/annotation-references.service';
|
||||
import { ViewModeService } from '../../services/view-mode.service';
|
||||
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-annotations-list',
|
||||
@ -16,7 +18,6 @@ export class AnnotationsListComponent implements OnChanges {
|
||||
@Input() selectedAnnotations: AnnotationWrapper[];
|
||||
@Input() annotationActionsTemplate: TemplateRef<unknown>;
|
||||
@Input() activeViewerPage: number;
|
||||
@Input() canMultiSelect = true;
|
||||
|
||||
@Output() readonly pagesPanelActive = new EventEmitter<boolean>();
|
||||
@Output() readonly selectAnnotations = new EventEmitter<AnnotationWrapper[]>();
|
||||
@ -28,6 +29,7 @@ export class AnnotationsListComponent implements OnChanges {
|
||||
readonly helpModeService: HelpModeService,
|
||||
readonly annotationReferencesService: AnnotationReferencesService,
|
||||
private readonly _filterService: FilterService,
|
||||
private readonly _state: FilePreviewStateService,
|
||||
) {}
|
||||
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
@ -36,7 +38,7 @@ export class AnnotationsListComponent implements OnChanges {
|
||||
}
|
||||
}
|
||||
|
||||
annotationClicked(annotation: AnnotationWrapper, $event: MouseEvent): void {
|
||||
async annotationClicked(annotation: AnnotationWrapper, $event: MouseEvent): Promise<void> {
|
||||
if (($event?.target as IqserEventTarget)?.localName === 'input') {
|
||||
return;
|
||||
}
|
||||
@ -50,15 +52,16 @@ export class AnnotationsListComponent implements OnChanges {
|
||||
if (this.isSelected(annotation.annotationId)) {
|
||||
this.deselectAnnotations.emit([annotation]);
|
||||
} else {
|
||||
if (this.canMultiSelect && ($event?.ctrlKey || $event?.metaKey) && this.selectedAnnotations.length > 0) {
|
||||
const canMultiSelect = await firstValueFrom(this._state.isWritable$);
|
||||
if (canMultiSelect && ($event?.ctrlKey || $event?.metaKey) && this.selectedAnnotations.length > 0) {
|
||||
this.multiSelectService.activate();
|
||||
}
|
||||
this.selectAnnotations.emit([annotation]);
|
||||
}
|
||||
}
|
||||
|
||||
referenceClicked(annotation: AnnotationWrapper): void {
|
||||
this.annotationClicked(annotation, null);
|
||||
async referenceClicked(annotation: AnnotationWrapper): Promise<void> {
|
||||
await this.annotationClicked(annotation, null);
|
||||
if (this._filterService.filtersEnabled('primaryFilters')) {
|
||||
this._filterService.toggleFilter('primaryFilters', annotation.superType, true);
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@use 'apps/red-ui/src/assets/styles/variables';
|
||||
@use 'libs/common-ui/src/assets/styles/common-mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
:host {
|
||||
display: block;
|
||||
|
||||
@ -14,7 +14,7 @@
|
||||
<div>
|
||||
<div
|
||||
(click)="multiSelectService.activate()"
|
||||
*ngIf="!isReadOnly && (multiSelectInactive$ | async)"
|
||||
*ngIf="(multiSelectInactive$ | async) && state.isWritable$ | async"
|
||||
class="all-caps-label primary pointer"
|
||||
iqserHelpMode="bulk-select-annotations"
|
||||
translate="file-preview.tabs.annotations.select"
|
||||
@ -31,7 +31,7 @@
|
||||
</ng-template>
|
||||
|
||||
<div class="right-content">
|
||||
<div *ngIf="isReadOnly" class="justify-center banner read-only d-flex">
|
||||
<div *ngIf="state.isReadonly$ | async" class="justify-center banner read-only d-flex">
|
||||
<div class="flex-center">
|
||||
<mat-icon class="primary-white" svgIcon="red:read-only"></mat-icon>
|
||||
<span class="read-only-text" translate="readonly"></span>
|
||||
@ -59,7 +59,7 @@
|
||||
*ngIf="selectedAnnotations?.length > 0"
|
||||
[alwaysVisible]="true"
|
||||
[annotations]="selectedAnnotations"
|
||||
[canPerformAnnotationActions]="!isReadOnly"
|
||||
[canPerformAnnotationActions]="state.isWritable$ | async"
|
||||
[viewer]="viewer"
|
||||
buttonType="primary"
|
||||
tooltipPosition="above"
|
||||
@ -73,7 +73,7 @@
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
|
||||
<div [class.lower-height]="(multiSelectActive$ | async) || isReadOnly" class="annotations-wrapper">
|
||||
<div [class.lower-height]="(multiSelectActive$ | async) || (state.isReadonly$ | async)" class="annotations-wrapper">
|
||||
<div
|
||||
#quickNavigation
|
||||
(keydown)="preventKeyDefault($event)"
|
||||
@ -206,7 +206,6 @@
|
||||
[activeViewerPage]="activeViewerPage"
|
||||
[annotationActionsTemplate]="annotationActionsTemplate"
|
||||
[annotations]="(displayedAnnotations$ | async)?.get(activeViewerPage)"
|
||||
[canMultiSelect]="!isReadOnly"
|
||||
[selectedAnnotations]="selectedAnnotations"
|
||||
iqserHelpMode="workload-annotations-list"
|
||||
></redaction-annotations-list>
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@use 'apps/red-ui/src/assets/styles/variables';
|
||||
@use 'libs/common-ui/src/assets/styles/common-mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
.banner {
|
||||
padding: 13px 16px;
|
||||
|
||||
@ -33,6 +33,7 @@ import { ExcludedPagesService } from '../../services/excluded-pages.service';
|
||||
import { MultiSelectService } from '../../services/multi-select.service';
|
||||
import { DocumentInfoService } from '../../services/document-info.service';
|
||||
import { SkippedService } from '../../services/skipped.service';
|
||||
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
||||
|
||||
const COMMAND_KEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown', 'Escape'];
|
||||
const ALL_HOTKEY_ARRAY = ['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'];
|
||||
@ -75,6 +76,7 @@ export class FileWorkloadComponent {
|
||||
readonly multiSelectService: MultiSelectService,
|
||||
readonly documentInfoService: DocumentInfoService,
|
||||
readonly skippedService: SkippedService,
|
||||
readonly state: FilePreviewStateService,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _changeDetectorRef: ChangeDetectorRef,
|
||||
private readonly _filterService: FilterService,
|
||||
@ -95,10 +97,6 @@ export class FileWorkloadComponent {
|
||||
return this.displayedAnnotations.get(this.activeViewerPage);
|
||||
}
|
||||
|
||||
get isReadOnly(): boolean {
|
||||
return !this._permissionsService.canPerformAnnotationActions(this.file);
|
||||
}
|
||||
|
||||
get currentPageIsExcluded(): boolean {
|
||||
return this.file?.excludedPages?.includes(this.activeViewerPage);
|
||||
}
|
||||
@ -252,8 +250,8 @@ export class FileWorkloadComponent {
|
||||
this.selectPage.emit(1);
|
||||
}
|
||||
|
||||
scrollQuickNavLast(): void {
|
||||
this.selectPage.emit(this.file.numberOfPages);
|
||||
scrollQuickNavLast(): Promise<void> {
|
||||
return this.state.file.then(file => this.selectPage.emit(file.numberOfPages));
|
||||
}
|
||||
|
||||
pageSelectedByClick($event: number): void {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
@use 'apps/red-ui/src/assets/styles/variables';
|
||||
@use 'libs/common-ui/src/assets/styles/common-mixins';
|
||||
@use 'variables';
|
||||
@use 'common-mixins';
|
||||
|
||||
:host {
|
||||
height: 100%;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@use 'apps/red-ui/src/assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.page-wrapper {
|
||||
color: variables.$accent;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
@use 'apps/red-ui/src/assets/styles/variables';
|
||||
@use 'variables';
|
||||
|
||||
.page {
|
||||
display: flex;
|
||||
|
||||
@ -27,7 +27,7 @@ import { AnnotationActionsService } from '../../services/annotation-actions.serv
|
||||
import { UserPreferenceService } from '@services/user-preference.service';
|
||||
import { BASE_HREF } from '../../../../../../tokens';
|
||||
import { ConfigService } from '@services/config.service';
|
||||
import { AutoUnsubscribe, ConfirmationDialogInput, LoadingService, shareDistinctLast } from '@iqser/common-ui';
|
||||
import { AutoUnsubscribe, ConfirmationDialogInput, LoadingService } from '@iqser/common-ui';
|
||||
import { DossiersDialogService } from '../../../../services/dossiers-dialog.service';
|
||||
import { loadCompareDocumentWrapper } from '../../../../utils/compare-mode.utils';
|
||||
import { PdfViewerUtils } from '../../../../utils/pdf-viewer.utils';
|
||||
@ -37,7 +37,7 @@ import { toPosition } from '../../../../utils/pdf-calculation.utils';
|
||||
import { ViewModeService } from '../../services/view-mode.service';
|
||||
import { MultiSelectService } from '../../services/multi-select.service';
|
||||
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
||||
import { filter, switchMap, tap, withLatestFrom } from 'rxjs/operators';
|
||||
import { tap, withLatestFrom } from 'rxjs/operators';
|
||||
import Tools = Core.Tools;
|
||||
import TextTool = Tools.TextTool;
|
||||
import Annotation = Core.Annotations.Annotation;
|
||||
@ -120,12 +120,8 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
|
||||
this._setReadyAndInitialState = this._setReadyAndInitialState.bind(this);
|
||||
await this._loadViewer();
|
||||
|
||||
this.addActiveScreenSubscription = this.stateService.fileData$
|
||||
this.addActiveScreenSubscription = this.stateService.blob$
|
||||
.pipe(
|
||||
filter(fileData => !!fileData),
|
||||
switchMap(fileData => fileData.blob$),
|
||||
// Skip document reload if file content hasn't changed
|
||||
shareDistinctLast(),
|
||||
withLatestFrom(this.stateService.file$),
|
||||
tap(([blob, file]) => this._loadDocument(blob, file)),
|
||||
)
|
||||
@ -158,7 +154,8 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
|
||||
await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
|
||||
|
||||
const compareDocument = await pdfNet.PDFDoc.createFromBuffer(fileReader.result as ArrayBuffer);
|
||||
const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await this.stateService.fileData.blob$.value.arrayBuffer());
|
||||
const blob = await this.stateService.blob;
|
||||
const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await blob.arrayBuffer());
|
||||
|
||||
const loadCompareDocument = async () => {
|
||||
this._loadingService.start();
|
||||
@ -212,7 +209,8 @@ export class PdfViewerComponent extends AutoUnsubscribe implements OnInit, OnCha
|
||||
this.viewModeService.compareMode = false;
|
||||
const pdfNet = this.instance.Core.PDFNet;
|
||||
await pdfNet.initialize(environment.licenseKey ? atob(environment.licenseKey) : null);
|
||||
const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await this.stateService.fileData.blob$.value.arrayBuffer());
|
||||
const blob = await this.stateService.blob;
|
||||
const currentDocument = await pdfNet.PDFDoc.createFromBuffer(await blob.arrayBuffer());
|
||||
|
||||
const filename = (await this.stateService.file).filename ?? 'document.pdf';
|
||||
this.instance.UI.loadDocument(currentDocument, { filename });
|
||||
|
||||
@ -1,135 +1,137 @@
|
||||
<ng-container *ngIf="stateService.dossier$ | async as dossier">
|
||||
<ng-container *ngIf="stateService.file$ | async as file">
|
||||
<section [class.fullscreen]="fullScreen">
|
||||
<div class="page-header">
|
||||
<div class="flex flex-1">
|
||||
<redaction-view-switch (switchView)="switchView($event)"></redaction-view-switch>
|
||||
<section *ngIf="stateService.file$ | async as file" [class.fullscreen]="fullScreen">
|
||||
<div class="page-header">
|
||||
<div class="flex flex-1">
|
||||
<redaction-view-switch (switchView)="switchView($event)"></redaction-view-switch>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 actions-container">
|
||||
<div
|
||||
*ngIf="file.isProcessing"
|
||||
class="spinning-icon mr-16"
|
||||
matTooltip="{{ 'file-status.processing' | translate }}"
|
||||
matTooltipPosition="above"
|
||||
>
|
||||
<mat-icon svgIcon="red:reanalyse"></mat-icon>
|
||||
</div>
|
||||
|
||||
<div class="flex-1 actions-container">
|
||||
<div
|
||||
*ngIf="file.isProcessing"
|
||||
class="spinning-icon mr-16"
|
||||
matTooltip="{{ 'file-status.processing' | translate }}"
|
||||
matTooltipPosition="above"
|
||||
>
|
||||
<mat-icon svgIcon="red:reanalyse"></mat-icon>
|
||||
</div>
|
||||
|
||||
<redaction-user-management></redaction-user-management>
|
||||
|
||||
<ng-container *ngIf="permissionsService.isApprover(dossier) && !!file.lastReviewer">
|
||||
<div class="vertical-line"></div>
|
||||
<div class="all-caps-label mr-16 ml-8" translate="file-preview.last-reviewer"></div>
|
||||
<redaction-initials-avatar [user]="file.lastReviewer" [withName]="true"></redaction-initials-avatar>
|
||||
</ng-container>
|
||||
<redaction-user-management></redaction-user-management>
|
||||
|
||||
<ng-container *ngIf="permissionsService.isApprover(dossier) && !!file.lastReviewer">
|
||||
<div class="vertical-line"></div>
|
||||
<div class="all-caps-label mr-16 ml-8" translate="file-preview.last-reviewer"></div>
|
||||
<redaction-initials-avatar [user]="file.lastReviewer" [withName]="true"></redaction-initials-avatar>
|
||||
</ng-container>
|
||||
|
||||
<redaction-file-actions [file]="file" type="file-preview"></redaction-file-actions>
|
||||
<div class="vertical-line"></div>
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="toggleFullScreen()"
|
||||
[icon]="fullScreen ? 'red:exit-fullscreen' : 'red:fullscreen'"
|
||||
[tooltip]="'file-preview.fullscreen' | translate"
|
||||
class="ml-2"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
<redaction-file-actions [file]="file" type="file-preview"></redaction-file-actions>
|
||||
|
||||
<!-- Dev Mode Features-->
|
||||
<iqser-circle-button
|
||||
(action)="downloadOriginalFile(file)"
|
||||
*ngIf="userPreferenceService.areDevFeaturesEnabled"
|
||||
[tooltip]="'file-preview.download-original-file' | translate"
|
||||
[type]="circleButtonTypes.primary"
|
||||
class="ml-8"
|
||||
icon="iqser:download"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
<!-- End Dev Mode Features-->
|
||||
<iqser-circle-button
|
||||
(action)="toggleFullScreen()"
|
||||
[icon]="fullScreen ? 'red:exit-fullscreen' : 'red:fullscreen'"
|
||||
[tooltip]="'file-preview.fullscreen' | translate"
|
||||
class="ml-2"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="closeFullScreen()"
|
||||
*ngIf="!fullScreen"
|
||||
[routerLink]="dossier.routerLink"
|
||||
[tooltip]="'common.close' | translate"
|
||||
class="ml-8"
|
||||
icon="iqser:close"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
<!-- Dev Mode Features-->
|
||||
<iqser-circle-button
|
||||
(action)="downloadOriginalFile(file)"
|
||||
*ngIf="userPreferenceService.areDevFeaturesEnabled"
|
||||
[tooltip]="'file-preview.download-original-file' | translate"
|
||||
[type]="circleButtonTypes.primary"
|
||||
class="ml-8"
|
||||
icon="iqser:download"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
<!-- End Dev Mode Features-->
|
||||
|
||||
<iqser-circle-button
|
||||
(action)="closeFullScreen()"
|
||||
*ngIf="!fullScreen"
|
||||
[routerLink]="dossier.routerLink"
|
||||
[tooltip]="'common.close' | translate"
|
||||
class="ml-8"
|
||||
icon="iqser:close"
|
||||
tooltipPosition="below"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="overlay-shadow"></div>
|
||||
|
||||
<div class="content-inner">
|
||||
<div class="content-container">
|
||||
<redaction-pdf-viewer
|
||||
(annotationSelected)="handleAnnotationSelected($event)"
|
||||
(annotationsChanged)="annotationsChangedByReviewAction($event)"
|
||||
(keyUp)="handleKeyEvent($event); handleArrowEvent($event)"
|
||||
(manualAnnotationRequested)="openManualAnnotationDialog($event)"
|
||||
(pageChanged)="viewerPageChanged($event)"
|
||||
(viewerReady)="viewerReady($event)"
|
||||
*ngIf="displayPdfViewer"
|
||||
[annotations]="visibleAnnotations"
|
||||
[canPerformActions]="canPerformAnnotationActions$ | async"
|
||||
[class.hidden]="!ready"
|
||||
[dossier]="dossier"
|
||||
[shouldDeselectAnnotationsOnPageChange]="shouldDeselectAnnotationsOnPageChange"
|
||||
></redaction-pdf-viewer>
|
||||
</div>
|
||||
|
||||
<div class="overlay-shadow"></div>
|
||||
<div class="right-container">
|
||||
<iqser-empty-state
|
||||
*ngIf="file.excluded && (documentInfoService.hidden$ | async) && excludedPagesService.hidden$ | async"
|
||||
[horizontalPadding]="40"
|
||||
[text]="'file-preview.tabs.is-excluded' | translate"
|
||||
icon="red:needs-work"
|
||||
></iqser-empty-state>
|
||||
|
||||
<div class="content-inner">
|
||||
<div class="content-container">
|
||||
<redaction-pdf-viewer
|
||||
(annotationSelected)="handleAnnotationSelected($event)"
|
||||
(annotationsChanged)="annotationsChangedByReviewAction($event)"
|
||||
(keyUp)="handleKeyEvent($event); handleArrowEvent($event)"
|
||||
(manualAnnotationRequested)="openManualAnnotationDialog($event)"
|
||||
(pageChanged)="viewerPageChanged($event)"
|
||||
(viewerReady)="viewerReady($event)"
|
||||
*ngIf="displayPdfViewer"
|
||||
[annotations]="visibleAnnotations"
|
||||
[canPerformActions]="canPerformAnnotationActions$ | async"
|
||||
[class.hidden]="!ready"
|
||||
[dossier]="dossier"
|
||||
[shouldDeselectAnnotationsOnPageChange]="shouldDeselectAnnotationsOnPageChange"
|
||||
></redaction-pdf-viewer>
|
||||
</div>
|
||||
<redaction-document-info *ngIf="documentInfoService.shown$ | async"></redaction-document-info>
|
||||
|
||||
<div class="right-container">
|
||||
<iqser-empty-state
|
||||
*ngIf="file.excluded && (documentInfoService.hidden$ | async) && excludedPagesService.hidden$ | async"
|
||||
[horizontalPadding]="40"
|
||||
[text]="'file-preview.tabs.is-excluded' | translate"
|
||||
icon="red:needs-work"
|
||||
></iqser-empty-state>
|
||||
|
||||
<redaction-document-info *ngIf="documentInfoService.shown$ | async"></redaction-document-info>
|
||||
|
||||
<redaction-file-workload
|
||||
#fileWorkloadComponent
|
||||
(annotationsChanged)="annotationsChangedByReviewAction($event)"
|
||||
(deselectAnnotations)="deselectAnnotations($event)"
|
||||
(selectAnnotations)="selectAnnotations($event)"
|
||||
(selectPage)="selectPage($event)"
|
||||
*ngIf="!file.excluded"
|
||||
[(shouldDeselectAnnotationsOnPageChange)]="shouldDeselectAnnotationsOnPageChange"
|
||||
[activeViewerPage]="activeViewerPage"
|
||||
[annotationActionsTemplate]="annotationActionsTemplate"
|
||||
[annotations]="visibleAnnotations"
|
||||
[dialogRef]="dialogRef"
|
||||
[file]="file"
|
||||
[selectedAnnotations]="selectedAnnotations"
|
||||
[viewer]="activeViewer"
|
||||
></redaction-file-workload>
|
||||
</div>
|
||||
<redaction-file-workload
|
||||
#fileWorkloadComponent
|
||||
(annotationsChanged)="annotationsChangedByReviewAction($event)"
|
||||
(deselectAnnotations)="deselectAnnotations($event)"
|
||||
(selectAnnotations)="selectAnnotations($event)"
|
||||
(selectPage)="selectPage($event)"
|
||||
*ngIf="!file.excluded"
|
||||
[(shouldDeselectAnnotationsOnPageChange)]="shouldDeselectAnnotationsOnPageChange"
|
||||
[activeViewerPage]="activeViewerPage"
|
||||
[annotationActionsTemplate]="annotationActionsTemplate"
|
||||
[annotations]="visibleAnnotations"
|
||||
[dialogRef]="dialogRef"
|
||||
[file]="file"
|
||||
[selectedAnnotations]="selectedAnnotations"
|
||||
[viewer]="activeViewer"
|
||||
></redaction-file-workload>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<ng-template #annotationActionsTemplate let-annotation="annotation">
|
||||
<redaction-annotation-actions
|
||||
(annotationsChanged)="annotationsChangedByReviewAction($event)"
|
||||
[annotations]="[annotation]"
|
||||
[canPerformAnnotationActions]="canPerformAnnotationActions$ | async"
|
||||
[viewer]="activeViewer"
|
||||
></redaction-annotation-actions>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #annotationFilterTemplate let-filter="filter">
|
||||
<redaction-type-filter
|
||||
*ngIf="filter.topLevelFilter"
|
||||
[dossierTemplateId]="dossier.dossierTemplateId"
|
||||
[filter]="filter"
|
||||
></redaction-type-filter>
|
||||
<ng-container *ngIf="!filter.topLevelFilter">
|
||||
<redaction-dictionary-annotation-icon [dictionaryKey]="filter.id" [dossierTemplateId]="dossier.dossierTemplateId">
|
||||
</redaction-dictionary-annotation-icon>
|
||||
{{ filter.label | humanize: false }}
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
</section>
|
||||
</ng-container>
|
||||
|
||||
<ng-template #annotationActionsTemplate let-annotation="annotation">
|
||||
<redaction-annotation-actions
|
||||
(annotationsChanged)="annotationsChangedByReviewAction($event)"
|
||||
[annotations]="[annotation]"
|
||||
[canPerformAnnotationActions]="canPerformAnnotationActions$ | async"
|
||||
[viewer]="activeViewer"
|
||||
></redaction-annotation-actions>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #annotationFilterTemplate let-filter="filter">
|
||||
<redaction-type-filter
|
||||
*ngIf="filter.topLevelFilter"
|
||||
[dossierTemplateId]="stateService.dossierTemplateId"
|
||||
[filter]="filter"
|
||||
></redaction-type-filter>
|
||||
|
||||
<ng-container *ngIf="!filter.topLevelFilter">
|
||||
<redaction-dictionary-annotation-icon
|
||||
[dictionaryKey]="filter.id"
|
||||
[dossierTemplateId]="stateService.dossierTemplateId"
|
||||
></redaction-dictionary-annotation-icon>
|
||||
|
||||
{{ filter.label | humanize: false }}
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
|
||||
@ -277,6 +277,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
selectPage(pageNumber: number) {
|
||||
this.viewerComponent.utils.navigateToPage(pageNumber);
|
||||
this._workloadComponent?.scrollAnnotationsToPage(pageNumber, 'always');
|
||||
this._lastPage = pageNumber.toString();
|
||||
}
|
||||
|
||||
openManualAnnotationDialog(manualRedactionEntryWrapper: ManualRedactionEntryWrapper) {
|
||||
@ -421,7 +422,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
|
||||
async downloadOriginalFile(file: File) {
|
||||
const data = await this._fileManagementService
|
||||
.downloadOriginalFile(this.dossierId, this.fileId, 'response', true, file.cacheIdentifier)
|
||||
.downloadOriginalFile(this.dossierId, this.fileId, 'response', file.cacheIdentifier)
|
||||
.toPromise();
|
||||
download(data, file.filename);
|
||||
}
|
||||
@ -693,7 +694,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
||||
this._instance.Core.annotationManager.showAnnotations(annotations);
|
||||
}
|
||||
|
||||
private async _setAnnotationsColor(annotations: Annotation[], customData: string) {
|
||||
private _setAnnotationsColor(annotations: Annotation[], customData: string) {
|
||||
annotations.forEach(annotation => {
|
||||
annotation['StrokeColor'] = this._annotationDrawService.convertColor(this._instance, annotation.getCustomData(customData));
|
||||
});
|
||||
|
||||
@ -45,7 +45,7 @@ export class AnnotationDrawService {
|
||||
}
|
||||
|
||||
getColor(activeViewer: WebViewerInstance, dossierTemplateId: string, superType: string, dictionary?: string) {
|
||||
let color;
|
||||
let color: string;
|
||||
switch (superType) {
|
||||
case 'hint':
|
||||
case 'redaction':
|
||||
@ -62,11 +62,11 @@ export class AnnotationDrawService {
|
||||
return color;
|
||||
}
|
||||
|
||||
public getAndConvertColor(activeViewer: WebViewerInstance, dossierTemplateId: string, superType: string, dictionary?: string) {
|
||||
getAndConvertColor(activeViewer: WebViewerInstance, dossierTemplateId: string, superType: string, dictionary?: string) {
|
||||
return this.convertColor(activeViewer, this.getColor(activeViewer, dossierTemplateId, superType, dictionary));
|
||||
}
|
||||
|
||||
public convertColor(activeViewer: WebViewerInstance, hexColor: string) {
|
||||
convertColor(activeViewer: WebViewerInstance, hexColor: string) {
|
||||
const rgbColor = hexToRgb(hexColor);
|
||||
return new activeViewer.Core.Annotations.Color(rgbColor.r, rgbColor.g, rgbColor.b);
|
||||
}
|
||||
@ -108,7 +108,7 @@ export class AnnotationDrawService {
|
||||
}
|
||||
|
||||
private async _drawSections(activeViewer: WebViewerInstance, sectionGrid: ISectionGrid, dossierId: string) {
|
||||
const sections = [];
|
||||
const sections: Core.Annotations.RectangleAnnotation[] = [];
|
||||
for (const page of Object.keys(sectionGrid.rectanglesPerPage)) {
|
||||
const sectionRectangles = sectionGrid.rectanglesPerPage[page];
|
||||
sectionRectangles.forEach(sectionRectangle => {
|
||||
@ -154,7 +154,7 @@ export class AnnotationDrawService {
|
||||
const pageNumber = compareMode ? annotationWrapper.pageNumber * 2 - 1 : annotationWrapper.pageNumber;
|
||||
const dossierTemplateId = this._dossiersService.find(dossierId).dossierTemplateId;
|
||||
|
||||
let annotation;
|
||||
let annotation: Core.Annotations.RectangleAnnotation | Core.Annotations.TextHighlightAnnotation;
|
||||
if (annotationWrapper.rectangle || annotationWrapper.isImage) {
|
||||
annotation = new activeViewer.Core.Annotations.RectangleAnnotation();
|
||||
const pageHeight = activeViewer.Core.documentViewer.getPageHeight(pageNumber);
|
||||
|
||||
@ -1,44 +1,80 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, firstValueFrom, Observable } from 'rxjs';
|
||||
import { BehaviorSubject, firstValueFrom, Observable, pairwise, switchMap } from 'rxjs';
|
||||
import { FileDataModel } from '@models/file/file-data.model';
|
||||
import { Dossier, File } from '@red/domain';
|
||||
import { DossiersService } from '../../../../../services/entity-services/dossiers.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { FilesMapService } from '../../../../../services/entity-services/files-map.service';
|
||||
import { PermissionsService } from '../../../../../services/permissions.service';
|
||||
import { boolFactory, shareLast } from '@iqser/common-ui';
|
||||
import { filter, startWith } from 'rxjs/operators';
|
||||
import { FileManagementService } from '../../../../../services/entity-services/file-management.service';
|
||||
|
||||
@Injectable()
|
||||
export class FilePreviewStateService {
|
||||
readonly fileData$: Observable<FileDataModel>;
|
||||
readonly file$: Observable<File>;
|
||||
readonly blob$: Observable<Blob>;
|
||||
readonly dossier$: Observable<Dossier>;
|
||||
readonly isReadonly$: Observable<boolean>;
|
||||
readonly isWritable$: Observable<boolean>;
|
||||
readonly fileData$: Observable<FileDataModel>;
|
||||
|
||||
readonly dossierId: string;
|
||||
readonly dossierTemplateId: string;
|
||||
readonly fileId: string;
|
||||
private readonly _fileData$ = new BehaviorSubject<FileDataModel>(undefined);
|
||||
|
||||
readonly #fileData$ = new BehaviorSubject<FileDataModel | undefined>(undefined);
|
||||
|
||||
constructor(
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _filesMapService: FilesMapService,
|
||||
dossiersService: DossiersService,
|
||||
filesMapService: FilesMapService,
|
||||
permissionsService: PermissionsService,
|
||||
activatedRoute: ActivatedRoute,
|
||||
private readonly _fileManagementService: FileManagementService,
|
||||
) {
|
||||
this.dossierId = activatedRoute.snapshot.paramMap.get('dossierId');
|
||||
this.dossierTemplateId = this._dossiersService.find(this.dossierId).dossierTemplateId;
|
||||
this.dossier$ = _dossiersService.getEntityChanged$(this.dossierId);
|
||||
this.fileId = activatedRoute.snapshot.paramMap.get('fileId');
|
||||
this.dossierId = activatedRoute.snapshot.paramMap.get('dossierId');
|
||||
this.dossierTemplateId = dossiersService.find(this.dossierId).dossierTemplateId;
|
||||
|
||||
this.fileData$ = this._fileData$.asObservable();
|
||||
this.file$ = _filesMapService.watch$(this.dossierId, this.fileId);
|
||||
this.dossier$ = dossiersService.getEntityChanged$(this.dossierId);
|
||||
this.file$ = filesMapService.watch$(this.dossierId, this.fileId);
|
||||
[this.isReadonly$, this.isWritable$] = boolFactory(this.file$, file => !permissionsService.canPerformAnnotationActions(file));
|
||||
|
||||
this.fileData$ = this.#fileData$.asObservable().pipe(filter(value => !!value));
|
||||
this.blob$ = this.#blob$;
|
||||
}
|
||||
|
||||
get fileData(): FileDataModel {
|
||||
return this._fileData$.value;
|
||||
return this.#fileData$.value;
|
||||
}
|
||||
|
||||
set fileData(fileDataModel: FileDataModel) {
|
||||
this._fileData$.next(fileDataModel);
|
||||
this.#fileData$.next(fileDataModel);
|
||||
}
|
||||
|
||||
get file(): Promise<File> {
|
||||
return firstValueFrom(this.file$);
|
||||
}
|
||||
|
||||
get dossier(): Promise<Dossier> {
|
||||
return firstValueFrom(this.dossier$);
|
||||
}
|
||||
|
||||
get blob(): Promise<Blob> {
|
||||
return firstValueFrom(this.blob$);
|
||||
}
|
||||
|
||||
get #blob$() {
|
||||
return this.file$.pipe(
|
||||
startWith(undefined),
|
||||
pairwise(),
|
||||
filter(([oldFile, newFile]) => oldFile?.cacheIdentifier !== newFile.cacheIdentifier),
|
||||
switchMap(([, newFile]) => this.#downloadOriginalFile(newFile.cacheIdentifier)),
|
||||
shareLast(),
|
||||
);
|
||||
}
|
||||
|
||||
#downloadOriginalFile(cacheIdentifier: string): Observable<Blob> {
|
||||
return this._fileManagementService.downloadOriginalFile(this.dossierId, this.fileId, 'body', cacheIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,32 +1,30 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { shareDistinctLast } from '@iqser/common-ui';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { boolFactory } from '@iqser/common-ui';
|
||||
|
||||
@Injectable()
|
||||
export class MultiSelectService {
|
||||
readonly active$: Observable<boolean>;
|
||||
readonly inactive$: Observable<boolean>;
|
||||
private readonly _active$ = new BehaviorSubject(false);
|
||||
readonly #active$ = new BehaviorSubject(false);
|
||||
|
||||
constructor() {
|
||||
this.active$ = this._active$.asObservable().pipe(shareDistinctLast());
|
||||
this.inactive$ = this.active$.pipe(map(value => !value));
|
||||
[this.active$, this.inactive$] = boolFactory(this.#active$.asObservable());
|
||||
}
|
||||
|
||||
get isActive() {
|
||||
return this._active$.value;
|
||||
return this.#active$.value;
|
||||
}
|
||||
|
||||
activate() {
|
||||
this._active$.next(true);
|
||||
this.#active$.next(true);
|
||||
}
|
||||
|
||||
deactivate() {
|
||||
this._active$.next(false);
|
||||
this.#active$.next(false);
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this._active$.next(!this._active$.value);
|
||||
this.#active$.next(!this.#active$.value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,23 +1,19 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { forkJoin, Observable, of, switchMap } from 'rxjs';
|
||||
import { catchError, map, take, tap } from 'rxjs/operators';
|
||||
import { forkJoin, Observable, of } from 'rxjs';
|
||||
import { catchError, map, tap } from 'rxjs/operators';
|
||||
import { FileDataModel } from '@models/file/file-data.model';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
import { File, IRedactionLog, IViewedPage } from '@red/domain';
|
||||
import { FileManagementService } from '@services/entity-services/file-management.service';
|
||||
import { RedactionLogService } from './redaction-log.service';
|
||||
import { ViewedPagesService } from '@services/entity-services/viewed-pages.service';
|
||||
import { AppStateService } from '../../../state/app-state.service';
|
||||
import { DossiersService } from '../../../services/entity-services/dossiers.service';
|
||||
import { UserPreferenceService } from '../../../services/user-preference.service';
|
||||
import { FilePreviewStateService } from '../screens/file-preview-screen/services/file-preview-state.service';
|
||||
|
||||
@Injectable()
|
||||
export class PdfViewerDataService {
|
||||
constructor(
|
||||
private readonly _dossiersService: DossiersService,
|
||||
private readonly _permissionsService: PermissionsService,
|
||||
private readonly _fileManagementService: FileManagementService,
|
||||
private readonly _redactionLogService: RedactionLogService,
|
||||
private readonly _viewedPagesService: ViewedPagesService,
|
||||
private readonly _appStateService: AppStateService,
|
||||
@ -33,24 +29,16 @@ export class PdfViewerDataService {
|
||||
}
|
||||
|
||||
loadDataFor(newFile: File): Observable<FileDataModel> {
|
||||
const oldBlob$ = this._stateService.fileData?.blob$;
|
||||
const blob$ = this._stateService.file$.pipe(
|
||||
map(file => file.cacheIdentifier === newFile.cacheIdentifier && oldBlob$),
|
||||
switchMap(isSame => (isSame ? oldBlob$ : this.downloadOriginalFile(newFile))),
|
||||
take(1),
|
||||
);
|
||||
const redactionLog$ = this.loadRedactionLogFor(newFile.dossierId, newFile.fileId);
|
||||
const viewedPages$ = this.getViewedPagesFor(newFile);
|
||||
|
||||
const dossier = this._dossiersService.find(newFile.dossierId);
|
||||
|
||||
return forkJoin([blob$, redactionLog$, viewedPages$]).pipe(
|
||||
return forkJoin([redactionLog$, viewedPages$]).pipe(
|
||||
map(
|
||||
(data: [blob: Blob, redactionLog: IRedactionLog, viewedPages: IViewedPage[]]) =>
|
||||
(data: [redactionLog: IRedactionLog, viewedPages: IViewedPage[]]) =>
|
||||
new FileDataModel(
|
||||
newFile,
|
||||
...data,
|
||||
this._appStateService.dictionaryData[dossier.dossierTemplateId],
|
||||
this._appStateService.dictionaryData[this._stateService.dossierTemplateId],
|
||||
this._userPreferenceService.areDevFeaturesEnabled,
|
||||
),
|
||||
),
|
||||
@ -63,8 +51,4 @@ export class PdfViewerDataService {
|
||||
}
|
||||
return of([]);
|
||||
}
|
||||
|
||||
downloadOriginalFile(file: File): Observable<Blob> {
|
||||
return this._fileManagementService.downloadOriginalFile(file.dossierId, file.fileId, 'body', true, file.cacheIdentifier);
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,26 +36,16 @@ export class FileManagementService extends GenericService<unknown> {
|
||||
return this._post(body, `delete/restore/${dossierId}`).pipe(switchMap(() => this._filesService.loadAll(dossierId)));
|
||||
}
|
||||
|
||||
downloadOriginalFile(dossierId: string, fileId: string, observe?: 'body', inline?: boolean, indicator?: string): Observable<Blob>;
|
||||
downloadOriginalFile(
|
||||
dossierId: string,
|
||||
fileId: string,
|
||||
observe?: 'response',
|
||||
inline?: boolean,
|
||||
indicator?: string,
|
||||
): Observable<HttpResponse<Blob>>;
|
||||
downloadOriginalFile(dossierId: string, fileId: string, observe?: 'body', indicator?: string): Observable<Blob>;
|
||||
downloadOriginalFile(dossierId: string, fileId: string, observe?: 'response', indicator?: string): Observable<HttpResponse<Blob>>;
|
||||
@Validate()
|
||||
downloadOriginalFile(
|
||||
@RequiredParam() dossierId: string,
|
||||
@RequiredParam() fileId: string,
|
||||
observe: 'body' | 'response' = 'body',
|
||||
inline?: boolean,
|
||||
indicator?: string,
|
||||
) {
|
||||
const queryParams: QueryParam[] = [];
|
||||
if (inline) {
|
||||
queryParams.push({ key: 'inline', value: inline });
|
||||
}
|
||||
const queryParams: QueryParam[] = [{ key: 'inline', value: true }];
|
||||
|
||||
if (indicator) {
|
||||
queryParams.push({ key: 'indicator', value: indicator });
|
||||
|
||||
@ -113,8 +113,8 @@ export class UserService extends EntitiesService<User, IUser> {
|
||||
|
||||
find(id: string): User | undefined {
|
||||
if (id?.toLowerCase() === 'system') {
|
||||
return new User({ email: 'System' }, [], 'system');
|
||||
return new User({ username: 'System' }, [], 'system');
|
||||
}
|
||||
return super.find(id);
|
||||
return super.find(id) || new User({ username: 'Deleted User' }, [], 'deleted');
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,5 +19,6 @@
|
||||
"OAUTH_IDP_HINT": null,
|
||||
"OAUTH_URL": "https://dev-05.iqser.cloud/auth/realms/redaction",
|
||||
"RECENT_PERIOD_IN_HOURS": 24,
|
||||
"SELECTION_MODE": "structural"
|
||||
"SELECTION_MODE": "structural",
|
||||
"MANUAL_BASE_URL": "https://docs.redactmanager.com/3.0"
|
||||
}
|
||||
|
||||
@ -1,42 +1,42 @@
|
||||
{
|
||||
"open-usermenu": {
|
||||
"en": "https://docs.redactmanager.com/2.2/en/user-menu-and-profile.html",
|
||||
"en": "/en/23200-user-menu-and-account.html",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"filter-dossier-list": {
|
||||
"en": "https://docs.redactmanager.com/2.2/en/creating-and-managing-dossiers/dossier-overview/dossier-list.html#UUID-e5177955-3e92-8627-0732-af8d4a2036e2",
|
||||
"en": "/en/26024-features-and-actions-in-the-dossier-overview.html",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"filter-document-list": {
|
||||
"en": "https://docs.redactmanager.com/preview/en/create-and-manage-dossier/dossier-overview/dossier-list.html",
|
||||
"en": "/en/create-and-manage-dossier/dossier-overview/dossier-list.html",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"dossiers-quickfilter-my-dossiers": {
|
||||
"en": "https://docs.redactmanager.com/preview/en/create-and-manage-dossier/dossier-overview/dossier-list.html",
|
||||
"en": "/en/create-and-manage-dossier/dossier-overview/dossier-list.html",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"search-in-entire-application": {
|
||||
"en": "https://docs.redactmanager.com/2.2/en/searching-the-application.html",
|
||||
"en": "/en/15632-searching-the-application.html",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"open-notifications": {
|
||||
"en": "https://docs.redactmanager.com/2.2/en/notifications.html",
|
||||
"en": "/en/15471-notifications.html",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"dossier-list": {
|
||||
"en": "https://docs.redactmanager.com/2.2/en/20941-dossier-liste.html",
|
||||
"en": "/en/20941-dossier-liste.html",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
@ -48,7 +48,7 @@
|
||||
"fr": ""
|
||||
},
|
||||
"new-dossier-button": {
|
||||
"en": "https://docs.redactmanager.com/2.2/en/creating-and-managing-dossiers/dossier-overview/creating-a-new-dossier.html",
|
||||
"en": "/en/creating-and-managing-dossiers/dossier-overview/creating-a-new-dossier.html",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
@ -90,19 +90,19 @@
|
||||
"fr": ""
|
||||
},
|
||||
"standard-view": {
|
||||
"en": "https://docs.redactmanager.com/2.2/en/editing-documents-in-the-editor/views-in-the-editor/standard-view.html",
|
||||
"en": "/en/editing-documents-in-the-editor/views-in-the-editor/standard-view.html",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"delta-view": {
|
||||
"en": "https://docs.redactmanager.com/2.2/en/editing-documents-in-the-editor/views-in-the-editor/delta-view.html",
|
||||
"en": "/en/editing-documents-in-the-editor/views-in-the-editor/delta-view.html",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
},
|
||||
"preview-view": {
|
||||
"en": "https://docs.redactmanager.com/2.2/en/editing-documents-in-the-editor/views-in-the-editor/preview.html",
|
||||
"en": "/en/editing-documents-in-the-editor/views-in-the-editor/preview.html",
|
||||
"de": "",
|
||||
"it": "",
|
||||
"fr": ""
|
||||
|
||||
@ -498,7 +498,7 @@
|
||||
"defaultColor": "Default Color",
|
||||
"dictionaryRequestColor": "Dictionary Request",
|
||||
"ignoredHintColor": "Ignored Hint",
|
||||
"manualRedactionColor": "Manual Redaction",
|
||||
"manualRedactionColor": "Redaction Color",
|
||||
"notRedacted": "Skipped",
|
||||
"previewColor": "Preview",
|
||||
"requestAdd": "Request Add",
|
||||
|
||||
@ -23,6 +23,7 @@ OAUTH_IDP_HINT="${OAUTH_IDP_HINT:-}"
|
||||
OAUTH_URL="${OAUTH_URL:-/auth}"
|
||||
RECENT_PERIOD_IN_HOURS="${RECENT_PERIOD_IN_HOURS:-24}"
|
||||
SELECTION_MODE="${SELECTION_MODE:-structural}"
|
||||
MANUAL_BASE_URL="${MANUAL_BASE_URL:-https://docs.redactmanager.com/3.0}"
|
||||
|
||||
|
||||
|
||||
@ -47,6 +48,7 @@ echo '{
|
||||
"OAUTH_URL":"'"$OAUTH_URL"'",
|
||||
"RECENT_PERIOD_IN_HOURS":'"$RECENT_PERIOD_IN_HOURS"',
|
||||
"SELECTION_MODE":"'"$SELECTION_MODE"'"
|
||||
"MANUAL_BASE_URL":"'"$MANUAL_BASE_URL"'"
|
||||
}' > /usr/share/nginx/html/ui/assets/config/config.json
|
||||
|
||||
echo 'Env variables: '
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit b808e4661e56aa93baca96c57f910443437112d4
|
||||
Subproject commit 6b4fe281cb6e23fb541ce75ead740a5678c968b8
|
||||
@ -18,6 +18,11 @@ export class DossierTemplateStats implements IDossierTemplateStats {
|
||||
}
|
||||
|
||||
dictionarySummary(type: string): DictionarySummary | undefined {
|
||||
return this._dictionarySummaryMap.get(type);
|
||||
const defaultValue: DictionarySummary = { entriesCount: 0, id: type, name: type, type };
|
||||
if (!this._dictionarySummaryMap.get(type)) {
|
||||
// TODO
|
||||
console.error(`Missing type ${type}`);
|
||||
}
|
||||
return this._dictionarySummaryMap.get(type) || defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "redaction",
|
||||
"version": "3.205.0",
|
||||
"version": "3.213.0",
|
||||
"private": true,
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user