Merge branch 'master' into VM/RED-3982
This commit is contained in:
commit
c7217d7ae4
@ -1,5 +1,5 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { ActivatedRouteSnapshot, CanActivate } from '@angular/router';
|
import { CanActivate } from '@angular/router';
|
||||||
import { firstValueFrom } from 'rxjs';
|
import { firstValueFrom } from 'rxjs';
|
||||||
import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service';
|
import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service';
|
||||||
|
|
||||||
@ -7,7 +7,7 @@ import { DashboardStatsService } from '@services/dossier-templates/dashboard-sta
|
|||||||
export class DashboardGuard implements CanActivate {
|
export class DashboardGuard implements CanActivate {
|
||||||
constructor(private readonly _dashboardStatsService: DashboardStatsService) {}
|
constructor(private readonly _dashboardStatsService: DashboardStatsService) {}
|
||||||
|
|
||||||
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
|
async canActivate(): Promise<boolean> {
|
||||||
await firstValueFrom(this._dashboardStatsService.loadAll());
|
await firstValueFrom(this._dashboardStatsService.loadAll());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,19 +2,32 @@ import { Injectable } from '@angular/core';
|
|||||||
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
|
import { ActivatedRouteSnapshot, CanActivate, Router } from '@angular/router';
|
||||||
import { DOSSIER_TEMPLATE_ID } from '@red/domain';
|
import { DOSSIER_TEMPLATE_ID } from '@red/domain';
|
||||||
import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service';
|
import { DashboardStatsService } from '@services/dossier-templates/dashboard-stats.service';
|
||||||
|
import { DossierTemplatesService } from '@services/dossier-templates/dossier-templates.service';
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class DossierTemplateExistsGuard implements CanActivate {
|
export class DossierTemplateExistsGuard implements CanActivate {
|
||||||
constructor(private readonly _dashboardStatsService: DashboardStatsService, private readonly _router: Router) {}
|
constructor(
|
||||||
|
private readonly _dashboardStatsService: DashboardStatsService,
|
||||||
|
private readonly _dossierTemplatesService: DossierTemplatesService,
|
||||||
|
private readonly _router: Router,
|
||||||
|
) {}
|
||||||
|
|
||||||
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
|
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
|
||||||
const dossierTemplateId: string = route.paramMap.get(DOSSIER_TEMPLATE_ID);
|
const dossierTemplateId: string = route.paramMap.get(DOSSIER_TEMPLATE_ID);
|
||||||
const dossiersListView = !route.pathFromRoot.find(r => r.routeConfig?.path === 'admin');
|
const dossiersListView = !route.pathFromRoot.find(r => r.routeConfig?.path === 'admin');
|
||||||
const dossierTemplateStats = this._dashboardStatsService.find(dossierTemplateId);
|
|
||||||
if (!dossierTemplateStats || (dossiersListView && dossierTemplateStats.isEmpty)) {
|
if (dossiersListView) {
|
||||||
const routerPath = dossiersListView ? [''] : ['main', 'admin', 'dossier-templates'];
|
const dossierTemplateStats = this._dashboardStatsService.find(dossierTemplateId);
|
||||||
await this._router.navigate(routerPath);
|
if (!dossierTemplateStats || (dossiersListView && dossierTemplateStats.isEmpty)) {
|
||||||
return false;
|
await this._router.navigate(['']);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const dossierTemplate = this._dossierTemplatesService.find(dossierTemplateId);
|
||||||
|
if (!dossierTemplate) {
|
||||||
|
await this._router.navigate(['main', 'admin', 'dossier-templates']);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
|||||||
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||||
import { BaseFormComponent, LoadingService, Toaster } from '@iqser/common-ui';
|
import { BaseFormComponent, LoadingService, Toaster } from '@iqser/common-ui';
|
||||||
|
|
||||||
const REDACTION_FIELDS = ['defaultReason', 'caseSensitive', 'addToDictionaryAction'];
|
const REDACTION_FIELDS = ['defaultReason', 'addToDictionaryAction'];
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-add-edit-entity [entity] [dossierTemplateId]',
|
selector: 'redaction-add-edit-entity [entity] [dossierTemplateId]',
|
||||||
@ -38,10 +38,6 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
get #caseSensitiveControl() {
|
|
||||||
return { value: this.entity ? !this.entity.caseInsensitive : false, disabled: this.#isSystemManaged };
|
|
||||||
}
|
|
||||||
|
|
||||||
get #isSystemManaged(): boolean {
|
get #isSystemManaged(): boolean {
|
||||||
return !!this.entity?.systemManaged;
|
return !!this.entity?.systemManaged;
|
||||||
}
|
}
|
||||||
@ -91,12 +87,12 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit
|
|||||||
recommendationHexColor: [this.entity?.recommendationHexColor, [Validators.required, Validators.minLength(7)]],
|
recommendationHexColor: [this.entity?.recommendationHexColor, [Validators.required, Validators.minLength(7)]],
|
||||||
hint: [{ value: !!this.entity?.hint, disabled: this.#isSystemManaged }],
|
hint: [{ value: !!this.entity?.hint, disabled: this.#isSystemManaged }],
|
||||||
hasDictionary: [{ value: !!this.entity?.hasDictionary, disabled: this.#isSystemManaged }],
|
hasDictionary: [{ value: !!this.entity?.hasDictionary, disabled: this.#isSystemManaged }],
|
||||||
|
caseSensitive: [{ value: this.entity ? !this.entity.caseInsensitive : false, disabled: this.#isSystemManaged }],
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!this.entity?.hint) {
|
if (!this.entity?.hint) {
|
||||||
Object.assign(controlsConfig, {
|
Object.assign(controlsConfig, {
|
||||||
defaultReason: [{ value: null, disabled: true }],
|
defaultReason: [{ value: null, disabled: true }],
|
||||||
caseSensitive: [this.#caseSensitiveControl],
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.entity?.hasDictionary) {
|
if (this.entity?.hasDictionary) {
|
||||||
@ -116,7 +112,6 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit
|
|||||||
REDACTION_FIELDS.forEach(field => form.removeControl(field));
|
REDACTION_FIELDS.forEach(field => form.removeControl(field));
|
||||||
} else {
|
} else {
|
||||||
form.addControl('defaultReason', new FormControl({ value: null, disabled: true }));
|
form.addControl('defaultReason', new FormControl({ value: null, disabled: true }));
|
||||||
form.addControl('caseSensitive', new FormControl(this.#caseSensitiveControl));
|
|
||||||
|
|
||||||
if (form.get('hasDictionary').value) {
|
if (form.get('hasDictionary').value) {
|
||||||
form.addControl('addToDictionaryAction', new FormControl(this.#addToDictionaryActionControl));
|
form.addControl('addToDictionaryAction', new FormControl(this.#addToDictionaryActionControl));
|
||||||
@ -167,7 +162,6 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit
|
|||||||
|
|
||||||
private _formToObject(): IDictionary {
|
private _formToObject(): IDictionary {
|
||||||
// Fields that aren't set for hints, need additional check
|
// Fields that aren't set for hints, need additional check
|
||||||
const caseInsensitive = this.form.get('caseSensitive') ? !this.form.get('caseSensitive').value : null;
|
|
||||||
const addToDictionaryAction = !!this.form.get('addToDictionaryAction')?.value;
|
const addToDictionaryAction = !!this.form.get('addToDictionaryAction')?.value;
|
||||||
const hasDictionary = !!this.form.get('hasDictionary')?.value;
|
const hasDictionary = !!this.form.get('hasDictionary')?.value;
|
||||||
|
|
||||||
@ -180,7 +174,7 @@ export class AddEditEntityComponent extends BaseFormComponent implements OnInit
|
|||||||
hint: this.form.get('hint').value,
|
hint: this.form.get('hint').value,
|
||||||
rank: this.form.get('rank').value,
|
rank: this.form.get('rank').value,
|
||||||
dossierTemplateId: this.dossierTemplateId,
|
dossierTemplateId: this.dossierTemplateId,
|
||||||
caseInsensitive,
|
caseInsensitive: !this.form.get('caseSensitive').value,
|
||||||
addToDictionaryAction,
|
addToDictionaryAction,
|
||||||
hasDictionary,
|
hasDictionary,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -107,7 +107,7 @@ export class ConfigService {
|
|||||||
label: myDossiersLabel,
|
label: myDossiersLabel,
|
||||||
checker: this._myDossiersChecker,
|
checker: this._myDossiersChecker,
|
||||||
disabled: entities.filter(this._myDossiersChecker).length === 0,
|
disabled: entities.filter(this._myDossiersChecker).length === 0,
|
||||||
helpModeKey: 'dossiers_quickfilter_my_dossiers',
|
helpModeKey: 'filter_dossier_list',
|
||||||
},
|
},
|
||||||
].map(filter => new NestedFilter(filter));
|
].map(filter => new NestedFilter(filter));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import { HttpClientModule } from '@angular/common/http';
|
|||||||
import { KeycloakAngularModule, KeycloakOptions, KeycloakService } from 'keycloak-angular';
|
import { KeycloakAngularModule, KeycloakOptions, KeycloakService } from 'keycloak-angular';
|
||||||
import { ConfigService } from '@services/config.service';
|
import { ConfigService } from '@services/config.service';
|
||||||
import { BASE_HREF } from '../../tokens';
|
import { BASE_HREF } from '../../tokens';
|
||||||
import { firstValueFrom } from 'rxjs';
|
|
||||||
|
|
||||||
function getKeycloakOptions(configService: ConfigService, baseUrl: string) {
|
function getKeycloakOptions(configService: ConfigService, baseUrl: string) {
|
||||||
let url: string = configService.values.OAUTH_URL;
|
let url: string = configService.values.OAUTH_URL;
|
||||||
@ -37,11 +36,9 @@ function configureAutomaticRedirectToLoginScreen(keyCloakService: KeycloakServic
|
|||||||
|
|
||||||
export function keycloakInitializer(keycloakService: KeycloakService, configService: ConfigService, baseUrl: string): () => Promise<void> {
|
export function keycloakInitializer(keycloakService: KeycloakService, configService: ConfigService, baseUrl: string): () => Promise<void> {
|
||||||
return () =>
|
return () =>
|
||||||
firstValueFrom(configService.loadAppConfig()).then(() =>
|
keycloakService
|
||||||
keycloakService
|
.init(getKeycloakOptions(configService, baseUrl))
|
||||||
.init(getKeycloakOptions(configService, baseUrl))
|
.then(() => configureAutomaticRedirectToLoginScreen(keycloakService));
|
||||||
.then(() => configureAutomaticRedirectToLoginScreen(keycloakService)),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
import { Component, Input, OnInit, ViewChild } from '@angular/core';
|
||||||
import { Dossier, IDictionary } from '@red/domain';
|
import { Dictionary, Dossier, IDictionary } from '@red/domain';
|
||||||
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
|
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
|
||||||
import { PermissionsService } from '@services/permissions.service';
|
import { PermissionsService } from '@services/permissions.service';
|
||||||
import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
|
import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
|
||||||
@ -21,7 +21,7 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
|
|||||||
form: FormGroup;
|
form: FormGroup;
|
||||||
canEdit = false;
|
canEdit = false;
|
||||||
canEditDisplayName = false;
|
canEditDisplayName = false;
|
||||||
dossierDictionary: IDictionary;
|
dossierDictionary: Dictionary;
|
||||||
|
|
||||||
readonly circleButtonTypes = CircleButtonTypes;
|
readonly circleButtonTypes = CircleButtonTypes;
|
||||||
@ViewChild(DictionaryManagerComponent, { static: false }) private readonly _dictionaryManager: DictionaryManagerComponent;
|
@ViewChild(DictionaryManagerComponent, { static: false }) private readonly _dictionaryManager: DictionaryManagerComponent;
|
||||||
@ -130,8 +130,6 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
|
|||||||
|
|
||||||
private async _updateDossierDictionary() {
|
private async _updateDossierDictionary() {
|
||||||
const { dossierId, dossierTemplateId } = this.dossier;
|
const { dossierId, dossierTemplateId } = this.dossier;
|
||||||
this.dossierDictionary = await firstValueFrom(
|
this.dossierDictionary = await firstValueFrom(this._dictionaryService.getDossierDictionary(dossierTemplateId, dossierId));
|
||||||
this._dictionaryService.getForType(dossierTemplateId, 'dossier_redaction', dossierId),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -74,7 +74,10 @@ export class AnnotationProcessingService {
|
|||||||
if (!parentFilter) {
|
if (!parentFilter) {
|
||||||
parentFilter = this._createParentFilter(a.superType, filterMap, filters);
|
parentFilter = this._createParentFilter(a.superType, filterMap, filters);
|
||||||
}
|
}
|
||||||
const dictionary = this._dictionariesMapService.getDictionary(a.type, this._state.dossierTemplateId);
|
const dictionary =
|
||||||
|
a.type === 'dossier_redaction'
|
||||||
|
? this._state.dossierDictionary
|
||||||
|
: this._dictionariesMapService.getDictionary(a.type, this._state.dossierTemplateId);
|
||||||
const childFilter: IFilter = {
|
const childFilter: IFilter = {
|
||||||
id: a.filterKey,
|
id: a.filterKey,
|
||||||
label: dictionary.label,
|
label: dictionary.label,
|
||||||
|
|||||||
@ -203,7 +203,7 @@ export class ConfigService {
|
|||||||
label: myDossiersLabel,
|
label: myDossiersLabel,
|
||||||
checker: this._myDossiersChecker,
|
checker: this._myDossiersChecker,
|
||||||
disabled: entities.filter(this._myDossiersChecker).length === 0,
|
disabled: entities.filter(this._myDossiersChecker).length === 0,
|
||||||
helpModeKey: 'dossiers_quickfilter_my_dossiers',
|
helpModeKey: 'filter_dossier_list',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'to-approve',
|
id: 'to-approve',
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges } from '@angular/core';
|
||||||
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
|
||||||
import { MultiSelectService } from '../../services/multi-select.service';
|
import { MultiSelectService } from '../../services/multi-select.service';
|
||||||
|
import { FilePreviewStateService } from '../../services/file-preview-state.service';
|
||||||
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
import { DictionariesMapService } from '@services/entity-services/dictionaries-map.service';
|
||||||
import { Dictionary, DOSSIER_ID } from '@red/domain';
|
import { Dictionary, DOSSIER_ID } from '@red/domain';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { DossiersService } from '@services/dossiers/dossiers.service';
|
import { DossiersService } from '@services/dossiers/dossiers.service';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'redaction-annotation-card',
|
selector: 'redaction-annotation-card',
|
||||||
@ -17,6 +19,7 @@ export class AnnotationCardComponent implements OnChanges {
|
|||||||
@Input() annotation: AnnotationWrapper;
|
@Input() annotation: AnnotationWrapper;
|
||||||
@Input() isSelected = false;
|
@Input() isSelected = false;
|
||||||
readonly dictionary$ = new BehaviorSubject<Dictionary>(undefined);
|
readonly dictionary$ = new BehaviorSubject<Dictionary>(undefined);
|
||||||
|
readonly #dossierId: string;
|
||||||
readonly #dossierTemplateId: string;
|
readonly #dossierTemplateId: string;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -24,15 +27,20 @@ export class AnnotationCardComponent implements OnChanges {
|
|||||||
dossiersService: DossiersService,
|
dossiersService: DossiersService,
|
||||||
readonly multiSelectService: MultiSelectService,
|
readonly multiSelectService: MultiSelectService,
|
||||||
private readonly _dictionariesMapService: DictionariesMapService,
|
private readonly _dictionariesMapService: DictionariesMapService,
|
||||||
|
private readonly _dictionaryService: DictionaryService,
|
||||||
|
private readonly _state: FilePreviewStateService,
|
||||||
) {
|
) {
|
||||||
const dossierId: string = route.snapshot.paramMap.get(DOSSIER_ID);
|
this.#dossierId = route.snapshot.paramMap.get(DOSSIER_ID);
|
||||||
this.#dossierTemplateId = dossiersService.find(dossierId).dossierTemplateId;
|
this.#dossierTemplateId = dossiersService.find(this.#dossierId).dossierTemplateId;
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnChanges(changes: SimpleChanges): void {
|
ngOnChanges(changes: SimpleChanges): void {
|
||||||
if (changes.annotation) {
|
if (changes.annotation) {
|
||||||
if (this.annotation.type !== 'manual' && !this.annotation.isHighlight) {
|
if (this.annotation.type !== 'manual' && !this.annotation.isHighlight) {
|
||||||
const dictionary = this._dictionariesMapService.getDictionary(this.annotation.type, this.#dossierTemplateId);
|
const dictionary =
|
||||||
|
this.annotation.type === 'dossier_redaction'
|
||||||
|
? this._state.dossierDictionary
|
||||||
|
: this._dictionariesMapService.getDictionary(this.annotation.type, this.#dossierTemplateId);
|
||||||
this.dictionary$.next(dictionary);
|
this.dictionary$.next(dictionary);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,6 @@ import { PdfViewer } from '../../services/pdf-viewer.service';
|
|||||||
export class AnnotationsListComponent extends HasScrollbarDirective implements OnChanges {
|
export class AnnotationsListComponent extends HasScrollbarDirective implements OnChanges {
|
||||||
@Input() annotations: AnnotationWrapper[];
|
@Input() annotations: AnnotationWrapper[];
|
||||||
@Input() annotationActionsTemplate: TemplateRef<unknown>;
|
@Input() annotationActionsTemplate: TemplateRef<unknown>;
|
||||||
@Input() activeViewerPage: number;
|
|
||||||
|
|
||||||
@Output() readonly pagesPanelActive = new EventEmitter<boolean>();
|
@Output() readonly pagesPanelActive = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
|||||||
@ -48,7 +48,7 @@
|
|||||||
<div *ngIf="multiSelectService.active$ | async" class="multi-select">
|
<div *ngIf="multiSelectService.active$ | async" class="multi-select">
|
||||||
<div class="selected-wrapper">
|
<div class="selected-wrapper">
|
||||||
<iqser-round-checkbox
|
<iqser-round-checkbox
|
||||||
(click)="pdf.selectAnnotations()"
|
(click)="pdf.deselectAllAnnotations()"
|
||||||
[indeterminate]="listingService.areSomeSelected$ | async"
|
[indeterminate]="listingService.areSomeSelected$ | async"
|
||||||
type="with-bg"
|
type="with-bg"
|
||||||
></iqser-round-checkbox>
|
></iqser-round-checkbox>
|
||||||
@ -213,7 +213,6 @@
|
|||||||
|
|
||||||
<redaction-annotations-list
|
<redaction-annotations-list
|
||||||
(pagesPanelActive)="pagesPanelActive = $event"
|
(pagesPanelActive)="pagesPanelActive = $event"
|
||||||
[activeViewerPage]="activeViewerPage"
|
|
||||||
[annotationActionsTemplate]="annotationActionsTemplate"
|
[annotationActionsTemplate]="annotationActionsTemplate"
|
||||||
[annotations]="(displayedAnnotations$ | async)?.get(activeViewerPage)"
|
[annotations]="(displayedAnnotations$ | async)?.get(activeViewerPage)"
|
||||||
></redaction-annotations-list>
|
></redaction-annotations-list>
|
||||||
|
|||||||
@ -134,7 +134,7 @@ export class FileWorkloadComponent {
|
|||||||
return this.multiSelectService.inactive$.pipe(
|
return this.multiSelectService.inactive$.pipe(
|
||||||
tap(value => {
|
tap(value => {
|
||||||
if (value) {
|
if (value) {
|
||||||
this.pdf.selectAnnotations();
|
this.pdf.deselectAllAnnotations();
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
shareDistinctLast(),
|
shareDistinctLast(),
|
||||||
|
|||||||
@ -31,7 +31,7 @@ import { download, handleFilterDelta } from '../../utils';
|
|||||||
import { FileWorkloadComponent } from './components/file-workload/file-workload.component';
|
import { FileWorkloadComponent } from './components/file-workload/file-workload.component';
|
||||||
import { FilesService } from '@services/entity-services/files.service';
|
import { FilesService } from '@services/entity-services/files.service';
|
||||||
import { FileManagementService } from '@services/entity-services/file-management.service';
|
import { FileManagementService } from '@services/entity-services/file-management.service';
|
||||||
import { catchError, debounceTime, map, startWith, switchMap, tap } from 'rxjs/operators';
|
import { catchError, map, startWith, switchMap, tap } from 'rxjs/operators';
|
||||||
import { FilesMapService } from '@services/entity-services/files-map.service';
|
import { FilesMapService } from '@services/entity-services/files-map.service';
|
||||||
import { ExcludedPagesService } from './services/excluded-pages.service';
|
import { ExcludedPagesService } from './services/excluded-pages.service';
|
||||||
import { ViewModeService } from './services/view-mode.service';
|
import { ViewModeService } from './services/view-mode.service';
|
||||||
@ -362,7 +362,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
|
|||||||
);
|
);
|
||||||
let start;
|
let start;
|
||||||
return combineLatest([currentPageAnnotations$, documentLoaded$]).pipe(
|
return combineLatest([currentPageAnnotations$, documentLoaded$]).pipe(
|
||||||
debounceTime(300),
|
|
||||||
tap(() => (start = new Date().getTime())),
|
tap(() => (start = new Date().getTime())),
|
||||||
map(([annotations]) => annotations),
|
map(([annotations]) => annotations),
|
||||||
startWith([] as AnnotationWrapper[]),
|
startWith([] as AnnotationWrapper[]),
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Injectable, Injector } from '@angular/core';
|
import { Injectable, Injector } from '@angular/core';
|
||||||
import { combineLatest, firstValueFrom, from, merge, Observable, of, pairwise, Subject, switchMap } from 'rxjs';
|
import { combineLatest, firstValueFrom, from, merge, Observable, of, pairwise, Subject, switchMap } from 'rxjs';
|
||||||
import { Dossier, DOSSIER_ID, File, FILE_ID } from '@red/domain';
|
import { Dictionary, Dossier, DOSSIER_ID, File, FILE_ID } from '@red/domain';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { FilesMapService } from '@services/entity-services/files-map.service';
|
import { FilesMapService } from '@services/entity-services/files-map.service';
|
||||||
import { PermissionsService } from '@services/permissions.service';
|
import { PermissionsService } from '@services/permissions.service';
|
||||||
@ -11,6 +11,7 @@ import { dossiersServiceResolver } from '@services/entity-services/dossiers.serv
|
|||||||
import { wipeFilesCache } from '@red/cache';
|
import { wipeFilesCache } from '@red/cache';
|
||||||
import { DossiersService } from '@services/dossiers/dossiers.service';
|
import { DossiersService } from '@services/dossiers/dossiers.service';
|
||||||
import { FilesService } from '@services/entity-services/files.service';
|
import { FilesService } from '@services/entity-services/files.service';
|
||||||
|
import { DictionaryService } from '@services/entity-services/dictionary.service';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FilePreviewStateService {
|
export class FilePreviewStateService {
|
||||||
@ -24,10 +25,9 @@ export class FilePreviewStateService {
|
|||||||
readonly dossierId: string;
|
readonly dossierId: string;
|
||||||
readonly dossierTemplateId: string;
|
readonly dossierTemplateId: string;
|
||||||
readonly fileId: string;
|
readonly fileId: string;
|
||||||
|
|
||||||
dossier: Dossier;
|
dossier: Dossier;
|
||||||
file: File;
|
file: File;
|
||||||
|
#dossierDictionary: Dictionary;
|
||||||
readonly #reloadBlob$ = new Subject();
|
readonly #reloadBlob$ = new Subject();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -39,6 +39,7 @@ export class FilePreviewStateService {
|
|||||||
private readonly _filesService: FilesService,
|
private readonly _filesService: FilesService,
|
||||||
private readonly _dossiersService: DossiersService,
|
private readonly _dossiersService: DossiersService,
|
||||||
private readonly _fileManagementService: FileManagementService,
|
private readonly _fileManagementService: FileManagementService,
|
||||||
|
private readonly _dictionaryService: DictionaryService,
|
||||||
) {
|
) {
|
||||||
const dossiersService = dossiersServiceResolver(_injector, router);
|
const dossiersService = dossiersServiceResolver(_injector, router);
|
||||||
|
|
||||||
@ -55,6 +56,14 @@ export class FilePreviewStateService {
|
|||||||
|
|
||||||
this.blob$ = this.#blob$;
|
this.blob$ = this.#blob$;
|
||||||
this.dossierFileChange$ = this.#dossierFilesChange$();
|
this.dossierFileChange$ = this.#dossierFilesChange$();
|
||||||
|
|
||||||
|
this._dictionaryService
|
||||||
|
.getDossierDictionary(this.dossierTemplateId, this.dossierId)
|
||||||
|
.subscribe(dictionary => (this.#dossierDictionary = dictionary));
|
||||||
|
}
|
||||||
|
|
||||||
|
get dossierDictionary(): Dictionary {
|
||||||
|
return this.#dossierDictionary;
|
||||||
}
|
}
|
||||||
|
|
||||||
get blob(): Promise<Blob> {
|
get blob(): Promise<Blob> {
|
||||||
|
|||||||
@ -13,12 +13,13 @@ export class MultiSelectService {
|
|||||||
readonly enabled$: Observable<boolean>;
|
readonly enabled$: Observable<boolean>;
|
||||||
readonly active$: Observable<boolean>;
|
readonly active$: Observable<boolean>;
|
||||||
readonly inactive$: Observable<boolean>;
|
readonly inactive$: Observable<boolean>;
|
||||||
|
|
||||||
readonly #active$ = new BehaviorSubject(false);
|
readonly #active$ = new BehaviorSubject(false);
|
||||||
readonly #enabled$ = new BehaviorSubject(true);
|
readonly #enabled$ = new BehaviorSubject(true);
|
||||||
|
|
||||||
constructor(private readonly _viewModeService: ViewModeService, private readonly _state: FilePreviewStateService) {
|
constructor(viewModeService: ViewModeService, state: FilePreviewStateService) {
|
||||||
[this.active$, this.inactive$] = boolFactory(this.#active$.asObservable());
|
[this.active$, this.inactive$] = boolFactory(this.#active$.asObservable());
|
||||||
this.enabled$ = combineLatest([this._viewModeService.viewMode$, _state.isWritable$]).pipe(
|
this.enabled$ = combineLatest([viewModeService.viewMode$, state.isWritable$]).pipe(
|
||||||
map(([viewMode, isWritable]) => isWritable && ENABLED_MULTISELECT.includes(viewMode)),
|
map(([viewMode, isWritable]) => isWritable && ENABLED_MULTISELECT.includes(viewMode)),
|
||||||
tap(enabled => this.#enabled$.next(enabled)),
|
tap(enabled => this.#enabled$.next(enabled)),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -227,7 +227,7 @@ export class PdfViewer {
|
|||||||
|
|
||||||
this.navigateToPage(pageNumber);
|
this.navigateToPage(pageNumber);
|
||||||
// wait for page to be loaded and to draw annotations
|
// wait for page to be loaded and to draw annotations
|
||||||
setTimeout(() => this.#jumpAndSelectAnnotations(filteredAnnotationsIds), 500);
|
setTimeout(() => this.#jumpAndSelectAnnotations(filteredAnnotationsIds), 300);
|
||||||
}
|
}
|
||||||
|
|
||||||
#jumpAndSelectAnnotations(annotationIds: readonly string[]) {
|
#jumpAndSelectAnnotations(annotationIds: readonly string[]) {
|
||||||
|
|||||||
@ -2,10 +2,11 @@ import { Injectable } from '@angular/core';
|
|||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Title } from '@angular/platform-browser';
|
import { Title } from '@angular/platform-browser';
|
||||||
import packageInfo from '../../../../../package.json';
|
import packageInfo from '../../../../../package.json';
|
||||||
import config from '../../assets/config/config.json';
|
import envConfig from '../../assets/config/config.json';
|
||||||
import { CacheApiService, wipeCaches } from '@red/cache';
|
import { CacheApiService, wipeCaches } from '@red/cache';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { tap } from 'rxjs/operators';
|
import { tap } from 'rxjs/operators';
|
||||||
|
import { AppConfig } from '@red/domain';
|
||||||
|
|
||||||
const version = packageInfo.version;
|
const version = packageInfo.version;
|
||||||
|
|
||||||
@ -19,19 +20,21 @@ export class ConfigService {
|
|||||||
private readonly _titleService: Title,
|
private readonly _titleService: Title,
|
||||||
) {
|
) {
|
||||||
this._checkFrontendVersion();
|
this._checkFrontendVersion();
|
||||||
|
|
||||||
|
console.log('[REDACTION] Started with config: ', this._values);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _values = { ...config, FRONTEND_APP_VERSION: version } as const;
|
private _values: AppConfig = { ...envConfig, FRONTEND_APP_VERSION: version } as const;
|
||||||
|
|
||||||
get values() {
|
get values() {
|
||||||
return this._values;
|
return this._values;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadAppConfig(): Observable<any> {
|
loadAppConfig(): Observable<any> {
|
||||||
return this._httpClient.get<any>('/assets/config/config.json').pipe(
|
return this._httpClient.get('/app-config').pipe(
|
||||||
tap(envConfig => {
|
tap(appConfig => {
|
||||||
console.log('[REDACTION] Started with config: ', envConfig);
|
console.log('[REDACTION] Loaded app config: ', appConfig);
|
||||||
this._values = envConfig;
|
this._values = { ...this._values, ...appConfig };
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { Injectable, Injector } from '@angular/core';
|
import { Injectable, Injector } from '@angular/core';
|
||||||
import { firstValueFrom, forkJoin, Observable, of, throwError } from 'rxjs';
|
import { firstValueFrom, forkJoin, Observable, of, throwError } from 'rxjs';
|
||||||
import { EntitiesService, List, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
|
import { EntitiesService, List, log, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
|
||||||
import { Dictionary, DictionaryEntryType, DictionaryEntryTypes, IColors, IDictionary, IUpdateDictionary } from '@red/domain';
|
import { Dictionary, DictionaryEntryType, DictionaryEntryTypes, IColors, IDictionary, IUpdateDictionary } from '@red/domain';
|
||||||
import { catchError, map, switchMap, tap } from 'rxjs/operators';
|
import { catchError, map, switchMap, tap } from 'rxjs/operators';
|
||||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||||
@ -174,7 +174,7 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
|||||||
async getDictionariesOptions(dossierTemplateId: string, dossierId: string): Promise<Dictionary[]> {
|
async getDictionariesOptions(dossierTemplateId: string, dossierId: string): Promise<Dictionary[]> {
|
||||||
const possibleDictionaries: Dictionary[] = [];
|
const possibleDictionaries: Dictionary[] = [];
|
||||||
|
|
||||||
const dossierDictionary = await firstValueFrom(this.getForType(dossierTemplateId, 'dossier_redaction', dossierId));
|
const dossierDictionary: Dictionary = await firstValueFrom(this.getDossierDictionary(dossierTemplateId, dossierId));
|
||||||
|
|
||||||
for (const dictionary of this._dictionariesMapService.get(dossierTemplateId)) {
|
for (const dictionary of this._dictionariesMapService.get(dossierTemplateId)) {
|
||||||
if (!dictionary.virtual && dictionary.addToDictionaryAction) {
|
if (!dictionary.virtual && dictionary.addToDictionaryAction) {
|
||||||
@ -183,8 +183,7 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dossierDictionary.addToDictionaryAction) {
|
if (dossierDictionary.addToDictionaryAction) {
|
||||||
// TODO fix this in the backend
|
possibleDictionaries.push(dossierDictionary);
|
||||||
possibleDictionaries.push(new Dictionary({ ...dossierDictionary, type: 'dossier_redaction' }));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
possibleDictionaries.sort((a, b) => a.label.localeCompare(b.label));
|
possibleDictionaries.sort((a, b) => a.label.localeCompare(b.label));
|
||||||
@ -192,6 +191,18 @@ export class DictionaryService extends EntitiesService<Dictionary, IDictionary>
|
|||||||
return possibleDictionaries;
|
return possibleDictionaries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getDossierDictionary(dossierTemplateId: string, dossierId: string): Observable<Dictionary> {
|
||||||
|
return this.getForType(dossierTemplateId, 'dossier_redaction', dossierId).pipe(
|
||||||
|
map(
|
||||||
|
dictionary =>
|
||||||
|
new Dictionary({
|
||||||
|
...dictionary,
|
||||||
|
type: 'dossier_redaction',
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
loadDictionaryData(dossierTemplatesIds: string[]): Observable<Dictionary[][]> {
|
loadDictionaryData(dossierTemplatesIds: string[]): Observable<Dictionary[][]> {
|
||||||
const observables: Observable<Dictionary[]>[] = [];
|
const observables: Observable<Dictionary[]>[] = [];
|
||||||
for (const dossierTemplateId of dossierTemplatesIds) {
|
for (const dossierTemplateId of dossierTemplatesIds) {
|
||||||
|
|||||||
@ -64,7 +64,7 @@ export class TrashService extends EntitiesService<TrashItem> {
|
|||||||
dossier =>
|
dossier =>
|
||||||
new TrashDossier(
|
new TrashDossier(
|
||||||
dossier,
|
dossier,
|
||||||
this._configService.values.DELETE_RETENTION_HOURS as number,
|
this._configService.values.softDeleteCleanupTime,
|
||||||
this._permissionsService.canRestoreDossier(dossier),
|
this._permissionsService.canRestoreDossier(dossier),
|
||||||
this._permissionsService.canHardDeleteDossier(dossier),
|
this._permissionsService.canHardDeleteDossier(dossier),
|
||||||
),
|
),
|
||||||
@ -82,7 +82,7 @@ export class TrashService extends EntitiesService<TrashItem> {
|
|||||||
return new TrashFile(
|
return new TrashFile(
|
||||||
file,
|
file,
|
||||||
dossier.dossierTemplateId,
|
dossier.dossierTemplateId,
|
||||||
this._configService.values.DELETE_RETENTION_HOURS as number,
|
this._configService.values.softDeleteCleanupTime,
|
||||||
this._permissionsService.canRestoreFile(file, dossier),
|
this._permissionsService.canRestoreFile(file, dossier),
|
||||||
this._permissionsService.canHardDeleteFile(file, dossier),
|
this._permissionsService.canHardDeleteFile(file, dossier),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -39,6 +39,7 @@ export function configurationInitializer(
|
|||||||
switchMap(user => (!user.hasAnyREDRoles ? throwError('Not user has no red roles') : of({}))),
|
switchMap(user => (!user.hasAnyREDRoles ? throwError('Not user has no red roles') : of({}))),
|
||||||
mergeMap(() => generalSettingsService.getGeneralConfigurations()),
|
mergeMap(() => generalSettingsService.getGeneralConfigurations()),
|
||||||
tap(configuration => configService.updateDisplayName(configuration.displayName)),
|
tap(configuration => configService.updateDisplayName(configuration.displayName)),
|
||||||
|
switchMap(() => configService.loadAppConfig()),
|
||||||
switchMap(() => userPreferenceService.reload()),
|
switchMap(() => userPreferenceService.reload()),
|
||||||
catchError(e => {
|
catchError(e => {
|
||||||
console.log('[Redaction] Initialization error:', e);
|
console.log('[Redaction] Initialization error:', e);
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
"APP_NAME": "RedactManager",
|
"APP_NAME": "RedactManager",
|
||||||
"AUTO_READ_TIME": 3,
|
"AUTO_READ_TIME": 3,
|
||||||
"BACKEND_APP_VERSION": "4.4.40",
|
"BACKEND_APP_VERSION": "4.4.40",
|
||||||
"DELETE_RETENTION_HOURS": 96,
|
|
||||||
"EULA_URL": "EULA_URL",
|
"EULA_URL": "EULA_URL",
|
||||||
"FRONTEND_APP_VERSION": "1.1",
|
"FRONTEND_APP_VERSION": "1.1",
|
||||||
"LICENSE_CUSTOMER": "Development License",
|
"LICENSE_CUSTOMER": "Development License",
|
||||||
|
|||||||
@ -83,12 +83,6 @@
|
|||||||
"it": "",
|
"it": "",
|
||||||
"fr": ""
|
"fr": ""
|
||||||
},
|
},
|
||||||
"dossiers_quickfilter_my_dossiers": {
|
|
||||||
"en": "/en/index-en.html?contextId=dossiers_quickfilter_my_dossiers",
|
|
||||||
"de": "",
|
|
||||||
"it": "",
|
|
||||||
"fr": ""
|
|
||||||
},
|
|
||||||
"edit_dossier_in_dossier": {
|
"edit_dossier_in_dossier": {
|
||||||
"en": "/en/index-en.html?contextId=edit_dossier_in_dossier",
|
"en": "/en/index-en.html?contextId=edit_dossier_in_dossier",
|
||||||
"de": "",
|
"de": "",
|
||||||
|
|||||||
@ -6,7 +6,6 @@ API_URL="${API_URL:-/redaction-gateway-v1}"
|
|||||||
APP_NAME="${APP_NAME:-}"
|
APP_NAME="${APP_NAME:-}"
|
||||||
AUTO_READ_TIME="${AUTO_READ_TIME:-1.5}"
|
AUTO_READ_TIME="${AUTO_READ_TIME:-1.5}"
|
||||||
BACKEND_APP_VERSION="${BACKEND_APP_VERSION:-4.7.0}"
|
BACKEND_APP_VERSION="${BACKEND_APP_VERSION:-4.7.0}"
|
||||||
DELETE_RETENTION_HOURS="${DELETE_RETENTION_HOURS:-96}"
|
|
||||||
EULA_URL="${EULA_URL:-}"
|
EULA_URL="${EULA_URL:-}"
|
||||||
FRONTEND_APP_VERSION="${FRONTEND_APP_VERSION:-}"
|
FRONTEND_APP_VERSION="${FRONTEND_APP_VERSION:-}"
|
||||||
|
|
||||||
@ -34,7 +33,6 @@ echo '{
|
|||||||
"APP_NAME":"'"$APP_NAME"'",
|
"APP_NAME":"'"$APP_NAME"'",
|
||||||
"AUTO_READ_TIME":'"$AUTO_READ_TIME"',
|
"AUTO_READ_TIME":'"$AUTO_READ_TIME"',
|
||||||
"BACKEND_APP_VERSION":"'"$BACKEND_APP_VERSION"'",
|
"BACKEND_APP_VERSION":"'"$BACKEND_APP_VERSION"'",
|
||||||
"DELETE_RETENTION_HOURS":'"$DELETE_RETENTION_HOURS"',
|
|
||||||
"EULA_URL":"'"$EULA_URL:"'",
|
"EULA_URL":"'"$EULA_URL:"'",
|
||||||
"FRONTEND_APP_VERSION":"'"$FRONTEND_APP_VERSION:"'",
|
"FRONTEND_APP_VERSION":"'"$FRONTEND_APP_VERSION:"'",
|
||||||
"LICENSE_EMAIL":"'"$LICENSE_EMAIL"'",
|
"LICENSE_EMAIL":"'"$LICENSE_EMAIL"'",
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
Subproject commit f90405572f662bb150950032f726305a616de0dc
|
Subproject commit e7be61efff0b9baa3d6b53002cbecd8b53d7b934
|
||||||
26
libs/red-domain/src/lib/shared/app-config.ts
Normal file
26
libs/red-domain/src/lib/shared/app-config.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
export interface AppConfig {
|
||||||
|
ADMIN_CONTACT_NAME: string;
|
||||||
|
ADMIN_CONTACT_URL: string;
|
||||||
|
API_URL: string;
|
||||||
|
APP_NAME: string;
|
||||||
|
AUTO_READ_TIME: number;
|
||||||
|
BACKEND_APP_VERSION: string;
|
||||||
|
EULA_URL: string;
|
||||||
|
FRONTEND_APP_VERSION: string;
|
||||||
|
LICENSE_CUSTOMER: string;
|
||||||
|
LICENSE_EMAIL: string;
|
||||||
|
LICENSE_END: string;
|
||||||
|
LICENSE_PAGE_COUNT: number;
|
||||||
|
LICENSE_START: string;
|
||||||
|
MAX_FILE_SIZE_MB: number;
|
||||||
|
MAX_RETRIES_ON_SERVER_ERROR: number;
|
||||||
|
OAUTH_CLIENT_ID: string;
|
||||||
|
OAUTH_IDP_HINT: null;
|
||||||
|
OAUTH_URL: string;
|
||||||
|
RECENT_PERIOD_IN_HOURS: number;
|
||||||
|
SELECTION_MODE: string;
|
||||||
|
MANUAL_BASE_URL: string;
|
||||||
|
softDeleteCleanupTime?: number;
|
||||||
|
downloadCleanupDownloadFilesHours?: number;
|
||||||
|
downloadCleanupNotDownloadFilesHours?: number;
|
||||||
|
}
|
||||||
@ -11,3 +11,4 @@ export * from './pdf.types';
|
|||||||
export * from './logger-config';
|
export * from './logger-config';
|
||||||
export * from './admin-side-nav-types';
|
export * from './admin-side-nav-types';
|
||||||
export * from './charts';
|
export * from './charts';
|
||||||
|
export * from './app-config';
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "redaction",
|
"name": "redaction",
|
||||||
"version": "3.479.0",
|
"version": "3.486.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -31,6 +31,10 @@
|
|||||||
|
|
||||||
.publication-contents {
|
.publication-contents {
|
||||||
@include mixin.card;
|
@include mixin.card;
|
||||||
|
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
|
||||||
width: 250px;
|
width: 250px;
|
||||||
margin: 0 15px !important;
|
margin: 0 15px !important;
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user