@saltcorn/builder 1.3.1-beta.0 → 1.3.1-beta.10

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": "1.3.1-beta.0",
3
+ "version": "1.3.1-beta.10",
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.3.1-beta.0",
23
+ "@saltcorn/common-code": "1.3.1-beta.10",
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",
@@ -58,6 +58,7 @@
58
58
  "overrides": {
59
59
  "immer": "9.0.6",
60
60
  "glob-parent": "^5.1.2",
61
+ "undici": "7.12.0",
61
62
  "parse5": "7.2.1",
62
63
  "parse5-htmlparser2-tree-adapter": "7.0.0"
63
64
  },
@@ -127,7 +127,8 @@ const SettingsPanel = () => {
127
127
  */
128
128
  const handleUserKeyPress = (event) => {
129
129
  const { keyCode, target } = event;
130
- if (target.tagName.toLowerCase() === "body" && selected) {
130
+ const tagName = target.tagName.toLowerCase();
131
+ if ((tagName === "body" || tagName === "button") && selected) {
131
132
  //8 backsp, 46 del
132
133
  if ((keyCode === 8 || keyCode === 46) && selected.id === "ROOT") {
133
134
  deleteChildren();
@@ -5,7 +5,7 @@
5
5
  */
6
6
  /*global notifyAlert*/
7
7
 
8
- import React, { Fragment, useContext } from "react";
8
+ import React, { Fragment, useContext, useEffect } from "react";
9
9
  import { useNode } from "@craftjs/core";
10
10
  import optionsCtx from "../context";
11
11
  import {
@@ -22,6 +22,7 @@ import {
22
22
  } from "./utils";
23
23
  import { ntimes } from "./Columns";
24
24
  import { ArrayManager } from "./ArrayManager";
25
+ import Select from "react-select";
25
26
 
26
27
  export /**
27
28
  *
@@ -155,6 +156,78 @@ const ActionSettings = () => {
155
156
  step_action_names?.[use_setting_action_n]
156
157
  )}`
157
158
  : "";
159
+ const setAction = (value0) => {
160
+ const value = value0.value || value0;
161
+ setProp((prop) => {
162
+ prop.name = value;
163
+ if (options.mode === "filter" && value !== "Clear") {
164
+ const rowRequired =
165
+ options.actionConstraints &&
166
+ options.actionConstraints[value]?.requireRow;
167
+ if (!action_row_variable) {
168
+ prop.action_row_variable = rowRequired ? "state" : "none";
169
+ } else if (rowRequired && action_row_variable === "none") {
170
+ prop.action_row_variable = "state";
171
+ }
172
+ }
173
+ if (value === "Multi-step action" && !nsteps) prop.nsteps = 1;
174
+ if (value === "Multi-step action" && !setting_action_n)
175
+ prop.setting_action_n = 0;
176
+ if (value === "Multi-step action" && !configuration.steps)
177
+ prop.configuration = { steps: [] };
178
+ });
179
+ setInitialConfig(setProp, value, getCfgFields(value));
180
+ };
181
+ const setMultistepAction = (value0) => {
182
+ const value = value0.value || value0;
183
+ setProp((prop) => {
184
+ if (!prop.step_action_names) prop.step_action_names = [];
185
+ prop.step_action_names[use_setting_action_n] = value;
186
+ });
187
+ };
188
+ const actionOptions = options.actions.filter(Boolean).map((f, ix) =>
189
+ f.optgroup && !f.options.length
190
+ ? null
191
+ : f.optgroup
192
+ ? {
193
+ label: f.label,
194
+ options: f.options.map((a, jx) => ({ label: a, value: a })),
195
+ }
196
+ : { label: f, value: f }
197
+ );
198
+ const selectedAction = { label: name, value: name };
199
+ const multiStepActionOptions = options.actions
200
+ .filter((f) => f && !(options.builtInActions || []).includes(f))
201
+ .map((f, ix) =>
202
+ f.optgroup && !f.options.length
203
+ ? null
204
+ : f.optgroup
205
+ ? {
206
+ label: f.label,
207
+ options: f.options
208
+ .filter(
209
+ (f) =>
210
+ ![
211
+ "Multi-step action",
212
+ ...(options.builtInActions || []),
213
+ ].includes(f)
214
+ )
215
+ .map((a, jx) => ({ label: a, value: a })),
216
+ }
217
+ : { label: f, value: f }
218
+ );
219
+ const selectedMultiStepAction = {
220
+ label: step_action_names?.[use_setting_action_n] || "",
221
+ value: step_action_names?.[use_setting_action_n] || "",
222
+ };
223
+ useEffect(() => {
224
+ apply_showif();
225
+ }, [
226
+ name,
227
+ step_action_names?.[use_setting_action_n] || "",
228
+ JSON.stringify(configuration?.steps?.[use_setting_action_n]),
229
+ ]);
230
+
158
231
  return (
159
232
  <div>
160
233
  <table className="w-100">
@@ -164,55 +237,19 @@ const ActionSettings = () => {
164
237
  <label>Action</label>
165
238
  </td>
166
239
  <td>
167
- <select
168
- value={name}
169
- className="form-control form-select"
170
- onChange={(e) => {
171
- if (!e.target) return;
172
- const value = e.target.value;
173
- setProp((prop) => {
174
- prop.name = value;
175
- if (options.mode === "filter" && value !== "Clear") {
176
- const rowRequired =
177
- options.actionConstraints &&
178
- options.actionConstraints[value]?.requireRow;
179
- if (!action_row_variable) {
180
- prop.action_row_variable = rowRequired
181
- ? "state"
182
- : "none";
183
- } else if (
184
- rowRequired &&
185
- action_row_variable === "none"
186
- ) {
187
- prop.action_row_variable = "state";
188
- }
189
- }
190
- if (value === "Multi-step action" && !nsteps)
191
- prop.nsteps = 1;
192
- if (value === "Multi-step action" && !setting_action_n)
193
- prop.setting_action_n = 0;
194
- if (value === "Multi-step action" && !configuration.steps)
195
- prop.configuration = { steps: [] };
196
- });
197
- setInitialConfig(setProp, value, getCfgFields(value));
198
- }}
199
- >
200
- {options.actions.filter(Boolean).map((f, ix) =>
201
- f.optgroup && !f.options.length ? null : f.optgroup ? (
202
- <optgroup key={ix} label={f.label}>
203
- {f.options.map((a, jx) => (
204
- <option key={jx} value={a}>
205
- {a}
206
- </option>
207
- ))}
208
- </optgroup>
209
- ) : (
210
- <option key={ix} value={f}>
211
- {f}
212
- </option>
213
- )
214
- )}
215
- </select>
240
+ {options.inJestTestingMode ? null : (
241
+ <Select
242
+ options={actionOptions}
243
+ className="react-select action-selector"
244
+ value={selectedAction}
245
+ defaultValue={selectedAction}
246
+ onChange={setAction}
247
+ menuPortalTarget={document.body}
248
+ styles={{
249
+ menuPortal: (base) => ({ ...base, zIndex: 19999 }),
250
+ }}
251
+ ></Select>
252
+ )}
216
253
  </td>
217
254
  </tr>
218
255
  {name !== "Clear" && options.mode === "filter" ? (
@@ -344,47 +381,19 @@ const ActionSettings = () => {
344
381
  ></ArrayManager>
345
382
 
346
383
  <label>Action</label>
347
- <select
348
- value={step_action_names?.[use_setting_action_n] || ""}
349
- className="form-control form-select"
350
- onChange={(e) => {
351
- if (!e.target) return;
352
- const value = e.target.value;
353
- setProp((prop) => {
354
- if (!prop.step_action_names) prop.step_action_names = [];
355
- prop.step_action_names[use_setting_action_n] = value;
356
- });
357
- }}
358
- >
359
- <option value="" disabled>
360
- Select action...
361
- </option>
362
- {options.actions
363
- .filter((f) => !(options.builtInActions || []).includes(f))
364
- .map((f, ix) =>
365
- f.optgroup ? (
366
- <optgroup key={ix} label={f.label}>
367
- {f.options
368
- .filter(
369
- (f) =>
370
- ![
371
- "Multi-step action",
372
- ...(options.builtInActions || []),
373
- ].includes(f)
374
- )
375
- .map((a, jx) => (
376
- <option key={jx} value={a}>
377
- {a}
378
- </option>
379
- ))}
380
- </optgroup>
381
- ) : (
382
- <option key={ix} value={f}>
383
- {f}
384
- </option>
385
- )
386
- )}
387
- </select>
384
+ {options.inJestTestingMode ? null : (
385
+ <Select
386
+ options={multiStepActionOptions}
387
+ className="react-select multistep-action-selector"
388
+ value={selectedMultiStepAction}
389
+ defaultValue={selectedMultiStepAction}
390
+ onChange={setMultistepAction}
391
+ menuPortalTarget={document.body}
392
+ styles={{
393
+ menuPortal: (base) => ({ ...base, zIndex: 19999 }),
394
+ }}
395
+ ></Select>
396
+ )}
388
397
  {options.mode !== "page" ? (
389
398
  <Fragment>
390
399
  <label>Only if... (formula)</label>
@@ -51,11 +51,11 @@ const DropMenu = ({
51
51
  //const [dropWidth, setDropWidth] = useState(200);
52
52
  return (
53
53
  <div
54
- className={`${selected ? "selected-node" : ""} ${block ? "d-block" : ""}`}
54
+ className={`${selected ? "selected-node" : ""} ${block ? "d-block" : "d-inline"}`}
55
55
  ref={(dom) => connect(drag(dom))}
56
56
  >
57
57
  <button
58
- className={`btn ${action_style || "btn-primary"} ${action_size || ""} `}
58
+ className={`btn ${action_style || "btn-primary"} d-inline-block ${action_size || ""} `}
59
59
  style={
60
60
  action_style === "btn-custom-color"
61
61
  ? {
@@ -67,7 +67,7 @@ const Link = ({
67
67
  <button
68
68
  className={`${textStyle} is-builder-link ${
69
69
  selected ? "selected-node" : ""
70
- } ${isFormula?.text ? "font-monospace" : ""} ${link_style} ${
70
+ } ${isFormula?.text ? "font-monospace" : ""} ${link_style} ${link_style && link_style.includes("btn") ? "d-inline-block" : ""} ${
71
71
  link_size || ""
72
72
  } ${block ? "d-block" : ""}`}
73
73
  ref={(dom) => connect(drag(dom))}
@@ -261,6 +261,7 @@ const ViewSettings = () => {
261
261
  <Select
262
262
  options={viewOptions}
263
263
  value={selectedView}
264
+ className="react-select view-selector"
264
265
  onChange={set_view_name}
265
266
  onBlur={set_view_name}
266
267
  menuPortalTarget={document.body}
@@ -302,6 +303,7 @@ const ViewSettings = () => {
302
303
  <Select
303
304
  options={viewOptions}
304
305
  value={selectedView}
306
+ className="react-select view-selector"
305
307
  onChange={(e) => {
306
308
  const target_value = e?.target?.value || e?.value;
307
309
  setProp((prop) => {
@@ -254,6 +254,7 @@ const ViewLinkSettings = () => {
254
254
  {options.inJestTestingMode ? null : (
255
255
  <Select
256
256
  options={viewOptions}
257
+ className="react-select viewlink-selector"
257
258
  value={selectedView}
258
259
  onChange={set_view_name}
259
260
  onBlur={set_view_name}
@@ -132,15 +132,19 @@ export const FormulaTooltip = () => {
132
132
  ))}
133
133
  </Fragment>
134
134
  ) : null}
135
-
135
+
136
136
  <div>
137
- In view formulae, you can use aggregation formulae. The syntax for this is
138
- <code>{inbound_table}${inboundkey_field}${target_field}${aggrgation}</code>
139
- The aggregation (which should be lower case) can be ommitted and defaults to
140
- <code>array_agg</code>. Examples: <code>patients$favbook$id$count</code> or
141
- <code>patients$favbook$id</code>.
142
- This is useful if you want a count in a view link label
143
- without creating a stored calculated field.
137
+ In view formulae, you can use aggregation formulae. The syntax for this
138
+ is
139
+ <code>
140
+ [inbound_table]$[inboundkey_field]$[target_field]$[aggrgation]
141
+ </code>
142
+ The aggregation (which should be lower case) can be ommitted and
143
+ defaults to
144
+ <code>array_agg</code>. Examples: <code>patients$favbook$id$count</code>{" "}
145
+ or
146
+ <code>patients$favbook$id</code>. This is useful if you want a count in
147
+ a view link label without creating a stored calculated field.
144
148
  </div>
145
149
  <a
146
150
  className="d-block"
@@ -786,7 +790,7 @@ const ConfigForm = ({
786
790
  tableName,
787
791
  fieldName,
788
792
  }) => (
789
- <div>
793
+ <div className="form-namespace">
790
794
  {fields.map((f, ix) => {
791
795
  if (f.showIf && configuration) {
792
796
  let noshow = false;
@@ -948,6 +952,7 @@ const ConfigField = ({
948
952
  return (
949
953
  <select
950
954
  className={`field-${field?.name} form-control form-select`}
955
+ name={field?.name}
951
956
  value={value || ""}
952
957
  onChange={(e) => e.target && myOnChange(e.target.value)}
953
958
  onBlur={(e) => e.target && myOnChange(e.target.value)}
@@ -966,6 +971,7 @@ const ConfigField = ({
966
971
  return (
967
972
  <input
968
973
  type="text"
974
+ name={field?.name}
969
975
  className={`field-${field?.name} form-control`}
970
976
  value={value || ""}
971
977
  spellCheck={false}
@@ -977,6 +983,7 @@ const ConfigField = ({
977
983
  <select
978
984
  className="fontselect form-control form-select"
979
985
  value={value || ""}
986
+ name={field?.name}
980
987
  onChange={(e) => e.target && myOnChange(e.target.value)}
981
988
  onBlur={(e) => e.target && myOnChange(e.target.value)}
982
989
  >
@@ -997,6 +1004,7 @@ const ConfigField = ({
997
1004
  step={field.step || 1}
998
1005
  min={field.min}
999
1006
  max={field.max}
1007
+ name={field?.name}
1000
1008
  value={value || ""}
1001
1009
  onChange={(e) => e.target && myOnChange(e.target.value)}
1002
1010
  />
@@ -1007,6 +1015,7 @@ const ConfigField = ({
1007
1015
  className={`field-${field?.name} form-control`}
1008
1016
  value={value || ""}
1009
1017
  step={0.01}
1018
+ name={field?.name}
1010
1019
  max={or_if_undef(field?.attributes?.max, undefined)}
1011
1020
  min={or_if_undef(field?.attributes?.min, undefined)}
1012
1021
  onChange={(e) => e.target && myOnChange(e.target.value)}
@@ -1019,6 +1028,7 @@ const ConfigField = ({
1019
1028
  type="checkbox"
1020
1029
  className={`field-${field?.name} form-check-input`}
1021
1030
  checked={value}
1031
+ name={field?.name}
1022
1032
  onChange={(e) => e.target && myOnChange(e.target.checked)}
1023
1033
  />
1024
1034
  <label className="form-check-label">{field.label}</label>
@@ -1030,6 +1040,7 @@ const ConfigField = ({
1030
1040
  type="text"
1031
1041
  className={`field-${field?.name} form-control`}
1032
1042
  value={value}
1043
+ name={field?.name}
1033
1044
  spellCheck={false}
1034
1045
  onChange={(e) => e.target && myOnChange(e.target.value)}
1035
1046
  />
@@ -1040,6 +1051,7 @@ const ConfigField = ({
1040
1051
  type="text"
1041
1052
  className={`field-${field?.name} form-control`}
1042
1053
  value={value}
1054
+ name={field?.name}
1043
1055
  onChange={(e) => e.target && myOnChange(e.target.value)}
1044
1056
  spellCheck={false}
1045
1057
  />
@@ -1056,12 +1068,14 @@ const ConfigField = ({
1056
1068
  return (
1057
1069
  <Select
1058
1070
  options={seloptions}
1071
+ className="react-select selectized-field"
1059
1072
  value={seloptions.find((so) => value === so.value)}
1060
1073
  onChange={(e) =>
1061
1074
  (e.name && myOnChange(e.name)) ||
1062
1075
  (e.value && myOnChange(e.value)) ||
1063
1076
  (typeof e === "string" && myOnChange(e))
1064
1077
  }
1078
+ name={field?.name}
1065
1079
  onBlur={(e) =>
1066
1080
  (e.name && myOnChange(e.name)) ||
1067
1081
  (e.value && myOnChange(e.value)) ||
@@ -1076,6 +1090,7 @@ const ConfigField = ({
1076
1090
  <select
1077
1091
  className={`field-${field?.name} form-control form-select`}
1078
1092
  value={value || ""}
1093
+ name={field?.name}
1079
1094
  onChange={(e) => e.target && myOnChange(e.target.value)}
1080
1095
  onBlur={(e) => e.target && myOnChange(e.target.value)}
1081
1096
  >
@@ -1790,8 +1805,7 @@ export const buildLayers = (relations, tableName, tableNameCache) => {
1790
1805
  fkeys: [],
1791
1806
  relPath: relation.relationString,
1792
1807
  });
1793
- }
1794
- else {
1808
+ } else {
1795
1809
  let currentTbl = relation.sourceTblName;
1796
1810
  for (const pathElement of relation.path) {
1797
1811
  if (pathElement.inboundKey) {