@saltcorn/builder 0.6.1-beta.1 → 0.6.2-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.
package/package.json CHANGED
@@ -1,13 +1,15 @@
1
1
  {
2
2
  "name": "@saltcorn/builder",
3
- "version": "0.6.1-beta.1",
3
+ "version": "0.6.2-beta.0",
4
4
  "description": "Drag and drop view builder for Saltcorn, open-source no-code platform",
5
5
  "main": "index.js",
6
6
  "homepage": "https://saltcorn.com",
7
7
  "scripts": {
8
8
  "build": "webpack --mode production",
9
9
  "builddev": "webpack --mode none",
10
- "test": "echo \"Error: no test specified\""
10
+ "test": "echo \"Error: no test specified\"",
11
+ "tsc": "echo \"Error: no TypeScript support yet\"",
12
+ "clean": "echo \"Error: no TypeScript support yet\""
11
13
  },
12
14
  "repository": "github:saltcorn/saltcorn",
13
15
  "author": "Tom Nielsen",
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @category saltcorn-builder
3
- * @module components / Toolbox
3
+ * @module components/Toolbox
4
4
  * @subcategory components
5
5
  */
6
6
 
@@ -34,9 +34,9 @@ import {
34
34
  } from "react-bootstrap-icons";
35
35
 
36
36
  /**
37
- *
38
- * @param {object[]} xs
39
- * @param {object} def
37
+ *
38
+ * @param {object[]} xs
39
+ * @param {object} def
40
40
  * @returns {object}
41
41
  */
42
42
  const headOr = (xs, def) => (xs && xs.length > 0 ? xs[0] : def);
@@ -349,7 +349,7 @@ const DropDownFilterElem = ({ connectors, fields }) => (
349
349
  /**
350
350
  * @param {object} props
351
351
  * @param {object} props.connectors
352
- * @returns {WrapElem}
352
+ * @returns {WrapElem}
353
353
  * @category saltcorn-builder
354
354
  * @subcategory components / Toolbox
355
355
  * @namespace
@@ -448,7 +448,7 @@ const ActionElem = ({ connectors, options }) => (
448
448
  * @returns {WrapElem}
449
449
  * @category saltcorn-builder
450
450
  * @subcategory components / Toolbox
451
- * @namespace
451
+ * @namespace
452
452
  */
453
453
  const AggregationElem = ({ connectors, child_field_list, agg_field_opts }) => (
454
454
  <WrapElem
@@ -533,9 +533,7 @@ const ToolboxShow = () => {
533
533
  );
534
534
  };
535
535
 
536
-
537
-
538
- export /**
536
+ export /**
539
537
  * @returns {Fragment}
540
538
  * @category saltcorn-builder
541
539
  * @subcategory components / Toolbox
@@ -544,7 +542,7 @@ export /**
544
542
  const ToolboxFilter = () => {
545
543
  const { connectors, query } = useEditor();
546
544
  const options = useContext(optionsCtx);
547
- const { fields, views } = options;
545
+ const { fields, views, field_view_options } = options;
548
546
  return (
549
547
  <Fragment>
550
548
  <div className="toolbar-row">
@@ -552,23 +550,31 @@ const ToolboxFilter = () => {
552
550
  <ColumnsElem connectors={connectors} />
553
551
  </div>
554
552
  <div className="toolbar-row">
553
+ <FieldElem
554
+ connectors={connectors}
555
+ fields={fields}
556
+ field_view_options={field_view_options}
557
+ />
555
558
  <LineBreakElem connectors={connectors} />
556
- <DropDownFilterElem connectors={connectors} fields={fields} />
557
559
  </div>
558
560
  <div className="toolbar-row">
561
+ <DropDownFilterElem connectors={connectors} fields={fields} />
559
562
  <ToggleFilterElem connectors={connectors} fields={fields} />
560
- <SearchElem connectors={connectors} />
561
563
  </div>
562
564
  <div className="toolbar-row">
565
+ <SearchElem connectors={connectors} />
563
566
  <ActionElem connectors={connectors} options={options} />
564
- <ContainerElem connectors={connectors} />
565
567
  </div>
566
568
  <div className="toolbar-row">
569
+ <ContainerElem connectors={connectors} />
570
+
567
571
  <CardElem connectors={connectors} />
568
- <TabsElem connectors={connectors} />
569
572
  </div>
570
573
  <div className="toolbar-row">
574
+ <TabsElem connectors={connectors} />
571
575
  <ViewElem connectors={connectors} views={views} />
576
+ </div>
577
+ <div className="toolbar-row">
572
578
  <HTMLElem connectors={connectors} />
573
579
  </div>
574
580
  </Fragment>
@@ -46,8 +46,8 @@ import { BoxModelEditor } from "./BoxModelEditor";
46
46
  import previewCtx from "../preview_context";
47
47
 
48
48
  /**
49
- *
50
- * @param {string} string
49
+ *
50
+ * @param {string} string
51
51
  * @returns {string}
52
52
  */
53
53
  function capitalizeFirstLetter(string) {
@@ -55,7 +55,7 @@ function capitalizeFirstLetter(string) {
55
55
  }
56
56
 
57
57
  export /**
58
- * @param {object} props
58
+ * @param {object} props
59
59
  * @param {*} props.children
60
60
  * @param {*} props.minHeight
61
61
  * @param {*} props.height
@@ -185,7 +185,6 @@ const Container = ({
185
185
  );
186
186
  };
187
187
 
188
-
189
188
  export /**
190
189
  * @returns {div}
191
190
  * @returns {Accordion}
@@ -265,7 +264,7 @@ const ContainerSettings = () => {
265
264
  const ownership = !!options.ownership;
266
265
 
267
266
  /**
268
- * @param {string} key
267
+ * @param {string} key
269
268
  * @returns {function}
270
269
  */
271
270
  const setAProp = (key) => (e) => {
@@ -763,9 +762,13 @@ const ContainerSettings = () => {
763
762
  : showForRole[id]
764
763
  }
765
764
  onChange={(e) =>
766
- setProp(
767
- (prop) => (prop.showForRole[id] = e.target.checked)
768
- )
765
+ setProp((prop) => {
766
+ if (!prop.showForRole || prop.showForRole.length === 0)
767
+ options.roles.forEach(
768
+ (r) => (prop.showForRole[r.id] = true)
769
+ );
770
+ prop.showForRole[id] = e.target.checked;
771
+ })
769
772
  }
770
773
  />
771
774
  <label className="form-check-label">{role}</label>
@@ -882,8 +885,8 @@ const ContainerSettings = () => {
882
885
  );
883
886
  };
884
887
 
885
- /**
886
- * @type {object}
888
+ /**
889
+ * @type {object}
887
890
  */
888
891
  Container.craft = {
889
892
  displayName: "Container",
@@ -21,23 +21,36 @@ export /**
21
21
  * @category saltcorn-builder
22
22
  * @subcategory components
23
23
  */
24
- const Tabs = ({ contents, titles, tabsStyle, ntabs }) => {
24
+ const Tabs = ({ contents, titles, tabsStyle, ntabs, independent }) => {
25
25
  const {
26
26
  selected,
27
27
  connectors: { connect, drag },
28
28
  } = useNode((node) => ({ selected: node.events.selected }));
29
29
  const [showTab, setShowTab] = useState(0);
30
+ const [showTabs, setShowTabs] = useState([true]);
31
+
30
32
  if (tabsStyle === "Accordion")
31
33
  return (
32
34
  <div className="accordion">
33
35
  {ntimes(ntabs, (ix) => (
34
- <div className="card">
36
+ <div key={ix} className="card">
35
37
  <div className="card-header">
36
38
  <h2 className="mb-0">
37
39
  <button
38
40
  className="btn btn-link btn-block text-left"
39
41
  type="button"
40
- onClick={() => setShowTab(ix)}
42
+ onClick={() => {
43
+ setShowTab(ix);
44
+ if (!independent) {
45
+ let newArr = [];
46
+ newArr[ix] = true;
47
+ setShowTabs(newArr);
48
+ } else {
49
+ let newArr = [...showTabs];
50
+ newArr[ix] = !newArr[ix];
51
+ setShowTabs(newArr);
52
+ }
53
+ }}
41
54
  >
42
55
  {titles[ix]}
43
56
  </button>
@@ -45,8 +58,12 @@ const Tabs = ({ contents, titles, tabsStyle, ntabs }) => {
45
58
  </div>
46
59
 
47
60
  <div
48
- id="collapseOne"
49
- className={`collapse ${ix === showTab ? "show" : ""}`}
61
+ id={`collapse${ix}`}
62
+ className={`collapse ${
63
+ (independent && showTabs[ix]) || (!independent && showTab == ix)
64
+ ? "show"
65
+ : ""
66
+ }`}
50
67
  aria-labelledby="headingOne"
51
68
  data-parent="#accordionExample"
52
69
  >
@@ -110,12 +127,14 @@ const TabsSettings = () => {
110
127
  const node = useNode((node) => ({
111
128
  tabsStyle: node.data.props.tabsStyle,
112
129
  ntabs: node.data.props.ntabs,
130
+ independent: node.data.props.independent,
113
131
  titles: node.data.props.titles,
114
132
  }));
115
133
  const {
116
134
  actions: { setProp },
117
135
  titles,
118
136
  tabsStyle,
137
+ independent,
119
138
  ntabs,
120
139
  } = node;
121
140
  return (
@@ -175,6 +194,26 @@ const TabsSettings = () => {
175
194
  </td>
176
195
  </tr>
177
196
  ))}
197
+ {tabsStyle === "Accordion" && (
198
+ <tr>
199
+ <td colSpan="2">
200
+ <div className="form-check">
201
+ <input
202
+ className="form-check-input"
203
+ name="block"
204
+ type="checkbox"
205
+ checked={independent}
206
+ onChange={(e) => {
207
+ if (e.target) {
208
+ setProp((prop) => (prop.independent = e.target.checked));
209
+ }
210
+ }}
211
+ />
212
+ <label className="form-check-label">Open independently</label>
213
+ </div>
214
+ </td>
215
+ </tr>
216
+ )}
178
217
  </tbody>
179
218
  </table>
180
219
  );
@@ -188,6 +227,7 @@ Tabs.craft = {
188
227
  titles: ["Tab1", "Tab2"],
189
228
  ntabs: 2,
190
229
  tabsStyle: "Tabs",
230
+ independent: false,
191
231
  },
192
232
  displayName: "Tabs",
193
233
  related: {
@@ -27,7 +27,7 @@ export /**
27
27
  * @subcategory components
28
28
  * @namespace
29
29
  */
30
- const View = ({ name, view, state }) => {
30
+ const View = ({ name, view, configuration, state }) => {
31
31
  const {
32
32
  selected,
33
33
  node_id,
@@ -45,9 +45,10 @@ const View = ({ name, view, state }) => {
45
45
  options,
46
46
  view,
47
47
  setPreviews,
48
+ configuration,
48
49
  node_id,
49
50
  })();
50
- }, []);
51
+ }, [view, configuration, state]);
51
52
  return (
52
53
  <div
53
54
  ref={(dom) => connect(drag(dom))}
@@ -95,12 +96,7 @@ const ViewSettings = () => {
95
96
  const fixed_state_fields =
96
97
  options.fixed_state_fields && options.fixed_state_fields[view];
97
98
  const { setPreviews } = useContext(previewCtx);
98
- const refetchPreview = fetchViewPreview({
99
- options,
100
- view,
101
- setPreviews,
102
- node_id,
103
- });
99
+
104
100
  const setAProp = (key) => (e) => {
105
101
  if (e.target) {
106
102
  const target_value = e.target.value;
@@ -116,7 +112,6 @@ const ViewSettings = () => {
116
112
  className="form-control"
117
113
  onChange={(e) => {
118
114
  setProp((prop) => (prop.view = e.target.value));
119
- refetchPreview({ view: e.target.value });
120
115
  }}
121
116
  >
122
117
  {views.map((f, ix) => (
@@ -154,6 +149,15 @@ const ViewSettings = () => {
154
149
  )}
155
150
  </Fragment>
156
151
  )}
152
+ {view ? (
153
+ <a
154
+ className="d-block mt-2"
155
+ target="_blank"
156
+ href={`/viewedit/config/${view}`}
157
+ >
158
+ Configure this view
159
+ </a>
160
+ ) : null}
157
161
  </div>
158
162
  );
159
163
  };
@@ -22,7 +22,7 @@ export const DynamicFontAwesomeIcon = ({ icon, className }) => {
22
22
  };
23
23
 
24
24
  export /**
25
- * @param {boolean} is_block
25
+ * @param {boolean} is_block
26
26
  * @returns {object}
27
27
  */
28
28
  const blockProps = (is_block) =>
@@ -390,12 +390,12 @@ export const fetchFieldPreview = (args = {}) => (changes = {}) => {
390
390
  * @return {function}
391
391
  */
392
392
  export const fetchViewPreview = (args = {}) => (changes = {}) => {
393
- const { node_id, options, view, setPreviews } = {
393
+ const { node_id, options, view, setPreviews, configuration } = {
394
394
  ...args,
395
395
  ...changes,
396
396
  };
397
397
  let viewname,
398
- body = {};
398
+ body = configuration || {};
399
399
  if (view.includes(":")) {
400
400
  const [reltype, rest] = view.split(":");
401
401
  const [vnm] = rest.split(".");
@@ -463,9 +463,9 @@ export const parseStyles = (styles) =>
463
463
 
464
464
  /**
465
465
  * @function
466
- * @param {object} styles
466
+ * @param {object} styles
467
467
  * @returns {object}
468
- */
468
+ */
469
469
  export const reactifyStyles = (styles) => {
470
470
  const toCamel = (s) => {
471
471
  return s.replace(/([-][a-z])/gi, ($1) => {
@@ -480,7 +480,7 @@ export const reactifyStyles = (styles) => {
480
480
  };
481
481
 
482
482
  /**
483
- * @param {object} f
483
+ * @param {object} f
484
484
  * @returns {boolean}
485
485
  */
486
486
  const isCheckbox = (f) =>
@@ -488,8 +488,8 @@ const isCheckbox = (f) =>
488
488
 
489
489
  /**
490
490
  * @function
491
- * @param {function} setProp
492
- * @param {*} fieldview
491
+ * @param {function} setProp
492
+ * @param {*} fieldview
493
493
  * @param {object[]} [fields]
494
494
  * @returns {void}
495
495
  */
@@ -540,14 +540,8 @@ export /**
540
540
  * @category saltcorn-builder
541
541
  * @subcategory components / elements / utils
542
542
  * @namespace
543
- */
544
- const ConfigForm = ({
545
- fields,
546
- configuration,
547
- setProp,
548
- node,
549
- onChange,
550
- }) => (
543
+ */
544
+ const ConfigForm = ({ fields, configuration, setProp, node, onChange }) => (
551
545
  <div>
552
546
  {fields.map((f, ix) => {
553
547
  if (f.showIf && node && node.configuration) {
@@ -579,13 +573,12 @@ const ConfigForm = ({
579
573
  );
580
574
 
581
575
  /**
582
- * @param {object|undefined} x
583
- * @param {object} y
576
+ * @param {object|undefined} x
577
+ * @param {object} y
584
578
  * @returns {object}
585
579
  */
586
580
  const or_if_undef = (x, y) => (typeof x === "undefined" ? y : x);
587
581
 
588
-
589
582
  export /**
590
583
  * @param {object} props
591
584
  * @param {object} props.field
@@ -598,7 +591,7 @@ export /**
598
591
  * @category saltcorn-builder
599
592
  * @subcategory components / elements / utils
600
593
  * @namespace
601
- */
594
+ */
602
595
  const ConfigField = ({
603
596
  field,
604
597
  configuration,
@@ -608,7 +601,7 @@ const ConfigField = ({
608
601
  isStyle,
609
602
  }) => {
610
603
  /**
611
- * @param {object} v
604
+ * @param {object} v
612
605
  * @returns {void}
613
606
  */
614
607
  const myOnChange = (v) => {
@@ -928,7 +921,7 @@ const SettingsRow = ({ field, node, setProp, onChange, isStyle }) => {
928
921
  export class ErrorBoundary extends React.Component {
929
922
  /**
930
923
  * ErrorBoundary constructor
931
- * @param {object} props
924
+ * @param {object} props
932
925
  */
933
926
  constructor(props) {
934
927
  super(props);
@@ -936,7 +929,7 @@ export class ErrorBoundary extends React.Component {
936
929
  }
937
930
 
938
931
  /**
939
- * @param {*} error
932
+ * @param {*} error
940
933
  * @returns {object}
941
934
  */
942
935
  static getDerivedStateFromError(error) {
@@ -945,8 +938,8 @@ export class ErrorBoundary extends React.Component {
945
938
  }
946
939
 
947
940
  /**
948
- * @param {object} error
949
- * @param {object} errorInfo
941
+ * @param {object} error
942
+ * @param {object} errorInfo
950
943
  * @returns {void}
951
944
  */
952
945
  componentDidCatch(error, errorInfo) {
@@ -1107,7 +1100,7 @@ const ButtonOrLinkSettingsRows = ({
1107
1100
 
1108
1101
  /**
1109
1102
  * @function
1110
- * @param {string} style
1103
+ * @param {string} style
1111
1104
  * @returns {object}
1112
1105
  */
1113
1106
  export const bstyleopt = (style) => ({
@@ -27,7 +27,7 @@ import { DropDownFilter } from "./elements/DropDownFilter";
27
27
  import { ToggleFilter } from "./elements/ToggleFilter";
28
28
 
29
29
  /**
30
- * @param {object} segment
30
+ * @param {object} segment
31
31
  * @returns {number}
32
32
  */
33
33
  const getColWidths = (segment) => {
@@ -43,7 +43,7 @@ const getColWidths = (segment) => {
43
43
  };
44
44
 
45
45
  /**
46
- * @param {object} segment
46
+ * @param {object} segment
47
47
  * @returns {object[]}
48
48
  */
49
49
  const default_breakpoints = (segment) =>
@@ -72,9 +72,9 @@ const allElements = [
72
72
  ];
73
73
 
74
74
  export /**
75
- * @param {object} layout
76
- * @param {object} query
77
- * @param {object} actions
75
+ * @param {object} layout
76
+ * @param {object} query
77
+ * @param {object} actions
78
78
  * @param {string} [parent = "ROOT"]
79
79
  * @returns {Text|View|Action|Element|Tabs|Columns}
80
80
  * @category saltcorn-builder
@@ -84,8 +84,8 @@ export /**
84
84
  const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
85
85
  //console.log("layoutToNodes", JSON.stringify(layout));
86
86
  /**
87
- * @param {object} segment
88
- * @param {string} ix
87
+ * @param {object} segment
88
+ * @param {string} ix
89
89
  * @returns {Element|Text|View|Action|Tabs|Columns}
90
90
  */
91
91
  function toTag(segment, ix) {
@@ -223,6 +223,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
223
223
  key={ix}
224
224
  titles={segment.titles}
225
225
  ntabs={segment.ntabs}
226
+ independent={segment.independent}
226
227
  tabsStyle={segment.tabsStyle}
227
228
  contents={segment.contents.map(toTag)}
228
229
  />
@@ -243,8 +244,8 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
243
244
  }
244
245
 
245
246
  /**
246
- * @param {object} segment
247
- * @param {object} parent
247
+ * @param {object} segment
248
+ * @param {object} parent
248
249
  * @returns {void}
249
250
  */
250
251
  function go(segment, parent) {
@@ -285,7 +286,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT") => {
285
286
  const rand_ident = () => Math.floor(Math.random() * 16777215).toString(16);
286
287
 
287
288
  export /**
288
- * @param {object[]} nodes
289
+ * @param {object[]} nodes
289
290
  * @param {string} [startFrom = "ROOT" ]
290
291
  * @returns {object}
291
292
  * @category saltcorn-builder
@@ -295,9 +296,9 @@ export /**
295
296
  const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
296
297
  //console.log(JSON.stringify(nodes, null, 2));
297
298
  var columns = [];
298
-
299
+
299
300
  /**
300
- * @param {object} node
301
+ * @param {object} node
301
302
  * @returns {void|object}
302
303
  */
303
304
  const get_nodes = (node) => {
@@ -307,7 +308,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
307
308
  };
308
309
 
309
310
  /**
310
- * @param {object} node
311
+ * @param {object} node
311
312
  * @returns {object}
312
313
  */
313
314
  const go = (node) => {
@@ -410,6 +411,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT") => {
410
411
  ),
411
412
  titles: node.props.titles,
412
413
  tabsStyle: node.props.tabsStyle,
414
+ independent: node.props.independent,
413
415
  ntabs: node.props.ntabs,
414
416
  };
415
417
  }
package/src/index.js CHANGED
@@ -3,6 +3,51 @@
3
3
  * @module saltcorn-builder/index
4
4
  */
5
5
 
6
+ /**
7
+ * All files in the saltcorn-builder package.
8
+ * @namespace saltcorn-builder_overview
9
+ * @property {module:components/Builder} Builder
10
+ * @property {module:components/context} context
11
+ * @property {module:components/Library} Library
12
+ * @property {module:components/preview_context} preview_context
13
+ * @property {module:components/RenderNode} RenderNode
14
+ * @property {module:components/storage} storage
15
+ * @property {module:components/Toolbox} Toolbox
16
+ *
17
+ * @category saltcorn-builder
18
+ */
19
+
20
+ /**
21
+ * All files in the elements folder.
22
+ * @namespace saltcorn-builder_overview/elements
23
+ * @memberof module:saltcorn-builder/index~saltcorn-builder_overview
24
+ * @property {module:components/elements/Action} Action
25
+ * @property {module:components/elements/Aggregation} Aggregation
26
+ * @property {module:components/elements/BoxModelEditor} BoxModelEditor
27
+ * @property {module:components/elements/Card} Card
28
+ * @property {module:components/elements/Column} Column
29
+ * @property {module:components/elements/Columns} Columns
30
+ * @property {module:components/elements/Container} Container
31
+ * @property {module:components/elements/DropDownFilter} DropDownFilter
32
+ * @property {module:components/elements/Empty} Empty
33
+ * @property {module:components/elements/faicons} faicons
34
+ * @property {module:components/elements/Field} Field
35
+ * @property {module:components/elements/HTMLCode} HTMLCode
36
+ * @property {module:components/elements/Image} Image
37
+ * @property {module:components/elements/JoinField} JoinField
38
+ * @property {module:components/elements/LineBreak} LineBreak
39
+ * @property {module:components/elements/Link} Link
40
+ * @property {module:components/elements/SearchBar} SearchBar
41
+ * @property {module:components/elements/Tabs} Tabs
42
+ * @property {module:components/elements/Text} Text
43
+ * @property {module:components/elements/ToggleFilter} ToggleFilter
44
+ * @property {module:components/elements/utils} utils
45
+ * @property {module:components/elements/View} View
46
+ * @property {module:components/elements/ViewLink} ViewLink
47
+ *
48
+ * @category saltcorn-builder
49
+ */
50
+
6
51
  import React from "react";
7
52
  import Builder from "./components/Builder";
8
53
  import ReactDOM from "react-dom";