+ this.updateItem(itemDescriptor.model);
+ }
+
+ setItemError(descriptor, path, message) {
+ // save locally and globally
+ descriptor.setUiState('error', path, message);
+ if (descriptor.parent) {
+ let parentPath = [];
+ while (descriptor.parent) {
+ parentPath.push(descriptor.type);
+ const index = descriptor.parent.model[descriptor.type].findIndex(item => item.id === descriptor.id);
+ parentPath.push(index);
+ descriptor = descriptor.parent;
+ }
+ parentPath.length && descriptor.setUiState('error', parentPath.concat(path), message);
+ } else if (path.length > 1 && descriptor[path[0]]) {
+ // if we are indirectly editing a sub model set the error state in the sub model
+ descriptor[path[0]][path[1]].setUiState('error', path.slice(2), message);
+ }
+ }
+
+ modelSaveError(input) {
+ const { descriptor, type, id } = input;
+ const errorMessage = {
+ 'data-missing': "Required value.",
+ 'missing-element': "Incomplete configuration."
+ }
+ if (descriptor.id === id) {
+ let error = input.error;
+ let rpcError = null;
+ if (typeof error === 'string') {
+ try {
+ error = JSON.parse(error);
+ } catch (e) {
+ error = {};
+ }
+ }
+ rpcError = error['rcp-error']
+ || (error['rcp-reply'] && error['rcp-reply']['rcp-error'])
+ || (error.body && error.body['rpc-reply'] && error.body['rpc-reply']['rpc-error']);
+ if (rpcError) {
+ const errorTag = rpcError['error-tag'];
+ const message = errorMessage[errorTag] || errorTag;
+ let errPath = rpcError['error-path'].trim();
+ errPath = errPath.replace(/[-\w]*:/g, '');
+ errPath = errPath.slice(errPath.indexOf('/' + type + '[') + 1);
+ const path = [];
+ let splitIndex = errPath.indexOf('/');
+ function ripOutNodeExpression(str, complexNode) {
+ const expressionEnd = str.indexOf(']');
+ complexNode.push(str.slice(1, expressionEnd));
+ if (str.charAt(expressionEnd + 1) === '[') {
+ str = str.slice(expressionEnd + 1);
+ return ripOutNodeExpression(str, complexNode)
+ }
+ return str.slice(expressionEnd + 2);
+ }
+ while (splitIndex > -1) {
+ const expressionStart = errPath.indexOf('[');
+ if (expressionStart > 0 && expressionStart < splitIndex) {
+ const complexNode = [];
+ complexNode.push(errPath.slice(0, expressionStart));
+ errPath = errPath.slice(expressionStart);
+ errPath = ripOutNodeExpression(errPath, complexNode);
+ path.push(complexNode);
+ } else {
+ path.push(errPath.slice(0, splitIndex))
+ errPath = errPath.slice(splitIndex + 1);
+ }
+ splitIndex = errPath.indexOf('/');
+ }
+ const expressionStart = errPath.indexOf('[');
+ if (expressionStart > 0) {
+ const complexNode = [];
+ complexNode.push(errPath.slice(0, expressionStart));
+ errPath = errPath.slice(expressionStart);
+ errPath = ripOutNodeExpression(errPath, complexNode);
+ } else {
+ path.push(errPath.slice(0))
+ }
+ let model = descriptor.model;
+ path.shift();
+ let fullPath = path.reduce((a, p, i) => {
+ let element = p;
+ let subPath = [];
+ if (Array.isArray(p)) {
+ element = p.shift();
+ subPath = p;
+ }
+ a.push(element);
+ model = model[element];
+ const match = subPath.reduce((m, e) => {
+ const id = e.split('=');
+ const key = id[0];
+ let value = id[1];
+ value = value.charAt(0) === "'" ? value.split("'")[1] : value;
+ m.push({ key, value });
+ return m;
+ }, []);
+ if (match.length) {
+ const index = model.findIndex(obj => match.every(e => obj[e.key] == e.value));
+ a.push(index);
+ model = model[index];
+ }
+ return a;
+ }, []);
+ this.setItemError(descriptor, fullPath, message);
+ this.updateItem(descriptor.getRoot().model);
+ }
+ }
+ }
+
+ modelError(input) {
+ const { descriptor, path, message } = input;
+ this.setItemError(descriptor, path, message);
+ this.updateItem(descriptor.getRoot().model)
+ }
+
+ modelSet(input) {
+ const { descriptor, path, value } = input;
+ _set(descriptor.model, path, value);
+ this.setItemError(descriptor, path, null);
+ this.updateItem(descriptor.getRoot().model)
+ CatalogItemsActions.catalogItemDescriptorChanged.defer(descriptor.getRoot());
+ }
+
+ modelSetOpenState(input) {
+ const { descriptor, path, isOpen } = input;
+ descriptor.setUiState('opened', path, isOpen);
+ this.updateItem(descriptor.getRoot().model)
+ }
+
+ modelForceOpenState(input) {
+ const { descriptor, path } = input;
+ let openPath = [];
+ const targetPath = _isArray(path) ? path : [path];
+ targetPath.forEach(p => {
+ openPath.push(p);
+ descriptor.setUiState('opened', openPath, true);
+ });
+ this.updateItem(descriptor.getRoot().model)
+ }
+
+ modelAssign(input) {
+ const { descriptor, path, source } = input;
+ let obj = _get(descriptor.model, path) || {};
+ Object.assign(obj, source);
+ this.updateItem(descriptor.getRoot().model)
+ CatalogItemsActions.catalogItemDescriptorChanged.defer(descriptor.getRoot());
+ }
+
+ modelListNew(input) {
+ const { descriptor, path, property } = input;
+ const create = Property.getContainerCreateMethod(property, descriptor);
+ if (create) {
+ const model = null;
+ create(model, path, property);
+ } else {
+ // get a unique name for the new list item based on the current list content
+ // some lists, based on the key, may not get a uniqueName generated here
+ const uniqueName = DescriptorModelMetaFactory.generateItemUniqueName(descriptor.model[property.name], property);
+ const value = Property.createModelInstance(property, uniqueName);
+ let list = _get(descriptor.model, path) || [];
+ list.push(value);
+ _set(descriptor.model, path, list);
+ }
+ const list = _get(descriptor.model, path);
+ let openPath = path.slice();
+ descriptor.setUiState('opened', openPath, true);
+ openPath.push((list.length - 1).toString());
+ descriptor.setUiState('opened', openPath, true);
+ function traverseProps(properties) {
+ properties.forEach((p) => {
+ if (p.type === 'list' || p.type === 'container') {
+ openPath.push(p.name);
+ descriptor.setUiState('opened', openPath, true);
+ p.type === 'container' && traverseProps(p.properties);
+ openPath.pop();
+ }
+ });
+ }
+ traverseProps(property.properties);
+ this.updateItem(descriptor.getRoot().model);
+ CatalogItemsActions.catalogItemDescriptorChanged.defer(descriptor.getRoot());
+ }
+
+ modelListRemove(input) {
+ const { descriptor, path, property } = input;
+ const removeMethod = Property.getContainerMethod(property, descriptor, 'remove');
+ if (removeMethod) {
+ removeMethod(_get(descriptor.model, path));
+ } else {
+ const index = path.pop();
+ let list = _get(descriptor.model, path);
+ list = list.splice(index, 1);
+ }
+ this.updateItem(descriptor.getRoot().model);
+ CatalogItemsActions.catalogItemDescriptorChanged.defer(descriptor.getRoot());
+ }
+
+ showHelpForNothing() {
+ this.setState({ showHelp: { onFocus: false, forAll: false, forNothing: true } })
+ }
+
+ showHelpForAll() {
+ this.setState({ showHelp: { onFocus: false, forAll: true, forNothing: false } })
+ }
+
+ showHelpOnFocus() {
+ this.setState({ showHelp: { onFocus: true, forAll: false, forNothing: false } })
+ }
+
+ clearOpenPanelState(descriptor) {
+ if (descriptor) {
+ descriptor.setUiState('opened', [], {});
+ this.updateItem(descriptor.getRoot().model);
+ }
+ }
+ collapseAllPanels(input) {
+ this.setState({ openPanelsWithData: false, collapsePanelsByDefault: true });
+ this.clearOpenPanelState(input.descriptor);
+ }
+
+ expandAllPanels(input) {
+ this.setState({ openPanelsWithData: false, collapsePanelsByDefault: false });
+ this.clearOpenPanelState(input.descriptor);
+ }
+
+ showPanelsWithData(input) {
+ this.setState({ openPanelsWithData: true, collapsePanelsByDefault: true });
+ this.clearOpenPanelState(input.descriptor);