Implement Attributes/Outputs FE

Change-Id: I014bb0ebc07f3fea4266a4f295172eadee546705
Signed-off-by: Vasyl Razinkov <vasyl.razinkov@est.tech>
Issue-ID: SDC-3448
diff --git a/catalog-ui/src/app/models/attributes-outputs/attribute-be-model.ts b/catalog-ui/src/app/models/attributes-outputs/attribute-be-model.ts
new file mode 100644
index 0000000..e06a807
--- /dev/null
+++ b/catalog-ui/src/app/models/attributes-outputs/attribute-be-model.ts
@@ -0,0 +1,105 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 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=========================================================
+ */
+
+import {PROPERTY_DATA, PROPERTY_TYPES} from 'app/utils/constants';
+import {ToscaPresentationData} from '../tosca-presentation';
+import {AttributeOutputDetail} from "app/models/attributes-outputs/attribute-output-detail";
+import {SchemaAttribute, SchemaAttributeGroupModel} from "../schema-attribute";
+
+export enum DerivedAttributeType {
+  SIMPLE,
+  LIST,
+  MAP,
+  COMPLEX
+}
+
+export class AttributeBEModel {
+
+  constraints: any[];
+  defaultValue: string;
+  definition: boolean;
+  description: string;
+  fromDerived: boolean;
+  getOutputValues: AttributeOutputDetail[];
+  name: string;
+  origName: string;
+  parentUniqueId: string;
+  password: boolean;
+  required: boolean;
+  schema: SchemaAttributeGroupModel;
+  schemaType: string;
+  type: string;
+  uniqueId: string;
+  value: string;
+  parentAttributeType: string;
+  subAttributeOutputPath: string;
+  outputPath: string;
+  toscaPresentation: ToscaPresentationData;
+
+  constructor(attribute?: AttributeBEModel) {
+    if (attribute) {
+      this.constraints = attribute.constraints;
+      this.defaultValue = attribute.defaultValue;
+      this.description = attribute.description;
+      this.fromDerived = attribute.fromDerived;
+      this.name = attribute.name;
+      this.origName = attribute.origName;
+      this.parentUniqueId = attribute.parentUniqueId;
+      this.password = attribute.password;
+      this.required = attribute.required;
+      this.schema = attribute.schema;
+      this.schemaType = attribute.schemaType;
+      this.type = attribute.type;
+      this.uniqueId = attribute.uniqueId;
+      this.value = attribute.value;
+      this.definition = attribute.definition;
+      this.getOutputValues = attribute.getOutputValues;
+      this.parentAttributeType = attribute.parentAttributeType;
+      this.subAttributeOutputPath = attribute.subAttributeOutputPath;
+      this.toscaPresentation = attribute.toscaPresentation;
+      this.outputPath = attribute.outputPath;
+    }
+
+    if (!this.schema || !this.schema.property) {
+      this.schema = new SchemaAttributeGroupModel(new SchemaAttribute());
+    } else { // forcing creating new object, so editing different one than the object in the table
+      this.schema = new SchemaAttributeGroupModel(new SchemaAttribute(this.schema.property));
+    }
+  }
+
+  public toJSON = (): any => {
+    const temp = angular.copy(this);
+    temp.value = temp.value === '{}' || temp.value === '[]' ? undefined : temp.value;
+    temp.defaultValue = temp.defaultValue === '{}' || temp.defaultValue === '[]' ? undefined : temp.defaultValue;
+    return temp;
+  }
+
+  public getDerivedAttributeType = () => {
+    if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.type) > -1) {
+      return DerivedAttributeType.SIMPLE;
+    } else if (this.type === PROPERTY_TYPES.LIST) {
+      return DerivedAttributeType.LIST;
+    } else if (this.type === PROPERTY_TYPES.MAP) {
+      return DerivedAttributeType.MAP;
+    } else {
+      return DerivedAttributeType.COMPLEX;
+    }
+  }
+}
diff --git a/catalog-ui/src/app/models/attributes-outputs/attribute-declare-api-model.ts b/catalog-ui/src/app/models/attributes-outputs/attribute-declare-api-model.ts
new file mode 100644
index 0000000..aa05b39
--- /dev/null
+++ b/catalog-ui/src/app/models/attributes-outputs/attribute-declare-api-model.ts
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 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=========================================================
+ */
+
+'use strict';
+import {AttributeBEModel} from "./attribute-be-model";
+import {AttributeFEModel} from "./attribute-fe-model";
+import {DerivedFEAttribute} from "./derived-fe-attribute";
+
+export class AttributeDeclareAPIModel extends AttributeBEModel {
+  output: AttributeBEModel;
+  attributesName: string;
+
+  constructor(attribute: AttributeFEModel, childAttribute?: DerivedFEAttribute) {
+    super(attribute);
+    if (childAttribute) {
+      this.output = childAttribute;
+      this.attributesName = childAttribute.attributesName;
+    }
+  }
+
+}
diff --git a/catalog-ui/src/app/models/attributes-outputs/attribute-fe-map.ts b/catalog-ui/src/app/models/attributes-outputs/attribute-fe-map.ts
new file mode 100644
index 0000000..e962e91
--- /dev/null
+++ b/catalog-ui/src/app/models/attributes-outputs/attribute-fe-map.ts
@@ -0,0 +1,43 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 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=========================================================
+ */
+
+'use strict';
+
+import {AttributeBEModel} from "./attribute-be-model";
+import {AttributeFEModel} from "./attribute-fe-model";
+
+export class InstanceBeAttributesMap {
+  [instanceId: string]: Array<AttributeBEModel>;
+}
+
+export class InstanceFeAttributesMap {
+  [instanceId: string]: Array<AttributeFEModel>;
+}
+
+export class InstanceAttributesAPIMap {
+  componentInstanceAttributes: InstanceBeAttributesMap;
+  componentInstanceOutputsMap: InstanceBeAttributesMap;
+
+  constructor(outputsMapData: InstanceBeAttributesMap, attributesMapData: InstanceBeAttributesMap) {
+    this.componentInstanceOutputsMap = outputsMapData ? outputsMapData : new InstanceBeAttributesMap();
+    this.componentInstanceAttributes = attributesMapData ? attributesMapData : new InstanceBeAttributesMap();
+  }
+
+}
diff --git a/catalog-ui/src/app/models/attributes-outputs/attribute-fe-model.ts b/catalog-ui/src/app/models/attributes-outputs/attribute-fe-model.ts
new file mode 100644
index 0000000..a939783
--- /dev/null
+++ b/catalog-ui/src/app/models/attributes-outputs/attribute-fe-model.ts
@@ -0,0 +1,326 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 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=========================================================
+ */
+
+import * as _ from "lodash";
+import {PROPERTY_DATA, PROPERTY_TYPES} from 'app/utils';
+import {
+  AttributeBEModel,
+  DerivedAttributeType
+} from "app/models/attributes-outputs/attribute-be-model";
+import {DerivedFEAttribute} from "app/models/attributes-outputs/derived-fe-attribute";
+
+export class AttributeFEModel extends AttributeBEModel {
+
+  expandedChildAttributeId: string;
+  flattenedChildren: Array<DerivedFEAttribute>;
+  isDeclared: boolean;
+  isDisabled: boolean;
+  isSelected: boolean;
+  isSimpleType: boolean; //for convenience only - we can really just check if derivedDataType == derivedPropertyTypes.SIMPLE to know if the attrib is simple
+  attributesName: string;
+  uniqueId: string;
+  valueObj: any; //this is the only value we relate to in the html templates
+  valueObjValidation: any;
+  valueObjIsValid: boolean;
+  valueObjOrig: any; //this is valueObj representation as saved in server
+  valueObjIsChanged: boolean;
+  derivedDataType: DerivedAttributeType;
+  origName: string;
+
+  constructor(attribute: AttributeBEModel) {
+    super(attribute);
+    this.value = attribute.value ? attribute.value : attribute.defaultValue;//In FE if a attribute doesn't have value - display the default value
+    this.isSimpleType = PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.type) > -1;
+    this.setNonDeclared();
+    this.derivedDataType = this.getDerivedAttributeType();
+    this.flattenedChildren = [];
+    this.attributesName = this.name;
+    this.valueObj = null;
+    this.updateValueObjOrig();
+    this.resetValueObjValidation();
+    this.origName = this.name;
+  }
+
+
+  public updateValueObj(valueObj: any, isValid: boolean) {
+    this.valueObj = AttributeFEModel.cleanValueObj(valueObj);
+    this.valueObjValidation = this.valueObjIsValid = isValid;
+    this.valueObjIsChanged = this.hasValueObjChanged();
+  }
+
+  public updateValueObjOrig() {
+    this.valueObjOrig = _.cloneDeep(this.valueObj);
+    this.valueObjIsChanged = false;
+  }
+
+  public calculateValueObjIsValid(valueObjValidation?: any) {
+    valueObjValidation = (valueObjValidation !== undefined) ? valueObjValidation : this.valueObjValidation;
+    if (valueObjValidation instanceof Array) {
+      return valueObjValidation.every((v) => this.calculateValueObjIsValid(v));
+    } else if (valueObjValidation instanceof Object) {
+      return Object.keys(valueObjValidation).every((k) => this.calculateValueObjIsValid(valueObjValidation[k]));
+    }
+    return Boolean(valueObjValidation);
+  }
+
+  public resetValueObjValidation() {
+    if (this.derivedDataType === DerivedAttributeType.SIMPLE) {
+      this.valueObjValidation = null;
+    } else if (this.derivedDataType === DerivedAttributeType.LIST) {
+      this.valueObjValidation = [];
+    } else {
+      this.valueObjValidation = {};
+    }
+    this.valueObjIsValid = true;
+  }
+
+  public getJSONValue = (): string => {
+    return AttributeFEModel.stringifyValueObj(this.valueObj, this.schema.property.type, this.derivedDataType);
+  }
+
+  public getValueObj = (): any => {
+    return AttributeFEModel.parseValueObj(this.value, this.type, this.derivedDataType, this.defaultValue);
+  }
+
+  public setNonDeclared = (childPath?: string): void => {
+    if (!childPath) { //un-declaring a child attrib
+      this.isDeclared = false;
+    } else {
+      let childProp: DerivedFEAttribute = this.flattenedChildren.find(child => child.attributesName == childPath);
+      childProp.isDeclared = false;
+    }
+  }
+
+  public setAsDeclared = (childNameToDeclare?: string): void => {
+    if (!childNameToDeclare) { //declaring a child attrib
+      this.isSelected = false;
+      this.isDeclared = true;
+    } else {
+      let childProp: DerivedFEAttribute = this.flattenedChildren.find(child => child.attributesName == childNameToDeclare);
+      if (!childProp) {
+        console.log("ERROR: Unabled to find child: " + childNameToDeclare, this);
+        return;
+      }
+      childProp.isSelected = false;
+      childProp.isDeclared = true;
+    }
+  }
+
+  //For expand-collapse functionality - used within HTML template
+  public updateExpandedChildAttributeId = (childAttributeId: string): void => {
+    if (childAttributeId.lastIndexOf('#') > -1) {
+      this.expandedChildAttributeId = (this.expandedChildAttributeId == childAttributeId) ? (childAttributeId.substring(0, childAttributeId.lastIndexOf('#'))) : childAttributeId;
+    } else {
+      this.expandedChildAttributeId = this.name;
+    }
+  }
+
+  public getIndexOfChild = (childPropName: string): number => {
+    return this.flattenedChildren.findIndex(attrib => attrib.attributesName.indexOf(childPropName) === 0);
+  }
+
+  public getCountOfChildren = (childPropName: string): number => {
+    let matchingChildren: Array<DerivedFEAttribute> = this.flattenedChildren.filter(attrib => attrib.attributesName.indexOf(childPropName) === 0) || [];
+    return matchingChildren.length;
+  }
+
+
+  /* Updates parent valueObj when a child attrib's value has changed */
+  public childPropUpdated = (childProp: DerivedFEAttribute): void => {
+    let parentNames = this.getParentNamesArray(childProp.attributesName, []);
+    if (parentNames.length) {
+      const childPropName = parentNames.join('.');
+      // unset value only if is null and valid, and not in a list
+      if (childProp.valueObj === null && childProp.valueObjIsValid) {
+        const parentChildProp = this.flattenedChildren.find((ch) => ch.attributesName === childProp.parentName) || this;
+        if (parentChildProp.derivedDataType !== DerivedAttributeType.LIST) {
+          _.unset(this.valueObj, childPropName);
+          this.valueObj = AttributeFEModel.cleanValueObj(this.valueObj);
+        } else {
+          _.set(this.valueObj, childPropName, null);
+        }
+      } else {
+        _.set(this.valueObj, childPropName, childProp.valueObj);
+      }
+      if (childProp.valueObjIsChanged) {
+        _.set(this.valueObjValidation, childPropName, childProp.valueObjIsValid);
+        this.valueObjIsValid = childProp.valueObjIsValid && this.calculateValueObjIsValid();
+        this.valueObjIsChanged = true;
+      } else {
+        _.unset(this.valueObjValidation, childPropName);
+        this.valueObjIsValid = this.calculateValueObjIsValid();
+        this.valueObjIsChanged = this.hasValueObjChanged();
+      }
+    }
+  };
+
+  childPropMapKeyUpdated = (childProp: DerivedFEAttribute, newMapKey: string, forceValidate: boolean = false) => {
+    if (!childProp.isChildOfListOrMap || childProp.derivedDataType !== DerivedAttributeType.MAP) {
+      return;
+    }
+
+    const childParentNames = this.getParentNamesArray(childProp.parentName);
+    const oldActualMapKey = childProp.getActualMapKey();
+
+    childProp.mapKey = newMapKey;
+    if (childProp.mapKey === null) {  // null -> remove map key
+      childProp.mapKeyError = null;
+    } else if (!childProp.mapKey) {
+      childProp.mapKeyError = 'Key cannot be empty.';
+    } else if (this.flattenedChildren
+    .filter((fch) => fch !== childProp && fch.parentName === childProp.parentName)  // filter sibling child props
+    .map((fch) => fch.mapKey)
+    .indexOf(childProp.mapKey) !== -1) {
+      childProp.mapKeyError = 'This key already exists.';
+    } else {
+      childProp.mapKeyError = null;
+    }
+    const newActualMapKey = childProp.getActualMapKey();
+    const newMapKeyIsValid = !childProp.mapKeyError;
+
+    // if mapKey was changed, then replace the old key with the new one
+    if (newActualMapKey !== oldActualMapKey) {
+      const oldChildPropNames = childParentNames.concat([oldActualMapKey]);
+      const newChildPropNames = (newActualMapKey) ? childParentNames.concat([newActualMapKey]) : null;
+
+      // add map key to valueObj and valueObjValidation
+      if (newChildPropNames) {
+        const newChildVal = _.get(this.valueObj, oldChildPropNames);
+        if (newChildVal !== undefined) {
+          _.set(this.valueObj, newChildPropNames, newChildVal);
+          _.set(this.valueObjValidation, newChildPropNames, _.get(this.valueObjValidation, oldChildPropNames, childProp.valueObjIsValid));
+        }
+      }
+
+      // remove map key from valueObj and valueObjValidation
+      _.unset(this.valueObj, oldChildPropNames);
+      _.unset(this.valueObjValidation, oldChildPropNames);
+
+      // force validate after map key change
+      forceValidate = true;
+    }
+
+    if (forceValidate) {
+      // add custom entry for map key validation:
+      const childMapKeyNames = childParentNames.concat(`%%KEY:${childProp.name}%%`);
+      if (newActualMapKey) {
+        _.set(this.valueObjValidation, childMapKeyNames, newMapKeyIsValid);
+      } else {
+        _.unset(this.valueObjValidation, childMapKeyNames);
+      }
+
+      this.valueObjIsValid = newMapKeyIsValid && this.calculateValueObjIsValid();
+      this.valueObjIsChanged = this.hasValueObjChanged();
+    }
+  };
+
+  /* Returns array of individual parents for given attrib path, with list/map UUIDs replaced with index/mapkey */
+  public getParentNamesArray = (parentPropName: string, parentNames?: Array<string>, noHashKeys: boolean = false): Array<string> => {
+    parentNames = parentNames || [];
+    if (parentPropName.indexOf("#") == -1) {
+      return parentNames;
+    } //finished recursing parents. return
+
+    let parentAttrib: DerivedFEAttribute = this.flattenedChildren.find(attrib => attrib.attributesName === parentPropName);
+    let nameToInsert: string = parentAttrib.name;
+
+    if (parentAttrib.isChildOfListOrMap) {
+      if (!noHashKeys && parentAttrib.derivedDataType == DerivedAttributeType.MAP) {
+        nameToInsert = parentAttrib.getActualMapKey();
+      } else { //LIST
+        let siblingProps = this.flattenedChildren.filter(attrib => attrib.parentName == parentAttrib.parentName).map(attrib => attrib.attributesName);
+        nameToInsert = siblingProps.indexOf(parentAttrib.attributesName).toString();
+      }
+    }
+
+    parentNames.splice(0, 0, nameToInsert); //add attrib name to array
+    return this.getParentNamesArray(parentAttrib.parentName, parentNames, noHashKeys); //continue recursing
+  }
+
+  public hasValueObjChanged() {
+    return !_.isEqual(this.valueObj, this.valueObjOrig);
+  }
+
+  static stringifyValueObj(valueObj: any, attributeType: PROPERTY_TYPES, derivedAttributeType: DerivedAttributeType): string {
+    // if valueObj is null, return null
+    if (valueObj === null || valueObj === undefined) {
+      return null;
+    }
+
+    //If type is JSON, need to try parsing it before we stringify it so that it appears property in TOSCA - change per Bracha due to AMDOCS
+    //TODO: handle this.derivedDataType == DerivedAttributeType.MAP
+    if (derivedAttributeType == DerivedAttributeType.LIST && attributeType == PROPERTY_TYPES.JSON) {
+      try {
+        return JSON.stringify(valueObj.map(item => (typeof item == 'string') ? JSON.parse(item) : item));
+      } catch (e) {
+      }
+    }
+
+    // if type is anything but string, then stringify valueObj
+    if ((typeof valueObj) !== 'string') {
+      return JSON.stringify(valueObj);
+    }
+
+    // return string value as is
+    return valueObj;
+  }
+
+  static parseValueObj(value: string, attributeType: PROPERTY_TYPES, derivedAttributeType: DerivedAttributeType, defaultValue?: string): any {
+    let valueObj;
+    if (derivedAttributeType === DerivedAttributeType.SIMPLE) {
+      valueObj = value || defaultValue || null;  // use null for empty value object
+      if (valueObj &&
+          attributeType !== PROPERTY_TYPES.STRING &&
+          attributeType !== PROPERTY_TYPES.JSON &&
+          PROPERTY_DATA.SCALAR_TYPES.indexOf(<string>attributeType) == -1) {
+        valueObj = JSON.parse(value);  // the value object contains the real value ans not the value as string
+      }
+    } else if (derivedAttributeType == DerivedAttributeType.LIST) {
+      valueObj = _.merge([], JSON.parse(defaultValue || '[]'), JSON.parse(value || '[]'));  // value object should be merged value and default value. Value takes higher precedence. Set value object to empty obj if undefined.
+    } else {
+      valueObj = _.merge({}, JSON.parse(defaultValue || '{}'), JSON.parse(value || '{}'));  // value object should be merged value and default value. Value takes higher precedence. Set value object to empty obj if undefined.
+    }
+    return valueObj;
+  }
+
+  static cleanValueObj(valueObj: any, unsetEmpty?: boolean): any {
+    // By default - unsetEmpty undefined - will make valueObj cleaned (no null or empty objects, but array will keep null or empty objects).
+    if (valueObj === undefined || valueObj === null || valueObj === '') {
+      return null;
+    }
+    if (valueObj instanceof Array) {
+      const cleanArr = valueObj.map((v) => AttributeFEModel.cleanValueObj(v)).filter((v) => v !== null);
+      valueObj.splice(0, valueObj.length, ...cleanArr)
+    } else if (valueObj instanceof Object) {
+      Object.keys(valueObj).forEach((k) => {
+        // clean each item in the valueObj (by default, unset empty objects)
+        valueObj[k] = AttributeFEModel.cleanValueObj(valueObj[k], unsetEmpty !== undefined ? unsetEmpty : true);
+        if (valueObj[k] === null) {
+          delete valueObj[k];
+        }
+      });
+      // if unsetEmpty flag is true and valueObj is empty
+      if (unsetEmpty && !Object.keys(valueObj).length) {
+        return null;
+      }
+    }
+    return valueObj;
+  }
+}
diff --git a/catalog-ui/src/app/models/attributes-outputs/attribute-output-detail.ts b/catalog-ui/src/app/models/attributes-outputs/attribute-output-detail.ts
new file mode 100644
index 0000000..e646878
--- /dev/null
+++ b/catalog-ui/src/app/models/attributes-outputs/attribute-output-detail.ts
@@ -0,0 +1,26 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 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=========================================================
+ */
+
+export class AttributeOutputDetail {
+  outputId: string;
+  outputName: string;
+  outputPath: string;
+  list: boolean;
+}
diff --git a/catalog-ui/src/app/models/attributes-outputs/derived-fe-attribute.ts b/catalog-ui/src/app/models/attributes-outputs/derived-fe-attribute.ts
new file mode 100644
index 0000000..e9fad4d
--- /dev/null
+++ b/catalog-ui/src/app/models/attributes-outputs/derived-fe-attribute.ts
@@ -0,0 +1,99 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 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=========================================================
+ */
+
+import * as _ from "lodash";
+import {SchemaAttribute, SchemaAttributeGroupModel} from '../../models';
+import {PROPERTY_TYPES} from 'app/utils';
+import {UUID} from "angular2-uuid";
+import {AttributeBEModel, DerivedAttributeType} from "./attribute-be-model";
+import {AttributeFEModel} from "./attribute-fe-model";
+
+export class DerivedFEAttribute extends AttributeBEModel {
+  valueObj: any;
+  valueObjIsValid: boolean;
+  valueObjOrig: any;
+  valueObjIsChanged: boolean;
+  parentName: string;
+  attributesName: string;
+  derivedDataType: DerivedAttributeType;
+  isDeclared: boolean;
+  isSelected: boolean;
+  isDisabled: boolean;
+  hidden: boolean;
+  isChildOfListOrMap: boolean;
+  canBeDeclared: boolean;
+  mapKey: string;
+  mapKeyError: string;
+
+  constructor(attribute: AttributeBEModel, parentName?: string, createChildOfListOrMap?: boolean, key?: string, value?: any) {
+    if (createChildOfListOrMap) { //creating a direct child of list or map (ie. Item that can be deleted, with UUID instead of name)
+      super(null);
+      this.isChildOfListOrMap = true;
+      this.canBeDeclared = false;
+      this.name = UUID.UUID();
+      this.parentName = parentName;
+      this.attributesName = parentName + '#' + this.name;
+
+      if (attribute.type == PROPERTY_TYPES.LIST) {
+        this.mapKey = attribute.schema.property.type.split('.').pop();
+        this.mapKeyError = null;
+        this.type = attribute.schema.property.type;
+      } else { //map
+        if (key) {
+          this.mapKey = key;
+          this.mapKeyError = null;
+        } else {
+          this.mapKey = '';
+          this.mapKeyError = 'Key cannot be empty.';
+        }
+        this.type = attribute.type;
+      }
+      this.valueObj = (this.type == PROPERTY_TYPES.JSON && typeof value == 'object') ? JSON.stringify(value) : value;
+      this.schema = new SchemaAttributeGroupModel(new SchemaAttribute(attribute.schema.property));
+      this.updateValueObjOrig();
+    } else { //creating a standard derived prop
+      super(attribute);
+      this.parentName = parentName ? parentName : null;
+      this.attributesName = (parentName) ? parentName + '#' + attribute.name : attribute.name;
+      this.canBeDeclared = true; //defaults to true
+    }
+    this.valueObjIsValid = true;
+    this.derivedDataType = this.getDerivedAttributeType();
+  }
+
+  public getActualMapKey() {
+    return (this.mapKeyError) ? this.name : this.mapKey;
+  }
+
+  public updateValueObj(valueObj: any, isValid: boolean) {
+    this.valueObj = AttributeFEModel.cleanValueObj(valueObj);
+    this.valueObjIsValid = isValid;
+    this.valueObjIsChanged = this.hasValueObjChanged();
+  }
+
+  public updateValueObjOrig() {
+    this.valueObjOrig = _.cloneDeep(this.valueObj);
+    this.valueObjIsChanged = false;
+  }
+
+  public hasValueObjChanged() {
+    return !_.isEqual(this.valueObj, this.valueObjOrig);
+  }
+}
diff --git a/catalog-ui/src/app/models/attributes-outputs/output-be-model.ts b/catalog-ui/src/app/models/attributes-outputs/output-be-model.ts
new file mode 100644
index 0000000..c5f0bfa
--- /dev/null
+++ b/catalog-ui/src/app/models/attributes-outputs/output-be-model.ts
@@ -0,0 +1,47 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 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=========================================================
+ */
+
+import {AttributeBEModel} from "./attribute-be-model";
+
+export class OutputBEModel extends AttributeBEModel {
+
+  outputPath: string;
+  outputs: Array<OutputComponentInstanceModel>;
+  instanceUniqueId: string;
+  ownerId: string;
+  attributeId: string;
+  attributes: Array<OutputComponentInstanceModel>;
+
+  constructor(output?: OutputBEModel) {
+    super(output);
+    this.instanceUniqueId = output.instanceUniqueId;
+    this.attributeId = output.attributeId;
+    this.attributes = output.attributes;
+    this.outputs = output.outputs;
+    this.ownerId = output.ownerId;
+    this.outputPath = output.outputPath;
+  }
+
+}
+
+export interface OutputComponentInstanceModel extends OutputBEModel {
+  componentInstanceId: string;
+  componentInstanceName: string;
+}
diff --git a/catalog-ui/src/app/models/attributes-outputs/output-fe-model.ts b/catalog-ui/src/app/models/attributes-outputs/output-fe-model.ts
new file mode 100644
index 0000000..8806562
--- /dev/null
+++ b/catalog-ui/src/app/models/attributes-outputs/output-fe-model.ts
@@ -0,0 +1,76 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 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=========================================================
+ */
+
+import * as _ from "lodash";
+import {PROPERTY_DATA} from "../../utils/constants";
+import {OutputBEModel} from "./output-be-model";
+import {AttributeFEModel} from "./attribute-fe-model";
+import {DerivedAttributeType} from "./attribute-be-model";
+
+export class OutputFEModel extends OutputBEModel {
+  isSimpleType: boolean;
+  relatedAttributeValue: any;
+  relatedAttributeName: string;
+  defaultValueObj: any;
+  defaultValueObjIsValid: boolean;
+  defaultValueObjOrig: any;
+  defaultValueObjIsChanged: boolean;
+  derivedDataType: DerivedAttributeType;
+
+  constructor(output?: OutputBEModel) {
+    super(output);
+    if (output) {
+      this.isSimpleType = PROPERTY_DATA.SIMPLE_TYPES.indexOf(this.type) > -1;
+      let relatedAttribute = output.attributes && output.attributes[0] || output.outputs && output.outputs[0];
+      if (relatedAttribute) {
+        this.relatedAttributeValue = relatedAttribute.value;
+        this.relatedAttributeName = relatedAttribute.name;
+      }
+      this.derivedDataType = this.getDerivedAttributeType();
+      this.resetDefaultValueObjValidation();
+      this.updateDefaultValueObjOrig();
+    }
+  }
+
+  public updateDefaultValueObjOrig() {
+    this.defaultValueObjOrig = _.cloneDeep(this.defaultValueObj);
+    this.defaultValueObjIsChanged = false;
+  }
+
+  public getJSONDefaultValue(): string {
+    return AttributeFEModel.stringifyValueObj(this.defaultValueObj, this.schema.property.type, this.derivedDataType);
+  }
+
+  public getDefaultValueObj(): any {
+    return AttributeFEModel.parseValueObj(this.defaultValueObj, this.type, this.derivedDataType);
+  }
+
+  public resetDefaultValueObjValidation() {
+    this.defaultValueObjIsValid = true;
+  }
+
+  hasDefaultValueChanged(): boolean {
+    return !_.isEqual(this.defaultValueObj, this.defaultValueObjOrig);
+  }
+
+  hasChanged(): boolean {
+    return this.hasDefaultValueChanged() ;
+  }
+}
diff --git a/catalog-ui/src/app/models/attributes-outputs/simple-flat-attribute.ts b/catalog-ui/src/app/models/attributes-outputs/simple-flat-attribute.ts
new file mode 100644
index 0000000..bd8b0cd
--- /dev/null
+++ b/catalog-ui/src/app/models/attributes-outputs/simple-flat-attribute.ts
@@ -0,0 +1,35 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2021 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=========================================================
+ */
+
+export class SimpleFlatAttribute {
+    uniqueId: string;
+    path: string;
+    name: string;
+    parentName: string;
+    instanceName: string;
+
+    constructor(uniqueId?: string, path?: string, name?: string, parentName?: string, instanceName?: string) {
+        this.uniqueId = uniqueId;
+        this.path = path;
+        this.name = name;
+        this.parentName = parentName;
+        this.instanceName = instanceName;
+    }
+}
diff --git a/catalog-ui/src/app/models/attributes.ts b/catalog-ui/src/app/models/attributes.ts
index a51358c..ae5eac0 100644
--- a/catalog-ui/src/app/models/attributes.ts
+++ b/catalog-ui/src/app/models/attributes.ts
@@ -20,120 +20,130 @@
 
 'use strict';
 import * as _ from "lodash";
