update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b third try
[osm/UI.git] / skyquake / plugins / composer / src / src / libraries / model / DescriptorModel.js
1
2 /*
3 *
4 * Copyright 2016 RIFT.IO Inc
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 */
19 /**
20 * Created by onvelocity on 8/23/15.
21 */
22
23 import _isArray from 'lodash/isArray'
24 import _set from 'lodash/set'
25 import _get from 'lodash/get'
26 import guid from '../guid'
27 import Position from '../graph/Position'
28 import IconFactory from './IconFactory'
29 import SelectionManager from '../SelectionManager'
30 import DescriptorModelMetaFactory from './DescriptorModelMetaFactory'
31
32 /**
33 * Abstract base class for the CONFD MANO Descriptors as defined by the Rift.ware YANG configuration files.
34 *
35 * Sub-classes should specify the type and qualified-type properties.
36 */
37 export default class DescriptorModel {
38
39 constructor(model = {uiState: {}}, parent = null, readonly = false) {
40 // when our instance has no more strong references
41 // then our properties will get garbage collected.
42 this._props_ = new WeakMap();
43 this._props_.set(this, {
44 position: new Position(),
45 children: new Set(),
46 values: {},
47 model: model
48 });
49 this.className = 'DescriptorModel';
50 this.uid = this.uid || guid();
51 if (parent instanceof DescriptorModel) {
52 parent.addChild(this);
53 }
54 this.isReadOnly = readonly;
55 }
56
57 get fieldNames() {
58 return DescriptorModelMetaFactory.getModelFieldNamesForType(this.uiState['qualified-type'] || this.type);
59 }
60
61 get property() {
62 return DescriptorModelMetaFactory.getModelMetaForType(this.uiState['qualified-type'] || this.type);
63 }
64
65 get model() {
66 let model = this._props_.get(this).model;
67 if (!model) {
68 model = this.model = {uiState: {}};
69 }
70 return model;
71 }
72
73 set model(model) {
74 this._props_.get(this).model = model;
75 return this;
76 }
77
78 get uiState() {
79 return this.model.uiState = this.model.uiState || {};
80 }
81
82 set uiState(uiState) {
83 this.model.uiState = uiState;
84 return this;
85 }
86
87 get uid() {
88 return this.uiState[':uid'];
89 }
90
91 set uid(uid) {
92 this.uiState[':uid'] = uid;
93 return this;
94 }
95
96 get key() {
97 return this.id;
98 }
99
100 // key is read only by design
101
102 get id() {
103 return this.model.id;
104 }
105
106 set id(id) {
107 this.model.id = id;
108 return this;
109 }
110
111 get title() {
112 return this.model['short-name'] || this.model.name || this.key;
113 }
114
115 // title is read only by design
116
117 get name() {
118 return this.model.name;
119 }
120
121 set name(name) {
122 this.model.name = name;
123 }
124
125 get 'short-name'() {
126 return this.model['short-name'];
127 }
128
129 set 'short-name'(name) {
130 this.model['short-name'] = name;
131 }
132
133 get type() {
134 return this.uiState.type;
135 }
136
137 set type(type) {
138 this.uiState.type = type;
139 return this;
140 }
141
142 get qualifiedType() {
143 return this.uiState['qualified-type'] || this.type;
144 }
145
146 set qualifiedType(type) {
147 this.uiState['qualified-type'] = type;
148 }
149
150 get position() {
151 return this._props_.get(this).position;
152 }
153
154 set position(position) {
155 if (!(position instanceof Position)) {
156
157 }
158 this._props_.get(this).position = position;
159 return this;
160 }
161
162 get location() {
163 return this.uiState.location;
164 }
165
166 set location(v) {
167 this.uiState.location = v;
168 }
169
170 get children() {
171 return Array.from(this._props_.get(this).children);
172 }
173
174 addProp(name, value) {
175 this._props_.get(this).values[name] = value;
176 return this;
177 }
178
179 getProp(name) {
180 return this._props_.get(this).values[name];
181 }
182
183 addChild(child) {
184 if (!child instanceof DescriptorModel) {
185 throw new ReferenceError('child must be an instance of DescriptorModel class');
186 }
187 if (this.findChildByUid(child.uid)) {
188 console.warn('Child already exists');
189 // NOTE: Commented out this line because it was causing issues with Internal VLD.
190 // TODO: Check why it caused issues with Internal VLD
191 // throw new ReferenceError('child already exists');
192 }
193 if (child.parent instanceof DescriptorModel) {
194 throw new ReferenceError('child already has a parent');
195 }
196 child.parent = this;
197 this._props_.get(this).children.add(child);
198 }
199
200 findChildByUid(uid) {
201 // uid can be a DescriptorModel instance, JSON model object, or a uid string
202 if (typeof uid === 'object') {
203 uid = uid.uiState && uid.uiState[':uid'];
204 }
205 if (typeof uid === 'string') {
206 return this.children.filter(d => d.uid === uid)[0];
207 }
208 }
209
210 removeChild(child) {
211 let uid;
212 // warn don't clear parent so that removed ones can get to root for updating the catalog json model
213 //child.parent = null;
214 // uid can be a DescriptorModel instance, JSON model object, or a uid string
215 if (typeof uid === 'object') {
216 uid = uid.uiState && uid.uiState[':uid'];
217 }
218 if (typeof uid === 'string') {
219 this.children.filter(d => d.uid === uid).forEach(d => this._props_.get(this).children.delete(d));
220 } else {
221 this._props_.get(this).children.delete(child);
222 }
223 }
224
225 getRoot() {
226 let root = this;
227 while (root && root.parent) {
228 root = root.parent;
229 }
230 return root;
231 }
232
233 getRootNSDContainer() {
234 let container = this.parent;
235 while(container) {
236 if (container.type === 'nsd') {
237 return container;
238 }
239 container = container.parent;
240 }
241 }
242
243 setPosition(position) {
244 this.position = new Position(position);
245 }
246
247 get selected() {
248 return SelectionManager.isSelected(this);
249 }
250
251 get colors() {
252 return this.uiState.colors || {primary: 'black', secondary: 'white'};
253 }
254
255 set colors(colors) {
256 this.uiState.colors = colors;
257 }
258
259 get icon() {
260 return IconFactory.getIconForType(this.type);
261 }
262
263 get width() {
264 return this.position.width;
265 }
266
267 get height() {
268 return this.position.height;
269 }
270
271 get displayData() {
272 return {
273 title: this.title,
274 type: this.model.type,
275 cpNumber: this.cpNumber
276 };
277 }
278
279 valueOf() {
280 return this.model;
281 }
282
283 updateModelList(modelFieldName, modelFieldValue, descriptorClass = DescriptorModel, newItemAddedSuccessCallback = () => {}) {
284 // value can be Array of (DescriptorModel | json model), DescriptorModel, or json model
285 if (_isArray(modelFieldValue)) {
286 this.model[modelFieldName] = modelFieldValue.map(d => d instanceof descriptorClass ? d.model : d);
287 return true;
288 }
289 const size = this.model[modelFieldName].length;
290 if (modelFieldValue instanceof descriptorClass) {
291 this.model[modelFieldName].push(modelFieldValue.valueOf());
292 newItemAddedSuccessCallback(modelFieldValue);
293 } else if (typeof modelFieldValue === 'object') {
294 this.model[modelFieldName].push(modelFieldValue);
295 newItemAddedSuccessCallback(new descriptorClass(modelFieldValue, this));
296 } else {
297 throw new ReferenceError(`expect object to be either an Array, ${descriptorClass.name} or JSON object`);
298 }
299 return size !== this.model[modelFieldName].length;
300 }
301
302 removeModelListItem(propertyName, child) {
303 // ensure child is a DescriptorModel instance
304 child = this.findChildByUid(child) || child;
305 if (!child) {
306 return false;
307 }
308 this.removeChild(child);
309 const uid = child.uid;
310 const length = this[propertyName].length;
311 this[propertyName] = this[propertyName].filter(d => d.uid !== uid);
312 return length !== this[propertyName].length;
313 }
314
315 setUiState(setting, path, value){
316 _set(this.uiState, [setting].concat(path), value);
317 }
318
319 getUiState(setting, path, defaultValue){
320 return _get(this.uiState, [setting].concat(path), defaultValue);
321 }
322
323 }