Merge branch 'master' into RED-2830

This commit is contained in:
Adina Țeudan 2021-12-07 16:01:43 +02:00
commit a660f3e3af
38 changed files with 176 additions and 209 deletions

View File

@ -7,7 +7,8 @@ import { NotificationsService } from '@services/notifications.service';
import { Notification } from '@red/domain';
import { distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators';
import { BehaviorSubject, Observable, timer } from 'rxjs';
import { AutoUnsubscribe, CHANGED_CHECK_INTERVAL, List, shareLast } from '@iqser/common-ui';
import { AutoUnsubscribe, List, shareLast } from '@iqser/common-ui';
import { CHANGED_CHECK_INTERVAL } from '@utils/constants';
const INCLUDE_SEEN = false;

View File

@ -18,8 +18,9 @@
<div class="statement" translate="notifications-screen.options-title"></div>
<div class="group" *ngFor="let key of notificationGroupsKeys; let i = index">
<div class="group-title" [translate]="translations[key]"></div>
<!-- <div class="group" -->
<ng-container *ngFor="let key of notificationGroupsKeys; let i = index">
<!-- <div class="group-title" [translate]="translations[key]"></div>-->
<div class="iqser-input-group">
<mat-checkbox
*ngFor="let preference of notificationGroupsValues[i]"
@ -30,7 +31,8 @@
{{ translations[preference] | translate }}
</mat-checkbox>
</div>
</div>
<!-- </div>-->
</ng-container>
</div>
</div>
</div>

View File

@ -175,6 +175,7 @@ const routes: Routes = [
canActivate: [CompositeRouteGuard],
data: {
routeGuards: [AuthGuard, RedRoleGuard, AppStateGuard],
requiredRoles: ['RED_MANAGER'],
},
},
];

View File

@ -15,9 +15,10 @@
/>
</div>
<div class="inline-input-group flex-align-items-center">
<mat-slide-toggle color="primary" formControlName="forgotPasswordFunctionEnabled"></mat-slide-toggle>
<span class="ml-8" translate="general-config-screen.general.form.forgot-password"></span>
<div class="iqser-input-group">
<mat-slide-toggle color="primary" formControlName="forgotPasswordFunctionEnabled"
>{{ 'general-config-screen.general.form.forgot-password' | translate }}
</mat-slide-toggle>
</div>
</div>
</div>

View File

@ -21,10 +21,10 @@
<div class="content-inner">
<div class="content-container">
<div class="dialog mb-8">
<div class="dialog mb-0">
<redaction-general-config-form></redaction-general-config-form>
</div>
<div class="dialog mt-16">
<div class="dialog mt-24">
<redaction-smtp-form></redaction-smtp-form>
</div>
</div>

View File

