import DeletionManager from '../libraries/DeletionManager'
import DescriptorModelIconFactory from '../libraries/model/IconFactory'
import getEventPath from '../libraries/getEventPath'
+import CatalogDataStore from '../stores/CatalogDataStore'
import imgAdd from '../../../node_modules/open-iconic/svg/plus.svg'
import imgRemove from '../../../node_modules/open-iconic/svg/trash.svg'
}
function buildField(container, property, path, value, fieldKey) {
+ let cds = CatalogDataStore;
+ let catalogs = cds.getTransientCatalogs();
const name = path.join('.');
const isEditable = true;
const isGuid = Property.isGuid(property);
const onChange = onFormFieldValueChanged.bind(container);
const isEnumeration = Property.isEnumeration(property);
+ const isLeafRef = Property.isLeafRef(property);
const onFocus = onFocusPropertyFormInputElement.bind(container, property, path, value);
const placeholder = changeCase.title(property.name);
const className = ClassNames(property.name + '-input', {'-is-guid': isGuid});
return <select key={fieldKey.toString()} id={fieldKey.toString()} className={ClassNames({'-value-not-set': !isValueSet})} name={name} value={value} title={name} onChange={onChange} onFocus={onFocus} onBlur={endEditing} onMouseDown={startEditing} onMouseOver={startEditing} readOnly={!isEditable}>{options}</select>;
}
+ if (isLeafRef) {
+ let fullFieldKey = fieldKey;
+ let containerRef = container;
+ while (containerRef.parent) {
+ fullFieldKey = containerRef.parent.key + ':' + fullFieldKey;
+ containerRef = containerRef.parent;
+ }
+ const leafRefPathValues = Property.getLeafRef(property, path, value, fullFieldKey, catalogs, container);
+
+ const options = leafRefPathValues && leafRefPathValues.map((d, i) => {
+ return <option key={fieldKey.toString() + ':' + i} value={d.value}>{d.value}</option>;
+ });
+ const isValueSet = leafRefPathValues.filter(d => d.isSelected).length > 0;
+ if (!isValueSet || property.cardinality === '0..1') {
+ const noValueDisplayText = changeCase.title(property.name);
+ options.unshift(<option key={'(value-not-in-leafref)' + fieldKey.toString()} value="" placeholder={placeholder}>{noValueDisplayText}</option>);
+ }
+ return <select key={fieldKey.toString()} id={fieldKey.toString()} className={ClassNames({'-value-not-set': !isValueSet})} name={name} value={value} title={name} onChange={onChange} onFocus={onFocus} onBlur={endEditing} onMouseDown={startEditing} onMouseOver={startEditing} readOnly={!isEditable}>{options}</select>;
+ }
+
if (property['preserve-line-breaks']) {
return <textarea key={fieldKey.toString()} cols="5" id={fieldKey.toString()} name={name} value={value} placeholder={placeholder} onChange={onChange} onFocus={onFocus} onBlur={endEditing} onMouseDown={startEditing} onMouseOver={startEditing} onMouseOut={endEditing} onMouseLeave={endEditing} readOnly={!isEditable} />;
}
import InstanceCounter from './../InstanceCounter'
import DescriptorModelFields from './DescriptorModelFields'
import DescriptorTemplateFactory from './DescriptorTemplateFactory'
+import utils from '../utils'
export default {
isLeaf(property = {}) {
isLeafList(property = {}) {
return property.type === 'leaf_list';
},
+ isLeafRef(property = {}) {
+ const type = property['data-type'] || {};
+ return type.hasOwnProperty('leafref');
+ },
isArray(property = {}) {
// give '1' or '0..N' or '0..1' or '0..5' determine if represents an array
// '0..1' is not an array
return {name: enumName, value: enumValue, isSelected: String(enumValue) === String(value)};
});
},
+ getLeafRef(property = {}, path, value, fullFieldKey, transientCatalogs, container) {
+ const leafRefPath = property['data-type']['leafref']['path'];
+
+ const transientCatalogHash = {};
+
+ transientCatalogs.map((catalog) => {
+ transientCatalogHash[catalog.type + '-catalog'] = {};
+ transientCatalogHash[catalog.type + '-catalog'][catalog.type] = catalog['descriptors'];
+ });
+
+ let leafRefPathValues = utils.resolveLeafRefPath(transientCatalogHash, leafRefPath, fullFieldKey, path, container);
+
+ let leafRefObjects = [];
+
+ leafRefPathValues && leafRefPathValues.map((leafRefPathValue) => {
+ leafRefObjects.push({
+ name: leafRefPathValue,
+ value: leafRefPathValue,
+ isSelected: String(leafRefPathValue) === String(value)
+ });
+ });
+
+ return leafRefObjects;
+ },
isGuid(property = {}) {
const type = property['data-type'];
if (typeof type === 'object' && type.leafref && type.leafref.path) {
};
},
- toBiggestValue: (maxIndex, curIndex) => Math.max(maxIndex, curIndex)
+ toBiggestValue: (maxIndex, curIndex) => Math.max(maxIndex, curIndex),
+ isRelativePath (path) {
+ if (path.split('/')[0] == '..') {
+ return true;
+ }
+ return false;
+ },
+
+ getResults (topLevelObject, pathArray) {
+ let objectCopy = _.cloneDeep(topLevelObject);
+ let i = pathArray.length;
+ let results = [];
+
+ while(pathArray[pathArray.length - i]) {
+ if (_.isArray(objectCopy[pathArray[pathArray.length - i]])) {
+ if (i == 2) {
+ results = _.map(objectCopy[pathArray[pathArray.length - i]], pathArray[pathArray.length - 1]);
+ } else {
+ objectCopy = objectCopy[pathArray[pathArray.length - i]];
+ }
+ } else if (_.isArray(objectCopy)) {
+ objectCopy.map((object) => {
+ if (_.isArray(object[pathArray[pathArray.length - i]])) {
+ if (i == 2) {
+ results = results.concat(_.map(object[pathArray[pathArray.length - i]], pathArray[pathArray.length - 1]));
+ }
+ }
+ })
+ }
+ i--;
+ }
+
+ return results;
+ },
+
+ getAbsoluteResults (topLevelObject, pathArray) {
+ let i = pathArray.length;
+ let objectCopy = _.cloneDeep(topLevelObject);
+ let results = [];
+
+ let fragment = pathArray[pathArray.length - i]
+
+ while (fragment) {
+ if (i == 1) {
+ // last fragment
+ if (_.isArray(objectCopy)) {
+ // results will be obtained from a map
+ results = _.map(objectCopy, fragment);
+ } else {
+ // object
+ if (fragment.match(/\[.*\]/g)) {
+ // contains a predicate
+ // shouldn't reach here
+ console.log('Something went wrong while resolving a leafref. Reached a leaf with predicate.');
+ } else {
+ // contains no predicate
+ results.push(objectCopy[fragment]);
+ }
+ }
+ } else {
+ if (_.isArray(objectCopy)) {
+ // is array
+ objectCopy = _.map(objectCopy, fragment);
+
+ // If any of the deeper object is an array, flatten the entire list.
+ // This would usually be a bad leafref going out of its scope.
+ // Log it too
+ for (let i = 0; i < objectCopy.length; i++) {
+ if (_.isArray(objectCopy[i])) {
+ objectCopy = _.flatten(objectCopy);
+ console.log('This might be a bad leafref. Verify with backend team.')
+ break;
+ }
+ }
+ } else {
+ // is object
+ if (fragment.match(/\[.*\]/g)) {
+ // contains a predicate
+ let predicateStr = fragment.match(/\[.*\]/g)[0];
+ // Clip leading [ and trailing ]
+ predicateStr = predicateStr.substr(1, predicateStr.length - 2);
+ const predicateKeyValue = predicateStr.split('=');
+ const predicateKey = predicateKeyValue[0];
+ const predicateValue = predicateKeyValue[1];
+ // get key for object to search into
+ let key = fragment.split('[')[0];
+ let searchObject = {};
+ searchObject[predicateKey] = predicateValue;
+ objectCopy = _.find(objectCopy[key], searchObject);
+ if (!objectCopy) {
+ return [];
+ }
+ } else {
+ // contains no predicate
+ objectCopy = objectCopy[fragment];
+ }
+ }
+ }
+ i--;
+ fragment = pathArray[pathArray.length - i];
+ }
+
+ return results;
+ },
+
+ resolveCurrentPredicate (leafRefPath, container, pathCopy) {
+ if (leafRefPath.indexOf('current()') != -1) {
+ // contains current
+
+ // Get the relative path from current
+ let relativePath = leafRefPath.match("current\\(\\)\/(.*)\]");
+ let relativePathArray = relativePath[1].split('/');
+
+ while (relativePathArray[0] == '..') {
+ pathCopy.pop();
+ relativePathArray.shift();
+ }
+
+ // Supports only one relative path up
+ // To support deeper paths, will need to massage the string more
+ // i.e. change '/'' to '.'
+ const searchPath = pathCopy.join('.').concat('.', relativePathArray[0]);
+ const searchValue = this.resolvePath(container.model, searchPath);
+
+ const predicateStr = leafRefPath.match("(current.*)\]")[1];
+ leafRefPath = leafRefPath.replace(predicateStr, searchValue);
+ }
+ return leafRefPath;
+ },
+
+ resolveLeafRefPath (catalogs, leafRefPath, fieldKey, path, container) {
+ let pathCopy = _.clone(path);
+ // Strip any prefixes
+ let leafRefPathCopy = leafRefPath.replace(/[\w\d]*:/g, '');
+ // Strip any spaces
+ leafRefPathCopy = leafRefPathCopy.replace(/\s/g, '');
+
+ // resolve any current paths
+ leafRefPathCopy = this.resolveCurrentPredicate(leafRefPathCopy, container, pathCopy);
+
+ // Split on delimiter (/)
+ const pathArray = leafRefPathCopy.split('/');
+ let fieldKeyArray = fieldKey.split(':');
+ let results = [];
+
+ // Check if relative path or not
+ // TODO: Below works but
+ // better to convert the pathCopy to absolute/rooted path
+ // and use the absolute module instead
+ if (this.isRelativePath(leafRefPathCopy)) {
+ let i = pathArray.length;
+ while (pathArray[pathArray.length - i] == '..') {
+ fieldKeyArray.splice(-1, 1);
+ if (!isNaN(Number(fieldKeyArray[fieldKeyArray.length - 1]))) {
+ // found a number, so an index. strip it
+ fieldKeyArray.splice(-1, 1);
+ }
+ i--;
+ }
+
+ // traversed all .. - now traverse down
+ if (fieldKeyArray.length == 1) {
+ for (let key in catalogs) {
+ for (let subKey in catalogs[key]) {
+ let found = _.find(catalogs[key][subKey], {id: fieldKeyArray[0]});
+ if (found) {
+ results = this.getResults(found, pathArray.splice(-i, i));
+ return results;
+ }
+ }
+ }
+ } else if (fieldKeyArray.length == 2) {
+ for (let key in catalogs) {
+ for (let subKey in catalogs[key]) {
+ let found = _.find(catalogs[key][subKey], {id: fieldKeyArray[0]});
+ if (found) {
+ for (let foundKey in found) {
+ let topLevel = _.find(found[foundKey], {id: fieldKeyArray[1]});
+ if (topLevel) {
+ results = this.getResults(topLevel, pathArray.splice(-i, i));
+ return results;
+ }
+ }
+ }
+ }
+ }
+ } else {
+ // not supported - too many levels deep ... maybe some day
+ console.log('The relative path is from a node too many levels deep from root. This is not supported at the time');
+ }
+ } else {
+ // absolute path
+ if (pathArray[0] == "") {
+ pathArray.splice(0, 1);
+ }
+
+ let catalogKey = pathArray[0];
+ let topLevelObject = {};
+
+ topLevelObject[catalogKey] = catalogs[catalogKey];
+
+ results = this.getAbsoluteResults(topLevelObject, pathArray);
+
+ return results;
+ }
+ }
}
this.registerAsync(CatalogDataSource);
this.bindActions(CatalogDataSourceActions);
this.bindActions(CatalogItemsActions);
+ this.exportPublicMethods({
+ getCatalogs: this.getCatalogs,
+ getCatalogItemById: this.getCatalogItemById,
+ getCatalogItemByUid: this.getCatalogItemByUid,
+ getTransientCatalogs: this.getTransientCatalogs,
+ getTransientCatalogItemById: this.getTransientCatalogItemById,
+ getTransientCatalogItemByUid: this.getTransientCatalogItemByUid
+ });
}
resetSelectionState = () => {
return this.catalogs || (this.catalogs = []);
}
+ getTransientCatalogs() {
+ return this.state.catalogs || (this.state.catalogs = []);
+ }
+
getAllSelectedCatalogItems() {
return this.getCatalogs().reduce((r, d) => {
d.descriptors.forEach(d => {
}, [])[0];
}
+ getTransientCatalogItemById(id) {
+ return this.getTransientCatalogs().reduce((r, catalog) => {
+ return r.concat(catalog.descriptors.filter(d => d.id === id));
+ }, [])[0];
+ }
+
getCatalogItemByUid(uid) {
return this.getCatalogs().reduce((r, catalog) => {
return r.concat(catalog.descriptors.filter(d => UID.from(d) === uid));
}, [])[0];
}
+ getTransientCatalogItemByUid(uid) {
+ return this.getTransientCatalogs().reduce((r, catalog) => {
+ return r.concat(catalog.descriptors.filter(d => UID.from(d) === uid));
+ }, [])[0];
+ }
+
removeCatalogItem(deleteItem = {}) {
this.getCatalogs().map(catalog => {
catalog.descriptors = catalog.descriptors.filter(d => d.id !== deleteItem.id);