summaryrefslogtreecommitdiffstats
path: root/catalog-ui
diff options
context:
space:
mode:
authorJvD_Ericsson <jeff.van.dam@est.tech>2023-08-16 14:43:13 +0100
committerMichael Morris <michael.morris@est.tech>2023-09-22 07:43:34 +0000
commitdb333a620e4b8dec6c58009162561b32c83d6bd9 (patch)
treee1541ffd45a005c9aa190d56b55a8fcf10175e30 /catalog-ui
parent035d670c792c9408493b3d729a3ac91124c2d4df (diff)
UI Support for operation milestones
Issue-ID: SDC-4601 Signed-off-by: JvD_Ericsson <jeff.van.dam@est.tech> Change-Id: I9088a1d004ae3a3470aee8d831066584fd26b0d4
Diffstat (limited to 'catalog-ui')
-rw-r--r--catalog-ui/src/app/models/interfaceOperation.ts65
-rw-r--r--catalog-ui/src/app/models/operation.ts3
-rw-r--r--catalog-ui/src/app/ng2/components/ui/tabs/tab/tab.component.ts1
-rw-r--r--catalog-ui/src/app/ng2/components/ui/tabs/tabs.component.html2
-rw-r--r--catalog-ui/src/app/ng2/components/ui/tabs/tabs.component.less20
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts9
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.html106
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.less88
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.spec.ts63
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.ts187
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.ts4
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.html168
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.less110
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.spec.ts53
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.ts241
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts1
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html26
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts130
-rw-r--r--catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts40
-rw-r--r--catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts17
-rw-r--r--catalog-ui/src/app/utils/common-utils.ts5
21 files changed, 1312 insertions, 27 deletions
diff --git a/catalog-ui/src/app/models/interfaceOperation.ts b/catalog-ui/src/app/models/interfaceOperation.ts
index a6279a589f..fdf26aaad1 100644
--- a/catalog-ui/src/app/models/interfaceOperation.ts
+++ b/catalog-ui/src/app/models/interfaceOperation.ts
@@ -25,6 +25,17 @@ import {PROPERTY_DATA, PROPERTY_TYPES} from "../utils/constants";
import {ToscaFunction} from "./tosca-function";
import {SubPropertyToscaFunction} from "./sub-property-tosca-function";
+export enum MilestoneEnum {
+ on_entry = 'on_entry',
+ on_success = 'on_success',
+ on_failure = 'on_failure',
+ on_timeout = 'on_timeout'
+}
+
+export enum ActivityTypesEnum {
+ Delegate = 'delegate'
+}
+
export class InputOperationParameter {
name: string;
type: string;
@@ -96,12 +107,63 @@ export interface IOperationParamsList {
listToscaDataDefinition: Array<InputOperationParameter>;
}
+export class Milestone {
+ activities: IActivityParameterList;
+ filterParams: IActivityParameterList;
+
+ constructor(param?: any) {
+ if (param) {
+ this.activities = param.activityParams;
+ this.filterParams = param.filterParams;
+ }
+ }
+}
+
+export class ActivityParameter {
+ type: string;
+ workflow: string;
+ inputs: IOperationParamsList;
+
+ constructor(param?: any) {
+ if (param) {
+ this.type = param.type;
+ this.workflow = param.workflow;
+ this.inputs = param.inputs;
+ }
+ }
+}
+
+export interface IActivityParameterList {
+ listToscaDataDefinition: Array<ActivityParameter>;
+}
+
+export class FilterParameter {
+ name: string;
+ constraint: string;
+ filterValue: any;
+ toscaFunction?: ToscaFunction;
+
+ constructor(param?: any) {
+ if (param) {
+ this.name = param.name;
+ this.constraint = param.constraint;
+ this.filterValue = param.filterValue;
+ this.toscaFunction = param.toscaFunction;
+ }
+ }
+}
+
+export interface IFilterParameterList {
+ listToscaDataDefinition: Array<FilterParameter>;
+}
+
export class BEInterfaceOperationModel {
name: string;
description: string;
uniqueId: string;
inputs: IOperationParamsList;
implementation: ArtifactModel;
+ milestones: Object;
constructor(operation?: any) {
if (operation) {
@@ -110,6 +172,7 @@ export class BEInterfaceOperationModel {
this.uniqueId = operation.uniqueId;
this.inputs = operation.inputs;
this.implementation = operation.implementation;
+ this.milestones = operation.milestones;
}
}
}
@@ -126,6 +189,7 @@ export class InterfaceOperationModel extends BEInterfaceOperationModel {
uniqueId: string;
inputParams: IOperationParamsList;
implementation: ArtifactModel;
+ milestones: Object
constructor(operation?: any) {
super(operation);
@@ -147,6 +211,7 @@ export class InterfaceOperationModel extends BEInterfaceOperationModel {
if (operation.implementation) {
this.implementation = new ArtifactModel(operation.implementation);
}
+ this.milestones = operation.milestones;
}
}
diff --git a/catalog-ui/src/app/models/operation.ts b/catalog-ui/src/app/models/operation.ts
index 3d4917fd45..3b2f203476 100644
--- a/catalog-ui/src/app/models/operation.ts
+++ b/catalog-ui/src/app/models/operation.ts
@@ -101,6 +101,8 @@ export class OperationModel extends BEOperationModel{
workflowName: string;
workflowVersion: string;
+ milestones: Object;
+
protected OperationTypeEnum: Array<String> = [
'Create',
'Delete',
@@ -125,6 +127,7 @@ export class OperationModel extends BEOperationModel{
this.artifactData = operation.artifactData;
this.workflowName = operation.workflowName;
this.workflowVersion = operation.workflowVersion;
+ this.milestones = operation.milestones;
}
}
diff --git a/catalog-ui/src/app/ng2/components/ui/tabs/tab/tab.component.ts b/catalog-ui/src/app/ng2/components/ui/tabs/tab/tab.component.ts
index e0eacdc43b..8e0b0a55b3 100644
--- a/catalog-ui/src/app/ng2/components/ui/tabs/tab/tab.component.ts
+++ b/catalog-ui/src/app/ng2/components/ui/tabs/tab/tab.component.ts
@@ -34,6 +34,7 @@ export class Tab {
@Input('tabTitle') title: string;
@Input() active:boolean = false;
@Input() show:boolean = true;
+ @Input() highlight?: string;
@Input() indication?: number;
}
diff --git a/catalog-ui/src/app/ng2/components/ui/tabs/tabs.component.html b/catalog-ui/src/app/ng2/components/ui/tabs/tabs.component.html
index d52dccc054..d6cf69355c 100644
--- a/catalog-ui/src/app/ng2/components/ui/tabs/tabs.component.html
+++ b/catalog-ui/src/app/ng2/components/ui/tabs/tabs.component.html
@@ -16,7 +16,7 @@
<div class="tabs {{tabStyle}}">
<ng-container *ngFor="let tab of tabs">
- <div class="tab" *ngIf="tab.show" (click)="selectTab(tab)" [class.active]="tab.active" [attr.data-tests-id]="tab.title">
+ <div class="tab" *ngIf="tab.show" (click)="selectTab(tab)" [class.active]="tab.active" [attr.data-tests-id]="tab.title" [ngStyle]="{'color': tab.highlight}">
{{tab.title}}
<div class="tab-indication" *ngIf="tab.indication" [@indicatorAnimation]="tab.indication">{{tab.indication}}</div>
</div>
diff --git a/catalog-ui/src/app/ng2/components/ui/tabs/tabs.component.less b/catalog-ui/src/app/ng2/components/ui/tabs/tabs.component.less
index db60be5371..d37868d987 100644
--- a/catalog-ui/src/app/ng2/components/ui/tabs/tabs.component.less
+++ b/catalog-ui/src/app/ng2/components/ui/tabs/tabs.component.less
@@ -82,4 +82,24 @@
}
}
}
+
+ &.basic-tabs .tab {
+ color: @main_color_n;
+ flex: 0 0 auto;
+
+ &:after {
+ display:block;
+ content: '';
+ border-bottom: 2px solid @main_color_a;
+ transform: scaleX(0);
+ transition: transform 200ms ease-in-out;
+ }
+
+ &.active {
+ color: @main_color_a;
+ &:after {
+ transform: scaleX(1.2);
+ }
+ }
+ }
}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts
index 04210ae39c..dfdaa77e21 100644
--- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/interface-operations.component.ts
@@ -142,6 +142,8 @@ export class InterfaceOperationsComponent {
toscaArtifactTypes: Array<DropdownValue> = [];
componentInstanceMap: Map<string, InstanceFeDetails> = new Map<string, InstanceFeDetails>();
validImplementationProps: boolean = true;
+ validMilestoneActivities: boolean = true;
+ validMilestoneFilters: boolean = true;
@Input() component: ComponentInstance;
@Input() isViewOnly: boolean;
@@ -224,6 +226,11 @@ export class InterfaceOperationsComponent {
return disable;
}
+ const validMilestoneFilters = this.modalInstance.instance.dynamicContent.instance.validMilestoneFilters;
+ const validMilestoneActivities = this.modalInstance.instance.dynamicContent.instance.validMilestoneActivities;
+ if (!validMilestoneActivities || !validMilestoneFilters) {
+ return disable;
+ }
let enableAddArtifactImplementation = this.modalInstance.instance.dynamicContent.instance.enableAddArtifactImplementation;
if(enableAddArtifactImplementation) {
const validImplementationProps = this.modalInstance.instance.dynamicContent.instance.validImplementationProps;
@@ -273,6 +280,8 @@ export class InterfaceOperationsComponent {
validityChangedCallback: this.disableSaveButton,
isViewOnly: this.isViewOnly,
validImplementationProps: this.validImplementationProps,
+ validMilestoneActivities: this.validMilestoneActivities,
+ validMilestoneFilters: this.validMilestoneFilters,
isEdit: true,
modelName: this.componentMetaData.model
}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.html
new file mode 100644
index 0000000000..ce8eb2f51d
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.html
@@ -0,0 +1,106 @@
+<!--
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2023 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+-->
+
+<div class="sub-operation-activities">
+ <div class="group-with-border content-row">
+ <form novalidate class="w-sdc-form two-columns" [formGroup]="activityForm">
+ <div formArrayName="activityFormList">
+ <label class="activities-label"> Activities </label>
+ <div *ngFor="let activity of activities; let idx = index">
+ <div class="side-by-side group-with-border-blue">
+ <div class="form-item">
+ <label class="sdc-timeout-label">Type: </label>
+ <div class="sdc-dropdown">
+ <select class="i-sdc-form-select"
+ data-tests-id="activity-type"
+ [value]="activity.type"
+ [disabled]="isViewOnly"
+ (change)="onActivityTypeChange($event.target.value, idx)"
+ required>
+ <option *ngIf="activity" [value]="activity.type" hidden selected>
+ {{ activity.type }}
+ </option>
+ <option *ngFor="let activityType of activityTypes"
+ [value]="activityType">
+ {{ activityType }}
+ </option>
+ </select>
+ </div>
+ </div>
+ <div class="form-item">
+ <div class="side-by-side">
+ <div class="form-item-big">
+ <label>Workflow: </label>
+ <input type="text"
+ class="i-sdc-form-input"
+ [disabled]="isViewOnly"
+ (input)="onActivityValueChange($event.target.value, idx)"
+ [value]="activity.workflow"
+ [ngClass]="{'disabled': isViewOnly}"
+ required/>
+ </div>
+ <div class="form-item-icon">
+ <span class="sprite-new delete-btn" [ngClass]="{'disabled': isViewOnly}" (click)="removeFromActivities(idx)"></span>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="w-sdc-form-columns-wrapper">
+ <div class="validation-errors">
+ <ng-container *ngFor="let validation of validationMessages.activity">
+ <div class="input-error" *ngIf="activityFormArray.at(idx).hasError(validation.type);">
+ {{ validation.message }}
+ </div>
+ </ng-container>
+ </div>
+ </div>
+ <div class="group-with-border content-row" *ngIf="dataTypeMap">
+ <input-list
+ [title]="'INPUT_LIST_TITLE' | translate"
+ [emptyMessage]="'INPUT_LIST_EMPTY' | translate"
+ [inputs]="getInputs(idx)"
+ [dataTypeMap]="dataTypeMap"
+ [isViewOnly]="isViewOnly"
+ [allowDeletion]="true"
+ [componentInstanceMap]="componentInstanceMap"
+ (onValueChange)="onInputValueChange($event, idx)"
+ (onDelete)="onInputDelete($event, idx)"
+ >
+ </input-list>
+ </div>
+ <div class="group-with-border content-row">
+ <app-add-input
+ [dataTypeMap]="dataTypeMap$"
+ [isView]="isViewOnly"
+ [defaultType]="DEFAULT_INPUT_TYPE"
+ [existingInputNames]="collectInputNames(idx)"
+ (onAddInput)="onAddInput($event, idx)"
+ >
+ </app-add-input>
+ </div>
+ </div>
+ <div class="add-button-container group-with-border" *ngIf="!isViewOnly">
+ <a class="add-btn" data-tests-id="add-input.add-input-link"
+ (click)="addActivity()">Add Activity</a>
+ </div>
+ </div>
+ </form>
+ </div>
+</div>
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.less b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.less
new file mode 100644
index 0000000000..99a053441c
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.less
@@ -0,0 +1,88 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+@import '../../../../../../../assets/styles/variables.less';
+@import '../../../../../../../assets/styles/override.less';
+
+.group-with-border {
+ margin: 10px 0;
+ padding: 10px 0;
+ border-top: 1px solid @tlv_color_u;
+ .content-row:not(:last-of-type) {
+ padding-bottom: 13px;
+ }
+}
+
+.group-with-border-blue {
+ margin: 10px 0;
+ padding: 10px 0;
+ border-top: 1px solid @tlv_color_x;
+ .content-row:not(:last-of-type) {
+ padding-bottom: 13px;
+ }
+}
+
+.i-sdc-form-select, .i-sdc-form-input {
+ color: #5a5a5a;
+ font-family: OpenSans-Regular, sans-serif;
+ font-size: 14px;
+ background-color: #ffffff;
+ border-radius: 2px;
+ margin: 0;
+ padding: 0;
+ border: solid 1px #d2d2d2;
+ height: 30px;
+ width: 100%;
+ display: block;
+}
+
+.side-by-side {
+ display: flex;
+
+ .form-item {
+ flex: 1 1 auto;
+
+ &:first-child {
+ margin-right: 14px;
+ flex-basis: 37%;
+ flex-grow: 0;
+ flex-shrink: 0;
+ }
+
+ &:nth-child(3) {
+ margin-left: 14px;
+ flex: 0.4;
+ }
+ }
+
+ .form-item-big {
+ flex: 1 1 auto;
+ flex-grow: 0;
+ flex-basis: 90%;
+ }
+
+ .form-item-icon {
+ margin-left: auto;
+ margin-right: 14px;
+
+ .sprite-new {
+ margin-top: 110%;
+ }
+ }
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.spec.ts
new file mode 100644
index 0000000000..20b574b7eb
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.spec.ts
@@ -0,0 +1,63 @@
+
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { ActivitiesListComponent } from './activities-list.component';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { TranslateModule } from '../../../../../shared/translator/translate.module';
+import { AddInputComponent } from '../add-input/add-input.component';
+import { InputListComponent } from '../input-list/input-list.component';
+import { InputListItemComponent } from '../input-list/input-list-item/input-list-item.component';
+import { SdcUiComponentsModule } from "onap-ui-angular/dist";
+import { ToscaFunctionModule } from '../../../../properties-assignment/tosca-function/tosca-function.module';
+
+describe('ActivitiesListComponent', () => {
+ let component: ActivitiesListComponent;
+ let fixture: ComponentFixture<ActivitiesListComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ ActivitiesListComponent,
+ AddInputComponent,
+ InputListComponent,
+ InputListItemComponent,
+ ],
+ imports: [
+ FormsModule,
+ ReactiveFormsModule,
+ TranslateModule,
+ SdcUiComponentsModule,
+ ToscaFunctionModule
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ActivitiesListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.ts
new file mode 100644
index 0000000000..b265464f86
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/activities-list/activities-list.component.ts
@@ -0,0 +1,187 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import {
+ ActivityParameter,
+ IActivityParameterList,
+ InputOperationParameter,
+ IOperationParamsList,
+ ActivityTypesEnum
+} from "../../../../../../models/interfaceOperation";
+import { DataTypeModel } from "../../../../../../models/data-types";
+import { Observable } from "rxjs/Observable";
+import { InstanceFeDetails } from "../../../../../../models/instance-fe-details";
+import {
+ AbstractControl,
+ FormArray,
+ FormControl,
+ FormGroup,
+ ValidationErrors,
+ ValidatorFn,
+ Validators
+} from '@angular/forms';
+
+@Component({
+ selector: 'activities-list',
+ templateUrl: './activities-list.component.html',
+ styleUrls: ['./activities-list.component.less']
+})
+export class ActivitiesListComponent implements OnInit {
+
+ @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map();
+ @Input() dataTypeMap: Map<string, DataTypeModel>;;
+ @Input() dataTypeMap$: Observable<Map<string, DataTypeModel>>;
+ @Input() existingActivities: IActivityParameterList;
+ @Input() isViewOnly: boolean;
+ @Output('activitiesChangeEvent') activitiesChangeEvent: EventEmitter<any> = new EventEmitter<any>();
+
+ readonly DEFAULT_INPUT_TYPE: string = "tosca.dataTypes.tmf.milestoneJeopardyData";
+ readonly DEFAULT_INPUT_NAME: string = "TMFMilestoneJeopardyData";
+ activityTypes: string[] = [];
+ activities: ActivityParameter[] = [];
+ activityFormArray: FormArray = new FormArray([]);
+ activityForm: FormGroup = new FormGroup (
+ {
+ 'activityFormList': this.activityFormArray
+ }
+ );
+ validationMessages = {
+ activity: [
+ { type: 'required', message: 'Activity type and value is required'}
+ ]
+ };
+
+ ngOnInit() {
+ Object.keys(ActivityTypesEnum).forEach(key => {
+ this.activityTypes.push(ActivityTypesEnum[key])
+ });
+ this.activityForm.valueChanges.subscribe(() => {
+ this.emitOnActivityChange();
+ });
+ if (this.existingActivities && this.existingActivities.listToscaDataDefinition && this.existingActivities.listToscaDataDefinition.length > 0) {
+ this.existingActivities.listToscaDataDefinition.forEach(val => {
+ this.activities.push(val);
+ this.activityFormArray.push(
+ new FormControl(val, [Validators.required, this.formControlValidator()])
+ );
+ })
+ }
+ }
+
+ private emitOnActivityChange(): void {
+ this.activitiesChangeEvent.emit({
+ activities: this.activities,
+ valid: this.activityForm.valid
+ });
+ }
+
+ addActivity() {
+ let input = new class implements IOperationParamsList {
+ listToscaDataDefinition: Array<InputOperationParameter> = [];
+ }
+ let activityParameter: ActivityParameter = {
+ type: null,
+ workflow: null,
+ inputs: input
+ }
+ this.activities.push(activityParameter);
+ this.activityFormArray.push(
+ new FormControl(activityParameter, [Validators.required, this.formControlValidator()])
+ );
+
+ let index = this.activities.indexOf(activityParameter);
+ let inputOperationParameter: InputOperationParameter = new InputOperationParameter();
+ inputOperationParameter.name = this.DEFAULT_INPUT_NAME;
+ inputOperationParameter.type = this.DEFAULT_INPUT_TYPE;
+ inputOperationParameter.valid = true;
+ this.activities[index].inputs.listToscaDataDefinition.push(inputOperationParameter);
+ this.activities[index].inputs.listToscaDataDefinition = Array.from(this.activities[index].inputs.listToscaDataDefinition);
+ }
+
+ private formControlValidator(): ValidatorFn {
+ return (control: AbstractControl): ValidationErrors | null => {
+ const activity = control.value;
+ if (!activity || !activity.type || !activity.workflow) {
+ return {required:true};
+ }
+ return null;
+ }
+ }
+
+ removeFromActivities (index: number) {
+ this.activities.splice(index, 1);
+ this.activityFormArray.removeAt(index);
+ }
+
+ onActivityTypeChange(type: string, index: number) {
+ let activity = this.activityFormArray.controls[index].value;
+ activity.type = type;
+ this.activityFormArray.controls[index].setValue(activity);
+ }
+
+ onActivityValueChange (value: any, index: number) {
+ let activity = this.activityFormArray.controls[index].value;
+ activity.workflow = value;
+ this.activityFormArray.controls[index].setValue(activity);
+ }
+
+ collectInputNames(index: number) {
+ return this.activities[index].inputs.listToscaDataDefinition.map((input) => input.name);
+}
+
+ onAddInput(inputOperationParameter: InputOperationParameter, index: number) {
+ this.activities[index].inputs.listToscaDataDefinition.push(inputOperationParameter);
+ this.activities[index].inputs.listToscaDataDefinition = Array.from(this.activities[index].inputs.listToscaDataDefinition);
+ }
+
+ getInputs(index: number) {
+ if (this.activities[index].inputs.listToscaDataDefinition) {
+ let test: InputOperationParameter[] = this.activities[index].inputs.listToscaDataDefinition;
+ return test;
+ }
+ return {};
+ }
+
+ onInputValueChange(changedInput: InputOperationParameter, index: number) {
+ if (changedInput.value instanceof Object) {
+ changedInput.value = JSON.stringify(changedInput.value);
+ }
+ const inputOperationParameter = this.activities[index].inputs.listToscaDataDefinition.find(value => value.name == changedInput.name);
+ inputOperationParameter.toscaFunction = null;
+ inputOperationParameter.value = changedInput.value;
+ inputOperationParameter.subPropertyToscaFunctions = changedInput.subPropertyToscaFunctions;
+ if (changedInput.isToscaFunction()) {
+ inputOperationParameter.toscaFunction = changedInput.toscaFunction;
+ inputOperationParameter.value = changedInput.toscaFunction.buildValueString();
+ }
+}
+
+ onInputDelete(inputName: string, index: number) {
+ const currentInputs = this.activities[index].inputs.listToscaDataDefinition;
+ const input1 = currentInputs.find(value => value.name === inputName);
+ const indexOfInput = currentInputs.indexOf(input1);
+ if (indexOfInput === -1) {
+ console.error(`Could not delete input '${inputName}'. Input not found.`);
+ return;
+ }
+ currentInputs.splice(currentInputs.indexOf(input1), 1);
+ this.activities[index].inputs.listToscaDataDefinition = Array.from(currentInputs);
+ }
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.ts
index c757d5f9e3..5620d193a8 100644
--- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/add-input/add-input.component.ts
@@ -38,6 +38,7 @@ export class AddInputComponent implements OnInit {
@Input('dataTypeMap') dataTypeMap$: Observable<Map<string, DataTypeModel>>;
@Input('isView') isView: boolean;
@Input() existingInputNames: Array<string> = [];
+ @Input('defaultType') defaultType: string;
@Output('onAddInput') onAddInputEvent: EventEmitter<InputOperationParameter>;
dataTypeMap: Map<string, DataTypeModel>;
@@ -143,6 +144,9 @@ export class AddInputComponent implements OnInit {
}
showAddInput() {
+ if (this.defaultType) {
+ this.inputToAdd.type = this.dataTypeMap.get(this.defaultType) ? this.defaultType : undefined;
+ }
this.showForm = true;
this.showAddLink = false;
}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.html
new file mode 100644
index 0000000000..3103421a8d
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.html
@@ -0,0 +1,168 @@
+<!--
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2023 Nordix Foundation. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+-->
+
+<div class="sub-operation-filters">
+ <div class="group-with-border content-row">
+ <form novalidate class="w-sdc-form two-columns" [formGroup]="filterForm">
+ <div formArrayName="filterFormList">
+ <label class="filters-label"> Filters </label>
+ <div *ngFor="let filter of filters; let idx = index">
+ <div class="side-by-side group-with-border">
+ <div class="form-item">
+ <div class="side-by-side">
+ <div class="form-item">
+ <label class="sdc-timeout-label">Name: </label>
+ <input type="text"
+ class="i-sdc-form-input"
+ [disabled]="isViewOnly"
+ [value]="filter.name"
+ [ngClass]="{'disabled': isViewOnly}"
+ (input)="onFilterNameChange($event.target.value, idx)"
+ required/>
+ </div>
+ <div class="form-item">
+ <label>Constraint: </label>
+ <div class="sdc-dropdown">
+ <select class="i-sdc-form-select"
+ data-tests-id="filter-type"
+ [value]="filter.constraint"
+ [disabled]="isViewOnly"
+ (change)="onFilterConstraintChange($event.target.value, idx)"
+ required>
+ <option *ngIf="filter" [value]="filter.constraint" hidden selected>
+ {{ ConstraintTypesMapping[filter.constraint] }}
+ </option>
+ <option *ngFor="let operatorType of operatorTypes"
+ [value]="operatorType">
+ {{ ConstraintTypesMapping[operatorType] }}
+ </option>
+ </select>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="form-item">
+ <div class="side-by-side">
+ <div class="form-item-big">
+ <fieldset class="padding-zero" [disabled]="isViewOnly" >
+ <label>Value: </label>
+ <input type="radio" [name]="'hasGetFunctionValue.' + filter.name + idx"
+ [value]="false"
+ [checked]="!isToscaFunction(idx)"
+ (change)="onValueTypeChange($event.target.value, idx)"/> Value
+ <input type="radio" [name]="'hasGetFunctionValue.' + filter.name + idx"
+ [checked]="isToscaFunction(idx)"
+ (change)="onValueTypeChange($event.target.value, idx)"
+ [value]="true"/> {{'TOSCA_FUNCTION_LABEL' | translate}}
+ </fieldset>
+ <div *ngIf="isToscaFunction(idx)">
+ <div *ngIf="componentInstanceMap">
+ <tosca-function
+ [property]="getAsProperty(idx)"
+ [allowClear]="false"
+ [customToscaFunctions]="customToscaFunctions"
+ [componentInstanceMap]="componentInstanceMap"
+ (onValidityChange)="onToscaFunctionValidityChange($event, idx)">
+ </tosca-function>
+ </div>
+ <div *ngIf="!componentInstanceMap">
+ <tosca-function
+ [property]="getAsProperty(idx)"
+ [allowClear]="false"
+ [customToscaFunctions]="customToscaFunctions"
+ (onValidityChange)="onToscaFunctionValidityChange($event, idx)">
+ </tosca-function>
+ </div>
+ </div>
+ <div *ngIf="!isToscaFunction(idx)">
+ <div *ngIf="filter.constraint == 'validValues'">
+ <div class="add-btn padding-bottom"
+ [ngClass]="{'disabled': isViewOnly}"
+ (click)="addToList(idx)">
+ Add to List
+ </div>
+ <div class="w-sdc-form-columns-wrapper padding-bottom" *ngFor="let value of constraintValuesArray(idx); let valueIndex = index; trackBy:trackByFn">
+ <div class="w-sdc-form-column">
+ <input type="text" required
+ (change)="onChangeConstrainValueIndex(idx, $event.target.value, valueIndex)"
+ [disabled]="isViewOnly"
+ [value]="getInRangeValue(idx, valueIndex)"/>
+ </div>
+ <div class="w-sdc-form-column">
+ <span class="sprite-new delete-btn" [ngClass]="{'disabled': isViewOnly}" (click)="removeFromList(idx, valueIndex)"></span>
+ </div>
+ </div>
+ </div>
+ <div *ngIf="filter.constraint == 'inRange'">
+ <div class="side-by-side">
+ <div class="form-item-50">
+ <input type="text" required
+ (input)="onChangeConstrainValueIndex(idx, $event.target.value, 0)"
+ [disabled]="isViewOnly"
+ [value]="getInRangeValue(idx, 0)"/>
+ </div>
+ <div class="form-item-50">
+ <input type="text" required
+ (input)="onChangeConstrainValueIndex(idx, $event.target.value, 1)"
+ [disabled]="isViewOnly"
+ [value]="getInRangeValue(idx, 1)"/>
+ </div>
+ </div>
+ </div>
+ <div *ngIf="filter.constraint != 'inRange' && filter.constraint != 'validValues'">
+ <input type="text"
+ class="i-sdc-form-input"
+ [disabled]="isViewOnly"
+ [ngClass]="{'disabled': isViewOnly}"
+ [value]="filter.filterValue"
+ (input)="onFilterValueChange($event.target.value, idx)"
+ required/>
+ </div>
+ </div>
+ </div>
+ <div class="form-item-icon">
+ <span class="sprite-new delete-btn" [ngClass]="{'disabled': isViewOnly}" (click)="removeFromFilters(idx)"></span>
+ </div>
+ </div>
+ </div>
+ </div>
+ <div class="w-sdc-form-columns-wrapper">
+ <div class="validation-errors">
+ <ng-container *ngFor="let validation of validationMessages.filter">
+ <div class="input-error" *ngIf="filterFormArray.at(idx).hasError(validation.type);">
+ {{ validation.message }}
+ </div>
+ </ng-container>
+ </div>
+ </div>
+ </div>
+
+ <div class="add-button-container group-with-border" *ngIf="!isViewOnly && activitiesExist">
+ <a class="add-btn" data-tests-id="add-input.add-input-link"
+ (click)="addFilter()">Add Filter</a>
+ </div>
+ <div *ngIf="!activitiesExist">
+ Must have at leat one actifity before adding filters
+ </div>
+ </div>
+ </form>
+ </div>
+</div>
+
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.less b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.less
new file mode 100644
index 0000000000..a17b4b97e4
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.less
@@ -0,0 +1,110 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+@import '../../../../../../../assets/styles/variables.less';
+@import '../../../../../../../assets/styles/override.less';
+
+.group-with-border {
+ margin: 10px 0;
+ padding: 10px 0;
+ border-top: 1px solid @tlv_color_u;
+ .content-row:not(:last-of-type) {
+ padding-bottom: 13px;
+ }
+}
+
+.group-with-border-blue {
+ margin: 10px 0;
+ padding: 10px 0;
+ border-top: 1px solid @tlv_color_x;
+ .content-row:not(:last-of-type) {
+ padding-bottom: 13px;
+ }
+}
+
+.i-sdc-form-select, .i-sdc-form-input {
+ color: #5a5a5a;
+ font-family: OpenSans-Regular, sans-serif;
+ font-size: 14px;
+ background-color: #ffffff;
+ border-radius: 2px;
+ margin: 0;
+ padding: 0;
+ border: solid 1px #d2d2d2;
+ height: 30px;
+ width: 100%;
+ display: block;
+}
+
+.padding-bottom {
+ padding-bottom: 10px;
+}
+
+.padding-zero {
+ padding: 0px;
+}
+
+.side-by-side {
+ display: flex;
+
+ .form-item {
+ flex: 1 1 auto;
+
+ &:first-child {
+ margin-right: 14px;
+ flex-basis: 37%;
+ flex-grow: 0;
+ flex-shrink: 0;
+ }
+
+ &:nth-child(3) {
+ margin-left: 14px;
+ flex: 0.4;
+ }
+ }
+
+ .form-item-50 {
+ flex: 1 1 auto;
+ flex-grow: 0;
+ flex-basis: 50%;
+
+ &:first-child {
+ margin-right: 14px;
+ }
+
+ &:nth-child(3) {
+ margin-left: 14px;
+ }
+ }
+
+ .form-item-big {
+ flex: 1 1 auto;
+ flex-grow: 0;
+ flex-basis: 90%;
+ }
+
+ .form-item-icon {
+ margin-left: auto;
+ margin-right: 14px;
+
+ .sprite-new {
+ margin-top: 110%;
+ }
+ }
+} \ No newline at end of file
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.spec.ts
new file mode 100644
index 0000000000..3b9fdbf345
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.spec.ts
@@ -0,0 +1,53 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FiltersListComponent } from './filters-list.component';
+import { TranslateModule } from '../../../../../shared/translator/translate.module';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { ToscaFunctionModule } from '../../../../properties-assignment/tosca-function/tosca-function.module';
+import { SdcUiComponentsModule } from "onap-ui-angular/dist";
+
+describe('FiltersListComponent', () => {
+ let component: FiltersListComponent;
+ let fixture: ComponentFixture<FiltersListComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ FiltersListComponent ],
+ imports: [
+ FormsModule,
+ ReactiveFormsModule,
+ TranslateModule,
+ SdcUiComponentsModule,
+ ToscaFunctionModule
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(FiltersListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.ts
new file mode 100644
index 0000000000..5aaaea5327
--- /dev/null
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/filters-list/filters-list.component.ts
@@ -0,0 +1,241 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2023 Nordix Foundation
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+import { Component, EventEmitter, Input, OnInit, Output, SimpleChanges} from '@angular/core';
+import {
+ AbstractControl,
+ FormArray,
+ FormControl,
+ FormGroup, ValidationErrors,
+ ValidatorFn,
+ Validators
+} from '@angular/forms';
+import {
+ FilterParameter,
+ IFilterParameterList
+} from '../../../../../../models/interfaceOperation';
+import { InstanceFeDetails } from '../../../../../../models/instance-fe-details';
+import { ConstraintTypes, ConstraintTypesMapping } from '../../../../../pages/properties-assignment/constraints/constraints.component';
+import {CustomToscaFunction } from '../../../../../../models/default-custom-functions';
+import { ToscaFunction } from '../../../../../../models/tosca-function';
+import { PropertyBEModel } from '../../../../../../models/properties-inputs/property-be-model';
+import { ToscaFunctionValidationEvent } from '../../../../properties-assignment/tosca-function/tosca-function.component';
+
+@Component({
+ selector: 'filters-list',
+ templateUrl: './filters-list.component.html',
+ styleUrls: ['./filters-list.component.less']
+})
+export class FiltersListComponent implements OnInit {
+
+ @Input() customToscaFunctions: Array<CustomToscaFunction> = [];
+ @Input() componentInstanceMap: Map<string, InstanceFeDetails> = new Map();
+ @Input() activitiesExist: boolean;
+ @Input() existingFilters: IFilterParameterList;
+ @Input() isViewOnly: boolean;
+ @Output('filtersChangeEvent') filtersChangeEvent: EventEmitter<any> = new EventEmitter<any>();
+
+ isAProperty: Map<number, PropertyBEModel> = new Map();
+ operatorTypes: any[];
+ ConstraintTypesMapping = ConstraintTypesMapping;
+ filters: FilterParameter[] = [];
+ filterFormArray: FormArray = new FormArray([]);
+ filterForm: FormGroup = new FormGroup (
+ {
+ 'filterFormList': this.filterFormArray
+ }
+ );
+ validationMessages = {
+ filter: [
+ { type: 'required', message: 'Filter name, constraint, and value is required'}
+ ]
+ };
+
+ ngOnInit () {
+ this.operatorTypes = Object.keys(ConstraintTypes).map((key) => ConstraintTypes[key]);
+ }
+
+ ngOnChanges (changes: SimpleChanges) {
+ this.filterForm.valueChanges.subscribe(() => {
+ this.emitOnFilterChange();
+ });
+ if (!changes.activitiesExist) {
+ return;
+ }
+ if (changes.activitiesExist.currentValue) {
+ this.initFilters();
+ } else {
+ this.filters = [];
+ this.filterFormArray = new FormArray([]);
+ this. filterForm = new FormGroup (
+ {
+ 'filterFormList': this.filterFormArray
+ }
+ );
+ }
+ }
+
+ private initFilters () {
+ if (this.existingFilters && this.existingFilters.listToscaDataDefinition && this.existingFilters.listToscaDataDefinition.length > 0) {
+ this.existingFilters.listToscaDataDefinition.forEach(val => {
+ this.filters.push(val);
+ this.filterFormArray.push(
+ new FormControl(val, [Validators.required, this.formControlValidator()])
+ );
+ })
+ }
+ }
+
+ private emitOnFilterChange (): void {
+ this.filtersChangeEvent.emit({
+ filters: this.filters,
+ valid: this.filterForm.valid
+ });
+ }
+
+ addFilter () {
+ let filterParameter: FilterParameter = {
+ name: null,
+ constraint: null,
+ filterValue: null
+ }
+ this.filters.push(filterParameter);
+ this.filterFormArray.push(
+ new FormControl(filterParameter, [Validators.required, this.formControlValidator()])
+ );
+ }
+
+ private formControlValidator (): ValidatorFn {
+ return (control: AbstractControl): ValidationErrors | null => {
+ const filter = control.value;
+
+ if (!filter || !filter.name || !filter.constraint || !filter.filterValue) {
+ return {required:true};
+ }
+ return null;
+ }
+ }
+
+ removeFromFilters (index: number) {
+ this.filters.splice(index, 1);
+ this.filterFormArray.removeAt(index);
+ }
+
+ onFilterConstraintChange (type: string, index: number) {
+ let filter = this.filterFormArray.controls[index].value;
+ filter.constraint = type;
+ if (ConstraintTypes.valid_values == type || ConstraintTypes.in_range == type) {
+ filter.filterValue = [];
+ } else {
+ filter.filterValue = '';
+ }
+ this.filterFormArray.controls[index].setValue(filter);
+ }
+
+ onFilterValueChange (value: any, index: number) {
+ let filter = this.filterFormArray.controls[index].value;
+ filter.filterValue = value;
+ this.filterFormArray.controls[index].setValue(filter);
+ }
+
+ onFilterNameChange (value: any, index: number) {
+ let filter = this.filterFormArray.controls[index].value;
+ filter.name = value;
+ this.filterFormArray.controls[index].setValue(filter);
+ }
+
+ getInRangeValue (index: number, valueIndex: number): string {
+ const value = this.filters[index].filterValue;
+
+ if (!value || !value[valueIndex]) {
+ return '';
+ }
+
+ return value[valueIndex];
+ }
+
+ onChangeConstrainValueIndex (index: number, newValue: any, valueIndex: number) {
+ let filter = this.filterFormArray.controls[index].value;
+ if (!filter.filterValue) {
+ filter.filterValue = [];
+ }
+ filter.filterValue[valueIndex] = newValue;
+ this.filterFormArray.controls[index].setValue(filter);
+ }
+
+ constraintValuesArray (index: number) {
+ let filters = this.filterForm.get('filterFormList') as FormArray;
+ return filters.at(index).value.filterValue;
+ }
+
+ addToList (filterIndex: number) {
+ this.constraintValuesArray(filterIndex).push('');
+ }
+
+ removeFromList (filterIndex: number, valueIndex: number) {
+ this.constraintValuesArray(filterIndex).splice(valueIndex, 1);
+ }
+
+ onValueTypeChange (value: string, index: number) {
+ if (value === 'true') {
+ let filter = this.filterFormArray.controls[index].value;
+ if (!filter.toscaFunction) {
+ filter.toscaFunction = {} as ToscaFunction;
+ }
+ filter.filterValue = '';
+ this.filterFormArray.controls[index].setValue(filter);
+ } else {
+ let filter = this.filterFormArray.controls[index].value;
+ filter.toscaFunction = undefined;
+ this.filterFormArray.controls[index].setValue(filter);
+ if (this.isAProperty.has(index)) {
+ this.isAProperty.delete(index);
+ }
+ }
+ }
+
+ getAsProperty(index: number) {
+ if (!this.isAProperty.has(index)) {
+ let filter = this.filterFormArray.controls[index].value;
+ let property = new PropertyBEModel();
+ property.type = 'any';
+ property.toscaFunction = filter.toscaFunction;
+ property.value = filter.filterValue;
+ this.isAProperty.set(index, property);
+ return property;
+ }
+ return this.isAProperty.get(index);
+ }
+
+ onToscaFunctionValidityChange(validationEvent: ToscaFunctionValidationEvent, index: number):void {
+ if (validationEvent.isValid) {
+ let filter = this.filterFormArray.controls[index].value;
+ filter.toscaFunction = validationEvent.toscaFunction;
+ filter.filterValue = validationEvent.toscaFunction.buildValueString();
+ this.filterFormArray.controls[index].setValue(filter);
+ }
+ }
+
+ isToscaFunction(index: number): boolean {
+ let filter = this.filterFormArray.controls[index].value;
+ let toscaFunction = filter.toscaFunction;
+ return toscaFunction;
+ }
+
+}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts
index 116b9ebc9d..80dd252a66 100644
--- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/input-list/input-list-item/input-list-item.component.ts
@@ -95,6 +95,7 @@ export class InputListItemComponent implements OnInit {
this.property.toscaFunction = this.toscaFunction;
this.valueObjRef = this.toscaFunction.value;
} else {
+ this.property = this.property ? this.property : new PropertyBEModel();
this.property.toscaFunction = undefined;
}
}
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html
index 38aed30918..787655542f 100644
--- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.html
@@ -156,5 +156,31 @@
<option value="day">Days</option>
</select>
</div>
+
+ <div class="group-with-border content-row">
+ <label class="sub-operations-label"> Sub operations </label>
+ <tabs tabStyle="basic-tabs" [hideIndicationOnTabChange]="true" (tabChanged)="tabChanged($event)">
+ <div *ngFor="let milestone of milestones">
+ <tab tabTitle="{{milestone}}" [active]="isActiveTab(milestone)" [highlight]="isInvalidActivity(milestone)">
+ <filters-list
+ [customToscaFunctions]="customToscaFunctions"
+ [activitiesExist]="getExistingActivities(milestone) ? true : false"
+ [isViewOnly]="isViewOnly"
+ [componentInstanceMap]="componentInstanceMap"
+ [existingFilters]="getExistingFilters(milestone)"
+ (filtersChangeEvent)="filtersChangeEvent($event, milestone)">
+ </filters-list>
+ <activities-list
+ [isViewOnly]="isViewOnly"
+ [dataTypeMap]="dataTypeMap"
+ [dataTypeMap$]="dataTypeMap$"
+ [componentInstanceMap]="componentInstanceMap"
+ [existingActivities]="getExistingActivities(milestone)"
+ (activitiesChangeEvent)="activitiesChangeEvent($event, milestone)">
+ </activities-list>
+ </tab>
+ </div>
+ </tabs>
+ </div>
</form>
</div>
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts
index 5c5ec1be34..d3f02e71c1 100644
--- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.component.ts
@@ -21,7 +21,17 @@
import {Component, EventEmitter, Output, ViewChild} from '@angular/core';
import { FormControl } from '@angular/forms';
import {UIInterfaceModel} from "../interface-operations.component";
-import {InputOperationParameter, InterfaceOperationModel, IOperationParamsList} from "../../../../../models/interfaceOperation";
+import {
+ ActivityParameter,
+ IActivityParameterList,
+ IFilterParameterList,
+ InputOperationParameter,
+ InterfaceOperationModel,
+ IOperationParamsList,
+ FilterParameter,
+ Milestone,
+ MilestoneEnum
+} from "../../../../../models/interfaceOperation";
import {TranslateService} from "../../../../shared/translator/translate.service";
import {DropdownValue} from "../../../../components/ui/form-components/dropdown/ui-element-dropdown.component";
import {ArtifactModel} from "../../../../../models/artifacts";
@@ -57,7 +67,9 @@ export class InterfaceOperationHandlerComponent {
validityChangedCallback: Function;
isViewOnly: boolean;
isEdit: boolean;
- validImplementationProps:boolean;
+ validImplementationProps: boolean;
+ validMilestoneActivities: boolean;
+ validMilestoneFilters: boolean;
modelName: string;
};
@@ -73,7 +85,9 @@ export class InterfaceOperationHandlerComponent {
isLoading: boolean = false;
isViewOnly: boolean;
isEdit: boolean;
- validImplementationProps:boolean;
+ validImplementationProps: boolean;
+ validMilestoneActivities: boolean;
+ validMilestoneFilters: boolean;
interfaceTypes: Array<DropdownValue> = [];
interfaceTypeOptions: Array<DropDownOption> = [];
selectedInterfaceType: DropDownOption = undefined;
@@ -92,6 +106,10 @@ export class InterfaceOperationHandlerComponent {
inputTypeOptions: any[];
timeoutValue = new FormControl('');
timeoutType = new FormControl('');
+ invalidMilestones: string[] = [];
+ activeTab: string;
+ milestones = Object.keys(MilestoneEnum)
+ .map(key => MilestoneEnum[key]);
constructor(private dataTypeService: DataTypeService,
private componentServiceNg2: ComponentServiceNg2,
@@ -102,6 +120,8 @@ export class InterfaceOperationHandlerComponent {
this.isViewOnly = this.input.isViewOnly;
this.isEdit = this.input.isEdit;
this.validImplementationProps = this.input.validImplementationProps;
+ this.validMilestoneActivities = this.input.validMilestoneActivities;
+ this.validMilestoneFilters = this.input.validMilestoneFilters;
this.componentInstanceMap = this.input.componentInstanceMap ? this.input.componentInstanceMap : null;
this.interfaceType = this.input.selectedInterface.type;
this.operationToUpdate = new InterfaceOperationModel(this.input.selectedInterfaceOperation);
@@ -125,6 +145,9 @@ export class InterfaceOperationHandlerComponent {
this.timeoutType.setValue("day");
}
}
+ if (!this.operationToUpdate.milestones) {
+ this.operationToUpdate.milestones = {};
+ }
this.initCustomToscaFunctions();
this.initInputs();
this.removeImplementationQuote();
@@ -441,6 +464,107 @@ export class InterfaceOperationHandlerComponent {
this.operationToUpdate.operationType = dropDownOption ? dropDownOption.value : undefined;
this.selectedInterfaceOperation = dropDownOption ? dropDownOption : undefined;
}
+
+ getExistingFilters(key: string) {
+ if (this.operationToUpdate.milestones[key] && this.operationToUpdate.milestones[key].filters) {
+ return this.operationToUpdate.milestones[key].filters
+ }
+ return undefined;
+ }
+
+ filtersChangeEvent($event: any, milestone: string) {
+ if ($event.valid) {
+ if (this.invalidMilestones.indexOf(milestone) > -1) {
+ this.invalidMilestones.splice(this.invalidMilestones.indexOf(milestone), 1);
+ this.validMilestoneFilters = this.invalidMilestones.length < 1;
+ this.validMilestoneActivities = this.invalidMilestones.length < 1;
+ }
+ let operationMilestone = this.operationToUpdate.milestones[milestone];
+ if (!operationMilestone) {
+ operationMilestone = new Milestone();
+ }
+ operationMilestone.filters = new class implements IFilterParameterList {
+ listToscaDataDefinition: Array<FilterParameter> = [];
+ }
+ let milestoneFilters = $event.filters;
+ for (let filter of milestoneFilters) {
+ let filterParameter = new FilterParameter();
+ filterParameter.constraint = filter.constraint;
+ filterParameter.name = filter.name;
+ filterParameter.filterValue = filter.filterValue;
+ filterParameter.toscaFunction = filter.toscaFunction;
+ operationMilestone.filters.listToscaDataDefinition.push(filterParameter);
+ }
+ this.operationToUpdate.milestones[milestone] = operationMilestone;
+ } else {
+ if (this.invalidMilestones.indexOf(milestone) == -1) {
+ this.invalidMilestones.push(milestone);
+ }
+ this.validMilestoneFilters = false;
+ this.validMilestoneActivities = false;
+ }
+ }
+
+ getExistingActivities(key: string) {
+ if (
+ this.operationToUpdate.milestones[key]
+ && this.operationToUpdate.milestones[key].activities
+ && this.operationToUpdate.milestones[key].activities.listToscaDataDefinition
+ && this.operationToUpdate.milestones[key].activities.listToscaDataDefinition.length > 0
+ ) {
+ return this.operationToUpdate.milestones[key].activities
+ }
+ return undefined;
+ }
+
+ activitiesChangeEvent($event: any, milestone: string) {
+ if ($event.valid) {
+ if (this.invalidMilestones.indexOf(milestone) > -1) {
+ this.invalidMilestones.splice(this.invalidMilestones.indexOf(milestone), 1);
+ this.validMilestoneActivities = this.invalidMilestones.length < 1;
+ this.validMilestoneFilters = this.invalidMilestones.length < 1;
+ }
+ let operationMilestone = this.operationToUpdate.milestones[milestone];
+ if (!operationMilestone) {
+ operationMilestone = new Milestone();
+ }
+ operationMilestone.activities = new class implements IActivityParameterList {
+ listToscaDataDefinition: Array<ActivityParameter> = [];
+ }
+ let milestoneActivities = $event.activities;
+ for (let activity of milestoneActivities) {
+ let activityParameter = new ActivityParameter();
+ activityParameter.type = activity.type;
+ activityParameter.workflow = activity.workflow;
+ activityParameter.inputs = activity.inputs;
+ operationMilestone.activities.listToscaDataDefinition.push(activityParameter);
+ }
+ this.operationToUpdate.milestones[milestone] = operationMilestone;
+ } else {
+ if (this.invalidMilestones.indexOf(milestone) == -1) {
+ this.invalidMilestones.push(milestone);
+ }
+ this.validMilestoneActivities = false;
+ this.validMilestoneFilters = false;
+ }
+ }
+
+ isActiveTab(title: string): boolean {
+ if (this.activeTab) {
+ return this.activeTab == title;
+ }
+ return this.milestones[0] == title;
+ }
+
+ tabChanged = (event) => {
+ this.activeTab = event.title;
+ }
+
+ isInvalidActivity(title: string) {
+ if (this.invalidMilestones.indexOf(title) > -1) {
+ return "#cf2a2a";
+ }
+ }
}
class DropDownOption implements IDropDownOption {
diff --git a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts
index 3fa20ab624..f79de44ef7 100644
--- a/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts
+++ b/catalog-ui/src/app/ng2/pages/composition/interface-operatons/operation-creator/interface-operation-handler.module.ts
@@ -19,22 +19,25 @@
* ============LICENSE_END=========================================================
*/
-import {NgModule} from "@angular/core";
-import {CommonModule} from "@angular/common";
+import { NgModule} from '@angular/core';
+import { CommonModule} from '@angular/common';
-import {FormsModule, ReactiveFormsModule} from "@angular/forms";
-import {BrowserModule} from '@angular/platform-browser';
-import {FormElementsModule} from "app/ng2/components/ui/form-components/form-elements.module";
-import {TranslateModule} from "app/ng2/shared/translator/translate.module";
-import {AddInputComponent} from './add-input/add-input.component';
-import {InputListComponent} from './input-list/input-list.component';
-import {InputListItemComponent} from './input-list/input-list-item/input-list-item.component';
-import {PropertyParamRowComponent} from "./property-param-row/property-param-row.component";
-import {InterfaceOperationHandlerComponent} from "./interface-operation-handler.component";
-import {SdcUiComponentsModule} from "onap-ui-angular/dist";
-import {UiElementsModule} from "app/ng2/components/ui/ui-elements.module";
-import {PropertyTableModule} from "app/ng2/components/logic/properties-table/property-table.module";
-import {ToscaFunctionModule} from '../../../properties-assignment/tosca-function/tosca-function.module';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { BrowserModule } from '@angular/platform-browser';
+import { FormElementsModule } from 'app/ng2/components/ui/form-components/form-elements.module';
+import { TranslateModule } from 'app/ng2/shared/translator/translate.module';
+import { AddInputComponent } from './add-input/add-input.component';
+import { InputListComponent } from './input-list/input-list.component';
+import { InputListItemComponent } from './input-list/input-list-item/input-list-item.component';
+import { PropertyParamRowComponent } from './property-param-row/property-param-row.component';
+import { InterfaceOperationHandlerComponent } from './interface-operation-handler.component';
+import { SdcUiComponentsModule } from 'onap-ui-angular/dist';
+import { UiElementsModule } from 'app/ng2/components/ui/ui-elements.module';
+import { PropertyTableModule } from 'app/ng2/components/logic/properties-table/property-table.module';
+import { ToscaFunctionModule } from '../../../properties-assignment/tosca-function/tosca-function.module';
+import { TabModule } from 'app/ng2/components/ui/tabs/tabs.module';
+import { FiltersListComponent } from './filters-list/filters-list.component';
+import { ActivitiesListComponent } from './activities-list/activities-list.component';
@NgModule({
declarations: [
@@ -42,7 +45,9 @@ import {ToscaFunctionModule} from '../../../properties-assignment/tosca-function
PropertyParamRowComponent,
AddInputComponent,
InputListComponent,
- InputListItemComponent
+ InputListItemComponent,
+ FiltersListComponent,
+ ActivitiesListComponent
],
imports: [
CommonModule,
@@ -54,7 +59,8 @@ import {ToscaFunctionModule} from '../../../properties-assignment/tosca-function
UiElementsModule,
PropertyTableModule,
ReactiveFormsModule,
- ToscaFunctionModule
+ ToscaFunctionModule,
+ TabModule
],
exports: [
PropertyParamRowComponent,
diff --git a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts
index 23c855ecb1..82afb0a3e7 100644
--- a/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts
+++ b/catalog-ui/src/app/ng2/pages/interface-definition/interface-definition.page.component.ts
@@ -156,7 +156,9 @@ export class InterfaceDefinitionComponent {
openOperation: OperationModel;
enableWorkflowAssociation: boolean;
workflowIsOnline: boolean;
- validImplementationProps:boolean = true;
+ validImplementationProps: boolean = true;
+ validMilestoneActivities: boolean = true;
+ validMilestoneFilters: boolean = true;
serviceInterfaces: InterfaceModel[];
@Input() component: IComponent;
@@ -186,7 +188,6 @@ export class InterfaceDefinitionComponent {
ngOnInit(): void {
this.isLoading = true;
this.interfaces = [];
- //this.disableFlag = this.readonly;
this.workflowIsOnline = !_.isUndefined(this.PluginsService.getPluginByStateUrl('workflowDesigner'));
Observable.forkJoin(
this.ComponentServiceNg2.getInterfaceOperations(this.component),
@@ -218,7 +219,7 @@ export class InterfaceDefinitionComponent {
});
this.onInstanceSelectedUpdate(this.instancesNavigationData[0]);
this.loadingInstances = false;
-
+
};
if (this.enableWorkflowAssociation && this.workflowIsOnline) {
this.WorkflowServiceNg2.getWorkflows().subscribe(
@@ -275,7 +276,6 @@ export class InterfaceDefinitionComponent {
}
this.interfaces = newInterfaces.map((interf) => new UIInterfaceModel(interf));
} else {
- //this.disableFlag = this.readonly;
this.interfaces = this.serviceInterfaces.map((interf) => new UIInterfaceModel(interf));
}
this.sortInterfaces();
@@ -299,7 +299,12 @@ export class InterfaceDefinitionComponent {
if (this.component.isService()) {
return disable;
}
-
+ const validMilestoneActivities = this.modalInstance.instance.dynamicContent.instance.validMilestoneActivities;
+ const validMilestoneFilters = this.modalInstance.instance.dynamicContent.instance.validMilestoneFilters;
+ if (!validMilestoneActivities || !validMilestoneFilters) {
+ return disable;
+ }
+
let selectedInterfaceOperation = this.modalInstance.instance.dynamicContent.instance.selectedInterfaceOperation;
let isInterfaceOperation:boolean = !(typeof selectedInterfaceOperation == 'undefined' || _.isEmpty(selectedInterfaceOperation));
let selectedInterfaceType = this.modalInstance.instance.dynamicContent.instance.selectedInterfaceType;
@@ -344,6 +349,8 @@ export class InterfaceDefinitionComponent {
validityChangedCallback: this.disableSaveButton,
isViewOnly: this.readonly,
validImplementationProps: this.validImplementationProps,
+ validMilestoneActivities: this.validMilestoneActivities,
+ validMilestoneFilters: this.validMilestoneFilters,
'isEdit': isEdit,
interfaceTypesMap: this.interfaceTypesMap,
modelName: this.component.model
diff --git a/catalog-ui/src/app/utils/common-utils.ts b/catalog-ui/src/app/utils/common-utils.ts
index b4e184ab44..92398e871d 100644
--- a/catalog-ui/src/app/utils/common-utils.ts
+++ b/catalog-ui/src/app/utils/common-utils.ts
@@ -181,13 +181,16 @@ export class CommonUtils {
newOperation.interfaceType = interf.type;
newOperation.interfaceId = interf.uniqueId;
- const {inputs, outputs} = operation;
+ const {inputs, outputs, milestones} = operation;
if (inputs) {
newOperation.createInputsList(inputs.listToscaDataDefinition);
}
if (outputs) {
newOperation.createOutputsList(outputs.listToscaDataDefinition);
}
+ if (milestones) {
+ newOperation.milestones = milestones;
+ }
return newOperation;
}