@saltcorn/builder 0.7.3 → 0.7.4-beta.2

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,6 +1,6 @@
1
1
  {
2
2
  "name": "@saltcorn/builder",
3
- "version": "0.7.3",
3
+ "version": "0.7.4-beta.2",
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",
@@ -35,6 +35,7 @@
35
35
  "react-contenteditable": "3.3.5",
36
36
  "react-dom": "16.13.1",
37
37
  "react-transition-group": "4.4.1",
38
+ "@tippyjs/react": "4.2.6",
38
39
  "webpack": "4.43.0",
39
40
  "webpack-cli": "3.3.11",
40
41
  "lodash": "4.17.11"
@@ -58,7 +58,6 @@ import {
58
58
  } from "./elements/utils";
59
59
  import { InitNewElement, Library } from "./Library";
60
60
  import { RenderNode } from "./RenderNode";
61
- import { isEqual } from "lodash";
62
61
  const { Provider } = optionsCtx;
63
62
 
64
63
  /**
@@ -389,47 +388,11 @@ const Builder = ({ options, layout, mode }) => {
389
388
  const [previews, setPreviews] = useState({});
390
389
  const [uploadedFiles, setUploadedFiles] = useState([]);
391
390
  const nodekeys = useRef([]);
392
- const [saveTimeout, setSaveTimeout] = useState(false);
393
391
  const [isSaving, setIsSaving] = useState(false);
394
- const [savedData, setSavedData] = useState(false);
395
- const doSave = (query) => {
396
- if (!query.serialize) return;
397
392
 
398
- const data = craftToSaltcorn(JSON.parse(query.serialize()));
399
- const urlroot = options.page_id ? "pageedit" : "viewedit";
400
- if (savedData === false) {
401
- //do not save on first call
402
- setSavedData(data.layout);
403
- setIsSaving(false);
404
- return;
405
- }
406
- if (isEqual(savedData, data.layout)) return;
407
- setSavedData(data.layout);
408
-
409
- fetch(`/${urlroot}/savebuilder/${options.page_id || options.view_id}`, {
410
- method: "POST", // or 'PUT'
411
- headers: {
412
- "Content-Type": "application/json",
413
- "CSRF-Token": options.csrfToken,
414
- },
415
- body: JSON.stringify(data),
416
- }).then(() => {
417
- setIsSaving(false);
418
- });
419
- };
420
- const nodesChange = (query) => {
421
- if (saveTimeout) clearTimeout(saveTimeout);
422
- setIsSaving(true);
423
- setSaveTimeout(
424
- setTimeout(() => {
425
- doSave(query);
426
- setSaveTimeout(false);
427
- }, 500)
428
- );
429
- };
430
393
  return (
431
394
  <ErrorBoundary>
432
- <Editor onRender={RenderNode} onNodesChange={nodesChange}>
395
+ <Editor onRender={RenderNode}>
433
396
  <Provider value={options}>
434
397
  <PreviewCtx.Provider
435
398
  value={{ previews, setPreviews, uploadedFiles, setUploadedFiles }}
@@ -437,7 +400,10 @@ const Builder = ({ options, layout, mode }) => {
437
400
  <div className="row" style={{ marginTop: "-5px" }}>
438
401
  <div className="col-sm-auto left-builder-col">
439
402
  <div className="componets-and-library-accordion toolbox-card">
440
- <InitNewElement nodekeys={nodekeys} />
403
+ <InitNewElement
404
+ nodekeys={nodekeys}
405
+ setIsSaving={setIsSaving}
406
+ />
441
407
  <Accordion>
442
408
  <div className="card mt-1" accordiontitle="Components">
443
409
  {{
@@ -4,7 +4,13 @@
4
4
  * @subcategory components
5
5
  */
6
6
 
7
- import React, { useEffect, useContext, useState, Fragment } from "react";
7
+ import React, {
8
+ useEffect,
9
+ useContext,
10
+ useState,
11
+ Fragment,
12
+ useRef,
13
+ } from "react";
8
14
  import { useEditor, useNode } from "@craftjs/core";
9
15
  import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
10
16
  import { faPlus, faTimes } from "@fortawesome/free-solid-svg-icons";
@@ -13,10 +19,11 @@ import faIcons from "./elements/faicons";
13
19
  import { craftToSaltcorn, layoutToNodes } from "./storage";
14
20
  import optionsCtx from "./context";
15
21
  import { WrapElem } from "./Toolbox";
22
+ import { isEqual } from "lodash";
16
23
 
17
24
  /**
18
- *
19
- * @param {object[]} xs
25
+ *
26
+ * @param {object[]} xs
20
27
  * @returns {object[]}
21
28
  */
22
29
  const twoByTwos = (xs) => {
@@ -67,10 +74,38 @@ export /**
67
74
  * @subcategory components
68
75
  * @namespace
69
76
  */
70
- const InitNewElement = ({ nodekeys }) => {
77
+ const InitNewElement = ({ nodekeys, setIsSaving }) => {
78
+ const [saveTimeout, setSaveTimeout] = useState(false);
79
+ const savedData = useRef(false);
71
80
  const { actions, query, connectors } = useEditor((state, query) => {
72
81
  return {};
73
82
  });
83
+ const options = useContext(optionsCtx);
84
+ const doSave = (query) => {
85
+ if (!query.serialize) return;
86
+
87
+ const data = craftToSaltcorn(JSON.parse(query.serialize()));
88
+ const urlroot = options.page_id ? "pageedit" : "viewedit";
89
+ if (savedData.current === false) {
90
+ //do not save on first call
91
+ savedData.current = JSON.stringify(data.layout);
92
+ setIsSaving(false);
93
+ return;
94
+ }
95
+ if (isEqual(savedData.current, JSON.stringify(data.layout))) return;
96
+ savedData.current = JSON.stringify(data.layout);
97
+
98
+ fetch(`/${urlroot}/savebuilder/${options.page_id || options.view_id}`, {
99
+ method: "POST", // or 'PUT'
100
+ headers: {
101
+ "Content-Type": "application/json",
102
+ "CSRF-Token": options.csrfToken,
103
+ },
104
+ body: JSON.stringify(data),
105
+ }).then(() => {
106
+ setIsSaving(false);
107
+ });
108
+ };
74
109
  const onNodesChange = (arg, arg1) => {
75
110
  const nodes = arg.getSerializedNodes();
76
111
  const newNodeIds = [];
@@ -98,6 +133,14 @@ const InitNewElement = ({ nodekeys }) => {
98
133
  actions.selectNode(id);
99
134
  }
100
135
  }
136
+ if (saveTimeout) clearTimeout(saveTimeout);
137
+ setIsSaving(true);
138
+ setSaveTimeout(
139
+ setTimeout(() => {
140
+ doSave(query);
141
+ setSaveTimeout(false);
142
+ }, 500)
143
+ );
101
144
  };
102
145
  useEffect(() => {
103
146
  const nodes = query.getSerializedNodes();
@@ -19,6 +19,7 @@ import {
19
19
  reactifyStyles,
20
20
  bstyleopt,
21
21
  setAPropGen,
22
+ FormulaTooltip,
22
23
  } from "./utils";
23
24
  import {
24
25
  BorderOuter,
@@ -757,7 +758,7 @@ const ContainerSettings = () => {
757
758
  onChange={setAProp("showIfFormula")}
758
759
  />
759
760
  <div style={{ marginTop: "-5px" }}>
760
- <small className="text-muted font-monospace">FORMULA</small>
761
+ <small className="text-muted font-monospace">FORMULA <FormulaTooltip /></small>
761
762
  </div>
762
763
  </td>
763
764
  </tr>
@@ -79,6 +79,11 @@ const DropDownFilterSettings = () => {
79
79
  {f.label}
80
80
  </option>
81
81
  ))}
82
+ {options.parent_field_list.map((f, ix) => (
83
+ <option key={ix} value={f}>
84
+ {f}
85
+ </option>
86
+ ))}
82
87
  </select>
83
88
  </td>
84
89
  </tr>
@@ -16,6 +16,7 @@ import {
16
16
  fetchViewPreview,
17
17
  ConfigForm,
18
18
  setAPropGen,
19
+ FormulaTooltip,
19
20
  } from "./utils";
20
21
 
21
22
  export /**
@@ -158,7 +159,7 @@ const ViewSettings = () => {
158
159
  {(state === "shared" || options.mode === "page") && (
159
160
  <Fragment>
160
161
  {" "}
161
- <label>Extra state Formula</label>
162
+ <label>Extra state Formula <FormulaTooltip /></label>
162
163
  <input
163
164
  type="text"
164
165
  className="viewlink-label form-control"
@@ -15,6 +15,7 @@ import {
15
15
  TextStyleSetting,
16
16
  ButtonOrLinkSettingsRows,
17
17
  setAPropGen,
18
+ FormulaTooltip,
18
19
  } from "./utils";
19
20
 
20
21
  export /**
@@ -157,7 +158,7 @@ const ViewLinkSettings = () => {
157
158
  </tr>
158
159
  <tr>
159
160
  <td colSpan="2">
160
- <label>Extra state Formula</label>
161
+ <label>Extra state Formula <FormulaTooltip /></label>
161
162
  <input
162
163
  type="text"
163
164
  className="viewlink-label form-control"