@saltcorn/builder 0.7.3-beta.3 → 0.7.3
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 +20 -12
- package/package.json +3 -2
- package/src/components/Builder.js +45 -2
- package/src/components/Library.js +1 -1
- package/src/components/elements/Action.js +9 -12
- package/src/components/elements/Aggregation.js +13 -13
- package/src/components/elements/Columns.js +17 -11
- package/src/components/elements/Container.js +15 -23
- package/src/components/elements/DropDownFilter.js +9 -11
- package/src/components/elements/Field.js +12 -11
- package/src/components/elements/Image.js +3 -7
- package/src/components/elements/JoinField.js +10 -6
- package/src/components/elements/Link.js +12 -22
- package/src/components/elements/SearchBar.js +4 -6
- package/src/components/elements/Tabs.js +13 -26
- package/src/components/elements/Text.js +10 -10
- package/src/components/elements/ToggleFilter.js +11 -14
- package/src/components/elements/View.js +9 -13
- package/src/components/elements/ViewLink.js +7 -10
- package/src/components/elements/utils.js +12 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/builder",
|
|
3
|
-
"version": "0.7.3
|
|
3
|
+
"version": "0.7.3",
|
|
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",
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"react-dom": "16.13.1",
|
|
37
37
|
"react-transition-group": "4.4.1",
|
|
38
38
|
"webpack": "4.43.0",
|
|
39
|
-
"webpack-cli": "3.3.11"
|
|
39
|
+
"webpack-cli": "3.3.11",
|
|
40
|
+
"lodash": "4.17.11"
|
|
40
41
|
},
|
|
41
42
|
"publishConfig": {
|
|
42
43
|
"access": "public"
|
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
faUndo,
|
|
50
50
|
faRedo,
|
|
51
51
|
faTrashAlt,
|
|
52
|
+
faSave,
|
|
52
53
|
} from "@fortawesome/free-solid-svg-icons";
|
|
53
54
|
import {
|
|
54
55
|
Accordion,
|
|
@@ -57,6 +58,7 @@ import {
|
|
|
57
58
|
} from "./elements/utils";
|
|
58
59
|
import { InitNewElement, Library } from "./Library";
|
|
59
60
|
import { RenderNode } from "./RenderNode";
|
|
61
|
+
import { isEqual } from "lodash";
|
|
60
62
|
const { Provider } = optionsCtx;
|
|
61
63
|
|
|
62
64
|
/**
|
|
@@ -387,10 +389,47 @@ const Builder = ({ options, layout, mode }) => {
|
|
|
387
389
|
const [previews, setPreviews] = useState({});
|
|
388
390
|
const [uploadedFiles, setUploadedFiles] = useState([]);
|
|
389
391
|
const nodekeys = useRef([]);
|
|
392
|
+
const [saveTimeout, setSaveTimeout] = useState(false);
|
|
393
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
394
|
+
const [savedData, setSavedData] = useState(false);
|
|
395
|
+
const doSave = (query) => {
|
|
396
|
+
if (!query.serialize) return;
|
|
390
397
|
|
|
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
|
+
};
|
|
391
430
|
return (
|
|
392
431
|
<ErrorBoundary>
|
|
393
|
-
<Editor onRender={RenderNode}>
|
|
432
|
+
<Editor onRender={RenderNode} onNodesChange={nodesChange}>
|
|
394
433
|
<Provider value={options}>
|
|
395
434
|
<PreviewCtx.Provider
|
|
396
435
|
value={{ previews, setPreviews, uploadedFiles, setUploadedFiles }}
|
|
@@ -458,9 +497,13 @@ const Builder = ({ options, layout, mode }) => {
|
|
|
458
497
|
</div>
|
|
459
498
|
<div className="col-sm-auto builder-sidebar">
|
|
460
499
|
<div style={{ width: "16rem" }}>
|
|
461
|
-
<SaveButton />
|
|
462
500
|
<NextButton layout={layout} />
|
|
463
501
|
<HistoryPanel />
|
|
502
|
+
<FontAwesomeIcon
|
|
503
|
+
icon={faSave}
|
|
504
|
+
title={isSaving ? "Saving..." : "All changes saved"}
|
|
505
|
+
className={isSaving ? "text-muted" : ""}
|
|
506
|
+
/>
|
|
464
507
|
<ViewPageLink />
|
|
465
508
|
<SettingsPanel />
|
|
466
509
|
</div>
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
setInitialConfig,
|
|
17
17
|
ButtonOrLinkSettingsRows,
|
|
18
18
|
DynamicFontAwesomeIcon,
|
|
19
|
+
setAPropGen,
|
|
19
20
|
} from "./utils";
|
|
20
21
|
|
|
21
22
|
export /**
|
|
@@ -110,6 +111,8 @@ const ActionSettings = () => {
|
|
|
110
111
|
const options = useContext(optionsCtx);
|
|
111
112
|
const getCfgFields = (fv) => (options.actionConfigForms || {})[fv];
|
|
112
113
|
const cfgFields = getCfgFields(name);
|
|
114
|
+
const setAProp = setAPropGen(setProp);
|
|
115
|
+
|
|
113
116
|
return (
|
|
114
117
|
<div>
|
|
115
118
|
<table className="w-100">
|
|
@@ -123,12 +126,10 @@ const ActionSettings = () => {
|
|
|
123
126
|
value={name}
|
|
124
127
|
className="form-control form-select"
|
|
125
128
|
onChange={(e) => {
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
getCfgFields(e.target.value)
|
|
131
|
-
);
|
|
129
|
+
if (!e.target) return;
|
|
130
|
+
const value = e.target.value;
|
|
131
|
+
setProp((prop) => (prop.name = value));
|
|
132
|
+
setInitialConfig(setProp, value, getCfgFields(value));
|
|
132
133
|
}}
|
|
133
134
|
>
|
|
134
135
|
{options.actions.map((f, ix) => (
|
|
@@ -150,9 +151,7 @@ const ActionSettings = () => {
|
|
|
150
151
|
type="text"
|
|
151
152
|
className="form-control"
|
|
152
153
|
value={action_label}
|
|
153
|
-
onChange={(
|
|
154
|
-
setProp((prop) => (prop.action_label = e.target.value))
|
|
155
|
-
}
|
|
154
|
+
onChange={setAProp("action_label")}
|
|
156
155
|
/>
|
|
157
156
|
</OrFormula>
|
|
158
157
|
</td>
|
|
@@ -172,9 +171,7 @@ const ActionSettings = () => {
|
|
|
172
171
|
name="block"
|
|
173
172
|
type="checkbox"
|
|
174
173
|
checked={confirm}
|
|
175
|
-
onChange={(
|
|
176
|
-
setProp((prop) => (prop.confirm = e.target.checked))
|
|
177
|
-
}
|
|
174
|
+
onChange={setAProp("confirm", { checked: true })}
|
|
178
175
|
/>
|
|
179
176
|
<label className="form-check-label">User confirmation?</label>
|
|
180
177
|
</div>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import React, { useContext } from "react";
|
|
8
8
|
import { useNode } from "@craftjs/core";
|
|
9
9
|
import optionsCtx from "../context";
|
|
10
|
-
import { blockProps, BlockSetting, TextStyleRow } from "./utils";
|
|
10
|
+
import { blockProps, BlockSetting, TextStyleRow, setAPropGen } from "./utils";
|
|
11
11
|
|
|
12
12
|
export /**
|
|
13
13
|
* @param {object} props
|
|
@@ -61,6 +61,8 @@ const AggregationSettings = () => {
|
|
|
61
61
|
textStyle: node.data.props.textStyle,
|
|
62
62
|
}));
|
|
63
63
|
const options = useContext(optionsCtx);
|
|
64
|
+
const setAProp = setAPropGen(setProp);
|
|
65
|
+
|
|
64
66
|
return (
|
|
65
67
|
<table>
|
|
66
68
|
<tbody>
|
|
@@ -72,13 +74,15 @@ const AggregationSettings = () => {
|
|
|
72
74
|
<select
|
|
73
75
|
className="form-control form-select"
|
|
74
76
|
value={agg_relation}
|
|
75
|
-
onChange={(e) =>
|
|
77
|
+
onChange={(e) => {
|
|
78
|
+
if (!e.target) return;
|
|
79
|
+
const value = e.target.value;
|
|
76
80
|
setProp((prop) => {
|
|
77
|
-
prop.agg_relation =
|
|
78
|
-
const fs = options.agg_field_opts[
|
|
81
|
+
prop.agg_relation = value;
|
|
82
|
+
const fs = options.agg_field_opts[value];
|
|
79
83
|
if (fs && fs.length > 0) prop.agg_field = fs[0];
|
|
80
|
-
})
|
|
81
|
-
}
|
|
84
|
+
});
|
|
85
|
+
}}
|
|
82
86
|
>
|
|
83
87
|
{options.child_field_list.map((f, ix) => (
|
|
84
88
|
<option key={ix} value={f}>
|
|
@@ -96,9 +100,7 @@ const AggregationSettings = () => {
|
|
|
96
100
|
<select
|
|
97
101
|
className="form-control form-select"
|
|
98
102
|
value={agg_field}
|
|
99
|
-
onChange={(
|
|
100
|
-
setProp((prop) => (prop.agg_field = e.target.value))
|
|
101
|
-
}
|
|
103
|
+
onChange={setAProp("agg_field")}
|
|
102
104
|
>
|
|
103
105
|
{(options.agg_field_opts[agg_relation] || []).map((f, ix) => (
|
|
104
106
|
<option key={ix} value={f}>
|
|
@@ -116,7 +118,7 @@ const AggregationSettings = () => {
|
|
|
116
118
|
<select
|
|
117
119
|
value={stat}
|
|
118
120
|
className="form-control form-select"
|
|
119
|
-
onChange={(
|
|
121
|
+
onChange={setAProp("stat")}
|
|
120
122
|
>
|
|
121
123
|
<option value={"Count"}>Count</option>
|
|
122
124
|
<option value={"Avg"}>Avg</option>
|
|
@@ -141,9 +143,7 @@ const AggregationSettings = () => {
|
|
|
141
143
|
type="text"
|
|
142
144
|
className="form-control"
|
|
143
145
|
value={aggwhere}
|
|
144
|
-
onChange={(
|
|
145
|
-
setProp((prop) => (prop.aggwhere = e.target.value))
|
|
146
|
-
}
|
|
146
|
+
onChange={setAProp("aggwhere")}
|
|
147
147
|
/>
|
|
148
148
|
</td>
|
|
149
149
|
</tr>
|
|
@@ -118,12 +118,14 @@ const ColumnsSettings = () => {
|
|
|
118
118
|
step="1"
|
|
119
119
|
min="1"
|
|
120
120
|
max="4"
|
|
121
|
-
onChange={(e) =>
|
|
121
|
+
onChange={(e) => {
|
|
122
|
+
if (!e.target) return;
|
|
123
|
+
const value = e.target.value;
|
|
122
124
|
setProp((prop) => {
|
|
123
|
-
prop.ncols =
|
|
124
|
-
prop.widths = resetWidths(
|
|
125
|
-
})
|
|
126
|
-
}
|
|
125
|
+
prop.ncols = value;
|
|
126
|
+
prop.widths = resetWidths(value);
|
|
127
|
+
});
|
|
128
|
+
}}
|
|
127
129
|
/>
|
|
128
130
|
</td>
|
|
129
131
|
</tr>
|
|
@@ -148,9 +150,11 @@ const ColumnsSettings = () => {
|
|
|
148
150
|
step="1"
|
|
149
151
|
min="1"
|
|
150
152
|
max={12 - (sum(widths) - widths[ix]) - 1}
|
|
151
|
-
onChange={(e) =>
|
|
152
|
-
|
|
153
|
-
|
|
153
|
+
onChange={(e) => {
|
|
154
|
+
if (!e.target) return;
|
|
155
|
+
const value = e.target.value;
|
|
156
|
+
setProp((prop) => (prop.widths[ix] = +value));
|
|
157
|
+
}}
|
|
154
158
|
/>
|
|
155
159
|
) : (
|
|
156
160
|
`${12 - sum(widths)}`
|
|
@@ -161,9 +165,11 @@ const ColumnsSettings = () => {
|
|
|
161
165
|
<select
|
|
162
166
|
className="form-control form-select"
|
|
163
167
|
value={breakpoints[ix]}
|
|
164
|
-
onChange={(e) =>
|
|
165
|
-
|
|
166
|
-
|
|
168
|
+
onChange={(e) => {
|
|
169
|
+
if (!e.target) return;
|
|
170
|
+
const value = e.target.value;
|
|
171
|
+
setProp((prop) => (prop.breakpoints[ix] = value));
|
|
172
|
+
}}
|
|
167
173
|
>
|
|
168
174
|
<option disabled>Breakpoint</option>
|
|
169
175
|
<option value="">None</option>
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
SettingsRow,
|
|
19
19
|
reactifyStyles,
|
|
20
20
|
bstyleopt,
|
|
21
|
+
setAPropGen,
|
|
21
22
|
} from "./utils";
|
|
22
23
|
import {
|
|
23
24
|
BorderOuter,
|
|
@@ -269,12 +270,7 @@ const ContainerSettings = () => {
|
|
|
269
270
|
* @param {string} key
|
|
270
271
|
* @returns {function}
|
|
271
272
|
*/
|
|
272
|
-
const setAProp = (
|
|
273
|
-
if (e.target) {
|
|
274
|
-
const target_value = e.target.value;
|
|
275
|
-
setProp((prop) => (prop[key] = target_value));
|
|
276
|
-
}
|
|
277
|
-
};
|
|
273
|
+
const setAProp = setAPropGen(setProp);
|
|
278
274
|
return (
|
|
279
275
|
<Accordion>
|
|
280
276
|
<div accordiontitle="Box" className="w-100">
|
|
@@ -350,9 +346,7 @@ const ContainerSettings = () => {
|
|
|
350
346
|
name="block"
|
|
351
347
|
type="checkbox"
|
|
352
348
|
checked={fullPageWidth}
|
|
353
|
-
onChange={(
|
|
354
|
-
setProp((prop) => (prop.fullPageWidth = e.target.checked))
|
|
355
|
-
}
|
|
349
|
+
onChange={setAProp("fullPageWidth", { checked: true })}
|
|
356
350
|
/>
|
|
357
351
|
<label className="form-check-label">
|
|
358
352
|
Expand to full page width
|
|
@@ -536,8 +530,10 @@ const ContainerSettings = () => {
|
|
|
536
530
|
onChange={setAProp("imgResponsiveWidths")}
|
|
537
531
|
/>
|
|
538
532
|
<small>
|
|
539
|
-
<i>
|
|
540
|
-
|
|
533
|
+
<i>
|
|
534
|
+
List of widths to serve resized images, e.g. 300, 400,
|
|
535
|
+
600
|
|
536
|
+
</i>
|
|
541
537
|
</small>
|
|
542
538
|
</td>
|
|
543
539
|
</tr>
|
|
@@ -611,9 +607,7 @@ const ContainerSettings = () => {
|
|
|
611
607
|
name="setTextColor"
|
|
612
608
|
type="checkbox"
|
|
613
609
|
checked={setTextColor}
|
|
614
|
-
onChange={(
|
|
615
|
-
setProp((prop) => (prop.setTextColor = e.target.checked))
|
|
616
|
-
}
|
|
610
|
+
onChange={setAProp("setTextColor", { checked: true })}
|
|
617
611
|
/>
|
|
618
612
|
</label>
|
|
619
613
|
</td>
|
|
@@ -782,15 +776,17 @@ const ContainerSettings = () => {
|
|
|
782
776
|
? true
|
|
783
777
|
: showForRole[id]
|
|
784
778
|
}
|
|
785
|
-
onChange={(e) =>
|
|
779
|
+
onChange={(e) => {
|
|
780
|
+
if (!e?.target) return;
|
|
781
|
+
const checked = e.target.checked;
|
|
786
782
|
setProp((prop) => {
|
|
787
783
|
if (!prop.showForRole || prop.showForRole.length === 0)
|
|
788
784
|
options.roles.forEach(
|
|
789
785
|
(r) => (prop.showForRole[r.id] = true)
|
|
790
786
|
);
|
|
791
|
-
prop.showForRole[id] =
|
|
792
|
-
})
|
|
793
|
-
}
|
|
787
|
+
prop.showForRole[id] = checked;
|
|
788
|
+
});
|
|
789
|
+
}}
|
|
794
790
|
/>
|
|
795
791
|
<label className="form-check-label">{role}</label>
|
|
796
792
|
</div>
|
|
@@ -806,11 +802,7 @@ const ContainerSettings = () => {
|
|
|
806
802
|
name="block"
|
|
807
803
|
type="checkbox"
|
|
808
804
|
checked={show_for_owner}
|
|
809
|
-
onChange={(
|
|
810
|
-
setProp(
|
|
811
|
-
(prop) => (prop.show_for_owner = e.target.checked)
|
|
812
|
-
)
|
|
813
|
-
}
|
|
805
|
+
onChange={setAProp("show_for_owner", { checked: true })}
|
|
814
806
|
/>
|
|
815
807
|
<label className="form-check-label">Owner</label>
|
|
816
808
|
</div>
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import React, { useContext, Fragment } from "react";
|
|
8
8
|
import { useNode } from "@craftjs/core";
|
|
9
9
|
import optionsCtx from "../context";
|
|
10
|
-
import { blockProps, BlockSetting, TextStyleRow } from "./utils";
|
|
10
|
+
import { blockProps, BlockSetting, TextStyleRow, setAPropGen } from "./utils";
|
|
11
11
|
|
|
12
12
|
export /**
|
|
13
13
|
* @param {object} props
|
|
@@ -59,6 +59,8 @@ const DropDownFilterSettings = () => {
|
|
|
59
59
|
where: node.data.props.where,
|
|
60
60
|
}));
|
|
61
61
|
const options = useContext(optionsCtx);
|
|
62
|
+
const setAProp = setAPropGen(setProp);
|
|
63
|
+
|
|
62
64
|
return (
|
|
63
65
|
<table className="w-100">
|
|
64
66
|
<tbody>
|
|
@@ -70,7 +72,7 @@ const DropDownFilterSettings = () => {
|
|
|
70
72
|
<select
|
|
71
73
|
value={name}
|
|
72
74
|
className="form-control form-select"
|
|
73
|
-
onChange={(
|
|
75
|
+
onChange={setAProp("name")}
|
|
74
76
|
>
|
|
75
77
|
{options.fields.map((f, ix) => (
|
|
76
78
|
<option key={ix} value={f.name}>
|
|
@@ -88,9 +90,7 @@ const DropDownFilterSettings = () => {
|
|
|
88
90
|
<input
|
|
89
91
|
value={neutral_label}
|
|
90
92
|
className="form-control"
|
|
91
|
-
onChange={(
|
|
92
|
-
setProp((prop) => (prop.neutral_label = e.target.value))
|
|
93
|
-
}
|
|
93
|
+
onChange={setAProp("neutral_label")}
|
|
94
94
|
/>
|
|
95
95
|
</td>
|
|
96
96
|
</tr>
|
|
@@ -102,7 +102,7 @@ const DropDownFilterSettings = () => {
|
|
|
102
102
|
<input
|
|
103
103
|
value={where}
|
|
104
104
|
className="form-control"
|
|
105
|
-
onChange={(
|
|
105
|
+
onChange={setAProp("where")}
|
|
106
106
|
/>
|
|
107
107
|
</td>
|
|
108
108
|
</tr>
|
|
@@ -121,9 +121,7 @@ const DropDownFilterSettings = () => {
|
|
|
121
121
|
name="block"
|
|
122
122
|
type="checkbox"
|
|
123
123
|
checked={full_width}
|
|
124
|
-
onChange={(
|
|
125
|
-
setProp((prop) => (prop.full_width = e.target.checked))
|
|
126
|
-
}
|
|
124
|
+
onChange={setAProp("full_width", { checked: true })}
|
|
127
125
|
/>
|
|
128
126
|
<label className="form-check-label">Full width</label>
|
|
129
127
|
</div>
|
|
@@ -134,8 +132,8 @@ const DropDownFilterSettings = () => {
|
|
|
134
132
|
);
|
|
135
133
|
};
|
|
136
134
|
|
|
137
|
-
/**
|
|
138
|
-
* @type {object}
|
|
135
|
+
/**
|
|
136
|
+
* @type {object}
|
|
139
137
|
*/
|
|
140
138
|
DropDownFilter.craft = {
|
|
141
139
|
displayName: "DropDownFilter",
|
|
@@ -140,15 +140,17 @@ const FieldSettings = () => {
|
|
|
140
140
|
value={name}
|
|
141
141
|
className="form-control form-select"
|
|
142
142
|
onChange={(e) => {
|
|
143
|
-
|
|
144
|
-
const
|
|
143
|
+
if (!e.target) return;
|
|
144
|
+
const value = e.target.value;
|
|
145
|
+
setProp((prop) => (prop.name = value));
|
|
146
|
+
const newfvs = options.field_view_options[value];
|
|
145
147
|
if (newfvs && newfvs.length > 0) {
|
|
146
148
|
setProp((prop) => (prop.fieldview = newfvs[0]));
|
|
147
149
|
refetchPreview({
|
|
148
|
-
name:
|
|
150
|
+
name: value,
|
|
149
151
|
fieldview: newfvs[0],
|
|
150
152
|
});
|
|
151
|
-
} else refetchPreview({ name:
|
|
153
|
+
} else refetchPreview({ name: value });
|
|
152
154
|
}}
|
|
153
155
|
>
|
|
154
156
|
{options.fields.map((f, ix) => (
|
|
@@ -170,13 +172,12 @@ const FieldSettings = () => {
|
|
|
170
172
|
value={fieldview}
|
|
171
173
|
className="form-control form-select"
|
|
172
174
|
onChange={(e) => {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
);
|
|
179
|
-
refetchPreview({ fieldview: e.target.value });
|
|
175
|
+
if (!e.target) return;
|
|
176
|
+
const value = e.target.value;
|
|
177
|
+
|
|
178
|
+
setProp((prop) => (prop.fieldview = value));
|
|
179
|
+
setInitialConfig(setProp, value, getCfgFields(value));
|
|
180
|
+
refetchPreview({ fieldview: value });
|
|
180
181
|
}}
|
|
181
182
|
>
|
|
182
183
|
{(fvs || []).map((fvnm, ix) => (
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
reactifyStyles,
|
|
17
17
|
Accordion,
|
|
18
18
|
OrFormula,
|
|
19
|
+
setAPropGen,
|
|
19
20
|
} from "./utils";
|
|
20
21
|
|
|
21
22
|
export /**
|
|
@@ -120,12 +121,7 @@ const ImageSettings = () => {
|
|
|
120
121
|
});
|
|
121
122
|
}
|
|
122
123
|
};
|
|
123
|
-
const setAProp = (
|
|
124
|
-
if (e.target) {
|
|
125
|
-
const target_value = e.target.value;
|
|
126
|
-
setProp((prop) => (prop[key] = target_value));
|
|
127
|
-
}
|
|
128
|
-
};
|
|
124
|
+
const setAProp = setAPropGen(setProp);
|
|
129
125
|
return (
|
|
130
126
|
<Accordion>
|
|
131
127
|
<table accordiontitle="Select image">
|
|
@@ -256,7 +252,7 @@ const ImageSettings = () => {
|
|
|
256
252
|
)}
|
|
257
253
|
{srctype !== "Upload" && (
|
|
258
254
|
<tr>
|
|
259
|
-
<td>
|
|
255
|
+
<td style={{ verticalAlign: "top" }}>
|
|
260
256
|
<label>Responsive widths</label>
|
|
261
257
|
</td>
|
|
262
258
|
|
|
@@ -122,15 +122,17 @@ const JoinFieldSettings = () => {
|
|
|
122
122
|
value={name}
|
|
123
123
|
className="form-control form-select"
|
|
124
124
|
onChange={(e) => {
|
|
125
|
-
|
|
126
|
-
const
|
|
125
|
+
if (!e.target) return;
|
|
126
|
+
const value = e.target.value;
|
|
127
|
+
setProp((prop) => (prop.name = value));
|
|
128
|
+
const newfvs = options.field_view_options[value];
|
|
127
129
|
if (newfvs && newfvs.length > 0) {
|
|
128
130
|
setProp((prop) => (prop.fieldview = newfvs[0]));
|
|
129
131
|
refetchPreview({
|
|
130
|
-
name:
|
|
132
|
+
name: value,
|
|
131
133
|
fieldview: newfvs[0],
|
|
132
134
|
});
|
|
133
|
-
} else refetchPreview({ name:
|
|
135
|
+
} else refetchPreview({ name: value });
|
|
134
136
|
}}
|
|
135
137
|
>
|
|
136
138
|
{options.parent_field_list.map((f, ix) => (
|
|
@@ -152,8 +154,10 @@ const JoinFieldSettings = () => {
|
|
|
152
154
|
value={fieldview}
|
|
153
155
|
className="form-control form-select"
|
|
154
156
|
onChange={(e) => {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
+
if (!e.target) return;
|
|
158
|
+
const value = e.target.value;
|
|
159
|
+
setProp((prop) => (prop.fieldview = value));
|
|
160
|
+
refetchPreview({ fieldview: value });
|
|
157
161
|
}}
|
|
158
162
|
>
|
|
159
163
|
{(fvs || []).map((fvnm, ix) => (
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
OrFormula,
|
|
14
14
|
ButtonOrLinkSettingsRows,
|
|
15
15
|
DynamicFontAwesomeIcon,
|
|
16
|
+
setAPropGen,
|
|
16
17
|
} from "./utils";
|
|
17
18
|
import optionsCtx from "../context";
|
|
18
19
|
|
|
@@ -111,12 +112,7 @@ const LinkSettings = () => {
|
|
|
111
112
|
transfer_state,
|
|
112
113
|
} = node;
|
|
113
114
|
const options = useContext(optionsCtx);
|
|
114
|
-
const setAProp = (
|
|
115
|
-
if (e.target) {
|
|
116
|
-
const target_value = e.target.value;
|
|
117
|
-
setProp((prop) => (prop[key] = target_value));
|
|
118
|
-
}
|
|
119
|
-
};
|
|
115
|
+
const setAProp = setAPropGen(setProp);
|
|
120
116
|
return (
|
|
121
117
|
<div>
|
|
122
118
|
<table className="w-100">
|
|
@@ -144,14 +140,16 @@ const LinkSettings = () => {
|
|
|
144
140
|
<select
|
|
145
141
|
value={link_src}
|
|
146
142
|
className="form-control form-select"
|
|
147
|
-
onChange={(e) =>
|
|
143
|
+
onChange={(e) => {
|
|
144
|
+
if (!e.target) return;
|
|
145
|
+
const value = e.target.value;
|
|
148
146
|
setProp((prop) => {
|
|
149
|
-
prop.link_src =
|
|
147
|
+
prop.link_src = value;
|
|
150
148
|
if (e.target.value !== "URL") {
|
|
151
149
|
prop.isFormula.url = false;
|
|
152
150
|
}
|
|
153
|
-
})
|
|
154
|
-
}
|
|
151
|
+
});
|
|
152
|
+
}}
|
|
155
153
|
>
|
|
156
154
|
<option>URL</option>
|
|
157
155
|
{(options.pages || []).length > 0 && <option>Page</option>}
|
|
@@ -237,9 +235,7 @@ const LinkSettings = () => {
|
|
|
237
235
|
name="block"
|
|
238
236
|
type="checkbox"
|
|
239
237
|
checked={nofollow}
|
|
240
|
-
onChange={(
|
|
241
|
-
setProp((prop) => (prop.nofollow = e.target.checked))
|
|
242
|
-
}
|
|
238
|
+
onChange={setAProp("nofollow", { checked: true })}
|
|
243
239
|
/>
|
|
244
240
|
<label className="form-check-label">Nofollow</label>
|
|
245
241
|
</div>
|
|
@@ -249,9 +245,7 @@ const LinkSettings = () => {
|
|
|
249
245
|
name="block"
|
|
250
246
|
type="checkbox"
|
|
251
247
|
checked={target_blank}
|
|
252
|
-
onChange={(
|
|
253
|
-
setProp((prop) => (prop.target_blank = e.target.checked))
|
|
254
|
-
}
|
|
248
|
+
onChange={setAProp("target_blank", { checked: true })}
|
|
255
249
|
/>
|
|
256
250
|
<label className="form-check-label">Open in new tab</label>
|
|
257
251
|
</div>
|
|
@@ -261,9 +255,7 @@ const LinkSettings = () => {
|
|
|
261
255
|
name="block"
|
|
262
256
|
type="checkbox"
|
|
263
257
|
checked={in_modal}
|
|
264
|
-
onChange={(
|
|
265
|
-
setProp((prop) => (prop.in_modal = e.target.checked))
|
|
266
|
-
}
|
|
258
|
+
onChange={setAProp("in_modal", { checked: true })}
|
|
267
259
|
/>
|
|
268
260
|
<label className="form-check-label">Open in popup modal?</label>
|
|
269
261
|
</div>
|
|
@@ -275,9 +267,7 @@ const LinkSettings = () => {
|
|
|
275
267
|
name="block"
|
|
276
268
|
type="checkbox"
|
|
277
269
|
checked={transfer_state}
|
|
278
|
-
onChange={(
|
|
279
|
-
setProp((prop) => (prop.transfer_state = e.target.checked))
|
|
280
|
-
}
|
|
270
|
+
onChange={setAProp("transfer_state", { checked: true })}
|
|
281
271
|
/>
|
|
282
272
|
<label className="form-check-label">Transfer state</label>
|
|
283
273
|
</div>
|
|
@@ -9,6 +9,7 @@ import { Element, useNode } from "@craftjs/core";
|
|
|
9
9
|
import { Column } from "./Column";
|
|
10
10
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
11
11
|
import { faCaretDown } from "@fortawesome/free-solid-svg-icons";
|
|
12
|
+
import { setAPropGen } from "./utils";
|
|
12
13
|
|
|
13
14
|
export /**
|
|
14
15
|
* @param {object} props
|
|
@@ -92,6 +93,7 @@ const SearchBarSettings = () => {
|
|
|
92
93
|
has_dropdown: node.data.props.has_dropdown,
|
|
93
94
|
show_badges: node.data.props.show_badges,
|
|
94
95
|
}));
|
|
96
|
+
const setAProp = setAPropGen(setProp);
|
|
95
97
|
|
|
96
98
|
return (
|
|
97
99
|
<div>
|
|
@@ -101,9 +103,7 @@ const SearchBarSettings = () => {
|
|
|
101
103
|
name="block"
|
|
102
104
|
type="checkbox"
|
|
103
105
|
checked={has_dropdown}
|
|
104
|
-
onChange={(
|
|
105
|
-
setProp((prop) => (prop.has_dropdown = e.target.checked))
|
|
106
|
-
}
|
|
106
|
+
onChange={setAProp("has_dropdown", { checked: true })}
|
|
107
107
|
/>
|
|
108
108
|
<label className="form-check-label">Has Dropdown</label>
|
|
109
109
|
</div>
|
|
@@ -113,9 +113,7 @@ const SearchBarSettings = () => {
|
|
|
113
113
|
name="block"
|
|
114
114
|
type="checkbox"
|
|
115
115
|
checked={show_badges}
|
|
116
|
-
onChange={(
|
|
117
|
-
setProp((prop) => (prop.show_badges = e.target.checked))
|
|
118
|
-
}
|
|
116
|
+
onChange={setAProp("show_badges", { checked: true })}
|
|
119
117
|
/>
|
|
120
118
|
<label className="form-check-label">Show current state badges</label>
|
|
121
119
|
</div>
|