Added support to Composer to support a model leaf of type empty.
[osm/UI.git] / skyquake / plugins / composer / src / src / libraries / model / DescriptorModelMetaProperty.js
1 /*
2 *
3 * Copyright 2016 RIFT.IO Inc
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 */
18 /**
19 * Created by onvelocity on 1/27/16.
20 *
21 * This class provides utility methods for interrogating an instance of model uiState object.
22 */
23
24 import _includes from 'lodash/includes'
25 import _isArray from 'lodash/isArray'
26 import guid from './../guid'
27 import changeCase from 'change-case'
28 import InstanceCounter from './../InstanceCounter'
29 import DescriptorModelFields from './DescriptorModelFields'
30 import DescriptorTemplateFactory from './DescriptorTemplateFactory'
31 import utils from '../utils'
32
33 export default {
34 isBoolean(property = {}) {
35 return (typeof(property['data-type']) == 'string') && (property['data-type'].toLowerCase() == 'boolean')
36 },
37 isLeafEmpty(property = {}) {
38 return (typeof(property['data-type']) == 'string') && (property['data-type'].toLowerCase() == 'empty')
39 },
40 isLeaf(property = {}) {
41 return /leaf|choice/.test(property.type);
42 },
43 isList(property = {}) {
44 return /list|leaf_list/.test(property.type);
45 },
46 isLeafList(property = {}) {
47 return property.type === 'leaf_list';
48 },
49 isLeafRef(property = {}) {
50 const type = property['data-type'] || {};
51 return type.hasOwnProperty('leafref');
52 },
53 isArray(property = {}) {
54 // give '1' or '0..N' or '0..1' or '0..5' determine if represents an array
55 // '0..1' is not an array
56 // '0..2' is an array
57 // '0..N' is an array
58 const cardinality = String(property.cardinality).toUpperCase();
59 const pos = cardinality.lastIndexOf('.') + 1;
60 const val = cardinality.substr(pos);
61 return val === 'N' || parseInt(val, 10) > 1;
62 },
63 isEnumeration(property = {}) {
64 const type = property['data-type'] || {};
65 return type.hasOwnProperty('enumeration');
66 },
67 isRequired(property = {}) {
68 return /^1/.test(property.cardinality);
69 },
70 isObject(property = {}) {
71 return !/^(leaf|leaf_list)$/.test(property.type);
72 },
73 isSimpleList(property = {}) {
74 return _includes(DescriptorModelFields.simpleList, property.name);
75 },
76 isPrimativeDataType(property = {}) {
77 const Property = this;
78 return /string|int/.test(property['data-type']) || Property.isEnumeration(property) || Property.isGuid(property);
79 },
80 defaultValue(property = {}) {
81 if (property.defaultValue) {
82 return property.defaultValue;
83 }
84 if (this.isObject(property)) {
85 return {};
86 }
87 return '';
88 },
89 getContainerMethod(property, container, methodName) {
90 const name = changeCase.camel(methodName + '-' + property.name);
91 if (typeof container[name] === 'function') {
92 return container[name].bind(container);
93 }
94 },
95 getContainerCreateMethod(property, container) {
96 const name = changeCase.camel('create-' + property.name);
97 if (typeof container[name] === 'function') {
98 return container[name].bind(container);
99 }
100 },
101 containerHasCreateMethod(container, property = {}) {
102 const find = changeCase.camel('create-' + property.name);
103 return typeof container[find] === 'function';
104 },
105 getEnumeration(property = {}, value) {
106 const enumeration = property['data-type'].enumeration.enum;
107 if (typeof enumeration === 'string') {
108 return [{name: enumeration, value: enumeration, isSelected: String(value) === enumeration}];
109 }
110 return Object.keys(enumeration).map(enumName => {
111 let enumValue = enumName;
112 // warn we only support named enums and systematically ignore enum values
113 //const enumObj = enumeration[enumName];
114 //if (enumObj) {
115 // enumValue = enumObj.value || enumName;
116 //}
117 return {name: enumName, value: enumValue, isSelected: String(enumValue) === String(value)};
118 });
119 },
120 getLeafRef(property = {}, path, value, fullFieldKey, transientCatalogs, container) {
121 const leafRefPath = property['data-type']['leafref']['path'];
122
123 const transientCatalogHash = {};
124
125 transientCatalogs.map((catalog) => {
126 transientCatalogHash[catalog.type + '-catalog'] = {};
127 transientCatalogHash[catalog.type + '-catalog'][catalog.type] = catalog['descriptors'];
128 });
129
130 let leafRefPathValues = utils.resolveLeafRefPath(transientCatalogHash, leafRefPath, fullFieldKey, path, container);
131
132 let leafRefObjects = [];
133
134 leafRefPathValues && leafRefPathValues.map((leafRefPathValue) => {
135 leafRefObjects.push({
136 name: leafRefPathValue,
137 value: leafRefPathValue,
138 isSelected: String(leafRefPathValue) === String(value)
139 });
140 });
141
142 return leafRefObjects;
143 },
144 isGuid(property = {}) {
145 const type = property['data-type'];
146 if (typeof type === 'object' && type.leafref && type.leafref.path) {
147 return /\bid$/.test(type.leafref.path);
148 }
149 return /uuid/.test(property['data-type']);
150 },
151 /**
152 * Create a new instance of the indicated property and, if relevent, use the given
153 * unique name for the instance's key (see generateItemUniqueName)
154 *
155 * @param {Object} typeOrPath - property definition
156 * @param {any} uniqueName
157 * @returns
158 */
159 createModelInstance(property, uniqueName) {
160 const Property = this;
161 const defaultValue = Property.defaultValue.bind(this);
162 function createModel(uiState, parentMeta, uniqueName) {
163 const model = {};
164 if (Property.isLeaf(uiState)) {
165 if (uiState.name === 'name') {
166 return uniqueName || (changeCase.param(parentMeta.name) + '-' + InstanceCounter.count(parentMeta[':qualified-type']));
167 }
168 if (_isArray(parentMeta.key) && _includes(parentMeta.key, uiState.name)) {
169 if (/uuid/.test(uiState['data-type'])) {
170 return guid();
171 }
172 if (uiState['data-type'] === 'string') {
173 // if there is only one key property and we were given a
174 // unique name (probably because creating a list entry
175 // property) then use the unique name otherwise make one up.
176 if (parentMeta.key.length > 1 || !uniqueName) {
177 const prefix = uiState.name.replace('id', '');
178 uniqueName = (prefix ? changeCase.param(prefix) + '-' : '') + guid(5);
179 }
180 return uniqueName;
181 }
182 if (/int/.test(uiState['data-type'])) {
183 return InstanceCounter.count(uiState[':qualified-type']);
184 }
185 }
186 return defaultValue(uiState);
187 } else if (Property.isList(uiState)) {
188 return [];
189 } else {
190 uiState.properties.forEach(p => {
191 model[p.name] = createModel(p, uiState, uniqueName);
192 });
193 }
194 return model;
195 }
196 if (property) {
197 if (Property.isPrimativeDataType(property)) {
198 return defaultValue(property);
199 }
200 if (property.type === 'leaf') {
201 return defaultValue(property);
202 }
203 if (/list/.test(property.type)) {
204 property.type = 'container';
205 }
206 const modelInstance = createModel(property, property, uniqueName);
207 modelInstance.uiState = {type: property.name};
208 const modelFragment = DescriptorTemplateFactory.createModelForType(property[':qualified-type'] || property.name) || {};
209 Object.assign(modelInstance, modelFragment);
210 return modelInstance;
211 }
212 }
213 }