Merge branch 'master' into dev

This commit is contained in:
Dan Percic 2023-03-13 16:22:49 +02:00
commit 83bbfa3873
15 changed files with 162 additions and 165 deletions

View File

@ -48,7 +48,7 @@ export class DossierOverviewBulkActionsComponent implements OnChanges {
) {}
private get _buttons(): Action[] {
return [
const actions: Action[] = [
{
id: 'delete-files-btn',
type: ActionTypes.circleBtn,
@ -161,7 +161,9 @@ export class DossierOverviewBulkActionsComponent implements OnChanges {
checked: !this.#allFilesAreExcluded,
show: this.#canToggleAnalysis,
},
].filter(btn => btn.show);
];
return actions.filter(btn => btn.show);
}
ngOnChanges() {

View File

@ -1,11 +1,10 @@
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
import { Component, Input } from '@angular/core';
import { Dossier, File, IFileAttributeConfig } from '@red/domain';
@Component({
selector: 'redaction-table-item [file] [dossier] [displayedAttributes] [dossierTemplateId]',
templateUrl: './table-item.component.html',
styleUrls: ['./table-item.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TableItemComponent {
@Input() file: File;

View File

@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
import { ChangeDetectorRef, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core';
import { Dossier, File, IFileAttributeConfig } from '@red/domain';
import { Debounce } from '@iqser/common-ui';
@ -6,7 +6,6 @@ import { Debounce } from '@iqser/common-ui';
selector: 'redaction-workflow-item [file] [dossier] [displayedAttributes]',
templateUrl: './workflow-item.component.html',
styleUrls: ['./workflow-item.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class WorkflowItemComponent implements OnInit {
@Input() file: File;

View File

@ -29,7 +29,7 @@ export class BulkActionsService {
this._assignFiles(files, WorkflowFileStatuses.UNDER_APPROVAL, true);
} else {
this._loadingService.start();
await firstValueFrom(this._filesService.setUnderApprovalFor(files, dossier.id, dossier.approverIds[0]));
await this._filesService.setUnderApproval(files, dossier.approverIds[0]);
this._loadingService.stop();
}
}
@ -82,13 +82,13 @@ export class BulkActionsService {
async backToUnderReview(files: File[]): Promise<void> {
this._loadingService.start();
await firstValueFrom(this._filesService.setUnderReviewFor(files, files[0].dossierId));
await this._filesService.setUnderReviewFor(files);
this._loadingService.stop();
}
async setToNew(files: File[]): Promise<void> {
this._loadingService.start();
await firstValueFrom(this._filesService.setToNewFor(files, files[0].dossierId));
await this._filesService.setToNew(files);
this._loadingService.stop();
}
@ -113,13 +113,13 @@ export class BulkActionsService {
}),
async () => {
this._loadingService.start();
await firstValueFrom(this._filesService.setApprovedFor(files, files[0].dossierId));
await this._filesService.setApproved(files);
this._loadingService.stop();
},
);
} else {
this._loadingService.start();
await firstValueFrom(this._filesService.setApprovedFor(files, files[0].dossierId));
await this._filesService.setApproved(files);
this._loadingService.stop();
}
}

View File

@ -7,7 +7,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { UserService } from '@users/user.service';
import { FilesService } from '@services/files/files.service';
import { TranslateService } from '@ngx-translate/core';
import { combineLatest, combineLatestWith, firstValueFrom, Observable, switchMap } from 'rxjs';
import { combineLatest, combineLatestWith, Observable, switchMap } from 'rxjs';
import { FilePreviewStateService } from '../../services/file-preview-state.service';
import { distinctUntilChanged, map } from 'rxjs/operators';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
@ -99,22 +99,21 @@ export class UserManagementComponent {
async assignReviewer(file: File, user: User | string) {
const assigneeId = typeof user === 'string' ? user : user?.id;
const reviewerName = this.userService.getName(assigneeId);
const { dossierId, filename } = file;
this.loadingService.start();
if (!assigneeId || file.isApproved) {
await firstValueFrom(this.filesService.setAssignee([file], dossierId, assigneeId));
await this.filesService.setAssignee(file, assigneeId);
} else if (file.isNew || file.isUnderReview) {
await firstValueFrom(this.filesService.setReviewerFor([file], dossierId, assigneeId));
await this.filesService.setReviewer(file, assigneeId);
} else {
await firstValueFrom(this.filesService.setUnderApprovalFor([file], dossierId, assigneeId));
await this.filesService.setUnderApproval(file, assigneeId);
}
this.loadingService.stop();
this.toaster.success(_('assignment.reviewer'), { params: { reviewerName, filename } });
const translateParams = { reviewerName: this.userService.getName(assigneeId), filename: file.filename };
this.toaster.success(_('assignment.reviewer'), { params: translateParams });
this.editingReviewer = false;
}

View File

@ -1,5 +1,5 @@
import { List } from '@iqser/common-ui';
import { AnnotationWrapper } from '../../../models/file/annotation.wrapper';
import { AnnotationWrapper } from '@models/file/annotation.wrapper';
import { ALLOWED_KEYBOARD_SHORTCUTS } from './constants';
export function stopAndPrevent<T extends Event>($event: T) {

View File

@ -1,4 +1,4 @@
<div *ngIf="isDossierOverviewList && (this.fileAttributesService.isEditingFileAttribute$ | async) === false" class="action-buttons">
<div *ngIf="isDossierOverviewList && (fileAttributesService.isEditingFileAttribute$ | async) === false" class="action-buttons">
<ng-container *ngTemplateOutlet="actions"></ng-container>
<redaction-processing-indicator *ngIf="showStatusBar" [file]="file"></redaction-processing-indicator>

View File

@ -120,9 +120,10 @@ export class FileActionsComponent implements OnChanges {
}
private get _buttons(): Action[] {
return [
const fileId = this.file.fileId;
const actions: Action[] = [
{
id: 'delete-file-btn',
id: 'delete-file-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._openDeleteFileDialog($event),
tooltip: _('dossier-overview.delete.action'),
@ -130,7 +131,7 @@ export class FileActionsComponent implements OnChanges {
show: this.showDelete,
},
{
id: 'assign-btn',
id: 'assign-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._assign($event),
tooltip: this.assignTooltip,
@ -138,7 +139,7 @@ export class FileActionsComponent implements OnChanges {
show: this.showAssign,
},
{
id: 'assign-to-me-btn',
id: 'assign-to-me-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._assignToMe($event),
tooltip: _('dossier-overview.assign-me'),
@ -146,7 +147,7 @@ export class FileActionsComponent implements OnChanges {
show: this.showAssignToSelf,
},
{
id: 'open-import-redactions-dialog-btn',
id: 'open-import-redactions-dialog-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._openImportRedactionsDialog($event),
tooltip: _('dossier-overview.import-redactions'),
@ -154,7 +155,7 @@ export class FileActionsComponent implements OnChanges {
show: this.showImportRedactions && !this._iqserPermissionsService.has(ROLES.getRss),
},
{
id: 'download-file-btn',
id: 'download-file-btn-' + fileId,
type: ActionTypes.downloadBtn,
files: [this.file],
dossier: this.dossier,
@ -163,7 +164,7 @@ export class FileActionsComponent implements OnChanges {
disabled: this.file.processingStatus === ProcessingFileStatuses.ERROR,
},
{
id: 'toggle-document-info-btn',
id: 'toggle-document-info-btn-' + fileId,
type: ActionTypes.circleBtn,
action: () => this._documentInfoService.toggle(),
tooltip: _('file-preview.document-info'),
@ -172,7 +173,7 @@ export class FileActionsComponent implements OnChanges {
show: !!this._documentInfoService,
},
{
id: 'toggle-exclude-pages-btn',
id: 'toggle-exclude-pages-btn-' + fileId,
type: ActionTypes.circleBtn,
action: () => this._excludedPagesService.toggle(),
tooltip: _('file-preview.exclude-pages'),
@ -185,15 +186,15 @@ export class FileActionsComponent implements OnChanges {
!this._iqserPermissionsService.has(ROLES.getRss),
},
{
id: 'set-file-to-new-btn',
id: 'set-file-to-new-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._setToNew($event),
action: ($event: MouseEvent) => this.#setToNew($event),
tooltip: _('dossier-overview.back-to-new'),
icon: 'red:undo',
show: this.showSetToNew,
},
{
id: 'set-file-under-approval-btn',
id: 'set-file-under-approval-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._setFileUnderApproval($event),
tooltip: _('dossier-overview.under-approval'),
@ -201,7 +202,7 @@ export class FileActionsComponent implements OnChanges {
show: this.showUnderApproval,
},
{
id: 'set-file-under-review-btn',
id: 'set-file-under-review-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._setFileUnderReview($event),
tooltip: _('dossier-overview.under-review'),
@ -209,7 +210,7 @@ export class FileActionsComponent implements OnChanges {
show: this.showUnderReview,
},
{
id: 'set-file-approved-btn',
id: 'set-file-approved-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this.setFileApproved($event),
tooltip: this.file.canBeApproved ? _('dossier-overview.approve') : _('dossier-overview.approve-disabled'),
@ -218,7 +219,7 @@ export class FileActionsComponent implements OnChanges {
show: this.showApprove,
},
{
id: 'toggle-automatic-analysis-btn',
id: 'toggle-automatic-analysis-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._toggleAutomaticAnalysis($event),
tooltip: _('dossier-overview.stop-auto-analysis'),
@ -226,7 +227,7 @@ export class FileActionsComponent implements OnChanges {
show: this.canDisableAutoAnalysis,
},
{
id: 'reanalyse-file-preview-btn',
id: 'reanalyse-file-preview-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._reanalyseFile($event),
tooltip: _('file-preview.reanalyse-notification'),
@ -236,7 +237,7 @@ export class FileActionsComponent implements OnChanges {
disabled: this.file.isProcessing,
},
{
id: 'toggle-automatic-analysis-btn',
id: 'toggle-automatic-analysis-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._toggleAutomaticAnalysis($event),
tooltip: _('dossier-overview.start-auto-analysis'),
@ -245,7 +246,7 @@ export class FileActionsComponent implements OnChanges {
show: this.canEnableAutoAnalysis,
},
{
id: 'set-under-approval-btn',
id: 'set-under-approval-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._setFileUnderApproval($event),
tooltip: _('dossier-overview.under-approval'),
@ -253,7 +254,7 @@ export class FileActionsComponent implements OnChanges {
show: this.showUndoApproval,
},
{
id: 'ocr-file-btn',
id: 'ocr-file-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._ocrFile($event),
tooltip: _('dossier-overview.ocr-file'),
@ -261,7 +262,7 @@ export class FileActionsComponent implements OnChanges {
show: this.showOCR,
},
{
id: 'reanalyse-file-btn',
id: 'reanalyse-file-btn-' + fileId,
type: ActionTypes.circleBtn,
action: ($event: MouseEvent) => this._reanalyseFile($event),
tooltip: _('dossier-overview.reanalyse.action'),
@ -269,7 +270,7 @@ export class FileActionsComponent implements OnChanges {
show: this.showReanalyseDossierOverview,
},
{
id: 'toggle-analysis-btn',
id: 'toggle-analysis-btn-' + fileId,
type: ActionTypes.toggle,
action: () => this._toggleAnalysis(),
disabled: !this.canToggleAnalysis,
@ -278,7 +279,9 @@ export class FileActionsComponent implements OnChanges {
checked: !this.file.excluded,
show: this.showToggleAnalysis,
},
].filter(btn => btn.show);
];
return actions.filter(btn => btn.show);
}
ngOnChanges(changes: SimpleChanges) {
@ -292,7 +295,7 @@ export class FileActionsComponent implements OnChanges {
async setFileApproved($event: MouseEvent) {
$event.stopPropagation();
if (!this.file.analysisRequired && !this.file.hasUpdates) {
await this._setFileApproved();
await this.#setFileApproved();
return;
}
@ -311,7 +314,7 @@ export class FileActionsComponent implements OnChanges {
: null,
denyText: this.file.analysisRequired ? _('confirmation-dialog.approve-file-without-analysis.denyText') : null,
}),
() => this._setFileApproved(),
() => this.#setFileApproved(),
);
}
@ -466,16 +469,16 @@ export class FileActionsComponent implements OnChanges {
this._changeRef.markForCheck();
}
private async _setFileApproved() {
async #setFileApproved() {
this._loadingService.start();
await firstValueFrom(this._filesService.setApprovedFor([this.file], this.file.dossierId));
await this._filesService.setApproved(this.file);
this._loadingService.stop();
}
private async _setToNew($event: MouseEvent) {
async #setToNew($event: MouseEvent) {
$event.stopPropagation();
this._loadingService.start();
await firstValueFrom(this._filesService.setToNewFor([this.file], this.file.dossierId));
await this._filesService.setToNew(this.file);
this._loadingService.stop();
}
}

View File

@ -1,14 +1,13 @@
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { UserService } from '@users/user.service';
import { IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms';
import { Dossier, File, WorkflowFileStatus, WorkflowFileStatuses } from '@red/domain';
import { getCurrentUser, IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
import { FormBuilder, Validators } from '@angular/forms';
import { File, User, WorkflowFileStatus, WorkflowFileStatuses } from '@red/domain';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { FilesService } from '@services/files/files.service';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
import { PermissionsService } from '@services/permissions.service';
import { firstValueFrom } from 'rxjs';
import { moveElementInArray } from '@utils/functions';
class DialogData {
@ -24,59 +23,37 @@ class DialogData {
})
export class AssignReviewerApproverDialogComponent {
readonly iconButtonTypes = IconButtonTypes;
readonly form: UntypedFormGroup;
readonly mode: 'reviewer' | 'approver';
dossier: Dossier;
readonly currentUser = getCurrentUser<User>();
readonly mode = this.#mode;
readonly dossier = this._activeDossiersService.find(this.data.files[0].dossierId);
readonly userOptions = this.#userOptions;
readonly form = this.#form;
constructor(
readonly userService: UserService,
private readonly _toaster: Toaster,
private readonly _formBuilder: UntypedFormBuilder,
private readonly _formBuilder: FormBuilder,
private readonly _activeDossiersService: ActiveDossiersService,
private readonly _filesService: FilesService,
private readonly _loadingService: LoadingService,
readonly permissionsService: PermissionsService,
private readonly _dialogRef: MatDialogRef<AssignReviewerApproverDialogComponent, boolean>,
@Inject(MAT_DIALOG_DATA) readonly data: DialogData,
) {
this.dossier = this._activeDossiersService.find(this.data.files[0].dossierId);
this.form = this._getForm();
this.mode =
data.targetStatus === WorkflowFileStatuses.UNDER_APPROVAL || data.targetStatus === WorkflowFileStatuses.APPROVED
? 'approver'
: 'reviewer';
}
) {}
get selectedUser(): string {
const value = this.form.get('user').value;
const value = this.form.controls.user.value;
return value === 'undefined' ? undefined : value;
}
get userOptions() {
const unassignUser = this._canUnassignFiles && this.data.withUnassignedOption ? ['undefined'] : [];
const cannotAssignUser = !this.permissionsService.canAssignUser(this.data.files, this.dossier);
if (this.mode === 'reviewer') {
if (this.dossier.hasReviewers && cannotAssignUser) {
return [...unassignUser];
}
return this._customSort([...this.dossier.memberIds, ...unassignUser]);
}
if (this.dossier.approverIds.length > 1 && cannotAssignUser) {
return [...unassignUser];
}
return this._customSort([...this.dossier.approverIds, ...unassignUser]);
}
get changed(): boolean {
if (this.data.ignoreChanged) {
return true;
}
const selectedUser = this.selectedUser;
for (const file of this.data.files) {
if (file.assignee !== this.selectedUser) {
if (file.assignee !== selectedUser) {
return true;
}
}
@ -84,71 +61,100 @@ export class AssignReviewerApproverDialogComponent {
return false;
}
private get _canUnassignFiles() {
get #mode() {
const isUnderApproval = this.data.targetStatus === WorkflowFileStatuses.UNDER_APPROVAL;
const isApproved = this.data.targetStatus === WorkflowFileStatuses.APPROVED;
return isUnderApproval || isApproved ? 'approver' : 'reviewer';
}
get #userOptions() {
const unassignUser = this.#canUnassignUser && this.data.withUnassignedOption ? ['undefined'] : [];
const cannotAssignUser = !this.permissionsService.canAssignUser(this.data.files, this.dossier);
if (this.mode === 'reviewer') {
if (this.dossier.hasReviewers && cannotAssignUser) {
return [...unassignUser];
}
return this.#customSort([...this.dossier.memberIds, ...unassignUser]);
}
if (this.dossier.approverIds.length > 1 && cannotAssignUser) {
return [...unassignUser];
}
return this.#customSort([...this.dossier.approverIds, ...unassignUser]);
}
get #canUnassignUser() {
return this.permissionsService.canUnassignUser(this.data.files, this.dossier);
}
/** Initialize the form with:
* the id of the current reviewer of the files list if there is only one reviewer for all of them;
* or the id of the current user
**/
private get _uniqueReviewers(): Set<string> {
get #uniqueReviewers(): Set<string> {
const uniqueReviewers = new Set<string>();
for (const file of this.data.files) {
if (file.assignee) {
uniqueReviewers.add(file.assignee);
}
}
return uniqueReviewers;
}
private get _user(): string {
get #user(): string {
const userOptions = this.userOptions;
if (this.data.withCurrentUserAsDefault && userOptions.includes(this.userService.currentUser.id)) {
return this.userService.currentUser.id;
if (this.data.withCurrentUserAsDefault && userOptions.includes(this.currentUser.id)) {
return this.currentUser.id;
}
const uniqueReviewers = [...this._uniqueReviewers.values()];
const user = uniqueReviewers.length === 1 ? uniqueReviewers[0] : this.userService.currentUser.id;
const uniqueReviewers = [...this.#uniqueReviewers.values()];
const user = uniqueReviewers.length === 1 ? uniqueReviewers[0] : this.currentUser.id;
return userOptions.indexOf(user) >= 0 ? userOptions[userOptions.indexOf(user)] : user;
}
get #form() {
const user = this.#user;
return this._formBuilder.group({
// Allow a null reviewer if a previous reviewer exists (= it's not the first assignment) & current user is allowed to unassign
user: [user, this.#canUnassignUser && !user ? Validators.required : null],
});
}
async save() {
this._loadingService.start();
const selectedUser = this.selectedUser;
try {
if (!this.selectedUser || this.data.targetStatus === WorkflowFileStatuses.APPROVED) {
await firstValueFrom(this._filesService.setAssignee(this.data.files, this.dossier.id, this.selectedUser));
if (!selectedUser || this.data.targetStatus === WorkflowFileStatuses.APPROVED) {
await this._filesService.setAssignee(this.data.files, selectedUser);
} else if (this.mode === 'reviewer') {
await firstValueFrom(this._filesService.setReviewerFor(this.data.files, this.dossier.id, this.selectedUser));
await this._filesService.setReviewer(this.data.files, selectedUser);
} else {
await firstValueFrom(this._filesService.setUnderApprovalFor(this.data.files, this.dossier.id, this.selectedUser));
await this._filesService.setUnderApproval(this.data.files, selectedUser);
}
} catch (error) {
this._toaster.error(_('error.http.generic'), { params: error });
}
this._loadingService.stop();
this._loadingService.stop();
this._dialogRef.close(true);
}
private _getForm(): UntypedFormGroup {
return this._formBuilder.group({
// Allow a null reviewer if a previous reviewer exists (= it's not the first assignment) & current user is allowed to unassign
user: [this._user, this._canUnassignFiles && !this._user ? Validators.required : null],
});
}
private _customSort(ids: string[]) {
#customSort(ids: string[]) {
let sorted = ids.sort((a, b) => this.userService.getName(a).localeCompare(this.userService.getName(b)));
if (this.data.files.length === 1 && this.data.files[0].assignee) {
const fileHasAssignee = this.data.files.length === 1 && this.data.files[0].assignee;
if (fileHasAssignee) {
sorted = moveElementInArray(sorted, this.data.files[0].assignee, 0);
}
if (this.data.withUnassignedOption) {
sorted = moveElementInArray(sorted, 'undefined', this.data.files[0].assignee && this.data.files.length === 1 ? 1 : 0);
if (sorted.includes('undefined')) {
sorted = moveElementInArray(sorted, 'undefined', fileHasAssignee ? 1 : 0);
}
return sorted;
}
}

View File

@ -1,10 +1,9 @@
import { Injectable } from '@angular/core';
import { UserService } from '@users/user.service';
import { Dossier, File, User, WorkflowFileStatus, WorkflowFileStatuses } from '@red/domain';
import { DossiersDialogService } from './dossiers-dialog.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { FilesService } from '@services/files/files.service';
import { ConfirmationDialogInput, LoadingService, Toaster } from '@iqser/common-ui';
import { ConfirmationDialogInput, getCurrentUser, LoadingService, Toaster } from '@iqser/common-ui';
import { ActiveDossiersService } from '@services/dossiers/active-dossiers.service';
import { firstValueFrom } from 'rxjs';
@ -12,18 +11,15 @@ const atLeastOneAssignee = (files: File[]) => files.reduce((acc, fs) => acc || !
@Injectable()
export class FileAssignService {
readonly currentUser: User;
readonly currentUser = getCurrentUser<User>();
constructor(
userService: UserService,
private readonly _toaster: Toaster,
private readonly _filesService: FilesService,
private readonly _loadingService: LoadingService,
private readonly _dialogService: DossiersDialogService,
private readonly _activeDossiersService: ActiveDossiersService,
) {
this.currentUser = userService.currentUser;
}
) {}
async assignToMe(files: File[]): Promise<unknown> {
const assignReq = async () => {
@ -31,10 +27,11 @@ export class FileAssignService {
if (files[0].isNew) {
await this._makeAssignFileRequest(this.currentUser.id, 'UNDER_REVIEW', files);
} else {
await firstValueFrom(this._filesService.setAssignee(files, files[0].dossierId, this.currentUser.id));
await this._filesService.setAssignee(files, this.currentUser.id);
}
this._loadingService.stop();
};
if (atLeastOneAssignee(files)) {
const dialogInput = new ConfirmationDialogInput({
title: _('confirmation-dialog.assign-file-to-me.title'),
@ -88,17 +85,19 @@ export class FileAssignService {
private async _makeAssignFileRequest(userId: string, targetStatus: WorkflowFileStatus, files: File[]) {
this._loadingService.start();
try {
if (!userId || targetStatus === WorkflowFileStatuses.APPROVED) {
await firstValueFrom(this._filesService.setAssignee(files, files[0].dossierId, userId));
await this._filesService.setAssignee(files, userId);
} else if (targetStatus === WorkflowFileStatuses.UNDER_REVIEW) {
await firstValueFrom(this._filesService.setReviewerFor(files, files[0].dossierId, userId));
await this._filesService.setReviewer(files, userId);
} else {
await firstValueFrom(this._filesService.setUnderApprovalFor(files, files[0].dossierId, userId));
await this._filesService.setUnderApproval(files, userId);
}
} catch (error) {
this._toaster.error(_('error.http.generic'), { params: error });
}
this._loadingService.stop();
}

View File

@ -30,7 +30,7 @@ export class ExpandableFileActionsComponent implements OnChanges {
expanded = false;
@ViewChild(MatMenuTrigger) matMenu: MatMenuTrigger;
trackBy = trackByFactory();
readonly trackBy = trackByFactory();
constructor(
private readonly _fileDownloadService: FileDownloadService,

View File

@ -1,13 +1,15 @@
import { Injectable } from '@angular/core';
import { EntitiesService, List, mapEach, RequiredParam, Validate } from '@iqser/common-ui';
import { EntitiesService, isArray, List, mapEach, QueryParam, RequiredParam, Validate } from '@iqser/common-ui';
import { File, IFile } from '@red/domain';
import { Observable } from 'rxjs';
import { firstValueFrom, Observable } from 'rxjs';
import { UserService } from '@users/user.service';
import { FilesMapService } from './files-map.service';
import { map, switchMap, tap } from 'rxjs/operators';
import { DossierStatsService } from '../dossiers/dossier-stats.service';
import { NGXLogger } from 'ngx-logger';
const asList = <T>(value: T | List<T>): List<T> => (isArray(value) ? value : [value]);
@Injectable({
providedIn: 'root',
})
@ -44,46 +46,47 @@ export class FilesService extends EntitiesService<IFile, File> {
}
@Validate()
setAssignee(@RequiredParam() files: List<File>, @RequiredParam() dossierId: string, assigneeId: string) {
const url = `${this._defaultModelPath}/set-assignee/${dossierId}/bulk`;
const fileIds = files.map(f => f.id);
return this._post<unknown>(fileIds, url, [{ key: 'assigneeId', value: assigneeId }]).pipe(switchMap(() => this.loadAll(dossierId)));
async setAssignee(@RequiredParam() files: File | List<File>, assigneeId: string) {
const _files = asList(files);
const url = `${this._defaultModelPath}/set-assignee/${_files[0].dossierId}/bulk`;
return this.#makePost(_files, url, [{ key: 'assigneeId', value: assigneeId }]);
}
@Validate()
setToNewFor(@RequiredParam() files: List<File>, @RequiredParam() dossierId: string) {
const url = `${this._defaultModelPath}/new/${dossierId}/bulk`;
const fileIds = files.map(f => f.id);
return this._post<unknown>(fileIds, url).pipe(switchMap(() => this.loadAll(dossierId)));
async setToNew(@RequiredParam() files: File | List<File>) {
const _files = asList(files);
return this.#makePost(_files, `${this._defaultModelPath}/new/${_files[0].dossierId}/bulk`);
}
@Validate()
setUnderApprovalFor(@RequiredParam() files: List<File>, @RequiredParam() dossierId: string, assigneeId: string) {
const url = `${this._defaultModelPath}/under-approval/${dossierId}/bulk`;
const fileIds = files.map(f => f.id);
return this._post<unknown>(fileIds, url, [{ key: 'assigneeId', value: assigneeId }]).pipe(switchMap(() => this.loadAll(dossierId)));
async setUnderApproval(@RequiredParam() files: File | List<File>, assigneeId: string) {
const _files = asList(files);
const url = `${this._defaultModelPath}/under-approval/${_files[0].dossierId}/bulk`;
return this.#makePost(_files, url, [{ key: 'assigneeId', value: assigneeId }]);
}
@Validate()
setReviewerFor(@RequiredParam() files: List<File>, @RequiredParam() dossierId: string, assigneeId: string) {
const url = `${this._defaultModelPath}/under-review/${dossierId}/bulk`;
const fileIds = files.map(f => f.id);
return this._post<unknown>(fileIds, url, [{ key: 'assigneeId', value: assigneeId }]).pipe(switchMap(() => this.loadAll(dossierId)));
async setReviewer(@RequiredParam() files: File | List<File>, assigneeId: string) {
const _files = asList(files);
const url = `${this._defaultModelPath}/under-review/${_files[0].dossierId}/bulk`;
return this.#makePost(_files, url, [{ key: 'assigneeId', value: assigneeId }]);
}
@Validate()
setApprovedFor(@RequiredParam() files: List<File>, @RequiredParam() dossierId: string) {
const fileIds = files.map(f => f.id);
return this._post<unknown>(fileIds, `${this._defaultModelPath}/approved/${dossierId}/bulk`).pipe(
switchMap(() => this.loadAll(dossierId)),
);
async setApproved(@RequiredParam() files: File | List<File>) {
const _files = asList(files);
return this.#makePost(_files, `${this._defaultModelPath}/approved/${_files[0].dossierId}/bulk`);
}
@Validate()
setUnderReviewFor(@RequiredParam() files: List<File>, @RequiredParam() dossierId: string) {
async setUnderReviewFor(@RequiredParam() files: File | List<File>) {
const _files = asList(files);
return this.#makePost(_files, `${this._defaultModelPath}/under-review/${_files[0].dossierId}/bulk`);
}
async #makePost(files: List<File>, url: string, queryParams?: List<QueryParam>) {
const fileIds = files.map(f => f.id);
return this._post<unknown>(fileIds, `${this._defaultModelPath}/under-review/${dossierId}/bulk`).pipe(
switchMap(() => this.loadAll(dossierId)),
);
await firstValueFrom(this._post(fileIds, url, queryParams));
return firstValueFrom(this.loadAll(files[0].dossierId));
}
}

View File

@ -89,19 +89,6 @@ export class NotificationsService extends EntitiesService<INotification, Notific
return true;
}
console.log('------------------------------------------------------------------------------');
console.log('id: ', n.id);
console.log('today date: ', todayDate);
console.log('read date: ', readDate);
console.log('diff in minutes: ', todayDate.diff(readDate, 'minute'));
console.log(
'should be shown: ',
todayDate.diff(readDate, 'minute') <=
(this.#config.AVAILABLE_OLD_NOTIFICATIONS_MINUTES ?? AVAILABLE_OLD_NOTIFICATIONS_MINUTES),
);
console.log('CONFIG AVAILABLE_OLD_NOTIFICATIONS_MINUTES: ', this.#config.AVAILABLE_OLD_NOTIFICATIONS_MINUTES);
console.log('DEFAULT AVAILABLE_OLD_NOTIFICATIONS_MINUTES: ', AVAILABLE_OLD_NOTIFICATIONS_MINUTES);
return (
todayDate.diff(readDate, 'minute') <=
(this.#config.AVAILABLE_OLD_NOTIFICATIONS_MINUTES ?? AVAILABLE_OLD_NOTIFICATIONS_MINUTES)

View File

@ -1,6 +1,6 @@
{
"name": "redaction",
"version": "3.983.0",
"version": "3.987.0",
"private": true,
"license": "MIT",
"scripts": {

Binary file not shown.