Add UI support for adding tosca artifact types
[sdc.git] / catalog-ui / src / app / ng2 / pages / composition / interface-operatons / interface-operations.component.ts
1 /*
2 * ============LICENSE_START=======================================================
3 * SDC
4 * ================================================================================
5 *  Copyright (C) 2021 Nordix Foundation. All rights reserved.
6 *  ================================================================================
7 *  Licensed under the Apache License, Version 2.0 (the "License");
8 *  you may not use this file except in compliance with the License.
9 *  You may obtain a copy of the License at
10 *
11 *        http://www.apache.org/licenses/LICENSE-2.0
12 *  Unless required by applicable law or agreed to in writing, software
13 *  distributed under the License is distributed on an "AS IS" BASIS,
14 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 *  See the License for the specific language governing permissions and
16 *  limitations under the License.
17 *
18 *  SPDX-License-Identifier: Apache-2.0
19 *  ============LICENSE_END=========================================================
20 */
21
22 import {Component, ComponentRef, Inject, Input} from '@angular/core';
23 import {TopologyTemplateService} from '../../../services/component-services/topology-template.service';
24 import {TranslateService} from "../../../shared/translator/translate.service";
25 import {ModalService } from 'app/ng2/services/modal.service';
26 import { ModalComponent } from 'app/ng2/components/ui/modal/modal.component';
27 import {
28   Component as TopologyTemplate
29 } from "../../../../models/components/component";
30 import {PluginsService} from "app/ng2/services/plugins.service";
31 import {SelectedComponentType} from "../common/store/graph.actions";
32
33 import {WorkspaceService} from "../../workspace/workspace.service";
34 import {
35   ComponentInstanceInterfaceModel,
36   InterfaceOperationModel
37 } from "../../../../models/interfaceOperation";
38 import {
39   InterfaceOperationHandlerComponent
40 } from "./operation-creator/interface-operation-handler.component";
41
42 import {
43   ButtonModel,
44   ComponentMetadata,
45   InterfaceModel,
46   InputBEModel,
47   ModalModel,
48   ComponentInstance, ArtifactModel
49 } from 'app/models';
50 import {ArtifactGroupType} from "../../../../utils/constants";
51 import {DropdownValue} from "../../../components/ui/form-components/dropdown/ui-element-dropdown.component";
52 import {ToscaArtifactService} from "../../../services/tosca-artifact.service";
53 import {ToscaArtifactModel} from "../../../../models/toscaArtifact";
54
55 export class UIInterfaceOperationModel extends InterfaceOperationModel {
56   isCollapsed: boolean = true;
57   isEllipsis: boolean;
58   MAX_LENGTH = 75;
59   constructor(operation: InterfaceOperationModel) {
60     super(operation);
61
62     if (!operation.description) {
63       this.description = '';
64     }
65
66     if (this.description.length > this.MAX_LENGTH) {
67       this.isEllipsis = true;
68     } else {
69       this.isEllipsis = false;
70     }
71   }
72
73   getDescriptionEllipsis(): string {
74     if (this.isCollapsed && this.description.length > this.MAX_LENGTH) {
75       return this.description.substr(0, this.MAX_LENGTH - 3) + '...';
76     }
77     return this.description;
78   }
79
80   toggleCollapsed(e) {
81     e.stopPropagation();
82     this.isCollapsed = !this.isCollapsed;
83   }
84 }
85
86 class ModalTranslation {
87   EDIT_TITLE: string;
88   CANCEL_BUTTON: string;
89   SAVE_BUTTON: string;
90
91   constructor(private TranslateService: TranslateService) {
92     this.TranslateService.languageChangedObservable.subscribe(lang => {
93       this.EDIT_TITLE = this.TranslateService.translate('INTERFACE_EDIT_TITLE');
94       this.CANCEL_BUTTON = this.TranslateService.translate("INTERFACE_CANCEL_BUTTON");
95       this.SAVE_BUTTON = this.TranslateService.translate("INTERFACE_SAVE_BUTTON");
96     });
97   }
98 }
99
100 export class UIInterfaceModel extends ComponentInstanceInterfaceModel {
101   isCollapsed: boolean = false;
102
103   constructor(interf?: any) {
104     super(interf);
105     this.operations = _.map(
106         this.operations,
107         (operation) => new UIInterfaceOperationModel(operation)
108     );
109   }
110
111   toggleCollapse() {
112     this.isCollapsed = !this.isCollapsed;
113   }
114 }
115
116 @Component({
117   selector: 'app-interface-operations',
118   templateUrl: './interface-operations.component.html',
119   styleUrls: ['./interface-operations.component.less'],
120   providers: [ModalService, TranslateService]
121 })
122 export class InterfaceOperationsComponent {
123   interfaces: UIInterfaceModel[];
124   inputs: Array<InputBEModel>;
125   isLoading: boolean;
126   interfaceTypes: { [interfaceType: string]: string[] };
127   topologyTemplate: TopologyTemplate;
128   componentMetaData: ComponentMetadata;
129   componentInstanceSelected: ComponentInstance;
130   modalInstance: ComponentRef<ModalComponent>;
131   modalTranslation: ModalTranslation;
132   componentInstancesInterfaces: Map<string, InterfaceModel[]>;
133
134   deploymentArtifactsFilePath: Array<DropdownValue> = [];
135   toscaArtifactTypes: Array<DropdownValue> = [];
136
137   @Input() component: ComponentInstance;
138   @Input() readonly: boolean;
139   @Input() enableMenuItems: Function;
140   @Input() disableMenuItems: Function;
141   @Input() componentType: SelectedComponentType;
142
143
144   constructor(
145       private TranslateService: TranslateService,
146       private PluginsService: PluginsService,
147       private topologyTemplateService: TopologyTemplateService,
148       private toscaArtifactService: ToscaArtifactService,
149       private modalServiceNg2: ModalService,
150       private workspaceService: WorkspaceService,
151       @Inject("Notification") private Notification: any,
152   ) {
153     this.modalTranslation = new ModalTranslation(TranslateService);
154   }
155
156   ngOnInit(): void {
157     this.componentMetaData = this.workspaceService.metadata;
158     this.loadComponentInstances();
159     this.loadDeployedArtifacts();
160     this.loadToscaArtifacts()
161   }
162
163   private loadComponentInstances() {
164     this.isLoading = true;
165     this.topologyTemplateService.getComponentInstances(this.componentMetaData.componentType, this.componentMetaData.uniqueId)
166     .subscribe((response) => {
167       this.componentInstanceSelected = response.componentInstances.find(ci => ci.uniqueId === this.component.uniqueId);
168       this.initComponentInstanceInterfaceOperations();
169       this.isLoading = false;
170     });
171   }
172
173   private initComponentInstanceInterfaceOperations() {
174     this.initInterfaces(this.componentInstanceSelected.interfaces);
175     this.sortInterfaces();
176   }
177
178   private initInterfaces(interfaces: ComponentInstanceInterfaceModel[]): void {
179     this.interfaces = _.map(interfaces, (interfaceModel) => new UIInterfaceModel(interfaceModel));
180   }
181
182   private sortInterfaces(): void {
183     this.interfaces = _.filter(this.interfaces, (interf) => interf.operations && interf.operations.length > 0); // remove empty interfaces
184     this.interfaces.sort((a, b) => a.type.localeCompare(b.type)); // sort interfaces alphabetically
185     _.forEach(this.interfaces, (interf) => {
186       interf.operations.sort((a, b) => a.name.localeCompare(b.name)); // sort operations alphabetically
187     });
188   }
189
190   collapseAll(value: boolean = true): void {
191     _.forEach(this.interfaces, (interf) => {
192       interf.isCollapsed = value;
193     });
194   }
195
196   isAllCollapsed(): boolean {
197     return _.every(this.interfaces, (interf) => interf.isCollapsed);
198   }
199
200   isAllExpanded(): boolean {
201     return _.every(this.interfaces, (interf) => !interf.isCollapsed);
202   }
203
204   isListEmpty(): boolean {
205     return _.filter(
206         this.interfaces,
207         (interf) => interf.operations && interf.operations.length > 0
208     ).length === 0;
209   }
210
211   private enableOrDisableSaveButton = (): boolean => {
212     return this.modalInstance.instance.dynamicContent.instance.readonly;
213   }
214
215   onSelectInterfaceOperation(interfaceModel: UIInterfaceModel, operation: InterfaceOperationModel) {
216     const cancelButton: ButtonModel = new ButtonModel(this.modalTranslation.CANCEL_BUTTON, 'outline white', this.cancelAndCloseModal);
217     const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue', () =>
218         this.updateInterfaceOperation(), this.enableOrDisableSaveButton);
219     const modalModel: ModalModel = new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', [saveButton, cancelButton], 'custom');
220     this.modalInstance = this.modalServiceNg2.createCustomModal(modalModel);
221
222     this.modalServiceNg2.addDynamicContentToModal(
223         this.modalInstance,
224         InterfaceOperationHandlerComponent,
225         {
226           deploymentArtifactsFilePath: this.deploymentArtifactsFilePath,
227           toscaArtifactTypes: this.toscaArtifactTypes,
228           selectedInterface: interfaceModel,
229           selectedInterfaceOperation: operation,
230           validityChangedCallback: this.enableOrDisableSaveButton
231         }
232     );
233     this.modalInstance.instance.open();
234   }
235
236   private cancelAndCloseModal = () => {
237     this.loadComponentInstances();
238     return this.modalServiceNg2.closeCurrentModal();
239   }
240
241   private updateInterfaceOperation() {
242     this.isLoading = true;
243     let operationUpdated = this.modalInstance.instance.dynamicContent.instance.operationToUpdate;
244     this.topologyTemplateService.updateComponentInstanceInterfaceOperation(
245         this.componentMetaData.uniqueId,
246         this.componentMetaData.componentType,
247         this.componentInstanceSelected.uniqueId,
248         operationUpdated).subscribe((updatedComponentInstance: ComponentInstance) => {
249           this.componentInstanceSelected = new ComponentInstance(updatedComponentInstance);
250           this.initComponentInstanceInterfaceOperations();
251     });
252     this.modalServiceNg2.closeCurrentModal();
253     this.isLoading = false;
254   }
255
256   loadDeployedArtifacts() {
257     this.topologyTemplateService.getArtifactsByType(this.componentMetaData.componentType, this.componentMetaData.uniqueId, ArtifactGroupType.DEPLOYMENT)
258     .subscribe(response => {
259       let artifactsDeployment = response.deploymentArtifacts;
260       if (artifactsDeployment) {
261         let deploymentArtifactsFound = <ArtifactModel[]>_.values(artifactsDeployment)
262         deploymentArtifactsFound.forEach(value => {
263           this.deploymentArtifactsFilePath.push(new DropdownValue(value, value.artifactType.concat('->').concat(value.artifactName)));
264         });
265       }}, error => {
266       this.Notification.error({
267         message: 'Failed to Load the Deployed Artifacts:' + error,
268         title: 'Failure'
269       });
270     });
271   }
272
273   loadToscaArtifacts() {
274     this.toscaArtifactService.getToscaArtifacts(this.componentMetaData.model).subscribe(response => {
275       if (response) {
276         let toscaArtifactsFound = <ToscaArtifactModel[]>_.values(response);
277         toscaArtifactsFound.forEach(value => this.toscaArtifactTypes.push(new DropdownValue(value, value.type)));
278       }
279     }, error => {
280       this.Notification.error({
281         message: 'Failed to Load Tosca Artifacts:' + error,
282         title: 'Failure'
283       });
284     });
285   }
286
287 }