move active dossier to dossiers service

This commit is contained in:
Dan Percic 2021-10-01 17:13:57 +03:00
parent 08d23a3118
commit e32ee45d9c
25 changed files with 285 additions and 337 deletions

View File

@ -4,30 +4,7 @@
<div class="top-bar-row">
<div *ngIf="!currentUser.isUser" class="menu-placeholder"></div>
<div *ngIf="currentUser.isUser" class="menu visible-lt-lg">
<button [matMenuTriggerFor]="menuNav" mat-flat-button>
<mat-icon svgIcon="red:menu"></mat-icon>
</button>
<mat-menu #menuNav="matMenu">
<button mat-menu-item routerLink="/main/dossiers" translate="top-bar.navigation-items.dossiers"></button>
<button
*ngIf="appStateService.activeDossier"
[routerLink]="'/main/dossiers/' + appStateService.activeDossierId"
mat-menu-item
>
{{ appStateService.activeDossier.dossierName }}
</button>
<button
*ngIf="appStateService.activeFile"
[routerLink]="'/main/dossiers/' + appStateService.activeDossierId + '/file/' + appStateService.activeFile.fileId"
mat-menu-item
>
{{ appStateService.activeFile.filename }}
</button>
</mat-menu>
</div>
<div *ngIf="currentUser.isUser" class="menu flex-2 visible-lg breadcrumbs-container">
<div *ngIf="currentUser.isUser" class="menu flex-2 breadcrumbs-container">
<a *ngIf="(isDossiersView$ | async) === false" class="breadcrumb back" redactionNavigateLastDossiersScreen>
<mat-icon svgIcon="red:expand"></mat-icon>
{{ 'top-bar.navigation-items.back' | translate }}
@ -42,28 +19,26 @@
translate="top-bar.navigation-items.dossiers"
></a>
<mat-icon *ngIf="appStateService.activeDossier" svgIcon="red:arrow-right"></mat-icon>
<ng-container *ngIf="dossiersService.activeDossier$ | async as activeDossier">
<mat-icon svgIcon="red:arrow-right"></mat-icon>
<a
*ngIf="appStateService.activeDossier"
[routerLinkActiveOptions]="{ exact: true }"
[routerLink]="'/main/dossiers/' + appStateService.activeDossierId"
class="breadcrumb"
routerLinkActive="active"
>
{{ appStateService.activeDossier.dossierName }}
</a>
<a
[routerLinkActiveOptions]="{ exact: true }"
[routerLink]="activeDossier.routerLink"
class="breadcrumb"
routerLinkActive="active"
>
{{ activeDossier.dossierName }}
</a>
</ng-container>
<mat-icon *ngIf="appStateService.activeFile" svgIcon="red:arrow-right"></mat-icon>
<ng-container *ngIf="appStateService.activeFile as activeFile">
<mat-icon svgIcon="red:arrow-right"></mat-icon>
<a
*ngIf="appStateService.activeFile"
[routerLink]="'/main/dossiers/' + appStateService.activeDossierId + '/file/' + appStateService.activeFile.fileId"
class="breadcrumb"
routerLinkActive="active"
>
{{ appStateService.activeFile.filename }}
</a>
<a [routerLink]="activeFile.routerLink" class="breadcrumb" routerLinkActive="active">
{{ activeFile.filename }}
</a>
</ng-container>
</ng-container>
</div>
@ -78,8 +53,8 @@
<div class="buttons">
<redaction-spotlight-search
*ngIf="(isSearchScreen$ | async) === false"
[placeholder]="'search.placeholder' | translate"
[actions]="searchActions"
[placeholder]="'search.placeholder' | translate"
iqserHelpMode="search"
></redaction-spotlight-search>

View File

