Merge branch 'master' into VM/DM-508

This commit is contained in:
Valentin Mihai 2023-10-02 16:02:45 +03:00
commit 9fe3fc39ed
19 changed files with 123 additions and 117 deletions

View File

@ -34,7 +34,7 @@ export function templateExistsWhenEnteringDossierList(): CanActivateFn {
await firstValueFrom(dossierTemplatesService.loadAll()); await firstValueFrom(dossierTemplatesService.loadAll());
const dossierTemplateStats = dashboardStatsService.find(dossierTemplateId); const dossierTemplateStats = dashboardStatsService.find(dossierTemplateId);
if (!dossierTemplateStats || dossierTemplateStats.isEmpty) { if (!dossierTemplateStats || dossierTemplateStats.isEmpty) {
logger.warn('[ROUTES] Dossier template not found, redirecting to main'); logger.warn(`[ROUTES] Dossier template ${dossierTemplateId} not found, redirecting to main`);
await router.navigate([tenantsService.activeTenantId, 'main']); await router.navigate([tenantsService.activeTenantId, 'main']);
return false; return false;
} }

View File

@ -10,6 +10,7 @@ import jwt_decode from 'jwt-decode';
export interface JwtToken { export interface JwtToken {
auth_time: number; auth_time: number;
iat: number;
} }
export function ifLoggedIn(): AsyncGuard { export function ifLoggedIn(): AsyncGuard {
@ -42,7 +43,8 @@ export function ifLoggedIn(): AsyncGuard {
await licenseService.loadLicenses(); await licenseService.loadLicenses();
const token = await keycloakService.getToken(); const token = await keycloakService.getToken();
const authTime = (jwt_decode(token) as JwtToken).auth_time.toString(); const jwtToken = jwt_decode(token) as JwtToken;
const authTime = (jwtToken.auth_time || jwtToken.iat).toString();
localStorage.setItem('authTime', authTime); localStorage.setItem('authTime', authTime);
} }

View File

@ -93,11 +93,11 @@ export class AddEditCloneDossierTemplateDialogComponent extends BaseDialogCompon
} }
this._dialogRef.close(true); this._dialogRef.close(true);
} catch (error) { } catch (error) {
const message = if (error.status === HttpStatusCode.Conflict) {
error.status === HttpStatusCode.Conflict this._toaster.error(_('add-edit-clone-dossier-template.error.conflict'), { error });
? _('add-edit-clone-dossier-template.error.conflict') } else {
: _('add-edit-clone-dossier-template.error.generic'); this._toaster.rawError(error.error.message);
this._toaster.error(message, { error }); }
} }
this._loadingService.stop(); this._loadingService.stop();
} }
@ -114,8 +114,8 @@ export class AddEditCloneDossierTemplateDialogComponent extends BaseDialogCompon
#getForm() { #getForm() {
return this._formBuilder.group({ return this._formBuilder.group({
name: [this.#getCloneName(), Validators.required], name: [this.#getCloneName(), [Validators.required, Validators.maxLength(255)]],
description: [this.dossierTemplate?.description], description: [this.dossierTemplate?.description, Validators.maxLength(4000)],
validFrom: [ validFrom: [
this.dossierTemplate?.validFrom ? dayjs(this.dossierTemplate?.validFrom).toDate() : null, this.dossierTemplate?.validFrom ? dayjs(this.dossierTemplate?.validFrom).toDate() : null,
this.#requiredIfValidator(() => this.hasValidFrom), this.#requiredIfValidator(() => this.hasValidFrom),

View File

@ -1,7 +1,7 @@
<section class="dialog"> <section class="dialog">
<div <div
[innerHTML]=" [innerHTML]="
'add-edit-justification.title' | translate : { type: data.justification ? 'edit' : 'create', name: data.justification?.name } 'add-edit-justification.title' | translate: { type: data.justification ? 'edit' : 'create', name: data.justification?.name }
" "
class="dialog-header heading-l" class="dialog-header heading-l"
></div> ></div>

View File

@ -29,19 +29,25 @@ export class AddEditJustificationDialogComponent extends BaseDialogComponent {
async save() { async save() {
const dossierTemplateId = this.data.dossierTemplateId; const dossierTemplateId = this.data.dossierTemplateId;
this._loadingService.start(); this._loadingService.start();
await firstValueFrom(this._justificationService.createOrUpdate(this.form.getRawValue() as Justification, dossierTemplateId)); try {
await firstValueFrom(this._justificationService.loadAll(dossierTemplateId)); await firstValueFrom(this._justificationService.createOrUpdate(this.form.getRawValue() as Justification, dossierTemplateId));
await firstValueFrom(this._justificationService.loadAll(dossierTemplateId));
this._dialogRef.close(true);
} catch (error) {
this._toaster.rawError(error.error.message);
}
this._loadingService.stop(); this._loadingService.stop();
this._dialogRef.close(true);
} }
private _getForm(): UntypedFormGroup { private _getForm(): UntypedFormGroup {
return this._formBuilder.group({ return this._formBuilder.group({
name: [{ value: this.data.justification?.name, disabled: !!this.data.justification }, Validators.required], name: [
reason: [this.data.justification?.reason, Validators.required], { value: this.data.justification?.name, disabled: !!this.data.justification },
description: [this.data.justification?.description, Validators.required], [Validators.required, Validators.maxLength(255)],
],
reason: [this.data.justification?.reason, [Validators.required, Validators.maxLength(4000)]],
description: [this.data.justification?.description, [Validators.required, Validators.maxLength(4000)]],
}); });
} }
} }

View File

@ -1,3 +1 @@
<div class="canvas-container"> <canvas [data]="chartData" [options]="chartOptions" [type]="'line'" baseChart height="400px" width="1000px"></canvas>
<canvas [data]="chartData" [options]="chartOptions" [type]="'line'" baseChart></canvas>
</div>

View File

@ -1,4 +0,0 @@
.canvas-container {
position: relative;
width: 1000px;
}

View File

@ -32,6 +32,7 @@ export class ChartComponent implements OnChanges {
#setChartOptions(): void { #setChartOptions(): void {
this.chartOptions = { this.chartOptions = {
responsive: false,
scales: { scales: {
y: { y: {
stacked: true, stacked: true,

View File

@ -3,7 +3,6 @@
} }
.grid-container { .grid-container {
width: calc(100% - 40px);
display: grid; display: grid;
grid-template-columns: 250px 300px 1fr; grid-template-columns: 250px 300px 1fr;
margin: 20px; margin: 20px;

View File

@ -3,7 +3,6 @@
} }
.grid-container { .grid-container {
width: calc(100% - 40px);
display: grid; display: grid;
grid-template-columns: 250px 300px 1fr; grid-template-columns: 250px 300px 1fr;
margin: 20px; margin: 20px;

View File

@ -3,7 +3,6 @@
} }
.grid-container { .grid-container {
width: calc(100% - 40px);
display: grid; display: grid;
grid-template-columns: 250px 300px 1fr; grid-template-columns: 250px 300px 1fr;
margin: 20px; margin: 20px;

View File

@ -1,81 +1,77 @@
<section class="settings"> <iqser-page-header
<div> (closeAction)="routerHistoryService.navigateToLastDossiersScreen()"
<iqser-page-header [buttonConfigs]="buttonConfigs"
(closeAction)="routerHistoryService.navigateToLastDossiersScreen()" [pageLabel]="'license-information' | translate"
[buttonConfigs]="buttonConfigs" [showCloseButton]="currentUser.isUser && permissionsService.has$(roles.dossiers.read) | async"
[pageLabel]="'license-information' | translate" ></iqser-page-header>
[showCloseButton]="currentUser.isUser && permissionsService.has$(roles.dossiers.read) | async"
></iqser-page-header>
<div class="content-inner"> <div class="content-inner">
<div class="content-container"> <div class="content-container">
<div *ngIf="licenseService.licenseData$ | async" class="grid-container"> <div *ngIf="licenseService.licenseData$ | async" class="grid-container">
<div class="row"> <div class="row">
<div translate="license-info-screen.backend-version"></div> <div translate="license-info-screen.backend-version"></div>
<div>{{ configService.values.BACKEND_APP_VERSION || '-' }}</div> <div>{{ configService.values.BACKEND_APP_VERSION || '-' }}</div>
</div> </div>
<div class="row"> <div class="row">
<div translate="license-info-screen.custom-app-title"></div> <div translate="license-info-screen.custom-app-title"></div>
<div>{{ configService.values.APP_NAME || '-' }}</div> <div>{{ configService.values.APP_NAME || '-' }}</div>
</div> </div>
<div class="row"> <div class="row">
<div translate="license-info-screen.copyright-claim-title"></div> <div translate="license-info-screen.copyright-claim-title"></div>
<div> <div>
{{ 'license-info-screen.copyright-claim-text' | translate: { currentYear: currentYear } }} {{ 'license-info-screen.copyright-claim-text' | translate: { currentYear: currentYear } }}
</div> </div>
</div> </div>
<div class="row"> <div class="row">
<div translate="license-info-screen.end-user-license-title"></div> <div translate="license-info-screen.end-user-license-title"></div>
<div translate="license-info-screen.end-user-license-text"></div> <div translate="license-info-screen.end-user-license-text"></div>
</div> </div>
<div class="section-title all-caps-label" translate="license-info-screen.licensing-details.section-title"></div> <div class="section-title all-caps-label" translate="license-info-screen.licensing-details.section-title"></div>
<div class="row"> <div class="row">
<div class="flex-align-items-center" translate="license-info-screen.licensing-details.license-title"></div> <div class="flex-align-items-center" translate="license-info-screen.licensing-details.license-title"></div>
<div> <div>
<redaction-license-select></redaction-license-select> <redaction-license-select></redaction-license-select>
</div> </div>
</div> </div>
<ng-container *ngIf="licenseService.selectedLicense$ | async as selectedLicense"> <ng-container *ngIf="licenseService.selectedLicense$ | async as selectedLicense">
<div class="row"> <div class="row">
<div translate="license-info-screen.licensing-details.licensed-to"></div> <div translate="license-info-screen.licensing-details.licensed-to"></div>
<div>{{ selectedLicense.licensedTo || '-' }}</div> <div>{{ selectedLicense.licensedTo || '-' }}</div>
</div>
<div class="row">
<div translate="license-info-screen.licensing-details.licensing-period"></div>
<div>
{{ (selectedLicense.validFrom | date: 'dd-MM-yyyy') || '-' }} /
{{ (selectedLicense.validUntil | date: 'dd-MM-yyyy') || '-' }}
</div>
</div>
</ng-container>
<div *ngIf="licenseService.isPageBased" class="row">
<div>{{ 'license-info-screen.licensing-details.licensed-page-count' | translate }}</div>
<div>{{ licenseService.totalLicensedNumberOfPages }}</div>
</div>
<div *ngIf="licenseService.isCapacityBased" class="row">
<div>{{ 'license-info-screen.licensing-details.licensed-analysis-capacity' | translate }}</div>
<div>{{ licenseService.analysisCapacityBytes | size }}</div>
</div>
<div *ngIf="licenseService.isCapacityBased" class="row">
<div>{{ 'license-info-screen.licensing-details.licensed-retention-capacity' | translate }}</div>
<div>{{ licenseService.retentionCapacityBytes | size }}</div>
</div>
</div> </div>
<red-license-page-usage *ngIf="licenseService.isPageBased"></red-license-page-usage> <div class="row">
<red-license-analysis-capacity-usage *ngIf="licenseService.isCapacityBased"></red-license-analysis-capacity-usage> <div translate="license-info-screen.licensing-details.licensing-period"></div>
<red-license-retention-capacity *ngIf="licenseService.isCapacityBased"></red-license-retention-capacity> <div>
{{ (selectedLicense.validFrom | date: 'dd-MM-yyyy') || '-' }} /
{{ (selectedLicense.validUntil | date: 'dd-MM-yyyy') || '-' }}
</div>
</div>
</ng-container>
<div *ngIf="licenseService.isPageBased" class="row">
<div>{{ 'license-info-screen.licensing-details.licensed-page-count' | translate }}</div>
<div>{{ licenseService.totalLicensedNumberOfPages }}</div>
</div>
<div *ngIf="licenseService.isCapacityBased" class="row">
<div>{{ 'license-info-screen.licensing-details.licensed-analysis-capacity' | translate }}</div>
<div>{{ licenseService.analysisCapacityBytes | size }}</div>
</div>
<div *ngIf="licenseService.isCapacityBased" class="row">
<div>{{ 'license-info-screen.licensing-details.licensed-retention-capacity' | translate }}</div>
<div>{{ licenseService.retentionCapacityBytes | size }}</div>
</div> </div>
</div> </div>
<red-license-page-usage *ngIf="licenseService.isPageBased"></red-license-page-usage>
<red-license-analysis-capacity-usage *ngIf="licenseService.isCapacityBased"></red-license-analysis-capacity-usage>
<red-license-retention-capacity *ngIf="licenseService.isCapacityBased"></red-license-retention-capacity>
</div> </div>
</section> </div>

View File

@ -4,12 +4,7 @@
overflow: auto; overflow: auto;
@include common-mixins.scroll-bar; @include common-mixins.scroll-bar;
display: flex;
flex-direction: column;
align-items: center;
.grid-container { .grid-container {
width: calc(100% - 40px);
display: grid; display: grid;
grid-template-columns: 250px 300px 1fr; grid-template-columns: 250px 300px 1fr;
margin: 20px; margin: 20px;

View File

@ -1,5 +1,5 @@
import { Component, inject, OnInit } from '@angular/core'; import { Component, inject, OnInit } from '@angular/core';
import { FormBuilder, FormControl } from '@angular/forms'; import { FormBuilder, FormControl, Validators } from '@angular/forms';
import { DetailsRadioOption, IconButtonTypes, IqserDialogComponent } from '@iqser/common-ui'; import { DetailsRadioOption, IconButtonTypes, IqserDialogComponent } from '@iqser/common-ui';
import { Dictionary, SuperTypes } from '@red/domain'; import { Dictionary, SuperTypes } from '@red/domain';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service'; import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
@ -58,7 +58,7 @@ export class EditRedactionDialogComponent
} }
get disabled() { get disabled() {
return this.showExtras ? !this.form.controls.reason.value : false; return this.form.invalid || (this.showExtras ? !this.form.controls.reason.value : false);
} }
async ngOnInit() { async ngOnInit() {
@ -126,7 +126,7 @@ export class EditRedactionDialogComponent
const sameSection = this.data.annotations.every(annotation => annotation.section === this.data.annotations[0].section); const sameSection = this.data.annotations.every(annotation => annotation.section === this.data.annotations[0].section);
return this._formBuilder.group({ return this._formBuilder.group({
reason: new FormControl<LegalBasisOption>(null), reason: new FormControl<LegalBasisOption>(null),
comment: new FormControl<string>(null), comment: new FormControl<string>(null, Validators.maxLength(4000)),
type: new FormControl<string>(sameType ? this.data.annotations[0].type : null), type: new FormControl<string>(sameType ? this.data.annotations[0].type : null),
section: new FormControl<string>(sameSection ? this.data.annotations[0].section : null), section: new FormControl<string>(sameSection ? this.data.annotations[0].section : null),
option: new FormControl<LegalBasisOption>(null), option: new FormControl<LegalBasisOption>(null),

View File

@ -397,8 +397,6 @@ export class FilePreviewScreenComponent
$event.preventDefault(); $event.preventDefault();
this.fullScreen = false; this.fullScreen = false;
this.closeFullScreen(); this.closeFullScreen();
this.pdf.deactivateSearch();
this.pdf.focusViewer();
this._changeRef.markForCheck(); this._changeRef.markForCheck();
} }

View File

@ -1,6 +1,6 @@
import { Injectable } from '@angular/core'; import { Injectable } from '@angular/core';
import { IqserDialog } from '@common-ui/dialog/iqser-dialog.service'; import { IqserDialog } from '@common-ui/dialog/iqser-dialog.service';
import { getConfig } 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';
import { AnnotationPermissions } from '@models/file/annotation.permissions'; import { AnnotationPermissions } from '@models/file/annotation.permissions';
import { AnnotationWrapper } from '@models/file/annotation.wrapper'; import { AnnotationWrapper } from '@models/file/annotation.wrapper';
@ -60,6 +60,7 @@ export class AnnotationActionsService {
private readonly _skippedService: SkippedService, private readonly _skippedService: SkippedService,
private readonly _dossierTemplatesService: DossierTemplatesService, private readonly _dossierTemplatesService: DossierTemplatesService,
private readonly _permissionsService: PermissionsService, private readonly _permissionsService: PermissionsService,
private readonly _toaster: Toaster,
) {} ) {}
removeHighlights(highlights: AnnotationWrapper[]): void { removeHighlights(highlights: AnnotationWrapper[]): void {
@ -126,8 +127,12 @@ export class AnnotationActionsService {
} }
if (result.comment) { if (result.comment) {
for (const a of annotations) { try {
await this._manualRedactionService.addComment(result.comment, a.id, dossierId, fileId); for (const a of annotations) {
await this._manualRedactionService.addComment(result.comment, a.id, dossierId, fileId);
}
} catch (error) {
this._toaster.rawError(error.error.message);
} }
} }

View File

@ -108,14 +108,9 @@ export class PdfViewer {
} }
deactivateSearch() { deactivateSearch() {
this.#clearSearchResultsWhenVisibilityChanged();
this.#instance.UI.closeElements(['searchPanel']); this.#instance.UI.closeElements(['searchPanel']);
} }
focusViewer() {
this.instance.UI.iframeWindow.focus();
}
resetAnnotationActions() { resetAnnotationActions() {
if (this.#instance.UI.annotationPopup.getItems().length) { if (this.#instance.UI.annotationPopup.getItems().length) {
this.#logger.info('[PDF] Reset annotation actions'); this.#logger.info('[PDF] Reset annotation actions');
@ -167,8 +162,9 @@ export class PdfViewer {
this.#setSelectionMode(); this.#setSelectionMode();
this.#configureElements(); this.#configureElements();
this.#disableHotkeys(); this.#disableHotkeys();
this.#clearSearchResultsWhenVisibilityChanged();
this.#listenForCommandF(); this.#listenForCommandF();
this.#listenForEsc();
this.#clearSearchResultsWhenVisibilityChanged();
}); });
return this.#instance; return this.#instance;
@ -267,6 +263,16 @@ export class PdfViewer {
}); });
} }
#listenForEsc() {
this.#instance.UI.hotkeys.on('esc', e => {
e.preventDefault();
if (this.#isElementActive('searchPanel')) {
this.deactivateSearch();
this.#focusViewer();
}
});
}
#adjustPage(page: number) { #adjustPage(page: number) {
if (this.isCompareMode()) { if (this.isCompareMode()) {
if (page % 2 === 1) { if (page % 2 === 1) {
@ -351,4 +357,9 @@ export class PdfViewer {
input.select(); input.select();
} }
} }
#focusViewer() {
this.instance.UI.iframeWindow.document.getElementById('SearchPanel__input').blur();
this.instance.UI.iframeWindow.focus();
}
} }

View File

@ -33,7 +33,8 @@ export class RouterHistoryService {
} }
const token = await this._keycloakService.getToken(); const token = await this._keycloakService.getToken();
const authTime = (jwt_decode(token) as JwtToken).auth_time; const jwtToken = jwt_decode(token) as JwtToken;
const authTime = (jwtToken.auth_time || jwtToken.iat).toString();
const localStorageAuthTime = localStorage.getItem('authTime'); const localStorageAuthTime = localStorage.getItem('authTime');
if (authTime.toString() !== localStorageAuthTime) { if (authTime.toString() !== localStorageAuthTime) {

@ -1 +1 @@
Subproject commit 6dc910c4ca6182fd4f1d6746b1114ad5210229a8 Subproject commit a9d6e5e7286b7655140a3ed19c9f0b9c5464b0ae