@saltcorn/builder 0.5.6-beta.2 → 0.6.0-alpha.0

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.
@@ -34,6 +34,11 @@ import {
34
34
  } from "react-bootstrap-icons";
35
35
  import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
36
36
  import { faScroll, faRobot } from "@fortawesome/free-solid-svg-icons";
37
+
38
+ function capitalizeFirstLetter(string) {
39
+ return string.charAt(0).toUpperCase() + string.slice(1);
40
+ }
41
+
37
42
  export const Container = ({
38
43
  children,
39
44
  borderWidth,
@@ -65,6 +70,7 @@ export const Container = ({
65
70
  gradStartColor,
66
71
  gradEndColor,
67
72
  gradDirection,
73
+ rotate,
68
74
  }) => {
69
75
  const {
70
76
  selected,
@@ -84,7 +90,7 @@ export const Container = ({
84
90
  margin: margin.map((p) => p + "px").join(" "),
85
91
  minHeight: `${Math.max(minHeight, 15)}${minHeightUnit || "px"}`,
86
92
  [`border${
87
- borderDirection ? `-${borderDirection}` : ""
93
+ borderDirection ? `${capitalizeFirstLetter(borderDirection)}` : ""
88
94
  }`]: `${borderWidth}px ${borderStyle} ${borderColor || "black"}`,
89
95
  ...(block === false ? { display: "inline-block" } : {}),
90
96
  ...(bgType === "Image" && bgFileId && +bgFileId
@@ -126,6 +132,11 @@ export const Container = ({
126
132
  width: `${width}${widthUnit || "px"}`,
127
133
  }
128
134
  : {}),
135
+ ...(rotate
136
+ ? {
137
+ transform: `rotate(${rotate}deg)`,
138
+ }
139
+ : {}),
129
140
  }}
130
141
  >
131
142
  <div className="canvas">{children}</div>
@@ -173,23 +184,12 @@ export const ContainerSettings = () => {
173
184
  gradEndColor: node.data.props.gradEndColor,
174
185
  gradDirection: node.data.props.gradDirection,
175
186
  overflow: node.data.props.overflow,
187
+ rotate: node.data.props.rotate,
176
188
  }));
177
189
  const {
178
190
  actions: { setProp },
179
191
  borderWidth,
180
- borderStyle,
181
- borderDirection,
182
- borderRadius,
183
- borderRadiusUnit,
184
192
  borderColor,
185
- minHeight,
186
- height,
187
- width,
188
- minHeightUnit,
189
- heightUnit,
190
- widthUnit,
191
- vAlign,
192
- hAlign,
193
193
  bgFileId,
194
194
  imageSize,
195
195
  bgType,
@@ -231,6 +231,12 @@ export const ContainerSettings = () => {
231
231
  ></div>
232
232
  ),
233
233
  });
234
+ const setAProp = (key) => (e) => {
235
+ if (e.target) {
236
+ const target_value = e.target.value;
237
+ setProp((prop) => (prop[key] = target_value));
238
+ }
239
+ };
234
240
  return (
235
241
  <Accordion>
236
242
  <table className="w-100" accordiontitle="Placement">
@@ -249,14 +255,10 @@ export const ContainerSettings = () => {
249
255
  className="form-control w-50"
250
256
  min="0"
251
257
  max="20"
252
- onChange={(e) =>
253
- setProp((prop) => {
254
- prop.borderWidth = e.target.value;
255
- })
256
- }
258
+ onChange={setAProp("borderWidth")}
257
259
  />
258
- <div class="input-group-append w-50 d-inline">
259
- <span class="input-group-text">px</span>
260
+ <div className="input-group-append w-50 d-inline">
261
+ <span className="input-group-text">px</span>
260
262
  </div>
261
263
  </div>
262
264
  </td>
@@ -308,11 +310,7 @@ export const ContainerSettings = () => {
308
310
  type="color"
309
311
  value={borderColor}
310
312
  className="form-control-sm w-50 mr-2"
311
- onChange={(e) =>
312
- setProp((prop) => {
313
- prop.borderColor = e.target.value;
314
- })
315
- }
313
+ onChange={setAProp("borderColor")}
316
314
  />
317
315
  <small>{borderColor}</small>
318
316
  </td>
@@ -406,6 +404,15 @@ export const ContainerSettings = () => {
406
404
  </table>
407
405
  <table className="w-100" accordiontitle="Contents">
408
406
  <tbody>
407
+ <SettingsRow
408
+ field={{
409
+ name: "rotate",
410
+ label: "Rotate °",
411
+ type: "Integer",
412
+ }}
413
+ node={node}
414
+ setProp={setProp}
415
+ />
409
416
  <SettingsSectionHeaderRow title="Align" />
410
417
  <SettingsRow
411
418
  field={{
@@ -495,11 +502,7 @@ export const ContainerSettings = () => {
495
502
  type="color"
496
503
  value={gradStartColor}
497
504
  className="form-control-sm w-50"
498
- onChange={(e) =>
499
- setProp((prop) => {
500
- prop.gradStartColor = e.target.value;
501
- })
502
- }
505
+ onChange={setAProp("gradStartColor")}
503
506
  />
504
507
  </OrFormula>
505
508
  </td>
@@ -515,11 +518,7 @@ export const ContainerSettings = () => {
515
518
  type="color"
516
519
  value={gradEndColor}
517
520
  className="form-control-sm w-50"
518
- onChange={(e) =>
519
- setProp((prop) => {
520
- prop.gradEndColor = e.target.value;
521
- })
522
- }
521
+ onChange={setAProp("gradEndColor")}
523
522
  />
524
523
  </OrFormula>
525
524
  </td>
@@ -537,11 +536,7 @@ export const ContainerSettings = () => {
537
536
  max="360"
538
537
  value={gradDirection}
539
538
  className="form-control-sm w-50"
540
- onChange={(e) =>
541
- setProp((prop) => {
542
- prop.gradDirection = e.target.value;
543
- })
544
- }
539
+ onChange={setAProp("gradDirection")}
545
540
  />
546
541
  </OrFormula>
547
542
  </td>
@@ -558,9 +553,7 @@ export const ContainerSettings = () => {
558
553
  <select
559
554
  value={bgFileId}
560
555
  className="form-control-sm w-100"
561
- onChange={(e) =>
562
- setProp((prop) => (prop.bgFileId = e.target.value))
563
- }
556
+ onChange={setAProp("bgFileId")}
564
557
  >
565
558
  {options.images.map((f, ix) => (
566
559
  <option key={ix} value={f.id}>
@@ -579,11 +572,7 @@ export const ContainerSettings = () => {
579
572
  <select
580
573
  value={imageSize}
581
574
  className="form-control-sm"
582
- onChange={(e) =>
583
- setProp((prop) => {
584
- prop.imageSize = e.target.value;
585
- })
586
- }
575
+ onChange={setAProp("imageSize")}
587
576
  >
588
577
  <option>contain</option>
589
578
  <option>cover</option>
@@ -601,11 +590,7 @@ export const ContainerSettings = () => {
601
590
  type="color"
602
591
  value={bgColor}
603
592
  className="form-control-sm w-50"
604
- onChange={(e) =>
605
- setProp((prop) => {
606
- prop.bgColor = e.target.value;
607
- })
608
- }
593
+ onChange={setAProp("bgColor")}
609
594
  />
610
595
  </OrFormula>
611
596
  </td>
@@ -614,7 +599,7 @@ export const ContainerSettings = () => {
614
599
  <tr>
615
600
  <td colSpan="2">
616
601
  <label>
617
- Set text color{" "}
602
+ Set text color
618
603
  <input
619
604
  name="setTextColor"
620
605
  type="checkbox"
@@ -622,10 +607,10 @@ export const ContainerSettings = () => {
622
607
  onChange={(e) =>
623
608
  setProp((prop) => (prop.setTextColor = e.target.checked))
624
609
  }
625
- />{" "}
610
+ />
626
611
  </label>
627
612
  </td>
628
- </tr>{" "}
613
+ </tr>
629
614
  {setTextColor && (
630
615
  <tr>
631
616
  <td>
@@ -636,11 +621,7 @@ export const ContainerSettings = () => {
636
621
  type="color"
637
622
  value={textColor}
638
623
  className="form-control-sm"
639
- onChange={(e) =>
640
- setProp((prop) => {
641
- prop.textColor = e.target.value;
642
- })
643
- }
624
+ onChange={setAProp("textColor")}
644
625
  />
645
626
  </td>
646
627
  </tr>
@@ -659,9 +640,7 @@ export const ContainerSettings = () => {
659
640
  type="text"
660
641
  className="form-control text-to-display"
661
642
  value={showIfFormula}
662
- onChange={(e) =>
663
- setProp((prop) => (prop.showIfFormula = e.target.value))
664
- }
643
+ onChange={setAProp("showIfFormula")}
665
644
  />
666
645
  <div style={{ marginTop: "-5px" }}>
667
646
  <small className="text-muted text-monospace">FORMULA</small>
@@ -722,11 +701,7 @@ export const ContainerSettings = () => {
722
701
  <select
723
702
  value={minScreenWidth}
724
703
  className="form-control"
725
- onChange={(e) =>
726
- setProp((prop) => {
727
- prop.minScreenWidth = e.target.value;
728
- })
729
- }
704
+ onChange={setAProp("minScreenWidth")}
730
705
  >
731
706
  <option value="">all</option>
732
707
  <option value="sm">small</option>
@@ -744,11 +719,7 @@ export const ContainerSettings = () => {
744
719
  <select
745
720
  value={maxScreenWidth}
746
721
  className="form-control"
747
- onChange={(e) =>
748
- setProp((prop) => {
749
- prop.maxScreenWidth = e.target.value;
750
- })
751
- }
722
+ onChange={setAProp("maxScreenWidth")}
752
723
  >
753
724
  <option value="">all</option>
754
725
  <option value="md">small</option>
@@ -766,7 +737,7 @@ export const ContainerSettings = () => {
766
737
  type="text"
767
738
  className="form-control"
768
739
  value={url}
769
- onChange={(e) => setProp((prop) => (prop.url = e.target.value))}
740
+ onChange={setAProp("url")}
770
741
  />
771
742
  </OrFormula>
772
743
 
@@ -774,11 +745,7 @@ export const ContainerSettings = () => {
774
745
  <select
775
746
  value={hoverColor}
776
747
  className="form-control"
777
- onChange={(e) =>
778
- setProp((prop) => {
779
- prop.hoverColor = e.target.value;
780
- })
781
- }
748
+ onChange={setAProp("hoverColor")}
782
749
  >
783
750
  <option value="">None</option>
784
751
  <option value="gray">gray</option>
@@ -797,9 +764,7 @@ export const ContainerSettings = () => {
797
764
  type="text"
798
765
  className="form-control text-to-display"
799
766
  value={customClass}
800
- onChange={(e) =>
801
- setProp((prop) => (prop.customClass = e.target.value))
802
- }
767
+ onChange={setAProp("customClass")}
803
768
  />
804
769
  </OrFormula>
805
770
  <div>
@@ -810,7 +775,7 @@ export const ContainerSettings = () => {
810
775
  type="text"
811
776
  className="text-to-display form-control"
812
777
  value={customCSS}
813
- onChange={(e) => setProp((prop) => (prop.customCSS = e.target.value))}
778
+ onChange={setAProp("customCSS")}
814
779
  ></textarea>
815
780
  </div>
816
781
  </Accordion>
@@ -825,6 +790,7 @@ Container.craft = {
825
790
  vAlign: "top",
826
791
  hAlign: "left",
827
792
  bgFileId: 0,
793
+ rotate: 0,
828
794
  isFormula: {},
829
795
  bgType: "None",
830
796
  block: true,
@@ -28,11 +28,13 @@ export const DropDownFilterSettings = () => {
28
28
  block,
29
29
  neutral_label,
30
30
  full_width,
31
+ where,
31
32
  } = useNode((node) => ({
32
33
  name: node.data.props.name,
33
34
  block: node.data.props.block,
34
35
  neutral_label: node.data.props.neutral_label,
35
36
  full_width: node.data.props.full_width,
37
+ where: node.data.props.where,
36
38
  }));
37
39
  const options = useContext(optionsCtx);
38
40
  return (
@@ -70,12 +72,24 @@ export const DropDownFilterSettings = () => {
70
72
  />
71
73
  </td>
72
74
  </tr>
75
+ <tr>
76
+ <td>
77
+ <label>Where</label>
78
+ </td>
79
+ <td>
80
+ <input
81
+ value={where}
82
+ className="form-control"
83
+ onChange={(e) => setProp((prop) => (prop.where = e.target.value))}
84
+ />
85
+ </td>
86
+ </tr>
73
87
  <tr>
74
88
  <td></td>
75
89
  <td>
76
90
  <BlockSetting block={block} setProp={setProp} />
77
91
  </td>
78
- </tr>{" "}
92
+ </tr>
79
93
  <tr>
80
94
  <td></td>
81
95
  <td>
@@ -108,6 +122,7 @@ DropDownFilter.craft = {
108
122
  { name: "name", segment_name: "field_name", column_name: "field_name" },
109
123
  "full_width",
110
124
  "neutral_label",
125
+ "where",
111
126
  "block",
112
127
  ],
113
128
  },
@@ -160,7 +160,7 @@ export const FieldSettings = () => {
160
160
  <TextStyleRow textStyle={textStyle} setProp={setProp} />
161
161
  )}
162
162
  </tbody>
163
- </table>{" "}
163
+ </table>
164
164
  {cfgFields ? (
165
165
  <ConfigForm
166
166
  fields={cfgFields}
@@ -29,8 +29,10 @@ export const ImageSettings = () => {
29
29
  fileid: node.data.props.fileid,
30
30
  field: node.data.props.field,
31
31
  url: node.data.props.url,
32
+ filepath: node.data.props.filepath,
32
33
  srctype: node.data.props.srctype,
33
- alt: node.data.props.fieldview,
34
+ alt: node.data.props.alt,
35
+ uploadedFiles: node.data.props.uploadedFiles,
34
36
  block: node.data.props.block,
35
37
  isFormula: node.data.props.isFormula,
36
38
  }));
@@ -43,8 +45,47 @@ export const ImageSettings = () => {
43
45
  alt,
44
46
  block,
45
47
  isFormula,
48
+ filepath,
49
+ uploadedFiles,
46
50
  } = node;
47
51
  const options = useContext(optionsCtx);
52
+ const handleUpload = (e) => {
53
+ if (e.target.files && e.target.files.length > 0) {
54
+ const formData = new FormData();
55
+
56
+ formData.append("file", e.target.files[0]);
57
+ formData.append("min_role_read", options.min_role || 1);
58
+
59
+ fetch("/files/upload", {
60
+ method: "POST",
61
+ body: formData,
62
+ headers: {
63
+ "X-Requested-With": "XMLHttpRequest",
64
+ "CSRF-Token": options.csrfToken,
65
+ },
66
+ })
67
+ .then((response) => response.json())
68
+ .then((result) => {
69
+ setProp((prop) => {
70
+ prop.fileid = result.success.id;
71
+ prop.srctype = "File";
72
+ prop.uploadedFiles = [
73
+ ...prop.uploadedFiles,
74
+ { id: result.success.id, filename: result.success.filename },
75
+ ];
76
+ });
77
+ })
78
+ .catch((error) => {
79
+ console.error("Error:", error);
80
+ });
81
+ }
82
+ };
83
+ const setAProp = (key) => (e) => {
84
+ if (e.target) {
85
+ const target_value = e.target.value;
86
+ setProp((prop) => (prop[key] = target_value));
87
+ }
88
+ };
48
89
  return (
49
90
  <table>
50
91
  <tbody>
@@ -63,12 +104,11 @@ export const ImageSettings = () => {
63
104
  <select
64
105
  value={srctype}
65
106
  className="form-control"
66
- onChange={(e) =>
67
- setProp((prop) => (prop.srctype = e.target.value))
68
- }
107
+ onChange={setAProp("srctype")}
69
108
  >
70
109
  <option>File</option>
71
110
  <option>URL</option>
111
+ <option>Upload</option>
72
112
  {options.mode === "show" && <option>Field</option>}
73
113
  </select>
74
114
  </td>
@@ -82,15 +122,18 @@ export const ImageSettings = () => {
82
122
  <select
83
123
  value={fileid}
84
124
  className="form-control"
85
- onChange={(e) =>
86
- setProp((prop) => (prop.fileid = e.target.value))
87
- }
125
+ onChange={setAProp("fileid")}
88
126
  >
89
127
  {options.images.map((f, ix) => (
90
128
  <option key={ix} value={f.id}>
91
129
  {f.filename}
92
130
  </option>
93
131
  ))}
132
+ {(uploadedFiles || []).map((uf, ix) => (
133
+ <option key={ix} value={uf.id}>
134
+ {uf.filename}
135
+ </option>
136
+ ))}
94
137
  </select>
95
138
  </td>
96
139
  </tr>
@@ -106,14 +149,27 @@ export const ImageSettings = () => {
106
149
  type="text"
107
150
  className="form-control"
108
151
  value={url}
109
- onChange={(e) =>
110
- setProp((prop) => (prop.url = e.target.value))
111
- }
152
+ onChange={setAProp("url")}
112
153
  />
113
154
  </OrFormula>
114
155
  </td>
115
156
  </tr>
116
157
  )}
158
+ {srctype === "Upload" && (
159
+ <tr>
160
+ <td>
161
+ <label>File</label>
162
+ </td>
163
+ <td>
164
+ <input
165
+ type="file"
166
+ className="form-control"
167
+ value={filepath}
168
+ onChange={handleUpload}
169
+ />
170
+ </td>
171
+ </tr>
172
+ )}
117
173
  {srctype === "Field" && (
118
174
  <tr>
119
175
  <td>
@@ -123,9 +179,7 @@ export const ImageSettings = () => {
123
179
  <select
124
180
  value={field}
125
181
  className="form-control"
126
- onChange={(e) =>
127
- setProp((prop) => (prop.field = e.target.value))
128
- }
182
+ onChange={setAProp("field")}
129
183
  >
130
184
  {options.fields
131
185
  .filter(
@@ -142,26 +196,30 @@ export const ImageSettings = () => {
142
196
  </td>
143
197
  </tr>
144
198
  )}
145
- <tr>
146
- <td>
147
- <label>Alt text</label>
148
- </td>
149
- <td>
150
- <OrFormula nodekey="alt" {...{ setProp, isFormula, node }}>
151
- <input
152
- type="text"
153
- className="form-control"
154
- value={alt}
155
- onChange={(e) => setProp((prop) => (prop.alt = e.target.value))}
156
- />
157
- </OrFormula>
158
- </td>
159
- </tr>
160
- <tr>
161
- <td colSpan="2">
162
- <BlockSetting block={block} setProp={setProp} />
163
- </td>
164
- </tr>
199
+ {srctype !== "Upload" && (
200
+ <tr>
201
+ <td>
202
+ <label>Alt text</label>
203
+ </td>
204
+ <td>
205
+ <OrFormula nodekey="alt" {...{ setProp, isFormula, node }}>
206
+ <input
207
+ type="text"
208
+ className="form-control"
209
+ value={alt}
210
+ onChange={setAProp("alt")}
211
+ />
212
+ </OrFormula>
213
+ </td>
214
+ </tr>
215
+ )}
216
+ {srctype !== "Upload" && (
217
+ <tr>
218
+ <td colSpan="2">
219
+ <BlockSetting block={block} setProp={setProp} />
220
+ </td>
221
+ </tr>
222
+ )}
165
223
  </tbody>
166
224
  </table>
167
225
  );
@@ -173,6 +231,7 @@ Image.craft = {
173
231
  alt: "",
174
232
  block: false,
175
233
  isFormula: {},
234
+ uploadedFiles: [],
176
235
  srctype: "File",
177
236
  },
178
237
  related: {