@ -9,6 +9,7 @@ import { TranslateService } from '@ngx-translate/core';
import { SpotlightSearchAction } from '@components/spotlight-search/spotlight-search-action';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { distinctUntilChanged, filter, map, startWith } from 'rxjs/operators';
import { DossiersService } from '../../modules/dossier/services/dossiers.service';
interface MenuItem {
readonly name: string;
@ -26,15 +27,7 @@ const isSearchScreen = url => url.includes('/main/dossiers') && url.includes('/s
styleUrls: ['./base-screen.component.scss']
})
export class BaseScreenComponent {
private readonly _navigationStart$ = this._router.events.pipe(
filter(isNavigationStart),
map((event: NavigationStart) => event.url),
startWith(this._router.url),
distinctUntilChanged()
);
readonly currentUser = this.userService.currentUser;
readonly isDossiersView$ = this._navigationStart$.pipe(map(isDossiersView));
readonly isSearchScreen$ = this._navigationStart$.pipe(map(isSearchScreen));
readonly userMenuItems: readonly MenuItem[] = [
{
name: _('top-bar.navigation-items.my-account.children.my-profile'),
@ -62,8 +55,8 @@ export class BaseScreenComponent {
{
text: this._translateService.instant('search.this-dossier'),
icon: 'red:enter',
hide: (): boolean => !this.appStateService.activeDossier,
action: (query): void => this._search(query, this.appStateService.activeDossier.id)
hide: (): boolean => !this.dossiersService.activeDossier,
action: (query): void => this._search(query, this.dossiersService.activeDossierId)
},
{
text: this._translateService.instant('search.entire-platform'),
@ -71,9 +64,18 @@ export class BaseScreenComponent {
action: (query): void => this._search(query)
}
];
private readonly _navigationStart$ = this._router.events.pipe(
filter(isNavigationStart),
map((event: NavigationStart) => event.url),
startWith(this._router.url),
distinctUntilChanged()
);
readonly isDossiersView$ = this._navigationStart$.pipe(map(isDossiersView));
readonly isSearchScreen$ = this._navigationStart$.pipe(map(isSearchScreen));
constructor(
readonly appStateService: AppStateService,
readonly dossiersService: DossiersService,
readonly userService: UserService,
readonly userPreferenceService: UserPreferenceService,
readonly titleService: Title,
@ -82,12 +84,12 @@ export class BaseScreenComponent {
private readonly _translateService: TranslateService
) {}
trackByName(index: number, item: MenuItem) {
return item.name;
}
private _search(query: string, dossierId?: string) {
const queryParams = { query, dossierId };
this._router.navigate(['main/dossiers/search'], { queryParams }).then();
}
trackByName(index: number, item: MenuItem) {
return item.name;
}
}

View File

@ -4,6 +4,7 @@ import { AppStateService } from '@state/app-state.service';
import { PermissionsService } from '@services/permissions.service';
import { ConfigService } from '@services/config.service';
import { Subscription } from 'rxjs';
import { DossiersService } from '../../services/dossiers.service';
@Component({
selector: 'redaction-page-indicator',
@ -25,6 +26,7 @@ export class PageIndicatorComponent implements OnChanges, OnInit, OnDestroy {
constructor(
private readonly _viewedPagesControllerService: ViewedPagesControllerService,
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _configService: ConfigService,
private readonly _permissionService: PermissionsService
) {}
@ -95,7 +97,7 @@ export class PageIndicatorComponent implements OnChanges, OnInit, OnDestroy {
private _markPageRead() {
this._viewedPagesControllerService
.addPage({ page: this.number }, this._appStateService.activeDossierId, this._appStateService.activeFileId)
.addPage({ page: this.number }, this._dossiersService.activeDossierId, this._appStateService.activeFileId)
.subscribe(() => {
this.viewedPages?.pages?.push({ page: this.number, fileId: this._appStateService.activeFileId });
});
@ -103,7 +105,7 @@ export class PageIndicatorComponent implements OnChanges, OnInit, OnDestroy {
private _markPageUnread() {
this._viewedPagesControllerService
.removePage(this._appStateService.activeDossierId, this._appStateService.activeFileId, this.number)
.removePage(this._dossiersService.activeDossierId, this._appStateService.activeFileId, this.number)
.subscribe(() => {
this.viewedPages?.pages?.splice(
this.viewedPages?.pages?.findIndex(p => p.page === this.number),

View File

@ -8,6 +8,7 @@ import { File } from '@models/file/file';
import { Dossier } from '@state/model/dossier';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { FilesService } from '../../services/files.service';
import { DossiersService } from '../../services/dossiers.service';
class DialogData {
mode: 'approver' | 'reviewer';
@ -29,6 +30,7 @@ export class AssignReviewerApproverDialogComponent {
private readonly _toaster: Toaster,
private readonly _formBuilder: FormBuilder,
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _filesService: FilesService,
private readonly _dialogRef: MatDialogRef<AssignReviewerApproverDialogComponent>,
@Inject(MAT_DIALOG_DATA) readonly data: DialogData
@ -42,8 +44,8 @@ export class AssignReviewerApproverDialogComponent {
get singleUsersSelectOptions() {
return this.data.mode === 'approver'
? this._appStateService.activeDossier.approverIds
: this._appStateService.activeDossier.memberIds;
? this._dossiersService.activeDossier.approverIds
: this._dossiersService.activeDossier.memberIds;
}
get changed(): boolean {
@ -72,7 +74,7 @@ export class AssignReviewerApproverDialogComponent {
await this._filesService
.setReviewerFor(
this.data.files.map(f => f.fileId),
this._appStateService.activeDossierId,
this._dossiersService.activeDossierId,
selectedUser
)
.toPromise();
@ -81,7 +83,7 @@ export class AssignReviewerApproverDialogComponent {
.setUnderApprovalFor(
this.data.files.map(f => f.fileId),
selectedUser,
this._appStateService.activeDossierId
this._dossiersService.activeDossierId
)
.toPromise();
}

View File

@ -6,6 +6,7 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { LegalBasisMappingControllerService } from '@redaction/red-ui-http';
import { AppStateService } from '@state/app-state.service';
import { PermissionsService } from '@services/permissions.service';
import { DossiersService } from '../../services/dossiers.service';
export interface LegalBasisOption {
label?: string;
@ -27,6 +28,7 @@ export class ChangeLegalBasisDialogComponent implements OnInit {
private readonly _translateService: TranslateService,
private readonly _legalBasisMappingControllerService: LegalBasisMappingControllerService,
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _permissionsService: PermissionsService,
private readonly _formBuilder: FormBuilder,
public dialogRef: MatDialogRef<ChangeLegalBasisDialogComponent>,
@ -45,7 +47,7 @@ export class ChangeLegalBasisDialogComponent implements OnInit {
comment: this.isDocumentAdmin ? [null] : [null, Validators.required]
});
const data = await this._legalBasisMappingControllerService
.getLegalBasisMapping(this._appStateService.activeDossier.dossierTemplateId)
.getLegalBasisMapping(this._dossiersService.activeDossier.dossierTemplateId)
.toPromise();
this.legalOptions = data

View File

@ -1,5 +1,4 @@
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { AppStateService } from '@state/app-state.service';
import { Dossier } from '@state/model/dossier';
import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { PermissionsService } from '@services/permissions.service';
@ -8,6 +7,7 @@ import { DictionaryService } from '@shared/services/dictionary.service';
import { FormBuilder } from '@angular/forms';
import { CircleButtonTypes, LoadingService } from '@iqser/common-ui';
import { IDictionary } from '@redaction/red-ui-http';
import { DossiersService } from '../../../services/dossiers.service';
@Component({
selector: 'redaction-edit-dossier-dictionary',
@ -20,10 +20,10 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
canEdit = false;
readonly circleButtonTypes = CircleButtonTypes;
@ViewChild(DictionaryManagerComponent, { static: false }) private _dictionaryManager: DictionaryManagerComponent;
@ViewChild(DictionaryManagerComponent, { static: false }) private readonly _dictionaryManager: DictionaryManagerComponent;
constructor(
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _dictionaryService: DictionaryService,
private readonly _permissionsService: PermissionsService,
private readonly _loadingService: LoadingService,
@ -42,7 +42,7 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
async ngOnInit() {
this._loadingService.start();
await this._appStateService.updateDossierDictionary(this.dossier.dossierTemplateId, this.dossier.id);
await this._dossiersService.updateDossierDictionary(this.dossier.dossierTemplateId, this.dossier.id);
this._loadingService.stop();
}
@ -51,7 +51,7 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
await this._dictionaryService
.updateType(typeValue, this.dossier.dossierTemplateId, 'dossier_redaction', this.dossier.id)
.toPromise();
await this._appStateService.updateDossierDictionary(this.dossier.dossierTemplateId, this.dossier.id);
await this._dossiersService.updateDossierDictionary(this.dossier.dossierTemplateId, this.dossier.id);
this.updateDossier.emit();
}
@ -66,7 +66,7 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
false
)
.toPromise();
await this._appStateService.updateDossierDictionary(this.dossier.dossierTemplateId, this.dossier.id);
await this._dossiersService.updateDossierDictionary(this.dossier.dossierTemplateId, this.dossier.id);
this.updateDossier.emit();
}

View File

@ -1,6 +1,5 @@
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { AppStateService } from '@state/app-state.service';
import { MatDialogRef } from '@angular/material/dialog';
import { ForceRedactionRequest, LegalBasisMappingControllerService } from '@redaction/red-ui-http';
import { Toaster } from '@iqser/common-ui';
@ -8,6 +7,7 @@ import { TranslateService } from '@ngx-translate/core';
import { UserService } from '@services/user.service';
import { ManualAnnotationService } from '../../services/manual-annotation.service';
import { PermissionsService } from '@services/permissions.service';
import { DossiersService } from '../../services/dossiers.service';
export interface LegalBasisOption {
label?: string;
@ -26,7 +26,7 @@ export class ForceRedactionDialogComponent implements OnInit {
legalOptions: LegalBasisOption[] = [];
constructor(
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _userService: UserService,
private readonly _formBuilder: FormBuilder,
private readonly _notificationService: Toaster,
@ -39,7 +39,7 @@ export class ForceRedactionDialogComponent implements OnInit {
async ngOnInit() {
this._legalBasisMappingControllerService
.getLegalBasisMapping(this._appStateService.activeDossier.dossierTemplateId)
.getLegalBasisMapping(this._dossiersService.activeDossier.dossierTemplateId)
.subscribe(data => {
data.map(lbm => {
this.legalOptions.push({

View File

@ -11,6 +11,7 @@ import { ManualAnnotationService } from '../../services/manual-annotation.servic
import { ManualAnnotationResponse } from '@models/file/manual-annotation-response';
import { PermissionsService } from '@services/permissions.service';
import { TypeValue } from '@models/file/type-value';
import { DossiersService } from '../../services/dossiers.service';
export interface LegalBasisOption {
label?: string;
@ -35,6 +36,7 @@ export class ManualAnnotationDialogComponent implements OnInit {
constructor(
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _userService: UserService,
private readonly _formBuilder: FormBuilder,
private readonly _notificationService: Toaster,
@ -60,7 +62,7 @@ export class ManualAnnotationDialogComponent implements OnInit {
async ngOnInit() {
this._legalBasisMappingControllerService
.getLegalBasisMapping(this._appStateService.activeDossier.dossierTemplateId)
.getLegalBasisMapping(this._dossiersService.activeDossier.dossierTemplateId)
.subscribe(data => {
data.map(lbm => {
this.legalOptions.push({
@ -86,7 +88,7 @@ export class ManualAnnotationDialogComponent implements OnInit {
comment: this.isDocumentAdmin ? [null] : [null, Validators.required]
});
for (const key of Object.keys(this._appStateService.dictionaryData[this._appStateService.activeDossier.dossierTemplateId])) {
for (const key of Object.keys(this._appStateService.dictionaryData[this._dossiersService.activeDossier.dossierTemplateId])) {
const dictionaryData = this._appStateService.getDictionaryTypeValue(key);
if (!dictionaryData.virtual && dictionaryData.addToDictionaryAction) {
this.redactionDictionaries.push(dictionaryData);
@ -103,6 +105,14 @@ export class ManualAnnotationDialogComponent implements OnInit {
);
}
format(value: string) {
return value.replace(
// eslint-disable-next-line no-control-regex,max-len
/([^\s\d-]{2,})[-\u00AD]\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]/gi,
'$1'
);
}
private _enhanceManualRedaction(addRedactionRequest: AddRedactionRequest) {
const legalOption: LegalBasisOption = this.redactionForm.get('reason').value;
addRedactionRequest.type = this.redactionForm.get('dictionary').value;
@ -118,12 +128,4 @@ export class ManualAnnotationDialogComponent implements OnInit {
const commentValue = this.redactionForm.get('comment').value;
addRedactionRequest.comment = commentValue ? { text: commentValue } : null;
}
format(value: string) {
return value.replace(
// eslint-disable-next-line no-control-regex,max-len
/([^\s\d-]{2,})[-\u00AD]\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]/gi,
'$1'
);
}
}

View File

@ -1,66 +1,68 @@
<div>
<mat-icon svgIcon="red:document"></mat-icon>
<span>{{ 'dossier-overview.dossier-details.stats.documents' | translate: { count: activeDossier.files.length } }}</span>
</div>
<div>
<mat-icon svgIcon="red:user"></mat-icon>
<span>{{ 'dossier-overview.dossier-details.stats.people' | translate: { count: activeDossier.memberIds.length } }}</span>
</div>
<div>
<mat-icon svgIcon="red:pages"></mat-icon>
<span>{{
'dossier-overview.dossier-details.stats.analysed-pages' | translate: { count: activeDossier.totalNumberOfPages | number }
}}</span>
</div>
<div>
<mat-icon svgIcon="red:calendar"></mat-icon>
<span
>{{
'dossier-overview.dossier-details.stats.created-on'
<ng-container *ngIf="dossiersService.activeDossier as dossier">
<div>
<mat-icon svgIcon="red:document"></mat-icon>
<span>{{ 'dossier-overview.dossier-details.stats.documents' | translate: { count: dossier.files.length } }}</span>
</div>
<div>
<mat-icon svgIcon="red:user"></mat-icon>
<span>{{ 'dossier-overview.dossier-details.stats.people' | translate: { count: dossier.memberIds.length } }}</span>
</div>
<div>
<mat-icon svgIcon="red:pages"></mat-icon>
<span>{{
'dossier-overview.dossier-details.stats.analysed-pages' | translate: { count: dossier.totalNumberOfPages | number }
}}</span>
</div>
<div>
<mat-icon svgIcon="red:calendar"></mat-icon>
<span
>{{
'dossier-overview.dossier-details.stats.created-on'
| translate
: {
date: dossier.date | date: 'd MMM. yyyy'
}
}}
</span>
</div>
<div *ngIf="dossier.dueDate">
<mat-icon svgIcon="red:lightning"></mat-icon>
<span>{{
'dossier-overview.dossier-details.stats.due-date'
| translate
: {
date: activeDossier.date | date: 'd MMM. yyyy'
date: dossier.dueDate | date: 'd MMM. yyyy'
}
}}
</span>
</div>
<div *ngIf="activeDossier.dueDate">
<mat-icon svgIcon="red:lightning"></mat-icon>
<span>{{
'dossier-overview.dossier-details.stats.due-date'
| translate
: {
date: activeDossier.dueDate | date: 'd MMM. yyyy'
}
}}</span>
</div>
<div>
<mat-icon svgIcon="red:template"></mat-icon>
<span>{{ dossierTemplate?.name }} </span>
</div>
<div (click)="openDossierDictionaryDialog.emit()" *ngIf="activeDossier.type" class="link-property">
<mat-icon svgIcon="red:dictionary"></mat-icon>
<span>{{ 'dossier-overview.dossier-details.dictionary' | translate }} </span>
</div>
<ng-container *ngIf="dossierAttributes?.length">
<div (click)="attributesExpanded = true" *ngIf="!attributesExpanded" class="all-caps-label show-attributes">
{{ 'dossier-overview.dossier-details.attributes.expand' | translate: { count: dossierAttributes.length } }}
}}</span>
</div>
<div>
<mat-icon svgIcon="red:template"></mat-icon>
<span>{{ dossierTemplate?.name }} </span>
</div>
<div (click)="openDossierDictionaryDialog.emit()" *ngIf="dossier.type" class="link-property">
<mat-icon svgIcon="red:dictionary"></mat-icon>
<span>{{ 'dossier-overview.dossier-details.dictionary' | translate }} </span>
</div>
<ng-container *ngIf="attributesExpanded">
<div (click)="openEditDossierAttributesDialog()" *ngFor="let attr of dossierAttributes" class="link-property">
<mat-icon svgIcon="red:attribute"></mat-icon>
<span *ngIf="!attr.value"> {{ attr.label + ': -' }}</span>
<span *ngIf="attr.value && attr.type === 'DATE'"> {{ attr.label + ': ' + (attr.value | date: 'd MMM. yyyy') }}</span>
<span *ngIf="attr.value && attr.type === 'IMAGE'">
{{ attr.label + ': ' + ('dossier-overview.dossier-details.attributes.image-uploaded' | translate) }}</span
>
<span *ngIf="attr.value && (attr.type === 'TEXT' || attr.type === 'NUMBER')"> {{ attr.label + ': ' + attr.value }}</span>
<ng-container *ngIf="dossierAttributes?.length">
<div (click)="attributesExpanded = true" *ngIf="!attributesExpanded" class="all-caps-label show-attributes">
{{ 'dossier-overview.dossier-details.attributes.expand' | translate: { count: dossierAttributes.length } }}
</div>
<div (click)="attributesExpanded = false" class="all-caps-label hide-attributes">
{{ 'dossier-overview.dossier-details.attributes.show-less' | translate }}
</div>
<ng-container *ngIf="attributesExpanded">
<div (click)="openEditDossierAttributesDialog(dossier)" *ngFor="let attr of dossierAttributes" class="link-property">
<mat-icon svgIcon="red:attribute"></mat-icon>
<span *ngIf="!attr.value"> {{ attr.label + ': -' }}</span>
<span *ngIf="attr.value && attr.type === 'DATE'"> {{ attr.label + ': ' + (attr.value | date: 'd MMM. yyyy') }}</span>
<span *ngIf="attr.value && attr.type === 'IMAGE'">
{{ attr.label + ': ' + ('dossier-overview.dossier-details.attributes.image-uploaded' | translate) }}</span
>
<span *ngIf="attr.value && (attr.type === 'TEXT' || attr.type === 'NUMBER')"> {{ attr.label + ': ' + attr.value }}</span>
</div>
<div (click)="attributesExpanded = false" class="all-caps-label hide-attributes">
{{ 'dossier-overview.dossier-details.attributes.show-less' | translate }}
</div>
</ng-container>
</ng-container>
</ng-container>

View File

@ -1,11 +1,11 @@
<ng-container *ngIf="appStateService.activeDossier">
<ng-container *ngIf="dossiersService.activeDossier$ | async as dossier">
<div class="collapsed-wrapper">
<ng-container *ngTemplateOutlet="collapsible; context: { action: 'expand', tooltip: (expandTooltip | translate) }"></ng-container>
<div class="all-caps-label" translate="dossier-details.title"></div>
</div>
<div class="header-wrapper mt-8">
<div class="heading-xl flex-1">{{ appStateService.activeDossier.dossierName }}</div>
<div class="heading-xl flex-1">{{ dossier.dossierName }}</div>
<ng-container
*ngTemplateOutlet="collapsible; context: { action: 'collapse', tooltip: (collapseTooltip | translate) }"
></ng-container>
@ -33,12 +33,12 @@
<div class="all-caps-label" translate="dossier-details.members"></div>
<redaction-team-members
(openAssignDossierMembersDialog)="openAssignDossierMembersDialog.emit()"
[memberIds]="memberIds"
[memberIds]="dossier.memberIds"
[perLine]="9"
></redaction-team-members>
</div>
<div *ngIf="hasFiles" class="mt-24">
<div *ngIf="dossier.hasFiles" class="mt-24">
<redaction-simple-doughnut-chart
[config]="documentsChartData"
[radius]="63"
@ -48,7 +48,7 @@
></redaction-simple-doughnut-chart>
</div>
<div *ngIf="hasFiles" class="mt-24 legend pb-32">
<div *ngIf="dossier.hasFiles" class="mt-24 legend pb-32">
<div
(click)="filterService.toggleFilter('needsWorkFilters', filter.id)"
*ngFor="let filter of needsWorkFilters$ | async"
@ -58,14 +58,14 @@
</div>
</div>
<div [class.mt-24]="!hasFiles" class="pb-32">
<div [class.mt-24]="!dossier.hasFiles" class="pb-32">
<redaction-dossier-details-stats
(openDossierDictionaryDialog)="openDossierDictionaryDialog.emit()"
[dossierAttributes]="dossierAttributes"
></redaction-dossier-details-stats>
</div>
<div *ngIf="appStateService.activeDossier.description as description" class="pb-32">
<div *ngIf="dossier.description as description" class="pb-32">
<div class="heading" translate="dossier-overview.dossier-details.description"></div>
<div class="mt-8">{{ description }}</div>
</div>

View File

@ -8,8 +8,9 @@ import { FilterService, Toaster } from '@iqser/common-ui';
import { DossierAttributeWithValue } from '@models/dossier-attributes.model';
import { fileStatusTranslations } from '../../../../translations/file-status-translations';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { List } from '@redaction/red-ui-http';
import { DossierRequest } from '@redaction/red-ui-http';
import { User } from '@models/user';
import { DossiersService } from '../../services/dossiers.service';
@Component({
selector: 'redaction-dossier-details',
@ -32,6 +33,7 @@ export class DossierDetailsComponent implements OnInit {
constructor(
readonly appStateService: AppStateService,
readonly dossiersService: DossiersService,
readonly translateChartService: TranslateChartService,
readonly filterService: FilterService,
private readonly _changeDetectorRef: ChangeDetectorRef,
@ -39,20 +41,12 @@ export class DossierDetailsComponent implements OnInit {
private readonly _toaster: Toaster
) {}
get memberIds(): List {
return this.appStateService.activeDossier.memberIds;
}
get hasFiles(): boolean {
return this.appStateService.activeDossier.hasFiles;
}
get managers() {
return this._userService.managerUsers;
}
ngOnInit(): void {
this.owner = this._userService.getRedUserById(this.appStateService.activeDossier.ownerId);
this.owner = this._userService.getRedUserById(this.dossiersService.activeDossier.ownerId);
this.calculateChartConfig();
this.appStateService.fileChanged$.subscribe(() => {
this.calculateChartConfig();
@ -60,11 +54,12 @@ export class DossierDetailsComponent implements OnInit {
}
calculateChartConfig(): void {
if (!this.appStateService.activeDossier) {
const activeDossier = this.dossiersService.activeDossier;
if (!activeDossier) {
return;
}
const groups = groupBy(this.appStateService.activeDossier?.files, 'status');
const groups = groupBy(activeDossier?.files, 'status');
this.documentsChartData = [];
for (const status of Object.keys(groups)) {
this.documentsChartData.push({
@ -81,11 +76,12 @@ export class DossierDetailsComponent implements OnInit {
async assignOwner(user: User | string) {
this.owner = typeof user === 'string' ? this._userService.getRedUserById(user) : user;
const dw = { ...this.appStateService.activeDossier, id: this.appStateService.activeDossierId, ownerId: this.owner.id };
await this.appStateService.createOrUpdateDossier(dw);
const activeDossier = this.dossiersService.activeDossier;
const dossierRequest: DossierRequest = { ...activeDossier, dossierId: activeDossier.dossierId, ownerId: this.owner.id };
await this.appStateService.createOrUpdateDossier(dossierRequest);
const ownerName = this._userService.getNameForId(this.owner.id);
const dossierName = this.appStateService.activeDossier.dossierName;
const dossierName = activeDossier.dossierName;
this._toaster.info(_('assignment.owner'), { params: { ownerName, dossierName } });
}
}

View File

@ -14,7 +14,7 @@
<iqser-circle-button
(action)="reanalyseDossier()"
*ngIf="permissionsService.displayReanalyseBtn()"
*ngIf="permissionsService.displayReanalyseBtn(currentDossier)"
[tooltipClass]="'small ' + ((entitiesService.areSomeSelected$ | async) ? '' : 'warn')"
[tooltip]="'dossier-overview.new-rule.toast.actions.reanalyse-all' | translate"
[type]="circleButtonTypes.warn"
@ -88,7 +88,10 @@
<input #fileInput (change)="uploadFiles($event.target['files'])" class="file-upload-input" multiple="true" type="file" />
<ng-template #bulkActions>
<redaction-dossier-overview-bulk-actions (reload)="bulkActionPerformed()"></redaction-dossier-overview-bulk-actions>
<redaction-dossier-overview-bulk-actions
(reload)="bulkActionPerformed()"
[dossier]="currentDossier"
></redaction-dossier-overview-bulk-actions>
</ng-template>
<ng-template #viewModeSelection>

View File

@ -29,7 +29,7 @@
</div>
</div>
<div class="flex-1 actions-container">
<div *ngIf="dossiersService.activeDossier$ | async as dossier" class="flex-1 actions-container">
<ng-container *ngIf="!appStateService.activeFile.excluded">
<ng-container *ngIf="!appStateService.activeFile.isProcessing">
<iqser-status-bar [configs]="statusBarConfig" [small]="true"></iqser-status-bar>
@ -48,7 +48,7 @@
></redaction-initials-avatar>
<div
(click)="editingReviewer = true"
*ngIf="!editingReviewer && canAssignReviewer"
*ngIf="!editingReviewer && canAssignReviewer(dossier)"
class="assign-reviewer pointer"
translate="file-preview.assign-reviewer"
></div>
@ -58,7 +58,7 @@
(cancel)="editingReviewer = false"
(save)="assignReviewer($event)"
*ngIf="editingReviewer"
[options]="singleUsersSelectOptions"
[options]="singleUsersSelectOptions(dossier)"
[value]="currentReviewer"
></redaction-assign-user-dropdown>
@ -118,7 +118,7 @@
<iqser-circle-button
(action)="closeFullScreen()"
*ngIf="!fullScreen"
[routerLink]="['/main/dossiers/' + appStateService.activeDossierId]"
[routerLink]="dossier.routerLink"
[tooltip]="'common.close' | translate"
class="ml-8"
icon="iqser:close"

View File

@ -41,6 +41,8 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { FileActionsComponent } from '../../shared/components/file-actions/file-actions.component';
import { User } from '@models/user';
import { FilesService } from '../../services/files.service';
import { DossiersService } from '../../services/dossiers.service';
import { Dossier } from '@state/model/dossier';
import Annotation = Core.Annotations.Annotation;
const ALL_HOTKEY_ARRAY = ['Escape', 'F', 'f'];
@ -81,6 +83,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
constructor(
readonly appStateService: AppStateService,
readonly dossiersService: DossiersService,
readonly permissionsService: PermissionsService,
readonly userPreferenceService: UserPreferenceService,
readonly userService: UserService,
@ -110,12 +113,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
});
}
get singleUsersSelectOptions(): List {
return this.appStateService.activeFile?.isUnderApproval
? this.appStateService.activeDossier.approverIds
: this.appStateService.activeDossier.memberIds;
}
get assignTooltip(): string {
return this.appStateService.activeFile.isUnderApproval
? this._translateService.instant('dossier-overview.assign-approver')
@ -158,10 +155,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
return this.fileData?.fileData;
}
get dossierId(): string {
return this.appStateService.activeDossierId;
}
get fileId(): string {
return this.appStateService.activeFileId;
}
@ -196,8 +189,12 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
return this.status === 'UNDER_REVIEW' || this.status === 'UNDER_APPROVAL';
}
get canAssignReviewer(): boolean {
return !this.currentReviewer && this.permissionsService.canAssignUser() && this.appStateService.activeDossier.hasReviewers;
singleUsersSelectOptions(dossier: Dossier): List {
return this.appStateService.activeFile?.isUnderApproval ? dossier.approverIds : dossier.memberIds;
}
canAssignReviewer(dossier: Dossier): boolean {
return !this.currentReviewer && this.permissionsService.canAssignUser() && dossier.hasReviewers;
}
updateViewMode(): void {
@ -242,8 +239,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
async ngOnAttach(previousRoute: ActivatedRouteSnapshot): Promise<void> {
if (!this.appStateService.activeFile.canBeOpened) {
await this._router.navigate(['/main/dossiers/' + this.dossierId]);
return;
return await this.dossiersService.goToActiveDossier();
}
await this.ngOnInit();
@ -277,7 +273,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
console.log('[REDACTION] Delete previous annotations time: ' + (new Date().getTime() - startTime) + 'ms');
const processStartTime = new Date().getTime();
const newAnnotationsData = this.fileData.getAnnotations(
this.appStateService.dictionaryData[this.appStateService.activeDossier.dossierTemplateId],
this.appStateService.dictionaryData[this.dossiersService.activeDossier.dossierTemplateId],
this.userService.currentUser,
this.viewMode,
this.userPreferenceService.areDevFeaturesEnabled
@ -289,7 +285,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
this.annotationData = newAnnotationsData;
const annotationFilters = this._annotationProcessingService.getAnnotationFilter(this.annotations);
const primaryFilters = this._filterService.getGroup('primaryFilters')?.filters;
console.log(annotationFilters);
this._filterService.addFilterGroup({
slug: 'primaryFilters',
filterTemplate: this._filterTemplate,
@ -301,8 +296,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
filterTemplate: this._filterTemplate,
filters: processFilters(secondaryFilters, AnnotationProcessingService.secondaryAnnotationFilters)
});
console.log(this.annotations);
console.log(this.appStateService.activeFile);
console.log('[REDACTION] Process time: ' + (new Date().getTime() - processStartTime) + 'ms');
console.log(
'[REDACTION] Annotation Redraw and filter rebuild time: ' +
@ -450,8 +443,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
switch (action) {
case 'delete':
await this._router.navigate([`/main/dossiers/${this.dossierId}`]);
return;
return await this.dossiersService.goToActiveDossier();
case 'enable-analysis':
case 'reanalyse':
@ -521,7 +513,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
downloadOriginalFile() {
this.addSubscription = this._fileManagementControllerService
.downloadOriginalFile(this.dossierId, this.fileId, true, this.fileData.file.cacheIdentifier, 'response')
.downloadOriginalFile(this.fileData.file.dossierId, this.fileId, true, this.fileData.file.cacheIdentifier, 'response')
.subscribe(data => {
download(data, this.fileData.file.filename);
});
@ -537,15 +529,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
return false;
}
// <!-- Dev Mode Features-->
async openSSRFilePreview() {
window.open(`/pdf-preview/${this.dossierId}/${this.fileId}`, '_blank');
}
async openHTMLDebug() {
window.open(`/html-debug/${this.dossierId}/${this.fileId}`, '_blank');
}
private _setHiddenPropertyToNewAnnotations(newAnnotations: AnnotationWrapper[], oldAnnotations: AnnotationWrapper[]) {
newAnnotations.map((newAnnotation: AnnotationWrapper) => {
const oldAnnotation = oldAnnotations.find((a: AnnotationWrapper) => a.annotationId === newAnnotation.annotationId);
@ -618,7 +601,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
if (fileData.file.isError) {
await this._router.navigate(['/main/dossiers/' + this.dossierId]);
await this.dossiersService.goToActiveDossier();
}
}

View File

@ -5,12 +5,14 @@ import { hexToRgb } from '@utils/functions';
import { AppStateService } from '@state/app-state.service';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { UserPreferenceService } from '@services/user-preference.service';
import { DossiersService } from './dossiers.service';
import Annotation = Core.Annotations.Annotation;
@Injectable()
export class AnnotationDrawService {
constructor(
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _redactionLogControllerService: RedactionLogControllerService,
private readonly _userPreferenceService: UserPreferenceService
) {}
@ -28,7 +30,7 @@ export class AnnotationDrawService {
if (this._userPreferenceService.areDevFeaturesEnabled) {
this._redactionLogControllerService
.getSectionGrid(this._appStateService.activeDossierId, this._appStateService.activeFileId)
.getSectionGrid(this._dossiersService.activeDossierId, this._appStateService.activeFileId)
.subscribe(sectionGrid => {
this.drawSections(activeViewer, sectionGrid);
});

View File

@ -8,6 +8,7 @@ import { BehaviorSubject, Observable } from 'rxjs';
import { ActivationEnd, Router } from '@angular/router';
import { BaseScreenComponent } from '@components/base-screen/base-screen.component';
import { File } from '@models/file/file';
import { DictionaryService } from '@shared/services/dictionary.service';
export interface IDossiersStats {
totalPeople: number;
@ -21,38 +22,59 @@ const getRelatedEvents = filter(event => event instanceof ActivationEnd && event
})
export class DossiersService extends EntitiesService<Dossier, IDossier> {
readonly stats$ = this.all$.pipe(map(entities => this._computeStats(entities)));
readonly activeDossierId$: Observable<string | undefined>;
readonly activeDossier$: Observable<Dossier | undefined>;
private readonly _activeDossierId$ = new BehaviorSubject<string | undefined>(undefined);
private readonly _activeDossier$ = new BehaviorSubject<Dossier | undefined>(undefined);
constructor(protected readonly _injector: Injector, private readonly _router: Router) {
constructor(
protected readonly _injector: Injector,
private readonly _router: Router,
private readonly _dictionaryService: DictionaryService
) {
super(TEMPORARY_INJECTOR(_injector), 'dossier');
this.activeDossierId$ = this._activeDossierId$.asObservable();
this.activeDossier$ = this.activeDossierId$.pipe(map(id => this.all.find(dossier => dossier.id === id)));
this.activeDossier$ = this._activeDossier$.asObservable();
_router.events.pipe(getRelatedEvents).subscribe((event: ActivationEnd) => {
const dossierId = event.snapshot.paramMap.get('dossierId');
const sameIdAsCurrentActive = dossierId === this._activeDossierId$.getValue();
const sameIdAsCurrentActive = dossierId === this._activeDossier$.getValue()?.dossierId;
if (sameIdAsCurrentActive) {
return;
}
if (dossierId === null || dossierId === undefined) {
return this._activeDossierId$.next(undefined);
return this._activeDossier$.next(undefined);
}
// const notFound = !this.all.some(dossier => dossier.id === dossierId);
// if (notFound) {
// return this._router.navigate(['/main/dossiers']).then();
// }
if (!this.has(dossierId)) {
this._activeDossier$.next(undefined);
return this._router.navigate(['/main/dossiers']).then();
}
this._activeDossierId$.next(dossierId);
this._activeDossier$.next(this.find(dossierId));
this.updateDossierDictionary(this.activeDossier.dossierTemplateId, dossierId).then();
});
}
get allFiles(): File[] {
return this.all.reduce((acc: File[], { files }) => [...acc, ...files], []);
}
get activeDossier(): Dossier | undefined {
return this._activeDossier$.value;
}
get activeDossierId(): string | undefined {
return this._activeDossier$.value?.dossierId;
}
goToActiveDossier(): Promise<void> {
return this._router.navigate([this.activeDossier?.routerLink]).then();
}
find(dossierId: string): Dossier | undefined;
find(dossierId: string, fileId: string): File | undefined;
find(dossierId: string, fileId?: string): Dossier | File | undefined {
const getDossier = () => this.all.find(dossier => dossier.dossierId === dossierId);
if (!fileId) {
@ -62,6 +84,26 @@ export class DossiersService extends EntitiesService<Dossier, IDossier> {
return getDossier().files.find(file => file.fileId === fileId);
}
replace(newDossier: Dossier) {
const dossiers = this.all.filter(dossier => dossier.dossierId !== newDossier.dossierId);
dossiers.push(newDossier);
this.setEntities(dossiers);
}
has(dossierId: string): boolean {
return this.all.some(dossier => dossier.dossierId === dossierId);
}
async updateDossierDictionary(dossierTemplateId: string, dossierId: string) {
// dossier exists, load its dictionary
const dossier = this.find(dossierId);
try {
dossier.type = await this._dictionaryService.getFor(dossierTemplateId, 'dossier_redaction', dossierId).toPromise();
} catch (e) {
dossier.type = null;
}
}
get(): Observable<IDossier[]>;
get(dossierId: string): Observable<IDossier>;
get(dossierId?: string): Observable<IDossier | IDossier[]> {

View File

@ -10,6 +10,7 @@ import { PermissionsService } from '@services/permissions.service';
import { AnnotationActionMode } from '../models/annotation-action-mode.model';
import { annotationActionsTranslations } from '../translations/annotation-actions-translations';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { DossiersService } from './dossiers.service';
@Injectable()
export class ManualAnnotationService {
@ -19,6 +20,7 @@ export class ManualAnnotationService {
constructor(
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _userService: UserService,
private readonly _translateService: TranslateService,
private readonly _toaster: Toaster,
@ -46,13 +48,13 @@ export class ManualAnnotationService {
const obs = !secondParam
? this._manualRedactionControllerService[this.CONFIG[mode]](
body,
this._appStateService.activeDossierId,
this._dossiersService.activeDossierId,
this._appStateService.activeFileId
)
: this._manualRedactionControllerService[this.CONFIG[mode]](
body,
secondParam,
this._appStateService.activeDossierId,
this._dossiersService.activeDossierId,
this._appStateService.activeFileId
);
@ -74,7 +76,7 @@ export class ManualAnnotationService {
return this._manualRedactionControllerService.addComment(
{ text: comment },
annotationId,
this._appStateService.activeDossierId,
this._dossiersService.activeDossierId,
this._appStateService.activeFileId
);
}
@ -84,7 +86,7 @@ export class ManualAnnotationService {
return this._manualRedactionControllerService.undoComment(
annotationId,
commentId,
this._appStateService.activeDossierId,
this._dossiersService.activeDossierId,
this._appStateService.activeFileId
);
}

View File

@ -11,11 +11,13 @@ import { FileDataModel } from '@models/file/file-data.model';
import { AppStateService } from '@state/app-state.service';
import { PermissionsService } from '@services/permissions.service';
import { File } from '@models/file/file';
import { DossiersService } from './dossiers.service';
@Injectable()
export class PdfViewerDataService {
constructor(
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _permissionsService: PermissionsService,
private readonly _man: ManualRedactionControllerService,
private readonly _fileManagementControllerService: FileManagementControllerService,
@ -25,7 +27,7 @@ export class PdfViewerDataService {
loadActiveFileRedactionLog() {
return this._redactionLogControllerService
.getRedactionLog(this._appStateService.activeDossierId, this._appStateService.activeFileId)
.getRedactionLog(this._dossiersService.activeDossierId, this._appStateService.activeFileId)
.pipe(
tap(
redactionLog => redactionLog.redactionLogEntry.sort((a, b) => a.positions[0].page - b.positions[0].page),
@ -47,7 +49,7 @@ export class PdfViewerDataService {
getViewedPagesForActiveFile() {
if (this._permissionsService.canMarkPagesAsViewed()) {
return this._viewedPagesControllerService
.getViewedPages(this._appStateService.activeDossierId, this._appStateService.activeFileId)
.getViewedPages(this._dossiersService.activeDossierId, this._appStateService.activeFileId)
.pipe(catchError(() => of({ pages: [] })));
}
return of({ pages: [] });

View File

@ -47,7 +47,7 @@
<!-- download redacted file-->
<redaction-file-download-btn
[dossier]="appStateService.activeDossier"
[dossier]="dossiersService.activeDossier$ | async"
[files]="[file]"
[tooltipClass]="'small'"
[tooltipPosition]="tooltipPosition"

View File

@ -4,7 +4,7 @@ import { FileUploadModel } from '../model/file-upload.model';
import { OverlayRef } from '@angular/cdk/overlay';
import { StatusOverlayService } from '../services/status-overlay.service';
import { handleFileDrop } from '@utils/file-drop-utils';
import { AppStateService } from '@state/app-state.service';
import { DossiersService } from '../../dossier/services/dossiers.service';
@Component({
selector: 'redaction-file-drop',
@ -15,7 +15,7 @@ export class FileDropComponent {
constructor(
private readonly _dialogRef: OverlayRef,
private readonly _fileUploadService: FileUploadService,
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _changeDetectorRef: ChangeDetectorRef,
private readonly _statusOverlayService: StatusOverlayService
) {}
@ -33,7 +33,7 @@ export class FileDropComponent {
@HostListener('drop', ['$event'])
onDrop(event: DragEvent) {
handleFileDrop(event, this._appStateService.activeDossier, this.uploadFiles.bind(this));
handleFileDrop(event, this._dossiersService.activeDossier, this.uploadFiles.bind(this));
}
@HostListener('dragover', ['$event'])

View File

@ -10,6 +10,7 @@ import { toNumber } from '@utils/functions';
import { UploadControllerService } from '@redaction/red-ui-http';
import { isCsv } from '@utils/file-drop-utils';
import { ErrorMessageService } from '@iqser/common-ui';
import { DossiersService } from '../../dossier/services/dossiers.service';
export interface ActiveUpload {
subscription: Subscription;
@ -28,6 +29,7 @@ export class FileUploadService {
constructor(
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _applicationRef: ApplicationRef,
private readonly _translateService: TranslateService,
private readonly _configService: ConfigService,
@ -57,7 +59,7 @@ export class FileUploadService {
async uploadFiles(files: FileUploadModel[]): Promise<number> {
const maxSizeMB = this._configService.values.MAX_FILE_SIZE_MB;
const maxSizeBytes = toNumber(maxSizeMB) * 1024 * 1024;
const dossierFiles = this._appStateService.activeDossier.files;
const dossierFiles = this._dossiersService.activeDossier.files;
let option: 'overwrite' | 'skip';
for (let idx = 0; idx < files.length; ++idx) {
const file = files[idx];

View File

@ -21,14 +21,14 @@ export class PermissionsService {
}
private get _activeDossier(): Dossier | undefined {
return this._appStateService.activeDossier;
return this._dossiersService.activeDossier;
}
isReviewerOrApprover(file?: File): boolean {
return this.isFileReviewer(file) || this.isApprover();
}
displayReanalyseBtn(dossier = this._activeDossier): boolean {
displayReanalyseBtn(dossier: Dossier): boolean {
return this.isApprover(dossier) && dossier.files.filter(file => file.analysisRequired).length > 0;
}
@ -51,7 +51,7 @@ export class PermissionsService {
canAssignToSelf(file = this._activeFile): boolean {
const precondition = this.isDossierMember() && !file.isProcessing && !file.isError && !file.isApproved;
const isTheOnlyReviewer = !this._appStateService.activeDossier?.hasReviewers;
const isTheOnlyReviewer = !this._activeDossier?.hasReviewers;
if (precondition) {
if (
@ -90,7 +90,7 @@ export class PermissionsService {
return file?.isUnderReview && this.isReviewerOrApprover(file);
}
isOwner(dossier = this._activeDossier, user = this._userService.currentUser): boolean {
isOwner(dossier: Dossier, user = this._userService.currentUser): boolean {
return dossier?.ownerId === user.id;
}

View File

@ -1,11 +1,11 @@
import { Injectable } from '@angular/core';
import { Colors, DossierRequest, IFile, ReanalysisControllerService } from '@redaction/red-ui-http';
import { List, Toaster } from '@iqser/common-ui';
import { Toaster } from '@iqser/common-ui';
import { TranslateService } from '@ngx-translate/core';
import { Event, NavigationEnd, ResolveStart, Router } from '@angular/router';
import { UserService } from '@services/user.service';
import { forkJoin, Observable, of, Subject } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import { catchError, filter, first, map, tap } from 'rxjs/operators';
import { FALLBACK_COLOR, hexToRgb } from '@utils/functions';
import { File } from '@models/file/file';
import { Dossier } from './model/dossier';
@ -20,9 +20,7 @@ import { DossierTemplatesService } from '../modules/dossier/services/dossier-tem
import { FileAttributesService } from '../modules/dossier/services/file-attributes.service';
export interface AppState {
dossiers: Dossier[];
dossierTemplates: DossierTemplate[];
activeDossierId?: string;
activeFileId?: string;
activeDossierTemplateId?: string;
activeDictionaryType?: string;
@ -53,22 +51,23 @@ export class AppStateService {
private readonly _userPreferenceService: UserPreferenceService
) {
this._appState = {
dossiers: [],
dossierTemplates: []
};
_router.events.subscribe((event: Event) => {
_router.events.subscribe(async (event: Event) => {
if (AppStateService._isFileOverviewRoute(event)) {
const url = (event as ResolveStart).url.replace('/main/dossiers/', '');
const [dossierId, , fileId] = url.split(/[/?]/);
return this.activateFile(dossierId, fileId);
}
if (AppStateService._isDossierOverviewRoute(event)) {
const dossierId = (event as ResolveStart).url.replace('/main/dossiers/', '');
return this.activateDossier(dossierId);
await _dossiersService.activeDossier$
.pipe(
filter(dossier => !!dossier),
first()
)
.toPromise();
return await this.activateFile(dossierId, fileId);
}
if (AppStateService._isRandomRoute(event)) {
this._appState.activeDossierId = undefined;
this._appState.activeFileId = undefined;
}
});
}
@ -79,10 +78,6 @@ export class AppStateService {
return this._dictionaryData;
}
get aggregatedFiles(): File[] {
return this._dossiersService.all.reduce((acc, { files }) => [...acc, ...files], []);
}
get activeDossierTemplateId(): string | undefined {
return this._appState.activeDossierTemplateId;
}
@ -108,16 +103,8 @@ export class AppStateService {
: undefined;
}
get activeDossierId(): string | undefined {
return this._appState.activeDossierId;
}
get activeDossier(): Dossier | undefined {
return this._dossiersService.all.find(p => p.id === this.activeDossierId);
}
get activeFile(): File | undefined {
return this.activeDossier?.files.find(f => f.fileId === this.activeFileId);
return this._dossiersService.activeDossier?.files.find(f => f.fileId === this.activeFileId);
}
get activeFileId(): string | undefined {
@ -128,26 +115,17 @@ export class AppStateService {
return event instanceof ResolveStart && event.url.includes('/main/dossiers/') && event.url.includes('/file/');
}
private static _isDossierOverviewRoute(event: Event) {
return (
event instanceof ResolveStart &&
event.url.includes('/main/dossiers/') &&
!event.url.includes('/file/') &&
!event.url.includes('/search')
);
}
private static _isRandomRoute(event: Event) {
return event instanceof NavigationEnd && !event.url.includes('/main/dossiers/') && !event.url.includes('/file/');
}
async reloadActiveDossierFilesIfNecessary() {
if (this.activeDossier?.hasPendingOrProcessing) {
if (this._dossiersService.activeDossier?.hasPendingOrProcessing) {
await this.reloadActiveDossierFiles();
}
}
getDictionaryColor(type?: string, dossierTemplateId = this.activeDossier?.dossierTemplateId) {
getDictionaryColor(type?: string, dossierTemplateId = this._dossiersService.activeDossier?.dossierTemplateId) {
if (!dossierTemplateId) {
dossierTemplateId = this.dossierTemplates[0]?.dossierTemplateId;
}
@ -170,11 +148,7 @@ export class AppStateService {
return this.dossierTemplates.find(rs => rs.dossierTemplateId === id);
}
getDictionaryTypeValue(key: string, dossierTemplateId?: string): TypeValue | undefined {
if (!dossierTemplateId && this.activeDossier) {
dossierTemplateId = this.activeDossier.dossierTemplateId;
}
getDictionaryTypeValue(key: string, dossierTemplateId = this._dossiersService.activeDossier.dossierTemplateId): TypeValue | undefined {
if (!dossierTemplateId) {
dossierTemplateId = this.dossierTemplates.length > 0 ? this.dossierTemplates[0].dossierTemplateId : undefined;
}
@ -192,7 +166,8 @@ export class AppStateService {
return;
}
const mappedDossiers = dossiers.map(p => new Dossier(p, this._getExistingFiles(p.dossierId)));
const getFiles = (dossierId: string) => this._dossiersService.find(dossierId)?.files ?? [];
const mappedDossiers = dossiers.map(p => new Dossier(p, getFiles(p.dossierId)));
const fileData = await this._filesService.getFor(mappedDossiers.map(p => p.id)).toPromise();
for (const dossierId of Object.keys(fileData)) {
@ -204,21 +179,23 @@ export class AppStateService {
}
async reloadActiveFile() {
if (!this.activeFile) {
const activeDossier = this._dossiersService.activeDossier;
if (!this.activeFile || !activeDossier) {
return null;
}
const oldProcessedDate = this.activeFile.lastProcessed;
const iFile = await this._filesService.get(this.activeDossierId, this.activeFileId).toPromise();
const iFile = await this._filesService.get(activeDossier.dossierId, this.activeFileId).toPromise();
const activeFile = new File(
iFile,
this._userService.getNameForId(iFile.currentReviewer),
this._fileAttributesService.getFileAttributeConfig(this.activeDossier?.dossierTemplateId)
this._fileAttributesService.getFileAttributeConfig(activeDossier.dossierTemplateId)
);
const files = this.activeDossier?.files.map(file => (file.fileId === activeFile.fileId ? activeFile : file));
const newDossier = new Dossier(this.activeDossier, files);
this._appState.dossiers = [...this._appState.dossiers.filter(d => d.dossierId !== newDossier.dossierId), newDossier];
this._dossiersService.setEntities(this._appState.dossiers);
const files = activeDossier.files.filter(file => file.fileId !== activeFile.fileId);
files.push(activeFile);
const newDossier = new Dossier(activeDossier, files);
this._dossiersService.replace(newDossier);
if (activeFile.lastProcessed !== oldProcessedDate) {
this.fileReanalysed$.next(activeFile);
@ -227,48 +204,25 @@ export class AppStateService {
return activeFile;
}
async getFiles(dossier: Dossier = this.activeDossier, emitEvents = true) {
async getFiles(dossier = this._dossiersService.activeDossier, emitEvents = true) {
const files = await this._filesService.getFor(dossier.id).toPromise();
return this._processFiles(dossier, files, emitEvents);
}
async reanalyzeDossier({ id }: Dossier = this.activeDossier) {
async reanalyzeDossier({ id } = this._dossiersService.activeDossier) {
await this._reanalysisControllerService.reanalyzeDossier(id, true).toPromise();
}
async activateDossier(dossierId: string) {
this._appState.activeFileId = null;
this._appState.activeDossierId = dossierId;
if (!this.activeDossier) {
this._appState.activeDossierId = null;
await this._router.navigate(['/main/dossiers']);
return;
}
this.updateDossierDictionary(this.activeDossier.dossierTemplateId, dossierId);
}
async updateDossierDictionary(dossierTemplateId: string, dossierId: string) {
// dossier exists, load its dictionary
const dossier = this._dossiersService.find(dossierId);
try {
dossier.type = await this._dictionaryService.getFor(dossierTemplateId, 'dossier_redaction', dossierId).toPromise();
} catch (e) {
dossier.type = null;
}
}
async activateFile(dossierId: string, fileId: string) {
if (this.activeDossierId === dossierId && this.activeFileId === fileId) {
if (this._dossiersService.activeDossierId === dossierId && this.activeFileId === fileId) {
return;
}
await this.activateDossier(dossierId);
if (this.activeDossier) {
if (this._dossiersService.activeDossier) {
this._appState.activeFileId = fileId;
if (!this.activeFile) {
this._appState.activeFileId = null;
await this._router.navigate(['/main/dossiers/' + dossierId]);
await this._dossiersService.goToActiveDossier();
}
}
await this._updateLastActiveFileForDossier(dossierId, fileId);
@ -296,7 +250,6 @@ export class AppStateService {
reset() {
this._appState.activeFileId = null;
this._appState.activeDossierId = null;
this._appState.activeDossierTemplateId = null;
this._appState.activeDictionaryType = null;
}
@ -321,14 +274,12 @@ export class AppStateService {
const updatedDossier = await this._dossiersService.createOrUpdate(dossier);
let foundDossier = this._dossiersService.find(updatedDossier.dossierId);
if (foundDossier) {
this._appState.dossiers.splice(this._appState.dossiers.indexOf(foundDossier), 1);
foundDossier = new Dossier(updatedDossier, foundDossier.files);
} else {
foundDossier = new Dossier(updatedDossier, []);
}
this._appState.dossiers.push(foundDossier);
this._dossiersService.setEntities(this._appState.dossiers);
this._dossiersService.replace(foundDossier);
this.dossierChanged$.next(foundDossier);
return foundDossier;
} catch (error) {
@ -339,7 +290,7 @@ export class AppStateService {
}
async reloadActiveDossierFiles() {
if (this.activeDossierId) {
if (this._dossiersService.activeDossierId) {
await this.getFiles();
}
}
@ -390,7 +341,7 @@ export class AppStateService {
async loadDictionaryData(): Promise<void> {
const observables = [];
for (const dossierTemplate of this.dossierTemplates) {
observables.push(this._getDictionaryDataForDossierTemplateObservables(dossierTemplate.dossierTemplateId));
observables.push(this._getDictionaryDataForDossierTemplate$(dossierTemplate.dossierTemplateId));
}
const result = await forkJoin(observables).toPromise();
@ -403,7 +354,7 @@ export class AppStateService {
}
async refreshDossierTemplateDictionaryData(dossierTemplateId: string) {
this._dictionaryData[dossierTemplateId] = await this._getDictionaryDataForDossierTemplateObservables(dossierTemplateId).toPromise();
this._dictionaryData[dossierTemplateId] = await this._getDictionaryDataForDossierTemplate$(dossierTemplateId).toPromise();
}
loadColors(dossierTemplateId: string) {
@ -425,7 +376,7 @@ export class AppStateService {
);
}
private _getDictionaryDataForDossierTemplateObservables(dossierTemplateId: string): Observable<{ [key: string]: any }> {
private _getDictionaryDataForDossierTemplate$(dossierTemplateId: string): Observable<{ [key: string]: any }> {
const dictionaryData: { [key: string]: any } = {};
const typeObs = this._dictionaryService.getAllTypes(dossierTemplateId).pipe(
@ -637,18 +588,13 @@ export class AppStateService {
}
private async _updateLastActiveFileForDossier(dossierId: string, fileId: string) {
this.activeDossier.files.forEach(f => {
this._dossiersService.activeDossier.files.forEach(f => {
f.lastOpened = f.fileId === fileId;
});
await this._userPreferenceService.saveLastOpenedFileForDossier(dossierId, fileId);
}
private _getExistingFiles(dossierId: string): List<File> {
const dossier = this._dossiersService.find(dossierId);
return dossier?.files ?? [];
}
private _processFiles(dossier: Dossier, iFiles: IFile[], emitEvents = true) {
const oldFiles = [...dossier.files];
@ -700,8 +646,7 @@ export class AppStateService {
const lastOpenedFileId = this._userPreferenceService.getLastOpenedFileForDossier(dossier.id);
files.forEach(file => (file.lastOpened = file.fileId === lastOpenedFileId));
const newDossier = new Dossier(dossier, files);
this._appState.dossiers = [...this._appState.dossiers.filter(d => d.dossierId !== dossier.dossierId), newDossier];
this._dossiersService.setEntities(this._appState.dossiers);
this._dossiersService.replace(newDossier);
if (emitEvents) {
fileReanalysedEvent.forEach(file => this.fileReanalysed$.next(file));

View File

@ -1,15 +0,0 @@
@media only screen and (max-width: 800px) {
.visible-lg {
display: none !important;
}
}
.visible-lt-lg {
display: none !important;
}
@media only screen and (max-width: 800px) {
.visible-lt-lg {
display: flex !important;
}
}

View File

@ -9,7 +9,6 @@
@use 'red-toggle';
@use 'red-toggle-button';
@use 'red-menu';
@use 'red-media-queries';
@use 'red-tables';
@use 'red-components';
@use 'red-controls';