2 * ============LICENSE_START=======================================================
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
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.
18 * SPDX-License-Identifier: Apache-2.0
19 * ============LICENSE_END=========================================================
21 import {Component, ComponentRef, Inject, Input} from '@angular/core';
22 import {Component as IComponent} from 'app/models/components/component';
23 import {WorkflowServiceNg2} from 'app/ng2/services/workflow.service';
25 import {ISdcConfig, SdcConfigToken} from "app/ng2/config/sdc-config.config";
26 import {TranslateService} from "app/ng2/shared/translator/translate.service";
27 import {IModalButtonComponent, SdcUiServices} from 'onap-ui-angular';
28 import {ModalComponent} from 'app/ng2/components/ui/modal/modal.component';
30 import {ModalService} from 'app/ng2/services/modal.service';
39 WORKFLOW_ASSOCIATION_OPTIONS
42 import {ComponentServiceNg2} from 'app/ng2/services/component-services/component.service';
43 import {TopologyTemplateService} from "../../services/component-services/topology-template.service";
44 import {InterfaceOperationModel} from "../../../models/interfaceOperation";
45 import {InterfaceOperationHandlerComponent} from "../composition/interface-operatons/operation-creator/interface-operation-handler.component";
46 import {DropdownValue} from "../../components/ui/form-components/dropdown/ui-element-dropdown.component";
47 import {ToscaArtifactModel} from "../../../models/toscaArtifact";
48 import {ToscaArtifactService} from "../../services/tosca-artifact.service";
49 import {InterfaceOperationComponent} from "../interface-operation/interface-operation.page.component";
50 import {Observable} from "rxjs/Observable";
51 import {PluginsService} from 'app/ng2/services/plugins.service';
53 export class UIOperationModel extends OperationModel {
54 isCollapsed: boolean = true;
58 constructor(operation: OperationModel) {
60 if (!operation.description) {
61 this.description = '';
64 if (this.description.length > this.MAX_LENGTH) {
65 this.isEllipsis = true;
67 this.isEllipsis = false;
71 getDescriptionEllipsis(): string {
72 if (this.isCollapsed && this.description.length > this.MAX_LENGTH) {
73 return this.description.substr(0, this.MAX_LENGTH - 3) + '...';
75 return this.description;
80 this.isCollapsed = !this.isCollapsed;
84 class ModalTranslation {
88 CANCEL_BUTTON: string;
90 CREATE_BUTTON: string;
91 DELETE_BUTTON: string;
94 constructor(private TranslateService: TranslateService) {
95 this.TranslateService.languageChangedObservable.subscribe(lang => {
96 this.CREATE_TITLE = this.TranslateService.translate("INTERFACE_CREATE_TITLE");
97 this.EDIT_TITLE = this.TranslateService.translate('INTERFACE_EDIT_TITLE');
98 this.DELETE_TITLE = this.TranslateService.translate("INTERFACE_DELETE_TITLE");
99 this.CANCEL_BUTTON = this.TranslateService.translate("INTERFACE_CANCEL_BUTTON");
100 this.SAVE_BUTTON = this.TranslateService.translate("INTERFACE_SAVE_BUTTON");
101 this.CREATE_BUTTON = this.TranslateService.translate("INTERFACE_CREATE_BUTTON");
102 this.DELETE_BUTTON = this.TranslateService.translate("INTERFACE_DELETE_BUTTON");
103 this.deleteText = (operationName) => this.TranslateService.translate("INTERFACE_DELETE_TEXT", {operationName});
108 export class UIInterfaceModel extends InterfaceModel {
109 isCollapsed: boolean = false;
111 constructor(interf?: any) {
113 if (this.operations) {
114 this.operations = this.operations.map((operation) => new UIOperationModel(operation));
119 this.isCollapsed = !this.isCollapsed;
124 selector: 'interface-definition',
125 templateUrl: './interface-definition.page.component.html',
126 styleUrls: ['interface-definition.page.component.less'],
127 providers: [ModalService, TranslateService, InterfaceOperationComponent]
129 export class InterfaceDefinitionComponent {
131 modalInstance: ComponentRef<ModalComponent>;
132 interfaces: UIInterfaceModel[];
133 inputs: InputBEModel[];
135 deploymentArtifactsFilePath: Array<DropdownValue> = [];
137 toscaArtifactTypes: Array<DropdownValue> = [];
138 interfaceTypesTest: Array<DropdownValue> = [];
139 interfaceTypesMap: Map<string, string[]>;
142 interfaceTypes: { [interfaceType: string]: string[] };
143 modalTranslation: ModalTranslation;
145 capabilities: CapabilitiesGroup;
147 openOperation: OperationModel;
148 enableWorkflowAssociation: boolean;
149 workflowIsOnline: boolean;
151 @Input() component: IComponent;
152 @Input() readonly: boolean;
153 @Input() enableMenuItems: Function;
154 @Input() disableMenuItems: Function;
157 @Inject(SdcConfigToken) private sdcConfig: ISdcConfig,
158 @Inject("$state") private $state: ng.ui.IStateService,
159 @Inject("Notification") private notification: any,
160 private translateService: TranslateService,
161 private componentServiceNg2: ComponentServiceNg2,
162 private modalServiceNg2: ModalService,
163 private modalServiceSdcUI: SdcUiServices.ModalService,
164 private topologyTemplateService: TopologyTemplateService,
165 private toscaArtifactService: ToscaArtifactService,
166 private ComponentServiceNg2: ComponentServiceNg2,
167 private WorkflowServiceNg2: WorkflowServiceNg2,
168 private ModalServiceSdcUI: SdcUiServices.ModalService,
169 private PluginsService: PluginsService
171 this.modalTranslation = new ModalTranslation(translateService);
172 this.interfaceTypesMap = new Map<string, string[]>();
176 this.isLoading = true;
177 this.interfaces = [];
178 this.workflowIsOnline = !_.isUndefined(this.PluginsService.getPluginByStateUrl('workflowDesigner'));
180 this.ComponentServiceNg2.getInterfaceOperations(this.component),
181 this.ComponentServiceNg2.getComponentInputs(this.component),
182 this.ComponentServiceNg2.getInterfaceTypes(this.component),
183 this.ComponentServiceNg2.getCapabilitiesAndRequirements(this.component.componentType, this.component.uniqueId)
184 ).subscribe((response: any[]) => {
185 const callback = (workflows) => {
186 this.isLoading = false;
187 this.initInterfaces(response[0].interfaces);
188 this.sortInterfaces();
189 this.inputs = response[1].inputs;
190 this.interfaceTypes = response[2];
191 this.workflows = (workflows.items) ? workflows.items : workflows;
192 this.capabilities = response[3].capabilities;
194 if (this.enableWorkflowAssociation && this.workflowIsOnline) {
195 this.WorkflowServiceNg2.getWorkflows().subscribe(
198 this.workflowIsOnline = false;
206 this.loadToscaArtifacts();
209 initInterfaces(interfaces: InterfaceModel[]): void {
211 this.interfaces = interfaces.map((interf) => new UIInterfaceModel(interf));
215 private cancelAndCloseModal = () => {
216 return this.modalServiceNg2.closeCurrentModal();
219 private disableSaveButton = (): boolean => {
220 let disable:boolean = true;
225 let selectedInterfaceOperation = this.modalInstance.instance.dynamicContent.instance.selectedInterfaceOperation;
226 let isInterfaceOperation:boolean = !(typeof selectedInterfaceOperation == 'undefined' || _.isEmpty(selectedInterfaceOperation));
227 let selectedInterfaceType = this.modalInstance.instance.dynamicContent.instance.selectedInterfaceType;
228 let isInterfaceType:boolean = !(typeof selectedInterfaceType == 'undefined' || _.isEmpty(selectedInterfaceType));
229 let bothSet: boolean = isInterfaceOperation && isInterfaceType;
231 let enableAddArtifactImplementation = this.modalInstance.instance.dynamicContent.instance.enableAddArtifactImplementation;
232 if(enableAddArtifactImplementation) {
233 let toscaArtifactTypeSelected = this.modalInstance.instance.dynamicContent.instance.toscaArtifactTypeSelected;
234 let isToscaArtifactType:boolean = !(typeof toscaArtifactTypeSelected == 'undefined' || _.isEmpty(toscaArtifactTypeSelected));
235 disable = !bothSet || !isToscaArtifactType;
242 onSelectInterfaceOperation(interfaceModel: UIInterfaceModel, operation: InterfaceOperationModel) {
243 const isEdit = operation !== undefined;
244 const modalButtons = [];
245 if (!this.readonly) {
246 const saveButton: ButtonModel = new ButtonModel(this.modalTranslation.SAVE_BUTTON, 'blue',
247 () => isEdit ? this.updateOperation() : this.createOperationCallback(),
248 this.disableSaveButton
250 modalButtons.push(saveButton);
252 modalButtons.push(new ButtonModel(this.modalTranslation.CANCEL_BUTTON, 'outline white', this.cancelAndCloseModal));
253 const interfaceDataModal: ModalModel =
254 new ModalModel('l', this.modalTranslation.EDIT_TITLE, '', modalButtons, 'custom');
255 this.modalInstance = this.modalServiceNg2.createCustomModal(interfaceDataModal);
257 this.modalServiceNg2.addDynamicContentToModal(
259 InterfaceOperationHandlerComponent,
261 deploymentArtifactsFilePath: this.deploymentArtifactsFilePath,
262 toscaArtifactTypes: this.toscaArtifactTypes,
263 selectedInterface: interfaceModel ? interfaceModel : new UIInterfaceModel(),
264 selectedInterfaceOperation: operation ? operation : new InterfaceOperationModel(),
265 validityChangedCallback: this.disableSaveButton,
266 isViewOnly: this.readonly,
268 interfaceTypesMap: this.interfaceTypesMap,
269 modelName: this.component.model
272 this.modalInstance.instance.open();
275 private updateOperation = (): void => {
276 this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = true;
277 const interfaceOperationHandlerComponentInstance: InterfaceOperationHandlerComponent = this.modalInstance.instance.dynamicContent.instance;
278 const operationToUpdate = this.modalInstance.instance.dynamicContent.instance.operationToUpdate;
279 const isArtifactChecked = interfaceOperationHandlerComponentInstance.enableAddArtifactImplementation;
280 if (!isArtifactChecked) {
281 const artifactName = interfaceOperationHandlerComponentInstance.artifactName ?
282 interfaceOperationHandlerComponentInstance.artifactName : '';
283 operationToUpdate.implementation = new ArtifactModel({'artifactName': artifactName, 'artifactVersion': ''} as ArtifactModel);
285 this.componentServiceNg2.updateComponentInterfaceOperation(this.component.uniqueId, operationToUpdate)
286 .subscribe((newOperation: InterfaceOperationModel) => {
289 this.interfaces.forEach(interf => {
290 interf.operations.forEach(op => {
291 if (op.uniqueId === newOperation.uniqueId) {
293 oldOpIndex = interf.operations.findIndex((el) => el.uniqueId === op.uniqueId);
297 oldInterf.operations.splice(oldOpIndex, 1);
298 oldInterf.operations.push(new InterfaceOperationModel(newOperation));
300 this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
302 this.sortInterfaces();
303 this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
304 this.modalServiceNg2.closeCurrentModal();
308 private createOperationCallback(): void {
309 this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = true;
310 const operationToUpdate = this.modalInstance.instance.dynamicContent.instance.operationToUpdate;
311 console.log('createOperationCallback', operationToUpdate);
312 console.log('this.component', this.component);
313 this.componentServiceNg2.createComponentInterfaceOperation(this.component.uniqueId, this.component.getTypeUrl(), operationToUpdate)
314 .subscribe((newOperation: InterfaceOperationModel) => {
315 const foundInterface = this.interfaces.find(value => value.type === newOperation.interfaceType);
316 if (foundInterface) {
317 foundInterface.operations.push(new UIOperationModel(new OperationModel(newOperation)));
319 const uiInterfaceModel = new UIInterfaceModel();
320 uiInterfaceModel.type = newOperation.interfaceType;
321 uiInterfaceModel.uniqueId = newOperation.interfaceType;
322 uiInterfaceModel.operations = [];
323 uiInterfaceModel.operations.push(new UIOperationModel(new OperationModel(newOperation)));
324 this.interfaces.push(uiInterfaceModel);
327 this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
329 this.modalServiceNg2.currentModal.instance.dynamicContent.instance.isLoading = false;
330 this.modalServiceNg2.closeCurrentModal();
334 private handleEnableAddArtifactImplementation = (newOperation: InterfaceOperationModel): InterfaceOperationModel => {
335 if (!this.isEnableAddArtifactImplementation()) {
336 newOperation.implementation.artifactType = null;
337 newOperation.implementation.artifactVersion = null;
342 private isEnableAddArtifactImplementation = (): boolean => {
343 return this.modalInstance.instance.dynamicContent.enableAddArtifactImplementation;
346 private initInterfaceDefinition() {
347 this.isLoading = true;
348 this.interfaces = [];
349 this.topologyTemplateService.getComponentInterfaceOperations(this.component.componentType, this.component.uniqueId)
350 .subscribe((response) => {
351 if (response.interfaces) {
352 this.interfaces = response.interfaces.map((interfaceModel) => new UIInterfaceModel(interfaceModel));
354 this.isLoading = false;
358 private loadToscaArtifacts() {
359 this.toscaArtifactService.getToscaArtifacts(this.component.model).subscribe(response => {
361 let toscaArtifactsFound = <ToscaArtifactModel[]>_.values(response);
362 toscaArtifactsFound.forEach(value => this.toscaArtifactTypes.push(new DropdownValue(value, value.type)));
365 this.notification.error({
366 message: 'Failed to Load Tosca Artifacts:' + error,
372 private loadInterfaceTypes() {
373 this.componentServiceNg2.getInterfaceTypes(this.component).subscribe(response => {
375 console.info("loadInterfaceTypes ", response);
376 for (const interfaceType in response) {
377 this.interfaceTypesMap.set(interfaceType, response[interfaceType]);
378 this.interfaceTypesTest.push(new DropdownValue(interfaceType, interfaceType));
382 this.notification.error({
383 message: 'Failed to Load Interface Types:' + error,
389 collapseAll(value: boolean = true): void {
390 this.interfaces.forEach(interfaceData => {
391 interfaceData.isCollapsed = value;
395 isAllCollapsed(): boolean {
396 return this.interfaces.every((interfaceData) => interfaceData.isCollapsed);
399 isAllExpanded(): boolean {
400 return this.interfaces.every((interfaceData) => !interfaceData.isCollapsed);
403 isInterfaceListEmpty(): boolean {
404 return this.interfaces.length === 0;
407 isOperationListEmpty(): boolean {
408 return this.interfaces.filter((interfaceData) => interfaceData.operations && interfaceData.operations.length > 0).length > 0;
411 onRemoveOperation(operation: OperationModel): void {
416 const deleteButton: IModalButtonComponent = {
418 text: this.modalTranslation.DELETE_BUTTON,
423 this.ComponentServiceNg2
424 .deleteInterfaceOperation(this.component, operation)
426 const curInterf = this.interfaces.find((interf) => interf.type === operation.interfaceType);
427 const index = curInterf.operations.findIndex((el) => el.uniqueId === operation.uniqueId);
428 curInterf.operations.splice(index, 1);
429 if (!curInterf.operations.length) {
430 const interfIndex = this.interfaces.findIndex((interf) => interf.type === operation.interfaceType);
431 this.interfaces.splice(interfIndex, 1);
437 const cancelButton: IModalButtonComponent = {
439 text: this.modalTranslation.CANCEL_BUTTON,
444 this.openOperation = null;
448 this.ModalServiceSdcUI.openWarningModal(
449 this.modalTranslation.DELETE_TITLE,
450 this.modalTranslation.deleteText(operation.name),
451 'deleteOperationModal',
452 [deleteButton, cancelButton],
456 private createOperation = (operation: OperationModel): void => {
457 this.ComponentServiceNg2.createInterfaceOperation(this.component, operation).subscribe((response: OperationModel) => {
458 this.openOperation = null;
460 let curInterf = this.interfaces.find((interf) => interf.type === operation.interfaceType);
463 curInterf = new UIInterfaceModel({
464 type: response.interfaceType,
465 uniqueId: response.uniqueId,
468 this.interfaces.push(curInterf);
471 const newOpModel = new UIOperationModel(response);
472 curInterf.operations.push(newOpModel);
473 this.sortInterfaces();
475 if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL && operation.artifactData) {
476 this.ComponentServiceNg2.uploadInterfaceOperationArtifact(this.component, newOpModel, operation).subscribe();
477 } else if (response.workflowId && operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXISTING) {
478 this.WorkflowServiceNg2.associateWorkflowArtifact(this.component, response).subscribe();
479 } else if (operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.NEW) {
480 this.$state.go('workspace.plugins', {path: 'workflowDesigner'});
485 private enableOrDisableSaveButton = (shouldEnable: boolean): void => {
486 const saveButton = this.modalInstance.instance.dynamicContent.getButtonById('saveButton');
487 saveButton.disabled = !shouldEnable;
490 private sortInterfaces(): void {
491 this.interfaces = this.interfaces.filter((interf) => interf.operations && interf.operations.length > 0); // remove empty interfaces
492 this.interfaces.sort((a, b) => a.type.localeCompare(b.type)); // sort interfaces alphabetically
493 this.interfaces.forEach((interf) => {
494 interf.operations.sort((a, b) => a.name.localeCompare(b.name)); // sort operations alphabetically