From 7ebf25f3c3b130eb5ea175253c6b468bfd32b813 Mon Sep 17 00:00:00 2001
From: Alex ORLUC <alex.orluc@maarch.org>
Date: Tue, 3 Dec 2019 18:41:32 +0100
Subject: [PATCH] FEAT #12331 TIME 6 add default tab + load data in process +
 update data in process

---
 src/frontend/app/actions/actions.service.ts   |  2 +-
 .../list/list-administration.component.html   | 20 ++--
 .../list/list-administration.component.ts     | 14 ++-
 .../contact/list/contacts-list.component.html |  2 +-
 .../diffusions/diffusions-list.component.ts   | 11 ++-
 .../indexing-form.component.html              |  4 +-
 .../indexing-form/indexing-form.component.ts  | 92 +++++++++++++++++--
 .../app/process/process.component.html        |  9 +-
 src/frontend/app/process/process.component.ts | 52 ++++++++++-
 src/frontend/lang/lang-en.ts                  |  5 +-
 src/frontend/lang/lang-fr.ts                  |  5 +-
 src/frontend/lang/lang-nl.ts                  |  5 +-
 12 files changed, 185 insertions(+), 36 deletions(-)

diff --git a/src/frontend/app/actions/actions.service.ts b/src/frontend/app/actions/actions.service.ts
index 30feedb0d62..59e795ef05b 100644
--- a/src/frontend/app/actions/actions.service.ts
+++ b/src/frontend/app/actions/actions.service.ts
@@ -560,7 +560,7 @@ export class ActionsService {
     processDocument(options: any = null) {
         this.stopRefreshResourceLock();
         this.unlockResource();
-        this.router.navigate([`/process/users/${this.currentUserId}/groups/${this.currentGroupId}/baskets/${this.currentBasketId}/resId/${this.currentResIds}`], { queryParams: { tab: options } });
+        this.router.navigate([`/process/users/${this.currentUserId}/groups/${this.currentGroupId}/baskets/${this.currentBasketId}/resId/${this.currentResIds}`], { queryParams: { tab: options.defaultTab } });
     }
 
     signatureBookAction(options: any = null) {
diff --git a/src/frontend/app/administration/basket/list/list-administration.component.html b/src/frontend/app/administration/basket/list/list-administration.component.html
index dc3e5b199ad..4389a076f8a 100644
--- a/src/frontend/app/administration/basket/list/list-administration.component.html
+++ b/src/frontend/app/administration/basket/list/list-administration.component.html
@@ -6,14 +6,18 @@
         </mat-option>
     </mat-select>
 </mat-form-field>
-<mat-form-field *ngIf="selectedListEvent === 'processDocument'" class="eventList" appearance="outline">
-    <mat-label>{{lang.tabProcessPosition}}</mat-label>
-    <mat-select [(ngModel)]="selectedProcessTool">
-        <mat-option *ngFor="let tool of processTool" [value]="tool.id">
-            {{tool.label}}
-        </mat-option>
-    </mat-select>
-</mat-form-field>
+<div style="display: grid;grid-template-columns: 1fr auto;grid-gap: 10px;align-items: center;" *ngIf="selectedListEvent === 'processDocument'">
+    <mat-form-field class="eventList" appearance="outline">
+        <mat-label>{{lang.tabProcessPosition}}</mat-label>
+        <mat-select [(ngModel)]="selectedProcessTool.defaultTab">
+            <mat-option *ngFor="let tool of processTool | sortBy: 'label'" [value]="tool.id">
+                {{tool.label}}
+            </mat-option>
+        </mat-select>
+    </mat-form-field>
+    <mat-slide-toggle color="primary" [(ngModel)]="selectedProcessTool.canUpdate">{{lang.canUpdateData}}</mat-slide-toggle>
+</div>
+
 <hr />
 <mat-toolbar class="editorTool">
     <span>
diff --git a/src/frontend/app/administration/basket/list/list-administration.component.ts b/src/frontend/app/administration/basket/list/list-administration.component.ts
index 3e3dc4fa613..4b2ffae231e 100644
--- a/src/frontend/app/administration/basket/list/list-administration.component.ts
+++ b/src/frontend/app/administration/basket/list/list-administration.component.ts
@@ -209,7 +209,10 @@ export class ListAdministrationComponent implements OnInit {
             label: this.lang.informations,
         }
     ];
-    selectedProcessTool: string = null;
+    selectedProcessTool: any = {
+        defaultTab : null,
+        canUpdate: false, 
+    };
     selectedProcessToolClone: string = null;
 
     @Input('currentBasketGroup') private basketGroup: any;
@@ -235,8 +238,9 @@ export class ListAdministrationComponent implements OnInit {
         this.selectedListEvent = this.basketGroup.list_event === null ? 'noEvent' : this.basketGroup.list_event;
         this.selectedListEventClone = this.selectedListEvent;
 
-        this.selectedProcessTool = this.basketGroup.list_event_data === null && this.basketGroup.list_event === 'processDocument' ? 'dashboard' : this.basketGroup.list_event;
-        this.selectedProcessToolClone = this.selectedProcessTool;
+        this.selectedProcessTool.defaultTab = this.basketGroup.list_event_data === null && this.basketGroup.list_event === 'processDocument' ? 'dashboard' : this.basketGroup.list_event_data.defaultTab;
+        this.selectedProcessTool.canUpdate = this.basketGroup.list_event_data === null ? false : this.basketGroup.list_event_data.canUpdate;
+        this.selectedProcessToolClone = JSON.parse(JSON.stringify(this.selectedProcessTool));
         this.displayedSecondaryDataClone = JSON.parse(JSON.stringify(this.displayedSecondaryData));
     }
 
@@ -322,7 +326,7 @@ export class ListAdministrationComponent implements OnInit {
                 this.selectedListEvent = this.selectedListEvent === null ? 'noEvent' : this.selectedListEvent;
                 this.basketGroup.list_event = this.selectedListEvent;
                 this.selectedListEventClone = this.selectedListEvent;
-                this.selectedProcessToolClone = this.selectedProcessTool;
+                this.selectedProcessToolClone = JSON.parse(JSON.stringify(this.selectedProcessTool));
                 this.notify.success(this.lang.resultPageUpdated);
             }, (err) => {
                 this.notify.error(err.error.errors);
@@ -341,7 +345,7 @@ export class ListAdministrationComponent implements OnInit {
     }
 
     checkModif() { 
-        if (JSON.stringify(this.displayedSecondaryData) === JSON.stringify(this.displayedSecondaryDataClone) && this.selectedListEvent === this.selectedListEventClone && this.selectedProcessTool === this.selectedProcessToolClone) {
+        if (JSON.stringify(this.displayedSecondaryData) === JSON.stringify(this.displayedSecondaryDataClone) && this.selectedListEvent === this.selectedListEventClone && JSON.stringify(this.selectedProcessTool) === JSON.stringify(this.selectedProcessToolClone)) {
             return true 
         } else {
            return false;
diff --git a/src/frontend/app/contact/list/contacts-list.component.html b/src/frontend/app/contact/list/contacts-list.component.html
index c1df4de086d..9dfa5b9fa3d 100644
--- a/src/frontend/app/contact/list/contacts-list.component.html
+++ b/src/frontend/app/contact/list/contacts-list.component.html
@@ -14,7 +14,7 @@
                 <mat-card-title>{{contact.firstname}} {{contact.lastname}}</mat-card-title>
                 <mat-card-subtitle [title]="lang.contactsFilling_function">{{contact.function}}&nbsp;
                 </mat-card-subtitle>
-                <i class="contact-filling fa fa-circle" *ngIf="contact.mode === 'physical' && contact.mode === 'corporate'" [style.color]="contact.filling"
+                <i class="contact-filling fa fa-circle" *ngIf="(contact.mode === 'physical' || contact.mode === 'corporate') && contact.filling !== ''" [style.color]="contact.filling"
                     [title]="lang.contactsFillingRate"></i>
             </mat-card-header>
             <mat-card-content>
diff --git a/src/frontend/app/diffusions/diffusions-list.component.ts b/src/frontend/app/diffusions/diffusions-list.component.ts
index 0fcafe2e382..ff3c755f4db 100644
--- a/src/frontend/app/diffusions/diffusions-list.component.ts
+++ b/src/frontend/app/diffusions/diffusions-list.component.ts
@@ -34,7 +34,7 @@ export class DiffusionsListComponent implements OnInit {
     /**
      * Ressource identifier to load listinstance (Incompatible with templateId)
      */
-    @Input('resId') resId: number;
+    @Input('resId') resId: number = null;
 
     /**
      * Add previous dest in copy (Only compatible with resId)
@@ -91,7 +91,7 @@ export class DiffusionsListComponent implements OnInit {
         this.adminMode = this.adminMode !== undefined ? this.adminMode : false;
         this.keepDestForRedirection = this.keepDestForRedirection !== undefined ? this.keepDestForRedirection : false;
 
-        if (this.resId !== undefined && this.target !== 'redirect') {
+        if (this.resId !== null && this.target !== 'redirect') {
             this.loadListinstance(this.resId);
 
         } else if (this.entityId !== undefined && this.entityId !== '') {
@@ -135,7 +135,7 @@ export class DiffusionsListComponent implements OnInit {
 
         arrayRoutes.push(this.http.get('../../rest/listTemplates/entities/' + entityId));
 
-        if (this.resId !== undefined) {
+        if (this.resId !== null) {
             arrayRoutes.push(this.http.get('../../rest/resources/' + this.resId + '/listInstance'));
         }
 
@@ -271,6 +271,11 @@ export class DiffusionsListComponent implements OnInit {
                     }
                 });
             }),
+            tap((data: any) => {
+                if (this.diffFormControl !== undefined) {
+                    this.setFormValues();
+                }
+            }),
             finalize(() => this.loading = false),
             catchError((err: any) => {
                 this.notify.handleErrors(err);
diff --git a/src/frontend/app/indexation/indexing-form/indexing-form.component.html b/src/frontend/app/indexation/indexing-form/indexing-form.component.html
index 74c13098cec..4b08bb72b15 100644
--- a/src/frontend/app/indexation/indexing-form/indexing-form.component.html
+++ b/src/frontend/app/indexation/indexing-form/indexing-form.component.html
@@ -165,7 +165,7 @@
                             <div style="padding: 10px;font-size: 16px;color: #135F7F;letter-spacing: 2px;font-weight: bold;display: flex;
                                 align-items: center;">
                                 <div style="display: flex;flex: 1;align-items: center;">
-                                    {{lang.diffusionList}} <button mat-icon-button  *ngIf="appDiffusionsList.canUpdateRoles()" color="primary"
+                                    {{lang.diffusionList}} <button mat-icon-button  *ngIf="appDiffusionsList.canUpdateRoles() && canEdit && mode !== 'process'" color="primary"
                                             (click)="appDiffusionsList.switchMode()" [title]="lang.modifyDiffusionList">
                                             <mat-icon class="fa fa-edit"></mat-icon>
                                         </button>
@@ -178,7 +178,7 @@
                                     <i class="fas fa-check fieldFull" *ngIf="!adminMode && arrFormControl['diffusionList'].valid && !isEmptyField(field)"></i>
                                 </div>
                             </div>
-                            <app-diffusions-list #appDiffusionsList [entityId]="arrFormControl[field.identifier].value" [diffFormControl]="arrFormControl['diffusionList']" [allowedEntities]="field.allowedEntities" [target]="'indexation'" (triggerEvent)="changeDestination($event,field.allowedEntities)">
+                            <app-diffusions-list #appDiffusionsList [resId]="resId" [entityId]="arrFormControl[field.identifier].value" [diffFormControl]="arrFormControl['diffusionList']" [allowedEntities]="field.allowedEntities" [target]="'indexation'" (triggerEvent)="changeDestination($event,field.allowedEntities)">
                             </app-diffusions-list>
                             <mat-divider></mat-divider>
                         </div>
diff --git a/src/frontend/app/indexation/indexing-form/indexing-form.component.ts b/src/frontend/app/indexation/indexing-form/indexing-form.component.ts
index 2c3ffa95b07..323a18ea21a 100644
--- a/src/frontend/app/indexation/indexing-form/indexing-form.component.ts
+++ b/src/frontend/app/indexation/indexing-form/indexing-form.component.ts
@@ -27,8 +27,11 @@ export class IndexingFormComponent implements OnInit {
     loading: boolean = true;
 
     @Input('indexingFormId') indexingFormId: number;
+    @Input('resId') resId: number = null;
     @Input('groupId') groupId: number;
     @Input('admin') adminMode: boolean;
+    @Input('canEdit') canEdit: boolean = true;
+    @Input('mode') mode: string = 'indexation';
 
     @ViewChild('appDiffusionsList', { static: false }) appDiffusionsList: DiffusionsListComponent;
 
@@ -85,11 +88,11 @@ export class IndexingFormComponent implements OnInit {
             values: []
         },
         {
-            identifier: 'confidential',
+            identifier: 'confidentiality',
             label: this.lang.confidential,
             type: 'radio',
             default_value: '',
-            values: [{ 'id': 'true', 'label': this.lang.yes }, { 'id': 'false', 'label': this.lang.no }]
+            values: [{ 'id': true, 'label': this.lang.yes }, { 'id': false, 'label': this.lang.no }]
         },
         {
             identifier: 'initiator',
@@ -169,6 +172,8 @@ export class IndexingFormComponent implements OnInit {
     currentCategory: string = '';
     currentPriorityColor: string = '';
 
+    currentResourceValues: any = null;
+
     constructor(
         public http: HttpClient,
         private notify: NotificationService,
@@ -256,7 +261,7 @@ export class IndexingFormComponent implements OnInit {
         }
     }
 
-    getDatas() {
+    getDatas(withDiffusionList = true) {
         let arrIndexingModels: any[] = [];
         this.fieldCategories.forEach(category => {
             arrIndexingModels = arrIndexingModels.concat(this['indexingModels_' + category]);
@@ -286,7 +291,7 @@ export class IndexingFormComponent implements OnInit {
                 element.default_value = this.arrFormControl[element.identifier].value;
             }
 
-            if (element.identifier === "destination" && !this.adminMode) {
+            if (element.identifier === "destination" && !this.adminMode && withDiffusionList) {
                 arrIndexingModels.push({
                     identifier: 'diffusionList',
                     default_value: this.arrFormControl['diffusionList'].value
@@ -304,6 +309,40 @@ export class IndexingFormComponent implements OnInit {
         return arrIndexingModels;
     }
 
+    saveData(userId: number, groupId: number, basketId: number) {
+        const formatdatas = this.formatDatas(this.getDatas());
+
+        this.http.put(`../../rest/resources/${this.resId}/users/${userId}/groups/${groupId}/baskets/${basketId}`, formatdatas ).pipe(
+            tap(() => {
+                this.currentResourceValues = this.getDatas();
+                this.notify.success(this.lang.dataUpdated);
+            }),
+            catchError((err: any) => {
+                this.notify.handleErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
+
+    formatDatas(datas: any) {
+        let formatData: any = {};
+        const regex = /indexingCustomField_[.]*/g;
+
+        formatData['customFields'] = {};
+
+        datas.forEach((element: any) => {
+
+            if (element.identifier.match(regex) !== null) {
+
+                formatData['customFields'][element.identifier.split('_')[1]] = element.default_value;
+
+            } else {
+                formatData[element.identifier] = element.default_value;
+            }
+        });
+        return formatData;
+    }
+
     getCategory() {
         return this.currentCategory;
     }
@@ -333,6 +372,14 @@ export class IndexingFormComponent implements OnInit {
         return state;
     }
 
+    isResourceModified() {
+        if (JSON.stringify(this.currentResourceValues) === JSON.stringify(this.getDatas(false))) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
     setModification() {
         this.fieldCategories.forEach(element => {
             this['indexingModels_' + element + 'Clone'] = JSON.parse(JSON.stringify(this['indexingModels_' + element]));
@@ -489,9 +536,42 @@ export class IndexingFormComponent implements OnInit {
                     });
                 });
             }),
+            filter(() => this.resId !== null),
+            exhaustMap(() => this.http.get(`../../rest/resources/${this.resId}`)),
+            tap((data: any) => {
+                this.fieldCategories.forEach(element => {
+                    this['indexingModels_' + element].forEach((elem: any) => {
+
+                        if (Object.keys(data).indexOf(elem.identifier) > -1) {
+                            let fieldValue = data[elem.identifier];
+                            
+                            if (elem.type === 'date') {
+                                fieldValue = new Date(fieldValue);
+                            }
+                            
+                            if (elem.identifier === 'priority') {
+                                this.setPriorityColor(null, fieldValue);
+                            }
+
+                            if (elem.identifier === 'destination') {
+                                if (this.mode === 'process') {
+                                    this.arrFormControl[elem.identifier].disable();
+                                }
+                                this.arrFormControl['diffusionList'].disable();
+                            }
+                            this.arrFormControl[elem.identifier].setValue(fieldValue);
+                        }
+                        if (!this.canEdit) {
+                            this.arrFormControl[elem.identifier].disable();
+                        }
+                    });
+                });
+            }),
+            tap(() => {
+                this.currentResourceValues = JSON.parse(JSON.stringify(this.getDatas(false)));
+            }),
             finalize(() => this.loading = false)
         ).subscribe();
-
     }
 
     initializeRoutes() {
@@ -501,7 +581,7 @@ export class IndexingFormComponent implements OnInit {
         this.fieldCategories.forEach(element => {
             this['indexingModels_' + element].forEach((elem: any) => {
                 if (elem.identifier === 'destination') {
-                    if (this.adminMode) {
+                    if (this.adminMode || this.mode !== 'indexation') {
                         arrayRoutes.push(this.http.get('../../rest/indexingModels/entities'));
 
                     } else {
diff --git a/src/frontend/app/process/process.component.html b/src/frontend/app/process/process.component.html
index f8c8fc49bd5..bfcb2429477 100644
--- a/src/frontend/app/process/process.component.html
+++ b/src/frontend/app/process/process.component.html
@@ -9,7 +9,7 @@
             <div class="processTool">
                 <div class="processTool-module jiggle" *ngFor="let module of processTool"
                     [class.processTool-module-active]="module.id === currentTool" matRipple
-                    (click)="currentTool = module.id">
+                    (click)="changeTab(module.id)">
                     <i [class]="module.icon"></i>
                     <span *ngIf="!appService.getViewMode()">{{module.label}}</span>
                 </div>
@@ -90,7 +90,7 @@
                     [resId]="currentResourceInformations.resId" [target]="'process'">
                 </app-attachments-list>
                 <app-indexing-form *ngIf="currentTool === 'info'" #indexingForm [groupId]="currentGroupId"
-                    [indexingFormId]="1"></app-indexing-form>
+                    [indexingFormId]="1" [resId]="currentResourceInformations.resId" [mode]="'process'"></app-indexing-form>
             </ng-container>
             <ng-template #elseTemplate>
                 <div class="openedModal">
@@ -178,8 +178,7 @@
                                     *ngIf="this.currentResourceInformations.closingDate !== null; else elseLimitDate">
                                     <div style="font-weight: bold;"
                                         [title]="this.currentResourceInformations.closingDate | fullDate">
-                                        {{this.lang.closed}} {{this.lang.onRange}}
-                                        {{this.currentResourceInformations.closingDate | timeAgo}}&nbsp;&nbsp;<i
+                                        {{this.lang.closed}} {{this.currentResourceInformations.closingDate | timeAgo : 'full'}}&nbsp;&nbsp;<i
                                             class="fa fa-lock"></i></div>
                                 </ng-container>
                                 <ng-template #elseLimitDate>
@@ -238,7 +237,7 @@
         <app-attachments-list *ngIf="modal.id === 'attachments'" #appAttachmentsList
             [resId]="currentResourceInformations.resId" (reloadBadgeAttachments)="reloadBadgeAttachments($event)">
         </app-attachments-list>
-        <app-indexing-form *ngIf="modal.id === 'info'" #indexingForm [groupId]="currentGroupId" [indexingFormId]="1">
+        <app-indexing-form *ngIf="modal.id === 'info'" #indexingForm [groupId]="currentGroupId" [indexingFormId]="1" [resId]="currentResourceInformations.resId" [mode]="'process'">
         </app-indexing-form>
     </div>
 </div>
diff --git a/src/frontend/app/process/process.component.ts b/src/frontend/app/process/process.component.ts
index beffd76844e..2f22ea313f2 100644
--- a/src/frontend/app/process/process.component.ts
+++ b/src/frontend/app/process/process.component.ts
@@ -12,9 +12,11 @@ import { FiltersListService } from '../../service/filtersList.service';
 import { Overlay } from '@angular/cdk/overlay';
 import { AppService } from '../../service/app.service';
 import { ActionsService } from '../actions/actions.service';
-import { tap, catchError, map, finalize } from 'rxjs/operators';
+import { tap, catchError, map, finalize, filter } from 'rxjs/operators';
 import { of, Subscription } from 'rxjs';
 import { DocumentViewerComponent } from '../viewer/document-viewer.component';
+import { IndexingFormComponent } from '../indexation/indexing-form/indexing-form.component';
+import { ConfirmComponent } from '../../plugins/modal/confirm.component';
 
 @Component({
     templateUrl: "process.component.html",
@@ -114,6 +116,7 @@ export class ProcessComponent implements OnInit {
     @ViewChild('snav2', { static: true }) sidenavRight: MatSidenav;
 
     @ViewChild('appDocumentViewer', { static: true }) appDocumentViewer: DocumentViewerComponent;
+    @ViewChild('indexingForm', { static: false }) indexingForm: IndexingFormComponent;
     
     constructor(
         private route: ActivatedRoute,
@@ -236,7 +239,25 @@ export class ProcessComponent implements OnInit {
     }
 
     onSubmit() {
-        this.actionService.launchAction(this.selectedAction, this.currentUserId, this.currentGroupId, this.currentBasketId, [this.currentResourceInformations.resId], this.currentResourceInformations, false);
+        if (this.currentTool === 'info' && this.indexingForm.isResourceModified()) {
+            const dialogRef = this.dialog.open(ConfirmComponent, { autoFocus: false, disableClose: true, data: { title: this.lang.confirm, msg: this.lang.saveModifiedData } });
+
+                dialogRef.afterClosed().pipe(
+                    filter((data: string) => data === 'ok'),
+                    tap(() => {
+                        this.indexingForm.saveData(this.currentUserId, this.currentGroupId, this.currentBasketId);
+                    }),
+                    finalize(() => this.actionService.launchAction(this.selectedAction, this.currentUserId, this.currentGroupId, this.currentBasketId, [this.currentResourceInformations.resId], this.currentResourceInformations, false)),
+                    catchError((err: any) => {
+                        this.notify.handleErrors(err);
+                        return of(false);
+                    })
+                ).subscribe();
+        } else {
+            this.actionService.launchAction(this.selectedAction, this.currentUserId, this.currentGroupId, this.currentBasketId, [this.currentResourceInformations.resId], this.currentResourceInformations, false);
+        }
+
+        
     }
 
     showActionInCurrentCategory(action: any) {
@@ -279,4 +300,31 @@ export class ProcessComponent implements OnInit {
         this.subscription.unsubscribe();
     }
 
+    changeTab(tabId: string) {
+        if (this.currentTool === 'info' && this.indexingForm.isResourceModified()) {
+            const dialogRef = this.dialog.open(ConfirmComponent, { autoFocus: false, disableClose: true, data: { title: this.lang.confirm, msg: this.lang.saveModifiedData } });
+
+                dialogRef.afterClosed().pipe(
+                    tap((data: string) => {
+                        if (data !== 'ok') {
+                            this.currentTool = tabId;
+                        }
+                    }),
+                    filter((data: string) => data === 'ok'),
+                    tap(() => {
+                        this.indexingForm.saveData(this.currentUserId, this.currentGroupId, this.currentBasketId);
+                        setTimeout(() => {
+                            this.loadResource();
+                        }, 400);
+                        this.currentTool = tabId;
+                    }),
+                    catchError((err: any) => {
+                        this.notify.handleErrors(err);
+                        return of(false);
+                    })
+                ).subscribe();
+        } else {
+            this.currentTool = tabId;
+        }
+    }
 }
diff --git a/src/frontend/lang/lang-en.ts b/src/frontend/lang/lang-en.ts
index 2674ee55162..ec54f1c92db 100755
--- a/src/frontend/lang/lang-en.ts
+++ b/src/frontend/lang/lang-en.ts
@@ -1317,5 +1317,8 @@ export const LANG_EN = {
     "enableGroupMsg": "This group could access to all functionnalities.",
     "sendActivationNotification": "Send activation notification",
     "activationNotificationSend": "Activation notification send",
-    "tabProcessPosition": "Move to tab"
+    "tabProcessPosition": "Move to tab",
+    "saveModifiedData": "Do you want to save modified data ?",
+    "dataUpdated": "Data updated",
+    "canUpdateData": "Can update resource data",
 };
diff --git a/src/frontend/lang/lang-fr.ts b/src/frontend/lang/lang-fr.ts
index 9a8fdc43a12..fcda002cac4 100755
--- a/src/frontend/lang/lang-fr.ts
+++ b/src/frontend/lang/lang-fr.ts
@@ -1355,5 +1355,8 @@ export const LANG_FR = {
     "enableGroupMsg": "Ce groupe pourra potentiellement avoir accès à l'ensemble des fonctionnalités de l'application.",
     "sendActivationNotification": "Envoyer à nouveau le courriel d'activation",
     "activationNotificationSend": "Le courriel d'activation a été envoyé",
-    "tabProcessPosition": "Se positionner sur l'onglet"
+    "tabProcessPosition": "Se positionner sur l'onglet",
+    "saveModifiedData": "Voulez-vous sauvegarder les modifications ?",
+    "dataUpdated": "Données modifiées",
+    "canUpdateData": "Pouvoir modifier les métadonnées du courrier",
 };
diff --git a/src/frontend/lang/lang-nl.ts b/src/frontend/lang/lang-nl.ts
index a4a30783dc4..4469262e452 100755
--- a/src/frontend/lang/lang-nl.ts
+++ b/src/frontend/lang/lang-nl.ts
@@ -1342,5 +1342,8 @@ export const LANG_NL = {
     "enableGroupMsg": "This group could access to all functionnalities.", //_TO_TRANSLATE
     "sendActivationNotification": "Send activation notification", //_TO_TRANSLATE
     "activationNotificationSend": "Activation notification send", //_TO_TRANSLATE
-    "tabProcessPosition": "Move to tab" //_TO_TRANSLATE
+    "tabProcessPosition": "Move to tab", //_TO_TRANSLATE
+    "saveModifiedData": "Do you want to save modified data ?", //_TO_TRANSLATE
+    "dataUpdated": "Data updated", //_TO_TRANSLATE
+    "canUpdateData": "Can update resource data", //_TO_TRANSLATE
 };
-- 
GitLab