8dd17f60e273cbc38768cefe5ac9aec28c407c82
[sdc.git] / catalog-ui / src / app / ng2 / pages / interface-definition / interface-definition.page.component.ts
1 /*
2 * ============LICENSE_START=======================================================
3 * SDC
4 * ================================================================================
5 *  Copyright (C) 2022 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 import {Component, ComponentRef, Inject, Input} from '@angular/core';
22 import {Component as IComponent} from 'app/models/components/component';
23
24 import {ISdcConfig, SdcConfigToken} from "app/ng2/config/sdc-config.config";
25 import {TranslateService} from "app/ng2/shared/translator/translate.service";
26
27 import {ModalComponent} from 'app/ng2/components/ui/modal/modal.component';
28 import {ModalService} from 'app/ng2/services/modal.service';
29 import {ButtonModel, CapabilitiesGroup, ModalModel, OperationModel} from 'app/models';
30
31 import {ComponentServiceNg2} from 'app/ng2/services/component-services/component.service';
32
33 import {SdcUiServices} from 'onap-ui-angular';
34 import {TopologyTemplateService} from "../../services/component-services/topology-template.service";
35 import {
36     ComponentInterfaceDefinitionModel,
37     InputOperationParameter,
38     InterfaceOperationModel
39 } from "../../../models/interfaceOperation";
40 import {
41     PropertyParamRowComponent
42 } from "../composition/interface-operatons/operation-creator/property-param-row/property-param-row.component";
43 import {
44     InterfaceOperationHandlerComponent
45 } from "../composition/interface-operatons/operation-creator/interface-operation-handler.component";
46 import {
47     DropdownValue
48 } from "../../components/ui/form-components/dropdown/ui-element-dropdown.component";
49 import {ToscaArtifactModel} from "../../../models/toscaArtifact";
50 import {ToscaArtifactService} from "../../services/tosca-artifact.service";
51 import {
52     UIInterfaceOperationModel
53 } from "../composition/interface-operatons/interface-operations.component";
54
55 export class UIOperationModel extends OperationModel {
56     isCollapsed: boolean = true;
57     isEllipsis: boolean;
58     MAX_LENGTH = 75;
59
60     constructor(operation: UIOperationModel) {
61         super(operation);
62
63         if (!operation.description) {
64             this.description = '';
65         }
66
67         if (this.description.length > this.MAX_LENGTH) {
68             this.isEllipsis = true;
69         } else {
70             this.isEllipsis = false;
71         }
72     }
73
74     getDescriptionEllipsis(): string {
75         if (this.isCollapsed && this.description.length > this.MAX_LENGTH) {
76             return this.description.substr(0, this.MAX_LENGTH - 3) + '...';
77         }
78         return this.description;
79     }
80
81     toggleCollapsed(e) {
82         e.stopPropagation();
83         this.isCollapsed = !this.isCollapsed;
84     }
85 }
86
87 // tslint:disable-next-line:max-classes-per-file
88 class ModalTranslation {
89     CREATE_TITLE: string;
90     EDIT_TITLE: string;
91     DELETE_TITLE: string;
92     CANCEL_BUTTON: string;
93     SAVE_BUTTON: string;
94     CREATE_BUTTON: string;
95     DELETE_BUTTON: string;
96     deleteText: Function;
97
98     constructor(private TranslateService: TranslateService) {
99         this.TranslateService.languageChangedObservable.subscribe(lang => {
100             this.CREATE_TITLE = this.TranslateService.translate("INTERFACE_CREATE_TITLE");
101             this.EDIT_TITLE = this.TranslateService.translate('INTERFACE_EDIT_TITLE');
102             this.DELETE_TITLE = this.TranslateService.translate("INTERFACE_DELETE_TITLE");
103             this.CANCEL_BUTTON = this.TranslateService.translate("INTERFACE_CANCEL_BUTTON");
104             this.SAVE_BUTTON = this.TranslateService.translate("INTERFACE_SAVE_BUTTON");
105             this.CREATE_BUTTON = this.TranslateService.translate("INTERFACE_CREATE_BUTTON");
106             this.DELETE_BUTTON = this.TranslateService.translate("INTERFACE_DELETE_BUTTON");
107             this.deleteText = (operationName) => this.TranslateService.translate("INTERFACE_DELETE_TEXT", {operationName});
108         });
109     }
110 }
111
112 export class UIInterfaceModel extends ComponentInterfaceDefinitionModel {
113     isCollapsed: boolean = false;
114
115     constructor(interf?: any) {
116         super(interf);
117         this.operations = _.map(
118             this.operations,
119             (operation) => new UIInterfaceOperationModel(operation)
120         );
121     }
122
123     toggleCollapse() {
124         this.isCollapsed = !this.isCollapsed;
125     }
126 }
127
128 // tslint:disable-next-line:max-classes-per-file
129 @Component({
130     selector: 'interface-definition',
131     templateUrl: './interface-definition.page.component.html',
132     styleUrls: ['interface-definition.page.component.less'],
133     providers: [ModalService, TranslateService]
134 })
135
136 export class InterfaceDefinitionComponent {
137
138     modalInstance: ComponentRef<ModalComponent>;
139     interfaces: UIInterfaceModel[];
140     inputs: Array<InputOperationParameter> = [];
141
142     properties: Array<PropertyParamRowComponent> = [];
143     deploymentArtifactsFilePath: Array<DropdownValue> = [];
144
145     toscaArtifactTypes: Array<DropdownValue> = [];
146     interfaceTypesTest: Array<DropdownValue> = [];
147     interfaceTypesMap: Map<string, string[]>;
148
149     isLoading: boolean;
150     interfaceTypes: { [interfaceType: string]: string[] };
151     modalTranslation: ModalTranslation;
152     workflows: any[];
153     capabilities: CapabilitiesGroup;
154     isViewOnly: boolean;
155
156     @Input() component: IComponent;
157     @Input() readonly: boolean;
158     @Input() enableMenuItems: Function;
159     @Input() disableMenuItems: Function;
160
161     constructor(
162         @Inject(SdcConfigToken) private sdcConfig: ISdcConfig,
163         @Inject("$state") private $state: ng.ui.IStateService,
164         @Inject("Notification") private notification: any,
165         private translateService: TranslateService,
166         private componentServiceNg2: ComponentServiceNg2,
167         private modalServiceNg2: ModalService,
168         private modalServiceSdcUI: SdcUiServices.ModalService,
169         private topologyTemplateService: TopologyTemplateService,
170         private toscaArtifactService: ToscaArtifactService
171     ) {
172         this.modalTranslation = new ModalTranslation(translateService);
173         this.interfaceTypesMap = new Map<string, string[]>();
174     }
175
176     ngOnInit(): void {
177         console.info("this.component.lifecycleState ", this.component.lifecycleState);
178         if (this.component) {
179             this.isViewOnly = this.component.componentMetadata.isComponentDataEditable();
180             this.initInterfaceDefinition();
181             this.loadInterfaceTypes();
182             this.loadToscaArtifacts();
183         }
184     }
185
186     private cancelAndCloseModal = () => {
187         return this.modalServiceNg2.closeCurrentModal();
188     }
189
190     private disableSaveButton = (): boolean => {
191         return this.isViewOnly ||
192             (this.isEnableAddArtifactImplementation()
193                 && (!this.modalInstance.instance.dynamicContent.instance.toscaArtifactTypeSelected ||
194                     !this.modalInstance.instance.dynamicContent.instance.artifactName)
195             );
196     }
197
198     onSelectInterfaceOperation(interfaceModel: UIInterfaceModel, operation: InterfaceOperationModel) {
199         const cancelButton: ButtonModel = new ButtonModel(this.modalTranslation.CANCEL_BUTTON, 'outline white', this.cancelAndCloseModal);
200         const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue', () =>
201             this.updateOperation(), this.disableSaveButton);
202         const interfaceDataModal: ModalModel =
203             new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', [saveButton, cancelButton], 'custom');
204         this.modalInstance = this.modalServiceNg2.createCustomModal(interfaceDataModal);
205
206         this.modalServiceNg2.addDynamicContentToModal(
207             this.modalInstance,
208             InterfaceOperationHandlerComponent,
209             {
210                 deploymentArtifactsFilePath: this.deploymentArtifactsFilePath,
211                 toscaArtifactTypes: this.toscaArtifactTypes,
212                 selectedInterface: interfaceModel,
213                 selectedInterfaceOperation: operation,
214                 validityChangedCallback: this.disableSaveButton,
215                 isViewOnly: this.isViewOnly,
216                 interfaceTypesMap: this.interfaceTypesMap,
217             });
218         this.modalInstance.instance.open();
219     }
220
221     private updateOperation = (): void => {
222         let operationToUpdate = this.modalInstance.instance.dynamicContent.instance.operationToUpdate;
223         this.componentServiceNg2.updateComponentInterfaceOperation(this.component.uniqueId, operationToUpdate)
224         .subscribe((newOperation: InterfaceOperationModel) => {
225             let oldOpIndex;
226             let oldInterf;
227             this.interfaces.forEach(interf => {
228                 interf.operations.forEach(op => {
229                     if (op.uniqueId === newOperation.uniqueId) {
230                         oldInterf = interf;
231                         oldOpIndex = interf.operations.findIndex((el) => el.uniqueId === op.uniqueId);
232                     }
233                 });
234             });
235             newOperation = this.handleEnableAddArtifactImplementation(newOperation);
236             oldInterf.operations.splice(oldOpIndex, 1);
237             oldInterf.operations.push(new InterfaceOperationModel(newOperation));
238         });
239         this.modalServiceNg2.closeCurrentModal();
240     }
241
242     private handleEnableAddArtifactImplementation = (newOperation: InterfaceOperationModel): InterfaceOperationModel => {
243         if (!this.isEnableAddArtifactImplementation()) {
244             newOperation.implementation.artifactType = null;
245             newOperation.implementation.artifactVersion = null;
246         }
247         return newOperation;
248     }
249
250     private isEnableAddArtifactImplementation = (): boolean => {
251         return this.modalInstance.instance.dynamicContent.instance.enableAddArtifactImplementation;
252     }
253
254     private initInterfaceDefinition() {
255         this.isLoading = true;
256         this.interfaces = [];
257         this.topologyTemplateService.getComponentInterfaceOperations(this.component.componentType, this.component.uniqueId)
258         .subscribe((response) => {
259             if (response.interfaces) {
260                 this.interfaces = _.map(response.interfaces, (interfaceModel) => new UIInterfaceModel(interfaceModel));
261             }
262             this.isLoading = false;
263         });
264     }
265
266     private loadToscaArtifacts() {
267         this.toscaArtifactService.getToscaArtifacts(this.component.model).subscribe(response => {
268             if (response) {
269                 let toscaArtifactsFound = <ToscaArtifactModel[]>_.values(response);
270                 toscaArtifactsFound.forEach(value => this.toscaArtifactTypes.push(new DropdownValue(value, value.type)));
271             }
272         }, error => {
273             this.notification.error({
274                 message: 'Failed to Load Tosca Artifacts:' + error,
275                 title: 'Failure'
276             });
277         });
278     }
279
280     private loadInterfaceTypes() {
281         this.componentServiceNg2.getInterfaceTypes(this.component).subscribe(response => {
282             if (response) {
283                 console.info("loadInterfaceTypes ", response);
284                 for (const interfaceType in response) {
285                     this.interfaceTypesMap.set(interfaceType, response[interfaceType]);
286                     this.interfaceTypesTest.push(new DropdownValue(interfaceType, interfaceType));
287                 }
288             }
289         }, error => {
290             this.notification.error({
291                 message: 'Failed to Load Interface Types:' + error,
292                 title: 'Failure'
293             });
294         });
295     }
296
297     collapseAll(value: boolean = true): void {
298         this.interfaces.forEach(interfaceData => {
299             interfaceData.isCollapsed = value;
300         });
301     }
302
303     isAllCollapsed(): boolean {
304         return _.every(this.interfaces, (interfaceData) => interfaceData.isCollapsed);
305     }
306
307     isAllExpanded(): boolean {
308         return _.every(this.interfaces, (interfaceData) => !interfaceData.isCollapsed);
309     }
310
311     isInterfaceListEmpty(): boolean {
312         return this.interfaces.length === 0;
313     }
314
315     isOperationListEmpty(): boolean {
316         return _.filter(this.interfaces, (interfaceData) =>
317             interfaceData.operations && interfaceData.operations.length > 0).length > 0;
318     }
319
320 }