/* * * Copyright 2016 RIFT.IO Inc * * 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. * */ /** * Created by onvelocity on 1/18/16. * * This class generates the form fields used to edit the CONFD JSON model. */ import _uniqueId from 'lodash/uniqueId'; import _set from 'lodash/set'; import _get from 'lodash/get'; import _has from 'lodash/has'; import _keys from 'lodash/keys'; import _isObject from 'lodash/isObject'; import _isArray from 'lodash/isArray'; import _isNumber from 'lodash/isNumber'; import utils from '../libraries/utils' import React from 'react' import changeCase from 'change-case' import toggle from '../libraries/ToggleElementHandler' import Property from '../libraries/model/DescriptorModelMetaProperty' import SelectionManager from '../libraries/SelectionManager' import ComposerAppActions from '../actions/ComposerAppActions' import CatalogItemsActions from '../actions/CatalogItemsActions' import DescriptorEditorActions from '../actions/DescriptorEditorActions' import DescriptorModelFactory from '../libraries/model/DescriptorModelFactory' import DescriptorModelMetaFactory from '../libraries/model/DescriptorModelMetaFactory' import PropertyNavigate from './model/PropertyNavigate' import '../styles/EditDescriptorModelProperties.scss' function selectModel(container, model) { const root = container.getRoot(); if (SelectionManager.select(model)) { CatalogItemsActions.catalogItemMetaDataChanged(root.model); } } function isDataProperty(property) { return property.type === 'leaf' || property.type === 'leaf_list' || property.type === 'choice'; } function checkIfValueEmpty(value) { if (value === null || typeof value === 'undefined') { return true; } else if (_isArray(value) && !value.length) { return true; } else if (_isObject(value)) { const keys = _keys(value); if (keys.length < 2) { return !keys.length || (keys[0] === 'uiState') } } return false; } function makeOption(path, value) { let labelPath = path.map(node => _isNumber(node) ? node + 1: node); return { value: path, label: labelPath.join(' . ') + (value ? ' : ' + value : '') } } export default function NavigateDescriptorModel(props) { const { container, idMaker, style } = props; const uiState = container.uiState; function buildField(property, path, value) { return [makeOption(path, value)]; } function buildLeafList(property, path, value) { const searchValue = Array.isArray(value) ? value.join(' ') : value; return [makeOption(path, searchValue)]; } function buildChoice(property, path, value) { const uiStatePath = path.concat(['uiState']); const choiceStatePath = ['choice', property.name]; const fullChoiceStatePath = uiStatePath.concat(choiceStatePath); function determineSelectedChoice(model) { let choiceState = utils.resolvePath(container.model, fullChoiceStatePath.join('.')); if (choiceState) { return property.properties.find(c => c.name === choiceState.selected); } const selectedCase = property.properties.find(c => c.properties && c.properties.find(p => _has(model, path.concat([p.name]))) ); return selectedCase; } const selectedCase = determineSelectedChoice(container.model); return [makeOption(path)].concat(selectedCase ? buildComponentsForProperties( selectedCase.properties, path, path.length ? _get(container.model, path) : container.model) : []); } function buildList(property, path, value, uniqueId) { if (value && !Array.isArray(value)) { value = [value]; } function getListItemSummary(index, value) { const keys = property.key.map((key) => value[key]); const summary = keys.join(' '); return summary.length > 1 ? summary : '' + (index + 1); } const children = value ? value.reduce((a, itemValue, i) => { const itemPath = path.concat([i]); return a.concat(buildComponentsForProperties(property.properties, itemPath, itemValue)); }, [makeOption(path)]) : [makeOption(path)]; return children; } function buildSimpleList(property, path, value, uniqueId) { return [makeOption(path)]; } function buildContainer(property, path, value, uniqueId, readOnly) { return buildComponentsForProperties(property.properties, path, value); } /** * buiid and return an array of components representing an editor for each property. * * @param {any} container the master document being edited * @param {[property]} properties * @param {string} pathToProperties path within the container to the properties * @param {Object} data source for each property * which may be useful/necessary to a components rendering. * @returns an array of react components */ function buildComponentsForProperties(properties, pathToProperties, data) { return properties.reduce((a, property) => { let value; let propertyPath = pathToProperties.slice(); if (property.type != 'choice') { propertyPath.push(property.name); } if (data && typeof data === 'object') { value = _get(data, property.name); } let result = []; try { result = buildPropertyComponent(property, propertyPath, value); } catch (e) { console.error(e); } return a.concat(result); }, []); } function buildPropertyComponent(property, path, value) { const fields = []; const isObject = Property.isObject(property); const title = changeCase.titleCase(property.name); // create a unique Id for use as react component keys and html element ids // use uid (from ui info) instead of id property (which is not stable) let uniqueId = container.uid; let containerRef = container; while (containerRef.parent) { uniqueId = containerRef.parent.uid + ':' + uniqueId; containerRef = containerRef.parent; } uniqueId += ':' + path.join(':') if (!property.properties && isObject) { console.debug('no properties', property); const uiState = DescriptorModelMetaFactory.getModelMetaForType(property.name) || {}; property.properties = uiState.properties; } if (property.type === 'leaf') { return buildField(property, path, value, uniqueId); } else if (property.type === 'leaf_list') { return buildLeafList(property, path, value, uniqueId); } else if (property.type === 'list') { return Property.isSimpleList(property) ? buildSimpleList(property, path, value, uniqueId) : buildList(property, path, value, uniqueId); } else if (property.type === 'container') { return buildContainer(property, path, value, uniqueId); } else if (property.type === 'choice') { return buildChoice(property, path, value, uniqueId); } else { return ([]); } } if (!(DescriptorModelFactory.isContainer(container))) { return null; } const containerType = container.uiState['qualified-type'] || container.uiState.type; let properties = DescriptorModelMetaFactory.getModelMetaForType(containerType).properties; // bubble all data properties to top of list let twoLists = properties.reduce((o, property) => { const value = _get(container.model, [property.name]); if (isDataProperty(property)) { o.listOne.push(property); } else { o.listTwo.push(property); } return o; }, { listOne: [], listTwo: [] }); properties = twoLists.listOne.concat(twoLists.listTwo); const options = buildComponentsForProperties(properties, [], container.model); return options.length ? () :
; };