@saltcorn/builder 0.9.4-beta.9 → 0.9.5-beta.0

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.
@@ -19,6 +19,7 @@ import faIcons from "./faicons";
19
19
  import { Columns, ntimes } from "./Columns";
20
20
  import Tippy from "@tippyjs/react";
21
21
  import { RelationType } from "@saltcorn/common-code";
22
+ import Select from "react-select";
22
23
 
23
24
  export const DynamicFontAwesomeIcon = ({ icon, className }) => {
24
25
  if (!icon) return null;
@@ -139,7 +140,7 @@ export /**
139
140
  */
140
141
  const OrFormula = ({ setProp, isFormula, node, nodekey, children }) => {
141
142
  const { mode } = React.useContext(optionsCtx);
142
-
143
+ const allowFormula = mode === "show" || mode === "list";
143
144
  /**
144
145
  * @returns {void}
145
146
  */
@@ -160,14 +161,14 @@ const OrFormula = ({ setProp, isFormula, node, nodekey, children }) => {
160
161
  });
161
162
  };
162
163
  let errorString = false;
163
- if (mode === "show" && isFormula[nodekey]) {
164
+ if (allowFormula && isFormula[nodekey]) {
164
165
  try {
165
166
  Function("return " + node[nodekey]);
166
167
  } catch (error) {
167
168
  errorString = error.message;
168
169
  }
169
170
  }
170
- return mode !== "show" ? (
171
+ return !allowFormula ? (
171
172
  children
172
173
  ) : (
173
174
  <Fragment>
@@ -492,6 +493,7 @@ export const fetchViewPreview =
492
493
  };
493
494
  let viewname,
494
495
  body = configuration ? { ...configuration } : {};
496
+ if (!view) return "";
495
497
  if (view.includes(":")) {
496
498
  const [prefix, rest] = view.split(":");
497
499
  const tokens = rest.split(".");
@@ -902,24 +904,51 @@ const ConfigField = ({
902
904
  spellCheck={false}
903
905
  />
904
906
  ),
905
- select: () => (
906
- <select
907
- className="form-control form-select"
908
- value={value || ""}
909
- onChange={(e) => e.target && myOnChange(e.target.value)}
910
- onBlur={(e) => e.target && myOnChange(e.target.value)}
911
- >
912
- {field.options.map((o, ix) =>
913
- o.name && o.label ? (
914
- <option key={ix} value={o.name}>
915
- {o.label}
916
- </option>
917
- ) : (
918
- <option key={ix}>{o}</option>
919
- )
920
- )}
921
- </select>
922
- ),
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
+ },
923
952
  btn_select: () => (
924
953
  <div className="btn-group w-100" role="group">
925
954
  {field.options.map((o, ix) => (
@@ -1017,8 +1046,15 @@ export /**
1017
1046
  * @returns {table}
1018
1047
  */
1019
1048
  const SettingsFromFields =
1020
- (fields, opts = {}) =>
1049
+ (fieldsIn, opts = {}) =>
1021
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
+ }
1022
1058
  const node = useNode((node) => {
1023
1059
  const ps = {};
1024
1060
  fields.forEach((f) => {
@@ -1258,9 +1294,12 @@ const ButtonOrLinkSettingsRows = ({
1258
1294
  <option value={addBtnClass("btn-outline-secondary")}>
1259
1295
  Secondary outline button
1260
1296
  </option>
1297
+ <option value={addBtnClass("btn-outline-danger")}>
1298
+ Danger outline button
1299
+ </option>
1261
1300
  <option value={addBtnClass("btn-outline-warning")}>
1262
1301
  Warning outline button
1263
- </option>{" "}
1302
+ </option>
1264
1303
  <option value={addBtnClass("btn-outline-info")}>
1265
1304
  Info outline button
1266
1305
  </option>
@@ -1270,7 +1309,7 @@ const ButtonOrLinkSettingsRows = ({
1270
1309
  {!linkFirst ? (
1271
1310
  <option value={addBtnClass("btn-link")}>Link</option>
1272
1311
  ) : null}
1273
- {!linkFirst ? (
1312
+ {!linkFirst && allowRunOnLoad ? (
1274
1313
  <option value="on_page_load">Run on Page Load</option>
1275
1314
  ) : null}
1276
1315
  </select>
@@ -1290,6 +1329,7 @@ const ButtonOrLinkSettingsRows = ({
1290
1329
  <option value="">Standard</option>
1291
1330
  <option value="btn-lg">Large</option>
1292
1331
  <option value="btn-sm">Small</option>
1332
+ <option value="btn-sm btn-xs">Extra Small</option>
1293
1333
  <option value="btn-block">Block</option>
1294
1334
  <option value="btn-block btn-lg">Large block</option>
1295
1335
  </select>
@@ -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"}
@@ -258,6 +263,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
258
263
  independent={segment.independent}
259
264
  startClosed={segment.startClosed}
260
265
  deeplink={segment.deeplink}
266
+ acc_init_opens={segment.acc_init_opens}
261
267
  disable_inactive={segment.disable_inactive}
262
268
  serverRendered={segment.serverRendered}
263
269
  tabId={segment.tabId}
@@ -283,6 +289,27 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
283
289
  )}
284
290
  />
285
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
+ });
286
313
  } else if (segment.besides) {
287
314
  return (
288
315
  <Columns
@@ -317,7 +344,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
317
344
  segment.above.forEach((child) => {
318
345
  if (child) go(child, parent);
319
346
  });
320
- } else if (segment.besides) {
347
+ } else if (segment.besides && !segment.list_columns) {
321
348
  const node = query
322
349
  .parseReactElement(
323
350
  <Columns
@@ -339,7 +366,13 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
339
366
  actions.addNodeTree(node, parent);
340
367
  } else {
341
368
  const tag = toTag(segment);
342
- 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) {
343
376
  const node = query.parseReactElement(tag).toNodeTree();
344
377
  //console.log("other", node);
345
378
  actions.addNodeTree(node, parent);
@@ -363,7 +396,7 @@ export /**
363
396
  * @subcategory components
364
397
  * @namespace
365
398
  */
366
- const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
399
+ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
367
400
  //console.log(JSON.stringify(nodes, null, 2));
368
401
  var columns = [];
369
402
  /**
@@ -415,10 +448,33 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
415
448
  related.fields.forEach((f) => {
416
449
  c[f.column_name || f.name || f] = node.props[f.name || f];
417
450
  });
451
+ if (s.isFormula) c.isFormula = s.isFormula;
418
452
  columns.push(c);
419
453
  }
420
454
  return s;
421
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
+ }
422
478
  if (node.isCanvas) {
423
479
  if (node.displayName === Container.craft.displayName)
424
480
  return {
@@ -458,6 +514,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
458
514
  gradStartColor: node.props.gradStartColor,
459
515
  gradEndColor: node.props.gradEndColor,
460
516
  gradDirection: node.props.gradDirection,
517
+ click_action: node.props.click_action,
461
518
  rotate: node.props.rotate,
462
519
  style: node.props.style,
463
520
  };
@@ -535,6 +592,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
535
592
  field: node.props.field,
536
593
  independent: node.props.independent,
537
594
  startClosed: node.props.startClosed,
595
+ acc_init_opens: node.props.acc_init_opens,
538
596
  deeplink: node.props.deeplink,
539
597
  disable_inactive: node.props.disable_inactive,
540
598
  serverRendered: node.props.serverRendered,
@@ -575,6 +633,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
575
633
  action_textcol: node.props.action_textcol,
576
634
  minRole: node.props.minRole,
577
635
  confirm: node.props.confirm,
636
+ spinner: node.props.spinner,
578
637
  nsteps: node.props.nsteps,
579
638
  step_only_ifs: node.props.step_only_ifs,
580
639
  step_action_names: node.props.step_action_names,
@@ -587,6 +646,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
587
646
  block: node.props.block,
588
647
  configuration: node.props.configuration,
589
648
  confirm: node.props.confirm,
649
+ spinner: node.props.spinner,
590
650
  action_name: node.props.name,
591
651
  ...(node.props.name !== "Clear" && node.props.action_row_variable
592
652
  ? {
@@ -59,6 +59,7 @@ const doTest = (
59
59
  views: views,
60
60
  tableName: tableName,
61
61
  roles: [],
62
+ inJestTestingMode: true,
62
63
  excluded_subview_templates: excludedTemplates,
63
64
  // relationsCtx part
64
65
  relationsCache: relationsCache,