bugfix for operations screen
[sdc.git] / catalog-ui / src / app / ng2 / pages / interface-operation / operation-creator / operation-creator.component.ts
index cc7b5fe..23b6781 100644 (file)
 import * as _ from "lodash";
-import {Component} from '@angular/core';
-import {DropdownValue} from "app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component";
-import {InputModel, OperationModel, OperationParam} from 'app/models';
+import {Component, ViewChild} from '@angular/core';
+
+import {Subscription} from "rxjs/Subscription";
+
+import {TranslateService} from "app/ng2/shared/translator/translate.service";
+import {WorkflowServiceNg2} from 'app/ng2/services/workflow.service';
+import {
+    InterfaceModel,
+    OperationModel,
+    OperationParameter,
+    InputBEModel,
+    WORKFLOW_ASSOCIATION_OPTIONS,
+    Capability
+} from 'app/models';
+
+import { Tabs } from "app/ng2/components/ui/tabs/tabs.component";
+import { DropdownValue } from "app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component";
+import { IDropDownOption } from 'onap-ui-angular';
+import { DropDownComponent } from "onap-ui-angular/dist/components";
+import { DROPDOWN_OPTION_TYPE } from "app/utils/constants";
+
+export class DropDownOption implements IDropDownOption {
+    value: string;
+    label: string;
+
+    constructor(value: string, label?: string) {
+        this.value = value;
+        this.label = label || value;
+    }
+}
+
+class TypedDropDownOption extends DropDownOption {
+    type: string;
+
+    constructor(value: string, label?: string, type?: string) {
+        super(value, label);
+        this.type = type;
+    }
+}
+
+export interface OperationCreatorInput {
+    allWorkflows: Array<any>,
+    inputOperation: OperationModel,
+    interfaces: Array<InterfaceModel>,
+    inputProperties: Array<InputBEModel>,
+    enableWorkflowAssociation: boolean,
+    readonly: boolean,
+    interfaceTypes: { [interfaceType: string]: Array<string> },
+    validityChangedCallback: Function,
+    workflowIsOnline: boolean,
+    capabilities: Array<Capability>
+}
 
 @Component({
     selector: 'operation-creator',
     templateUrl: './operation-creator.component.html',
-    styleUrls:['./operation-creator.component.less'],
+    styleUrls: ['./operation-creator.component.less'],
+    providers: [TranslateService]
 })
 
