diff options
Diffstat (limited to 'catalog-ui/src/app/ng2/components/properties-table/dynamic-property')
3 files changed, 144 insertions, 139 deletions
diff --git a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.html b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.html index 17e4002ae5..d6ee568c0c 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.html +++ b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.html @@ -1,66 +1,65 @@ <div class="dynamic-property-row" - [ngClass]="{'selected': selectedPropertyId === property.uniqueId }" + [ngClass]="{'selected': selectedPropertyId && selectedPropertyId === property.propertiesName }" [class.with-top-border]="property.isChildOfListOrMap" (click)="onClickPropertyRow(property, $event)"> - <!-- LEFT CELL - for all NON-PropFEModel properties except for MAP)--> + <!-- LEFT CELL --> <ng-container *ngIf="!isPropertyFEModel"> - <div class="table-cell" *ngIf="canBeDeclared"> <!-- simple children of complex type --> - <checkbox [label]="property.name" [(checked)]="property.isSelected" [disabled]="property.isDisabled ||property.isDeclared" (checkedChange)="checkProperty.emit(property.propertiesName)" + <div class="table-cell" *ngIf="canBeDeclared" [ngClass]="{'filtered':property.name === propertyNameSearchText}"> <!-- simple children of complex type --> + <checkbox [label]="property.name" [(checked)]="property.isSelected" [disabled]="property.isDisabled ||property.isDeclared || readonly" (checkedChange)="checkProperty.emit(property.propertiesName)" ></checkbox> </div> <div class="table-cell" *ngIf="!canBeDeclared && !property.isChildOfListOrMap">{{property.name}}</div> <!-- simple children of complex type within map or list --> + <div class="table-cell map-entry" *ngIf="property.isChildOfListOrMap && propType == derivedPropertyTypes.MAP"><!-- map left cell --> + <input [value]="property.mapKey" #mapKey (change)="mapKeyChanged.emit(mapKey.value)" [readonly]="readonly" type="text" [ngClass]="{'disabled':readonly}" /> + </div> </ng-container> - <!-- RIGHT CELL --> - <ng-container *ngIf="propType == derivedPropertyTypes.SIMPLE || property.isDeclared"> - <div class="table-cell" [class.full-width]="isPropertyFEModel || property.isChildOfListOrMap"> + <!-- RIGHT CELL OR FULL WIDTH CELL--> + <ng-container *ngIf="propType == derivedPropertyTypes.SIMPLE || property.isDeclared || (property.isChildOfListOrMap && propType == derivedPropertyTypes.MAP && property.schema.property.isSimpleType)"> + <div class="table-cell"> <dynamic-element class="value-input" pattern="validationUtils.getValidationPattern(property.type)" - [(value)]="property.value" - [type]="property.type" + [(value)]="property.valueObj" + [type]="property.isDeclared ? 'string' : property.type" [name]="property.name" - (valueChange)="propValueChanged(property);" + (valueChange)="valueChanged.emit();" + [readonly]="readonly||property.isDeclared" > <!--[disabled]="property.isDisabled || property.isDeclared" --> </dynamic-element> </div> </ng-container> - <ng-container *ngIf="!property.isDeclared"> <!-- other cases need to fail if isDeclared, in which case we need to use full width value above instead) --> - - <ng-container *ngIf="propType == derivedPropertyTypes.COMPLEX && !isPropertyFEModel"> - <div class="table-cell complex" [class.full-width]="property.isChildOfListOrMap"> - <span>{{property.type | contentAfterLastDot }}</span> - </div> - </ng-container> - <ng-container *ngIf="property.isChildOfListOrMap && propType == derivedPropertyTypes.MAP"> - <div class="table-cell map-entry"><input type="text" /></div> - <div class="table-cell" *ngIf="property.schema.property.isSimpleType"> - <input type="text" [(ngModel)]="property.value" /></div> - <div class="table-cell" *ngIf="!property.schema.property.isSimpleType"> - <span>{{property.schema.property.type | contentAfterLastDot }}</span> - </div> - </ng-container> - - <!-- ICONS: add, delete, and expand --> - <div *ngIf="(propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && !property.isChildOfListOrMap" class="table-cell"><span class="sprite-new add-item-icon" (click)="addRows()"></span></div> - <span *ngIf="property.isChildOfListOrMap" class="delete-span sprite-new delete-item-icon" (click)="deleteItem.emit(property.propertiesName)"></span> - <span *ngIf="propType == derivedPropertyTypes.COMPLEX || (property.isChildOfListOrMap && propChildren)" (click)="expandChildById(propPath)" class="expand-icon" [class.expanded]="propPath == expandedChildId">V</span> + <ng-container *ngIf="!isPropertyFEModel && propType != derivedPropertyTypes.SIMPLE && !property.isDeclared"> <!-- right cell for complex elements, or list complex --> + <div class="table-cell" *ngIf="propType == derivedPropertyTypes.COMPLEX">{{property.type | contentAfterLastDot }}</div> + <div class="table-cell" *ngIf="propType == derivedPropertyTypes.MAP && !property.schema.property.isSimpleType">{{property.schema.property.type | contentAfterLastDot }}</div> + </ng-container> + <ng-container *ngIf="isPropertyFEModel && (propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP)"><!-- empty, full-width table cell - for PropertyFEModel of type list or map --> + <div class="table-cell empty"></div> + </ng-container> + <!-- ICONS: add, delete, and expand --> + <ng-container *ngIf="!property.isDeclared"> + <span *ngIf="(propType == derivedPropertyTypes.LIST || propType == derivedPropertyTypes.MAP) && !property.isChildOfListOrMap" class="property-icon sprite-new add-item-icon" (click)="createNewChildProperty();" [ngClass]="{'disabled':readonly}"></span> + <span *ngIf="property.isChildOfListOrMap" (click)="deleteItem.emit(property);" class="property-icon sprite-new delete-item-icon" [ngClass]="{'disabled':readonly}"></span> + <span *ngIf="!isPropertyFEModel && (propType == derivedPropertyTypes.COMPLEX || hasChildren())" (click)="expandChildById(propPath)" class="property-icon expand-icon" [class.expanded]="propPath == expandedChildId">V</span> </ng-container> </div> -<!-- Now, recurse into children --> -<ng-container *ngIf="propChildren && !property.isDeclared"> - <ng-container *ngFor="let prop of propChildren | filterChildProperties: expandedChildId; trackBy:prop?.propertiesName"> +<!-- FLAT CHILDREN --> +<div class="flat-children-container" *ngIf="isPropertyFEModel && !property.isDeclared"> + <ng-container *ngFor="let prop of property.flattenedChildren | filterChildProperties: expandedChildId; trackBy:prop?.propertiesName"> <dynamic-property [selectedPropertyId]="selectedPropertyId" - [canBeDeclared]="childrenCanBeDeclared" + [canBeDeclared]="prop.canBeDeclared" [property]="prop" [expandedChildId]="expandedChildId" - [propChildren]="" - (valueChanged)="propValueChanged(prop);" + [propertyNameSearchText]="propertyNameSearchText" + [readonly]="readonly" + (valueChanged)="childValueChanged(prop)" + (mapKeyChanged)="removeValueFromParent(prop, $event)" (expandChild)="expandChildById($event)" (deleteItem)="deleteListOrMapItem($event)" (clickOnPropertyRow)="onClickPropertyRow($event)" (checkProperty)="checkedChange($event)" + (addChildPropsToParent)="addChildProps($event, prop.propertiesName)" > </dynamic-property> </ng-container> -</ng-container> +</div> diff --git a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.less b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.less index 53cde3035a..cb7cd39640 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.less +++ b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.less @@ -1,40 +1,40 @@ +.flat-children-container { + dynamic-property:first-child .dynamic-property-row:not(.with-top-border) { + border-top:none; + } + .dynamic-property-row { + border-top: solid 1px #CCC; + } +} .dynamic-property-row { display:flex; flex-direction:row; - position:relative; - + align-items: center; + .table-cell { - flex: 1 0 50%; + flex: 1; padding:5px; - position:relative; text-overflow: ellipsis; white-space: nowrap; - + overflow:hidden; + min-height:32px; - &.full-width { - border-right:none; - flex: 0 0 100%; - } - - &:first-child:not(:only-child) { + &:first-child { + flex: 0 0 50%; border-right:#d2d2d2 solid 1px; - overflow:hidden; + + + &:only-of-type { + flex: 1 1 100%; + border-right:none; + } } - - } - span.delete-item-icon{ - position: absolute; - right: 25px; - top: 10px; } - span.add-item-icon { - float:right; + .property-icon { + flex: 0 0 auto; } span.expand-icon { - position: absolute; - top:6px; - right: 10px; transition: 200ms transform ease-in-out; } span.expand-icon.expanded { diff --git a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.ts b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.ts index 0ca93a773f..1c7fbfac7a 100644 --- a/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.ts +++ b/catalog-ui/src/app/ng2/components/properties-table/dynamic-property/dynamic-property.component.ts @@ -3,7 +3,6 @@ import { PropertyBEModel, PropertyFEModel, DerivedFEProperty, DerivedPropertyTyp import { PROPERTY_DATA, PROPERTY_TYPES } from 'app/utils'; import { PropertiesUtils } from "app/ng2/pages/properties-assignment/properties.utils"; import { DataTypeService } from "../../../services/data-type.service"; -import { UUID } from "angular2-uuid"; @Component({ @@ -17,64 +16,33 @@ export class DynamicPropertyComponent { propType: DerivedPropertyType; propPath: string; isPropertyFEModel: boolean; - mapOfIDsAndKeys: Map<string, string> = new Map(); //used for map and list + childrenCount: number; - childrenCanBeDeclared: boolean; @Input() canBeDeclared: boolean; @Input() property: PropertyFEModel | DerivedFEProperty; - @Input() propChildren: Array<DerivedFEProperty>; @Input() expandedChildId: string; @Input() selectedPropertyId: string; + @Input() propertyNameSearchText: string; + @Input() readonly: boolean; @Output() valueChanged: EventEmitter<any> = new EventEmitter<any>(); @Output() expandChild: EventEmitter<string> = new EventEmitter<string>(); @Output() checkProperty: EventEmitter<string> = new EventEmitter<string>(); @Output() deleteItem: EventEmitter<string> = new EventEmitter<string>(); @Output() clickOnPropertyRow: EventEmitter<PropertyFEModel | DerivedFEProperty> = new EventEmitter<PropertyFEModel | DerivedFEProperty>(); + @Output() mapKeyChanged: EventEmitter<string> = new EventEmitter<string>(); + @Output() addChildPropsToParent: EventEmitter<Array<DerivedFEProperty>> = new EventEmitter<Array<DerivedFEProperty>>(); + constructor(private propertiesUtils: PropertiesUtils, private dataTypeService: DataTypeService) { } ngOnInit() { this.isPropertyFEModel = this.property instanceof PropertyFEModel; - if (this.property instanceof PropertyFEModel) { - this.propType = this.getDerivedPropertyType(this.property.type); - this.propPath = this.property.name; - } else { - this.propType = this.property.derivedDataType; - this.propPath = this.property.propertiesName; - } - - this.childrenCanBeDeclared = this.canBeDeclared && this.propType != this.derivedPropertyTypes.MAP && this.propType != this.derivedPropertyTypes.LIST; - - if (this.propType == this.derivedPropertyTypes.LIST || this.propType == this.derivedPropertyTypes.MAP) { - this.initializeValues(); - } - + this.propType = this.property.derivedDataType; + this.propPath = (this.property instanceof PropertyFEModel) ? this.property.name : this.property.propertiesName; } - initializeValues = () => { - let tempValue: any; - if (this.property.value) { - tempValue = JSON.parse(this.property.value); - if (!_.isEmpty(tempValue)) { - tempValue.forEach((element, key) => { - let newChildID: string = this.createNewChildProperty(JSON.stringify(element)); - this.mapOfIDsAndKeys[newChildID] = key; - console.log(this.mapOfIDsAndKeys); - }); - } - } - //this.pseudoChildren = []; - //this.valueObjRef = []; - //TODO: generate necessary elements for existing values here - // if (this.propType == this.derivedPropertyTypes.LIST) { - // this.valueObjRef = (this.property.value) ? JSON.parse(this.property.value) : []; - // } else if (this.propType == this.derivedPropertyTypes.MAP) { - // this.valueObjRef = (this.property.value)? JSON.parse(this.property.value) : {}; - // } - console.log(this.property.value); - } onClickPropertyRow = (property, event) => { // Because DynamicPropertyComponent is recrusive second time the event is fire event.stopPropagation = undefined @@ -82,68 +50,106 @@ export class DynamicPropertyComponent { this.clickOnPropertyRow.emit(property); } - deleteListOrMapItem = (itemName: string) => { - this.propChildren = this.propChildren.filter(prop => prop.propertiesName.indexOf(itemName) != 0); //remove item and children; - } - - propValueChanged = (property) => { - console.log("property value change!! Prop type: " + property.type + " New value: " + property.value); - this.valueChanged.emit(property); - }; expandChildById = (id: string) => { this.expandedChildId = id; - this.expandChild.emit(id); + this.expandChild.emit(id); } checkedChange = (propName: string) => { this.checkProperty.emit(propName); } + hasChildren = (): number => { + return (this.property.valueObj && typeof this.property.valueObj == 'object') ? Object.keys(this.property.valueObj).length : 0; + } + createNewChildProperty = (): void => { + + let newProps: Array<DerivedFEProperty> = this.propertiesUtils.createListOrMapChildren(this.property, "", null); + if (this.property instanceof PropertyFEModel) { + this.addChildProps(newProps, this.property.name); + } else { + this.addChildPropsToParent.emit(newProps); + } + } - addRows = (): void => { //from within the template, when creating empty item - let childPropId = this.createNewChildProperty(); - this.expandChildById(this.propPath + "#" + childPropId); + addChildProps = (newProps: Array<DerivedFEProperty>, childPropName: string) => { + + if (this.property instanceof PropertyFEModel) { + let insertIndex: number = this.property.getIndexOfChild(childPropName) + this.property.getCountOfChildren(childPropName); //insert after parent prop and existing children + this.property.flattenedChildren.splice(insertIndex, 0, ...newProps); //using ES6 spread operator + this.expandChildById(newProps[0].propertiesName); + } } - createNewChildProperty = (value?:string):string => { - let propUUID:string = UUID.UUID(); - let newProp: DerivedFEProperty; - if (this.propType == this.derivedPropertyTypes.LIST) { //for list - create new prop of schema type - newProp = new DerivedFEProperty(propUUID, this.propPath, this.property.schema.property.type, value, true); - } else { //for map - create new prop of type map, with schema, but with flag that its a child - newProp = new DerivedFEProperty(propUUID, this.propPath, this.property.type, value, true, this.property.schema); + childValueChanged = (property: DerivedFEProperty) => { //value of child property changed + + if (this.property instanceof PropertyFEModel) { // will always be the case + let parentNames = this.getParentNamesArray(property.propertiesName, []); + if (parentNames.length) { + _.set(this.property.valueObj, parentNames.join('.'), property.valueObj); + } + console.log(parentNames); + this.valueChanged.emit(this.property.name); } + } + deleteListOrMapItem = (item: DerivedFEProperty) => { + if (this.property instanceof PropertyFEModel) { + this.removeValueFromParent(item); + this.property.flattenedChildren.splice(this.property.getIndexOfChild(item.propertiesName), this.property.getCountOfChildren(item.propertiesName)); + this.expandChildById(item.propertiesName); + } + } - this.propChildren = this.propChildren || []; - this.propChildren.push(newProp); + removeValueFromParent = (item: DerivedFEProperty, replaceKey?: string) => { + if (this.property instanceof PropertyFEModel) { + let itemParent = (item.parentName == this.property.name) ? this.property : this.property.flattenedChildren.find(prop => prop.propertiesName == item.parentName); + + if (item.derivedDataType == DerivedPropertyType.MAP) { + let oldKey = item.mapKey; + if (typeof replaceKey == 'string') { //allow saving empty string + _.set(itemParent.valueObj, replaceKey, itemParent.valueObj[oldKey]); + item.mapKey = replaceKey; + } + delete itemParent.valueObj[oldKey]; + } else { + let itemIndex: number = this.property.flattenedChildren.filter(prop => prop.parentName == item.parentName).map(prop => prop.propertiesName).indexOf(item.propertiesName); + itemParent.valueObj.splice(itemIndex, 1); + } - //if it's a complex type, add children properties - if (!this.property.schema.property.isSimpleType) { - let schemaDataType: DataTypeModel = this.dataTypeService.getDataTypeByTypeName(this.property.schema.property.type); - this.dataTypeService.getDerivedDataTypeProperties(schemaDataType, this.propChildren, newProp.propertiesName); - this.propertiesUtils.assignValuesRecursively(JSON.parse(value), this.propChildren, newProp.propertiesName); - console.log(JSON.stringify(this.propChildren)); + if (itemParent instanceof PropertyFEModel) { //direct child + this.valueChanged.emit(this.property.name); + } else { //nested child - need to update parent prop by getting flattened name (recurse through parents and replace map/list keys, etc) + this.childValueChanged(itemParent); + } } + } - return propUUID; - } + getParentNamesArray = (parentPropName: string, parentNames?: Array<string>): Array<string> => { + if (this.property instanceof PropertyFEModel) { + if (parentPropName.indexOf("#") == -1) { return parentNames; } //finished recursing parents. return - //TODO: remove this and move to somewhere central!! (or make all properties be the same type...) - getDerivedPropertyType = (type) => { - if (PROPERTY_DATA.SIMPLE_TYPES.indexOf(type) > -1) { - return DerivedPropertyType.SIMPLE; - } else if (type == PROPERTY_TYPES.LIST) { - return DerivedPropertyType.LIST; - } else if (type == PROPERTY_TYPES.MAP) { - return DerivedPropertyType.MAP; - } else { - return DerivedPropertyType.COMPLEX; + let parentProp: DerivedFEProperty = this.property.flattenedChildren.find(prop => prop.propertiesName === parentPropName); + let nameToInsert: string = parentProp.name; + + if (parentProp.isChildOfListOrMap) { + if (parentProp.derivedDataType == DerivedPropertyType.MAP) { + nameToInsert = parentProp.mapKey; + } else { //LIST + let siblingProps = this.property.flattenedChildren.filter(prop => prop.parentName == parentProp.parentName).map(prop => prop.propertiesName); + nameToInsert = siblingProps.indexOf(parentProp.propertiesName).toString(); + } + } + + parentNames.splice(0, 0, nameToInsert); //add prop name to array + return this.getParentNamesArray(parentProp.parentName, parentNames); //continue recursing + } } + } |