@saltcorn/builder 0.9.4-beta.19 → 0.9.4-beta.20
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/Toolbox.js +13 -2
- package/src/components/elements/Action.js +12 -0
- package/src/components/elements/Aggregation.js +193 -106
- package/src/components/elements/Field.js +22 -20
- package/src/components/elements/JoinField.js +25 -1
- package/src/components/elements/View.js +23 -15
- package/src/components/elements/utils.js +1 -0
- package/src/components/storage.js +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@saltcorn/builder",
|
|
3
|
-
"version": "0.9.4-beta.
|
|
3
|
+
"version": "0.9.4-beta.20",
|
|
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.9.4",
|
|
21
21
|
"@craftjs/core": "0.1.0-beta.20",
|
|
22
22
|
"@craftjs/utils": "0.1.0-beta.20",
|
|
23
|
-
"@saltcorn/common-code": "0.9.4-beta.
|
|
23
|
+
"@saltcorn/common-code": "0.9.4-beta.20",
|
|
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",
|
|
@@ -490,7 +490,7 @@ const AggregationElem = ({ connectors, child_field_list, agg_field_opts }) => (
|
|
|
490
490
|
>
|
|
491
491
|
<Aggregation
|
|
492
492
|
agg_relation={child_field_list[0]}
|
|
493
|
-
agg_field={headOr(agg_field_opts[child_field_list[0]], "")}
|
|
493
|
+
agg_field={headOr(agg_field_opts[child_field_list[0]], "")?.name}
|
|
494
494
|
stat={"Count"}
|
|
495
495
|
textStyle={""}
|
|
496
496
|
aggwhere={""}
|
|
@@ -628,7 +628,13 @@ export /**
|
|
|
628
628
|
const ToolboxFilter = ({ expanded }) => {
|
|
629
629
|
const { connectors, query } = useEditor();
|
|
630
630
|
const options = useContext(optionsCtx);
|
|
631
|
-
const {
|
|
631
|
+
const {
|
|
632
|
+
fields,
|
|
633
|
+
views,
|
|
634
|
+
field_view_options,
|
|
635
|
+
child_field_list,
|
|
636
|
+
agg_field_opts,
|
|
637
|
+
} = options;
|
|
632
638
|
return chunkToolBox(
|
|
633
639
|
[
|
|
634
640
|
<TextElem connectors={connectors} />,
|
|
@@ -643,6 +649,11 @@ const ToolboxFilter = ({ expanded }) => {
|
|
|
643
649
|
<ToggleFilterElem connectors={connectors} fields={fields} />,
|
|
644
650
|
<SearchElem connectors={connectors} />,
|
|
645
651
|
<ActionElem connectors={connectors} options={options} />,
|
|
652
|
+
<AggregationElem
|
|
653
|
+
connectors={connectors}
|
|
654
|
+
child_field_list={child_field_list}
|
|
655
|
+
agg_field_opts={agg_field_opts}
|
|
656
|
+
/>,
|
|
646
657
|
<ContainerElem connectors={connectors} />,
|
|
647
658
|
<CardElem connectors={connectors} />,
|
|
648
659
|
<TabsElem connectors={connectors} />,
|
|
@@ -110,6 +110,7 @@ const ActionSettings = () => {
|
|
|
110
110
|
step_only_ifs: node.data.props.step_only_ifs,
|
|
111
111
|
step_action_names: node.data.props.step_action_names,
|
|
112
112
|
setting_action_n: node.data.props.setting_action_n,
|
|
113
|
+
spinner: node.data.props.spinner,
|
|
113
114
|
}));
|
|
114
115
|
const {
|
|
115
116
|
actions: { setProp },
|
|
@@ -127,6 +128,7 @@ const ActionSettings = () => {
|
|
|
127
128
|
setting_action_n,
|
|
128
129
|
step_only_ifs,
|
|
129
130
|
step_action_names,
|
|
131
|
+
spinner,
|
|
130
132
|
} = node;
|
|
131
133
|
const options = useContext(optionsCtx);
|
|
132
134
|
const getCfgFields = (fv) => (options.actionConfigForms || {})[fv];
|
|
@@ -278,6 +280,16 @@ const ActionSettings = () => {
|
|
|
278
280
|
/>
|
|
279
281
|
<label className="form-check-label">User confirmation?</label>
|
|
280
282
|
</div>
|
|
283
|
+
<div className="form-check">
|
|
284
|
+
<input
|
|
285
|
+
className="form-check-input"
|
|
286
|
+
name="block"
|
|
287
|
+
type="checkbox"
|
|
288
|
+
checked={spinner}
|
|
289
|
+
onChange={setAProp("spinner", { checked: true })}
|
|
290
|
+
/>
|
|
291
|
+
<label className="form-check-label">Spinner on click</label>
|
|
292
|
+
</div>
|
|
281
293
|
{action_style !== "on_page_load" ? (
|
|
282
294
|
<BlockSetting block={block} setProp={setProp} />
|
|
283
295
|
) : null}
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* @subcategory components / elements
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import React, { useContext } from "react";
|
|
7
|
+
import React, { useContext, useState, useEffect, Fragment } from "react";
|
|
8
8
|
import { useNode } from "@craftjs/core";
|
|
9
9
|
import optionsCtx from "../context";
|
|
10
10
|
import {
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
TextStyleRow,
|
|
14
14
|
setAPropGen,
|
|
15
15
|
buildOptions,
|
|
16
|
+
ConfigForm,
|
|
16
17
|
} from "./utils";
|
|
17
18
|
|
|
18
19
|
export /**
|
|
@@ -58,125 +59,209 @@ const AggregationSettings = () => {
|
|
|
58
59
|
aggwhere,
|
|
59
60
|
block,
|
|
60
61
|
textStyle,
|
|
62
|
+
agg_fieldview,
|
|
63
|
+
configuration,
|
|
61
64
|
} = useNode((node) => ({
|
|
62
65
|
agg_relation: node.data.props.agg_relation,
|
|
63
66
|
agg_field: node.data.props.agg_field,
|
|
64
67
|
aggwhere: node.data.props.aggwhere,
|
|
65
68
|
stat: node.data.props.stat,
|
|
66
69
|
block: node.data.props.block,
|
|
70
|
+
agg_fieldview: node.data.props.agg_fieldview,
|
|
71
|
+
configuration: node.data.props.configuration,
|
|
67
72
|
textStyle: node.data.props.textStyle,
|
|
68
73
|
}));
|
|
69
74
|
const options = useContext(optionsCtx);
|
|
70
75
|
const setAProp = setAPropGen(setProp);
|
|
71
76
|
|
|
77
|
+
const targetField = options.agg_field_opts[agg_relation]?.find?.(
|
|
78
|
+
(f) => f.name === agg_field
|
|
79
|
+
);
|
|
80
|
+
const targetFieldType = targetField?.ftype;
|
|
81
|
+
const outcomeType =
|
|
82
|
+
stat === "Count" || stat === "CountUnique"
|
|
83
|
+
? "Integer"
|
|
84
|
+
: stat === "Array_Agg"
|
|
85
|
+
? "Array"
|
|
86
|
+
: targetFieldType;
|
|
87
|
+
const fvs = options.agg_fieldview_options[outcomeType];
|
|
88
|
+
|
|
89
|
+
const [fetchedCfgFields, setFetchedCfgFields] = useState([]);
|
|
90
|
+
const cfgFields = fetchedCfgFields;
|
|
91
|
+
useEffect(() => {
|
|
92
|
+
fetch(
|
|
93
|
+
`/field/fieldviewcfgform/${
|
|
94
|
+
targetField?.table_name || options.tableName
|
|
95
|
+
}?accept=json`,
|
|
96
|
+
{
|
|
97
|
+
method: "POST",
|
|
98
|
+
headers: {
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
"CSRF-Token": options.csrfToken,
|
|
101
|
+
"X-Requested-With": "XMLHttpRequest",
|
|
102
|
+
},
|
|
103
|
+
body: JSON.stringify({
|
|
104
|
+
agg_outcome_type: outcomeType,
|
|
105
|
+
agg_fieldview,
|
|
106
|
+
agg_field: targetField?.name,
|
|
107
|
+
}),
|
|
108
|
+
}
|
|
109
|
+
)
|
|
110
|
+
.then(function (response) {
|
|
111
|
+
if (response.status < 399) return response.json();
|
|
112
|
+
else return [];
|
|
113
|
+
})
|
|
114
|
+
.then(setFetchedCfgFields);
|
|
115
|
+
}, [outcomeType, agg_fieldview]);
|
|
116
|
+
|
|
72
117
|
return (
|
|
73
|
-
<
|
|
74
|
-
<
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
<
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
{f
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
>
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
<tr>
|
|
120
|
-
<td>
|
|
121
|
-
<label>Statistic</label>
|
|
122
|
-
</td>
|
|
123
|
-
<td>
|
|
124
|
-
<select
|
|
125
|
-
value={stat}
|
|
126
|
-
className="form-control form-select"
|
|
127
|
-
onChange={setAProp("stat")}
|
|
128
|
-
onBlur={setAProp("stat")}
|
|
129
|
-
>
|
|
130
|
-
{buildOptions(
|
|
131
|
-
[
|
|
132
|
-
"Count",
|
|
133
|
-
"CountUnique",
|
|
134
|
-
"Avg",
|
|
135
|
-
"Sum",
|
|
136
|
-
"Max",
|
|
137
|
-
"Min",
|
|
138
|
-
"Array_Agg",
|
|
139
|
-
],
|
|
140
|
-
{ valAttr: true }
|
|
141
|
-
)}
|
|
142
|
-
{options.fields
|
|
143
|
-
.filter((f) => f.type === "Date" || f.type.name === "Date")
|
|
144
|
-
.map((f, ix) => (
|
|
145
|
-
<option key={ix} value={`Latest ${f.name}`}>
|
|
146
|
-
Latest {f.name}
|
|
118
|
+
<Fragment>
|
|
119
|
+
<table>
|
|
120
|
+
<tbody>
|
|
121
|
+
{options.mode === "filter" ? null : (
|
|
122
|
+
<tr>
|
|
123
|
+
<td>
|
|
124
|
+
<label>Relation</label>
|
|
125
|
+
</td>
|
|
126
|
+
<td>
|
|
127
|
+
<select
|
|
128
|
+
className="form-control form-select"
|
|
129
|
+
value={agg_relation}
|
|
130
|
+
onChange={(e) => {
|
|
131
|
+
if (!e.target) return;
|
|
132
|
+
const value = e.target.value;
|
|
133
|
+
setProp((prop) => {
|
|
134
|
+
prop.agg_relation = value;
|
|
135
|
+
const fs = options.agg_field_opts[value];
|
|
136
|
+
if (fs && fs.length > 0) prop.agg_field = fs[0]?.name;
|
|
137
|
+
});
|
|
138
|
+
}}
|
|
139
|
+
>
|
|
140
|
+
{options.child_field_list.map((f, ix) => (
|
|
141
|
+
<option key={ix} value={f}>
|
|
142
|
+
{f}
|
|
143
|
+
</option>
|
|
144
|
+
))}
|
|
145
|
+
</select>
|
|
146
|
+
</td>
|
|
147
|
+
</tr>
|
|
148
|
+
)}
|
|
149
|
+
<tr>
|
|
150
|
+
<td>
|
|
151
|
+
<label>
|
|
152
|
+
{options.mode === "filter" ? "Field" : "Child table field"}
|
|
153
|
+
</label>
|
|
154
|
+
</td>
|
|
155
|
+
<td>
|
|
156
|
+
<select
|
|
157
|
+
className="form-control form-select"
|
|
158
|
+
value={agg_field}
|
|
159
|
+
onChange={setAProp("agg_field")}
|
|
160
|
+
>
|
|
161
|
+
{(options.agg_field_opts[agg_relation] || []).map((f, ix) => (
|
|
162
|
+
<option key={ix} value={f.name}>
|
|
163
|
+
{f.label}
|
|
147
164
|
</option>
|
|
148
165
|
))}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
166
|
+
</select>
|
|
167
|
+
</td>
|
|
168
|
+
</tr>
|
|
169
|
+
<tr>
|
|
170
|
+
<td>
|
|
171
|
+
<label>Statistic</label>
|
|
172
|
+
</td>
|
|
173
|
+
<td>
|
|
174
|
+
<select
|
|
175
|
+
value={stat}
|
|
176
|
+
className="form-control form-select"
|
|
177
|
+
onChange={setAProp("stat")}
|
|
178
|
+
onBlur={setAProp("stat")}
|
|
179
|
+
>
|
|
180
|
+
{buildOptions(
|
|
181
|
+
[
|
|
182
|
+
"Count",
|
|
183
|
+
"CountUnique",
|
|
184
|
+
"Avg",
|
|
185
|
+
"Sum",
|
|
186
|
+
"Max",
|
|
187
|
+
"Min",
|
|
188
|
+
"Array_Agg",
|
|
189
|
+
],
|
|
190
|
+
{ valAttr: true }
|
|
191
|
+
)}
|
|
192
|
+
{options.fields
|
|
193
|
+
.filter((f) => f.type === "Date" || f.type.name === "Date")
|
|
194
|
+
.map((f, ix) => (
|
|
195
|
+
<option key={ix} value={`Latest ${f.name}`}>
|
|
196
|
+
Latest {f.name}
|
|
197
|
+
</option>
|
|
198
|
+
))}
|
|
199
|
+
{options.fields
|
|
200
|
+
.filter((f) => f.type === "Date" || f.type.name === "Date")
|
|
201
|
+
.map((f, ix) => (
|
|
202
|
+
<option key={ix} value={`Earliest ${f.name}`}>
|
|
203
|
+
Earliest {f.name}
|
|
204
|
+
</option>
|
|
205
|
+
))}
|
|
206
|
+
</select>
|
|
207
|
+
</td>
|
|
208
|
+
</tr>
|
|
209
|
+
<tr>
|
|
210
|
+
<td>
|
|
211
|
+
<label>Where</label>
|
|
212
|
+
</td>
|
|
213
|
+
<td>
|
|
214
|
+
<input
|
|
215
|
+
type="text"
|
|
216
|
+
className="form-control"
|
|
217
|
+
value={aggwhere}
|
|
218
|
+
onChange={setAProp("aggwhere")}
|
|
219
|
+
/>
|
|
220
|
+
</td>
|
|
221
|
+
</tr>
|
|
222
|
+
{fvs && (
|
|
223
|
+
<tr>
|
|
224
|
+
<td>
|
|
225
|
+
<label>Field view</label>
|
|
226
|
+
</td>
|
|
227
|
+
|
|
228
|
+
<td>
|
|
229
|
+
<select
|
|
230
|
+
value={agg_fieldview}
|
|
231
|
+
className="form-control form-select"
|
|
232
|
+
onChange={(e) => {
|
|
233
|
+
if (!e.target) return;
|
|
234
|
+
const value = e.target.value;
|
|
235
|
+
setProp((prop) => (prop.agg_fieldview = value));
|
|
236
|
+
//refetchPreview({ fieldview: value });
|
|
237
|
+
}}
|
|
238
|
+
>
|
|
239
|
+
{(fvs || []).map((fvnm, ix) => (
|
|
240
|
+
<option key={ix} value={fvnm}>
|
|
241
|
+
{fvnm}
|
|
242
|
+
</option>
|
|
243
|
+
))}
|
|
244
|
+
</select>
|
|
245
|
+
</td>
|
|
246
|
+
</tr>
|
|
247
|
+
)}
|
|
248
|
+
|
|
249
|
+
<TextStyleRow textStyle={textStyle} setProp={setProp} />
|
|
250
|
+
<tr>
|
|
251
|
+
<td colSpan="2">
|
|
252
|
+
<BlockSetting block={block} setProp={setProp} />
|
|
253
|
+
</td>
|
|
254
|
+
</tr>
|
|
255
|
+
</tbody>
|
|
256
|
+
</table>{" "}
|
|
257
|
+
{cfgFields ? (
|
|
258
|
+
<ConfigForm
|
|
259
|
+
fields={cfgFields}
|
|
260
|
+
configuration={configuration || {}}
|
|
261
|
+
setProp={setProp}
|
|
262
|
+
/>
|
|
263
|
+
) : null}
|
|
264
|
+
</Fragment>
|
|
180
265
|
);
|
|
181
266
|
};
|
|
182
267
|
|
|
@@ -196,6 +281,8 @@ Aggregation.craft = {
|
|
|
196
281
|
"agg_field",
|
|
197
282
|
"aggwhere",
|
|
198
283
|
"stat",
|
|
284
|
+
"agg_fieldview",
|
|
285
|
+
{ name: "configuration", default: {} },
|
|
199
286
|
],
|
|
200
287
|
},
|
|
201
288
|
};
|
|
@@ -219,26 +219,28 @@ const FieldSettings = () => {
|
|
|
219
219
|
</td>
|
|
220
220
|
</tr>
|
|
221
221
|
)}
|
|
222
|
-
|
|
223
|
-
<
|
|
224
|
-
|
|
225
|
-
<
|
|
226
|
-
<
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
222
|
+
{options.mode === "show" || options.mode === "list" ? (
|
|
223
|
+
<tr>
|
|
224
|
+
<td></td>
|
|
225
|
+
<td>
|
|
226
|
+
<div className="form-check">
|
|
227
|
+
<input
|
|
228
|
+
className="form-check-input"
|
|
229
|
+
name="inline"
|
|
230
|
+
type="checkbox"
|
|
231
|
+
checked={click_to_edit}
|
|
232
|
+
onChange={(e) => {
|
|
233
|
+
if (e && e.target) {
|
|
234
|
+
const target_value = e.target.checked;
|
|
235
|
+
setProp((prop) => (prop.click_to_edit = target_value));
|
|
236
|
+
}
|
|
237
|
+
}}
|
|
238
|
+
/>
|
|
239
|
+
<label className="form-check-label">Click to edit?</label>
|
|
240
|
+
</div>
|
|
241
|
+
</td>
|
|
242
|
+
</tr>
|
|
243
|
+
) : null}
|
|
242
244
|
|
|
243
245
|
{!(blockDisplay && blockDisplay.includes(fieldview)) && (
|
|
244
246
|
<tr>
|
|
@@ -376,6 +376,7 @@ const JoinFieldSettings = () => {
|
|
|
376
376
|
textStyle,
|
|
377
377
|
configuration,
|
|
378
378
|
fieldview,
|
|
379
|
+
click_to_edit,
|
|
379
380
|
node_id,
|
|
380
381
|
} = useNode((node) => ({
|
|
381
382
|
name: node.data.props.name,
|
|
@@ -383,7 +384,7 @@ const JoinFieldSettings = () => {
|
|
|
383
384
|
textStyle: node.data.props.textStyle,
|
|
384
385
|
fieldview: node.data.props.fieldview,
|
|
385
386
|
configuration: node.data.props.configuration,
|
|
386
|
-
|
|
387
|
+
click_to_edit: node.data.props.click_to_edit,
|
|
387
388
|
node_id: node.id,
|
|
388
389
|
}));
|
|
389
390
|
const options = useContext(optionsCtx);
|
|
@@ -493,6 +494,28 @@ const JoinFieldSettings = () => {
|
|
|
493
494
|
</td>
|
|
494
495
|
</tr>
|
|
495
496
|
)}
|
|
497
|
+
{options.mode === "show" || options.mode === "list" ? (
|
|
498
|
+
<tr>
|
|
499
|
+
<td></td>
|
|
500
|
+
<td>
|
|
501
|
+
<div className="form-check">
|
|
502
|
+
<input
|
|
503
|
+
className="form-check-input"
|
|
504
|
+
name="inline"
|
|
505
|
+
type="checkbox"
|
|
506
|
+
checked={click_to_edit}
|
|
507
|
+
onChange={(e) => {
|
|
508
|
+
if (e && e.target) {
|
|
509
|
+
const target_value = e.target.checked;
|
|
510
|
+
setProp((prop) => (prop.click_to_edit = target_value));
|
|
511
|
+
}
|
|
512
|
+
}}
|
|
513
|
+
/>
|
|
514
|
+
<label className="form-check-label">Click to edit?</label>
|
|
515
|
+
</div>
|
|
516
|
+
</td>
|
|
517
|
+
</tr>
|
|
518
|
+
) : null}
|
|
496
519
|
<tr>
|
|
497
520
|
<td></td>
|
|
498
521
|
<td>
|
|
@@ -527,6 +550,7 @@ JoinField.craft = {
|
|
|
527
550
|
{ name: "name", segment_name: "join_field", column_name: "join_field" },
|
|
528
551
|
"fieldview",
|
|
529
552
|
"textStyle",
|
|
553
|
+
"click_to_edit",
|
|
530
554
|
"block",
|
|
531
555
|
{ name: "configuration", default: {} },
|
|
532
556
|
],
|
|
@@ -152,7 +152,7 @@ const ViewSettings = () => {
|
|
|
152
152
|
if (rest.startsWith(".")) viewname = prefix;
|
|
153
153
|
else viewname = rest;
|
|
154
154
|
}
|
|
155
|
-
if (viewname.includes(".")) viewname = viewname.split(".")[0];
|
|
155
|
+
if (viewname && viewname.includes(".")) viewname = viewname.split(".")[0];
|
|
156
156
|
|
|
157
157
|
if (
|
|
158
158
|
finder &&
|
|
@@ -177,7 +177,7 @@ const ViewSettings = () => {
|
|
|
177
177
|
: [undefined, undefined];
|
|
178
178
|
let safeRelation = null;
|
|
179
179
|
const subView = views.find((view) => view.name === viewname);
|
|
180
|
-
if (relation) {
|
|
180
|
+
if (relation && subView) {
|
|
181
181
|
const subTbl = tables.find((tbl) => tbl.id === subView.table_id);
|
|
182
182
|
safeRelation = new Relation(
|
|
183
183
|
relation,
|
|
@@ -187,7 +187,7 @@ const ViewSettings = () => {
|
|
|
187
187
|
}
|
|
188
188
|
if (
|
|
189
189
|
options.mode !== "filter" &&
|
|
190
|
-
subView
|
|
190
|
+
subView?.table_id &&
|
|
191
191
|
!safeRelation &&
|
|
192
192
|
!hasLegacyRelation &&
|
|
193
193
|
relationsData?.relations.length > 0
|
|
@@ -290,18 +290,26 @@ const ViewSettings = () => {
|
|
|
290
290
|
) : (
|
|
291
291
|
<div>
|
|
292
292
|
<label>View to {options.mode === "show" ? "embed" : "show"}</label>
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
293
|
+
{options.inJestTestingMode ? null : (
|
|
294
|
+
<Select
|
|
295
|
+
options={viewOptions}
|
|
296
|
+
value={selectedView}
|
|
297
|
+
onChange={(e) => {
|
|
298
|
+
const target_value = e?.target?.value || e?.value;
|
|
299
|
+
setProp((prop) => {
|
|
300
|
+
prop.view = target_value;
|
|
301
|
+
});
|
|
302
|
+
}}
|
|
303
|
+
onBlur={(e) => {
|
|
304
|
+
const target_value = e?.target?.value || e?.value;
|
|
305
|
+
setProp((prop) => {
|
|
306
|
+
prop.view = target_value;
|
|
307
|
+
});
|
|
308
|
+
}}
|
|
309
|
+
menuPortalTarget={document.body}
|
|
310
|
+
styles={{ menuPortal: (base) => ({ ...base, zIndex: 19999 }) }}
|
|
311
|
+
></Select>
|
|
312
|
+
)}
|
|
305
313
|
</div>
|
|
306
314
|
)}
|
|
307
315
|
{options.mode !== "edit" && (
|
|
@@ -180,6 +180,7 @@ const layoutToNodes = (layout, query, actions, parent = "ROOT", options) => {
|
|
|
180
180
|
step_only_ifs={segment.step_only_ifs || ""}
|
|
181
181
|
step_action_names={segment.step_action_names || ""}
|
|
182
182
|
confirm={segment.confirm}
|
|
183
|
+
spinner={segment.spinner}
|
|
183
184
|
configuration={segment.configuration || {}}
|
|
184
185
|
block={segment.block || false}
|
|
185
186
|
minRole={segment.minRole || 10}
|
|
@@ -632,6 +633,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
632
633
|
action_textcol: node.props.action_textcol,
|
|
633
634
|
minRole: node.props.minRole,
|
|
634
635
|
confirm: node.props.confirm,
|
|
636
|
+
spinner: node.props.spinner,
|
|
635
637
|
nsteps: node.props.nsteps,
|
|
636
638
|
step_only_ifs: node.props.step_only_ifs,
|
|
637
639
|
step_action_names: node.props.step_action_names,
|
|
@@ -644,6 +646,7 @@ const craftToSaltcorn = (nodes, startFrom = "ROOT", options) => {
|
|
|
644
646
|
block: node.props.block,
|
|
645
647
|
configuration: node.props.configuration,
|
|
646
648
|
confirm: node.props.confirm,
|
|
649
|
+
spinner: node.props.spinner,
|
|
647
650
|
action_name: node.props.name,
|
|
648
651
|
...(node.props.name !== "Clear" && node.props.action_row_variable
|
|
649
652
|
? {
|