Catalog alignment
[sdc.git] / catalog-ui / src / app / ng2 / pages / interface-operation / interface-operation.page.component.ts
1 import * as _ from "lodash";
2 import { Component, Input, Output, ComponentRef, 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 'app/ng2/components/ui/modal/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: ComponentRef<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
156         Observable.forkJoin(
157             this.ComponentServiceNg2.getInterfaceOperations(this.component),
158             this.ComponentServiceNg2.getComponentInputs(this.component),
159             this.ComponentServiceNg2.getInterfaceTypes(this.component),
160             this.ComponentServiceNg2.getCapabilitiesAndRequirements(this.component.componentType, this.component.uniqueId)
161         ).subscribe((response: any[]) => {
162             const callback = (workflows) => {
163                 this.isLoading = false;
164                 this.initInterfaces(response[0].interfaces);
165                 this.sortInterfaces();
166                 this.inputs = response[1].inputs;
167                 this.interfaceTypes = response[2];
168                 this.workflows = workflows;
169                 this.capabilities = response[3].capabilities;
170             };
171             if (this.enableWorkflowAssociation && this.workflowIsOnline) {
172                 this.WorkflowServiceNg2.getWorkflows().subscribe(
173                     callback,
174                     (err) => {
175                         this.workflowIsOnline = false;
176                         callback([]);
177                     }
178                 );
179             } else {
180                 callback([]);
181             }
182         });
183     }
184
185     initInterfaces(interfaces: InterfaceModel[]): void {
186         this.interfaces = _.map(interfaces, (interf) => new UIInterfaceModel(interf));
187     }
188
189     sortInterfaces(): void {
190         this.interfaces = _.filter(this.interfaces, (interf) => interf.operations && interf.operations.length > 0); // remove empty interfaces
191         this.interfaces.sort((a, b) => a.type.localeCompare(b.type)); // sort interfaces alphabetically
192         _.forEach(this.interfaces, (interf) => {
193             interf.operations.sort((a, b) => a.name.localeCompare(b.name)); // sort operations alphabetically
194         });
195     }
196
197     collapseAll(value: boolean = true): void {
198         _.forEach(this.interfaces, (interf) => {
199             interf.isCollapsed = value;
200         });
201     }
202
203     isAllCollapsed(): boolean {
204         return _.every(this.interfaces, (interf) => interf.isCollapsed);
205     }
206
207     isAllExpanded(): boolean {
208         return _.every(this.interfaces, (interf) => !interf.isCollapsed);
209     }
210
211     isListEmpty(): boolean {
212         return _.filter(
213             this.interfaces,
214             (interf) => interf.operations && interf.operations.length > 0
215         ).length === 0;
216     }
217
218     getDisabled = (): boolean => {
219         return !this.modalInstance.instance.dynamicContent.instance.checkFormValidForSubmit();
220     }
221
222     onEditOperation = (operation?: OperationModel): void => {
223
224         const modalMap = {
225             create: {
226                 modalTitle: this.modalTranslation.CREATE_TITLE,
227                 saveBtnText: this.modalTranslation.CREATE_BUTTON,
228                 submitCallback: this.createOperation,
229             },
230             edit: {
231                 modalTitle: this.modalTranslation.EDIT_TITLE,
232                 saveBtnText: this.modalTranslation.SAVE_BUTTON,
233                 submitCallback: this.updateOperation,
234             }
235         };
236
237         const modalData = operation ? modalMap.edit : modalMap.create;
238
239         if (this.openOperation) {
240             if (operation ? operation.uniqueId === this.openOperation.uniqueId : !this.openOperation.uniqueId) {
241                 operation = this.openOperation;
242             }
243         }
244
245         const cancelButton: IModalButtonComponent = {
246             id: 'cancelButton',
247             text: this.modalTranslation.CANCEL_BUTTON,
248             type: 'secondary',
249             size: 'small',
250             closeModal: true,
251             callback: () => {
252                 this.openOperation = null;
253             },
254         };
255
256         const saveButton: IModalButtonComponent = {
257             id: 'saveButton',
258             text: modalData.saveBtnText,
259             type: 'primary',
260             size: 'small',
261             closeModal: true,
262             callback: () => {
263                 const modalInstance = this.ModalServiceSdcUI.getCurrentInstance().innerModalContent.instance;
264
265                 const {operation, isUsingExistingWF, createParamLists} = modalInstance;
266                 createParamLists();
267                 this.openOperation = {...operation};
268
269                 if (this.enableWorkflowAssociation && !isUsingExistingWF()) {
270                     operation.workflowId = null;
271                     operation.workflowVersionId = null;
272                 }
273
274                 modalData.submitCallback(operation);
275             }
276         };
277
278         const input: OperationCreatorInput = {
279             allWorkflows: this.workflows,
280             inputOperation: operation,
281             interfaces: this.interfaces,
282             inputProperties: this.inputs,
283             enableWorkflowAssociation: this.enableWorkflowAssociation,
284             readonly: this.readonly,
285             interfaceTypes: this.interfaceTypes,
286             validityChangedCallback: this.enableOrDisableSaveButton,
287             workflowIsOnline: this.workflowIsOnline,
288             capabilities: _.filter(CapabilitiesGroup.getFlattenedCapabilities(this.capabilities), (capability: Capability) => capability.ownerId === this.component.uniqueId)
289         };
290
291         const modalConfig: IModalConfig = {
292             title: modalData.modalTitle,
293             size: 'l',
294             type: 'custom',
295             buttons: [saveButton, cancelButton] as IModalButtonComponent[]
296         };
297
298         this.ModalServiceSdcUI.openCustomModal(modalConfig, OperationCreatorComponent, input);
299
300     }
301
302     onRemoveOperation = (event: Event, operation: OperationModel): void => {
303         event.stopPropagation();
304
305         const confirmCallback = () => {
306             this.ComponentServiceNg2
307                 .deleteInterfaceOperation(this.component, operation)
308                 .subscribe(() => {
309                     const curInterf = _.find(this.interfaces, (interf) => interf.type === operation.interfaceType);
310                     const index = _.findIndex(curInterf.operations, (el) => el.uniqueId === operation.uniqueId);
311                     curInterf.operations.splice(index, 1);
312                     if (!curInterf.operations.length) {
313                         const interfIndex = _.findIndex(this.interfaces, (interf) => interf.type === operation.interfaceType);
314                         this.interfaces.splice(interfIndex, 1);
315                     }
316                 });
317         }
318
319         this.ModalServiceSdcUI.openAlertModal(
320             this.modalTranslation.DELETE_TITLE,
321             this.modalTranslation.deleteText(operation.name),
322             this.modalTranslation.DELETE_BUTTON,
323             confirmCallback,
324             'deleteOperationModal'
325         );
326     }
327
328     private enableOrDisableSaveButton = (shouldEnable: boolean): void => {
329         const saveButton: ModalButtonComponent = this.ModalServiceSdcUI.getCurrentInstance().getButtonById('saveButton');
330         saveButton.disabled = !shouldEnable;
331     }
332
333     private createOperation = (operation: OperationModel): void => {
334         this.ComponentServiceNg2.createInterfaceOperation(this.component, operation).subscribe((response: OperationModel) => {
335             this.openOperation = null;
336
337             let curInterf = _.find(
338                 this.interfaces,
339                 (interf) => interf.type === operation.interfaceType
340             );
341
342             if (!curInterf) {
343                 curInterf = new UIInterfaceModel({
344                     type: response.interfaceType,
345                     uniqueId: response.uniqueId,
346                     operations: []
347                 });
348                 this.interfaces.push(curInterf);
349             }
350
351             const newOpModel = new UIOperationModel(response);
352             curInterf.operations.push(newOpModel);
353             this.sortInterfaces();
354
355             if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL && operation.artifactData) {
356                 this.ComponentServiceNg2.uploadInterfaceOperationArtifact(this.component, newOpModel, operation).subscribe();
357             } else if (response.workflowId && operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXISTING) {
358                 this.WorkflowServiceNg2.associateWorkflowArtifact(this.component, response).subscribe();
359             } else if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.NEW) {
360                 this.$state.go('workspace.plugins', { path: 'workflowDesigner' });
361             }
362         });
363     }
364
365     private updateOperation = (operation: OperationModel): void => {
366         this.ComponentServiceNg2.updateInterfaceOperation(this.component, operation).subscribe((newOperation: OperationModel) => {
367             this.openOperation = null;
368
369             let oldOpIndex;
370             let oldInterf;
371             _.forEach(this.interfaces, (interf) => {
372                 _.forEach(interf.operations, (op) => {
373                     if (op.uniqueId === newOperation.uniqueId) {
374                         oldInterf = interf;
375                         oldOpIndex = _.findIndex(interf.operations, (el) => el.uniqueId === op.uniqueId);
376                     }
377                 })
378             });
379             oldInterf.operations.splice(oldOpIndex, 1);
380
381             const newInterf = _.find(this.interfaces, (interf) => interf.type === operation.interfaceType);
382             const newOpModel = new UIOperationModel(newOperation);
383             newInterf.operations.push(newOpModel);
384             this.sortInterfaces();
385
386             if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL && operation.artifactData) {
387                 this.ComponentServiceNg2.uploadInterfaceOperationArtifact(this.component, newOpModel, operation).subscribe();
388             } else if (newOperation.workflowId && operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXISTING) {
389                 this.WorkflowServiceNg2.associateWorkflowArtifact(this.component, newOperation).subscribe();
390             }
391         });
392     }
393
394 }