Merge branch 'master' into VM/NotificationsPreferences

This commit is contained in:
Valentin 2021-10-27 21:49:20 +03:00
commit 685dc3ea24
54 changed files with 174 additions and 251 deletions

View File

@ -51,7 +51,7 @@
<div class="menu right flex-2">
<div class="buttons">
<redaction-spotlight-search
*ngIf="(isSearchScreen$ | async) === false"
*ngIf="(isSearchScreen$ | async) === false && (currentUser.isUser || currentUser.isManager)"
[actions]="searchActions"
[placeholder]="'search.placeholder' | translate"
iqserHelpMode="search"

View File

@ -4,8 +4,7 @@ import { AnnotationWrapper } from './annotation.wrapper';
import { RedactionLogEntryWrapper } from './redaction-log-entry.wrapper';
import { ViewMode } from './view-mode';
import * as moment from 'moment';
import { IViewedPage, User } from '@red/domain';
import { Dictionary } from '@models/dictionary';
import { Dictionary, IViewedPage, User } from '@red/domain';
export class AnnotationData {
visibleAnnotations: AnnotationWrapper[];

View File

@ -8,8 +8,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { AppStateService } from '@state/app-state.service';
import { toKebabCase } from '@utils/functions';
import { DictionaryService } from '@shared/services/dictionary.service';
import { IDictionary } from '@redaction/red-ui-http';
import { Dictionary } from '@models/dictionary';
import { Dictionary, IDictionary } from '@red/domain';
@Component({
selector: 'redaction-add-edit-dictionary-dialog',

View File

@ -4,13 +4,12 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import * as moment from 'moment';
import { Moment } from 'moment';
import { IDossierTemplate } from '@redaction/red-ui-http';
import { applyIntervalConstraints } from '@utils/date-inputs-utils';
import { downloadTypesTranslations } from '../../../../translations/download-types-translations';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { CONFLICT_ERROR_CODE, Toaster } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { DownloadFileType } from '@red/domain';
import { DownloadFileType, IDossierTemplate } from '@red/domain';
@Component({
templateUrl: './add-edit-dossier-template-dialog.component.html',

View File

@ -18,7 +18,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { UserService } from '@services/user.service';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { Dictionary } from '@models/dictionary';
import { Dictionary } from '@red/domain';
const toChartConfig = (dict: Dictionary): DoughnutChartConfig => ({
value: dict.entries?.length ?? 0,
@ -39,7 +39,7 @@ export class DictionaryListingScreenComponent extends ListingComponent<Dictionar
readonly tableHeaderLabel = _('dictionary-listing.table-header.title');
readonly tableColumnConfigs: TableColumnConfig<Dictionary>[] = [
{ label: _('dictionary-listing.table-col-names.type'), sortByKey: 'searchKey', width: '2fr' },
{ label: _('dictionary-listing.table-col-names.order-of-importance'), sortByKey: 'rank', class: 'flex-center' },
{ label: _('dictionary-listing.table-col-names.rank'), sortByKey: 'rank', class: 'flex-center' },
{ label: _('dictionary-listing.table-col-names.hint-redaction'), class: 'flex-center' },
];
chartData: DoughnutChartConfig[] = [];

View File

@ -10,7 +10,7 @@ import { DictionaryService } from '@shared/services/dictionary.service';
import { CircleButtonTypes, LoadingService } from '@iqser/common-ui';
import { UserService } from '@services/user.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { Dictionary } from '@models/dictionary';
import { Dictionary } from '@red/domain';
@Component({
templateUrl: './dictionary-overview-screen.component.html',

View File

@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, Component, forwardRef, Injector, OnInit } from
import { AppStateService } from '@state/app-state.service';
import { UserPreferenceService } from '@services/user-preference.service';
import { AdminDialogService } from '../../services/admin-dialog.service';
import { DossierTemplate } from '@models/file/dossier-template';
import { DossierTemplate } from '@red/domain';
import {
CircleButtonTypes,
DefaultListingServicesTmp,

View File

@ -78,10 +78,6 @@ export class TrashScreenComponent extends ListingComponent<DossierListItem> impl
title: _('confirmation-dialog.delete-dossier.title'),
titleColor: TitleColors.WARN,
question: _('confirmation-dialog.delete-dossier.question'),
// details: _('confirmation-dialog.delete-dossier.details'),
confirmationText: _('confirmation-dialog.delete-dossier.confirmation-text'),
requireInput: true,
denyText: _('confirmation-dialog.delete-dossier.deny-text'),
translateParams: {
dossierName: dossiers[0].dossierName,
dossiersCount: dossiers.length,

View File

@ -132,10 +132,12 @@ export class UserListingScreenComponent extends ListingComponent<User> implement
}),
);
this.filterService.addFilterGroup({
slug: 'roleFilters',
filters: roleFilters,
checker: userTypeChecker,
});
this.filterService.addFilterGroups([
{
slug: 'roleFilters',
filters: roleFilters,
checker: userTypeChecker,
},
]);
}
}

View File

@ -1,6 +1,6 @@
import { Component } from '@angular/core';
import { MatDialogRef } from '@angular/material/dialog';
import { IDossierTemplate, ReportTemplate } from '@redaction/red-ui-http';
import { ReportTemplate } from '@redaction/red-ui-http';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import * as moment from 'moment';
import { downloadTypesTranslations } from '../../../../translations/download-types-translations';
@ -8,7 +8,7 @@ import { IconButtonTypes } from '@iqser/common-ui';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { ReportTemplateService } from '@services/report-template.service';
import { DownloadFileType, IDossierRequest } from '@red/domain';
import { DownloadFileType, IDossierRequest, IDossierTemplate } from '@red/domain';
@Component({
templateUrl: './add-dossier-dialog.component.html',
@ -33,7 +33,7 @@ export class AddDossierDialogComponent {
private readonly _reportTemplateController: ReportTemplateService,
readonly dialogRef: MatDialogRef<AddDossierDialogComponent>,
) {
this._filterInvalidDossierTemplates();
this._getDossierTemplates();
this.dossierForm = this._formBuilder.group(
{
dossierName: [null, Validators.required],
@ -105,12 +105,14 @@ export class AddDossierDialogComponent {
}
}
private _filterInvalidDossierTemplates() {
this.dossierTemplates = this._dossierTemplatesService.all.filter(r => {
const notYetValid = !!r.validFrom && moment(r.validFrom).isAfter(moment());
const notValidAnymore = !!r.validTo && moment(r.validTo).add(1, 'd').isBefore(moment());
return !(notYetValid || notValidAnymore);
});
private _getDossierTemplates() {
this.dossierTemplates = this._dossierTemplatesService.all
.filter(r => {
const notYetValid = !!r.validFrom && moment(r.validFrom).isAfter(moment());
const notValidAnymore = !!r.validTo && moment(r.validTo).add(1, 'd').isBefore(moment());
return !(notYetValid || notValidAnymore);
})
.sort((t1, t2) => t1.name.toLowerCase().localeCompare(t2.name.toLowerCase()));
}
private _formToObject(): IDossierRequest {

View File

@ -7,14 +7,14 @@
class="dialog-header heading-l"
></div>
<form (submit)="saveUsers()" [formGroup]="usersForm">
<form (submit)="save()" [formGroup]="usersForm">
<div class="dialog-content">
<div class="iqser-input-group w-300 required">
<mat-form-field floatLabel="always">
<mat-label>{{ 'assign-owner.dialog.label' | translate: { type: data.mode } }}</mat-label>
<mat-select formControlName="singleUser">
<mat-select [placeholder]="'initials-avatar.unassigned' | translate" formControlName="singleUser">
<mat-option *ngFor="let userId of singleUsersSelectOptions" [value]="userId">
{{ userId | name }}
{{ userId | name: { defaultValue: 'initials-avatar.unassigned' | translate } }}
</mat-option>
</mat-select>
</mat-form-field>

View File

@ -9,6 +9,7 @@ import { Dossier } from '@red/domain';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { FilesService } from '@services/entity-services/files.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { PermissionsService } from '@services/permissions.service';
class DialogData {
mode: 'approver' | 'reviewer';
@ -32,6 +33,7 @@ export class AssignReviewerApproverDialogComponent {
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
private readonly _filesService: FilesService,
readonly permissionsService: PermissionsService,
private readonly _dialogRef: MatDialogRef<AssignReviewerApproverDialogComponent, boolean>,
@Inject(MAT_DIALOG_DATA) readonly data: DialogData,
) {
@ -43,9 +45,10 @@ export class AssignReviewerApproverDialogComponent {
}
get singleUsersSelectOptions() {
const unassignUser = this._canUnassignFiles ? [undefined] : [];
return this.data.mode === 'approver'
? this._dossiersService.activeDossier.approverIds
: this._dossiersService.activeDossier.memberIds;
? [...this._dossiersService.activeDossier.approverIds, ...unassignUser]
: [...this._dossiersService.activeDossier.memberIds, ...unassignUser];
}
get changed(): boolean {
@ -62,11 +65,15 @@ export class AssignReviewerApproverDialogComponent {
return false;
}
private get _canUnassignFiles() {
return this.data.files.reduce((prev, file) => prev && this.permissionsService.canUnassignUser(file), true);
}
isOwner(userId: string): boolean {
return userId === this.selectedSingleUser;
}
async saveUsers() {
async save() {
try {
const selectedUser = this.selectedSingleUser;
@ -94,6 +101,10 @@ export class AssignReviewerApproverDialogComponent {
this._dialogRef.close(true);
}
/** 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 _loadData() {
const uniqueReviewers = new Set<string>();
for (const file of this.data.files) {
@ -101,12 +112,13 @@ export class AssignReviewerApproverDialogComponent {
uniqueReviewers.add(file.currentReviewer);
}
}
let singleUser = uniqueReviewers.size === 1 ? uniqueReviewers.values().next().value : this.userService.currentUser.id;
let singleUser: string = uniqueReviewers.size === 1 ? uniqueReviewers.values().next().value : this.userService.currentUser.id;
singleUser = this.singleUsersSelectOptions.indexOf(singleUser) >= 0 ? singleUser : this.singleUsersSelectOptions[0];
this.usersForm = this._formBuilder.group({
singleUser: [singleUser, Validators.required],
// Allow a null reviewer if a previous reviewer exists (= it's not the first assignment) & current user is allowed to unassign
singleUser: [singleUser, this._canUnassignFiles && !singleUser ? Validators.required : null],
});
}
}

View File

@ -1,12 +1,11 @@
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { Dossier } from '@red/domain';
import { Dossier, IDictionary } from '@red/domain';
import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { PermissionsService } from '@services/permissions.service';
import { DictionaryManagerComponent } from '@shared/components/dictionary-manager/dictionary-manager.component';
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/entity-services/dossiers.service';
@Component({

View File

@ -1,8 +1,7 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { IDossierTemplate } from '@redaction/red-ui-http';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import * as moment from 'moment';
import { Dossier, IDossierRequest } from '@red/domain';
import { Dossier, IDossierRequest, IDossierTemplate } from '@red/domain';
import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
import { PermissionsService } from '@services/permissions.service';

View File

@ -12,7 +12,7 @@ import { ManualAnnotationResponse } from '@models/file/manual-annotation-respons
import { PermissionsService } from '@services/permissions.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { JustificationsService } from '@services/entity-services/justifications.service';
import { Dictionary } from '@models/dictionary';
import { Dictionary } from '@red/domain';
export interface LegalBasisOption {
label?: string;

View File

@ -74,7 +74,10 @@ export class DossierOverviewBulkActionsComponent {
get canAssign() {
return (
this.allSelectedFilesCanBeAssignedIntoSameState &&
this.selectedFiles.reduce((acc, file) => acc && this._permissionsService.canAssignUser(file), true)
this.selectedFiles.reduce(
(acc, file) => (acc && this._permissionsService.canAssignUser(file)) || this._permissionsService.canUnassignUser(file),
true,
)
);
}

View File

@ -1,10 +1,9 @@
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { AppStateService } from '@state/app-state.service';
import { Dossier, DossierAttributeWithValue } from '@red/domain';
import { Dossier, DossierAttributeWithValue, DossierTemplate } from '@red/domain';
import { DossiersDialogService } from '../../../../services/dossiers-dialog.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { DossierTemplate } from '@models/file/dossier-template';
@Component({
selector: 'redaction-dossier-details-stats',

View File

@ -1,5 +1,15 @@
import { Injectable, TemplateRef } from '@angular/core';
import { IFilterGroup, INestedFilter, keyChecker, LoadingService, NestedFilter, TableColumnConfig, WorkflowConfig } from '@iqser/common-ui';
import {
IFilterGroup,
INestedFilter,
keyChecker,
ListingMode,
ListingModes,
LoadingService,
NestedFilter,
TableColumnConfig,
WorkflowConfig,
} from '@iqser/common-ui';
import { File } from '@models/file/file';
import { fileStatusTranslations } from '../../translations/file-status-translations';
import { FileStatus, FileStatuses, IFileAttributeConfig } from '@redaction/red-ui-http';
@ -15,11 +25,13 @@ import { workloadTranslations } from '../../translations/workload-translations';
import * as moment from 'moment';
import { ConfigService as AppConfigService } from '@services/config.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { FilesService } from '@services/entity-services/files.service';
@Injectable()
export class ConfigService {
constructor(
private readonly _fileActionService: FileActionService,
private readonly _filesService: FilesService,
private readonly _loadingService: LoadingService,
private readonly _appStateService: AppStateService,
private readonly _dossiersService: DossiersService,
@ -88,7 +100,7 @@ export class ConfigService {
label: fileStatusTranslations[FileStatuses.UNASSIGNED],
key: FileStatuses.UNASSIGNED,
enterFn: this._unassignFn(reloadDossiers),
enterPredicate: () => false,
enterPredicate: (file: File) => this._permissionsService.canUnassignUser(file),
color: '#D3D5DA',
},
{
@ -122,6 +134,7 @@ export class ConfigService {
filterGroups(
entities: File[],
listingMode: ListingMode,
fileAttributeConfigs: IFileAttributeConfig[],
needsWorkFilterTemplate: TemplateRef<unknown>,
checkedRequiredFilters: () => NestedFilter[],
@ -181,21 +194,23 @@ export class ConfigService {
});
});
const statusFilters = [...allDistinctFileStatuses].map(
status =>
new NestedFilter({
id: status,
label: this._translateService.instant(fileStatusTranslations[status]),
}),
);
if (listingMode === ListingModes.table) {
const statusFilters = [...allDistinctFileStatuses].map(
status =>
new NestedFilter({
id: status,
label: this._translateService.instant(fileStatusTranslations[status]),
}),
);
filterGroups.push({
slug: 'statusFilters',
label: this._translateService.instant('filters.status'),
icon: 'red:status',
filters: statusFilters.sort((a, b) => StatusSorter[a.id] - StatusSorter[b.id]),
checker: keyChecker('status'),
});
filterGroups.push({
slug: 'statusFilters',
label: this._translateService.instant('filters.status'),
icon: 'red:status',
filters: statusFilters.sort((a, b) => StatusSorter[a.id] - StatusSorter[b.id]),
checker: keyChecker('status'),
});
}
const peopleFilters: NestedFilter[] = [];
if (allDistinctPeople.has(undefined) || allDistinctPeople.has(null)) {
@ -333,10 +348,14 @@ export class ConfigService {
});
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
private _unassignFn = (reloadDossiers: () => Promise<void>) => (file: File) => {
// TODO
console.log('unassign', file);
private _unassignFn = (reloadDossiers: () => Promise<void>) => async (file: File) => {
this._loadingService.start();
if (file.isUnderReview) {
await this._filesService.setReviewerFor([file.fileId], this._dossiersService.activeDossierId, null).toPromise();
} else if (file.isUnderApproval) {
await this._filesService.setUnderApprovalFor([file.fileId], this._dossiersService.activeDossierId, null).toPromise();
}
this._loadingService.loadWhile(reloadDossiers());
};
private _underReviewFn = (reloadDossiers: () => Promise<void>) => (file: File) => {

View File

@ -159,6 +159,10 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
this.calculateData();
});
this.addSubscription = this.listingMode$.subscribe(() => {
this._computeAllFilters();
});
// this.addSubscription = this._appStateService.fileChanged$.subscribe(() => {
// this.calculateData();
// });
@ -316,11 +320,12 @@ export class DossierOverviewScreenComponent extends ListingComponent<File> imple
const filterGroups = this._configService.filterGroups(
this.entitiesService.all,
this.listingMode,
this._fileAttributeConfigs,
this._needsWorkFilterTemplate,
() => this.checkedRequiredFilters,
() => this.checkedNotRequiredFilters,
);
this.filterService.addFilterGroups(filterGroups);
this.filterService.addFilterGroups(filterGroups, true);
}
}

View File

@ -65,7 +65,7 @@
<div *ngIf="canAssign" class="assign-actions-wrapper">
<iqser-circle-button
(action)="editingReviewer = true"
*ngIf="permissionsService.canAssignUser() && currentReviewer"
*ngIf="(permissionsService.canAssignUser() || permissionsService.canUnassignUser()) && !!currentReviewer"
[tooltip]="assignTooltip"
icon="iqser:edit"
tooltipPosition="below"

View File

@ -149,7 +149,12 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
get canAssign(): boolean {
return !this.editingReviewer && (this.permissionsService.canAssignUser() || this.permissionsService.canAssignToSelf());
return (
!this.editingReviewer &&
(this.permissionsService.canAssignUser() ||
this.permissionsService.canAssignToSelf() ||
this.permissionsService.canUnassignUser())
);
}
get displayData(): Blob {
@ -191,7 +196,10 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
singleUsersSelectOptions(dossier: Dossier): List {
return this.appStateService.activeFile?.isUnderApproval ? dossier.approverIds : dossier.memberIds;
const unassignUser = this.permissionsService.canUnassignUser() ? [undefined] : [];
return this.appStateService.activeFile?.isUnderApproval
? [...dossier.approverIds, ...unassignUser]
: [...dossier.memberIds, ...unassignUser];
}
canAssignReviewer(dossier: Dossier): boolean {
@ -492,7 +500,7 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
}
async assignReviewer(user: User | string) {
const reviewerId = typeof user === 'string' ? user : user.id;
const reviewerId = typeof user === 'string' ? user : user?.id;
const reviewerName = this.userService.getNameForId(reviewerId);
const { dossierId, fileId, filename } = this.fileData.file;

View File

@ -76,20 +76,22 @@ export class SearchScreenComponent extends ListingComponent<ListItem> implements
super(_injector);
this.searchService.skip = true;
this.filterService.addFilterGroup({
slug: 'dossiers',
label: this._translateService.instant('search-screen.filters.by-dossier'),
filterceptionPlaceholder: this._translateService.instant('search-screen.filters.search-placeholder'),
icon: 'red:folder',
filters: this._dossiersService.all.map(
dossier =>
new NestedFilter({
id: dossier.id,
label: dossier.dossierName,
}),
),
checker: keyChecker('dossierId'),
});
this.filterService.addFilterGroups([
{
slug: 'dossiers',
label: this._translateService.instant('search-screen.filters.by-dossier'),
filterceptionPlaceholder: this._translateService.instant('search-screen.filters.search-placeholder'),
icon: 'red:folder',
filters: this._dossiersService.all.map(
dossier =>
new NestedFilter({
id: dossier.id,
label: dossier.dossierName,
}),
),
checker: keyChecker('dossierId'),
},
]);
this.addSubscription = _activatedRoute.queryParamMap
.pipe(map(value => ({ query: value.get('query'), dossierId: value.get('dossierId') })))

View File

@ -269,7 +269,9 @@ export class FileActionsComponent extends AutoUnsubscribe implements OnInit, OnD
this.showStatusBar = this.file.isWorkable && this.isDossierOverviewList;
this.showAssignToSelf = this.permissionsService.canAssignToSelf(this.file) && this.isDossierOverview;
this.showAssign = this.permissionsService.canAssignUser(this.file) && this.isDossierOverview;
this.showAssign =
(this.permissionsService.canAssignUser(this.file) || this.permissionsService.canUnassignUser(this.file)) &&
this.isDossierOverview;
this.showOpenDocument = this.file.canBeOpened && this.isDossierOverviewWorkflow;

View File

@ -1,5 +1,5 @@
import { Component, ElementRef, Input, OnChanges, ViewChild } from '@angular/core';
import { Dictionary } from '@models/dictionary';
import { Dictionary } from '@red/domain';
@Component({
selector: 'redaction-annotation-icon',

View File

@ -1,6 +1,6 @@
<div class="flex-align-items-center space-between">
<div class="iqser-input-group w-250">
<mat-select [(ngModel)]="value">
<mat-select [(ngModel)]="value" [placeholder]="'initials-avatar.unassigned' | translate">
<mat-select-trigger>
<ng-container *ngTemplateOutlet="avatar; context: getContext(value)"></ng-container>
</mat-select-trigger>

View File

@ -2,15 +2,13 @@ import { Component, EventEmitter, Input, OnChanges, Output, ViewChild } from '@a
import { Debounce, IconButtonTypes, List } from '@iqser/common-ui';
import { Observable, of } from 'rxjs';
import { catchError, map, take, tap } from 'rxjs/operators';
import { Dossier } from '@red/domain';
import { Dictionary, Dossier, DossierTemplate } from '@red/domain';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { DictionaryService } from '@shared/services/dictionary.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { DossierTemplate } from '@models/file/dossier-template';
import { AppStateService } from '@state/app-state.service';
import { EditorComponent } from '@shared/components/editor/editor.component';
import { Dictionary } from '@models/dictionary';
import IModelDeltaDecoration = monaco.editor.IModelDeltaDecoration;
import FindMatch = monaco.editor.FindMatch;

View File

@ -1,10 +1,10 @@
import { Injectable, Injector } from '@angular/core';
import { Observable, throwError } from 'rxjs';
import { EntitiesService, List, QueryParam, RequiredParam, Toaster, Validate } from '@iqser/common-ui';
import { Colors, IDictionary, UpdateDictionary } from '@redaction/red-ui-http';
import { Colors, UpdateDictionary } from '@redaction/red-ui-http';
import { tap } from 'rxjs/operators';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { Dictionary } from '@models/dictionary';
import { Dictionary, IDictionary } from '@red/domain';
const MIN_WORD_LENGTH = 2;

View File

@ -1,6 +1,5 @@
import { EntitiesService, List, RequiredParam, Validate } from '@iqser/common-ui';
import { DossierTemplate } from '@models/file/dossier-template';
import { IDossierTemplate } from '@redaction/red-ui-http';
import { DossierTemplate, IDossierTemplate } from '@red/domain';
import { Injectable, Injector } from '@angular/core';
import { BehaviorSubject, forkJoin, Observable } from 'rxjs';
import { FileAttributesService } from './file-attributes.service';

View File

@ -61,7 +61,7 @@ export class NotificationsService extends GenericService<unknown> {
const fileId = notification.target.fileId;
const dossierId = notification.target.dossierId;
const dossier = this._dossiersService.find(dossierId);
const file = dossier.files.find(f => f.fileId === fileId);
const file = dossier?.files?.find(f => f.fileId === fileId);
return this._translateService.instant(translation, {
fileHref: file?.routerLink,

View File

@ -78,6 +78,10 @@ export class PermissionsService {
return false;
}
canUnassignUser(file = this._activeFile): boolean {
return (file.isUnderReview || file.isUnderApproval) && (this.isFileReviewer(file) || this.isApprover());
}
canSetUnderReview(file = this._activeFile): boolean {
return file?.isUnderApproval && this.isApprover();
}

View File

@ -6,8 +6,7 @@ import { forkJoin, Observable, of, Subject } from 'rxjs';
import { catchError, filter, first, map, tap } from 'rxjs/operators';
import { currentComponentRoute, FALLBACK_COLOR, hexToRgb } from '@utils/functions';
import { File } from '@models/file/file';
import { Dossier, IDossier } from '@red/domain';
import { DossierTemplate } from '@models/file/dossier-template';
import { Dictionary, Dossier, DossierTemplate, IDossier } from '@red/domain';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { UserPreferenceService } from '@services/user-preference.service';
import { FilesService } from '@services/entity-services/files.service';
@ -15,7 +14,6 @@ import { DictionaryService } from '@shared/services/dictionary.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { FileAttributesService } from '@services/entity-services/file-attributes.service';
import { ReanalysisService } from '@services/reanalysis.service';
import { Dictionary } from '@models/dictionary';
export interface AppState {
activeFileId?: string;

View File

@ -418,7 +418,7 @@
},
"table-col-names": {
"hint-redaction": "Hinweis / Redaktion",
"order-of-importance": "Reihenfolge der Wichtigkeit",
"rank": "Reihenfolge der Wichtigkeit",
"type": "Art"
},
"table-header": {

View File

@ -301,7 +301,7 @@
},
"assignment": {
"owner": "Successfully assigned {ownerName} to dossier: {dossierName}.",
"reviewer": "Successfully assigned {reviewerName} to file: {filename}."
"reviewer": "Successfully {reviewerName, select, undefined{unassigned user from} other{assigned {reviewerName} to file:}} {filename}."
},
"audit": "Audit",
"audit-screen": {
@ -488,7 +488,7 @@
},
"table-col-names": {
"hint-redaction": "Hint/Redaction",
"order-of-importance": "Order Of Importance",
"rank": "Rank",
"type": "Type"
},
"table-header": {
@ -1270,7 +1270,7 @@
"assign-approver": "You have been assigned as approver for <b><a href=\"{fileHref}\" target=\"_blank\">{fileName}</a></b> in the <b><a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a><b>!",
"assign-reviewer": "You have been assigned as reviewer for <b><a href=\"{fileHref}\" target=\"_blank\">{fileName}</a></b> in the <b><a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a><b>!",
"document-approved": " <b><a href=\"{fileHref}\" target=\"_blank\">{fileName}</a></b> has been approved!",
"dossier-deleted": "Dossier: <b{dossierName}</b> has been deleted!",
"dossier-deleted": "Dossier: <b>{dossierName}</b> has been deleted!",
"dossier-owner-deleted": "<b><a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a></b> owner removed!",
"dossier-owner-removed": "<b><a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a></b> owner removed!",
"dossier-owner-set": " <b><a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a></b> owner changed to <b>{user}</b>!",

@ -1 +1 @@
Subproject commit 9461df16f71186ea40b365622900b03d7f7bb387
Subproject commit defdc2af4e226ca8bb17df6c4d1cdd85130cfce5

View File

@ -6,3 +6,5 @@ export * from './lib/users';
export * from './lib/pages';
export * from './lib/audit';
export * from './lib/notifications';
export * from './lib/dossier-templates';
export * from './lib/dictionaries';

View File

@ -1,20 +1,8 @@
/**
* API Documentation for Redaction Gateway
* Description for redaction
*
* OpenAPI spec version: 1.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { List } from '../red-types';
/**
* Object containing a list of dictionary entries and colors of an entry type.
*/
import { List } from '@iqser/common-ui';
export interface IDictionary {
/**
* If true the ui will add a action to add values to dictionary

View File

@ -1,5 +1,5 @@
import { IDictionary } from '@redaction/red-ui-http';
import { IListable, List } from '@iqser/common-ui';
import { IDictionary } from './dictionary.interface';
export class Dictionary implements IDictionary, IListable {
readonly addToDictionaryAction: boolean;

View File

@ -0,0 +1,2 @@
export * from './dictionary.interface';
export * from './dictionary.model';

View File

@ -1,30 +1,19 @@
/**
* API Documentation for Redaction Gateway
* Description for redaction
*
* OpenAPI spec version: 1.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { List } from '../red-types';
import { DownloadFileType } from '@red/domain';
import { List } from '@iqser/common-ui';
import { DownloadFileType } from '../shared/types';
export interface IDossierTemplate {
/**
* The userId of the user who created this DossierTemplate. Set by the system.
*/
readonly createdBy?: string;
readonly createdBy: string;
/**
* The date when this dossierTemplate was created. Set by System on create.
*/
readonly dateAdded?: string;
readonly dateAdded: string;
/**
* The date when this dossierTemplate was last modified. Set by System on create.
*/
readonly dateModified?: string;
readonly dateModified: string;
/**
* The description of this dossierTemplate
*/
@ -32,11 +21,11 @@ export interface IDossierTemplate {
/**
* The Rule Set Id. Generated by the system on create.
*/
readonly dossierTemplateId?: string;
readonly dossierTemplateId: string;
/**
* Download File Types for this dossierTemplate's dossiers submission package.
*/
readonly downloadFileTypes?: List<DownloadFileType>;
readonly downloadFileTypes: List<DownloadFileType>;
/**
* The userId of the user who last modified this DossierTemplate. Set by the system.
*/
@ -44,7 +33,7 @@ export interface IDossierTemplate {
/**
* The name of this dossierTemplate. Must be set on create / update requests
*/
readonly name?: string;
readonly name: string;
/**
* Report File Types for this dossierTemplate's dossiers submission package.
*/

View File

@ -1,16 +1,16 @@
import { IDossierTemplate } from '@redaction/red-ui-http';
import { IListable, List } from '@iqser/common-ui';
import { DownloadFileType } from '@red/domain';
import { IDossierTemplate } from './dossier-template.interface';
import { DownloadFileType } from '../shared/types';
export class DossierTemplate implements IDossierTemplate, IListable {
readonly createdBy?: string;
readonly dateAdded?: string;
readonly dateModified?: string;
readonly createdBy: string;
readonly dateAdded: string;
readonly dateModified: string;
readonly description?: string;
readonly dossierTemplateId?: string;
readonly downloadFileTypes?: List<DownloadFileType>;
readonly dossierTemplateId: string;
readonly downloadFileTypes: List<DownloadFileType>;
readonly modifiedBy?: string;
readonly name?: string;
readonly name: string;
readonly reportTemplateIds?: List;
readonly validFrom?: string;
readonly validTo?: string;

View File

@ -0,0 +1,2 @@
export * from './dossier-template.interface';
export * from './dossier-template.model';

View File

@ -1,9 +1,9 @@
import { File } from '@models/file/file';
import { IDictionary } from '@redaction/red-ui-http';
import { IListable, List } from '@iqser/common-ui';
import { IDossier } from './dossier.interface';
import { DossierStatus } from './types';
import { DownloadFileType } from '../shared/types';
import { IDictionary } from '../dictionaries';
export class Dossier implements IDossier, IListable {
readonly dossierId: string;

View File

@ -1,14 +1,3 @@
/**
* API Documentation for Redaction Gateway
* Description for redaction
*
* OpenAPI spec version: 1.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { IPageRange } from './page-range';
import { List } from '@iqser/common-ui';

View File

@ -1,15 +1,3 @@
/**
* API Documentation for Redaction Gateway
* Description for redaction
*
* OpenAPI spec version: 1.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
export interface IPageRange {
startPage?: number;
endPage?: number;

View File

@ -1,15 +1,3 @@
/**
* API Documentation for Redaction Gateway
* Description for redaction
*
* OpenAPI spec version: 1.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
export interface IViewedPage {
fileId?: string;
page?: number;

View File

@ -1,15 +1,3 @@
/**
* API Documentation for Redaction Gateway
* Description for redaction
*
* OpenAPI spec version: 1.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
export interface IViewedPagesRequest {
page?: number;
}

View File

@ -1,14 +1,3 @@
/**
* API Documentation for Redaction Gateway
* Description for redaction
*
* OpenAPI spec version: 1.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { IMatchedSection } from './matched-section';
import { List } from '@iqser/common-ui';

View File

@ -1,14 +1,3 @@
/**
* API Documentation for Redaction Gateway
* Description for redaction
*
* OpenAPI spec version: 1.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { List } from '@iqser/common-ui';
export interface IMatchedSection {

View File

@ -1,14 +1,3 @@
/**
* API Documentation for Redaction Gateway
* Description for redaction
*
* OpenAPI spec version: 1.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { List } from '@iqser/common-ui';
export interface ISearchRequest {

View File

@ -1,14 +1,3 @@
/**
* API Documentation for Redaction Gateway
* Description for redaction
*
* OpenAPI spec version: 1.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { IMatchedDocument } from './matched-document';
import { List } from '@iqser/common-ui';

View File

@ -1,14 +1,3 @@
/**
* API Documentation for Redaction Gateway
* Description for redaction
*
* OpenAPI spec version: 1.0
*
*
* NOTE: This class is auto generated by the swagger code generator program.
* https://github.com/swagger-api/swagger-codegen.git
* Do not edit the class manually.
*/
import { IMyProfileUpdateRequest } from './my-profile-update.request';
import { List } from '@iqser/common-ui';

View File

@ -7,10 +7,8 @@ export * from './colors';
export * from './comment';
export * from './commentResponse';
export * from './createUserRequest';
export * from './dictionary';
export * from './digitalSignature';
export * from './digitalSignatureViewModel';
export * from './dossierTemplate';
export * from './downloadResponse';
export * from './downloadStatus';
export * from './downloadStatusResponse';

View File

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

Binary file not shown.