From f22940719c1d109695be4e5b4b302dca228b5da1 Mon Sep 17 00:00:00 2001
From: Alex ORLUC <alex.orluc@maarch.org>
Date: Tue, 28 Jan 2020 15:16:21 +0100
Subject: [PATCH] FEAT #12869 TIME 3 front linked resource list

---
 src/frontend/app/app.module.ts                |  7 +-
 .../link-resource-modal.component.html        | 11 +++
 .../link-resource-modal.component.scss        | 15 +++
 .../link-resource-modal.component.ts          | 20 ++++
 .../linked-resource-list.component.html       | 71 +++++++++----
 .../linked-resource-list.component.scss       | 26 +++++
 .../linked-resource-list.component.ts         | 99 ++++++++++++++++++-
 .../app/list/basket-list.component.ts         |  2 +-
 .../app/process/process.component.html        |  4 +-
 src/frontend/app/process/process.component.ts |  2 +-
 src/frontend/lang/lang-en.ts                  |  2 +
 src/frontend/lang/lang-fr.ts                  |  2 +
 src/frontend/lang/lang-nl.ts                  |  2 +
 13 files changed, 235 insertions(+), 28 deletions(-)
 create mode 100644 src/frontend/app/linkedResource/linkResourceModal/link-resource-modal.component.html
 create mode 100644 src/frontend/app/linkedResource/linkResourceModal/link-resource-modal.component.scss
 create mode 100644 src/frontend/app/linkedResource/linkResourceModal/link-resource-modal.component.ts

diff --git a/src/frontend/app/app.module.ts b/src/frontend/app/app.module.ts
index 90274498768..c32ab57c838 100755
--- a/src/frontend/app/app.module.ts
+++ b/src/frontend/app/app.module.ts
@@ -104,6 +104,7 @@ import { AddAvisModelModalComponent } from './avis/addAvisModel/add-avis-model-m
 import { CriteriaToolComponent } from './adv-search/criteria-tool/criteria-tool.component';
 import { SearchAdvListComponent } from './adv-search/list/search-adv-list.component';
 import { LinkedResourceListComponent } from './linkedResource/linked-resource-list.component';