-import {SchemaAttributeGroupModel, SchemaAttribute} from "./schema-attribute";
-import {SchemaPropertyGroupModel, SchemaProperty} from "./aschema-property";
+import {SchemaAttribute, SchemaAttributeGroupModel} from "./schema-attribute";
+import {AttributeOutputDetail} from "app/models/attributes-outputs/attribute-output-detail";
+import {AttributeBEModel} from "app/models/attributes-outputs/attribute-be-model";
 
 export class AttributesGroup {
-    constructor(attributesObj?:AttributesGroup) {
-        _.forEach(attributesObj, (attributes:Array<AttributeModel>, instance) => {
-            this[instance] = [];
-            _.forEach(attributes, (attribute:AttributeModel):void => {
-                attribute.resourceInstanceUniqueId = instance;
-                attribute.readonly = true;
-                this[instance].push(new AttributeModel(attribute));
-            });
-        });
-    }
+  constructor(attributesObj?: AttributesGroup) {
+    _.forEach(attributesObj, (attributes: Array<AttributeModel>, instance) => {
+      this[instance] = [];
+      _.forEach(attributes, (attribute: AttributeModel): void => {
+        attribute.resourceInstanceUniqueId = instance;
+        attribute.readonly = true;
+        this[instance].push(new AttributeModel(attribute));
+      });
+    });
+  }
 }
 
 export interface IAttributeModel {
 
-    //server data
-    uniqueId:string;
-    name:string;
-    _default:string;
-    description:string;
-    type:string;
-    schema:SchemaAttributeGroupModel;
-    status:string;
-    value:string;
-    parentUniqueId:string;
-    //custom data
-    resourceInstanceUniqueId:string;
-    readonly:boolean;
-    valueUniqueUid:string;
+  //server data
+  uniqueId: string;
+  name: string;
+  _default: string;
+  description: string;
+  type: string;
+  schema: SchemaAttributeGroupModel;
+  status: string;
+  value: string;
+  parentUniqueId: string;
+  //custom data
+  resourceInstanceUniqueId: string;
+  readonly: boolean;
+  valueUniqueUid: string;
 }
 
