4f93e727eccd9fc49875423869ee34d48b762296
[sdc.git] / catalog-ui / src / app / ng2 / pages / interface-operation / interface-operation.page.component.ts
1 import * as _ from "lodash";
2 import { Component, Input, Inject } from '@angular/core';
3 import {Component as IComponent } from 'app/models/components/component';
4
5 import { SdcConfigToken, ISdcConfig } from "app/ng2/config/sdc-config.config";
6 import {TranslateService } from "app/ng2/shared/translator/translate.service";
7
8 import {Observable } from "rxjs/Observable";
9
10 import { ModalComponent } from 'onap-ui-angular/dist/modals/modal.component';
11 import {ModalService } from 'app/ng2/services/modal.service';
12 import {
13     InputBEModel,
14     OperationModel,
15     InterfaceModel,
16     WORKFLOW_ASSOCIATION_OPTIONS,
17     CapabilitiesGroup,
18     Capability
19 } from 'app/models';
20
21 // import {SdcUiComponents } from 'sdc-ui/lib/angular';
22 // import {ModalButtonComponent } from 'sdc-ui/lib/angular/components';
23 // import { IModalButtonComponent, IModalConfig } from 'sdc-ui/lib/angular/modals/models/modal-config';
24
25 import {ComponentServiceNg2 } from 'app/ng2/services/component-services/component.service';
26 import {PluginsService } from 'app/ng2/services/plugins.service';
27 import {WorkflowServiceNg2 } from 'app/ng2/services/workflow.service';
28
29 import { OperationCreatorComponent, OperationCreatorInput } from 'app/ng2/pages/interface-operation/operation-creator/operation-creator.component';
30 import { IModalButtonComponent } from 'onap-ui-angular';
31 import { ModalButtonComponent } from 'onap-ui-angular';
32 import { IModalConfig } from 'onap-ui-angular';
33 import { SdcUiServices } from 'onap-ui-angular';
34
35 export class UIOperationModel extends OperationModel {
36     isCollapsed: boolean = true;
37     isEllipsis: boolean;
38     MAX_LENGTH = 75;
39     _description: string;
40
41     constructor(operation: OperationModel) {
42         super(operation);
43
44         if (!operation.description) {
45             this.description = '';
46         }
47
48         if (this.description.length > this.MAX_LENGTH) {
49             this.isEllipsis = true;
50         } else {
51             this.isEllipsis = false;
52         }
53     }
54
55     getDescriptionEllipsis(): string {
56         if (this.isCollapsed && this.description.length > this.MAX_LENGTH) {
57             return this.description.substr(0, this.MAX_LENGTH - 3) + '...';
58         }
59         return this.description;
60     }
61
62     toggleCollapsed(e) {
63         e.stopPropagation();
64         this.isCollapsed = !this.isCollapsed;
65     }
66 }
67
68 // tslint:disable-next-line:max-classes-per-file
69 class ModalTranslation {
70     CREATE_TITLE: string;
71     EDIT_TITLE: string;
72     DELETE_TITLE: string;
73     CANCEL_BUTTON: string;
74     SAVE_BUTTON: string;
75     CREATE_BUTTON: string;
76     DELETE_BUTTON: string;
77     deleteText: Function;
78
79     constructor(private TranslateService: TranslateService) {
80         this.TranslateService.languageChangedObservable.subscribe(lang => {
81             this.CREATE_TITLE = this.TranslateService.translate("INTERFACE_CREATE_TITLE");
82             this.EDIT_TITLE = this.TranslateService.translate('INTERFACE_EDIT_TITLE');
83             this.DELETE_TITLE = this.TranslateService.translate("INTERFACE_DELETE_TITLE");
84             this.CANCEL_BUTTON = this.TranslateService.translate("INTERFACE_CANCEL_BUTTON");
85             this.SAVE_BUTTON = this.TranslateService.translate("INTERFACE_SAVE_BUTTON");
86             this.CREATE_BUTTON = this.TranslateService.translate("INTERFACE_CREATE_BUTTON");
87             this.DELETE_BUTTON = this.TranslateService.translate("INTERFACE_DELETE_BUTTON");
88             this.deleteText = (operationName) => this.TranslateService.translate("INTERFACE_DELETE_TEXT", {operationName});
89         });
90     }
91 }
92
93 // tslint:disable-next-line:max-classes-per-file
94 export class UIInterfaceModel extends InterfaceModel {
95     isCollapsed: boolean = false;
96
97     constructor(interf?: any) {
98         super(interf);
99         this.operations = _.map(
100             this.operations,
101             (operation) => new UIOperationModel(operation)
102         );
103     }
104
105     toggleCollapse() {
106         this.isCollapsed = !this.isCollapsed;
107     }
108 }
109
110 // tslint:disable-next-line:max-classes-per-file
111 @Component({
112     selector: 'interface-operation',
113     templateUrl: './interface-operation.page.component.html',
114     styleUrls: ['interface-operation.page.component.less'],
115     providers: [ModalService, TranslateService]
116 })
117
118 export class InterfaceOperationComponent {
119
120     interfaces: UIInterfaceModel[];
121     modalInstance: ModalComponent;
122     openOperation: OperationModel;
123     enableWorkflowAssociation: boolean;
124     inputs: InputBEModel[];
125     isLoading: boolean;
126     interfaceTypes: { [interfaceType: string]: string[] };
127     modalTranslation: ModalTranslation;
128     workflowIsOnline: boolean;
129     workflows: any[];
130     capabilities: CapabilitiesGroup;
131
132     @Input() component: IComponent;
133     @Input() readonly: boolean;
134     @Input() enableMenuItems: Function;
135     @Input() disableMenuItems: Function;
136
137     constructor(
138         @Inject(SdcConfigToken) private sdcConfig: ISdcConfig,
139         @Inject("$state") private $state: ng.ui.IStateService,
140         private TranslateService: TranslateService,
141         private PluginsService: PluginsService,
142         private ComponentServiceNg2: ComponentServiceNg2,
143         private WorkflowServiceNg2: WorkflowServiceNg2,
144         private ModalServiceNg2: ModalService,
145         private ModalServiceSdcUI: SdcUiServices.ModalService
146         
147     ) {
148         this.enableWorkflowAssociation = sdcConfig.enableWorkflowAssociation;
149         this.modalTranslation = new ModalTranslation(TranslateService);
150     }
151
152     ngOnInit(): void {
153         this.isLoading = true;
154         this.workflowIsOnline = !_.isUndefined(this.PluginsService.getPluginByStateUrl('workflowDesigner'));
155         Observable.forkJoin(
156             this.ComponentServiceNg2.getInterfaceOperations(this.component),
157             this.ComponentServiceNg2.getComponentInputs(this.component),
158             this.ComponentServiceNg2.getInterfaceTypes(this.component),
159             this.ComponentServiceNg2.getCapabilitiesAndRequirements(this.component.componentType, this.component.uniqueId)
160         ).subscribe((response: any[]) => {
161             const callback = (workflows) => {
162                 this.isLoading = false;
163                 this.initInterfaces(response[0].interfaces);
164                 this.sortInterfaces();
165                 this.inputs = response[1].inputs;
166                 this.interfaceTypes = response[2];
167                 this.workflows = (workflows.items) ? workflows.items: workflows;
168                 this.capabilities = response[3].capabilities;
169             };
170             if (this.enableWorkflowAssociation && this.workflowIsOnline) {
171                 this.WorkflowServiceNg2.getWorkflows().subscribe(
172                     callback,
173                     (err) => {
174                         this.workflowIsOnline = false;
175                         callback([]);
176                     }
177                 );
178             } else {
179                 callback([]);
180             }
181         });
182     }
183
184     initInterfaces(interfaces: InterfaceModel[]): void {
185         this.interfaces = _.map(interfaces, (interf) => new UIInterfaceModel(interf));
186     }
187
188     sortInterfaces(): void {
189         this.interfaces = _.filter(this.interfaces, (interf) => interf.operations && interf.operations.length > 0); // remove empty interfaces
190         this.interfaces.sort((a, b) => a.type.localeCompare(b.type)); // sort interfaces alphabetically
191         _.forEach(this.interfaces, (interf) => {
192             interf.operations.sort((a, b) => a.name.localeCompare(b.name)); // sort operations alphabetically
193         });
194     }
195
196     collapseAll(value: boolean = true): void {
197         _.forEach(this.interfaces, (interf) => {
198             interf.isCollapsed = value;
199         });
200     }
201
202     isAllCollapsed(): boolean {
203         return _.every(this.interfaces, (interf) => interf.isCollapsed);
204     }
205
206     isAllExpanded(): boolean {
207         return _.every(this.interfaces, (interf) => !interf.isCollapsed);
208     }
209
210     isListEmpty(): boolean {
211         return _.filter(
212             this.interfaces,
213             (interf) => interf.operations && interf.operations.length > 0
214         ).length === 0;
215     }
216
217     getDisabled = (): boolean => {
218         return !this.modalInstance.innerModalContent.instance.checkFormValidForSubmit();
219     }
220
221     onEditOperation = (operation?: OperationModel): void => {
222
223         const modalMap = {
224             create: {
225                 modalTitle: this.modalTranslation.CREATE_TITLE,
226                 saveBtnText: this.modalTranslation.CREATE_BUTTON,
227                 submitCallback: this.createOperation,
228             },
229             edit: {
230                 modalTitle: this.modalTranslation.EDIT_TITLE,
231                 saveBtnText: this.modalTranslation.SAVE_BUTTON,
232                 submitCallback: this.updateOperation,
233             }
234         };
235
236         const modalData = operation ? modalMap.edit : modalMap.create;
237
238         if (this.openOperation) {
239             if (operation ? operation.uniqueId === this.openOperation.uniqueId : !this.openOperation.uniqueId) {
240                 operation = this.openOperation;
241             }
242         }
243
244         const cancelButton: IModalButtonComponent = {
245             id: 'cancelButton',
246             text: this.modalTranslation.CANCEL_BUTTON,
247             type: 'secondary',
248             size: 'small',
249             closeModal: true,
250             callback: () => {
251                 this.openOperation = null;
252             },
253         };
254
255         const saveButton: IModalButtonComponent = {
256             id: 'saveButton',
257             text: modalData.saveBtnText,
258             type: 'primary',
259             size: 'small',
260             closeModal: true,
261             callback: () => {
262                 const modalInstance = this.modalInstance.innerModalContent.instance;
263
264                 const {operation, isUsingExistingWF, createParamLists} = modalInstance;
265                 createParamLists();
266                 this.openOperation = {...operation};
267
268                 if (this.enableWorkflowAssociation && !isUsingExistingWF()) {
269                     operation.workflowId = null;
270                     operation.workflowVersionId = null;
271                 }
272
273                 modalData.submitCallback(operation);
274             }
275         };
276
277         const input: OperationCreatorInput = {
278             allWorkflows: this.workflows,
279             inputOperation: operation,
280             interfaces: this.interfaces,
281             inputProperties: this.inputs,
282             enableWorkflowAssociation: this.enableWorkflowAssociation,
283             readonly: this.readonly,
284             interfaceTypes: this.interfaceTypes,
285             validityChangedCallback: this.enableOrDisableSaveButton,
286             workflowIsOnline: this.workflowIsOnline,
287             capabilities: _.filter(CapabilitiesGroup.getFlattenedCapabilities(this.capabilities), (capability: Capability) => capability.ownerId === this.component.uniqueId)
288         };
289
290         const modalConfig: IModalConfig = {
291             title: modalData.modalTitle,
292             size: 'l',
293             type: 'custom',
294             buttons: [saveButton, cancelButton] as IModalButtonComponent[]
295         };
296
297         this.modalInstance = this.ModalServiceSdcUI.openCustomModal(modalConfig, OperationCreatorComponent, input);
298     }
299
300     onRemoveOperation = (event: Event, operation: OperationModel): void => {
301         event.stopPropagation();
302
303         const deleteButton: IModalButtonComponent = {
304             id: 'deleteButton',
305             text: this.modalTranslation.DELETE_BUTTON,
306             type: 'primary',
307             size: 'small',
308             closeModal: true,
309             callback: () => {
310                 this.ComponentServiceNg2
311                     .deleteInterfaceOperation(this.component, operation)
312                     .subscribe(() => {
313                         const curInterf = _.find(this.interfaces, (interf) => interf.type === operation.interfaceType);
314                         const index = _.findIndex(curInterf.operations, (el) => el.uniqueId === operation.uniqueId);
315                         curInterf.operations.splice(index, 1);
316                         if (!curInterf.operations.length) {
317                             const interfIndex = _.findIndex(this.interfaces, (interf) => interf.type === operation.interfaceType);
318                             this.interfaces.splice(interfIndex, 1);
319                         }
320                     });
321             }
322         };
323
324         const cancelButton: IModalButtonComponent = {
325             id: 'cancelButton',
326             text: this.modalTranslation.CANCEL_BUTTON,
327             type: 'secondary',
328             size: 'small',
329             closeModal: true,
330             callback: () => {
331                 this.openOperation = null;
332             },
333         };
334
335         this.ModalServiceSdcUI.openWarningModal(
336             this.modalTranslation.DELETE_TITLE,
337             this.modalTranslation.deleteText(operation.name),
338             'deleteOperationModal',
339             [deleteButton, cancelButton],
340         );
341     }
342
343     private enableOrDisableSaveButton = (shouldEnable: boolean): void => {
344         const saveButton = this.modalInstance.getButtonById('saveButton');
345         saveButton.disabled = !shouldEnable;
346     }
347
348     private createOperation = (operation: OperationModel): void => {
349         this.ComponentServiceNg2.createInterfaceOperation(this.component, operation).subscribe((response: OperationModel) => {
350             this.openOperation = null;
351
352             let curInterf = _.find(
353                 this.interfaces,
354                 (interf) => interf.type === operation.interfaceType
355             );
356
357             if (!curInterf) {
358                 curInterf = new UIInterfaceModel({
359                     type: response.interfaceType,
360                     uniqueId: response.uniqueId,
361                     operations: []
362                 });
363                 this.interfaces.push(curInterf);
364             }
365
366             const newOpModel = new UIOperationModel(response);
367             curInterf.operations.push(newOpModel);
368             this.sortInterfaces();
369
370             if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL && operation.artifactData) {
371                 this.ComponentServiceNg2.uploadInterfaceOperationArtifact(this.component, newOpModel, operation).subscribe();
372             } else if (response.workflowId && operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXISTING) {
373                 this.WorkflowServiceNg2.associateWorkflowArtifact(this.component, response).subscribe();
374             } else if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.NEW) {
375                 this.$state.go('workspace.plugins', { path: 'workflowDesigner' });
376             }
377         });
378     }
379
380     private updateOperation = (operation: OperationModel): void => {
381         this.ComponentServiceNg2.updateInterfaceOperation(this.component, operation).subscribe((newOperation: OperationModel) => {
382             this.openOperation = null;
383
384             let oldOpIndex;
385             let oldInterf;
386             _.forEach(this.interfaces, (interf) => {
387                 _.forEach(interf.operations, (op) => {
388                     if (op.uniqueId === newOperation.uniqueId) {
389                         oldInterf = interf;
390                         oldOpIndex = _.findIndex(interf.operations, (el) => el.uniqueId === op.uniqueId);
391                     }
392                 })
393             });
394             oldInterf.operations.splice(oldOpIndex, 1);
395
396             const newInterf = _.find(this.interfaces, (interf) => interf.type === operation.interfaceType);
397             const newOpModel = new UIOperationModel(newOperation);
398             newInterf.operations.push(newOpModel);
399             this.sortInterfaces();
400
401             if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL && operation.artifactData) {
402                 this.ComponentServiceNg2.uploadInterfaceOperationArtifact(this.component, newOpModel, operation).subscribe();
403             } else if (newOperation.workflowId && operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXISTING) {
404                 this.WorkflowServiceNg2.associateWorkflowArtifact(this.component, newOperation).subscribe();
405             }
406         });
407     }
408
409 }