@saltcorn/builder 0.9.3-beta.0 → 0.9.3-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.9.3-beta.0",
3
+ "version": "0.9.3-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",
@@ -251,15 +251,19 @@ const LinkElem = ({ connectors }) => (
251
251
  * @subcategory components / Toolbox
252
252
  * @namespace
253
253
  */
254
- const ViewElem = ({ connectors, views }) => (
254
+ const ViewElem = ({ connectors, views, isPageEdit }) => (
255
255
  <WrapElem
256
256
  connectors={connectors}
257
257
  icon="fas fa-eye"
258
258
  title="Embed a view"
259
259
  label="View"
260
- disable={views.length < 2}
260
+ disable={!views || views.length < (!isPageEdit ? 2 : 1)}
261
261
  >
262
- <View name={"not_assigned"} state={"shared"} view={views[0].name} />
262
+ <View
263
+ name={"not_assigned"}
264
+ state={"shared"}
265
+ view={views?.length > 0 ? views[0].name : ""}
266
+ />
263
267
  </WrapElem>
264
268
  );
265
269
  /**
@@ -425,10 +429,10 @@ const ViewLinkElem = ({ connectors, options }) => (
425
429
  icons={["fas fa-eye", "fas fa-link"]}
426
430
  title="Link to a view"
427
431
  label="ViewLink"
428
- disable={options.views.length < 2}
432
+ disable={!options.views || options.views.length < 2}
429
433
  >
430
434
  <ViewLink
431
- name={options.views.length > 0 ? options.views[0].name : ""}
435
+ name={options.views?.length > 0 ? options.views[0].name : ""}
432
436
  block={false}
433
437
  minRole={100}
434
438
  label={""}
@@ -703,7 +707,7 @@ const ToolboxPage = () => {
703
707
  </div>
704
708
  <div className="toolbar-row">
705
709
  <LinkElem connectors={connectors} />
706
- <ViewElem connectors={connectors} views={views} />
710
+ <ViewElem connectors={connectors} views={views} isPageEdit={true} />
707
711
  </div>
708
712
  <div className="toolbar-row">
709
713
  <SearchElem connectors={connectors} />
@@ -336,6 +336,9 @@ const ActionSettings = () => {
336
336
  });
337
337
  }}
338
338
  >
339
+ <option value="" disabled>
340
+ Select action...
341
+ </option>
339
342
  {options.actions
340
343
  .filter((f) => !(options.builtInActions || []).includes(f))
341
344
  .map((f, ix) => (
@@ -344,20 +347,24 @@ const ActionSettings = () => {
344
347
  </option>
345
348
  ))}
346
349
  </select>
347
- <label>Only if... (formula)</label>
348
- <input
349
- type="text"
350
- className="form-control text-to-display"
351
- value={step_only_ifs?.[use_setting_action_n] || ""}
352
- onChange={(e) => {
353
- if (!e.target) return;
354
- const value = e.target.value;
355
- setProp((prop) => {
356
- if (!prop.step_only_ifs) prop.step_only_ifs = [];
357
- prop.step_only_ifs[use_setting_action_n] = value;
358
- });
359
- }}
360
- />
350
+ {options.mode !== "page" ? (
351
+ <Fragment>
352
+ <label>Only if... (formula)</label>
353
+ <input
354
+ type="text"
355
+ className="form-control text-to-display"
356
+ value={step_only_ifs?.[use_setting_action_n] || ""}
357
+ onChange={(e) => {
358
+ if (!e.target) return;
359
+ const value = e.target.value;
360
+ setProp((prop) => {
361
+ if (!prop.step_only_ifs) prop.step_only_ifs = [];
362
+ prop.step_only_ifs[use_setting_action_n] = value;
363
+ });
364
+ }}
365
+ />
366
+ </Fragment>
367
+ ) : null}
361
368
  {stepCfgFields ? (
362
369
  <Fragment>
363
370
  Step configuration:
@@ -97,6 +97,7 @@ const FieldSettings = () => {
97
97
  node_id,
98
98
  click_to_edit,
99
99
  textStyle,
100
+ onchange_action,
100
101
  } = useNode((node) => ({
101
102
  name: node.data.props.name,
102
103
  fieldview: node.data.props.fieldview,
@@ -104,6 +105,7 @@ const FieldSettings = () => {
104
105
  click_to_edit: node.data.props.click_to_edit,
105
106
  inline: node.data.props.inline,
106
107
  textStyle: node.data.props.textStyle,
108
+ onchange_action: node.data.props.onchange_action,
107
109
  configuration: node.data.props.configuration,
108
110
  node_id: node.id,
109
111
  }));
@@ -249,6 +251,38 @@ const FieldSettings = () => {
249
251
  onChange={(k, v) => refetchPreview({ configuration: { [k]: v } })}
250
252
  />
251
253
  ) : null}
254
+ {options.mode === "edit" && options.triggerActions ? (
255
+ <Fragment>
256
+ <label>On change action</label>
257
+ <select
258
+ value={onchange_action}
259
+ className="form-control form-select"
260
+ onChange={(e) => {
261
+ if (!e.target) return;
262
+ const value = e.target.value;
263
+ setProp((prop) => {
264
+ prop.onchange_action = value;
265
+ });
266
+ }}
267
+ >
268
+ <option value="">None</option>
269
+ {options.triggerActions.map((f, ix) => (
270
+ <option key={ix} value={f}>
271
+ {f}
272
+ </option>
273
+ ))}
274
+ </select>
275
+ {onchange_action ? (
276
+ <a
277
+ className="d-block mt-2"
278
+ target="_blank"
279
+ href={`/actions/configure/${onchange_action}`}
280
+ >
281
+ Configure this action
282
+ </a>
283
+ ) : null}
284
+ </Fragment>
285
+ ) : null}
252
286
  </Fragment>
253
287
  );
254
288
  };
@@ -269,6 +303,7 @@ Field.craft = {
269
303
  "block",
270
304
  "inline",
271
305
  "click_to_edit",
306
+ "onchange_action",
272
307
  { name: "configuration", default: {} },
273
308
  ],
274
309
  },
@@ -4,7 +4,7 @@
4
4
  * @subcategory components / elements
5
5
  */
6
6
  /* globals $, _sc_globalCsrf*/
7
- import React, { Fragment, useState } from "react";
7
+ import React, { Fragment, useState, useEffect } from "react";
8
8
  import optionsCtx from "../context";
9
9
  import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
10
10
  import {
@@ -775,13 +775,29 @@ const ConfigField = ({
775
775
  : field.attributes.options;
776
776
  if (!field.required && field.options) field.options.unshift("");
777
777
  }
778
+ const field_type = field.input_type || field.type.name || field.type;
779
+ const hasSelect =
780
+ (field_type === "String" && field.attributes?.options) ||
781
+ field_type === "select";
782
+ const getOptions = () =>
783
+ typeof field?.attributes?.options === "string"
784
+ ? field.attributes.options.split(",").map((s) => s.trim())
785
+ : field?.attributes?.options || field.options;
786
+
787
+ if (hasSelect && typeof value === "undefined") {
788
+ //pick first value to mimic html form behaviour
789
+ const options = getOptions();
790
+ let o;
791
+ if ((o = options[0]))
792
+ useEffect(() => {
793
+ myOnChange(typeof o === "string" ? o : o.value || o.name || o);
794
+ }, []);
795
+ }
796
+
778
797
  const dispatch = {
779
798
  String() {
780
799
  if (field.attributes?.options) {
781
- const options =
782
- typeof field.attributes.options === "string"
783
- ? field.attributes.options.split(",").map((s) => s.trim())
784
- : field.attributes.options;
800
+ const options = getOptions();
785
801
  return (
786
802
  <select
787
803
  className="form-control form-select"
@@ -973,7 +989,7 @@ const ConfigField = ({
973
989
  );
974
990
  },
975
991
  };
976
- const f = dispatch[field.input_type || field.type.name || field.type];
992
+ const f = dispatch[field_type];
977
993
  return f ? f() : null;
978
994
  };
979
995