RED-5445 - Adding value to file attribute in file list
This commit is contained in:
parent
0587c49cec
commit
91a7cb9b44
@ -3,11 +3,30 @@
|
||||
<ng-template #date>
|
||||
<span class="clamp-3"> {{ fileAttributeValue ? (fileAttributeValue | date : 'd MMM yyyy') : '-' }}</span>
|
||||
</ng-template>
|
||||
<iqser-circle-button
|
||||
*ngIf="permissionsService.canEditFileAttributes(file, dossier)"
|
||||
(action)="editFileAttribute($event)"
|
||||
[icon]="'iqser:edit'"
|
||||
[disabled]="!fileAttribute.editable"
|
||||
[tooltip]="'file-attribute.actions.edit' | translate"
|
||||
></iqser-circle-button>
|
||||
<ng-container *ngIf="(isEditingFileAttribute$ | async) === false || isInEditMode">
|
||||
<div class="edit-button" *ngIf="!isInEditMode">
|
||||
<iqser-circle-button
|
||||
id="edit-attribute-button"
|
||||
*ngIf="permissionsService.canEditFileAttributes(file, dossier)"
|
||||
(action)="editFileAttribute($event)"
|
||||
[icon]="'iqser:edit'"
|
||||
[disabled]="!fileAttribute.editable"
|
||||
[tooltip]="'file-attribute.actions.edit' | translate"
|
||||
></iqser-circle-button>
|
||||
</div>
|
||||
<div *ngIf="isInEditMode" class="edit">
|
||||
<form (submit)="save()" [formGroup]="form">
|
||||
<iqser-dynamic-input
|
||||
[formControlName]="fileAttribute.id"
|
||||
[id]="fileAttribute.id"
|
||||
[type]="fileAttribute.type"
|
||||
[classList]="'w-full'"
|
||||
>
|
||||
</iqser-dynamic-input>
|
||||
|
||||
<iqser-circle-button [icon]="'iqser:check'" [disabled]="disabled" (action)="save($event)"></iqser-circle-button>
|
||||
<iqser-circle-button [icon]="'iqser:close'" (action)="close($event)"></iqser-circle-button>
|
||||
</form>
|
||||
</div>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
@ -1,15 +1,53 @@
|
||||
.file-attribute {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
||||
iqser-circle-button {
|
||||
.edit-button,
|
||||
.edit {
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 150%;
|
||||
transform: translate(-25%);
|
||||
z-index: 1;
|
||||
background: radial-gradient(var(--iqser-side-nav) 10%, rgba(244, 245, 247, 0) 60%);
|
||||
|
||||
#edit-attribute-button,
|
||||
form {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
left: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
iqser-dynamic-input {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.edit {
|
||||
width: 300%;
|
||||
display: block;
|
||||
|
||||
form {
|
||||
display: flex;
|
||||
gap: 5px;
|
||||
align-items: center;
|
||||
z-index: 10;
|
||||
width: 75%;
|
||||
}
|
||||
|
||||
iqser-dynamic-input {
|
||||
width: 75%;
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
iqser-circle-button {
|
||||
.edit-button {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,29 +1,46 @@
|
||||
import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
|
||||
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||
import { Dossier, File, FileAttributeConfigTypes, IFileAttributeConfig } from '@red/domain';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import {
|
||||
EditFileAttributeValueData,
|
||||
EditFileAttributeValueDialogComponent,
|
||||
} from '../../../dialogs/edit-file-attribute-value-dialog/edit-file-attribute-value-dialog.component';
|
||||
import { defaultDialogConfig, Toaster } from '@iqser/common-ui';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { BaseFormComponent, Toaster } from '@iqser/common-ui';
|
||||
import { PermissionsService } from '@services/permissions.service';
|
||||
|
||||
import { FormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
import { FileAttributesService } from '@services/entity-services/file-attributes.service';
|
||||
import { BehaviorSubject, firstValueFrom, Observable } from 'rxjs';
|
||||
import { FilesService } from '@services/files/files.service';
|
||||
import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
|
||||
@Component({
|
||||
selector: 'redaction-file-attribute [fileAttribute] [file] [dossier]',
|
||||
templateUrl: './file-attribute.component.html',
|
||||
styleUrls: ['./file-attribute.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class FileAttributeComponent {
|
||||
export class FileAttributeComponent extends BaseFormComponent implements OnInit {
|
||||
@Input() fileAttribute!: IFileAttributeConfig;
|
||||
|
||||
@Input() file!: File;
|
||||
|
||||
@Input() dossier!: Dossier;
|
||||
isInEditMode = false;
|
||||
readonly isEditingFileAttribute$: BehaviorSubject<boolean>;
|
||||
|
||||
constructor(private readonly _dialog: MatDialog, private readonly _toaster: Toaster, readonly permissionsService: PermissionsService) {}
|
||||
constructor(
|
||||
private readonly _fileAttributesService: FileAttributesService,
|
||||
private readonly _toaster: Toaster,
|
||||
private readonly _formBuilder: FormBuilder,
|
||||
private readonly _filesService: FilesService,
|
||||
readonly permissionsService: PermissionsService,
|
||||
) {
|
||||
super();
|
||||
this.isEditingFileAttribute$ = this._fileAttributesService.isEditingFileAttribute$;
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
if (this.#noFileAttributes) {
|
||||
this.#initFileAttributes();
|
||||
}
|
||||
|
||||
this.form = this.#getForm();
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
}
|
||||
|
||||
get isDate(): boolean {
|
||||
return this.fileAttribute.type === FileAttributeConfigTypes.DATE;
|
||||
@ -33,19 +50,54 @@ export class FileAttributeComponent {
|
||||
return this.file.fileAttributes.attributeIdToValue[this.fileAttribute.id];
|
||||
}
|
||||
|
||||
get #noFileAttributes(): boolean {
|
||||
return JSON.stringify(this.file.fileAttributes.attributeIdToValue) === '{}';
|
||||
}
|
||||
|
||||
#initFileAttributes() {
|
||||
const configs = this._fileAttributesService.getFileAttributeConfig(this.file.dossierTemplateId).fileAttributeConfigs;
|
||||
configs.forEach(config => (this.file.fileAttributes.attributeIdToValue[config.id] = null));
|
||||
}
|
||||
|
||||
async editFileAttribute($event: MouseEvent): Promise<void> {
|
||||
$event?.stopPropagation();
|
||||
this.#toggleEdit();
|
||||
}
|
||||
|
||||
const dialogRef = this._dialog.open<EditFileAttributeValueDialogComponent, EditFileAttributeValueData>(
|
||||
EditFileAttributeValueDialogComponent,
|
||||
{ ...defaultDialogConfig, data: { fileAttribute: this.fileAttribute, file: this.file } },
|
||||
);
|
||||
const result = await firstValueFrom(dialogRef.afterClosed());
|
||||
#getForm(): UntypedFormGroup {
|
||||
const config = {};
|
||||
const fileAttributes = this.file.fileAttributes.attributeIdToValue;
|
||||
Object.keys(fileAttributes).forEach(key => {
|
||||
config[key] = [fileAttributes[key]];
|
||||
});
|
||||
return this._formBuilder.group(config);
|
||||
}
|
||||
|
||||
if (result) {
|
||||
async save($event?: MouseEvent): Promise<void> {
|
||||
$event.stopPropagation();
|
||||
|
||||
try {
|
||||
const attributeIdToValue = this.form.getRawValue();
|
||||
await firstValueFrom(
|
||||
this._fileAttributesService.setFileAttributes({ attributeIdToValue }, this.file.dossierId, this.file.fileId),
|
||||
);
|
||||
await firstValueFrom(this._filesService.reload(this.file.dossierId, this.file));
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
this._toaster.success(_('file-attribute.update.success'));
|
||||
} else if (result === false) {
|
||||
} catch (e) {
|
||||
this._toaster.error(_('file-attribute.update.error'));
|
||||
}
|
||||
|
||||
this.#toggleEdit();
|
||||
}
|
||||
|
||||
close($event: MouseEvent): void {
|
||||
$event?.stopPropagation();
|
||||
this.#toggleEdit();
|
||||
}
|
||||
|
||||
#toggleEdit(): void {
|
||||
this.isInEditMode = !this.isInEditMode;
|
||||
this.isEditingFileAttribute$.next(this.isInEditMode);
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<redaction-date-column [date]="file.redactionModificationDate" [isError]="file.isError"></redaction-date-column>
|
||||
</div>
|
||||
|
||||
<div *ngFor="let config of displayedAttributes" class="cell editable">
|
||||
<div *ngFor="let config of displayedAttributes" class="cell">
|
||||
<redaction-file-attribute [file]="file" [dossier]="dossier" [fileAttribute]="config"></redaction-file-attribute>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,28 +0,0 @@
|
||||
<section class="dialog">
|
||||
<form (submit)="save()" [formGroup]="form">
|
||||
<div translate="edit-file-attribute-value-dialog.header" class="dialog-header heading-l"></div>
|
||||
|
||||
<div class="dialog-content">
|
||||
<iqser-dynamic-input
|
||||
[formControlName]="fileAttribute.id"
|
||||
[id]="fileAttribute.id"
|
||||
[label]="fileAttribute.label"
|
||||
[type]="fileAttribute.type"
|
||||
[classList]="'w-full'"
|
||||
>
|
||||
</iqser-dynamic-input>
|
||||
</div>
|
||||
|
||||
<div class="dialog-actions">
|
||||
<iqser-icon-button
|
||||
[disabled]="disabled"
|
||||
[label]="'edit-file-attribute-value-dialog.actions.save' | translate"
|
||||
[submit]="true"
|
||||
[type]="iconButtonTypes.primary"
|
||||
></iqser-icon-button>
|
||||
<div class="all-caps-label cancel" translate="edit-file-attribute-value-dialog.actions.cancel" mat-dialog-close></div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<iqser-circle-button (action)="close()" class="dialog-close" icon="iqser:close"></iqser-circle-button>
|
||||
</section>
|
||||
@ -1,71 +0,0 @@
|
||||
import { Component, Inject } from '@angular/core';
|
||||
import { File, IFileAttributeConfig } from '@red/domain';
|
||||
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
|
||||
import { BaseDialogComponent } from '@iqser/common-ui';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
import { firstValueFrom } from 'rxjs';
|
||||
import { FileAttributesService } from '@services/entity-services/file-attributes.service';
|
||||
import { FilesService } from '@services/files/files.service';
|
||||
|
||||
export interface EditFileAttributeValueData {
|
||||
readonly fileAttribute: IFileAttributeConfig;
|
||||
readonly file: File;
|
||||
}
|
||||
|
||||
@Component({
|
||||
templateUrl: './edit-file-attribute-value-dialog.component.html',
|
||||
})
|
||||
export class EditFileAttributeValueDialogComponent extends BaseDialogComponent {
|
||||
readonly #file: File;
|
||||
readonly fileAttribute: IFileAttributeConfig;
|
||||
|
||||
constructor(
|
||||
private readonly _fileAttributesService: FileAttributesService,
|
||||
private readonly _filesService: FilesService,
|
||||
protected readonly _dialogRef: MatDialogRef<EditFileAttributeValueDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) readonly data: EditFileAttributeValueData,
|
||||
) {
|
||||
super(_dialogRef);
|
||||
|
||||
this.#file = data.file;
|
||||
this.fileAttribute = data.fileAttribute;
|
||||
|
||||
if (this.#noFileAttributes) {
|
||||
this.#initFileAttributes();
|
||||
}
|
||||
|
||||
this.form = this.#getForm();
|
||||
this.initialFormValue = this.form.getRawValue();
|
||||
}
|
||||
|
||||
get #noFileAttributes(): boolean {
|
||||
return JSON.stringify(this.#file.fileAttributes.attributeIdToValue) === '{}';
|
||||
}
|
||||
|
||||
#initFileAttributes() {
|
||||
const configs = this._fileAttributesService.getFileAttributeConfig(this.#file.dossierTemplateId).fileAttributeConfigs;
|
||||
configs.forEach(config => (this.#file.fileAttributes.attributeIdToValue[config.id] = null));
|
||||
}
|
||||
|
||||
#getForm(): UntypedFormGroup {
|
||||
const config = {};
|
||||
const fileAttributes = this.#file.fileAttributes.attributeIdToValue;
|
||||
Object.keys(fileAttributes).forEach(key => {
|
||||
config[key] = [fileAttributes[key]];
|
||||
});
|
||||
return this._formBuilder.group(config);
|
||||
}
|
||||
|
||||
async save(): Promise<void> {
|
||||
try {
|
||||
const attributeIdToValue = this.form.getRawValue();
|
||||
await firstValueFrom(
|
||||
this._fileAttributesService.setFileAttributes({ attributeIdToValue }, this.#file.dossierId, this.#file.fileId),
|
||||
);
|
||||
await firstValueFrom(this._filesService.reload(this.#file.dossierId, this.#file));
|
||||
this._dialogRef.close(true);
|
||||
} catch (e) {
|
||||
this._dialogRef.close(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -26,7 +26,6 @@ import { WorkflowItemComponent } from './components/workflow-item/workflow-item.
|
||||
import { DossierOverviewScreenHeaderComponent } from './components/screen-header/dossier-overview-screen-header.component';
|
||||
import { ViewModeSelectionComponent } from './components/view-mode-selection/view-mode-selection.component';
|
||||
import { FileAttributeComponent } from './components/table-item/file-attribute/file-attribute.component';
|
||||
import { EditFileAttributeValueDialogComponent } from './dialogs/edit-file-attribute-value-dialog/edit-file-attribute-value-dialog.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
@ -39,11 +38,8 @@ const routes: Routes = [
|
||||
},
|
||||
];
|
||||
|
||||
const dialogs = [EditFileAttributeValueDialogComponent];
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
...dialogs,
|
||||
DossierOverviewScreenComponent,
|
||||
DossierOverviewBulkActionsComponent,
|
||||
DossierDetailsComponent,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
<div *ngIf="isDossierOverviewList" class="action-buttons">
|
||||
<div *ngIf="isDossierOverviewList && (this.fileAttributesService.isEditingFileAttribute$ | async) === false" class="action-buttons">
|
||||
<ng-container *ngTemplateOutlet="actions"></ng-container>
|
||||
|
||||
<redaction-processing-indicator *ngIf="showStatusBar" [file]="file"></redaction-processing-indicator>
|
||||
|
||||
@ -32,6 +32,7 @@ import { FileAssignService } from '../../services/file-assign.service';
|
||||
import { ViewerHeaderService } from '../../../pdf-viewer/services/viewer-header.service';
|
||||
import { ROTATION_ACTION_BUTTONS } from '../../../pdf-viewer/utils/constants';
|
||||
import { ROLES } from '@users/roles';
|
||||
import { FileAttributesService } from '@services/entity-services/file-attributes.service';
|
||||
|
||||
@Component({
|
||||
selector: 'redaction-file-actions [file] [type] [dossier]',
|
||||
@ -96,6 +97,7 @@ export class FileActionsComponent implements OnChanges {
|
||||
private readonly _activeDossiersService: ActiveDossiersService,
|
||||
private readonly _fileManagementService: FileManagementService,
|
||||
private readonly _userPreferenceService: UserPreferenceService,
|
||||
readonly fileAttributesService: FileAttributesService,
|
||||
@Optional() private readonly _documentInfoService: DocumentInfoService,
|
||||
@Optional() private readonly _excludedPagesService: ExcludedPagesService,
|
||||
) {}
|
||||
|
||||
@ -14,6 +14,8 @@ export class FileAttributesService extends EntitiesService<IFileAttributeConfig,
|
||||
protected readonly _entityClass = FileAttributeConfig;
|
||||
readonly fileAttributesConfig$ = new BehaviorSubject<FileAttributesConfigMap>({});
|
||||
|
||||
readonly isEditingFileAttribute$ = new BehaviorSubject(false);
|
||||
|
||||
/**
|
||||
* Get the file attributes that can be used at importing csv.
|
||||
*/
|
||||
|
||||
@ -1 +1 @@
|
||||
Subproject commit 9891c2bf67285a4e2a46fdeadd2999919e5dcaf4
|
||||
Subproject commit b91586c470d502a505e1a78938ad72397cb51888
|
||||
Loading…
x
Reference in New Issue
Block a user