-export class OperationCreatorComponent {
+export class OperationCreatorComponent implements OperationCreatorInput {
 
-    inputProperties: Array<DropdownValue>;
-    input: any;
-    inputParams: Array<OperationParam> = [];
+    input: OperationCreatorInput;
+    inputOperation: OperationModel;
+    interfaces: Array<InterfaceModel>;
     operation: OperationModel;
+    interfaceNames: Array<TypedDropDownOption> = [];
+    interfaceTypes: { [interfaceType: string]: Array<string> };
+    operationNames: Array<TypedDropDownOption> = [];
+    validityChangedCallback: Function;
+    capabilities: Array<Capability>;
+
+    allWorkflows: Array<any>;
+    workflows: Array<DropdownValue> = [];
+    workflowVersions: Array<DropdownValue> = [];
+    inputProperties: Array<InputBEModel> = [];
+    archivedWorkflowId: string = '&';
+
+    inputParameters: Array<OperationParameter> = [];
+    noAssignInputParameters: Array<OperationParameter> = [];
+    assignInputParameters: { [key: string]: { [key: string]: Array<OperationParameter>; }; } = {};
+
+    outputParameters: Array<OperationParameter> = [];
+    noAssignOutputParameters: Array<OperationParameter> = [];
+    assignOutputParameters: { [key: string]: { [key: string]: Array<OperationParameter>; }; } = {};
+    componentCapabilities: Array<Capability> = [];
+
+    tableParameters: Array<OperationParameter> = [];
+    operationOutputs: Array<OperationModel> = [];
+
+    associationOptions: Array<DropdownValue> = [];
+    workflowAssociationType: string;
+
+    enableWorkflowAssociation: boolean;
+    workflowIsOnline: boolean;
     isEditMode: boolean = false;
+    isLoading: boolean = false;
+    readonly: boolean;
+
+    propertyTooltipText: String;
+
+    TYPE_INPUT = 'Inputs';
+    TYPE_OUTPUT = 'Outputs';
+
+    INTERFACE_OTHER_HEADER = 'Local Interfaces';
+    INTERFACE_OTHER = 'Local';
+
+    @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
+    @ViewChild('operationNamesDropdown') operationNamesDropdown: DropDownComponent;
+    @ViewChild('workflowAssignmentDropdown') workflowAssignmentDropdown: DropDownComponent;
+    currentTab: String;
+
+    constructor(private workflowServiceNg2: WorkflowServiceNg2, private translateService: TranslateService) {
+        this.translateService.languageChangedObservable.subscribe(lang => {
+            this.propertyTooltipText = this.translateService.translate("OPERATION_PROPERTY_TOOLTIP_TEXT");
+
+            this.associationOptions = [
+                new DropDownOption(WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL, this.translateService.translate("EXTERNAL_WORKFLOW_ASSOCIATION")),
+                new DropDownOption(WORKFLOW_ASSOCIATION_OPTIONS.EXISTING, this.translateService.translate("EXISTING_WORKFLOW_ASSOCIATION")),
+            ];
+
+            this.workflowAssociationType = this.operation.workflowAssociationType;
+        });
+
+        this.currentTab = this.TYPE_INPUT;
+    }
+
+    createInterfaceDropdown(type: string) {
+        let label = type;
+        const lastDot = label.lastIndexOf('.');
+        if (lastDot > -1) {
+            label = label.substr(lastDot + 1);
+        }
+        return new TypedDropDownOption(type, label);
+    }
 
     ngOnInit() {
-        this.operation = new OperationModel(this.input.operation || {});
+        this.interfaceNames = _.map(
+            _.keys(this.interfaceTypes),
+            type => this.createInterfaceDropdown(type)
+        );
+        this.interfaceNames.unshift(new TypedDropDownOption('Existing Interfaces', 'Existing Interfaces', DROPDOWN_OPTION_TYPE.HEADER));
+        this.interfaceNames = this.interfaceNames.concat([
+            new TypedDropDownOption(' ', ' ', DROPDOWN_OPTION_TYPE.HORIZONTAL_LINE),
+            new TypedDropDownOption(this.INTERFACE_OTHER_HEADER, this.INTERFACE_OTHER_HEADER, DROPDOWN_OPTION_TYPE.HEADER),
+            new TypedDropDownOption(this.INTERFACE_OTHER)
+        ]);
+        const inputOperation = this.inputOperation;
+        this.operation = new OperationModel(inputOperation || {});
 
-        if (this.input.operation) {
-            let {inputParams} = this.input.operation;
+        this.operationOutputs = _.reduce(
+            this.interfaces,
+            (acc: Array<OperationModel>, interf) => [
+                ...acc,
+                ..._.filter(
+                    interf.operations,
+                    op => op.uniqueId !== this.operation.uniqueId
+                ),
+            ],
+        []);
 
-            if (inputParams) {
-                _.forEach(inputParams.listToscaDataDefinition, (input: OperationParam) => {
-                    this.addParam(input);
-                });
+        if (this.enableWorkflowAssociation) {
+            if (this.workflowIsOnline) {
+                this.workflows = _.map(
+                    _.filter(
+                        this.allWorkflows,
+                        (workflow: any) => {
+                            if (workflow.archiving === this.workflowServiceNg2.WF_STATE_ACTIVE) {
+                                return true;
+                            }
+                            if (workflow.archiving === this.workflowServiceNg2.WF_STATE_ARCHIVED &&
+                                workflow.id === this.operation.workflowId) {
+                                this.archivedWorkflowId = workflow.id;
+                                return true;
+                            }
+                            return false;
+                        }
+                    ),
+                    (workflow: any) => new DropdownValue(workflow.id, workflow.name)
+                );
+            } else {
+                this.workflows = [];
             }
+        }
+        this.reconstructOperation();
+        this.filterCapabilities();
+        this.validityChanged();
+        this.updateTable();
+    }
 
-            if (this.input.operation.uniqueId) {
+    ngAfterViewInit() {
+        if(this.workflowAssignmentDropdown){
+            this.workflowAssignmentDropdown.allOptions = this.associationOptions && this.associationOptions.length ?
+                this.associationOptions :
+                [
+                    new DropDownOption(WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL, this.translateService.translate("EXTERNAL_WORKFLOW_ASSOCIATION")),
+                    new DropDownOption(WORKFLOW_ASSOCIATION_OPTIONS.EXISTING, this.translateService.translate("EXISTING_WORKFLOW_ASSOCIATION")),
+                ];
+        }
+    }
+
+    reconstructOperation = () => {
+
+        const buildAndUpdate = () => {
+            this.buildParams();
+            this.updateTable();
+        };
+
+        const inputOperation = this.inputOperation;
+        if (inputOperation) {
+            this.onSelectInterface(new DropDownOption(this.operation.interfaceType));
+
+            this.operation.artifactFileName = this.operation.artifactFileName || this.operation.implementation.artifactName;
+
+            if (this.enableWorkflowAssociation && inputOperation.workflowVersionId && this.isUsingExistingWF(inputOperation)) {
+                this.assignInputParameters[this.operation.workflowId] = {[inputOperation.workflowVersionId]: []};
+                this.assignOutputParameters[this.operation.workflowId] = {[inputOperation.workflowVersionId]: []};
+                this.inputParameters = this.assignInputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+                this.outputParameters = this.assignOutputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+
+                const sub = this.onSelectWorkflow(new DropDownOption(inputOperation.workflowId), inputOperation.workflowVersionId);
+                if (sub) {
+                    sub.add(() => {
+                        buildAndUpdate();
+                        this.operation.workflowVersionId = '-1';
+                        setTimeout(() => this.operation.workflowVersionId = this.inputOperation.workflowVersionId);
+                    });
+                } else {
+                    buildAndUpdate();
+                }
+            } else {
+                this.inputParameters = this.noAssignInputParameters;
+                this.outputParameters = this.noAssignOutputParameters;
+                buildAndUpdate();
+            }
+
+            if (inputOperation.uniqueId) {
                 this.isEditMode = true;
             }
         }
 
-        this.inputProperties = _.map(this.input.inputProperties,
-            (input: InputModel) => new DropdownValue(input.uniqueId, input.name)
+    }
+
+    filterCapabilities() {
+        this.componentCapabilities = _.filter(this.capabilities, (cap: Capability) => cap.properties);
+    }
+
+    buildParams = () => {
+
+        if (this.inputOperation.outputs) {
+            this.currentTab = this.TYPE_OUTPUT;
+            this.updateTable();
+            _.forEach(
+                [...this.inputOperation.outputs.listToscaDataDefinition].sort((a, b) => a.name.localeCompare(b.name)),
+                (output: OperationParameter) => {
+                    this.addParam({...output, required: Boolean(output.required)});
+                }
+            );
+        }
+
+        this.currentTab = this.TYPE_INPUT;
+        this.updateTable();
+        if (this.inputOperation.inputs) {
+            _.forEach(
+                [...this.inputOperation.inputs.listToscaDataDefinition].sort((a, b) => a.name.localeCompare(b.name)),
+                (input: OperationParameter) => {
+                    this.addParam({...input, required: Boolean(input.required)});
+                }
+            );
+        }
+
+    }
+
+    isInterfaceOther(): boolean {
+        return this.operation.interfaceType === this.INTERFACE_OTHER;
+    }
+
+    onSelectInterface(interf: IDropDownOption) {
+        if (interf && this.operation.interfaceType !== interf.value) {
+            this.operation.name = null;
+        }
+        this.operation.interfaceType = interf && interf.value;
+        this.operationNames = !this.operation.interfaceType ? [] : (
+            _.map(
+                this.interfaceTypes[this.operation.interfaceType],
+                name => {
+                    const curInterf = _.find(
+                        this.interfaces,
+                        interf => interf.type === this.operation.interfaceType
+                    );
+                    const existingOp = _.find(
+                        curInterf && curInterf.operations || [],
+                        op => op.name === name
+                    );
+                    const ddType = (existingOp && existingOp.uniqueId !== this.operation.uniqueId) ? DROPDOWN_OPTION_TYPE.HORIZONTAL_LINE : DROPDOWN_OPTION_TYPE.SIMPLE;
+                    return new TypedDropDownOption(name, name, ddType);
+                }
+            )
         );
+        if(this.operationNamesDropdown) {
+            this.operationNamesDropdown.allOptions = <IDropDownOption[]>this.operationNames;
+        }
+        this.validityChanged();
+    }
+
+    onSelectOperationName(name: IDropDownOption) {
+        if (name) {
+            this.operation.name = name.value;
+        }
+        this.validityChanged();
+    }
+
+    onChangeName() {
+        this.validityChanged();
+    }
+
+    get descriptionValue() {
+        return this.operation.description;
+    }
+
+    set descriptionValue(v) {
+        this.operation.description = v || null;
+        this.validityChanged();
     }
 
-    addParam(param?: OperationParam): void {
-        this.inputParams.push(new OperationParam(param));
+    onSelectWorkflow(workflowId: DropDownOption, selectedVersionId?: string): Subscription {
+
+        if (_.isUndefined(workflowId) || !this.workflowIsOnline) {
+            return;
+        }
+
+        if (this.operation.workflowId === workflowId.value && !selectedVersionId) {
+            return;
+        }
+
+        this.operation.workflowId = workflowId.value;
+        if (!this.assignInputParameters[this.operation.workflowId]) {
+            this.assignInputParameters[this.operation.workflowId] = {};
+            this.assignOutputParameters[this.operation.workflowId] = {};
+        }
+
+        this.isLoading = true;
+        this.validityChanged();
+        return this.workflowServiceNg2.getWorkflowVersions(this.operation.workflowId).subscribe((versions: Array<any>) => {
+            this.isLoading = false;
+
+            this.workflowVersions = _.map(
+                _.filter(
+                    versions, version => version.state === this.workflowServiceNg2.VERSION_STATE_CERTIFIED
+                ).sort((a, b) => a.name.localeCompare(b.name)),
+                (version: any) => {
+                    if (!this.assignInputParameters[this.operation.workflowId][version.id] && version.id !== selectedVersionId) {
+                        this.assignInputParameters[this.operation.workflowId][version.id] = _.map(version.inputs, (input: any) => {
+                            return new OperationParameter({...input, type: input.type.toLowerCase(), required: Boolean(input.mandatory)});
+                        })
+                        .sort((a, b) => a.name.localeCompare(b.name));
+
+                        this.assignOutputParameters[this.operation.workflowId][version.id] = _.map(version.outputs, (output: any) => {
+                            return new OperationParameter({...output, type: output.type.toLowerCase(), required: Boolean(output.mandatory)});
+                        })
+                        .sort((a, b) => a.name.localeCompare(b.name));
+                    }
+                    return new DropdownValue(version.id, `V ${version.name}`);
+                }
+            );
+            if (!selectedVersionId && this.workflowVersions.length) {
+                this.operation.workflowVersionId = _.last(this.workflowVersions).value;
+            }
+
+            this.changeWorkflowVersion(new DropDownOption(this.operation.workflowVersionId));
+            this.validityChanged();
+        });
+
     }
 
-    isAddAllowed(): boolean {
-        if (this.inputParams.length === 0) {
-            return true;
+    changeWorkflowVersion(versionId: DropDownOption) {
+
+        if (_.isUndefined(versionId) || !this.workflowIsOnline) {
+            return;
         }
 
-        const {paramId, paramName} = _.last(this.inputParams);
-        return paramId && paramName.length > 0;
+        this.operation.workflowVersionId = versionId.value;
+        this.inputParameters = this.assignInputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+        this.outputParameters = this.assignOutputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+        this.updateTable();
+        this.validityChanged();
+
     }
 
-    onRemoveParam = (param: OperationParam): void  => {
-        let index = _.indexOf(this.inputParams, param);
-        this.inputParams.splice(index, 1);
+    toggleAssociateWorkflow(type: DropDownOption) {
+
+        if (_.isUndefined(type)) {
+            return;
+        }
+
+        this.operation.workflowAssociationType = type.value;
+        this.workflowAssociationType = this.operation.workflowAssociationType;
+
+        if (!this.isUsingExistingWF()) {
+            this.inputParameters = this.noAssignInputParameters;
+            this.outputParameters = this.noAssignOutputParameters;
+        } else {
+            if (!this.operation.workflowId || !this.operation.workflowVersionId) {
+                this.inputParameters = [];
+                this.outputParameters = [];
+            } else {
+                this.inputParameters = this.assignInputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+                this.outputParameters = this.assignOutputParameters[this.operation.workflowId][this.operation.workflowVersionId];
+            }
+        }
+
+        this.updateTable();
+        this.validityChanged();
+
     }
 
-    createInputParamList(): void {
-        this.operation.createInputParamsList(this.inputParams);
+    onChangeArtifactFile(e: any) {
+        const file = e.target.files && e.target.files[0];
+        this.operation.artifactFileName = file && file.name;
+
+        if (!this.operation.artifactFileName) {
+            this.operation.artifactData = null;
+            this.validityChanged();
+            return;
+        }
+
+        const reader = new FileReader();
+        reader.onloadend = () => {
+            this.isLoading = false;
+            const result = <String>reader.result;
+            this.operation.artifactData = result.substring(result.indexOf(',') + 1);
+            this.validityChanged();
+        }
+
+        this.isLoading = true;
+        reader.readAsDataURL(file);
     }
 
-    checkFormValidForSubmit(): boolean {
-        return this.operation.operationType && this.operation.operationType.length > 0 && this.isAddAllowed();
+    tabChanged = (event) => {
+
+        this.currentTab = event.title;
+        this.updateTable();
+
     }
 
+    updateTable() {
+
+        switch (this.currentTab) {
+            case this.TYPE_INPUT:
+                this.tableParameters = this.inputParameters;
+                break;
+            case this.TYPE_OUTPUT:
+                this.tableParameters = this.outputParameters;
+                break;
+        }
+
+    }
+
+    addParam(param?: OperationParameter): void {
+        this.tableParameters.push(new OperationParameter(param || {required: false}));
+        this.validityChanged();
+    }
+
+    canAdd = (): boolean => {
+
+        let valid = true;
+        if (this.currentTab === this.TYPE_INPUT) {
+            _.forEach(this.inputParameters, param => {
+                if (!param.name || !param.inputId) {
+                    valid = false;
+                }
+            });
+        } else {
+            _.forEach(this.outputParameters, param => {
+                if (!param.name || !param.type) {
+                    valid = false;
+                }
+            });
+        }
+
+        return valid;
+
+    }
+
+    isParamsValid = (): boolean => {
+
+        let valid = true;
+        _.forEach(this.inputParameters, param => {
+            if (!param.name || !param.inputId) {
+                valid = false;
+            }
+        });
+        _.forEach(this.outputParameters, param => {
+            if (!param.name || !param.type) {
+                valid = false;
+            }
+        });
+
+        return valid;
+
+    }
+
+    onRemoveParam = (param: OperationParameter): void => {
+        let index = _.indexOf(this.tableParameters, param);
+        this.tableParameters.splice(index, 1);
+        this.validityChanged();
+    }
+
+    createParamLists = () => {
+        this.operation.createInputsList(this.inputParameters);
+        this.operation.createOutputsList(this.outputParameters);
+    }
+
+    isUsingExistingWF = (operation?: OperationModel): boolean => {
+        operation = operation || this.operation;
+        return operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXISTING;
+    }
+
+    isUsingExternalWF = (operation?: OperationModel): boolean => {
+        operation = operation || this.operation;
+        return operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXTERNAL;
+    }
+
+    shouldCreateWF = (operation?: OperationModel): boolean => {
+        operation = operation || this.operation;
+        return operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.NEW;
+    }
+
+    checkFormValidForSubmit = (): boolean => {
+        return this.operation.name &&
+            (!this.isUsingExistingWF() || this.operation.workflowVersionId) &&
+            this.isParamsValid();
+    }
+
+    validityChanged = () => {
+        let validState = this.checkFormValidForSubmit();
+        this.validityChangedCallback(validState);
+    }
+
+    getSelectedDropdown(options: DropdownValue[], selectedValue: string): DropdownValue {
+        const selectedDropdown = _.find(options, (option) => option.value === selectedValue);
+        return selectedDropdown || this.toDropDownOption(null);
+    }
+
+    toDropDownOption(val: string) {
+        return { value : val, label: val };
+    }
 }