@saltcorn/builder 0.9.4-beta.2 → 0.9.4-beta.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builder_bundle.js +23 -11
- package/package.json +3 -1
- package/src/components/Builder.js +92 -66
- package/src/components/Library.js +46 -22
- package/src/components/RenderNode.js +5 -0
- package/src/components/Toolbox.js +173 -165
- package/src/components/elements/Action.js +12 -0
- package/src/components/elements/Aggregation.js +193 -104
- package/src/components/elements/BoxModelEditor.js +8 -8
- package/src/components/elements/Column.js +16 -2
- package/src/components/elements/Columns.js +4 -4
- package/src/components/elements/Container.js +26 -2
- package/src/components/elements/DropMenu.js +31 -2
- package/src/components/elements/Field.js +22 -20
- package/src/components/elements/HTMLCode.js +1 -1
- package/src/components/elements/JoinField.js +25 -1
- package/src/components/elements/Link.js +1 -0
- package/src/components/elements/ListColumn.js +177 -0
- package/src/components/elements/ListColumns.js +62 -0
- package/src/components/elements/RelationBadges.js +53 -44
- package/src/components/elements/Tabs.js +118 -40
- package/src/components/elements/Text.js +4 -2
- package/src/components/elements/View.js +125 -68
- package/src/components/elements/ViewLink.js +100 -48
- package/src/components/elements/utils.js +198 -98
- package/src/components/storage.js +67 -5
- package/tests/relations_finder.test.js +58 -92
- package/tests/test_data.js +0 -163
|
@@ -18,6 +18,8 @@ import FontIconPicker from "@fonticonpicker/react-fonticonpicker";
|
|
|
18
18
|
import faIcons from "./faicons";
|
|
19
19
|
import { Columns, ntimes } from "./Columns";
|
|
20
20
|
import Tippy from "@tippyjs/react";
|
|
21
|
+
import { RelationType } from "@saltcorn/common-code";
|
|
22
|
+
import Select from "react-select";
|
|
21
23
|
|
|
22
24
|
export const DynamicFontAwesomeIcon = ({ icon, className }) => {
|
|
23
25
|
if (!icon) return null;
|
|
@@ -138,7 +140,7 @@ export /**
|
|
|
138
140
|
*/
|
|
139
141
|
const OrFormula = ({ setProp, isFormula, node, nodekey, children }) => {
|
|
140
142
|
const { mode } = React.useContext(optionsCtx);
|
|
141
|
-
|
|
143
|
+
const allowFormula = mode === "show" || mode === "list";
|
|
142
144
|
/**
|
|
143
145
|
* @returns {void}
|
|
144
146
|
*/
|
|
@@ -159,14 +161,14 @@ const OrFormula = ({ setProp, isFormula, node, nodekey, children }) => {
|
|
|
159
161
|
});
|
|
160
162
|
};
|
|
161
163
|
let errorString = false;
|
|
162
|
-
if (
|
|
164
|
+
if (allowFormula && isFormula[nodekey]) {
|
|
163
165
|
try {
|
|
164
166
|
Function("return " + node[nodekey]);
|
|
165
167
|
} catch (error) {
|
|
166
168
|
errorString = error.message;
|
|
167
169
|
}
|
|
168
170
|
}
|
|
169
|
-
return
|
|
171
|
+
return !allowFormula ? (
|
|
170
172
|
children
|
|
171
173
|
) : (
|
|
172
174
|
<Fragment>
|
|
@@ -445,6 +447,10 @@ const fetchPreview = ({ url, body, options, setPreviews, node_id, isView }) => {
|
|
|
445
447
|
}
|
|
446
448
|
const newHtml = $(".preview-scratchpad").html();
|
|
447
449
|
setPreviews((prevState) => ({ ...prevState, [node_id]: newHtml }));
|
|
450
|
+
})
|
|
451
|
+
.catch((e) => {
|
|
452
|
+
console.log("Unable to fetch the preview:");
|
|
453
|
+
console.log(e);
|
|
448
454
|
});
|
|
449
455
|
};
|
|
450
456
|
|
|
@@ -487,6 +493,7 @@ export const fetchViewPreview =
|
|
|
487
493
|
};
|
|
488
494
|
let viewname,
|
|
489
495
|
body = configuration ? { ...configuration } : {};
|
|
496
|
+
if (!view) return "";
|
|
490
497
|
if (view.includes(":")) {
|
|
491
498
|
const [prefix, rest] = view.split(":");
|
|
492
499
|
const tokens = rest.split(".");
|
|
@@ -897,24 +904,51 @@ const ConfigField = ({
|
|
|
897
904
|
spellCheck={false}
|
|
898
905
|
/>
|
|
899
906
|
),
|
|
900
|
-
select: () =>
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
907
|
+
select: () => {
|
|
908
|
+
if (field.class?.includes?.("selectizable")) {
|
|
909
|
+
const seloptions = field.options.map((o, ix) =>
|
|
910
|
+
o.name && o.label
|
|
911
|
+
? { value: o.name, label: o.label }
|
|
912
|
+
: { value: o, label: o }
|
|
913
|
+
);
|
|
914
|
+
return (
|
|
915
|
+
<Select
|
|
916
|
+
options={seloptions}
|
|
917
|
+
value={seloptions.find((so) => value === so.value)}
|
|
918
|
+
onChange={(e) =>
|
|
919
|
+
(e.name && myOnChange(e.name)) ||
|
|
920
|
+
(e.value && myOnChange(e.value)) ||
|
|
921
|
+
(typeof e === "string" && myOnChange(e))
|
|
922
|
+
}
|
|
923
|
+
onBlur={(e) =>
|
|
924
|
+
(e.name && myOnChange(e.name)) ||
|
|
925
|
+
(e.value && myOnChange(e.value)) ||
|
|
926
|
+
(typeof e === "string" && myOnChange(e))
|
|
927
|
+
}
|
|
928
|
+
menuPortalTarget={document.body}
|
|
929
|
+
styles={{ menuPortal: (base) => ({ ...base, zIndex: 19999 }) }}
|
|
930
|
+
></Select>
|
|
931
|
+
);
|
|
932
|
+
} else
|
|
933
|
+
return (
|
|
934
|
+
<select
|
|
935
|
+
className="form-control form-select"
|
|
936
|
+
value={value || ""}
|
|
937
|
+
onChange={(e) => e.target && myOnChange(e.target.value)}
|
|
938
|
+
onBlur={(e) => e.target && myOnChange(e.target.value)}
|
|
939
|
+
>
|
|
940
|
+
{field.options.map((o, ix) =>
|
|
941
|
+
o.name && o.label ? (
|
|
942
|
+
<option key={ix} value={o.name}>
|
|
943
|
+
{o.label}
|
|
944
|
+
</option>
|
|
945
|
+
) : (
|
|
946
|
+
<option key={ix}>{o}</option>
|
|
947
|
+
)
|
|
948
|
+
)}
|
|
949
|
+
</select>
|
|
950
|
+
);
|
|
951
|
+
},
|
|
918
952
|
btn_select: () => (
|
|
919
953
|
<div className="btn-group w-100" role="group">
|
|
920
954
|
{field.options.map((o, ix) => (
|
|
@@ -1012,8 +1046,15 @@ export /**
|
|
|
1012
1046
|
* @returns {table}
|
|
1013
1047
|
*/
|
|
1014
1048
|
const SettingsFromFields =
|
|
1015
|
-
(
|
|
1049
|
+
(fieldsIn, opts = {}) =>
|
|
1016
1050
|
() => {
|
|
1051
|
+
const fields = [...fieldsIn];
|
|
1052
|
+
if (opts.additionalFieldsOptionKey) {
|
|
1053
|
+
const options = React.useContext(optionsCtx);
|
|
1054
|
+
|
|
1055
|
+
const addFields = options[opts.additionalFieldsOptionKey];
|
|
1056
|
+
fields.push(...(addFields || []));
|
|
1057
|
+
}
|
|
1017
1058
|
const node = useNode((node) => {
|
|
1018
1059
|
const ps = {};
|
|
1019
1060
|
fields.forEach((f) => {
|
|
@@ -1245,19 +1286,27 @@ const ButtonOrLinkSettingsRows = ({
|
|
|
1245
1286
|
<option value={addBtnClass("btn-secondary")}>Secondary button</option>
|
|
1246
1287
|
<option value={addBtnClass("btn-success")}>Success button</option>
|
|
1247
1288
|
<option value={addBtnClass("btn-danger")}>Danger button</option>
|
|
1289
|
+
<option value={addBtnClass("btn-warning")}>Warning button</option>
|
|
1290
|
+
<option value={addBtnClass("btn-info")}>Info button</option>
|
|
1248
1291
|
<option value={addBtnClass("btn-outline-primary")}>
|
|
1249
1292
|
Primary outline button
|
|
1250
1293
|
</option>
|
|
1251
1294
|
<option value={addBtnClass("btn-outline-secondary")}>
|
|
1252
1295
|
Secondary outline button
|
|
1253
1296
|
</option>
|
|
1297
|
+
<option value={addBtnClass("btn-outline-warning")}>
|
|
1298
|
+
Warning outline button
|
|
1299
|
+
</option>{" "}
|
|
1300
|
+
<option value={addBtnClass("btn-outline-info")}>
|
|
1301
|
+
Info outline button
|
|
1302
|
+
</option>
|
|
1254
1303
|
<option value={addBtnClass("btn-custom-color")}>
|
|
1255
1304
|
Button custom color
|
|
1256
1305
|
</option>
|
|
1257
1306
|
{!linkFirst ? (
|
|
1258
1307
|
<option value={addBtnClass("btn-link")}>Link</option>
|
|
1259
1308
|
) : null}
|
|
1260
|
-
{!linkFirst ? (
|
|
1309
|
+
{!linkFirst && allowRunOnLoad ? (
|
|
1261
1310
|
<option value="on_page_load">Run on Page Load</option>
|
|
1262
1311
|
) : null}
|
|
1263
1312
|
</select>
|
|
@@ -1277,6 +1326,7 @@ const ButtonOrLinkSettingsRows = ({
|
|
|
1277
1326
|
<option value="">Standard</option>
|
|
1278
1327
|
<option value="btn-lg">Large</option>
|
|
1279
1328
|
<option value="btn-sm">Small</option>
|
|
1329
|
+
<option value="btn-sm btn-xs">Extra Small</option>
|
|
1280
1330
|
<option value="btn-block">Block</option>
|
|
1281
1331
|
<option value="btn-block btn-lg">Large block</option>
|
|
1282
1332
|
</select>
|
|
@@ -1439,22 +1489,6 @@ const Tooltip = ({ children }) => {
|
|
|
1439
1489
|
);
|
|
1440
1490
|
};
|
|
1441
1491
|
|
|
1442
|
-
export const buildTableCaches = (allTables) => {
|
|
1443
|
-
const tableIdCache = {};
|
|
1444
|
-
const tableNameCache = {};
|
|
1445
|
-
const fieldCache = {};
|
|
1446
|
-
for (const table of allTables) {
|
|
1447
|
-
tableIdCache[table.id] = table;
|
|
1448
|
-
tableNameCache[table.name] = table;
|
|
1449
|
-
for (const field of table.foreign_keys) {
|
|
1450
|
-
if (!fieldCache[field.reftable_name])
|
|
1451
|
-
fieldCache[field.reftable_name] = [];
|
|
1452
|
-
fieldCache[field.reftable_name].push(field);
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
return { tableIdCache, tableNameCache, fieldCache };
|
|
1456
|
-
};
|
|
1457
|
-
|
|
1458
1492
|
export const removeWhitespaces = (str) => {
|
|
1459
1493
|
return str.replace(/\s/g, "X");
|
|
1460
1494
|
};
|
|
@@ -1497,79 +1531,145 @@ export const buildBootstrapOptions = (values) => {
|
|
|
1497
1531
|
));
|
|
1498
1532
|
};
|
|
1499
1533
|
|
|
1500
|
-
export const
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
}
|
|
1505
|
-
|
|
1506
|
-
const caches = buildTableCaches(tables);
|
|
1507
|
-
const finder = new relationHelpers.RelationsFinder(
|
|
1508
|
-
caches,
|
|
1509
|
-
views,
|
|
1510
|
-
max_relations_layer_depth || 6
|
|
1511
|
-
);
|
|
1512
|
-
return { caches, finder };
|
|
1513
|
-
} else return { caches: null, finder: null };
|
|
1534
|
+
export const arrayChunks = (xs, n) => {
|
|
1535
|
+
const arrayOfArrays = [];
|
|
1536
|
+
for (var i = 0; i < bigarray.length; i += n) {
|
|
1537
|
+
arrayOfArrays.push(bigarray.slice(i, i + n));
|
|
1538
|
+
}
|
|
1539
|
+
return arrayOfArrays;
|
|
1514
1540
|
};
|
|
1515
1541
|
|
|
1516
1542
|
/**
|
|
1517
|
-
* @param {string[]}
|
|
1543
|
+
* @param {string[]} relations
|
|
1518
1544
|
* @param {string} sourceTbl name of the topview table
|
|
1519
1545
|
* @returns either a same table relation, a parent relation, a child relation, or the first relation
|
|
1520
1546
|
*/
|
|
1521
|
-
export const initialRelation = (
|
|
1547
|
+
export const initialRelation = (relations) => {
|
|
1522
1548
|
let sameTblRel = null;
|
|
1523
1549
|
let parentRel = null;
|
|
1524
1550
|
let childRel = null;
|
|
1525
|
-
for (const
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
const lastToken = tokens[tokens.length - 1];
|
|
1538
|
-
if (
|
|
1539
|
-
lastToken.indexOf("$") > 0 &&
|
|
1540
|
-
(!childRel || childRel.split(".").length > tokens.length)
|
|
1541
|
-
)
|
|
1542
|
-
childRel = path;
|
|
1543
|
-
}
|
|
1551
|
+
for (const relation of relations) {
|
|
1552
|
+
switch (relation.type) {
|
|
1553
|
+
case RelationType.OWN:
|
|
1554
|
+
sameTblRel = relation;
|
|
1555
|
+
break;
|
|
1556
|
+
case RelationType.PARENT_SHOW:
|
|
1557
|
+
parentRel = relation;
|
|
1558
|
+
break;
|
|
1559
|
+
case RelationType.CHILD_LIST:
|
|
1560
|
+
case RelationType.ONE_TO_ONE_SHOW:
|
|
1561
|
+
childRel = relation;
|
|
1562
|
+
break;
|
|
1544
1563
|
}
|
|
1545
1564
|
}
|
|
1546
|
-
return sameTblRel || parentRel || childRel ||
|
|
1565
|
+
return sameTblRel || parentRel || childRel || relations[0];
|
|
1547
1566
|
};
|
|
1548
1567
|
|
|
1549
1568
|
/**
|
|
1550
|
-
*
|
|
1551
|
-
*
|
|
1552
|
-
* @param
|
|
1553
|
-
* @
|
|
1554
|
-
* @param {any} options builder options
|
|
1555
|
-
* @param {RelationsFinder} finder
|
|
1556
|
-
* @param {string} viewname subview name
|
|
1569
|
+
* builder intern path method
|
|
1570
|
+
* @param path
|
|
1571
|
+
* @param tableNameCache
|
|
1572
|
+
* @returns
|
|
1557
1573
|
*/
|
|
1558
|
-
export const
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
)
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
+
export const buildRelationArray = (path, tableNameCache) => {
|
|
1575
|
+
if (path === ".")
|
|
1576
|
+
return [{ type: "Independent", table: "None (no relation)" }];
|
|
1577
|
+
const tokens = path.split(".");
|
|
1578
|
+
if (tokens.length === 2)
|
|
1579
|
+
return [{ type: "Own", table: `${tokens[1]} (same table)` }];
|
|
1580
|
+
else if (tokens.length >= 3) {
|
|
1581
|
+
const result = [];
|
|
1582
|
+
let currentTbl = tokens[1];
|
|
1583
|
+
for (const relation of tokens.slice(2)) {
|
|
1584
|
+
if (relation.indexOf("$") > 0) {
|
|
1585
|
+
const [inboundTbl, inboundKey] = relation.split("$");
|
|
1586
|
+
result.push({ type: "Inbound", table: inboundTbl, key: inboundKey });
|
|
1587
|
+
currentTbl = inboundTbl;
|
|
1588
|
+
} else {
|
|
1589
|
+
const srcTbl = tableNameCache[currentTbl];
|
|
1590
|
+
const fk = srcTbl.foreign_keys.find((fk) => fk.name === relation);
|
|
1591
|
+
if (fk) {
|
|
1592
|
+
const targetTbl = tableNameCache[fk.reftable_name];
|
|
1593
|
+
result.push({
|
|
1594
|
+
type: "Foreign",
|
|
1595
|
+
table: targetTbl.name,
|
|
1596
|
+
key: relation,
|
|
1597
|
+
});
|
|
1598
|
+
currentTbl = targetTbl.name;
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
return result;
|
|
1603
|
+
}
|
|
1604
|
+
};
|
|
1605
|
+
|
|
1606
|
+
export const buildLayers = (relations, tableName, tableNameCache) => {
|
|
1607
|
+
const result = { table: tableName, inboundKeys: [], fkeys: [] };
|
|
1608
|
+
for (const relation of relations) {
|
|
1609
|
+
const relType = relation.type;
|
|
1610
|
+
let currentLevel = result;
|
|
1611
|
+
if (relType === RelationType.INDEPENDENT) {
|
|
1612
|
+
currentLevel.fkeys.push({
|
|
1613
|
+
name: "none (no relation)",
|
|
1614
|
+
table: "",
|
|
1615
|
+
inboundKeys: [],
|
|
1616
|
+
fkeys: [],
|
|
1617
|
+
relPath: relation.relationString,
|
|
1618
|
+
});
|
|
1619
|
+
} else if (relType === RelationType.OWN) {
|
|
1620
|
+
currentLevel.fkeys.push({
|
|
1621
|
+
name: "same table",
|
|
1622
|
+
table: relation.targetTblName,
|
|
1623
|
+
inboundKeys: [],
|
|
1624
|
+
fkeys: [],
|
|
1625
|
+
relPath: relation.relationString,
|
|
1626
|
+
});
|
|
1627
|
+
} else {
|
|
1628
|
+
let currentTbl = relation.sourceTblName;
|
|
1629
|
+
for (const pathElement of relation.path) {
|
|
1630
|
+
if (pathElement.inboundKey) {
|
|
1631
|
+
currentTbl = pathElement.table;
|
|
1632
|
+
const existing = currentLevel.inboundKeys.find(
|
|
1633
|
+
(key) =>
|
|
1634
|
+
key.name === pathElement.inboundKey && key.table === currentTbl
|
|
1635
|
+
);
|
|
1636
|
+
if (existing) {
|
|
1637
|
+
currentLevel = existing;
|
|
1638
|
+
} else {
|
|
1639
|
+
const nextLevel = {
|
|
1640
|
+
name: pathElement.inboundKey,
|
|
1641
|
+
table: currentTbl,
|
|
1642
|
+
inboundKeys: [],
|
|
1643
|
+
fkeys: [],
|
|
1644
|
+
};
|
|
1645
|
+
currentLevel.inboundKeys.push(nextLevel);
|
|
1646
|
+
currentLevel = nextLevel;
|
|
1647
|
+
}
|
|
1648
|
+
} else if (pathElement.fkey) {
|
|
1649
|
+
const tblObj = tableNameCache[currentTbl];
|
|
1650
|
+
const fkey = tblObj.foreign_keys.find(
|
|
1651
|
+
(key) => key.name === pathElement.fkey
|
|
1652
|
+
);
|
|
1653
|
+
currentTbl = fkey.reftable_name;
|
|
1654
|
+
const existing = currentLevel.fkeys.find(
|
|
1655
|
+
(key) => key.name === pathElement.fkey
|
|
1656
|
+
);
|
|
1657
|
+
if (existing) {
|
|
1658
|
+
currentLevel = existing;
|
|
1659
|
+
} else {
|
|
1660
|
+
const nextLevel = {
|
|
1661
|
+
name: pathElement.fkey,
|
|
1662
|
+
table: currentTbl,
|
|
1663
|
+
inboundKeys: [],
|
|
1664
|
+
fkeys: [],
|
|
1665
|
+
};
|
|
1666
|
+
currentLevel.fkeys.push(nextLevel);
|
|
1667
|
+
currentLevel = nextLevel;
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
currentLevel.relPath = relation.relationString;
|
|
1574
1673
|
}
|
|
1674
|
+
return result;
|
|
1575
1675
|
};
|
|
@@ -12,6 +12,8 @@ import { Empty } from "./elements/Empty";
|
|
|
12
12
|
import { Columns, ntimes, sum } from "./elements/Columns";
|
|
13
13
|
import { JoinField } from "./elements/JoinField";
|
|
14
14
|
import { Tabs } from "./elements/Tabs";
|
|
15
|
+
import { ListColumns } from "./elements/ListColumns";
|
|
16
|
+
import { ListColumn } from "./elements/ListColumn";
|
|
15
17
|
import { Table } from "./elements/Table";
|
|
16
18
|
import { Aggregation } from "./elements/Aggregation";
|
|
17
19
|
import { LineBreak } from "./elements/LineBreak";
|
|
@@ -76,6 +78,8 @@ const allElements = [
|
|
|
76
78
|
DropMenu,
|
|
77
79
|
Page,
|
|
78
80
|
Table,
|
|
81
|
+
ListColumn,
|
|
82
|
+
ListColumns,
|
|
79
83
|
];
|
|
80
84
|
|
|
81
85
|
export /**
|
|
@@ -88,7 +92,7 @@ export /**
|
|
|
88
92
|
* @subcategory components
|
|
89
93
|
* @namespace
|
|
90
94
|
*/
|
|
91
|
-
const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
|
|
95
|
+
const layoutToNodes = (layout, query, actions, parent = "ROOT", options) => {
|
|
92
96
|
//console.log("layoutToNodes", JSON.stringify(layout));
|
|
93
97
|
/**
|
|
94
98
|
* @param {object} segment
|
|
@@ -129,7 +133,6 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
|
|
|
129
133
|
);
|
|
130
134
|
else return <MatchElement key={ix} {...props} />;
|
|
131
135
|
}
|
|
132
|
-
|
|
133
136
|
if (segment.type === "blank") {
|
|
134
137
|
return (
|
|
135
138
|
<Text
|
|
@@ -177,6 +180,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
|
|
|
177
180
|
step_only_ifs={segment.step_only_ifs || ""}
|
|
178
181
|
step_action_names={segment.step_action_names || ""}
|
|
179
182
|
confirm={segment.confirm}
|
|
183
|
+
spinner={segment.spinner}
|
|
180
184
|
configuration={segment.configuration || {}}
|
|
181
185
|
block={segment.block || false}
|
|
182
186
|
minRole={segment.minRole || 10}
|
|
@@ -200,6 +204,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
|
|
|
200
204
|
minHeight={segment.minHeight}
|
|
201
205
|
height={segment.height}
|
|
202
206
|
width={segment.width}
|
|
207
|
+
click_action={segment.click_action}
|
|
203
208
|
url={segment.url}
|
|
204
209
|
hoverColor={segment.hoverColor}
|
|
205
210
|
minHeightUnit={segment.minHeightUnit || "px"}
|
|
@@ -253,10 +258,12 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
|
|
|
253
258
|
<Tabs
|
|
254
259
|
key={ix}
|
|
255
260
|
titles={segment.titles}
|
|
261
|
+
showif={segment.showif}
|
|
256
262
|
ntabs={segment.ntabs}
|
|
257
263
|
independent={segment.independent}
|
|
258
264
|
startClosed={segment.startClosed}
|
|
259
265
|
deeplink={segment.deeplink}
|
|
266
|
+
acc_init_opens={segment.acc_init_opens}
|
|
260
267
|
disable_inactive={segment.disable_inactive}
|
|
261
268
|
serverRendered={segment.serverRendered}
|
|
262
269
|
tabId={segment.tabId}
|
|
@@ -282,6 +289,27 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
|
|
|
282
289
|
)}
|
|
283
290
|
/>
|
|
284
291
|
);
|
|
292
|
+
} else if (segment.besides && segment.list_columns) {
|
|
293
|
+
const addFields = options.additionalColumnFields;
|
|
294
|
+
|
|
295
|
+
return segment.besides.map((col, jx) => {
|
|
296
|
+
const addProps = {};
|
|
297
|
+
(addFields || []).forEach((f) => {
|
|
298
|
+
addProps[f.name] = col[f.name];
|
|
299
|
+
});
|
|
300
|
+
return (
|
|
301
|
+
<ListColumn
|
|
302
|
+
key={jx}
|
|
303
|
+
alignment={col.alignment}
|
|
304
|
+
header_label={col.header_label}
|
|
305
|
+
col_width={col.col_width}
|
|
306
|
+
showif={col.showif}
|
|
307
|
+
col_width_units={col.col_width_units}
|
|
308
|
+
contents={toTag(col.contents)}
|
|
309
|
+
{...addProps}
|
|
310
|
+
></ListColumn>
|
|
311
|
+
);
|
|
312
|
+
});
|
|
285
313
|
} else if (segment.besides) {
|
|
286
314
|
return (
|
|
287
315
|
<Columns
|
|
@@ -316,7 +344,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
|
|
|
316
344
|
segment.above.forEach((child) => {
|
|
317
345
|
if (child) go(child, parent);
|
|
318
346
|
});
|
|
319
|
-
} else if (segment.besides) {
|
|
347
|
+
} else if (segment.besides && !segment.list_columns) {
|
|
320
348
|
const node = query
|
|
321
349
|
.parseReactElement(
|
|
322
350
|
<Columns
|
|
@@ -338,7 +366,13 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
|
|
|
338
366
|
actions.addNodeTree(node, parent);
|
|
339
367
|
} else {
|
|
340
368
|
const tag = toTag(segment);
|
|
341
|
-
if (tag) {
|
|
369
|
+
if (Array.isArray(tag)) {
|
|
370
|
+
tag.forEach((t) => {
|
|
371
|
+
const node = query.parseReactElement(t).toNodeTree();
|
|
372
|
+
//console.log("other", node);
|
|
373
|
+
actions.addNodeTree(node, parent);
|
|
374
|
+
});
|
|
375
|
+
} else if (tag) {
|
|
342
376
|
const node = query.parseReactElement(tag).toNodeTree();
|
|
343
377
|
//console.log("other", node);
|
|
344
378
|
actions.addNodeTree(node, parent);
|
|
@@ -362,7 +396,7 @@ export /**
|
|
|
362
396
|
* @subcategory components
|
|
363
397
|
* @namespace
|
|
364
398
|
*/
|
|
365
|
-
const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
|
|
399
|
+
const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
366
400
|
//console.log(JSON.stringify(nodes, null, 2));
|
|
367
401
|
var columns = [];
|
|
368
402
|
/**
|
|
@@ -414,10 +448,33 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
|
|
|
414
448
|
related.fields.forEach((f) => {
|
|
415
449
|
c[f.column_name || f.name || f] = node.props[f.name || f];
|
|
416
450
|
});
|
|
451
|
+
if (s.isFormula) c.isFormula = s.isFormula;
|
|
417
452
|
columns.push(c);
|
|
418
453
|
}
|
|
419
454
|
return s;
|
|
420
455
|
}
|
|
456
|
+
if (node.displayName === ListColumns.craft.displayName) {
|
|
457
|
+
return {
|
|
458
|
+
besides: node.nodes.map((nm) => go(nodes[nm])),
|
|
459
|
+
list_columns: true,
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
if (node.displayName === ListColumn.craft.displayName) {
|
|
463
|
+
const contents = go(nodes[node.linkedNodes.listcol]);
|
|
464
|
+
const addFields = options.additionalColumnFields;
|
|
465
|
+
const lc = {
|
|
466
|
+
contents,
|
|
467
|
+
col_width: node.props.col_width,
|
|
468
|
+
col_width_units: node.props.col_width_units,
|
|
469
|
+
alignment: node.props.alignment,
|
|
470
|
+
header_label: node.props.header_label,
|
|
471
|
+
showif: node.props.showif,
|
|
472
|
+
};
|
|
473
|
+
(addFields || []).forEach((f) => {
|
|
474
|
+
lc[f.name] = node.props[f.name];
|
|
475
|
+
});
|
|
476
|
+
return lc;
|
|
477
|
+
}
|
|
421
478
|
if (node.isCanvas) {
|
|
422
479
|
if (node.displayName === Container.craft.displayName)
|
|
423
480
|
return {
|
|
@@ -457,6 +514,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
|
|
|
457
514
|
gradStartColor: node.props.gradStartColor,
|
|
458
515
|
gradEndColor: node.props.gradEndColor,
|
|
459
516
|
gradDirection: node.props.gradDirection,
|
|
517
|
+
click_action: node.props.click_action,
|
|
460
518
|
rotate: node.props.rotate,
|
|
461
519
|
style: node.props.style,
|
|
462
520
|
};
|
|
@@ -529,10 +587,12 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
|
|
|
529
587
|
type: "tabs",
|
|
530
588
|
contents,
|
|
531
589
|
titles: node.props.titles,
|
|
590
|
+
showif: node.props.showif,
|
|
532
591
|
tabsStyle: node.props.tabsStyle,
|
|
533
592
|
field: node.props.field,
|
|
534
593
|
independent: node.props.independent,
|
|
535
594
|
startClosed: node.props.startClosed,
|
|
595
|
+
acc_init_opens: node.props.acc_init_opens,
|
|
536
596
|
deeplink: node.props.deeplink,
|
|
537
597
|
disable_inactive: node.props.disable_inactive,
|
|
538
598
|
serverRendered: node.props.serverRendered,
|
|
@@ -573,6 +633,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
|
|
|
573
633
|
action_textcol: node.props.action_textcol,
|
|
574
634
|
minRole: node.props.minRole,
|
|
575
635
|
confirm: node.props.confirm,
|
|
636
|
+
spinner: node.props.spinner,
|
|
576
637
|
nsteps: node.props.nsteps,
|
|
577
638
|
step_only_ifs: node.props.step_only_ifs,
|
|
578
639
|
step_action_names: node.props.step_action_names,
|
|
@@ -585,6 +646,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
|
|
|
585
646
|
block: node.props.block,
|
|
586
647
|
configuration: node.props.configuration,
|
|
587
648
|
confirm: node.props.confirm,
|
|
649
|
+
spinner: node.props.spinner,
|
|
588
650
|
action_name: node.props.name,
|
|
589
651
|
...(node.props.name !== "Clear" && node.props.action_row_variable
|
|
590
652
|
? {
|