+import { LinkResourceModalComponent } from './linkedResource/linkResourceModal/link-resource-modal.component';
 
 
 @NgModule({
@@ -197,7 +198,8 @@ import { LinkedResourceListComponent } from './linkedResource/linked-resource-li
         AddAvisModelModalComponent,
         CriteriaToolComponent,
         SearchAdvListComponent,
-        LinkedResourceListComponent
+        LinkedResourceListComponent,
+        LinkResourceModalComponent
     ],
     entryComponents: [
         ConfirmModalComponent,
@@ -241,7 +243,8 @@ import { LinkedResourceListComponent } from './linkedResource/linked-resource-li
         ContactModalComponent,
         VisaWorkflowModalComponent,
         AddVisaModelModalComponent,
-        AddAvisModelModalComponent
+        AddAvisModelModalComponent,
+        LinkResourceModalComponent
     ],
     providers: [ FiltersListService, FoldersService, ActionsService, PrivilegeService ],
     bootstrap: [ AppComponent ]
diff --git a/src/frontend/app/linkedResource/linkResourceModal/link-resource-modal.component.html b/src/frontend/app/linkedResource/linkResourceModal/link-resource-modal.component.html
new file mode 100644
index 00000000000..9e5f0edf5af
--- /dev/null
+++ b/src/frontend/app/linkedResource/linkResourceModal/link-resource-modal.component.html
@@ -0,0 +1,11 @@
+<h1 mat-dialog-title>
+    <span style="flex: 1;" [title]="lang.linkResource">
+        {{lang.linkResource}}
+    </span>
+    <button [title]="lang.close" mat-icon-button (click)="dialogRef.close();">
+        <mat-icon class="fa fa-times"></mat-icon>
+    </button></h1>
+<mat-dialog-content class="modal-container">
+    <app-criteria-tool></app-criteria-tool>
+    <search-adv-list [search]="'&resourceField=aléa'"></search-adv-list>
+</mat-dialog-content>
\ No newline at end of file
diff --git a/src/frontend/app/linkedResource/linkResourceModal/link-resource-modal.component.scss b/src/frontend/app/linkedResource/linkResourceModal/link-resource-modal.component.scss
new file mode 100644
index 00000000000..7abd563bb58
--- /dev/null
+++ b/src/frontend/app/linkedResource/linkResourceModal/link-resource-modal.component.scss
@@ -0,0 +1,15 @@
+@import '../../../css/vars.scss';
+
+.mat-dialog-title {
+    padding: 10px;
+    display: flex;
+    align-items: center;
+}
+.modal-container{
+    min-height: 250px;
+    height: auto;
+}
+
+.modal-body{
+    min-height: auto;
+}
diff --git a/src/frontend/app/linkedResource/linkResourceModal/link-resource-modal.component.ts b/src/frontend/app/linkedResource/linkResourceModal/link-resource-modal.component.ts
new file mode 100644
index 00000000000..0875fa58c37
--- /dev/null
+++ b/src/frontend/app/linkedResource/linkResourceModal/link-resource-modal.component.ts
@@ -0,0 +1,20 @@
+import { Component, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { LANG } from '../../translate.component';
+import { HttpClient } from '@angular/common/http';
+
+@Component({
+    templateUrl: 'link-resource-modal.component.html',
+    styleUrls: ['link-resource-modal.component.scss'],
+})
+export class LinkResourceModalComponent {
+    lang: any = LANG;
+
+    constructor(
+        public http: HttpClient,
+        @Inject(MAT_DIALOG_DATA) public data: any,
+        public dialogRef: MatDialogRef<LinkResourceModalComponent>) {
+    }
+
+    ngOnInit(): void { }
+}
diff --git a/src/frontend/app/linkedResource/linked-resource-list.component.html b/src/frontend/app/linkedResource/linked-resource-list.component.html
index 6d6c190a90f..cb0a90637df 100644
--- a/src/frontend/app/linkedResource/linked-resource-list.component.html
+++ b/src/frontend/app/linkedResource/linked-resource-list.component.html
@@ -1,6 +1,4 @@
-<!--<app-criteria-tool></app-criteria-tool>
-<search-adv-list [search]="'&resourceField=aléa'"></search-adv-list>-->
-
+<mat-card id="viewThumbnail" style="display:none;position: fixed;z-index: 2;margin-left: 1px;left: 50%;transform: translate(-50%,-50%);top: 50%;"><img style="max-height: 100vh;" src="{{thumbnailUrl}}" /></mat-card>
 <div class="row">
     <div class="col-md-12">
         <mat-paginator #paginator [length]="100" [hidePageSize]="true" [pageSize]="10">
@@ -9,21 +7,58 @@
 </div>
 <mat-table #table [dataSource]="dataSource" matSort matSortActive="resId" matSortDirection="asc">
     <ng-container matColumnDef="resId">
-        <mat-cell *matCellDef="let element" style="flex:1;">
-            <span>
-                {{element.resId}}
-            </span>
+        <mat-cell *matCellDef="let row" style="flex: 1;flex-direction: column;padding: 0px;">
+            <div class="sub-info">
+                <span class="sub-info-data col-md-4">
+                    <i class="fas fa-exchange-alt" title="{{lang.category}}"></i>
+                    &nbsp;
+                    <span title="{{lang[row.categoryId]}}">{{lang[row.categoryId]}}</span>
+                </span>
+                <span class="sub-info-data col-md-4  text-center">
+                    <i class="fas fa-user" title="{{lang.contact}}"></i>
+                    &nbsp;
+                    <span [title]="'Pierre BRUNEL'">Pierre BRUNEL</span>
+                </span>
+                <span class="sub-info-data col-md-4 text-right">
+                    <i class="fas fa-calendar" title="{{lang.creationDate}}"></i>
+                    &nbsp;
+                    <span [title]="row.documentDate | fullDate">{{row.documentDate | timeAgo : 'full' | ucfirst}}</span>
+                </span>
+                <span class="sub-info-data col-md-6">
+                    <i class="fas fa-sitemap" title="{{lang.getAssignee}}"></i>
+                    &nbsp;
+                    <span
+                        [title]="row.destUserLabel + ' (' + row.destinationLabel +  ')'">{{row.destUserLabel + ' (' + row.destinationLabel +  ')'}}</span>
+                </span>
+                <span class="sub-info-data col-md-6 text-right" *ngIf="row.visaCircuit.length > 0">
+                    <i class="fas fa-list-ol" title="{{lang.visaWorkflow}}"></i>
+                    &nbsp;
+                    <span [title]="getUsersVisaCircuit(row)">{{getUsersVisaCircuit(row)}}</span>
+                </span>
+            </div>
+            <div class="main-info">
+                <span class="main-info-status">
+                    <mat-icon title="{{row.statusLabel}}" [ngStyle]="{'color': row.priorityColor}" color="primary"
+                        class="{{row.statusImage.charAt(0)}}{{row.statusImage.charAt(1)}} {{row.statusImage}} {{row.statusImage.charAt(0)}}{{row.statusImage.charAt(1)}}-2x">
+                    </mat-icon>
+                    <span *ngIf="row.confidentiality" class="watermark">{{lang.confidential}}</span>
+                </span>
+                <span class="main-info-data" style="width:200px;text-align:center;">
+                    {{row.chrono}}
+                </span>
+                <span class="main-info-data" style="font-weight:bold;flex:1;"
+                    [class.undefined]="row.subject == lang.undefined"
+                    title="{{row.subject}}">{{row.subject | shorten: 150: '...'}}</span>
+                <span class="main-info-data">
+                    <button mat-icon-button color="warn" [title]="lang.unlink" (click)="$event.stopPropagation();unlinkResource(row)">
+                        <mat-icon class="fa fa-unlink fa-2x" aria-hidden="true"></mat-icon>
+                    </button>
+                </span>
+            </div>
         </mat-cell>
     </ng-container>
-    <ng-container matColumnDef="actions">
-        <mat-cell *matCellDef="let element" style="justify-content: flex-end;">
-            <button mat-icon-button color="warn" (click)="$event.stopPropagation();">
-                <mat-icon class="fa fa-unlink fa-2x" aria-hidden="true"></mat-icon>
-            </button>
-        </mat-cell>
-    </ng-container>
-    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
+    <mat-row *matRowDef="let row; columns: displayedColumns;" (mouseenter)="viewThumbnail(row);" (mouseleave)="closeThumbnail();"></mat-row>
 </mat-table>
-<!--<button mat-fab class="linkRes" color="primary" [title]="lang.link" (click)="createAttachment()">-->
-<!--    <mat-icon class="fa fa-link" style="height:auto;"></mat-icon>-->
-<!--</button>-->
+<button mat-fab class="linkRes" color="primary" [title]="lang.linkResource" (click)="openSearchResourceModal()">
+    <mat-icon class="fa fa-link" style="height:auto;"></mat-icon>
+</button>
diff --git a/src/frontend/app/linkedResource/linked-resource-list.component.scss b/src/frontend/app/linkedResource/linked-resource-list.component.scss
index ce72680c5b5..9971bbcc135 100644
--- a/src/frontend/app/linkedResource/linked-resource-list.component.scss
+++ b/src/frontend/app/linkedResource/linked-resource-list.component.scss
@@ -7,4 +7,30 @@
     bottom: 10px;
     margin-left: 10px;
     margin-top: 10px;
+}
+
+.main-info {
+    width:100%;
+}
+
+.sub-info {
+    width: 100%;
+    display: block;
+}
+
+.sub-info-data {
+    white-space: pre;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    padding-left: 5px;
+    padding-right: 5px;
+}
+
+.watermark {
+    position: absolute;
+    left: 50%;
+    transform: translateX(-50%) rotate(-20deg);
+    color: red;
+    font-weight: bold;
+    opacity: 0.6;
 }
\ No newline at end of file
diff --git a/src/frontend/app/linkedResource/linked-resource-list.component.ts b/src/frontend/app/linkedResource/linked-resource-list.component.ts
index 1b9c8622e29..f3c12913301 100644
--- a/src/frontend/app/linkedResource/linked-resource-list.component.ts
+++ b/src/frontend/app/linkedResource/linked-resource-list.component.ts
@@ -6,8 +6,11 @@ import { MatPaginator } from '@angular/material/paginator';
 import { MatSort } from '@angular/material/sort';
 import { MatTableDataSource } from '@angular/material/table';
 import { AppService } from '../../service/app.service';
-import { tap, catchError, finalize } from 'rxjs/operators';
+import { tap, catchError, finalize, map, filter, exhaustMap } from 'rxjs/operators';
 import { of } from 'rxjs';
+import { ConfirmComponent } from '../../plugins/modal/confirm.component';
+import { MatDialog } from '@angular/material';
+import { LinkResourceModalComponent } from './linkResourceModal/link-resource-modal.component';
 
 declare function $j(selector: any): any;
 
@@ -24,7 +27,55 @@ export class LinkedResourceListComponent implements OnInit {
 
     linkedResources: any[] = [];
     dataSource: any;
-    displayedColumns = ['resId', 'actions'];
+    displayedColumns = ['resId'];
+
+    thumbnailUrl: string = '';
+
+    displayedMainData: any = [
+        {
+            'value': 'chrono',
+            'cssClasses': ['softColorData', 'align_centerData', 'chronoData'],
+            'icon': ''
+        },
+        {
+            'value': 'subject',
+            'cssClasses': ['longData'],
+            'icon': ''
+        }
+    ];
+
+    displayedSubData: any = [
+        { 
+            "value": "getCategory", 
+            "cssClasses": [], 
+            "icon": "fa-exchange-alt", 
+            "displayValue": "incoming" 
+        }, 
+       { 
+           "value": "getAssignee", 
+           "cssClasses": [], 
+           "icon": "fa-sitemap", 
+           "displayValue": "Georges GRAND (Direction Générale des Services)" 
+        }, 
+        { 
+            "value": "getRecipients", 
+            "cssClasses": [], 
+            "icon": "fa-user", 
+            "displayValue": ["Patricia PETIT"] 
+        }, 
+        { 
+            "value": "getSenders",
+            "cssClasses": [], 
+            "icon": "fa-book", 
+            "displayValue": ["Pierre BRUNEL "] 
+        }, 
+        { 
+            "value": "getCreationAndProcessLimitDates", 
+            "cssClasses": ["align_rightData"], 
+            "icon": "fa-calendar", 
+            "displayValue": { "creationDate": "2020-01-27 10:45:01.012295" } 
+        }
+    ];
 
     @Input('resId') resId: number;
 
@@ -34,7 +85,8 @@ export class LinkedResourceListComponent implements OnInit {
     constructor(
         public http: HttpClient,
         private notify: NotificationService,
-        public appService: AppService
+        public appService: AppService,
+        public dialog: MatDialog,
     ) { }
 
     ngOnInit(): void {
@@ -43,7 +95,7 @@ export class LinkedResourceListComponent implements OnInit {
     }
 
     initLinkedResources() {
-        this.http.get('../../rest/resources/100/linkedResources').pipe(
+        this.http.get(`../../rest/resources/${this.resId}/linkedResources`).pipe(
             tap((data: any) => {
                 this.linkedResources = data.linkedResources;
                 setTimeout(() => {
@@ -59,4 +111,43 @@ export class LinkedResourceListComponent implements OnInit {
             })
         ).subscribe();
     }
+
+    getUsersVisaCircuit(row: any) {
+        return row.visaCircuit.map((item: any) => item.userLabel);
+    }
+
+    unlinkResource(row: any) {
+        const dialogRef = this.dialog.open(ConfirmComponent, { autoFocus: false, disableClose: true, data: { title: this.lang.unlink, msg: this.lang.confirmAction } });
+
+        dialogRef.afterClosed().pipe(
+            filter((data: string) => data === 'ok'),
+            exhaustMap(() => this.http.delete(`../../rest/resources/${this.resId}/linkedResources/${row.resId}`)),
+            tap(() => {
+                this.linkedResources = this.linkedResources.filter(resource => resource.resId !== row.resId);
+                this.dataSource = new MatTableDataSource(this.linkedResources);
+                this.dataSource.paginator = this.paginator;
+                this.dataSource.sort = this.sort;
+                this.notify.success(this.lang.resourceUnlinked);
+            }),
+            catchError((err: any) => {
+                this.notify.handleSoftErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
+
+    viewThumbnail(row: any) {
+        //if (row.hasDocument) {
+            this.thumbnailUrl = '../../rest/resources/' + row.resId + '/thumbnail';
+            $j('#viewThumbnail').show();
+        //}
+    }
+
+    closeThumbnail() {
+        $j('#viewThumbnail').hide();
+    }
+
+    openSearchResourceModal() {
+        this.dialog.open(LinkResourceModalComponent, { data: { resId: this.resId } });
+    }
 }
diff --git a/src/frontend/app/list/basket-list.component.ts b/src/frontend/app/list/basket-list.component.ts
index 63e9089e694..6a0b10c1d37 100755
--- a/src/frontend/app/list/basket-list.component.ts
+++ b/src/frontend/app/list/basket-list.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit, ViewChild, EventEmitter, ViewContainerRef, ApplicationRef } from '@angular/core';
+import { Component, OnInit, ViewChild, EventEmitter, ViewContainerRef } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
 import { LANG } from '../translate.component';
 import { merge, Observable, of as observableOf, Subject, Subscription, of } from 'rxjs';
diff --git a/src/frontend/app/process/process.component.html b/src/frontend/app/process/process.component.html
index 58510d3fc65..e9b56e286b0 100644
--- a/src/frontend/app/process/process.component.html
+++ b/src/frontend/app/process/process.component.html
@@ -76,7 +76,7 @@
                 <app-notes-list *ngIf="currentTool === 'notes' && !loading" #appNotesList [editMode]="true"
                     [resId]="currentResourceInformations.resId">
                 </app-notes-list>
-                <app-linked-resource-list *ngIf="currentTool === 'link' && !loading" #appLinkedResourceList
+                <app-linked-resource-list *ngIf="currentTool === 'linkedResources' && !loading" #appLinkedResourceList
                     [resId]="currentResourceInformations.resId">
                 </app-linked-resource-list>
                 <app-diffusions-list *ngIf="currentTool === 'diffusionList' && !loading" #appDiffusionsList
@@ -252,7 +252,7 @@
         <app-notes-list *ngIf="modal.id === 'notes' && !loading" #appNotesList [editMode]="true"
             [resId]="currentResourceInformations.resId">
         </app-notes-list>
-        <app-linked-resource-list *ngIf="modal.id === 'link' && !loading" #appLinkedResourceList
+        <app-linked-resource-list *ngIf="modal.id === 'linkedResources' && !loading" #appLinkedResourceList
             [resId]="currentResourceInformations.resId"></app-linked-resource-list>
         <app-diffusions-list *ngIf="modal.id === 'diffusionList' && !loading" #appDiffusionsList [adminMode]="false"
             [resId]="currentResourceInformations.resId" [expanded]="true">
diff --git a/src/frontend/app/process/process.component.ts b/src/frontend/app/process/process.component.ts
index 0c99d62cd99..becd45d63e3 100755
--- a/src/frontend/app/process/process.component.ts
+++ b/src/frontend/app/process/process.component.ts
@@ -84,7 +84,7 @@ export class ProcessComponent implements OnInit {
             count: 0
         },
         {
-            id: 'link',
+            id: 'linkedResources',
             icon: 'fas fa-link',
             label: this.lang.links,
             count: 0
diff --git a/src/frontend/lang/lang-en.ts b/src/frontend/lang/lang-en.ts
index e2bbee1388d..8cf19b40c4d 100755
--- a/src/frontend/lang/lang-en.ts
+++ b/src/frontend/lang/lang-en.ts
@@ -1451,4 +1451,6 @@ export const LANG_EN = {
     "systemActions": "System action(s)",
     "viewAllHistory": "View all history",
     "viewActionsHistory": "View only actions in history",
+    "unlink": "Unlink this resource",
+    "linkResource": "Link to a new resource",
 };
diff --git a/src/frontend/lang/lang-fr.ts b/src/frontend/lang/lang-fr.ts
index 72c1c141fbe..5ead8df0f13 100755
--- a/src/frontend/lang/lang-fr.ts
+++ b/src/frontend/lang/lang-fr.ts
@@ -1491,4 +1491,6 @@ export const LANG_FR = {
     "systemActions": "Événement(s) système",
     "viewAllHistory": "Afficher tout l'historique",
     "viewActionsHistory": "Afficher l'historique des actions",
+    "unlink": "Enlever la liaison",
+    "linkResource": "Lier un nouveau courrier",
 };
diff --git a/src/frontend/lang/lang-nl.ts b/src/frontend/lang/lang-nl.ts
index 9cf76cecc56..02ada84bb9e 100755
--- a/src/frontend/lang/lang-nl.ts
+++ b/src/frontend/lang/lang-nl.ts
@@ -1476,4 +1476,6 @@ export const LANG_NL = {
     "systemActions": "System action(s)", //_TO_TRANSLATE
     "viewAllHistory": "View all history", //_TO_TRANSLATE
     "viewActionsHistory": "View only actions in history", //_TO_TRANSLATE
+    "unlink": "Unlink this resource", //_TO_TRANSLATE
+    "linkResource": "Link to a new resource", //_TO_TRANSLATE
 };
-- 
GitLab