-export class AttributeModel implements IAttributeModel {
+export class AttributeModel extends AttributeBEModel implements IAttributeModel {
 
-    //server data
-    uniqueId:string;
-    name:string;
-    _default:string;
-    description:string;
-    type:string;
-    schema:SchemaAttributeGroupModel;
-    status:string;
-    value:string;
-    parentUniqueId:string;
-    //custom data
-    resourceInstanceUniqueId:string;
-    readonly:boolean;
-    valueUniqueUid:string;
+  //server data
+  uniqueId: string;
+  name: string;
+  _default: string;
+  description: string;
+  type: string;
+  schema: SchemaAttributeGroupModel;
+  status: string;
+  value: string;
+  parentUniqueId: string;
+  //custom data
+  resourceInstanceUniqueId: string;
+  readonly: boolean;
+  valueUniqueUid: string;
 
-    constructor(attribute?:AttributeModel) {
-        if (attribute) {
-            this.uniqueId = attribute.uniqueId;
-            this.name = attribute.name;
-            this._default = attribute._default;
-            this.description = attribute.description;
-            this.type = attribute.type;
-            this.status = attribute.status;
-            this.schema = attribute.schema;
-            this.value = attribute.value;
-            this.parentUniqueId = attribute.parentUniqueId;
-            this.resourceInstanceUniqueId = attribute.resourceInstanceUniqueId;
-            this.readonly = attribute.readonly;
-            this.valueUniqueUid = attribute.valueUniqueUid;
-        } else {
-            this._default = '';
-        }
+  getOutputValues: AttributeOutputDetail[];
+  subAttributeOutputPath: string;
+  outputPath: string;
 
-        if (!this.schema || !this.schema.property) {
-            this.schema = new SchemaPropertyGroupModel(new SchemaProperty());
-        } else {
-            //forcing creating new object, so editing different one than the object in the table
-            this.schema = new SchemaAttributeGroupModel(new SchemaAttribute(this.schema.property));
-        }
+  constructor(attribute?: AttributeModel) {
+    super(attribute);
+    if (attribute) {
+      this.uniqueId = attribute.uniqueId;
+      this.name = attribute.name;
+      this._default = attribute._default;
+      this.description = attribute.description;
+      this.type = attribute.type;
+      this.status = attribute.status;
+      this.schema = attribute.schema;
+      this.value = attribute.value;
+      this.parentUniqueId = attribute.parentUniqueId;
+      this.resourceInstanceUniqueId = attribute.resourceInstanceUniqueId;
+      this.readonly = attribute.readonly;
+      this.valueUniqueUid = attribute.valueUniqueUid;
 
-        this.convertValueToView();
+      this.getOutputValues = attribute.getOutputValues;
+      this.subAttributeOutputPath = attribute.subAttributeOutputPath;
+      this.outputPath = attribute.outputPath;
+    } else {
+      this._default = '';
     }
 
-    public convertToServerObject():string {
-        if (this._default && this.type === 'map') {
-            this._default = '{' + this._default + '}';
-        }
-        if (this._default && this.type === 'list') {
-            this._default = '[' + this._default + ']';
-        }
-        this._default = this._default != "" && this._default != "[]" && this._default != "{}" ? this._default : null;
-
-        return JSON.stringify(this);
-    };
-
-
-    public convertValueToView() {
-        //unwrapping value {} or [] if type is complex
-        if (this._default && (this.type === 'map' || this.type === 'list') &&
-            ['[', '{'].indexOf(this._default.charAt(0)) > -1 &&
-            [']', '}'].indexOf(this._default.slice(-1)) > -1) {
-            this._default = this._default.slice(1, -1);
-        }
-
-        //also for value - for the modal in canvas
-        if (this.value && (this.type === 'map' || this.type === 'list') &&
-            ['[', '{'].indexOf(this.value.charAt(0)) > -1 &&
-            [']', '}'].indexOf(this.value.slice(-1)) > -1) {
-            this.value = this.value.slice(1, -1);
-        }
+    if (!this.schema || !this.schema.property) {
+      this.schema = new SchemaAttributeGroupModel(new SchemaAttribute());
+    } else {
+      //forcing creating new object, so editing different one than the object in the table
+      this.schema = new SchemaAttributeGroupModel(new SchemaAttribute(this.schema.property));
     }
 
-    public toJSON = ():any => {
-        if (!this.resourceInstanceUniqueId) {
-            this.value = undefined;
-        }
-        this.readonly = undefined;
-        this.resourceInstanceUniqueId = undefined;
-        return this;
-    };
+    this.convertValueToView();
+  }
+
+  public convertToServerObject(): string {
+    if (this._default && this.type === 'map') {
+      this._default = '{' + this._default + '}';
+    }
+    if (this._default && this.type === 'list') {
+      this._default = '[' + this._default + ']';
+    }
+    this._default = this._default != "" && this._default != "[]" && this._default != "{}" ? this._default : null;
+
+    return JSON.stringify(this);
+  }
+
+
+  public convertValueToView() {
+    //unwrapping value {} or [] if type is complex
+    if (this._default && (this.type === 'map' || this.type === 'list') &&
+        ['[', '{'].indexOf(this._default.charAt(0)) > -1 &&
+        [']', '}'].indexOf(this._default.slice(-1)) > -1) {
+      this._default = this._default.slice(1, -1);
+    }
+
+    //also for value - for the modal in canvas
+    if (this.value && (this.type === 'map' || this.type === 'list') &&
+        ['[', '{'].indexOf(this.value.charAt(0)) > -1 &&
+        [']', '}'].indexOf(this.value.slice(-1)) > -1) {
+      this.value = this.value.slice(1, -1);
+    }
+  }
+
+  public toJSON = (): any => {
+    if (!this.resourceInstanceUniqueId) {
+      this.value = undefined;
+    }
+    this.readonly = undefined;
+    this.resourceInstanceUniqueId = undefined;
+    return this;
+  };
 }
diff --git a/catalog-ui/src/app/models/data-type-properties.ts b/catalog-ui/src/app/models/data-type-properties.ts
index c278ad3..7717f8a 100644
--- a/catalog-ui/src/app/models/data-type-properties.ts
+++ b/catalog-ui/src/app/models/data-type-properties.ts
@@ -22,7 +22,7 @@
  * Created by rcohen on 9/25/2016.
  */
 'use strict';
-import {SchemaPropertyGroupModel} from "./aschema-property";
+import {SchemaPropertyGroupModel} from "./schema-property";
 import {PropertyModel} from "./properties";
 
 export class DataTypePropertyModel extends PropertyModel{
diff --git a/catalog-ui/src/app/models/data-types.ts b/catalog-ui/src/app/models/data-types.ts
index dc36d78..d72211c 100644
--- a/catalog-ui/src/app/models/data-types.ts
+++ b/catalog-ui/src/app/models/data-types.ts
@@ -23,6 +23,7 @@
  */
 'use strict';
 import {PropertyBEModel} from "./properties-inputs/property-be-model";
+import {AttributeBEModel} from "./attributes-outputs/attribute-be-model";
 
 export class DataTypeModel {
 
@@ -34,6 +35,7 @@
     creationTime:string;
     modificationTime:string;
     properties: Array<PropertyBEModel>;
+    attributes: Array<AttributeBEModel>;
 
     constructor(dataType:DataTypeModel) {
         if (dataType) {
@@ -43,6 +45,7 @@
             this.creationTime = dataType.creationTime;
             this.modificationTime = dataType.modificationTime;
             this.properties = dataType.properties;
+            this.attributes = dataType.attributes;
         }
     }
 
diff --git a/catalog-ui/src/app/models/input-property-base.ts b/catalog-ui/src/app/models/input-property-base.ts
index 33803b1..7524933 100644
--- a/catalog-ui/src/app/models/input-property-base.ts
+++ b/catalog-ui/src/app/models/input-property-base.ts
@@ -22,7 +22,7 @@
  * Created by obarda on 1/22/2017.
  */
 'use strict';
-import {SchemaPropertyGroupModel} from "./aschema-property";
+import {SchemaPropertyGroupModel} from "./schema-property";
 
 export interface InputPropertyBase {
 
diff --git a/catalog-ui/src/app/models/inputs.ts b/catalog-ui/src/app/models/inputs.ts
index 562db98..e267d5f 100644
--- a/catalog-ui/src/app/models/inputs.ts
+++ b/catalog-ui/src/app/models/inputs.ts
@@ -24,7 +24,7 @@
 'use strict';
 import {PropertyModel} from "./properties";
 import {InputPropertyBase} from "./input-property-base";
-import {SchemaPropertyGroupModel} from "./aschema-property";
+import {SchemaPropertyGroupModel} from "./schema-property";
 
 export class InputsGroup {
     constructor(inputsObj?: InputsGroup) {
diff --git a/catalog-ui/src/app/models/properties-inputs/derived-fe-property.ts b/catalog-ui/src/app/models/properties-inputs/derived-fe-property.ts
index 82f15a8..ac05f19 100644
--- a/catalog-ui/src/app/models/properties-inputs/derived-fe-property.ts
+++ b/catalog-ui/src/app/models/properties-inputs/derived-fe-property.ts
@@ -19,7 +19,7 @@
  */
 
 import * as _ from "lodash";
-import { SchemaPropertyGroupModel, SchemaProperty } from '../aschema-property';
+import { SchemaPropertyGroupModel, SchemaProperty } from '../schema-property';
 import { DerivedPropertyType, PropertyBEModel, PropertyFEModel } from '../../models';
 import { PROPERTY_TYPES } from 'app/utils';
 import { UUID } from "angular2-uuid";
diff --git a/catalog-ui/src/app/models/properties-inputs/input-fe-model.ts b/catalog-ui/src/app/models/properties-inputs/input-fe-model.ts
index 909f712..347b8a1 100644
--- a/catalog-ui/src/app/models/properties-inputs/input-fe-model.ts
+++ b/catalog-ui/src/app/models/properties-inputs/input-fe-model.ts
@@ -19,7 +19,7 @@
  */
 
 import * as _ from "lodash";
-import { SchemaPropertyGroupModel, SchemaProperty } from "../aschema-property";
+import { SchemaPropertyGroupModel, SchemaProperty } from "../schema-property";
 import {PropertyFEModel} from "../../models";
 import {PROPERTY_DATA} from "../../utils/constants";
 import {InputBEModel} from "./input-be-model";
diff --git a/catalog-ui/src/app/models/properties-inputs/property-be-model.ts b/catalog-ui/src/app/models/properties-inputs/property-be-model.ts
index b997ea4..aea5707 100644
--- a/catalog-ui/src/app/models/properties-inputs/property-be-model.ts
+++ b/catalog-ui/src/app/models/properties-inputs/property-be-model.ts
@@ -19,7 +19,7 @@
  */
 
 import { PROPERTY_DATA, PROPERTY_TYPES } from 'app/utils/constants';
-import { SchemaProperty, SchemaPropertyGroupModel } from '../aschema-property';
+import { SchemaProperty, SchemaPropertyGroupModel } from '../schema-property';
 import { ToscaPresentationData } from '../tosca-presentation';
 import { PropertyInputDetail } from './property-input-detail';
 import { Metadata } from '../metadata';
diff --git a/catalog-ui/src/app/models/properties-inputs/property-fe-model.ts b/catalog-ui/src/app/models/properties-inputs/property-fe-model.ts
index 06c735d..3b8c2d1 100644
--- a/catalog-ui/src/app/models/properties-inputs/property-fe-model.ts
+++ b/catalog-ui/src/app/models/properties-inputs/property-fe-model.ts
@@ -21,7 +21,7 @@
  */
 
 import * as _ from "lodash";
-import {SchemaPropertyGroupModel, SchemaProperty} from '../aschema-property';
+import {SchemaPropertyGroupModel, SchemaProperty} from '../schema-property';
 import { PROPERTY_DATA, PROPERTY_TYPES } from 'app/utils';
 import { FilterPropertiesAssignmentData, PropertyBEModel, DerivedPropertyType, DerivedFEPropertyMap, DerivedFEProperty } from 'app/models';
 
diff --git a/catalog-ui/src/app/models/properties.ts b/catalog-ui/src/app/models/properties.ts
index b87edff..e292a6c 100644
--- a/catalog-ui/src/app/models/properties.ts
+++ b/catalog-ui/src/app/models/properties.ts
@@ -20,7 +20,7 @@
 
 'use strict';
 import * as _ from "lodash";
-import {SchemaPropertyGroupModel, SchemaProperty} from "./aschema-property";
+import {SchemaPropertyGroupModel, SchemaProperty} from "./schema-property";
 import {InputPropertyBase} from "./input-property-base";
 import {PropertyBEModel} from "./properties-inputs/property-be-model";
 
diff --git a/catalog-ui/src/app/models/schema-attribute.ts b/catalog-ui/src/app/models/schema-attribute.ts
index 35211d4..e222007 100644
--- a/catalog-ui/src/app/models/schema-attribute.ts
+++ b/catalog-ui/src/app/models/schema-attribute.ts
@@ -20,14 +20,14 @@
 
 'use strict';
 
-import { SchemaProperty } from './aschema-property';
+import {SchemaProperty} from './schema-property';
 
 export class SchemaAttributeGroupModel {
-    property: SchemaAttribute;
+  property: SchemaAttribute;
 
-    constructor(schemaAttribute?: SchemaAttribute) {
-        this.property = schemaAttribute;
-    }
+  constructor(schemaAttribute?: SchemaAttribute) {
+    this.property = schemaAttribute;
+  }
 }
 
 export class SchemaAttribute extends SchemaProperty {
diff --git a/catalog-ui/src/app/models/aschema-property.ts b/catalog-ui/src/app/models/schema-property.ts
similarity index 100%
rename from catalog-ui/src/app/models/aschema-property.ts
rename to catalog-ui/src/app/models/schema-property.ts