@saltcorn/builder 0.8.6-beta.2 → 0.8.6-beta.3
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 +7 -7
- package/package.json +1 -1
- package/src/components/elements/RelationBadges.js +97 -0
- package/src/components/elements/RelationPicker.js +251 -0
- package/src/components/elements/View.js +209 -183
- package/src/components/elements/ViewLink.js +33 -20
- package/src/components/elements/utils.js +94 -5
- package/src/components/storage.js +2 -0
|
@@ -10,15 +10,15 @@ import optionsCtx from "../context";
|
|
|
10
10
|
import previewCtx from "../preview_context";
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
|
-
blockProps,
|
|
14
|
-
BlockSetting,
|
|
15
|
-
MinRoleSetting,
|
|
16
13
|
fetchViewPreview,
|
|
17
14
|
ConfigForm,
|
|
18
15
|
setAPropGen,
|
|
19
16
|
FormulaTooltip,
|
|
20
17
|
} from "./utils";
|
|
21
18
|
|
|
19
|
+
import { RelationPicker } from "./RelationPicker";
|
|
20
|
+
import { RelationBadges } from "./RelationBadges";
|
|
21
|
+
|
|
22
22
|
export /**
|
|
23
23
|
* @param {object} props
|
|
24
24
|
* @param {*} props.name
|
|
@@ -29,45 +29,46 @@ export /**
|
|
|
29
29
|
* @subcategory components
|
|
30
30
|
* @namespace
|
|
31
31
|
*/
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
32
|
+
const View = ({ name, view, configuration, state }) => {
|
|
33
|
+
const {
|
|
34
|
+
selected,
|
|
35
|
+
node_id,
|
|
36
|
+
connectors: { connect, drag },
|
|
37
|
+
} = useNode((node) => ({ selected: node.events.selected, node_id: node.id }));
|
|
38
|
+
const options = useContext(optionsCtx);
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
40
|
+
const views = options.views;
|
|
41
|
+
const theview = views.find((v) => v.name === view);
|
|
42
|
+
const label = theview ? theview.label : view;
|
|
43
|
+
const { previews, setPreviews } = useContext(previewCtx);
|
|
44
|
+
const myPreview = previews[node_id];
|
|
45
|
+
useEffect(() => {
|
|
46
|
+
fetchViewPreview({
|
|
47
|
+
options,
|
|
48
|
+
view,
|
|
49
|
+
setPreviews,
|
|
50
|
+
configuration,
|
|
51
|
+
node_id,
|
|
52
|
+
})();
|
|
53
|
+
}, [view, configuration, state]);
|
|
54
|
+
return (
|
|
55
|
+
<div
|
|
56
|
+
ref={(dom) => connect(drag(dom))}
|
|
57
|
+
className={`${myPreview ? "" : "builder-embed-view"} ${
|
|
58
|
+
selected ? "selected-node" : ""
|
|
59
|
+
}`}
|
|
60
|
+
>
|
|
61
|
+
{myPreview ? (
|
|
62
|
+
<div
|
|
63
|
+
className="d-inline"
|
|
64
|
+
dangerouslySetInnerHTML={{ __html: myPreview }}
|
|
65
|
+
></div>
|
|
66
|
+
) : (
|
|
67
|
+
`View: ${label}`
|
|
68
|
+
)}
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
71
|
+
};
|
|
71
72
|
|
|
72
73
|
export /**
|
|
73
74
|
* @returns {div}
|
|
@@ -75,161 +76,186 @@ export /**
|
|
|
75
76
|
* @subcategory components
|
|
76
77
|
* @namespace
|
|
77
78
|
*/
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
79
|
+
const ViewSettings = () => {
|
|
80
|
+
const node = useNode((node) => ({
|
|
81
|
+
view_name: node.data.props.view_name,
|
|
82
|
+
name: node.data.props.name,
|
|
83
|
+
view: node.data.props.view,
|
|
84
|
+
relation: node.data.props.relation,
|
|
85
|
+
state: node.data.props.state,
|
|
86
|
+
extra_state_fml: node.data.props.extra_state_fml,
|
|
87
|
+
configuration: node.data.props.configuration, // fixed states
|
|
88
|
+
node_id: node.id,
|
|
89
|
+
}));
|
|
88
90
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
91
|
+
const {
|
|
92
|
+
actions: { setProp },
|
|
93
|
+
name,
|
|
94
|
+
view,
|
|
95
|
+
relation,
|
|
96
|
+
state,
|
|
97
|
+
node_id,
|
|
98
|
+
configuration,
|
|
99
|
+
extra_state_fml,
|
|
100
|
+
view_name,
|
|
101
|
+
} = node;
|
|
102
|
+
const options = useContext(optionsCtx);
|
|
103
|
+
const views = options.views;
|
|
104
|
+
const fixed_state_fields =
|
|
105
|
+
options.fixed_state_fields && options.fixed_state_fields[view];
|
|
106
|
+
const { setPreviews } = useContext(previewCtx);
|
|
104
107
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
let viewname = view_name || view;
|
|
113
|
-
if (viewname && viewname.includes(":")) viewname = viewname.split(":")[1];
|
|
114
|
-
if (viewname && viewname.includes(".")) viewname = viewname.split(".")[0];
|
|
115
|
-
const set_view_name = (e) => {
|
|
116
|
-
if (e.target) {
|
|
117
|
-
const target_value = e.target.value;
|
|
118
|
-
setProp((prop) => (prop.view_name = target_value));
|
|
119
|
-
if (target_value !== viewname) {
|
|
120
|
-
setProp((prop) => (prop.view = options.view_relation_opts[target_value][0].value));
|
|
108
|
+
const setAProp = setAPropGen(setProp);
|
|
109
|
+
let errorString = false;
|
|
110
|
+
try {
|
|
111
|
+
Function("return " + extra_state_fml);
|
|
112
|
+
} catch (error) {
|
|
113
|
+
errorString = error.message;
|
|
114
|
+
}
|
|
121
115
|
|
|
122
|
-
|
|
116
|
+
let viewname = view_name || view;
|
|
117
|
+
if (viewname && viewname.includes(":")) {
|
|
118
|
+
const [prefix, rest] = viewname.split(":");
|
|
119
|
+
if (rest.startsWith(".")) viewname = prefix;
|
|
120
|
+
else viewname = rest;
|
|
121
|
+
}
|
|
122
|
+
if (viewname.includes(".")) viewname = viewname.split(".")[0];
|
|
123
|
+
|
|
124
|
+
const set_view_name = (e) => {
|
|
125
|
+
if (e.target) {
|
|
126
|
+
const target_value = e.target.value;
|
|
127
|
+
setProp((prop) => (prop.view_name = target_value));
|
|
128
|
+
if (target_value !== viewname) {
|
|
129
|
+
setProp((prop) => {
|
|
130
|
+
if (options.view_relation_opts[target_value]) {
|
|
131
|
+
prop.view = options.view_relation_opts[target_value][0].value;
|
|
132
|
+
prop.relation = undefined;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
123
135
|
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
value={viewname}
|
|
133
|
-
className="form-control form-select"
|
|
134
|
-
onChange={set_view_name}
|
|
135
|
-
onBlur={set_view_name}
|
|
136
|
-
>
|
|
137
|
-
{options.view_name_opts.map((f, ix) => (
|
|
138
|
-
<option key={ix} value={f.name}>
|
|
139
|
-
{f.label}
|
|
140
|
-
</option>
|
|
141
|
-
))}
|
|
142
|
-
</select>
|
|
143
|
-
</div>
|
|
144
|
-
<div>
|
|
145
|
-
<label>Relation</label>
|
|
146
|
-
<select
|
|
147
|
-
value={view}
|
|
148
|
-
className="form-control form-select"
|
|
149
|
-
onChange={setAProp("view")}
|
|
150
|
-
onBlur={setAProp("view")}
|
|
151
|
-
>
|
|
152
|
-
{(options.view_relation_opts[viewname] || []).map((f, ix) => (
|
|
153
|
-
<option key={ix} value={f.value}>
|
|
154
|
-
{f.label}
|
|
155
|
-
</option>
|
|
156
|
-
))}
|
|
157
|
-
</select>
|
|
158
|
-
</div>
|
|
159
|
-
</Fragment>
|
|
160
|
-
: <div>
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<div>
|
|
141
|
+
{options.view_name_opts ? (
|
|
142
|
+
<Fragment>
|
|
143
|
+
<div>
|
|
161
144
|
<label>View to {options.mode === "show" ? "embed" : "show"}</label>
|
|
162
145
|
<select
|
|
163
|
-
value={
|
|
146
|
+
value={viewname}
|
|
164
147
|
className="form-control form-select"
|
|
165
|
-
onChange={
|
|
166
|
-
onBlur={
|
|
148
|
+
onChange={set_view_name}
|
|
149
|
+
onBlur={set_view_name}
|
|
167
150
|
>
|
|
168
|
-
{
|
|
151
|
+
{options.view_name_opts.map((f, ix) => (
|
|
169
152
|
<option key={ix} value={f.name}>
|
|
170
|
-
{f.label
|
|
153
|
+
{f.label}
|
|
171
154
|
</option>
|
|
172
155
|
))}
|
|
173
156
|
</select>
|
|
174
|
-
</div>
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
{"
|
|
207
|
-
<label>Extra state Formula <FormulaTooltip /></label>
|
|
208
|
-
<input
|
|
209
|
-
type="text"
|
|
210
|
-
className="viewlink-label form-control"
|
|
211
|
-
value={extra_state_fml}
|
|
212
|
-
onChange={setAProp("extra_state_fml")}
|
|
213
|
-
/>
|
|
214
|
-
{errorString ? (
|
|
215
|
-
<small className="text-danger font-monospace d-block">
|
|
216
|
-
{errorString}
|
|
217
|
-
</small>
|
|
218
|
-
) : null}
|
|
219
|
-
</Fragment>
|
|
220
|
-
)}
|
|
221
|
-
{view ? (
|
|
222
|
-
<a
|
|
223
|
-
className="d-block mt-2"
|
|
224
|
-
target="_blank"
|
|
225
|
-
href={`/viewedit/config/${viewname}`}
|
|
157
|
+
</div>
|
|
158
|
+
<RelationPicker
|
|
159
|
+
options={options}
|
|
160
|
+
viewname={viewname}
|
|
161
|
+
update={(relPath) => {
|
|
162
|
+
if (relPath.startsWith(".")) {
|
|
163
|
+
setProp((prop) => {
|
|
164
|
+
prop.view = viewname;
|
|
165
|
+
prop.relation = relPath;
|
|
166
|
+
});
|
|
167
|
+
} else {
|
|
168
|
+
setProp((prop) => {
|
|
169
|
+
prop.view = relPath;
|
|
170
|
+
prop.relation = undefined;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
}}
|
|
174
|
+
/>
|
|
175
|
+
<RelationBadges
|
|
176
|
+
view={view}
|
|
177
|
+
relation={relation}
|
|
178
|
+
parentTbl={options.tableName}
|
|
179
|
+
fk_options={options.fk_options}
|
|
180
|
+
/>
|
|
181
|
+
</Fragment>
|
|
182
|
+
) : (
|
|
183
|
+
<div>
|
|
184
|
+
<label>View to {options.mode === "show" ? "embed" : "show"}</label>
|
|
185
|
+
<select
|
|
186
|
+
value={view}
|
|
187
|
+
className="form-control form-select"
|
|
188
|
+
onChange={setAProp("view")}
|
|
189
|
+
onBlur={setAProp("view")}
|
|
226
190
|
>
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
191
|
+
{views.map((f, ix) => (
|
|
192
|
+
<option key={ix} value={f.name}>
|
|
193
|
+
{f.label || f.name}
|
|
194
|
+
</option>
|
|
195
|
+
))}
|
|
196
|
+
</select>
|
|
197
|
+
</div>
|
|
198
|
+
)}
|
|
199
|
+
{options.mode === "page" && (
|
|
200
|
+
<Fragment>
|
|
201
|
+
<div>
|
|
202
|
+
<label>State</label>
|
|
203
|
+
<select
|
|
204
|
+
value={state}
|
|
205
|
+
className="form-control form-select"
|
|
206
|
+
onChange={setAProp("state")}
|
|
207
|
+
onBlur={setAProp("state")}
|
|
208
|
+
>
|
|
209
|
+
<option value="shared">Shared</option>
|
|
210
|
+
<option value="fixed">Fixed</option>
|
|
211
|
+
</select>
|
|
212
|
+
</div>
|
|
213
|
+
{state === "fixed" &&
|
|
214
|
+
fixed_state_fields &&
|
|
215
|
+
fixed_state_fields.length > 0 && (
|
|
216
|
+
<Fragment>
|
|
217
|
+
<h6>View state fields</h6>
|
|
218
|
+
<ConfigForm
|
|
219
|
+
fields={fixed_state_fields}
|
|
220
|
+
configuration={configuration || {}}
|
|
221
|
+
setProp={setProp}
|
|
222
|
+
node={node}
|
|
223
|
+
/>
|
|
224
|
+
</Fragment>
|
|
225
|
+
)}
|
|
226
|
+
</Fragment>
|
|
227
|
+
)}
|
|
228
|
+
{(state === "shared" || options.mode === "page") && (
|
|
229
|
+
<Fragment>
|
|
230
|
+
{" "}
|
|
231
|
+
<label>
|
|
232
|
+
Extra state Formula <FormulaTooltip />
|
|
233
|
+
</label>
|
|
234
|
+
<input
|
|
235
|
+
type="text"
|
|
236
|
+
className="viewlink-label form-control"
|
|
237
|
+
value={extra_state_fml}
|
|
238
|
+
onChange={setAProp("extra_state_fml")}
|
|
239
|
+
/>
|
|
240
|
+
{errorString ? (
|
|
241
|
+
<small className="text-danger font-monospace d-block">
|
|
242
|
+
{errorString}
|
|
243
|
+
</small>
|
|
244
|
+
) : null}
|
|
245
|
+
</Fragment>
|
|
246
|
+
)}
|
|
247
|
+
{view ? (
|
|
248
|
+
<a
|
|
249
|
+
className="d-block mt-2"
|
|
250
|
+
target="_blank"
|
|
251
|
+
href={`/viewedit/config/${viewname}`}
|
|
252
|
+
>
|
|
253
|
+
Configure this view
|
|
254
|
+
</a>
|
|
255
|
+
) : null}
|
|
256
|
+
</div>
|
|
257
|
+
);
|
|
258
|
+
};
|
|
233
259
|
|
|
234
260
|
/**
|
|
235
261
|
* @type {object}
|
|
@@ -8,7 +8,6 @@ import React, { useContext } from "react";
|
|
|
8
8
|
import { useNode } from "@craftjs/core";
|
|
9
9
|
import optionsCtx from "../context";
|
|
10
10
|
import {
|
|
11
|
-
blockProps,
|
|
12
11
|
BlockSetting,
|
|
13
12
|
MinRoleSettingRow,
|
|
14
13
|
OrFormula,
|
|
@@ -18,6 +17,9 @@ import {
|
|
|
18
17
|
FormulaTooltip,
|
|
19
18
|
} from "./utils";
|
|
20
19
|
|
|
20
|
+
import { RelationPicker } from "./RelationPicker";
|
|
21
|
+
import { RelationBadges } from "./RelationBadges";
|
|
22
|
+
|
|
21
23
|
export /**
|
|
22
24
|
* @param {object} props
|
|
23
25
|
* @param {string} props.name
|
|
@@ -91,6 +93,7 @@ export /**
|
|
|
91
93
|
const ViewLinkSettings = () => {
|
|
92
94
|
const node = useNode((node) => ({
|
|
93
95
|
name: node.data.props.name,
|
|
96
|
+
relation: node.data.props.relation,
|
|
94
97
|
block: node.data.props.block,
|
|
95
98
|
minRole: node.data.props.minRole,
|
|
96
99
|
isFormula: node.data.props.isFormula,
|
|
@@ -110,6 +113,7 @@ const ViewLinkSettings = () => {
|
|
|
110
113
|
const {
|
|
111
114
|
actions: { setProp },
|
|
112
115
|
name,
|
|
116
|
+
relation,
|
|
113
117
|
block,
|
|
114
118
|
minRole,
|
|
115
119
|
label,
|
|
@@ -138,10 +142,10 @@ const ViewLinkSettings = () => {
|
|
|
138
142
|
const target_value = e.target.value;
|
|
139
143
|
setProp((prop) => (prop.view_name = target_value));
|
|
140
144
|
if (target_value !== use_view_name) {
|
|
141
|
-
setProp(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
);
|
|
145
|
+
setProp((prop) => {
|
|
146
|
+
prop.name = options.view_relation_opts[target_value][0].value;
|
|
147
|
+
prop.relation = undefined;
|
|
148
|
+
});
|
|
145
149
|
}
|
|
146
150
|
}
|
|
147
151
|
};
|
|
@@ -168,21 +172,29 @@ const ViewLinkSettings = () => {
|
|
|
168
172
|
</tr>
|
|
169
173
|
<tr>
|
|
170
174
|
<td colSpan="2">
|
|
171
|
-
<
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
175
|
+
<RelationPicker
|
|
176
|
+
options={options}
|
|
177
|
+
viewname={use_view_name}
|
|
178
|
+
update={(relPath) => {
|
|
179
|
+
if (relPath.startsWith(".")) {
|
|
180
|
+
setProp((prop) => {
|
|
181
|
+
prop.name = use_view_name;
|
|
182
|
+
prop.relation = relPath;
|
|
183
|
+
});
|
|
184
|
+
} else {
|
|
185
|
+
setProp((prop) => {
|
|
186
|
+
prop.name = relPath;
|
|
187
|
+
prop.relation = undefined;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}}
|
|
191
|
+
/>
|
|
192
|
+
<RelationBadges
|
|
193
|
+
view={name}
|
|
194
|
+
relation={relation}
|
|
195
|
+
parentTbl={options.tableName}
|
|
196
|
+
fk_options={options.fk_options}
|
|
197
|
+
/>
|
|
186
198
|
</td>
|
|
187
199
|
</tr>
|
|
188
200
|
<tr>
|
|
@@ -272,6 +284,7 @@ ViewLink.craft = {
|
|
|
272
284
|
column_type: "ViewLink",
|
|
273
285
|
fields: [
|
|
274
286
|
{ name: "name", segment_name: "view", column_name: "view" },
|
|
287
|
+
"relation",
|
|
275
288
|
{ name: "label", segment_name: "view_label", canBeFormula: true },
|
|
276
289
|
"block",
|
|
277
290
|
"textStyle",
|
|
@@ -471,11 +471,15 @@ export const fetchViewPreview =
|
|
|
471
471
|
let viewname,
|
|
472
472
|
body = configuration ? { ...configuration } : {};
|
|
473
473
|
if (view.includes(":")) {
|
|
474
|
-
const [
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
474
|
+
const [prefix, rest] = view.split(":");
|
|
475
|
+
const tokens = rest.split(".");
|
|
476
|
+
if (rest.startsWith(".")) {
|
|
477
|
+
viewname = prefix;
|
|
478
|
+
} else {
|
|
479
|
+
viewname = tokens[0];
|
|
480
|
+
body.reltype = prefix;
|
|
481
|
+
body.path = rest;
|
|
482
|
+
}
|
|
479
483
|
} else viewname = view;
|
|
480
484
|
|
|
481
485
|
fetchPreview({
|
|
@@ -1319,3 +1323,88 @@ const Tooltip = ({ children }) => {
|
|
|
1319
1323
|
</Tippy>
|
|
1320
1324
|
);
|
|
1321
1325
|
};
|
|
1326
|
+
|
|
1327
|
+
const getFkTarget = (field, options) => {
|
|
1328
|
+
const option = options.find((fk) => fk.name === field);
|
|
1329
|
+
return option ? option.reftable_name : null;
|
|
1330
|
+
};
|
|
1331
|
+
|
|
1332
|
+
export const parseRelationPath = (path, fk_options) => {
|
|
1333
|
+
const result = [];
|
|
1334
|
+
const tokens = path.split(".");
|
|
1335
|
+
if (tokens.length >= 3) {
|
|
1336
|
+
let currentTbl = tokens[1];
|
|
1337
|
+
for (const relation of tokens.slice(2)) {
|
|
1338
|
+
if (relation.indexOf("$") > 0) {
|
|
1339
|
+
const [inboundTbl, inboundKey] = relation.split("$");
|
|
1340
|
+
result.push({ type: "Inbound", table: inboundTbl, key: inboundKey });
|
|
1341
|
+
currentTbl = inboundTbl;
|
|
1342
|
+
} else {
|
|
1343
|
+
const targetTbl = getFkTarget(relation, fk_options[currentTbl]);
|
|
1344
|
+
if (!targetTbl) {
|
|
1345
|
+
console.log(`The foreign key '${relation}' is invalid`);
|
|
1346
|
+
return [];
|
|
1347
|
+
}
|
|
1348
|
+
result.push({ type: "Foreign", table: targetTbl, key: relation });
|
|
1349
|
+
currentTbl = targetTbl;
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
return result;
|
|
1354
|
+
};
|
|
1355
|
+
|
|
1356
|
+
export const parseLegacyRelation = (type, rest, parentTbl) => {
|
|
1357
|
+
switch (type) {
|
|
1358
|
+
case "ChildList": {
|
|
1359
|
+
const path = rest ? rest.split(".") : [];
|
|
1360
|
+
if (path.length === 3) {
|
|
1361
|
+
const [viewName, table, key] = path;
|
|
1362
|
+
return [
|
|
1363
|
+
{
|
|
1364
|
+
type: "Inbound",
|
|
1365
|
+
table,
|
|
1366
|
+
key,
|
|
1367
|
+
},
|
|
1368
|
+
];
|
|
1369
|
+
} else if (path.length === 5) {
|
|
1370
|
+
const [viewName, thrTbl, thrTblFkey, fromTbl, fromTblFkey] = path;
|
|
1371
|
+
return [
|
|
1372
|
+
{
|
|
1373
|
+
type: "Inbound",
|
|
1374
|
+
table: thrTbl,
|
|
1375
|
+
key: thrTblFkey,
|
|
1376
|
+
},
|
|
1377
|
+
{
|
|
1378
|
+
type: "Inbound",
|
|
1379
|
+
table: fromTbl,
|
|
1380
|
+
key: fromTblFkey,
|
|
1381
|
+
},
|
|
1382
|
+
];
|
|
1383
|
+
}
|
|
1384
|
+
break;
|
|
1385
|
+
}
|
|
1386
|
+
case "Independent": {
|
|
1387
|
+
return [{ type: "Independent", table: "None (no relation)" }];
|
|
1388
|
+
}
|
|
1389
|
+
case "Own": {
|
|
1390
|
+
return [{ type: "Own", table: `${parentTbl} (same table)` }];
|
|
1391
|
+
}
|
|
1392
|
+
case "OneToOneShow": {
|
|
1393
|
+
const tokens = rest ? rest.split(".") : [];
|
|
1394
|
+
if (tokens.length !== 3) break;
|
|
1395
|
+
const [viewname, relatedTbl, fkey] = tokens;
|
|
1396
|
+
return [{ type: "Inbound", table: relatedTbl, key: fkey }];
|
|
1397
|
+
}
|
|
1398
|
+
case "ParentShow": {
|
|
1399
|
+
const tokens = rest ? rest.split(".") : [];
|
|
1400
|
+
if (tokens.length !== 3) break;
|
|
1401
|
+
const [viewname, parentTbl, fkey] = tokens;
|
|
1402
|
+
return [{ type: "Foreign", table: parentTbl, key: fkey }];
|
|
1403
|
+
}
|
|
1404
|
+
}
|
|
1405
|
+
return [];
|
|
1406
|
+
};
|
|
1407
|
+
|
|
1408
|
+
export const removeWhitespaces = (str) => {
|
|
1409
|
+
return str.replace(/\s/g, "X");
|
|
1410
|
+
};
|
|
@@ -142,6 +142,7 @@ export /**
|
|
|
142
142
|
<View
|
|
143
143
|
key={ix}
|
|
144
144
|
view={segment.view}
|
|
145
|
+
relation={segment.relation}
|
|
145
146
|
view_name={segment.view_name}
|
|
146
147
|
name={segment.name}
|
|
147
148
|
state={segment.state}
|
|
@@ -457,6 +458,7 @@ export /**
|
|
|
457
458
|
return {
|
|
458
459
|
type: "view",
|
|
459
460
|
view: node.props.view,
|
|
461
|
+
relation: node.props.relation,
|
|
460
462
|
name:
|
|
461
463
|
node.props.name === "not_assigned" ? rand_ident() : node.props.name,
|
|
462
464
|
state: node.props.state,
|