@ -10,20 +10,6 @@
overflow: auto;
}
.w-100 {
min-width: 100px;
width: 100px;
}
.inline-input-group {
background-color: rgba(variables.$grey-6, 0.8);
width: 100%;
height: 38px;
border-radius: 4px;
padding: 1px 11px;
margin-top: 20px;
}
.dialog {
width: 100%;
min-height: unset;

View File

@ -1,5 +1,5 @@
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, QueryList, ViewChildren } from '@angular/core';
import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { Component, ElementRef, Input, OnInit, QueryList, ViewChildren } from '@angular/core';
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { Dossier, DossierAttributeConfigType, DossierAttributeConfigTypes, DossierAttributeWithValue } from '@red/domain';
import { PermissionsService } from '@services/permissions.service';
import { CircleButtonTypes, IconButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
@ -19,7 +19,6 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa
readonly dossierAttributeConfigTypes = DossierAttributeConfigTypes;
@Input() dossier: Dossier;
@Output() readonly updateDossier = new EventEmitter();
customAttributes: DossierAttributeWithValue[] = [];
imageAttributes: DossierAttributeWithValue[] = [];
attributes: DossierAttributeWithValue[] = [];
@ -64,7 +63,7 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa
this._loadingService.stop();
}
async save() {
async save(): EditDossierSaveResult {
const dossierAttributeList = this.attributes.map(attr => ({
dossierAttributeConfigId: attr.id,
value: this.currentAttrValue(attr),
@ -72,9 +71,10 @@ export class EditDossierAttributesComponent implements EditDossierSectionInterfa
try {
await this._dossierAttributesService.setAttributes(this.dossier, dossierAttributeList).toPromise();
await this._loadAttributes();
this.updateDossier.emit();
} catch (e) {
return { success: true };
} catch (error) {
this._toaster.error(_('edit-dossier-dialog.attributes.error.generic'));
return { success: false };
}
}

View File

@ -1,5 +1,5 @@
import { Component, EventEmitter, forwardRef, Injector, Input, OnInit, Output } from '@angular/core';
import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { Component, forwardRef, Injector, Input, OnInit } from '@angular/core';
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { Dossier, IFile } from '@red/domain';
import {
CircleButtonTypes,
@ -16,7 +16,7 @@ import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import * as moment from 'moment';
import { ConfigService } from '@services/config.service';
import { getLeftDateTime } from '@utils/functions';
import { Observable } from 'rxjs';
import { Observable, of } from 'rxjs';
import { distinctUntilChanged, map } from 'rxjs/operators';
import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
import { FilesService } from '@services/entity-services/files.service';
@ -38,7 +38,6 @@ interface FileListItem extends IFile, IListable {
})
export class EditDossierDeletedDocumentsComponent extends ListingComponent<FileListItem> implements EditDossierSectionInterface, OnInit {
@Input() dossier: Dossier;
@Output() readonly updateDossier = new EventEmitter();
readonly changed = false;
readonly canRestoreSelected$ = this._canRestoreSelected$;
disabled: boolean;
@ -101,7 +100,9 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent<FileL
revert() {}
save() {}
save(): EditDossierSaveResult {
return of({ success: true }).toPromise();
}
restore(files = this.listingService.selected) {
this._loadingService.loadWhile(this._restore(files));
@ -114,14 +115,12 @@ export class EditDossierDeletedDocumentsComponent extends ListingComponent<FileL
await this._fileManagementService.restore(fileIds, this.dossier.id).toPromise();
this._removeFromList(fileIds);
await this._filesService.loadAll(files[0].dossierId).toPromise();
this.updateDossier.emit();
}
private async _hardDelete(files: FileListItem[]) {
const fileIds = files.map(f => f.fileId);
await this._fileManagementService.hardDelete(this.dossier.id, fileIds).toPromise();
this._removeFromList(fileIds);
this.updateDossier.emit();
}
private _removeFromList(ids: string[]): void {

View File

@ -1,11 +1,12 @@
import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { Component, Input, OnInit, ViewChild } from '@angular/core';
import { Dossier, IDictionary } from '@red/domain';
import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { EditDossierSaveResult, 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 { CircleButtonTypes, LoadingService } from '@iqser/common-ui';
import { CircleButtonTypes, LoadingService, Toaster } from '@iqser/common-ui';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
@Component({
selector: 'redaction-edit-dossier-dictionary',
@ -14,7 +15,6 @@ import { DossiersService } from '@services/entity-services/dossiers.service';
})
export class EditDossierDictionaryComponent implements EditDossierSectionInterface, OnInit {
@Input() dossier: Dossier;
@Output() readonly updateDossier = new EventEmitter();
canEdit = false;
readonly circleButtonTypes = CircleButtonTypes;
dossierDictionary: IDictionary;
@ -26,6 +26,7 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
private readonly _dictionaryService: DictionaryService,
private readonly _permissionsService: PermissionsService,
private readonly _loadingService: LoadingService,
private readonly _toaster: Toaster,
) {}
get changed() {
@ -44,27 +45,38 @@ export class EditDossierDictionaryComponent implements EditDossierSectionInterfa
}
async updateDisplayName(label: string) {
const dictionary: IDictionary = { ...this.dossierDictionary, label };
await this._dictionaryService
.updateDictionary(dictionary, this.dossier.dossierTemplateId, 'dossier_redaction', this.dossier.id)
.toPromise();
await this._updateDossierDictionary();
this.updateDossier.emit();
try {
this._loadingService.start();
// TODO: Setting the type manually shouldn't be necessary, but for now it fails with status code 500...
const dictionary: IDictionary = { ...this.dossierDictionary, type: 'dossier_redaction', label };
await this._dictionaryService
.updateDictionary(dictionary, this.dossier.dossierTemplateId, 'dossier_redaction', this.dossier.id)
.toPromise();
await this._updateDossierDictionary();
this._toaster.success(_('edit-dossier-dialog.dictionary.display-name.success'));
} catch (error) {
this._toaster.error(_('edit-dossier-dialog.dictionary.display-name.error'));
}
this._loadingService.stop();
}
async save() {
await this._dictionaryService
.saveEntries(
this._dictionaryManager.editor.currentEntries,
this._dictionaryManager.initialEntries,
this.dossier.dossierTemplateId,
'dossier_redaction',
this.dossier.id,
false,
)
.toPromise();
await this._updateDossierDictionary();
this.updateDossier.emit();
async save(): EditDossierSaveResult {
try {
await this._dictionaryService
.saveEntries(
this._dictionaryManager.editor.currentEntries,
this._dictionaryManager.initialEntries,
this.dossier.dossierTemplateId,
'dossier_redaction',
this.dossier.id,
false,
)
.toPromise();
await this._updateDossierDictionary();
return { success: true };
} catch (error) {
return { success: false };
}
}
revert() {

View File

@ -1,7 +1,7 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { Dossier, DownloadFileType, IReportTemplate } from '@red/domain';
import { FormBuilder, FormGroup } from '@angular/forms';
import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { downloadTypesTranslations } from '../../../../../translations/download-types-translations';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { ReportTemplateService } from '@services/report-template.service';
@ -20,7 +20,6 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS
availableReportTypes: IReportTemplate[] = [];
@Input() dossier: Dossier;
@Output() readonly updateDossier = new EventEmitter();
constructor(
private readonly _dossiersService: DossiersService,
@ -70,6 +69,27 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS
this.dossierForm = this._getForm();
}
async save(): EditDossierSaveResult {
const dossier = {
...this.dossier,
downloadFileTypes: this.dossierForm.get('downloadFileTypes').value,
reportTemplateIds: this.dossierForm.get('reportTemplateIds').value,
};
try {
await this._dossiersService.createOrUpdate(dossier).toPromise();
return { success: true };
} catch (error) {
return { success: false };
}
}
revert() {
this.dossierForm.reset({
downloadFileTypes: this.dossier.downloadFileTypes,
reportTemplateIds: this.dossier.reportTemplateIds,
});
}
private _getForm(): FormGroup {
return this._formBuilder.group(
{
@ -84,21 +104,4 @@ export class EditDossierDownloadPackageComponent implements OnInit, EditDossierS
},
);
}
async save() {
const dossier = {
...this.dossier,
downloadFileTypes: this.dossierForm.get('downloadFileTypes').value,
reportTemplateIds: this.dossierForm.get('reportTemplateIds').value,
};
await this._dossiersService.createOrUpdate(dossier).toPromise();
this.updateDossier.emit();
}
revert() {
this.dossierForm.reset({
downloadFileTypes: this.dossier.downloadFileTypes,
reportTemplateIds: this.dossier.reportTemplateIds,
});
}
}

View File

@ -21,37 +21,28 @@
</div>
<redaction-edit-dossier-general-info
(updateDossier)="updatedDossier()"
*ngIf="activeNav === 'dossierInfo'"
[dossier]="dossier"
></redaction-edit-dossier-general-info>
<redaction-edit-dossier-download-package
(updateDossier)="updatedDossier()"
*ngIf="activeNav === 'downloadPackage'"
[dossier]="dossier"
></redaction-edit-dossier-download-package>
<redaction-edit-dossier-dictionary
(updateDossier)="updatedDossier()"
*ngIf="activeNav === 'dossierDictionary'"
[dossier]="dossier"
></redaction-edit-dossier-dictionary>
<redaction-team-members-manager
(updateDossier)="updatedDossier()"
*ngIf="activeNav === 'members'"
[dossier]="dossier"
></redaction-team-members-manager>
<redaction-edit-dossier-team *ngIf="activeNav === 'members'" [dossier]="dossier"></redaction-edit-dossier-team>
<redaction-edit-dossier-attributes
(updateDossier)="updatedDossier()"
*ngIf="activeNav === 'dossierAttributes'"
[dossier]="dossier"
></redaction-edit-dossier-attributes>
<redaction-edit-dossier-deleted-documents
(updateDossier)="updatedDossier()"
*ngIf="activeNav === 'deletedDocuments'"
[dossier]="dossier"
></redaction-edit-dossier-deleted-documents>

View File

@ -11,9 +11,9 @@ import { EditDossierAttributesComponent } from './attributes/edit-dossier-attrib
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { EditDossierDeletedDocumentsComponent } from './deleted-documents/edit-dossier-deleted-documents.component';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { TeamMembersManagerComponent } from '../../components/team-members-manager/team-members-manager.component';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';
import { EditDossierTeamComponent } from './edit-dossier-team/edit-dossier-team.component';
type Section = 'dossierInfo' | 'downloadPackage' | 'dossierDictionary' | 'members' | 'dossierAttributes' | 'deletedDocuments';
@ -30,7 +30,7 @@ export class EditDossierDialogComponent {
@ViewChild(EditDossierGeneralInfoComponent) generalInfoComponent: EditDossierGeneralInfoComponent;
@ViewChild(EditDossierDownloadPackageComponent) downloadPackageComponent: EditDossierDownloadPackageComponent;
@ViewChild(EditDossierDictionaryComponent) dictionaryComponent: EditDossierDictionaryComponent;
@ViewChild(TeamMembersManagerComponent) membersComponent: TeamMembersManagerComponent;
@ViewChild(EditDossierTeamComponent) membersComponent: EditDossierTeamComponent;
@ViewChild(EditDossierAttributesComponent) attributesComponent: EditDossierAttributesComponent;
@ViewChild(EditDossierDeletedDocumentsComponent) deletedDocumentsComponent: EditDossierDeletedDocumentsComponent;
private _dossierName: string;
@ -44,7 +44,6 @@ export class EditDossierDialogComponent {
@Inject(MAT_DIALOG_DATA)
private readonly _data: {
dossierId: string;
afterSave: Function;
section?: Section;
},
) {
@ -112,23 +111,20 @@ export class EditDossierDialogComponent {
return !['deletedDocuments'].includes(this.activeNav);
}
updatedDossier() {
this._toaster.success(_('edit-dossier-dialog.change-successful'), { params: { dossierName: this._dossierName } });
this.afterSave();
}
afterSave() {
if (this._data?.afterSave) {
this._data.afterSave();
}
this._toaster.success(_('edit-dossier-dialog.change-successful'), { params: { dossierName: this._dossierName } });
}
async save(closeAfterSave: boolean = false) {
this._loadingService.start();
await this.activeComponent.save();
const result = await this.activeComponent.save();
this._loadingService.stop();
if (closeAfterSave) {
if (result.success) {
this.afterSave();
}
if (result.success && closeAfterSave) {
this._dialogRef.close();
}
}

View File

@ -1,6 +1,8 @@
export type EditDossierSaveResult = Promise<{ success: boolean }>;
export interface EditDossierSectionInterface {
changed: boolean;
disabled: boolean;
save: Function;
save: (...args: any) => EditDossierSaveResult;
revert: Function;
}

View File

@ -1,5 +1,5 @@
@use 'common-mixins';
@use 'variables';
@use 'libs/common-ui/src/assets/styles/common-mixins';
@use 'apps/red-ui/src/assets/styles/variables';
.search-container {
margin-top: 16px;

View File

@ -1,24 +1,23 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core';
import { ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit } from '@angular/core';
import { UserService } from '@services/user.service';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { Dossier, IDossier, IDossierRequest } from '@red/domain';
import { Dossier, IDossierRequest } from '@red/domain';
import { AutoUnsubscribe } from '@iqser/common-ui';
import { EditDossierSectionInterface } from '../../dialogs/edit-dossier-dialog/edit-dossier-section.interface';
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { BehaviorSubject } from 'rxjs';
@Component({
selector: 'redaction-team-members-manager',
templateUrl: './team-members-manager.component.html',
styleUrls: ['./team-members-manager.component.scss'],
selector: 'redaction-edit-dossier-team',
templateUrl: './edit-dossier-team.component.html',
styleUrls: ['./edit-dossier-team.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class TeamMembersManagerComponent extends AutoUnsubscribe implements EditDossierSectionInterface, OnInit, OnDestroy {
export class EditDossierTeamComponent extends AutoUnsubscribe implements EditDossierSectionInterface, OnInit, OnDestroy {
form: FormGroup;
searchQuery = '';
@Input() dossier: Dossier;
@Output() readonly updateDossier = new EventEmitter<IDossier>();
readonly ownersSelectOptions = this.userService.managerUsers.map(m => m.id);
membersSelectOptions: string[] = [];
@ -69,7 +68,7 @@ export class TeamMembersManagerComponent extends AutoUnsubscribe implements Edit
return userId === this.selectedOwnerId;
}
async save() {
async save(): EditDossierSaveResult {
const dossier = {
...this.dossier,
memberIds: this.selectedMembersList,
@ -77,9 +76,11 @@ export class TeamMembersManagerComponent extends AutoUnsubscribe implements Edit
ownerId: this.selectedOwnerId,
} as IDossierRequest;
const result = await this._dossiersService.createOrUpdate(dossier).toPromise();
if (result) {
this.updateDossier.emit();
try {
await this._dossiersService.createOrUpdate(dossier).toPromise();
return { success: true };
} catch (error) {
return { success: false };
}
}

View File

@ -1,8 +1,8 @@
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
import { Component, Input, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import * as moment from 'moment';
import { Dossier, IDossierRequest, IDossierTemplate } from '@red/domain';
import { EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { EditDossierSaveResult, EditDossierSectionInterface } from '../edit-dossier-section.interface';
import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
import { PermissionsService } from '@services/permissions.service';
import { Router } from '@angular/router';
@ -22,13 +22,12 @@ import { DossierStatsService } from '@services/entity-services/dossier-stats.ser
export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSectionInterface {
readonly iconButtonTypes = IconButtonTypes;
@Input() dossier: Dossier;
dossierForm: FormGroup;
hasDueDate: boolean;
dossierTemplates: IDossierTemplate[];
@Input() dossier: Dossier;
@Output() readonly updateDossier = new EventEmitter();
constructor(
readonly permissionsService: PermissionsService,
private readonly _dossierTemplatesService: DossierTemplatesService,
@ -83,7 +82,7 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
});
}
async save() {
async save(): EditDossierSaveResult {
const dossier = {
...this.dossier,
dossierName: this.dossierForm.get('dossierName').value,
@ -95,8 +94,10 @@ export class EditDossierGeneralInfoComponent implements OnInit, EditDossierSecti
} as IDossierRequest;
try {
await this._dossiersService.createOrUpdate(dossier).toPromise();
this.updateDossier.emit();
} catch (e) {}
return { success: true };
} catch (error) {
return { success: false };
}
}
deleteDossier() {

View File

@ -19,7 +19,6 @@ import { EditDossierDialogComponent } from './dialogs/edit-dossier-dialog/edit-d
import { EditDossierGeneralInfoComponent } from './dialogs/edit-dossier-dialog/general-info/edit-dossier-general-info.component';
import { EditDossierDownloadPackageComponent } from './dialogs/edit-dossier-dialog/download-package/edit-dossier-download-package.component';
import { EditDossierDictionaryComponent } from './dialogs/edit-dossier-dialog/dictionary/edit-dossier-dictionary.component';
import { TeamMembersManagerComponent } from './components/team-members-manager/team-members-manager.component';
import { ChangeLegalBasisDialogComponent } from './dialogs/change-legal-basis-dialog/change-legal-basis-dialog.component';
import { RecategorizeImageDialogComponent } from './dialogs/recategorize-image-dialog/recategorize-image-dialog.component';
import { EditDossierAttributesComponent } from './dialogs/edit-dossier-dialog/attributes/edit-dossier-attributes.component';
@ -31,6 +30,7 @@ import { ResizeAnnotationDialogComponent } from './dialogs/resize-annotation-dia
import { BreadcrumbsService } from '@services/breadcrumbs.service';
import { of } from 'rxjs';
import { TranslateService } from '@ngx-translate/core';
import { EditDossierTeamComponent } from './dialogs/edit-dossier-dialog/edit-dossier-team/edit-dossier-team.component';
const screens = [SearchScreenComponent];
@ -52,7 +52,7 @@ const components = [
EditDossierDownloadPackageComponent,
EditDossierDictionaryComponent,
EditDossierAttributesComponent,
TeamMembersManagerComponent,
EditDossierTeamComponent,
EditDossierDeletedDocumentsComponent,
...screens,

View File

@ -5,7 +5,7 @@
(action)="setListingMode(listingModes.table)"
[attr.aria-expanded]="mode === listingModes.table"
[tooltip]="'view-mode.list' | translate"
[type]="circleButtonTypes.dossierView"
[greySelected]="true"
icon="iqser:list"
></iqser-circle-button>
@ -13,7 +13,7 @@
(action)="setListingMode(listingModes.workflow)"
[attr.aria-expanded]="mode === listingModes.workflow"
[tooltip]="'view-mode.workflow' | translate"
[type]="circleButtonTypes.dossierView"
[greySelected]="true"
icon="iqser:lanes"
></iqser-circle-button>
</div>

View File

@ -20,7 +20,6 @@ import { Observable, timer } from 'rxjs';
import { filter, switchMap, tap } from 'rxjs/operators';
import { convertFiles, Files, handleFileDrop } from '@utils/index';
import {
CHANGED_CHECK_INTERVAL,
CircleButtonTypes,
DefaultListingServices,
ListingComponent,
@ -46,6 +45,7 @@ import { LongPressEvent } from '@shared/directives/long-press.directive';
import { UserPreferenceService } from '@services/user-preference.service';
import { FilesMapService } from '@services/entity-services/files-map.service';
import { FilesService } from '@services/entity-services/files.service';
import { CHANGED_CHECK_INTERVAL } from '@utils/constants';
@Component({
templateUrl: './dossier-overview-screen.component.html',

View File

@ -1,4 +1,4 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
import { PermissionsService } from '@services/permissions.service';
import { CircleButtonTypes, List, StatusBarConfig } from '@iqser/common-ui';
import { UserService } from '@services/user.service';
@ -28,8 +28,6 @@ export class DossiersListingActionsComponent implements OnChanges {
@Input() dossier: Dossier;
@Input() stats: DossierStats;
@Output() readonly actionPerformed = new EventEmitter<Dossier | undefined>();
constructor(
private readonly _reanalysisService: ReanalysisService,
private readonly _userService: UserService,
@ -57,10 +55,7 @@ export class DossiersListingActionsComponent implements OnChanges {
}
openEditDossierDialog($event: MouseEvent, dossierId: string): void {
this._dialogService.openDialog('editDossier', $event, {
dossierId,
afterSave: () => this.actionPerformed.emit(),
});
this._dialogService.openDialog('editDossier', $event, { dossierId });
}
async reanalyseDossier($event: MouseEvent, id: string): Promise<void> {

View File

@ -12,10 +12,6 @@
</div>
<div class="cell status-container">
<redaction-dossiers-listing-actions
(actionPerformed)="calculateData.emit()"
[dossier]="dossier"
[stats]="stats"
></redaction-dossiers-listing-actions>
<redaction-dossiers-listing-actions [dossier]="dossier" [stats]="stats"></redaction-dossiers-listing-actions>
</div>
</ng-container>

View File

@ -1,10 +1,8 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnChanges, Output } from '@angular/core';
import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core';
import { Dossier, DossierStats } from '@red/domain';
import { DossierStatsService } from '@services/entity-services/dossier-stats.service';
import { BehaviorSubject, merge, Observable, timer } from 'rxjs';
import { filter, switchMap } from 'rxjs/operators';
import { CHANGED_CHECK_INTERVAL } from '@iqser/common-ui';
import { FilesService } from '@services/entity-services/files.service';
import { BehaviorSubject, Observable } from 'rxjs';
import { switchMap } from 'rxjs/operators';
@Component({
selector: 'redaction-table-item [dossier]',
@ -14,29 +12,17 @@ import { FilesService } from '@services/entity-services/files.service';
})
export class TableItemComponent implements OnChanges {
@Input() dossier!: Dossier;
@Output() readonly calculateData = new EventEmitter();
readonly stats$: Observable<DossierStats>;
private readonly _ngOnChanges$ = new BehaviorSubject<string>(undefined);
constructor(readonly dossierStatsService: DossierStatsService, readonly filesService: FilesService) {
const hasChanges$ = this._hasChanges$;
this.stats$ = merge(this._ngOnChanges$, hasChanges$).pipe(
filter(() => !!this.dossier),
switchMap(() => this.dossierStatsService.watch$(this.dossier.dossierId)),
);
}
private get _hasChanges$() {
return timer(CHANGED_CHECK_INTERVAL, CHANGED_CHECK_INTERVAL).pipe(
filter(() => !!this.dossier),
switchMap(() => this.filesService.hasChanges$(this.dossier.dossierId)),
filter(changed => changed),
switchMap(() => this.dossierStatsService.getFor([this.dossier.dossierId])),
);
constructor(readonly dossierStatsService: DossierStatsService) {
this.stats$ = this._ngOnChanges$.pipe(switchMap(dossierId => this.dossierStatsService.watch$(dossierId)));
}
ngOnChanges() {
this._ngOnChanges$.next(this.dossier.dossierId);
if (this.dossier) {
this._ngOnChanges$.next(this.dossier.dossierId);
}
}
}

View File

@ -29,5 +29,5 @@
</ng-template>
<ng-template #tableItemTemplate let-dossier="entity">
<redaction-table-item (calculateData)="computeAllFilters()" [dossier]="dossier"></redaction-table-item>
<redaction-table-item [dossier]="dossier"></redaction-table-item>
</ng-template>

View File

@ -6,21 +6,14 @@ import { TranslateChartService } from '@services/translate-chart.service';
import { timer } from 'rxjs';
import { Router } from '@angular/router';
import { DossiersDialogService } from '../../../services/dossiers-dialog.service';
import {
CHANGED_CHECK_INTERVAL,
DefaultListingServicesTmp,
EntitiesService,
ListingComponent,
OnAttach,
OnDetach,
TableComponent,
} from '@iqser/common-ui';
import { DefaultListingServicesTmp, EntitiesService, ListingComponent, OnAttach, OnDetach, TableComponent } from '@iqser/common-ui';
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
import { ConfigService } from '../config.service';
import { DossiersService } from '@services/entity-services/dossiers.service';
import { FilesService } from '@services/entity-services/files.service';
import { DossierTemplatesService } from '@services/entity-services/dossier-templates.service';
import { switchMap, tap } from 'rxjs/operators';
import { CHANGED_CHECK_INTERVAL } from '@utils/constants';
@Component({
templateUrl: './dossiers-listing-screen.component.html',
@ -64,14 +57,11 @@ export class DossiersListingScreenComponent extends ListingComponent<Dossier> im
}
ngOnInit(): void {
this.computeAllFilters();
this.addSubscription = timer(CHANGED_CHECK_INTERVAL, CHANGED_CHECK_INTERVAL)
.pipe(
switchMap(() => this._dossiersService.loadAllIfChanged()),
tap(() => this.computeAllFilters()),
)
.pipe(switchMap(() => this._dossiersService.loadAllIfChanged()))
.subscribe();
this.addSubscription = this._dossiersService.all$.pipe(tap(() => this._computeAllFilters())).subscribe();
}
ngOnAttach(): void {
@ -95,7 +85,7 @@ export class DossiersListingScreenComponent extends ListingComponent<Dossier> im
});
}
computeAllFilters() {
private _computeAllFilters() {
const filterGroups = this._configService.filterGroups(this.entitiesService.all, this._needsWorkFilterTemplate);
this.filterService.addFilterGroups(filterGroups);
}

View File

@ -1,5 +1,5 @@
import { Component, Input, OnChanges, OnInit } from '@angular/core';
import { Color } from '@utils/types';
import { Color } from '@red/domain';
import { FilterService, INestedFilter } from '@iqser/common-ui';
import { Observable, of } from 'rxjs';
import { map } from 'rxjs/operators';

View File

@ -90,13 +90,15 @@ export class DatePipe extends BaseDatePipe implements PipeTransform {
return this._translateService.instant('yesterday');
}
const isShortMonthFormat = day < thisDay - 1 && (year === thisYear || month >= thisMonth - 3);
const isShortMonthFormat =
year === thisYear &&
((month === thisMonth && day !== thisDay && day !== thisDay - 1) || (month !== thisMonth && month >= thisMonth - 2));
if (isShortMonthFormat) {
const translatedMonth = this._translateService.instant(MONTH_NAMES[month]);
return `${day} ${translatedMonth}`;
}
const isShortMonthYearFormat = year === thisYear - 1 && month < thisMonth - 3;
const isShortMonthYearFormat = (year === thisYear && month <= thisMonth - 3) || year === thisYear - 1;
if (isShortMonthYearFormat) {
const translatedMonth = this._translateService.instant(MONTH_NAMES[month]);
return `${translatedMonth} ${year}`;

View File

@ -30,9 +30,15 @@ export class PermissionsService {
return file.assignee === this._userService.currentUser.id;
}
// https://jira.iqser.com/browse/RED-2787
canDeleteFile(file: File): boolean {
const dossier = this._getDossier(file);
return (this.isOwner(dossier) && !file.isApproved) || file.isNew;
return (
file.isNew ||
(file.isUnderReview && !file.assignee && this.isDossierMember(dossier)) ||
(file.isUnderApproval && !file.assignee && this.isApprover(dossier)) ||
(file.assignee && !file.isApproved && (this.isFileAssignee(file) || this.isOwner(dossier)))
);
}
canAssignToSelf(file: File, dossier = this._getDossier(file)): boolean {

View File

@ -5,7 +5,6 @@ export const notificationsTranslations: { [key in NotificationType]: string } =
[NotificationTypes.ASSIGN_APPROVER]: _('notification.assign-approver'),
[NotificationTypes.ASSIGN_REVIEWER]: _('notification.assign-reviewer'),
[NotificationTypes.DOCUMENT_APPROVED]: _('notification.document-approved'),
[NotificationTypes.DOSSIER_OWNER_DELETED]: _('notification.dossier-owner-deleted'),
[NotificationTypes.DOSSIER_OWNER_REMOVED]: _('notification.dossier-owner-removed'),
[NotificationTypes.DOSSIER_OWNER_SET]: _('notification.dossier-owner-set'),
[NotificationTypes.UNASSIGNED_FROM_FILE]: _('notification.unassigned-from-file'),

View File

@ -0,0 +1 @@
export const CHANGED_CHECK_INTERVAL = 3000;

View File

@ -1,3 +0,0 @@
import { DossierStatus, FileStatus } from '@red/domain';
export type Color = FileStatus | DossierStatus | string;

View File

@ -768,7 +768,7 @@
},
"dictionaries": "{length} {length, plural, one{dictionary} other{dictionaries}}",
"error": {
"conflict": "Cannot delete this DossierTemplate! At least on Dossier uses this template!",
"conflict": "Cannot delete this DossierTemplate! At least one Dossier uses this template!",
"generic": "Cannot delete this DossierTemplate!"
},
"no-data": {
@ -1287,7 +1287,6 @@
"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-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>!",
"no-data": "You currently have no notifications",
@ -1311,7 +1310,7 @@
"own": "Dossiers you own",
"reviewer": "Dossiers you are reviewer on"
},
"options-title": "Choose on which category you want to be notified",
"options-title": "Choose on which action you want to be notified",
"options": {
"document-is-sent-for-approval": "Document is sent for approval",
"document-status-changes": "Document status changes",

View File

@ -1,16 +1,15 @@
export const NotificationTypes = {
ASSIGN_REVIEWER: 'ASSIGN_REVIEWER',
ASSIGN_APPROVER: 'ASSIGN_APPROVER',
UNASSIGNED_FROM_FILE: 'UNASSIGNED_FROM_FILE',
DOCUMENT_APPROVED: 'DOCUMENT_APPROVED',
DOSSIER_OWNER_SET: 'DOSSIER_OWNER_SET',
DOSSIER_OWNER_REMOVED: 'DOSSIER_OWNER_REMOVED',
USER_BECOMES_DOSSIER_MEMBER: 'USER_BECOMES_DOSSIER_MEMBER',
DOSSIER_DELETED: 'DOSSIER_DELETED',
USER_REMOVED_AS_DOSSIER_MEMBER: 'USER_REMOVED_AS_DOSSIER_MEMBER',
USER_PROMOTED_TO_APPROVER: 'USER_PROMOTED_TO_APPROVER',
USER_DEGRADED_TO_REVIEWER: 'USER_DEGRADED_TO_REVIEWER',
DOSSIER_OWNER_DELETED: 'DOSSIER_OWNER_DELETED',
ASSIGN_REVIEWER: 'ASSIGN_REVIEWER', // "You are assigned as review"
ASSIGN_APPROVER: 'ASSIGN_APPROVER', // "You are assigned as approver"
UNASSIGNED_FROM_FILE: 'UNASSIGNED_FROM_FILE', // "You are unassigned"
DOCUMENT_APPROVED: 'DOCUMENT_APPROVED', // "A document has been approved"
DOSSIER_OWNER_SET: 'DOSSIER_OWNER_SET', // "Dossier owner has changed"
DOSSIER_OWNER_REMOVED: 'DOSSIER_OWNER_REMOVED', // "Dossier owner has been removed"
USER_BECOMES_DOSSIER_MEMBER: 'USER_BECOMES_DOSSIER_MEMBER', // "You have been assigned to a dossier"
DOSSIER_DELETED: 'DOSSIER_DELETED', // "A dossier has been deleted"
USER_REMOVED_AS_DOSSIER_MEMBER: 'USER_REMOVED_AS_DOSSIER_MEMBER', // "You have been removed from a dossier"
USER_PROMOTED_TO_APPROVER: 'USER_PROMOTED_TO_APPROVER', // "You are promoted to approver"
USER_DEGRADED_TO_REVIEWER: 'USER_DEGRADED_TO_REVIEWER', // "You are denoted to reviewer"
} as const;
export type NotificationType = keyof typeof NotificationTypes;

View File

@ -0,0 +1,4 @@
import { DossierStatus } from '../dossiers';
import { WorkflowFileStatus } from '../files';
export type Color = WorkflowFileStatus | DossierStatus | string;

View File

@ -3,5 +3,6 @@ export * from './types';
export * from './rules';
export * from './watermark';
export * from './default-color-type';
export * from './colors';
export * from './view-mode';
export * from './expandable-file-actions';

View File

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

Binary file not shown.