Skip to content

Commit e437f88

Browse files
authored
✨ Support enums and validate arrays (ITISFoundation#3053)
1 parent 9ce92d6 commit e437f88

File tree

4 files changed

+110
-29
lines changed

4 files changed

+110
-29
lines changed

services/web/client/source/class/osparc/component/form/Auto.js

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ qx.Class.define("osparc.component.form.Auto", {
8888
},
8989

9090
statics: {
91-
hasValidationProp: function(s) {
91+
hasValidatableProp: function(s) {
9292
return Object.keys(s).some(r => ["minimum", "maximum"].includes(r));
9393
}
9494
},
@@ -253,9 +253,6 @@ qx.Class.define("osparc.component.form.Auto", {
253253
}
254254
}
255255
);
256-
if (!s.set) {
257-
s.set = {};
258-
}
259256
s.set.dateFormat = new qx.util.format.DateFormat(
260257
this["tr"](
261258
s.set.dateFormat ?
@@ -293,9 +290,6 @@ qx.Class.define("osparc.component.form.Auto", {
293290
);
294291
},
295292
__setupNumberField: function(s, key) {
296-
if (!s.set) {
297-
s.set = {};
298-
}
299293
if (s.defaultValue) {
300294
s.set.value = qx.lang.Type.isNumber(s.defaultValue) ? String(s.defaultValue) : s.defaultValue;
301295
} else {
@@ -333,9 +327,6 @@ qx.Class.define("osparc.component.form.Auto", {
333327
this.__formCtrl.addBindingOptions(key, model2target, target2model);
334328
},
335329
__setupSpinner: function(s, key) {
336-
if (!s.set) {
337-
s.set = {};
338-
}
339330
s.set.maximum = s.maximum ? parseInt(s.maximum) : 10000;
340331
s.set.minimum = s.minimum ? parseInt(s.minimum) : -10000;
341332
s.set.value = s.defaultValue ? parseInt(String(s.defaultValue)) : 0;
@@ -366,23 +357,39 @@ qx.Class.define("osparc.component.form.Auto", {
366357
ctrl.bindProperty("label", "label", null, item, index);
367358
}
368359
});
360+
// Content Schema
361+
if ("enum" in s) {
362+
const entries = [];
363+
s.enum.forEach(entry => {
364+
entries.push({
365+
label: entry.toString(),
366+
key: entry
367+
});
368+
});
369+
s.widget["structure"] = entries;
370+
}
369371
const cfg = s.widget;
370-
let structure = cfg.structure;
371-
if (structure) {
372-
structure.forEach(item => {
372+
let items = cfg.structure;
373+
if (items) {
374+
items.forEach(item => {
373375
item.label = item.label || "";
374376
}, this);
375377
} else {
376-
structure = [{
378+
items = [{
377379
label: "",
378380
key: null
379381
}];
380382
}
381-
if (s.defaultValue) {
383+
if ("defaultValue" in s) {
382384
s.set.value = [s.defaultValue];
383385
}
384-
let sbModel = qx.data.marshal.Json.createModel(structure);
386+
// Content Schema
387+
if ("default" in s) {
388+
s.set.value = [s.default];
389+
}
390+
let sbModel = qx.data.marshal.Json.createModel(items);
385391
controller.setModel(sbModel);
392+
control.setModelSelection(s.set.value);
386393
},
387394
__setupComboBox: function(s, key, control) {
388395
let ctrl = this.__boxCtrl[key] = new qx.data.controller.List(null, control);
@@ -398,9 +405,6 @@ qx.Class.define("osparc.component.form.Auto", {
398405
ctrl.setModel(sbModel);
399406
},
400407
__setupBoolField: function(s, key, control) {
401-
if (!s.set) {
402-
s.set = {};
403-
}
404408
if (s.set.value && typeof s.set.value === "string") {
405409
s.set.value = Boolean(s.set.value.toLowerCase() === "true");
406410
}
@@ -448,12 +452,16 @@ qx.Class.define("osparc.component.form.Auto", {
448452
Object.assign(s, s.contentSchema);
449453
}
450454

451-
if (s.defaultValue) {
452-
if (!s.set) {
453-
s.set = {};
454-
}
455+
if (!s.set) {
456+
s.set = {};
457+
}
458+
if ("defaultValue" in s) {
455459
s.set.value = s.defaultValue;
456460
}
461+
// Content Schema
462+
if ("default" in s) {
463+
s.set.value = s.default;
464+
}
457465

458466
if (!s.widget) {
459467
let type = s.type;
@@ -472,6 +480,10 @@ qx.Class.define("osparc.component.form.Auto", {
472480
}[type]
473481
};
474482
}
483+
// Content Schema
484+
if ("enum" in s) {
485+
s.widget["type"] = "SelectBox";
486+
}
475487
let control;
476488
let setup;
477489
switch (s.widget.type) {
@@ -506,6 +518,7 @@ qx.Class.define("osparc.component.form.Auto", {
506518
case "SelectBox":
507519
control = new qx.ui.form.SelectBox();
508520
setup = this.__setupSelectBox;
521+
s.set["minWidth"] = 80;
509522
break;
510523
case "ComboBox":
511524
control = new qx.ui.form.ComboBox();
@@ -556,9 +569,14 @@ qx.Class.define("osparc.component.form.Auto", {
556569
control.unit = unit;
557570
}
558571

559-
if (this.self().hasValidationProp(s)) {
560-
const manager = osparc.ui.form.ContentSchemaHelper.createValidator(control, s);
561-
control.addListener("changeValue", () => manager.validate());
572+
let validator = null;
573+
if ("getValidator" in control) {
574+
validator = control.getValidator();
575+
} else if (this.self().hasValidatableProp(s)) {
576+
validator = osparc.ui.form.ContentSchemaHelper.createValidator(control, s);
577+
}
578+
if (validator) {
579+
control.addListener("changeValue", () => validator.validate());
562580
}
563581

564582
return control;

services/web/client/source/class/osparc/ui/form/ContentSchemaArray.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,13 @@ qx.Class.define("osparc.ui.form.ContentSchemaArray", {
3030
contentSchema: {
3131
check: "Object",
3232
init: null,
33+
nullable: true,
34+
apply: "__applyContentSchema"
35+
},
36+
37+
validator: {
38+
check: "qx.ui.form.validation.Manager",
39+
init: null,
3340
nullable: true
3441
}
3542
},
@@ -74,6 +81,14 @@ qx.Class.define("osparc.ui.form.ContentSchemaArray", {
7481
}
7582
}
7683
this.base(arguments, value);
84+
},
85+
86+
__applyContentSchema: function(contentSchema) {
87+
const isValidatable = Object.keys(contentSchema).some(r => ["items", "minItems", "maxItems"].indexOf(r) >= 0);
88+
if (isValidatable) {
89+
const validator = osparc.ui.form.ContentSchemaHelper.createArrayValidator(this, contentSchema);
90+
this.setValidator(validator);
91+
}
7792
}
7893
}
7994
});

services/web/client/source/class/osparc/ui/form/ContentSchemaHelper.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,49 @@ qx.Class.define("osparc.ui.form.ContentSchemaHelper", {
6969
return Boolean(valid);
7070
});
7171
return manager;
72+
},
73+
74+
createArrayValidator: function(control, s) {
75+
const manager = new qx.ui.form.validation.Manager();
76+
manager.add(control, (valuesInString, item) => {
77+
const values = JSON.parse(valuesInString);
78+
if ("minItems" in s && (values.length < s.minItems)) {
79+
let oorInvalidMessage = qx.locale.Manager.tr("Minimum items: ") + s.minItems;
80+
item.setInvalidMessage(oorInvalidMessage);
81+
return false;
82+
}
83+
if ("maxItems" in s && (values.length > s.maxItems)) {
84+
let oorInvalidMessage = qx.locale.Manager.tr("Maximum items: ") + s.maxItems;
85+
item.setInvalidMessage(oorInvalidMessage);
86+
return false;
87+
}
88+
let multiplier = 1;
89+
let oorInvalidMessage = qx.locale.Manager.tr("Out of range");
90+
if ("x_unit" in s) {
91+
const {
92+
unitPrefix
93+
} = osparc.utils.Units.decomposeXUnit(s["x_unit"]);
94+
multiplier = osparc.utils.Units.getMultiplier(unitPrefix, control.unitPrefix);
95+
}
96+
let valid = true;
97+
if ("items" in s) {
98+
if ("minimum" in s["items"] && values.some(v => v < multiplier*(s["items"].minimum))) {
99+
valid = false;
100+
oorInvalidMessage += "<br>";
101+
oorInvalidMessage += qx.locale.Manager.tr("Minimum value: ") + multiplier*(s["items"].minimum);
102+
}
103+
if ("maximum" in s["items"] && values.some(v => v > multiplier*(s["items"].maximum))) {
104+
valid = false;
105+
oorInvalidMessage += "<br>";
106+
oorInvalidMessage += qx.locale.Manager.tr("Maximum value: ") + multiplier*(s["items"].maximum);
107+
}
108+
}
109+
if (!valid) {
110+
item.setInvalidMessage(oorInvalidMessage);
111+
}
112+
return Boolean(valid);
113+
});
114+
return manager;
72115
}
73116
}
74117
});

services/web/client/source/class/osparc/utils/Units.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,14 @@ qx.Class.define("osparc.utils.Units", {
178178

179179
convertValue: function(val, oldPrefix, newPrefix) {
180180
const multiplier = this.getMultiplier(oldPrefix, newPrefix);
181-
const newValue = val*multiplier;
182-
// strip extra zeros
183-
return parseFloat((newValue).toFixed(15));
181+
if (Array.isArray(JSON.parse(val))) {
182+
val = JSON.parse(val);
183+
val.forEach((v, index) => {
184+
val[index] = parseFloat((v*multiplier).toFixed(15));
185+
});
186+
return val;
187+
}
188+
return parseFloat((val*multiplier).toFixed(15));
184189
},
185190

186191
composeXUnit: function(unit, unitPrefix) {

0 commit comments

Comments
 (0)