diff --git a/core/xml/actions_pages.xml b/core/xml/actions_pages.xml index ffb627bb595a7ff66e1255dbd92954329505e5ab..032b0398f839f683acce705bfbc1950bfe05e90a 100755 --- a/core/xml/actions_pages.xml +++ b/core/xml/actions_pages.xml @@ -17,7 +17,7 @@ An action page is described in a ACTIONPAGE tag : <LABEL>_REDIRECTION</LABEL> <NAME>redirect</NAME> <DESC>_REDIRECTION_DESC</DESC> - <component>v1Action</component> + <component>redirectAction</component> <ORIGIN>module</ORIGIN> <MODULE>entities</MODULE> <KEYWORD>redirect</KEYWORD> diff --git a/src/frontend/app/actions/actions-list.component.ts b/src/frontend/app/actions/actions-list.component.ts index 93acb06b90ee33aa54c7e7311dfa40544a3b71b2..1d5ecf36b6d853d31ca0051340d76d4bf9429fa2 100644 --- a/src/frontend/app/actions/actions-list.component.ts +++ b/src/frontend/app/actions/actions-list.component.ts @@ -16,6 +16,7 @@ import { UpdateDepartureDateActionComponent } from './update-departure-date-acti // import { ProcessActionComponent } from './process-action/process-action.component'; import { Router } from '@angular/router'; import { ViewDocActionComponent } from './view-doc-action/view-doc-action.component'; +import { RedirectActionComponent } from './redirect-action/redirect-action.component'; @Component({ selector: 'app-actions-list', @@ -299,6 +300,18 @@ export class ActionsListComponent implements OnInit { }); } + redirectAction() { + this.dialog.open(RedirectActionComponent, { + data: { + contextMode: this.contextMode, + contextChrono: this.contextMenuTitle, + selectedRes: this.selectedRes, + action: this.currentAction, + currentBasketInfo: this.currentBasketInfo + } + }); + } + // CALL GENERIC ACTION V1 v1Action() { location.hash = ""; diff --git a/src/frontend/app/actions/redirect-action/redirect-action.component.html b/src/frontend/app/actions/redirect-action/redirect-action.component.html new file mode 100644 index 0000000000000000000000000000000000000000..99c7a667e46d705a5251368a7a7390cd03efd08d --- /dev/null +++ b/src/frontend/app/actions/redirect-action/redirect-action.component.html @@ -0,0 +1,51 @@ +<h1 mat-dialog-title>"{{data.action.label_action}}"</h1> +<div mat-dialog-content [class.fullWidth]="redirectMode == 'entity'"> + <div *ngIf="loading" class="loading" style="display:flex;height:100%;"> + <mat-spinner style="margin:auto;"></mat-spinner> + </div> + <div class="chooseMode" *ngIf="redirectMode == ''"> + <div> + <button mat-raised-button color="primary" (click)="loadEntities()">Vers un service</button> + </div> + <div> + <button mat-raised-button color="primary" (click)="redirectMode = 'user'">Vers un utilisateur</button> + </div> + </div> + <div *ngIf="redirectMode == 'entity'" class="row" style="display: flex;"> + <div class="redirectContent" style="flex:2"> + <h2>Rediriger vers :</h2> + <div class="contentEntities"> + <div id="jstree"></div> + </div> + </div> + <div class="redirectContent" style="flex:1"> + <h2 title="{{currentEntity.entity_label}}" >Liste de diffusion "{{currentEntity.entity_label}}" :</h2> + <div class="contentEntities"> + <app-diffusions-list #appDiffusionsList [injectDatas]="injectDatasParam"></app-diffusions-list> + </div> + </div> + </div> + <div *ngIf="redirectMode == 'user'" class="row"> + <mat-form-field appearance="outline" floatLabel="never" [style.fontSize.px]="10"> + <input class="metaSearch" type="text" matInput placeholder="Sélectionner un nouvel attributaire"> + </mat-form-field> + <div class="redirectContent" style="flex:2"> + <h2 style="top:-5px;">Nouvel atributaire :</h2> + <div class="contentUser"> + <mat-list> + <mat-list-item> + <mat-icon mat-list-icon class="fa fa-2x fa-user" color="primary"></mat-icon> + <h4 mat-line>{{destUser.item_firstname}} + {{destUser.item_lastname}}</h4> + <p mat-line style="opacity:0.5;"> + {{destUser.item_entity}} </p> + </mat-list-item> + </mat-list> + </div> + </div> + </div> +</div> +<div mat-dialog-actions class="actions"> + <button *ngIf="redirectMode != ''" mat-raised-button mat-button color="primary" [disabled]="loading" (click)="onSubmit()">{{lang.validate}}</button> + <button mat-raised-button mat-button [disabled]="loading" [mat-dialog-close]="">{{lang.cancel}}</button> +</div> \ No newline at end of file diff --git a/src/frontend/app/actions/redirect-action/redirect-action.component.scss b/src/frontend/app/actions/redirect-action/redirect-action.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..eb77aaf58ae74940a7260e391452c6e59917800d --- /dev/null +++ b/src/frontend/app/actions/redirect-action/redirect-action.component.scss @@ -0,0 +1,97 @@ +.mat-dialog-content { + position: relative; + overflow: hidden; +} + +.fullWidth { + width: 70vw; +} + +.mat-dialog-actions, +.mat-dialog-title { + justify-content: center; + text-align: center; +} + +.highlight { + font-size: 110%; +} + +.loading { + display: flex; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: #ffffffb3; + z-index: 1; + overflow: hidden; +} + +.redirectContent { + position: relative; + + h2 { + white-space: pre; + overflow: hidden; + max-width: 85%; + text-overflow: ellipsis; + z-index: 1; + font-size: 10px; + font-weight: bold; + background: white; + position: absolute; + top: 5px; + letter-spacing: 3px; + left: 30px; + padding: 0px; + margin: 0px; + padding-left: 5px; + padding-right: 5px; + color: #135f7f; + } +} + +.contentEntities { + background: white; + border-radius: 4px; + border: solid 1px #ccc; + margin: 10px; + padding: 10px; + overflow: auto; + height: 60vh; +} + +.contentUser { + background: white; + border-radius: 4px; + border: solid 1px #ccc; + margin: 10px; + padding: 10px; +} + +.contentEntitiesList { + background: white; + margin: 10px; + padding: 10px; + overflow: auto; + height: 60vh; +} + +.chooseMode { + display: flex; + justify-content: center; + + div { + display: flex; + flex: 1; + justify-content: center; + } + + button { + font-size: 20px; + padding: 10px; + width: 200px; + } +} \ No newline at end of file diff --git a/src/frontend/app/actions/redirect-action/redirect-action.component.ts b/src/frontend/app/actions/redirect-action/redirect-action.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..b90fdf8fa2b500ee6795aa423e86bc01944d7954 --- /dev/null +++ b/src/frontend/app/actions/redirect-action/redirect-action.component.ts @@ -0,0 +1,115 @@ +import { Component, OnInit, Inject, ViewChild } from '@angular/core'; +import { LANG } from '../../translate.component'; +import { NotificationService } from '../../notification.service'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material'; +import { HttpClient } from '@angular/common/http'; +import { DiffusionsListComponent } from '../../diffusions/diffusions-list.component'; + +declare function $j(selector: any): any; + +@Component({ + templateUrl: "redirect-action.component.html", + styleUrls: ['redirect-action.component.scss'], + providers: [NotificationService], +}) +export class RedirectActionComponent implements OnInit { + + lang: any = LANG; + loading: boolean = false; + + entities: any[] = []; + injectDatasParam = { + modes: ['diffList'], + entities: ['DSI'], + editable: [true] + }; + destUser: any = { + item_firstname : 'Patricia', + item_lastname : 'PETIT', + item_entity : 'Pôle Jeunesse et Sport', + }; + currentEntity : any = { + 'entity_label' : '' + }; + redirectMode = ''; + + @ViewChild('appDiffusionsList') appDiffusionsList: DiffusionsListComponent; + + constructor(public http: HttpClient, private notify: NotificationService, public dialogRef: MatDialogRef<RedirectActionComponent>, @Inject(MAT_DIALOG_DATA) public data: any) { } + + ngOnInit(): void { } + + loadEntities() { + this.redirectMode = 'entity'; + + this.http.get("../../rest/entities") + .subscribe((data: any) => { + this.entities = data['entities']; + this.loading = false; + console.log(this.entities); + setTimeout(() => { + $j('#jstree').jstree({ + "checkbox": { + 'deselect_all': true, + "three_state": false //no cascade selection + }, + 'core': { + 'themes': { + 'name': 'proton', + 'responsive': true + }, + 'multiple': false, + 'data': this.entities, + }, + "plugins": ["checkbox", "search", "sort"] + }); + $j('#jstree').jstree('select_node', this.entities[0]); + var to: any = false; + $j('#jstree_search').keyup(function () { + if (to) { clearTimeout(to); } + to = setTimeout(function () { + var v = $j('#jstree_search').val(); + $j('#jstree').jstree(true).search(v); + }, 250); + }); + $j('#jstree') + // listen for event + .on('select_node.jstree', (e: any, data: any) => { + this.selectEntity(); + this.appDiffusionsList.loadListModel('toto'); + + }).on('deselect_node.jstree', (e: any, data: any) => { + + + }) + // create the instance + .jstree(); + }, 0); + setTimeout(() => { + $j('#jstree').jstree('select_node', this.entities[0]); + this.selectEntity(); + + }, 200); + + }, () => { + location.href = "index.php"; + }); + } + + selectEntity() { + const ind = this.entities.map((e:any) => { return e.entity_id; }).indexOf($j('#jstree').jstree(true).get_selected()[0]); + this.currentEntity = this.entities[ind]; + } + + onSubmit(): void { + this.loading = true; + /*this.http.put('../../rest/resourcesList/users/' + this.data.currentBasketInfo.ownerId + '/groups/' + this.data.currentBasketInfo.groupId + '/baskets/' + this.data.currentBasketInfo.basketId + '/actions/' + this.data.action.id, {resources : this.data.selectedRes}) + .subscribe((data: any) => { + this.loading = false; + this.dialogRef.close('success'); + }, (err: any) => { + this.notify.handleErrors(err); + this.loading = false; + });*/ + } +} diff --git a/src/frontend/app/app.module.ts b/src/frontend/app/app.module.ts index c2dcf3abbf98c6db8e31dceb9738a6e50a34874f..59c82853ccf33dcd99cc95c8656a77e0b249726b 100755 --- a/src/frontend/app/app.module.ts +++ b/src/frontend/app/app.module.ts @@ -35,6 +35,7 @@ import { CloseAndIndexActionComponent } from './actions/close-and-in import { UpdateDepartureDateActionComponent } from './actions/update-departure-date-action/update-departure-date-action.component'; import { ProcessActionComponent } from './actions/process-action/process-action.component'; import { ViewDocActionComponent } from './actions/view-doc-action/view-doc-action.component'; +import { RedirectActionComponent } from './actions/redirect-action/redirect-action.component'; import { FiltersListComponent } from './list/filters/filters-list.component'; import { FiltersToolComponent } from './list/filters/filters-tool.component'; @@ -87,6 +88,7 @@ import { DiffusionsListComponent } from './diffusions/diffusions-lis UpdateDepartureDateActionComponent, ProcessActionComponent, ViewDocActionComponent, + RedirectActionComponent, ActionsListComponent, ], entryComponents: [ @@ -108,6 +110,7 @@ import { DiffusionsListComponent } from './diffusions/diffusions-lis CloseMailActionComponent, UpdateDepartureDateActionComponent, ProcessActionComponent, + RedirectActionComponent, ViewDocActionComponent ], providers: [ ShortcutMenuService, HeaderService, FiltersListService ], diff --git a/src/frontend/app/diffusions/diffusions-list.component.html b/src/frontend/app/diffusions/diffusions-list.component.html index 62137219879ca0c84c13309668b238117cf70267..4834869113bc290c9d97f2b43e8b6346cd9a9a86 100644 --- a/src/frontend/app/diffusions/diffusions-list.component.html +++ b/src/frontend/app/diffusions/diffusions-list.component.html @@ -1,33 +1,51 @@ <div *ngIf="loading" style="display:flex;height:100%;"> <mat-spinner style="margin:auto;"></mat-spinner> </div> -<div style="text-align:center;font-weight:bold;opacity:0.3;">{{data.chrono}} - {{lang.diffusionList}}</div> -<mat-list *ngIf="!loading"> - <mat-tab-group> - <mat-tab label="{{lang.diffusionList}}"> - <div *ngIf="listinstance.length == 0" style="text-align:center;font-size:24px;font-weight:bold;opacity:0.3;"> - AUCUNE LISTE DE DIFFUSION - </div> - <ng-container *ngFor="let role of roles"> - <h3 mat-subheader>{{role}}</h3> - <mat-list-item *ngFor="let diffusion of listinstance[role]"> +<!--<div style="text-align:center;font-weight:bold;opacity:0.3;">{{data.chrono}} - {{lang.diffusionList}}</div>--> +<mat-list *ngIf="!loading"> + <div *ngIf="diffList.length == 0" style="text-align:center;font-size:24px;font-weight:bold;opacity:0.3;"> + AUCUNE LISTE DE DIFFUSION + </div> + <mat-form-field appearance="outline" floatLabel="never" [style.fontSize.px]="10"> + <input class="metaSearch" type="text" matInput placeholder="Ajouter une personne / une entité"> + </mat-form-field> + <div cdkDropListGroup> + <ng-container *ngFor="let role of availableRoles"> + <h3 mat-subheader>{{role.label}}</h3> + <mat-divider></mat-divider> + <div cdkDropList [id]="role.id" #dataAvailableList="cdkDropList" [cdkDropListData]="diffList[role.id].items" + class="cdk-list" (cdkDropListDropped)="drop($event)" [cdkDropListDisabled]="role.id == 'dest'"> + <div *ngIf="diffList[role.id].items.length === 0" style="opacity: 0.5;text-align: center;font-size: 10px;padding: 10px;"> + Acune personne + </div> + <mat-list-item *ngFor="let diffusion of diffList[role.id].items;let i=index" cdkDrag class="columns" + [cdkDragDisabled]="diffusion.item_type == 'entity_id'" [class.notDraggable]="diffusion.item_type == 'entity_id' || role.id == 'dest'"> <mat-icon *ngIf="diffusion.item_type == 'user_id'" mat-list-icon class="fa fa-2x" [ngClass]="[diffusion.item_mode == 'copy' ? 'fa-users' : 'fa-user']" color="primary"></mat-icon> <h4 mat-line *ngIf="diffusion.item_type == 'user_id'">{{diffusion.item_firstname}} {{diffusion.item_lastname}}</h4> <p mat-line *ngIf="diffusion.item_type == 'user_id'" style="opacity:0.5;"> {{diffusion.item_entity}} </p> - + <button mat-icon-button *ngIf="role.id != 'dest'" (click)="deleteItem(role.id,i)"> + <mat-icon class="fa fa-times" color="warn"></mat-icon> + </button> <mat-icon *ngIf="diffusion.item_type == 'entity_id'" mat-list-icon class="fa fa-sitemap fa-2x" color="primary"></mat-icon> <h4 *ngIf="diffusion.item_type == 'entity_id'" mat-line>{{diffusion.item_entity}}</h4> <p *ngIf="diffusion.item_type == 'entity_id'" mat-line style="opacity:0.5;"> </p> </mat-list-item> - <mat-divider></mat-divider> - </ng-container> + </div> + </ng-container> + </div> + + + + <!--<mat-tab-group> + <mat-tab label="{{lang.diffusionList}}" *ngIf="injectDatas.modes.indexOf('diffList') > -1"> + </mat-tab> - <mat-tab label="Circuit de visa" [disabled]='!tabVisaCircuit'> + <mat-tab label="Circuit de visa" *ngIf="injectDatas.modes.indexOf('visa') > -1" [disabled]='!tabVisaCircuit'> <div *ngIf="visaCircuit.length == 0" style="text-align:center;font-size:24px;font-weight:bold;opacity:0.3;"> AUCUN CIRCUIT DE VISA </div> @@ -51,7 +69,7 @@ </mat-list-item> </ng-container> </mat-tab> - <mat-tab label="Circuit d'avis" [disabled]='!tabAvisCircuit'> + <mat-tab label="Circuit d'avis" *ngIf="injectDatas.modes.indexOf('avis') > -1" [disabled]='!tabAvisCircuit'> <div *ngIf="avisCircuit.length == 0" style="text-align:center;font-size:24px;font-weight:bold;opacity:0.3;"> AUCUN CIRCUIT D'AVIS </div> @@ -73,7 +91,7 @@ </mat-list-item> </ng-container> </mat-tab> - </mat-tab-group> + </mat-tab-group>--> </mat-list> \ No newline at end of file diff --git a/src/frontend/app/diffusions/diffusions-list.component.scss b/src/frontend/app/diffusions/diffusions-list.component.scss index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fccf31c4dc939880ead09f3cd70300304c0fa4b4 100644 --- a/src/frontend/app/diffusions/diffusions-list.component.scss +++ b/src/frontend/app/diffusions/diffusions-list.component.scss @@ -0,0 +1,36 @@ +.cdk-drag-preview { + box-sizing: border-box; + border-radius: 4px; + box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); + background: white; + padding: 10px; + .mat-icon { + display: none; + } +} + +.cdk-drag-placeholder { + opacity: 0; +} + +.cdk-drag-animating { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} + +.columns:last-child { + border: none; +} + +.cdk-list.cdk-drop-list-dragging .columns:not(.cdk-drag-placeholder) { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} + +.columns { + cursor: move; +} + +.notDraggable { + cursor: not-allowed; +} \ No newline at end of file diff --git a/src/frontend/app/diffusions/diffusions-list.component.ts b/src/frontend/app/diffusions/diffusions-list.component.ts index bd85751b5c5d5d5278c8843c30c8ff5a594b7dc2..0d2b87b2e41b810368d94e96479cce3f02380a2d 100644 --- a/src/frontend/app/diffusions/diffusions-list.component.ts +++ b/src/frontend/app/diffusions/diffusions-list.component.ts @@ -1,10 +1,8 @@ -import { Component, AfterViewInit, Inject } from '@angular/core'; +import { Component, Input, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { LANG } from '../translate.component'; import { NotificationService } from '../notification.service'; -import { MAT_BOTTOM_SHEET_DATA } from '@angular/material'; - -declare function $j(selector: any): any; +import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; @Component({ selector: 'app-diffusions-list', @@ -12,43 +10,135 @@ declare function $j(selector: any): any; styleUrls: ['diffusions-list.component.scss'], providers: [NotificationService] }) -export class DiffusionsListComponent implements AfterViewInit { +export class DiffusionsListComponent implements OnInit { lang: any = LANG; listinstance: any = []; - visaCircuit: any; - avisCircuit: any; + visaCircuit: any = []; + avisCircuit: any = []; roles: any = []; loading: boolean = true; tabVisaCircuit: boolean = false; tabAvisCircuit: boolean = false; + data: any; + availableRoles: any[] = []; + + diffList: any = {}; + + @Input('injectDatas') injectDatas: any; - constructor(public http: HttpClient, @Inject(MAT_BOTTOM_SHEET_DATA) public data: any) { } + constructor(public http: HttpClient, private notify: NotificationService) { } - ngAfterViewInit() { - this.http.get("../../rest/res/" + this.data.resId + "/listinstance") + ngOnInit(): void { + this.http.get("../../rest/listTemplates/types/entity_id/roles") .subscribe((data: any) => { - if (data != null) { - this.roles = Object.keys(data); - this.listinstance = data; + data['roles'].forEach((element: any) => { + if (element.id == 'cc') { + element.id = 'copy'; + } + if (element.available) { + this.availableRoles.push(element); + this.diffList[element.id] = { + 'label': element.label, + 'items': [] + }; + } + }); + console.log(this.diffList); + if (!this.injectDatas) { + this.loadListinstance(100); + } else { + this.loadListModel('COU'); + } + }, (err: any) => { + this.notify.error(err.error.errors); + }); + } + + drop(event: CdkDragDrop<string[]>) { + if (event.previousContainer === event.container) { + //moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); + } else if (event.container.id != 'dest') { + console.log(event); + transferArrayItem(event.previousContainer.data, + event.container.data, + event.previousIndex, + event.currentIndex); + } + } + + loadListModel(entityId: string) { + this.loading = true; + + this.availableRoles.forEach(element => { + this.diffList[element.id].items = []; + }); - this.http.get("../../rest/res/" + this.data.resId + "/visaCircuit") - .subscribe((data: any) => { - this.visaCircuit = data; - if (this.visaCircuit.length > 0) { - this.tabVisaCircuit = true; - } - - this.http.get("../../rest/res/" + this.data.resId + "/avisCircuit") - .subscribe((data: any) => { - this.avisCircuit = data; - if (this.avisCircuit.length > 0) { - this.tabAvisCircuit = true; - } - }); - }); - this.loading = false; + // TO DO : ADD ROUTE + /*this.http.get("../../rest/???") + .subscribe((data: any) => { + this.loading = false; + });*/ + + this.diffList['dest'].items.push( + { + "listinstance_id": 20, + "sequence": 0, + "item_mode": "dest", + "item_id": "bbain", + "item_type": "user_id", + "item_firstname": "Barbara", + "item_lastname": "BAIN", + "item_entity": "P\u00f4le Jeunesse et Sport", + "viewed": 0, + "process_date": null, + "process_comment": "", + "signatory": false, + "requested_signature": false }); + this.diffList['copy'].items.push( + { + "listinstance_id": 21, + "sequence": 0, + "item_mode": "copy", + "item_id": "DSG", + "item_type": "entity_id", + "item_entity": "Secr\u00e9tariat G\u00e9n\u00e9ral", + "viewed": 0, + "process_date": null, + "process_comment": null, + "signatory": false, + "requested_signature": false + } + ); + this.diffList['copy'].items.push( + { + "listinstance_id": 20, + "sequence": 0, + "item_mode": "copy", + "item_id": "bboule", + "item_type": "user_id", + "item_firstname": "Bruno", + "item_lastname": "Boule", + "item_entity": "Archives", + "viewed": 0, + "process_date": null, + "process_comment": "", + "signatory": false, + "requested_signature": false + }); + this.loading = false; + //this.roles = Object.keys(this.data); + //this.listinstance = this.data; + //this.loading = false; + } + + loadListinstance(resId: number) { + + } + + deleteItem(roleId:string, index: number) { + this.diffList[roleId].items.splice(index, 1); } } \ No newline at end of file