@saltcorn/builder 1.6.0-alpha.1 → 1.6.0-alpha.11
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 +85 -1
- package/dist/builder_bundle.js.LICENSE.txt +18 -51
- package/package.json +31 -27
- package/src/components/Builder.js +445 -155
- package/src/components/Library.js +25 -13
- package/src/components/RenderNode.js +26 -8
- package/src/components/Toolbox.js +333 -269
- package/src/components/elements/Action.js +144 -29
- package/src/components/elements/Aggregation.js +20 -23
- package/src/components/elements/ArrayManager.js +17 -10
- package/src/components/elements/BoxModelEditor.js +19 -17
- package/src/components/elements/Card.js +47 -34
- package/src/components/elements/Clone.js +74 -2
- package/src/components/elements/Column.js +1 -1
- package/src/components/elements/Columns.js +130 -121
- package/src/components/elements/Container.js +185 -92
- package/src/components/elements/DropDownFilter.js +10 -8
- package/src/components/elements/DropMenu.js +18 -9
- package/src/components/elements/Field.js +9 -7
- package/src/components/elements/HTMLCode.js +3 -1
- package/src/components/elements/Image.js +20 -15
- package/src/components/elements/JoinField.js +15 -11
- package/src/components/elements/Link.js +18 -16
- package/src/components/elements/ListColumn.js +7 -3
- package/src/components/elements/ListColumns.js +4 -1
- package/src/components/elements/MonacoEditor.js +4 -2
- package/src/components/elements/Page.js +7 -4
- package/src/components/elements/RelationBadges.js +16 -11
- package/src/components/elements/RelationOnDemandPicker.js +18 -12
- package/src/components/elements/SearchBar.js +37 -10
- package/src/components/elements/Table.js +72 -65
- package/src/components/elements/Tabs.js +18 -15
- package/src/components/elements/Text.js +19 -14
- package/src/components/elements/ToggleFilter.js +28 -25
- package/src/components/elements/View.js +36 -18
- package/src/components/elements/ViewLink.js +15 -11
- package/src/components/elements/utils.js +224 -55
- package/src/components/storage.js +33 -134
- package/src/hooks/useTranslation.js +11 -0
- package/src/index.js +6 -3
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
* @module components/elements/Action
|
|
4
4
|
* @subcategory components / elements
|
|
5
5
|
*/
|
|
6
|
-
/*global notifyAlert*/
|
|
6
|
+
/*global notifyAlert, apply_showif*/
|
|
7
7
|
|
|
8
|
-
import React, { Fragment, useContext, useEffect } from "react";
|
|
8
|
+
import React, { Fragment, useContext, useEffect, useState } from "react";
|
|
9
9
|
import { useNode } from "@craftjs/core";
|
|
10
|
+
import useTranslation from "../../hooks/useTranslation";
|
|
10
11
|
import optionsCtx from "../context";
|
|
11
12
|
import {
|
|
12
13
|
BlockSetting,
|
|
@@ -19,9 +20,12 @@ import {
|
|
|
19
20
|
setAPropGen,
|
|
20
21
|
buildOptions,
|
|
21
22
|
ConfigField,
|
|
23
|
+
reactSelectStyles,
|
|
24
|
+
builderSelectClassName,
|
|
22
25
|
} from "./utils";
|
|
23
26
|
import { ntimes } from "./Columns";
|
|
24
27
|
import { ArrayManager } from "./ArrayManager";
|
|
28
|
+
import { MultiLineCodeEditor } from "./MonacoEditor";
|
|
25
29
|
import Select from "react-select";
|
|
26
30
|
|
|
27
31
|
export /**
|
|
@@ -91,6 +95,7 @@ export /**
|
|
|
91
95
|
* @returns {div}
|
|
92
96
|
*/
|
|
93
97
|
const ActionSettings = () => {
|
|
98
|
+
const { t } = useTranslation();
|
|
94
99
|
const node = useNode((node) => ({
|
|
95
100
|
name: node.data.props.name,
|
|
96
101
|
action_row_variable: node.data.props.action_row_variable,
|
|
@@ -141,6 +146,13 @@ const ActionSettings = () => {
|
|
|
141
146
|
const options = useContext(optionsCtx);
|
|
142
147
|
const getCfgFields = (fv) => (options.actionConfigForms || {})[fv];
|
|
143
148
|
const cfgFields = getCfgFields(name);
|
|
149
|
+
const cfgFieldsForForm =
|
|
150
|
+
name === "run_js_code"
|
|
151
|
+
? (cfgFields || []).filter((f) => f.name !== "code")
|
|
152
|
+
: cfgFields;
|
|
153
|
+
|
|
154
|
+
const runJsCodeModalOnly = false;
|
|
155
|
+
const [codeModalOpen, setCodeModalOpen] = useState(false);
|
|
144
156
|
const setAProp = setAPropGen(setProp);
|
|
145
157
|
const use_setting_action_n =
|
|
146
158
|
setting_action_n || setting_action_n === 0 ? setting_action_n : 0;
|
|
@@ -229,6 +241,7 @@ const ActionSettings = () => {
|
|
|
229
241
|
step_action_names?.[use_setting_action_n] || "",
|
|
230
242
|
JSON.stringify(configuration?.steps?.[use_setting_action_n]),
|
|
231
243
|
]);
|
|
244
|
+
|
|
232
245
|
|
|
233
246
|
return (
|
|
234
247
|
<div>
|
|
@@ -236,20 +249,19 @@ const ActionSettings = () => {
|
|
|
236
249
|
<tbody>
|
|
237
250
|
<tr>
|
|
238
251
|
<td>
|
|
239
|
-
<label>Action</label>
|
|
252
|
+
<label>{t("Action")}</label>
|
|
240
253
|
</td>
|
|
241
254
|
<td>
|
|
242
255
|
{options.inJestTestingMode ? null : (
|
|
243
256
|
<Select
|
|
244
257
|
options={actionOptions}
|
|
245
|
-
className="react-select action-selector"
|
|
258
|
+
className={builderSelectClassName("react-select action-selector")}
|
|
259
|
+
classNamePrefix="builder-select"
|
|
246
260
|
value={selectedAction}
|
|
247
261
|
defaultValue={selectedAction}
|
|
248
262
|
onChange={setAction}
|
|
249
263
|
menuPortalTarget={document.body}
|
|
250
|
-
styles={
|
|
251
|
-
menuPortal: (base) => ({ ...base, zIndex: 19999 }),
|
|
252
|
-
}}
|
|
264
|
+
styles={reactSelectStyles()}
|
|
253
265
|
></Select>
|
|
254
266
|
)}
|
|
255
267
|
</td>
|
|
@@ -257,7 +269,7 @@ const ActionSettings = () => {
|
|
|
257
269
|
{name !== "Clear" && options.mode === "filter" ? (
|
|
258
270
|
<tr>
|
|
259
271
|
<td>
|
|
260
|
-
<label>Row variable</label>
|
|
272
|
+
<label>{t("Row variable")}</label>
|
|
261
273
|
</td>
|
|
262
274
|
<td>
|
|
263
275
|
<select
|
|
@@ -290,7 +302,7 @@ const ActionSettings = () => {
|
|
|
290
302
|
{action_row_variable === "each_matching_row" ? (
|
|
291
303
|
<tr>
|
|
292
304
|
<td>
|
|
293
|
-
<label>Rows limit</label>
|
|
305
|
+
<label>{t("Rows limit")}</label>
|
|
294
306
|
</td>
|
|
295
307
|
<td>
|
|
296
308
|
<input
|
|
@@ -306,7 +318,7 @@ const ActionSettings = () => {
|
|
|
306
318
|
{action_style !== "on_page_load" ? (
|
|
307
319
|
<tr>
|
|
308
320
|
<td colSpan="2">
|
|
309
|
-
<label>Label (leave blank for default)</label>
|
|
321
|
+
<label>{t("Label (leave blank for default)")}</label>
|
|
310
322
|
<OrFormula
|
|
311
323
|
nodekey="action_label"
|
|
312
324
|
{...{ setProp, isFormula, node }}
|
|
@@ -339,7 +351,7 @@ const ActionSettings = () => {
|
|
|
339
351
|
checked={confirm}
|
|
340
352
|
onChange={setAProp("confirm", { checked: true })}
|
|
341
353
|
/>
|
|
342
|
-
<label className="form-check-label">User confirmation
|
|
354
|
+
<label className="form-check-label">{t("User confirmation?")}</label>
|
|
343
355
|
</div>
|
|
344
356
|
<div className="form-check">
|
|
345
357
|
<input
|
|
@@ -349,7 +361,7 @@ const ActionSettings = () => {
|
|
|
349
361
|
checked={spinner}
|
|
350
362
|
onChange={setAProp("spinner", { checked: true })}
|
|
351
363
|
/>
|
|
352
|
-
<label className="form-check-label">Spinner on click</label>
|
|
364
|
+
<label className="form-check-label">{t("Spinner on click")}</label>
|
|
353
365
|
</div>
|
|
354
366
|
<div className="form-check">
|
|
355
367
|
<input
|
|
@@ -359,7 +371,7 @@ const ActionSettings = () => {
|
|
|
359
371
|
checked={run_async}
|
|
360
372
|
onChange={setAProp("run_async", { checked: true })}
|
|
361
373
|
/>
|
|
362
|
-
<label className="form-check-label">Run async</label>
|
|
374
|
+
<label className="form-check-label">{t("Run async")}</label>
|
|
363
375
|
</div>
|
|
364
376
|
{action_style !== "on_page_load" ? (
|
|
365
377
|
<BlockSetting block={block} setProp={setProp} />
|
|
@@ -373,12 +385,12 @@ const ActionSettings = () => {
|
|
|
373
385
|
checked={is_submit_action}
|
|
374
386
|
onChange={setAProp("is_submit_action", { checked: true })}
|
|
375
387
|
/>
|
|
376
|
-
<label className="form-check-label">This is the submit action</label>
|
|
388
|
+
<label className="form-check-label">{t("This is the submit action")}</label>
|
|
377
389
|
</div>
|
|
378
390
|
) : null}
|
|
379
391
|
{name === "Multi-step action" ? (
|
|
380
392
|
<Fragment>
|
|
381
|
-
<label>Steps</label>
|
|
393
|
+
<label>{t("Steps")}</label>
|
|
382
394
|
|
|
383
395
|
<ArrayManager
|
|
384
396
|
node={node}
|
|
@@ -392,23 +404,22 @@ const ActionSettings = () => {
|
|
|
392
404
|
]}
|
|
393
405
|
></ArrayManager>
|
|
394
406
|
|
|
395
|
-
<label>Action</label>
|
|
407
|
+
<label>{t("Action")}</label>
|
|
396
408
|
{options.inJestTestingMode ? null : (
|
|
397
409
|
<Select
|
|
398
410
|
options={multiStepActionOptions}
|
|
399
|
-
className="react-select multistep-action-selector"
|
|
411
|
+
className={builderSelectClassName("react-select multistep-action-selector")}
|
|
412
|
+
classNamePrefix="builder-select"
|
|
400
413
|
value={selectedMultiStepAction}
|
|
401
414
|
defaultValue={selectedMultiStepAction}
|
|
402
415
|
onChange={setMultistepAction}
|
|
403
416
|
menuPortalTarget={document.body}
|
|
404
|
-
styles={
|
|
405
|
-
menuPortal: (base) => ({ ...base, zIndex: 19999 }),
|
|
406
|
-
}}
|
|
417
|
+
styles={reactSelectStyles()}
|
|
407
418
|
></Select>
|
|
408
419
|
)}
|
|
409
420
|
{options.mode !== "page" ? (
|
|
410
421
|
<Fragment>
|
|
411
|
-
<label>Only if... (formula)</label>
|
|
422
|
+
<label>{t("Only if... (formula)")}</label>
|
|
412
423
|
<input
|
|
413
424
|
type="text"
|
|
414
425
|
className="form-control text-to-display"
|
|
@@ -427,7 +438,7 @@ const ActionSettings = () => {
|
|
|
427
438
|
) : null}
|
|
428
439
|
{stepCfgFields ? (
|
|
429
440
|
<Fragment>
|
|
430
|
-
Step configuration:
|
|
441
|
+
{t("Step configuration:")}
|
|
431
442
|
<ConfigForm
|
|
432
443
|
fields={stepCfgFields}
|
|
433
444
|
configuration={
|
|
@@ -446,16 +457,120 @@ const ActionSettings = () => {
|
|
|
446
457
|
) : null}
|
|
447
458
|
</Fragment>
|
|
448
459
|
) : cfgFields ? (
|
|
449
|
-
<
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
460
|
+
<Fragment>
|
|
461
|
+
{name === "run_js_code" && runJsCodeModalOnly ? (
|
|
462
|
+
<div className="builder-config-field" data-field-name="code">
|
|
463
|
+
<label>{t("Code")}</label>
|
|
464
|
+
<button
|
|
465
|
+
type="button"
|
|
466
|
+
className="btn btn-secondary btn-sm"
|
|
467
|
+
onClick={() => setCodeModalOpen(true)}
|
|
468
|
+
>
|
|
469
|
+
{t("Open Code Popup")}
|
|
470
|
+
</button>
|
|
471
|
+
</div>
|
|
472
|
+
) : null}
|
|
473
|
+
{name === "run_js_code" && !runJsCodeModalOnly ? (
|
|
474
|
+
<Fragment>
|
|
475
|
+
<ConfigForm
|
|
476
|
+
fields={(cfgFields || []).filter((f) => f.name === "code")}
|
|
477
|
+
configuration={configuration}
|
|
478
|
+
setProp={setProp}
|
|
479
|
+
node={node}
|
|
480
|
+
openPopup={() => setCodeModalOpen(true)}
|
|
481
|
+
/>
|
|
482
|
+
{/* <div className="builder-config-field mt-2" data-field-name="code-modal-trigger">
|
|
483
|
+
<button
|
|
484
|
+
type="button"
|
|
485
|
+
className="btn btn-secondary btn-sm"
|
|
486
|
+
onClick={() => setCodeModalOpen(true)}
|
|
487
|
+
>
|
|
488
|
+
{t("Open Code Popup")}
|
|
489
|
+
</button>
|
|
490
|
+
</div> */}
|
|
491
|
+
<ConfigForm
|
|
492
|
+
fields={cfgFieldsForForm}
|
|
493
|
+
configuration={configuration}
|
|
494
|
+
setProp={setProp}
|
|
495
|
+
node={node}
|
|
496
|
+
/>
|
|
497
|
+
</Fragment>
|
|
498
|
+
) : (
|
|
499
|
+
<ConfigForm
|
|
500
|
+
fields={runJsCodeModalOnly ? cfgFieldsForForm : cfgFields}
|
|
501
|
+
configuration={configuration}
|
|
502
|
+
setProp={setProp}
|
|
503
|
+
node={node}
|
|
504
|
+
/>
|
|
505
|
+
)}
|
|
506
|
+
{name === "run_js_code" && codeModalOpen ? (
|
|
507
|
+
<div
|
|
508
|
+
className={`modal fade ${codeModalOpen ? "show" : ""}`}
|
|
509
|
+
style={{
|
|
510
|
+
display: codeModalOpen ? "block" : "none",
|
|
511
|
+
zIndex: 1055,
|
|
512
|
+
}}
|
|
513
|
+
tabIndex={-1}
|
|
514
|
+
role="dialog"
|
|
515
|
+
aria-labelledby="codeModalLabel"
|
|
516
|
+
aria-hidden={!codeModalOpen}
|
|
517
|
+
>
|
|
518
|
+
<div
|
|
519
|
+
className="modal-backdrop fade show"
|
|
520
|
+
style={{ zIndex: 1050 }}
|
|
521
|
+
onClick={() => setCodeModalOpen(false)}
|
|
522
|
+
aria-hidden="true"
|
|
523
|
+
/>
|
|
524
|
+
<div
|
|
525
|
+
className="modal-dialog modal-dialog-centered modal-lg"
|
|
526
|
+
role="document"
|
|
527
|
+
style={{ zIndex: 1060 }}
|
|
528
|
+
onClick={(e) => e.stopPropagation()}
|
|
529
|
+
>
|
|
530
|
+
<div className="modal-content code-modal">
|
|
531
|
+
<div className="modal-header">
|
|
532
|
+
<h5 className="modal-title" id="codeModalLabel">
|
|
533
|
+
{t("Code")}
|
|
534
|
+
</h5>
|
|
535
|
+
<button
|
|
536
|
+
type="button"
|
|
537
|
+
className="btn-close"
|
|
538
|
+
aria-label="Close"
|
|
539
|
+
onClick={() => setCodeModalOpen(false)}
|
|
540
|
+
/>
|
|
541
|
+
</div>
|
|
542
|
+
<div className="modal-body">
|
|
543
|
+
<MultiLineCodeEditor
|
|
544
|
+
setProp={setProp}
|
|
545
|
+
value={configuration?.code ?? ""}
|
|
546
|
+
onChange={(code) =>
|
|
547
|
+
setProp((prop) => {
|
|
548
|
+
if (!prop.configuration)
|
|
549
|
+
prop.configuration = {};
|
|
550
|
+
prop.configuration.code = code;
|
|
551
|
+
})
|
|
552
|
+
}
|
|
553
|
+
isModalEditor
|
|
554
|
+
/>
|
|
555
|
+
</div>
|
|
556
|
+
<div className="modal-footer">
|
|
557
|
+
<button
|
|
558
|
+
type="button"
|
|
559
|
+
className="btn btn-secondary"
|
|
560
|
+
onClick={() => setCodeModalOpen(false)}
|
|
561
|
+
>
|
|
562
|
+
{t("Close")}
|
|
563
|
+
</button>
|
|
564
|
+
</div>
|
|
565
|
+
</div>
|
|
566
|
+
</div>
|
|
567
|
+
</div>
|
|
568
|
+
) : null}
|
|
569
|
+
</Fragment>
|
|
455
570
|
) : null}
|
|
456
571
|
{cfg_link ? (
|
|
457
572
|
<a className="d-block mt-2" target="_blank" href={cfg_link}>
|
|
458
|
-
Configure this action
|
|
573
|
+
{t("Configure this action")}
|
|
459
574
|
</a>
|
|
460
575
|
) : null}
|
|
461
576
|
</div>
|
|
@@ -3,14 +3,10 @@
|
|
|
3
3
|
* @module components/elements/Aggregation
|
|
4
4
|
* @subcategory components / elements
|
|
5
5
|
*/
|
|
6
|
+
/* globals validate_expression_elem */
|
|
6
7
|
|
|
7
|
-
import React, {
|
|
8
|
-
|
|
9
|
-
useState,
|
|
10
|
-
useRef,
|
|
11
|
-
useEffect,
|
|
12
|
-
Fragment,
|
|
13
|
-
} from "react";
|
|
8
|
+
import React, { Fragment, useState, useContext, useEffect, useRef } from "react";
|
|
9
|
+
import useTranslation from "../../hooks/useTranslation";
|
|
14
10
|
import { useNode } from "@craftjs/core";
|
|
15
11
|
import optionsCtx from "../context";
|
|
16
12
|
import {
|
|
@@ -59,6 +55,7 @@ export /**
|
|
|
59
55
|
* @namespace
|
|
60
56
|
*/
|
|
61
57
|
const AggregationSettings = () => {
|
|
58
|
+
const { t } = useTranslation();
|
|
62
59
|
const {
|
|
63
60
|
actions: { setProp },
|
|
64
61
|
agg_relation,
|
|
@@ -132,7 +129,7 @@ const AggregationSettings = () => {
|
|
|
132
129
|
{options.mode === "filter" ? null : (
|
|
133
130
|
<tr>
|
|
134
131
|
<td>
|
|
135
|
-
<label>Relation</label>
|
|
132
|
+
<label>{t("Relation")}</label>
|
|
136
133
|
</td>
|
|
137
134
|
<td>
|
|
138
135
|
<select
|
|
@@ -160,7 +157,7 @@ const AggregationSettings = () => {
|
|
|
160
157
|
<tr>
|
|
161
158
|
<td>
|
|
162
159
|
<label>
|
|
163
|
-
{options.mode === "filter" ? "Field" : "Child table field"}
|
|
160
|
+
{options.mode === "filter" ? t("Field") : t("Child table field")}
|
|
164
161
|
</label>
|
|
165
162
|
</td>
|
|
166
163
|
<td>
|
|
@@ -179,7 +176,7 @@ const AggregationSettings = () => {
|
|
|
179
176
|
</tr>
|
|
180
177
|
<tr>
|
|
181
178
|
<td>
|
|
182
|
-
<label>Statistic</label>
|
|
179
|
+
<label>{t("Statistic")}</label>
|
|
183
180
|
</td>
|
|
184
181
|
<td>
|
|
185
182
|
<select
|
|
@@ -190,34 +187,34 @@ const AggregationSettings = () => {
|
|
|
190
187
|
>
|
|
191
188
|
{buildOptions(
|
|
192
189
|
[
|
|
193
|
-
"Count",
|
|
194
|
-
"CountUnique",
|
|
195
|
-
"Avg",
|
|
196
|
-
"Sum",
|
|
197
|
-
"Max",
|
|
198
|
-
"Min",
|
|
199
|
-
"Array_Agg",
|
|
190
|
+
t("Count"),
|
|
191
|
+
t("CountUnique"),
|
|
192
|
+
t("Avg"),
|
|
193
|
+
t("Sum"),
|
|
194
|
+
t("Max"),
|
|
195
|
+
t("Min"),
|
|
196
|
+
t("Array_Agg"),
|
|
200
197
|
],
|
|
201
198
|
{ valAttr: true }
|
|
202
199
|
)}
|
|
203
200
|
{targetFieldType === "Bool" ? (
|
|
204
|
-
<option value={`Percent true`}>Percent true</option>
|
|
201
|
+
<option value={`Percent true`}>{t("Percent true")}</option>
|
|
205
202
|
) : null}
|
|
206
203
|
{targetFieldType === "Bool" ? (
|
|
207
|
-
<option value={`Percent false`}>Percent false</option>
|
|
204
|
+
<option value={`Percent false`}>{t("Percent false")}</option>
|
|
208
205
|
) : null}
|
|
209
206
|
{(options.agg_field_opts[agg_relation] || [])
|
|
210
207
|
.filter((f) => f.ftype === "Date")
|
|
211
208
|
.map((f, ix) => (
|
|
212
209
|
<option key={ix} value={`Latest ${f.name}`}>
|
|
213
|
-
Latest {f.name}
|
|
210
|
+
{t("Latest")} {f.name}
|
|
214
211
|
</option>
|
|
215
212
|
))}
|
|
216
213
|
{(options.agg_field_opts[agg_relation] || [])
|
|
217
214
|
.filter((f) => f.ftype === "Date")
|
|
218
215
|
.map((f, ix) => (
|
|
219
216
|
<option key={ix} value={`Earliest ${f.name}`}>
|
|
220
|
-
Earliest {f.name}
|
|
217
|
+
{t("Earliest")} {f.name}
|
|
221
218
|
</option>
|
|
222
219
|
))}
|
|
223
220
|
</select>
|
|
@@ -226,7 +223,7 @@ const AggregationSettings = () => {
|
|
|
226
223
|
<tr>
|
|
227
224
|
<td>
|
|
228
225
|
<label>
|
|
229
|
-
Where
|
|
226
|
+
{t("Where")}
|
|
230
227
|
<HelpTopicLink
|
|
231
228
|
topic="Aggregation where formula"
|
|
232
229
|
table_name={options.tableName}
|
|
@@ -251,7 +248,7 @@ const AggregationSettings = () => {
|
|
|
251
248
|
{fvs && (
|
|
252
249
|
<tr>
|
|
253
250
|
<td>
|
|
254
|
-
<label>Field view</label>
|
|
251
|
+
<label>{t("Field view")}</label>
|
|
255
252
|
</td>
|
|
256
253
|
|
|
257
254
|
<td>
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
/* globals $, _sc_globalCsrf*/
|
|
7
7
|
import React, { Fragment, useState, useEffect } from "react";
|
|
8
|
+
import useTranslation from "../../hooks/useTranslation";
|
|
8
9
|
import optionsCtx from "../context";
|
|
9
10
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
10
11
|
import {
|
|
@@ -55,7 +56,10 @@ export const ArrayManager = ({
|
|
|
55
56
|
managedArrays,
|
|
56
57
|
manageContents,
|
|
57
58
|
initialAddProps,
|
|
59
|
+
contentsKey = "contents",
|
|
60
|
+
onLayoutChange,
|
|
58
61
|
}) => {
|
|
62
|
+
const { t } = useTranslation();
|
|
59
63
|
const { actions, query, connectors } = useEditor((state, query) => {
|
|
60
64
|
return {};
|
|
61
65
|
});
|
|
@@ -75,13 +79,14 @@ export const ArrayManager = ({
|
|
|
75
79
|
node.id,
|
|
76
80
|
options
|
|
77
81
|
);
|
|
78
|
-
layout.
|
|
82
|
+
layout[contentsKey].splice(rmIx, 1);
|
|
79
83
|
|
|
80
84
|
managedArrays.forEach((arrNm) => {
|
|
81
|
-
|
|
85
|
+
if (layout[arrNm]) layout[arrNm].splice(rmIx, 1);
|
|
82
86
|
});
|
|
83
87
|
layout[countProp] = node[countProp] - 1;
|
|
84
|
-
layout[currentProp] = node[currentProp] - 1;
|
|
88
|
+
layout[currentProp] = Math.max(0, node[currentProp] - 1);
|
|
89
|
+
if (onLayoutChange) onLayoutChange(layout, "delete");
|
|
85
90
|
actions.delete(node.id);
|
|
86
91
|
layoutToNodes(layout, query, actions, parentId, options, sibIx);
|
|
87
92
|
} else {
|
|
@@ -117,7 +122,7 @@ export const ArrayManager = ({
|
|
|
117
122
|
options
|
|
118
123
|
);
|
|
119
124
|
|
|
120
|
-
swapElements(layout
|
|
125
|
+
swapElements(layout[contentsKey], curIx, curIx + delta);
|
|
121
126
|
|
|
122
127
|
managedArrays.forEach((arrNm) => {
|
|
123
128
|
if (arrNm.includes(".")) {
|
|
@@ -128,6 +133,7 @@ export const ArrayManager = ({
|
|
|
128
133
|
swapElements(layout[arrNm], curIx, curIx + delta);
|
|
129
134
|
});
|
|
130
135
|
layout[currentProp] = node[currentProp] + delta;
|
|
136
|
+
if (onLayoutChange) onLayoutChange(layout, "move");
|
|
131
137
|
actions.delete(node.id);
|
|
132
138
|
layoutToNodes(layout, query, actions, parentId, options, sibIx);
|
|
133
139
|
} else
|
|
@@ -154,7 +160,7 @@ export const ArrayManager = ({
|
|
|
154
160
|
options
|
|
155
161
|
);
|
|
156
162
|
|
|
157
|
-
layout.
|
|
163
|
+
layout[contentsKey].push(null);
|
|
158
164
|
managedArrays.forEach((arrNm) => {
|
|
159
165
|
if (initialAddProps?.[arrNm])
|
|
160
166
|
layout[arrNm][node[countProp]] = initialAddProps?.[arrNm];
|
|
@@ -162,6 +168,7 @@ export const ArrayManager = ({
|
|
|
162
168
|
layout[currentProp] = +node[countProp];
|
|
163
169
|
layout[countProp] = +node[countProp] + 1;
|
|
164
170
|
|
|
171
|
+
if (onLayoutChange) onLayoutChange(layout, "add");
|
|
165
172
|
actions.delete(node.id);
|
|
166
173
|
layoutToNodes(layout, query, actions, parentId, options, sibIx);
|
|
167
174
|
} else
|
|
@@ -187,7 +194,7 @@ export const ArrayManager = ({
|
|
|
187
194
|
<ConfigField
|
|
188
195
|
field={{
|
|
189
196
|
name: currentProp,
|
|
190
|
-
label: "Number of things",
|
|
197
|
+
label: t("Number of things"),
|
|
191
198
|
type: "btn_select",
|
|
192
199
|
options: ntimes(node[countProp], (i) => ({
|
|
193
200
|
value: i,
|
|
@@ -201,7 +208,7 @@ export const ArrayManager = ({
|
|
|
201
208
|
></ConfigField>
|
|
202
209
|
<div className="btn-group w-100" role="group">
|
|
203
210
|
<button
|
|
204
|
-
title="Move left"
|
|
211
|
+
title={t("Move left")}
|
|
205
212
|
type="button"
|
|
206
213
|
style={{ width: "25%" }}
|
|
207
214
|
className="btn btn-outline-secondary btn-sm"
|
|
@@ -211,7 +218,7 @@ export const ArrayManager = ({
|
|
|
211
218
|
<FontAwesomeIcon icon={faAngleDoubleLeft} />
|
|
212
219
|
</button>
|
|
213
220
|
<button
|
|
214
|
-
title="Add"
|
|
221
|
+
title={t("Add")}
|
|
215
222
|
type="button"
|
|
216
223
|
style={{ width: "25%" }}
|
|
217
224
|
className="btn btn-outline-secondary btn-sm"
|
|
@@ -220,7 +227,7 @@ export const ArrayManager = ({
|
|
|
220
227
|
<FontAwesomeIcon icon={faPlus} />
|
|
221
228
|
</button>
|
|
222
229
|
<button
|
|
223
|
-
title="Delete"
|
|
230
|
+
title={t("Delete")}
|
|
224
231
|
type="button"
|
|
225
232
|
style={{ width: "25%" }}
|
|
226
233
|
className="btn btn-outline-secondary btn-sm"
|
|
@@ -229,7 +236,7 @@ export const ArrayManager = ({
|
|
|
229
236
|
<FontAwesomeIcon icon={faTrashAlt} />
|
|
230
237
|
</button>
|
|
231
238
|
<button
|
|
232
|
-
title="Move right"
|
|
239
|
+
title={t("Move right")}
|
|
233
240
|
type="button"
|
|
234
241
|
disabled={node[currentProp] === node[countProp] - 1}
|
|
235
242
|
style={{ width: "25%" }}
|