@saltcorn/builder 0.9.4-beta.14 → 0.9.4-beta.15

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.
@@ -24,6 +24,7 @@ import {
24
24
 
25
25
  import { RelationBadges } from "./RelationBadges";
26
26
  import { RelationOnDemandPicker } from "./RelationOnDemandPicker";
27
+ import Select from "react-select";
27
28
 
28
29
  import {
29
30
  RelationsFinder,
@@ -201,8 +202,8 @@ const ViewLinkSettings = () => {
201
202
  });
202
203
  }
203
204
  const set_view_name = (e) => {
204
- if (e.target) {
205
- const target_value = e.target.value;
205
+ if (e?.target?.value || e?.value) {
206
+ const target_value = e.target?.value || e.value;
206
207
  if (target_value !== use_view_name) {
207
208
  const newRelations = finder.findRelations(
208
209
  tableName,
@@ -236,6 +237,11 @@ const ViewLinkSettings = () => {
236
237
  };
237
238
  const helpContext = { view_name: use_view_name };
238
239
  if (tableName) helpContext.srcTable = tableName;
240
+ const viewOptions = options.views.map(({ name, label }) => ({
241
+ label,
242
+ value: name,
243
+ }));
244
+ const selectedView = viewOptions.find((v) => v.value === use_view_name);
239
245
  return (
240
246
  <div>
241
247
  <table className="w-100">
@@ -243,18 +249,18 @@ const ViewLinkSettings = () => {
243
249
  <tr>
244
250
  <td colSpan="2">
245
251
  <label>View to link to</label>
246
- <select
247
- value={use_view_name}
248
- className="form-control form-select"
249
- onChange={set_view_name}
250
- onBlur={set_view_name}
251
- >
252
- {options.views.map((f, ix) => (
253
- <option key={ix} value={f.name}>
254
- {f.label}
255
- </option>
256
- ))}
257
- </select>
252
+ {options.inJestTestingMode ? null : (
253
+ <Select
254
+ options={viewOptions}
255
+ value={selectedView}
256
+ onChange={set_view_name}
257
+ onBlur={set_view_name}
258
+ menuPortalTarget={document.body}
259
+ styles={{
260
+ menuPortal: (base) => ({ ...base, zIndex: 19999 }),
261
+ }}
262
+ ></Select>
263
+ )}
258
264
  </td>
259
265
  </tr>
260
266
  <tr>
@@ -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>
@@ -902,24 +903,51 @@ const ConfigField = ({
902
903
  spellCheck={false}
903
904
  />
904
905
  ),
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
- ),
906
+ select: () => {
907
+ if (field.class?.includes?.("selectizable")) {
908
+ const seloptions = field.options.map((o, ix) =>
909
+ o.name && o.label
910
+ ? { value: o.name, label: o.label }
911
+ : { value: o, label: o }
912
+ );
913
+ return (
914
+ <Select
915
+ options={seloptions}
916
+ value={seloptions.find((so) => value === so.value)}
917
+ onChange={(e) =>
918
+ (e.name && myOnChange(e.name)) ||
919
+ (e.value && myOnChange(e.value)) ||
920
+ (typeof e === "string" && myOnChange(e))
921
+ }
922
+ onBlur={(e) =>
923
+ (e.name && myOnChange(e.name)) ||
924
+ (e.value && myOnChange(e.value)) ||
925
+ (typeof e === "string" && myOnChange(e))
926
+ }
927
+ menuPortalTarget={document.body}
928
+ styles={{ menuPortal: (base) => ({ ...base, zIndex: 19999 }) }}
929
+ ></Select>
930
+ );
931
+ } else
932
+ return (
933
+ <select
934
+ className="form-control form-select"
935
+ value={value || ""}
936
+ onChange={(e) => e.target && myOnChange(e.target.value)}
937
+ onBlur={(e) => e.target && myOnChange(e.target.value)}
938
+ >
939
+ {field.options.map((o, ix) =>
940
+ o.name && o.label ? (
941
+ <option key={ix} value={o.name}>
942
+ {o.label}
943
+ </option>
944
+ ) : (
945
+ <option key={ix}>{o}</option>
946
+ )
947
+ )}
948
+ </select>
949
+ );
950
+ },
923
951
  btn_select: () => (
924
952
  <div className="btn-group w-100" role="group">
925
953
  {field.options.map((o, ix) => (
@@ -1017,8 +1045,15 @@ export /**
1017
1045
  * @returns {table}
1018
1046
  */
1019
1047
  const SettingsFromFields =
1020
- (fields, opts = {}) =>
1048
+ (fieldsIn, opts = {}) =>
1021
1049
  () => {
1050
+ const fields = [...fieldsIn];
1051
+ if (opts.additionalFieldsOptionKey) {
1052
+ const options = React.useContext(optionsCtx);
1053
+
1054
+ const addFields = options[opts.additionalFieldsOptionKey];
1055
+ fields.push(...(addFields || []));
1056
+ }
1022
1057
  const node = useNode((node) => {
1023
1058
  const ps = {};
1024
1059
  fields.forEach((f) => {
@@ -1290,6 +1325,7 @@ const ButtonOrLinkSettingsRows = ({
1290
1325
  <option value="">Standard</option>
1291
1326
  <option value="btn-lg">Large</option>
1292
1327
  <option value="btn-sm">Small</option>
1328
+ <option value="btn-sm btn-xs">Extra Small</option>
1293
1329
  <option value="btn-block">Block</option>
1294
1330
  <option value="btn-block btn-lg">Large block</option>
1295
1331
  </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
@@ -285,6 +288,27 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
285
288
  )}
286
289
  />
287
290
  );
291
+ } else if (segment.besides && segment.list_columns) {
292
+ const addFields = options.additionalColumnFields;
293
+
294
+ return segment.besides.map((col, jx) => {
295
+ const addProps = {};
296
+ (addFields || []).forEach((f) => {
297
+ addProps[f.name] = col[f.name];
298
+ });
299
+ return (
300
+ <ListColumn
301
+ key={jx}
302
+ alignment={col.alignment}
303
+ header_label={col.header_label}
304
+ col_width={col.col_width}
305
+ showif={col.showif}
306
+ col_width_units={col.col_width_units}
307
+ contents={toTag(col.contents)}
308
+ {...addProps}
309
+ ></ListColumn>
310
+ );
311
+ });
288
312
  } else if (segment.besides) {
289
313
  return (
290
314
  <Columns
@@ -319,7 +343,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
319
343
  segment.above.forEach((child) => {
320
344
  if (child) go(child, parent);
321
345
  });
322
- } else if (segment.besides) {
346
+ } else if (segment.besides && !segment.list_columns) {
323
347
  const node = query
324
348
  .parseReactElement(
325
349
  <Columns
@@ -341,7 +365,13 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
341
365
  actions.addNodeTree(node, parent);
342
366
  } else {
343
367
  const tag = toTag(segment);
344
- if (tag) {
368
+ if (Array.isArray(tag)) {
369
+ tag.forEach((t) => {
370
+ const node = query.parseReactElement(t).toNodeTree();
371
+ //console.log("other", node);
372
+ actions.addNodeTree(node, parent);
373
+ });
374
+ } else if (tag) {
345
375
  const node = query.parseReactElement(tag).toNodeTree();
346
376
  //console.log("other", node);
347
377
  actions.addNodeTree(node, parent);
@@ -365,7 +395,7 @@ export /**
365
395
  * @subcategory components
366
396
  * @namespace
367
397
  */
368
- const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
398
+ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
369
399
  //console.log(JSON.stringify(nodes, null, 2));
370
400
  var columns = [];
371
401
  /**
@@ -421,6 +451,28 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
421
451
  }
422
452
  return s;
423
453
  }
454
+ if (node.displayName === ListColumns.craft.displayName) {
455
+ return {
456
+ besides: node.nodes.map((nm) => go(nodes[nm])),
457
+ list_columns: true,
458
+ };
459
+ }
460
+ if (node.displayName === ListColumn.craft.displayName) {
461
+ const contents = go(nodes[node.linkedNodes.listcol]);
462
+ const addFields = options.additionalColumnFields;
463
+ const lc = {
464
+ contents,
465
+ col_width: node.props.col_width,
466
+ col_width_units: node.props.col_width_units,
467
+ alignment: node.props.alignment,
468
+ header_label: node.props.header_label,
469
+ showif: node.props.showif,
470
+ };
471
+ (addFields || []).forEach((f) => {
472
+ lc[f.name] = node.props[f.name];
473
+ });
474
+ return lc;
475
+ }
424
476
  if (node.isCanvas) {
425
477
  if (node.displayName === Container.craft.displayName)
426
478
  return {
@@ -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,