diff options
author | MichaelMorris <michael.morris@est.tech> | 2020-12-15 16:12:59 +0000 |
---|---|---|
committer | Michael Morris <michael.morris@est.tech> | 2021-01-12 16:35:48 +0000 |
commit | 69779180f8f4e020606634f9bd8cac728daed2a2 (patch) | |
tree | 87167832f478509436365d07bd2e46a9c8970365 /catalog-ui/src | |
parent | 1f4756dab7b29843a89fb42943ae3dc0ee8b1ae9 (diff) |
Support for category specific metadata
Signed-off-by: MichaelMorris <michael.morris@est.tech>
Issue-ID: SDC-3412
Change-Id: I87392cc21dc25253b558bdc1d453d99659d049fa
Diffstat (limited to 'catalog-ui/src')
9 files changed, 171 insertions, 3 deletions
diff --git a/catalog-ui/src/app/models/category.ts b/catalog-ui/src/app/models/category.ts index 15df98569d..64588d0c44 100644 --- a/catalog-ui/src/app/models/category.ts +++ b/catalog-ui/src/app/models/category.ts @@ -28,6 +28,7 @@ export interface ICategoryBase { normalizedName:string; uniqueId:string; icons:Array<string>; + metadataKeys: IMetadataKey[]; //custom properties filterTerms:string; @@ -46,3 +47,9 @@ export interface ISubCategory extends ICategoryBase { export interface IGroup extends ICategoryBase { } + +export interface IMetadataKey { + name:string; + mandatory:boolean + validValues: string[]; +} diff --git a/catalog-ui/src/app/models/component-metadata.ts b/catalog-ui/src/app/models/component-metadata.ts index 8a4b257f55..186cd8aa39 100644 --- a/catalog-ui/src/app/models/component-metadata.ts +++ b/catalog-ui/src/app/models/component-metadata.ts @@ -21,6 +21,7 @@ import { CapabilitiesGroup, RequirementsGroup } from 'app/models'; import { ComponentType } from 'app/utils'; import { IMainCategory } from './category'; +import { Metadata } from "app/models/metadata"; /** * Created by obarda on 4/18/2017. */ @@ -53,6 +54,7 @@ export interface IComponentMetadata { vspArchived: boolean; selectedCategory: string; filterTerm: string; + categorySpecificMetadata: Metadata; // Resource only resourceType: string; @@ -115,6 +117,7 @@ export class ComponentMetadata implements IComponentMetadata { public toscaResourceName: string; public selectedCategory: string; public filterTerm: string; + public categorySpecificMetadata: Metadata = new Metadata(); // Resource only public resourceType: string; @@ -192,6 +195,7 @@ export class ComponentMetadata implements IComponentMetadata { this.toscaResourceName = response.toscaResourceName; this.capabilities = response.capabilities; this.requirements = response.requirements; + this.categorySpecificMetadata = response.categorySpecificMetadata; return this; } diff --git a/catalog-ui/src/app/models/components/component.ts b/catalog-ui/src/app/models/components/component.ts index a0706b4157..1d48151be8 100644 --- a/catalog-ui/src/app/models/components/component.ts +++ b/catalog-ui/src/app/models/components/component.ts @@ -35,6 +35,7 @@ import {Requirement} from "../requirement"; import {Relationship} from "../graph/relationship"; import { PolicyInstance } from "app/models/graph/zones/policy-instance"; import { GroupInstance } from "../graph/zones/group-instance"; +import { Metadata } from "app/models/metadata"; // import {} @@ -142,6 +143,7 @@ export abstract class Component implements IComponent { public archived:boolean; public vspArchived: boolean; public componentMetadata: ComponentMetadata; + public categorySpecificMetadata: Metadata = new Metadata(); constructor(componentService:IComponentService, protected $q:ng.IQService, component?:Component) { if (component) { @@ -198,12 +200,36 @@ export abstract class Component implements IComponent { this.policies = component.policies; this.archived = component.archived; this.vspArchived = component.vspArchived; + + if (component.categorySpecificMetadata && component.categories && component.categories[0]){ + this.copyCategoryMetadata(component); + this.copySubcategoryMetadata(component); + } } //custom properties this.componentService = componentService; } + private copyCategoryMetadata = (component:Component):void => { + if (component.categories[0].metadataKeys){ + for (let key of Object.keys(component.categorySpecificMetadata)) { + if (component.categories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) { + this.categorySpecificMetadata[key] = component.categorySpecificMetadata[key]; + } + } + } + } + private copySubcategoryMetadata = (component:Component):void => { + if (component.categories[0].subcategories && component.categories[0].subcategories[0] && component.categories[0].subcategories[0].metadataKeys){ + for (let key of Object.keys(component.categorySpecificMetadata)) { + if (component.categories[0].subcategories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) { + this.categorySpecificMetadata[key] = component.categorySpecificMetadata[key]; + } + } + } + } + public setUniqueId = (uniqueId:string):void => { this.uniqueId = uniqueId; }; @@ -543,6 +569,11 @@ export abstract class Component implements IComponent { this.archived = componentMetadata.archived || false; this.vspArchived = componentMetadata.vspArchived; this.componentMetadata = componentMetadata; + if (componentMetadata.categorySpecificMetadata){ + this.categorySpecificMetadata = componentMetadata.categorySpecificMetadata; + } else { + this.categorySpecificMetadata = new Metadata(); + } } public toJSON = ():any => { diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/__snapshots__/info-tab.component.spec.ts.snap b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/__snapshots__/info-tab.component.spec.ts.snap index fdd0dcf75c..7fcb62dbd3 100644 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/__snapshots__/info-tab.component.spec.ts.snap +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/__snapshots__/info-tab.component.spec.ts.snap @@ -50,6 +50,7 @@ exports[`InfoTabComponent can load instance 1`] = ` + <div class="component-details-panel-item description" > diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.html b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.html index 71545f8143..cafe93e103 100644 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.html +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.html @@ -116,6 +116,14 @@ <span class="value" data-tests-id="rightTab_customizationModuleUUID" tooltip="{{component.customizationUUID}}">{{component.customizationUUID}}</span> </div> + <!-- Category specific metadata --> + <ng-container *ngFor="let metadata of component.categorySpecificMetadata | keyValue"> + <div class="component-details-panel-item"> + <span class="name" innerHTML="{{metadata.key}}"></span> + <span class="value" tooltip="{{metadata.value}}">{{metadata.value}}</span> + </div> + </ng-container> + <!-- DESCRIPTION --> <div class="component-details-panel-item description"> <span class="name" [innerHTML]="'GENERAL_LABEL_DESCRIPTION' | translate"></span> diff --git a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.spec.ts b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.spec.ts index 6915d651f1..388e4b5542 100644 --- a/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.spec.ts +++ b/catalog-ui/src/app/ng2/pages/composition/panel/panel-tabs/info-tab/info-tab.component.spec.ts @@ -19,6 +19,8 @@ import _ from "lodash"; import { TranslateService } from "../../../../../shared/translator/translate.service"; import { SdcUiServices } from "onap-ui-angular"; import { Component as TopologyTemplate, FullComponentInstance, ComponentInstance } from '../../../../../../../app/models'; +import {KeyValuePipe} from "../../../../../pipes/key-value.pipe"; + describe('InfoTabComponent', () => { @@ -48,7 +50,7 @@ describe('InfoTabComponent', () => { const configure: ConfigureFn = testBed => { testBed.configureTestingModule({ imports: [ ], - declarations: [ InfoTabComponent, TranslatePipe ], + declarations: [ InfoTabComponent, TranslatePipe, KeyValuePipe ], schemas: [ NO_ERRORS_SCHEMA ], providers: [ { provide: Store, useValue: {} }, diff --git a/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts b/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts index e10dc98fac..cab4b6c236 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts +++ b/catalog-ui/src/app/view-models/workspace/tabs/general/general-view-model.ts @@ -24,12 +24,13 @@ import {ModalsHandler, ValidationUtils, EVENTS, CHANGE_COMPONENT_CSAR_VERSION_FL ResourceType, ComponentState, instantiationType, ComponentFactory} from "app/utils"; import { EventListenerService, ProgressService} from "app/services"; import {CacheService, OnboardingService, ImportVSPService} from "app/services-ng2"; -import {IAppConfigurtaion, IValidate, IMainCategory, Resource, ISubCategory,Service, ICsarComponent, Component} from "app/models"; +import {IAppConfigurtaion, IValidate, IMainCategory, Resource, ISubCategory,Service, ICsarComponent, Component, IMetadataKey} from "app/models"; import {IWorkspaceViewModelScope} from "app/view-models/workspace/workspace-view-model"; import {Dictionary} from "lodash"; import { PREVIOUS_CSAR_COMPONENT } from "../../../../utils/constants"; import { Observable, Subject } from "rxjs"; - +import { MetadataEntry } from "app/models/metadataEntry"; +import { Metadata } from "app/models/metadata"; export class Validation { componentNameValidationPattern:RegExp; @@ -630,6 +631,20 @@ export class GeneralViewModel { this.$scope.component.selectedCategory = this.$scope.componentCategories.selectedCategory; this.$scope.component.categories = this.convertCategoryStringToOneArray(); this.$scope.component.icon = DEFAULT_ICON; + if (this.$scope.component.categories[0].metadataKeys) { + for (let metadataKey of this.$scope.component.categories[0].metadataKeys) { + if (!this.$scope.component.categorySpecificMetadata[metadataKey.name]) { + this.$scope.component.categorySpecificMetadata[metadataKey.name] = ""; + } + } + } + if (this.$scope.component.categories[0].subcategories && this.$scope.component.categories[0].subcategories[0].metadataKeys) { + for (let metadataKey of this.$scope.component.categories[0].subcategories[0].metadataKeys) { + if (!this.$scope.component.categorySpecificMetadata[metadataKey.name]) { + this.$scope.component.categorySpecificMetadata[metadataKey.name] = ""; + } + } + } }; this.$scope.onEcompGeneratedNamingChange = (): void => { @@ -645,11 +660,51 @@ export class GeneralViewModel { }; this.EventListenerService.registerObserverCallback(EVENTS.ON_LIFECYCLE_CHANGE, this.$scope.reload); + + this.$scope.isMetadataKeyMandatory = (key: string): boolean => { + let metadataKey = this.getMetadataKey(this.$scope.component.categories, key); + return metadataKey && metadataKey.mandatory; + } + + this.$scope.getMetadataKeyValidValues = (key: string): string[] => { + let metadataKey = this.getMetadataKey(this.$scope.component.categories, key); + if (metadataKey) { + return metadataKey.validValues; + } + return []; + } + + this.$scope.isMetadataKeyForComponentCategory = (key: string): boolean => { + return this.getMetadataKey(this.$scope.component.categories, key) != null; + } + } private setUnsavedChanges = (hasChanges: boolean): void => { this.$state.current.data.unsavedChanges = hasChanges; } + private getMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey { + let metadataKey = this.getSubcategoryMetadataKey(this.$scope.component.categories, key); + if (!metadataKey){ + return this.getCategoryMetadataKey(this.$scope.component.categories, key); + } + return metadataKey; + } + + private getSubcategoryMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey { + if (categories[0].subcategories && categories[0].subcategories[0].metadataKeys && categories[0].subcategories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) { + return categories[0].subcategories[0].metadataKeys.find(metadataKey => metadataKey.name == key); + } + return null; + } + + private getCategoryMetadataKey(categories: IMainCategory[], key: string) : IMetadataKey { + if (categories[0].metadataKeys && categories[0].metadataKeys.some(metadataKey => metadataKey.name == key)) { + return categories[0].metadataKeys.find(metadataKey => metadataKey.name == key); + } + return null; + } + } diff --git a/catalog-ui/src/app/view-models/workspace/tabs/general/general-view.html b/catalog-ui/src/app/view-models/workspace/tabs/general/general-view.html index 42a8aa3e68..a04948e460 100644 --- a/catalog-ui/src/app/view-models/workspace/tabs/general/general-view.html +++ b/catalog-ui/src/app/view-models/workspace/tabs/general/general-view.html @@ -114,6 +114,65 @@ <!--------------------- CATEGORIES --------------------> </div> </div> + + <!--------------------- Category Specific Metadata --------------------> + + <div ng-if="component.selectedCategory"> + <ng-container ng-repeat="(key, value) in component.categorySpecificMetadata"--> + <div ng-if="isMetadataKeyForComponentCategory(key) && getMetadataKeyValidValues(key) && isMetadataKeyMandatory(key)" + class="i-sdc-form-item" + data-ng-class="{'error': validateField(editForm['{{key}}'])}"> + <label class="i-sdc-form-label required" translate="{{key}}"></label> + <select class="i-sdc-form-select" + name="{{key}}" + data-ng-class="{'view-mode': isViewMode()}" + data-ng-model="component.categorySpecificMetadata[key]" + data-tests-id="{{key}}" + data-required> + <option ng-repeat="value in getMetadataKeyValidValues(key)">{{value}}</option> + </select> + <div class="input-error" data-ng-show="validateField(editForm['{{key}}'])"> + <span ng-show="editForm['{{key}}'].$error.required" translate="NEW_SERVICE_RESOURCE_ERROR_REQUIRED"></span> + </div> + </div> + <div ng-if="isMetadataKeyForComponentCategory(key) && getMetadataKeyValidValues(key) && !isMetadataKeyMandatory(key)" + class="i-sdc-form-item"> + <label class="i-sdc-form-label" translate="{{key}}"></label> + <select class="i-sdc-form-select" + name="{{key}}" + data-ng-class="{'view-mode': isViewMode()}" + data-ng-model="component.categorySpecificMetadata[key]" + data-tests-id="{{key}}"> + <option ng-repeat="value in getMetadataKeyValidValues(key)">{{value}}</option> + </select> + </div> + <div ng-if="isMetadataKeyForComponentCategory(key) && !getMetadataKeyValidValues(key) && isMetadataKeyMandatory(key)" + class="i-sdc-form-item" + data-ng-class="{'error': validateField(editForm['{{key}}'])}"> + <label class="i-sdc-form-label required" translate="{{key}}"></label> + <input class="i-sdc-form-input" type="text" + data-required + data-ng-class="{'view-mode': isViewMode()}" + data-ng-model="component.categorySpecificMetadata[key]" + name="{{key}}" + data-tests-id="{{key}}" + /> + <div class="input-error" data-ng-show="validateField(editForm['{{key}}'])"> + <span ng-show="editForm['{{key}}'].$error.required" translate="NEW_SERVICE_RESOURCE_ERROR_REQUIRED"></span> + </div> + </div> + <div ng-if="isMetadataKeyForComponentCategory(key) && !getMetadataKeyValidValues(key) && !isMetadataKeyMandatory(key)" + class="i-sdc-form-item"> + <label class="i-sdc-form-label" translate="{{key}}"></label> + <input class="i-sdc-form-input" type="text" + data-ng-class="{'view-mode': isViewMode()}" + data-ng-model="component.categorySpecificMetadata[key]" + name="{{key}}" + data-tests-id="{{key}}" + /> + </div> + </ng-container> + </div> <!--------------------- RESOURCE TAGS --------------------> <div class="i-sdc-form-item" data-ng-class="{'error': validateField(editForm.tags)}"> <label class="i-sdc-form-label" translate="GENERAL_LABEL_TAGS"></label> diff --git a/catalog-ui/src/assets/languages/en_US.json b/catalog-ui/src/assets/languages/en_US.json index cad8fc78df..fd4a3826b3 100644 --- a/catalog-ui/src/assets/languages/en_US.json +++ b/catalog-ui/src/assets/languages/en_US.json @@ -228,6 +228,7 @@ "NEW_SERVICE_RESOURCE_ERROR_RESOURCE_DESCRIPTION_REQUIRED": "Description is required.", "NEW_SERVICE_RESOURCE_ERROR_VENDOR_NAME_REQUIRED": "Vendor name is required.", "NEW_SERVICE_RESOURCE_ERROR_VENDOR_RELEASE_REQUIRED": "Vendor Release is required.", + "NEW_SERVICE_RESOURCE_ERROR_REQUIRED": "Value is required.", "NEW_SERVICE_RESOURCE_ERROR_TEMPLATE_REQUIRED": "Template is required.", "NEW_SERVICE_RESOURCE_ERROR_TAG_PATTERN": "{{text}}", "NEW_SERVICE_RESOURCE_ERROR_VALID_TOSCA_EXTENSIONS_TITLE": "Invalid Tosca file", |