@saltcorn/builder 1.0.0-beta.9 → 1.0.0-rc.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/dist/builder_bundle.js +13 -13
- package/package.json +2 -2
- package/src/components/Builder.js +45 -1
- package/src/components/Toolbox.js +5 -1
- package/src/components/elements/Action.js +53 -14
- package/src/components/elements/Aggregation.js +11 -1
- package/src/components/elements/Container.js +1 -1
- package/src/components/elements/utils.js +2 -2
- package/src/components/storage.js +32 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/builder",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-rc.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",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@babel/preset-react": "7.24.7",
|
|
21
21
|
"@craftjs/core": "0.1.0-beta.20",
|
|
22
22
|
"@craftjs/utils": "0.1.0-beta.20",
|
|
23
|
-
"@saltcorn/common-code": "1.0.0-
|
|
23
|
+
"@saltcorn/common-code": "1.0.0-rc.2",
|
|
24
24
|
"saltcorn-craft-layers-noeye": "0.1.0-beta.22",
|
|
25
25
|
"@fonticonpicker/react-fonticonpicker": "1.2.0",
|
|
26
26
|
"@fortawesome/fontawesome-svg-core": "1.2.34",
|
|
@@ -257,6 +257,32 @@ const SettingsPanel = () => {
|
|
|
257
257
|
);
|
|
258
258
|
};
|
|
259
259
|
|
|
260
|
+
// https://stackoverflow.com/questions/36862334/get-viewport-window-height-in-reactjs
|
|
261
|
+
function getWindowDimensions() {
|
|
262
|
+
const { innerWidth: windowWidth, innerHeight: windowHeight } = window;
|
|
263
|
+
return {
|
|
264
|
+
windowWidth,
|
|
265
|
+
windowHeight,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function useWindowDimensions() {
|
|
270
|
+
const [windowDimensions, setWindowDimensions] = useState(
|
|
271
|
+
getWindowDimensions()
|
|
272
|
+
);
|
|
273
|
+
|
|
274
|
+
useEffect(() => {
|
|
275
|
+
function handleResize() {
|
|
276
|
+
setWindowDimensions(getWindowDimensions());
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
window.addEventListener("resize", handleResize);
|
|
280
|
+
return () => window.removeEventListener("resize", handleResize);
|
|
281
|
+
}, []);
|
|
282
|
+
|
|
283
|
+
return windowDimensions;
|
|
284
|
+
}
|
|
285
|
+
|
|
260
286
|
const AddColumnButton = () => {
|
|
261
287
|
const { query, actions } = useEditor(() => {});
|
|
262
288
|
const options = useContext(optionsCtx);
|
|
@@ -369,6 +395,23 @@ const Builder = ({ options, layout, mode }) => {
|
|
|
369
395
|
const [isEnlarged, setIsEnlarged] = useState(false);
|
|
370
396
|
const [isLeftEnlarged, setIsLeftEnlarged] = useState(false);
|
|
371
397
|
const [relationsCache, setRelationsCache] = useState({});
|
|
398
|
+
const { windowWidth, windowHeight } = useWindowDimensions();
|
|
399
|
+
|
|
400
|
+
const [builderHeight, setBuilderHeight] = useState(0);
|
|
401
|
+
const [builderTop, setBuilderTop] = useState(0);
|
|
402
|
+
|
|
403
|
+
const ref = useRef(null);
|
|
404
|
+
|
|
405
|
+
useEffect(() => {
|
|
406
|
+
if (!ref.current) return;
|
|
407
|
+
setBuilderHeight(ref.current.clientHeight);
|
|
408
|
+
const rect = ref.current.getBoundingClientRect();
|
|
409
|
+
setBuilderTop(rect.top);
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
const canvasHeight =
|
|
413
|
+
Math.max(windowHeight - builderTop, builderHeight, 600) - 10;
|
|
414
|
+
|
|
372
415
|
return (
|
|
373
416
|
<ErrorBoundary>
|
|
374
417
|
<Editor onRender={RenderNode}>
|
|
@@ -382,7 +425,7 @@ const Builder = ({ options, layout, mode }) => {
|
|
|
382
425
|
setRelationsCache,
|
|
383
426
|
}}
|
|
384
427
|
>
|
|
385
|
-
<div className="row" style={{ marginTop: "-5px" }}>
|
|
428
|
+
<div className="row" ref={ref} style={{ marginTop: "-5px" }}>
|
|
386
429
|
<div
|
|
387
430
|
className={`col-sm-auto left-builder-col ${
|
|
388
431
|
isLeftEnlarged
|
|
@@ -437,6 +480,7 @@ const Builder = ({ options, layout, mode }) => {
|
|
|
437
480
|
</div>
|
|
438
481
|
<div
|
|
439
482
|
id="builder-main-canvas"
|
|
483
|
+
style={{ height: canvasHeight }}
|
|
440
484
|
className={`col builder-mode-${options.mode} ${
|
|
441
485
|
options.mode !== "list" ? "emptymsg" : ""
|
|
442
486
|
}`}
|
|
@@ -457,7 +457,11 @@ const ActionElem = ({ connectors, options }) => (
|
|
|
457
457
|
title="Action button"
|
|
458
458
|
>
|
|
459
459
|
<Action
|
|
460
|
-
name={
|
|
460
|
+
name={
|
|
461
|
+
options.actions[0].optgroup
|
|
462
|
+
? options.actions[0].options[0]
|
|
463
|
+
: options.actions[0]
|
|
464
|
+
}
|
|
461
465
|
action_row_variable={""}
|
|
462
466
|
block={false}
|
|
463
467
|
minRole={100}
|
|
@@ -142,7 +142,16 @@ const ActionSettings = () => {
|
|
|
142
142
|
name === "Multi-step action"
|
|
143
143
|
? getCfgFields(step_action_names?.[use_setting_action_n])
|
|
144
144
|
: null;
|
|
145
|
-
|
|
145
|
+
const cfg_link = (options.triggerActions || []).includes(name)
|
|
146
|
+
? `/actions/configure/${encodeURIComponent(name)}`
|
|
147
|
+
: name === "Multi-step action" &&
|
|
148
|
+
(options.triggerActions || []).includes(
|
|
149
|
+
step_action_names?.[use_setting_action_n]
|
|
150
|
+
)
|
|
151
|
+
? `/actions/configure/${encodeURIComponent(
|
|
152
|
+
step_action_names?.[use_setting_action_n]
|
|
153
|
+
)}`
|
|
154
|
+
: "";
|
|
146
155
|
return (
|
|
147
156
|
<div>
|
|
148
157
|
<table className="w-100">
|
|
@@ -185,14 +194,21 @@ const ActionSettings = () => {
|
|
|
185
194
|
setInitialConfig(setProp, value, getCfgFields(value));
|
|
186
195
|
}}
|
|
187
196
|
>
|
|
188
|
-
{options.actions.map((f, ix) =>
|
|
189
|
-
|
|
190
|
-
{f}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
197
|
+
{options.actions.map((f, ix) =>
|
|
198
|
+
f.optgroup && !f.options.length ? null : f.optgroup ? (
|
|
199
|
+
<optgroup key={ix} label={f.label}>
|
|
200
|
+
{f.options.map((a, jx) => (
|
|
201
|
+
<option key={jx} value={a}>
|
|
202
|
+
{a}
|
|
203
|
+
</option>
|
|
204
|
+
))}
|
|
205
|
+
</optgroup>
|
|
206
|
+
) : (
|
|
207
|
+
<option key={ix} value={f}>
|
|
208
|
+
{f}
|
|
209
|
+
</option>
|
|
210
|
+
)
|
|
211
|
+
)}
|
|
196
212
|
</select>
|
|
197
213
|
</td>
|
|
198
214
|
</tr>
|
|
@@ -355,11 +371,29 @@ const ActionSettings = () => {
|
|
|
355
371
|
</option>
|
|
356
372
|
{options.actions
|
|
357
373
|
.filter((f) => !(options.builtInActions || []).includes(f))
|
|
358
|
-
.map((f, ix) =>
|
|
359
|
-
|
|
360
|
-
{f}
|
|
361
|
-
|
|
362
|
-
|
|
374
|
+
.map((f, ix) =>
|
|
375
|
+
f.optgroup ? (
|
|
376
|
+
<optgroup key={ix} label={f.label}>
|
|
377
|
+
{f.options
|
|
378
|
+
.filter(
|
|
379
|
+
(f) =>
|
|
380
|
+
![
|
|
381
|
+
"Multi-step action",
|
|
382
|
+
...(options.builtInActions || []),
|
|
383
|
+
].includes(f)
|
|
384
|
+
)
|
|
385
|
+
.map((a, jx) => (
|
|
386
|
+
<option key={jx} value={a}>
|
|
387
|
+
{a}
|
|
388
|
+
</option>
|
|
389
|
+
))}
|
|
390
|
+
</optgroup>
|
|
391
|
+
) : (
|
|
392
|
+
<option key={ix} value={f}>
|
|
393
|
+
{f}
|
|
394
|
+
</option>
|
|
395
|
+
)
|
|
396
|
+
)}
|
|
363
397
|
</select>
|
|
364
398
|
{options.mode !== "page" ? (
|
|
365
399
|
<Fragment>
|
|
@@ -407,6 +441,11 @@ const ActionSettings = () => {
|
|
|
407
441
|
node={node}
|
|
408
442
|
/>
|
|
409
443
|
) : null}
|
|
444
|
+
{cfg_link ? (
|
|
445
|
+
<a className="d-block mt-2" target="_blank" href={cfg_link}>
|
|
446
|
+
Configure this action
|
|
447
|
+
</a>
|
|
448
|
+
) : null}
|
|
410
449
|
</div>
|
|
411
450
|
);
|
|
412
451
|
};
|
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
setAPropGen,
|
|
15
15
|
buildOptions,
|
|
16
16
|
ConfigForm,
|
|
17
|
+
HelpTopicLink,
|
|
17
18
|
} from "./utils";
|
|
18
19
|
|
|
19
20
|
export /**
|
|
@@ -215,7 +216,16 @@ const AggregationSettings = () => {
|
|
|
215
216
|
</tr>
|
|
216
217
|
<tr>
|
|
217
218
|
<td>
|
|
218
|
-
<label>
|
|
219
|
+
<label>
|
|
220
|
+
Where
|
|
221
|
+
<HelpTopicLink
|
|
222
|
+
topic="Aggregation where formula"
|
|
223
|
+
table_name={options.tableName}
|
|
224
|
+
mode={options.mode}
|
|
225
|
+
agg_relation={agg_relation}
|
|
226
|
+
agg_field={agg_field}
|
|
227
|
+
></HelpTopicLink>
|
|
228
|
+
</label>
|
|
219
229
|
</td>
|
|
220
230
|
<td>
|
|
221
231
|
<input
|
|
@@ -118,7 +118,7 @@ const Container = ({
|
|
|
118
118
|
htmlElement,
|
|
119
119
|
{
|
|
120
120
|
ref: (dom) => connect(drag(dom)),
|
|
121
|
-
className: `${customClass || ""} canvas text-${hAlign} ${
|
|
121
|
+
className: `${customClass || ""} container canvas text-${hAlign} ${
|
|
122
122
|
vAlign === "middle" ? "d-flex align-items-center" : ""
|
|
123
123
|
} ${
|
|
124
124
|
vAlign === "middle" && hAlign === "center" && "justify-content-center"
|
|
@@ -677,7 +677,7 @@ const ConfigForm = ({
|
|
|
677
677
|
if (noshow) return null;
|
|
678
678
|
}
|
|
679
679
|
return (
|
|
680
|
-
<div key={ix} className="builder-config-field">
|
|
680
|
+
<div key={ix} className="builder-config-field" data-field-name={f.name}>
|
|
681
681
|
{!isCheckbox(f) ? (
|
|
682
682
|
<label>
|
|
683
683
|
{f.label || f.name}
|
|
@@ -783,7 +783,7 @@ const ConfigField = ({
|
|
|
783
783
|
field.options =
|
|
784
784
|
typeof field.attributes?.options === "string"
|
|
785
785
|
? field.attributes?.options.split(",").map((s) => s.trim())
|
|
786
|
-
: field.attributes?.options;
|
|
786
|
+
: [...field.attributes?.options];
|
|
787
787
|
if (!field.required && field.options) field.options.unshift("");
|
|
788
788
|
}
|
|
789
789
|
const field_type = field.input_type || field.type.name || field.type;
|
|
@@ -127,15 +127,25 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT", options) => {
|
|
|
127
127
|
props.isFormula = segment.isFormula;
|
|
128
128
|
if (related.hasContents)
|
|
129
129
|
return (
|
|
130
|
-
<Element
|
|
130
|
+
<Element
|
|
131
|
+
key={ix}
|
|
132
|
+
canvas
|
|
133
|
+
{...props}
|
|
134
|
+
is={MatchElement}
|
|
135
|
+
custom={segment._custom || {}}
|
|
136
|
+
>
|
|
131
137
|
{toTag(segment.contents)}
|
|
132
138
|
</Element>
|
|
133
139
|
);
|
|
134
|
-
else
|
|
140
|
+
else
|
|
141
|
+
return (
|
|
142
|
+
<MatchElement key={ix} custom={segment._custom || {}} {...props} />
|
|
143
|
+
);
|
|
135
144
|
}
|
|
136
145
|
if (segment.type === "blank") {
|
|
137
146
|
return (
|
|
138
147
|
<Text
|
|
148
|
+
custom={segment._custom || {}}
|
|
139
149
|
key={ix}
|
|
140
150
|
text={segment.contents}
|
|
141
151
|
isFormula={segment.isFormula || {}}
|
|
@@ -151,6 +161,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT", options) => {
|
|
|
151
161
|
} else if (segment.type === "view") {
|
|
152
162
|
return (
|
|
153
163
|
<View
|
|
164
|
+
custom={segment._custom || {}}
|
|
154
165
|
key={ix}
|
|
155
166
|
view={segment.view}
|
|
156
167
|
relation={segment.relation}
|
|
@@ -165,6 +176,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT", options) => {
|
|
|
165
176
|
} else if (segment.type === "action") {
|
|
166
177
|
return (
|
|
167
178
|
<Action
|
|
179
|
+
custom={segment._custom || {}}
|
|
168
180
|
key={ix}
|
|
169
181
|
name={segment.action_name}
|
|
170
182
|
rndid={segment.rndid || "not_assigned"}
|
|
@@ -193,6 +205,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT", options) => {
|
|
|
193
205
|
return (
|
|
194
206
|
<Element
|
|
195
207
|
key={ix}
|
|
208
|
+
custom={segment._custom || {}}
|
|
196
209
|
canvas
|
|
197
210
|
gradStartColor={segment.gradStartColor}
|
|
198
211
|
gradEndColor={segment.gradEndColor}
|
|
@@ -259,6 +272,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT", options) => {
|
|
|
259
272
|
return (
|
|
260
273
|
<Tabs
|
|
261
274
|
key={ix}
|
|
275
|
+
custom={segment._custom || {}}
|
|
262
276
|
titles={segment.titles}
|
|
263
277
|
showif={segment.showif}
|
|
264
278
|
ntabs={segment.ntabs}
|
|
@@ -278,6 +292,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT", options) => {
|
|
|
278
292
|
return (
|
|
279
293
|
<Table
|
|
280
294
|
key={ix}
|
|
295
|
+
custom={segment._custom || {}}
|
|
281
296
|
rows={segment.rows || 2}
|
|
282
297
|
columns={segment.columns || 2}
|
|
283
298
|
bs_style={segment.bs_style || false}
|
|
@@ -301,6 +316,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT", options) => {
|
|
|
301
316
|
});
|
|
302
317
|
return (
|
|
303
318
|
<ListColumn
|
|
319
|
+
custom={segment._custom || {}}
|
|
304
320
|
key={jx}
|
|
305
321
|
alignment={col.alignment}
|
|
306
322
|
header_label={col.header_label}
|
|
@@ -316,6 +332,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT", options) => {
|
|
|
316
332
|
return (
|
|
317
333
|
<Columns
|
|
318
334
|
key={ix}
|
|
335
|
+
custom={segment._custom || {}}
|
|
319
336
|
breakpoints={segment.breakpoints || default_breakpoints(segment)}
|
|
320
337
|
ncols={segment.besides.length}
|
|
321
338
|
widths={getColWidths(segment)}
|
|
@@ -423,6 +440,9 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
423
440
|
*/
|
|
424
441
|
const go = (node) => {
|
|
425
442
|
if (!node) return;
|
|
443
|
+
let customProps = {};
|
|
444
|
+
if (Object.keys(node?.custom || {}).length)
|
|
445
|
+
customProps = { _custom: { ...node?.custom } };
|
|
426
446
|
const matchElement = allElements.find(
|
|
427
447
|
(e) =>
|
|
428
448
|
e.craft.related &&
|
|
@@ -432,7 +452,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
432
452
|
);
|
|
433
453
|
if (matchElement) {
|
|
434
454
|
const related = matchElement.craft.related;
|
|
435
|
-
const s = { type: related.segment_type };
|
|
455
|
+
const s = { type: related.segment_type, ...customProps };
|
|
436
456
|
if (related.hasContents) s.contents = get_nodes(node);
|
|
437
457
|
related.fields.forEach((f) => {
|
|
438
458
|
if (f.type === "Nodes" && f.nodeID) {
|
|
@@ -459,6 +479,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
459
479
|
return {
|
|
460
480
|
besides: node.nodes.map((nm) => go(nodes[nm])),
|
|
461
481
|
list_columns: true,
|
|
482
|
+
...customProps,
|
|
462
483
|
};
|
|
463
484
|
}
|
|
464
485
|
if (node.displayName === ListColumn.craft.displayName) {
|
|
@@ -471,6 +492,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
471
492
|
alignment: node.props.alignment,
|
|
472
493
|
header_label: node.props.header_label,
|
|
473
494
|
showif: node.props.showif,
|
|
495
|
+
...customProps,
|
|
474
496
|
};
|
|
475
497
|
(addFields || []).forEach((f) => {
|
|
476
498
|
lc[f.name] = node.props[f.name];
|
|
@@ -519,6 +541,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
519
541
|
click_action: node.props.click_action,
|
|
520
542
|
rotate: node.props.rotate,
|
|
521
543
|
style: node.props.style,
|
|
544
|
+
...customProps,
|
|
522
545
|
};
|
|
523
546
|
else return get_nodes(node);
|
|
524
547
|
}
|
|
@@ -535,6 +558,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
535
558
|
style: node.props.style,
|
|
536
559
|
icon: node.props.icon,
|
|
537
560
|
font: node.props.font,
|
|
561
|
+
...customProps,
|
|
538
562
|
};
|
|
539
563
|
}
|
|
540
564
|
|
|
@@ -556,6 +580,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
556
580
|
bs_bordered: node.props.bs_bordered,
|
|
557
581
|
bs_borderless: node.props.bs_borderless,
|
|
558
582
|
bs_wauto: node.props.bs_wauto,
|
|
583
|
+
...customProps,
|
|
559
584
|
};
|
|
560
585
|
}
|
|
561
586
|
|
|
@@ -572,6 +597,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
572
597
|
colStyles: node.props.colStyles,
|
|
573
598
|
style: node.props.style,
|
|
574
599
|
widths,
|
|
600
|
+
...customProps,
|
|
575
601
|
};
|
|
576
602
|
}
|
|
577
603
|
if (node.displayName === Tabs.craft.displayName) {
|
|
@@ -600,6 +626,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
600
626
|
serverRendered: node.props.serverRendered,
|
|
601
627
|
tabId: node.props.tabId,
|
|
602
628
|
ntabs: node.props.ntabs,
|
|
629
|
+
...customProps,
|
|
603
630
|
};
|
|
604
631
|
}
|
|
605
632
|
|
|
@@ -614,6 +641,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
614
641
|
state: node.props.state,
|
|
615
642
|
configuration: node.props.configuration,
|
|
616
643
|
extra_state_fml: node.props.extra_state_fml,
|
|
644
|
+
...customProps,
|
|
617
645
|
};
|
|
618
646
|
}
|
|
619
647
|
if (node.displayName === Action.craft.displayName) {
|
|
@@ -672,6 +700,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
672
700
|
minRole: node.props.minRole,
|
|
673
701
|
isFormula: node.props.isFormula,
|
|
674
702
|
rndid: node.props.rndid === "not_assigned" ? newid : node.props.rndid,
|
|
703
|
+
...customProps,
|
|
675
704
|
};
|
|
676
705
|
}
|
|
677
706
|
};
|