@saltcorn/builder 0.9.4-beta.9 → 0.9.4
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 +20 -12
- package/package.json +3 -2
- package/src/components/Builder.js +34 -54
- package/src/components/Library.js +16 -4
- package/src/components/RenderNode.js +5 -0
- package/src/components/Toolbox.js +61 -2
- package/src/components/elements/Action.js +12 -0
- package/src/components/elements/Aggregation.js +200 -104
- package/src/components/elements/BoxModelEditor.js +8 -8
- package/src/components/elements/Column.js +16 -2
- package/src/components/elements/Columns.js +3 -3
- package/src/components/elements/Container.js +25 -1
- package/src/components/elements/DropMenu.js +31 -2
- package/src/components/elements/Field.js +22 -20
- package/src/components/elements/HTMLCode.js +1 -1
- package/src/components/elements/JoinField.js +25 -1
- package/src/components/elements/Link.js +1 -0
- package/src/components/elements/ListColumn.js +177 -0
- package/src/components/elements/ListColumns.js +62 -0
- package/src/components/elements/Tabs.js +26 -0
- package/src/components/elements/Text.js +4 -2
- package/src/components/elements/View.js +37 -32
- package/src/components/elements/ViewLink.js +21 -14
- package/src/components/elements/utils.js +64 -24
- package/src/components/storage.js +65 -5
- package/tests/relations_finder.test.js +1 -0
|
@@ -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
|
],
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @category saltcorn-builder
|
|
3
|
+
* @module components/elements/Column
|
|
4
|
+
* @subcategory components / elements
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, {
|
|
8
|
+
useContext,
|
|
9
|
+
Fragment,
|
|
10
|
+
useRef,
|
|
11
|
+
useEffect,
|
|
12
|
+
useState,
|
|
13
|
+
} from "react";
|
|
14
|
+
|
|
15
|
+
import { Element, useNode, useEditor } from "@craftjs/core";
|
|
16
|
+
import { setAPropGen, SettingsFromFields } from "./utils";
|
|
17
|
+
import { Column } from "./Column";
|
|
18
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
19
|
+
import { faArrowUp, faArrowDown } from "@fortawesome/free-solid-svg-icons";
|
|
20
|
+
import optionsCtx from "../context";
|
|
21
|
+
|
|
22
|
+
export /**
|
|
23
|
+
*
|
|
24
|
+
* @param {object} props
|
|
25
|
+
* @param {string} props.children
|
|
26
|
+
* @param {*} props.align
|
|
27
|
+
* @returns {div}
|
|
28
|
+
* @category saltcorn-builder
|
|
29
|
+
* @subcategory components
|
|
30
|
+
* @namespace
|
|
31
|
+
*/
|
|
32
|
+
const ListColumn = ({
|
|
33
|
+
alignment,
|
|
34
|
+
colIndex,
|
|
35
|
+
contents,
|
|
36
|
+
header_label,
|
|
37
|
+
showif,
|
|
38
|
+
col_width,
|
|
39
|
+
col_width_units,
|
|
40
|
+
}) => {
|
|
41
|
+
const {
|
|
42
|
+
selected,
|
|
43
|
+
id,
|
|
44
|
+
connectors: { connect, drag },
|
|
45
|
+
} = useNode((node) => ({ selected: node.events.selected }));
|
|
46
|
+
const { actions, query, isActve } = useEditor((state) => ({}));
|
|
47
|
+
const options = useContext(optionsCtx);
|
|
48
|
+
|
|
49
|
+
const {
|
|
50
|
+
data: { parent },
|
|
51
|
+
} = query.node(id).get();
|
|
52
|
+
const siblings = query.node(parent).childNodes();
|
|
53
|
+
const nChildren = siblings.length;
|
|
54
|
+
const childIx = siblings.findIndex((sib) => sib === id);
|
|
55
|
+
|
|
56
|
+
const moveDown = () => {
|
|
57
|
+
const {
|
|
58
|
+
data: { parent },
|
|
59
|
+
} = query.node(id).get();
|
|
60
|
+
actions.move(id, parent, childIx + 2);
|
|
61
|
+
};
|
|
62
|
+
const moveUp = () => {
|
|
63
|
+
const {
|
|
64
|
+
data: { parent },
|
|
65
|
+
} = query.node(id).get();
|
|
66
|
+
actions.move(id, parent, childIx - 1);
|
|
67
|
+
};
|
|
68
|
+
return (
|
|
69
|
+
<div
|
|
70
|
+
className={`${
|
|
71
|
+
selected ? "selected-node" : ""
|
|
72
|
+
} d-flex w-100 list-column-outer`}
|
|
73
|
+
ref={(dom) => connect(drag(dom))}
|
|
74
|
+
>
|
|
75
|
+
<div className={`list-column flex-50 p-2`}>
|
|
76
|
+
<div className="d-flex justify-content-between h-100">
|
|
77
|
+
<div className="">
|
|
78
|
+
Column {childIx}
|
|
79
|
+
{header_label ? `: ${header_label}` : ""}
|
|
80
|
+
<br />
|
|
81
|
+
{showif ? (
|
|
82
|
+
<span className="badge bg-secondary me-2">showif</span>
|
|
83
|
+
) : (
|
|
84
|
+
""
|
|
85
|
+
)}
|
|
86
|
+
{alignment && alignment !== "Default" ? (
|
|
87
|
+
<span className="badge bg-secondary me-2">Align {alignment}</span>
|
|
88
|
+
) : (
|
|
89
|
+
""
|
|
90
|
+
)}
|
|
91
|
+
{col_width ? (
|
|
92
|
+
<span className="badge bg-secondary me-2">
|
|
93
|
+
{col_width}
|
|
94
|
+
{col_width_units}
|
|
95
|
+
</span>
|
|
96
|
+
) : (
|
|
97
|
+
""
|
|
98
|
+
)}
|
|
99
|
+
</div>
|
|
100
|
+
<div className="d-flex flex-column h-100 justify-content-between">
|
|
101
|
+
{childIx !== null && childIx > 0 ? (
|
|
102
|
+
<FontAwesomeIcon icon={faArrowUp} onClick={moveUp} />
|
|
103
|
+
) : (
|
|
104
|
+
<span></span>
|
|
105
|
+
)}
|
|
106
|
+
{childIx !== null && childIx < nChildren - 1 ? (
|
|
107
|
+
<FontAwesomeIcon icon={faArrowDown} onClick={moveDown} />
|
|
108
|
+
) : (
|
|
109
|
+
<span></span>
|
|
110
|
+
)}
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
<Element
|
|
115
|
+
canvas
|
|
116
|
+
id={`listcol`}
|
|
117
|
+
is={Column}
|
|
118
|
+
singleOccupancy={!options.allowMultipleElementsPerColumn}
|
|
119
|
+
>
|
|
120
|
+
{contents}
|
|
121
|
+
</Element>
|
|
122
|
+
</div>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const fields = [
|
|
127
|
+
{
|
|
128
|
+
name: "header_label",
|
|
129
|
+
label: "Header label",
|
|
130
|
+
type: "String",
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: "showif",
|
|
134
|
+
label: "Show if true",
|
|
135
|
+
sublabel: "Formula. Leave blank to always show",
|
|
136
|
+
class: "validate-expression",
|
|
137
|
+
type: "String",
|
|
138
|
+
required: false,
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: "col_width",
|
|
142
|
+
label: "Column width",
|
|
143
|
+
type: "Integer",
|
|
144
|
+
attributes: { asideNext: true },
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
name: "col_width_units",
|
|
148
|
+
label: "Units",
|
|
149
|
+
type: "String",
|
|
150
|
+
required: true,
|
|
151
|
+
attributes: {
|
|
152
|
+
inline: true,
|
|
153
|
+
options: ["px", "%", "vw", "em", "rem"],
|
|
154
|
+
},
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
name: "alignment",
|
|
158
|
+
label: "Alignment",
|
|
159
|
+
input_type: "select",
|
|
160
|
+
options: ["Default", "Left", "Center", "Right"],
|
|
161
|
+
},
|
|
162
|
+
];
|
|
163
|
+
ListColumn.craft = {
|
|
164
|
+
displayName: "ListColumn",
|
|
165
|
+
props: {},
|
|
166
|
+
rules: {
|
|
167
|
+
canDrag: () => true,
|
|
168
|
+
},
|
|
169
|
+
related: {
|
|
170
|
+
settings: SettingsFromFields(fields, {
|
|
171
|
+
additionalFieldsOptionKey: "additionalColumnFields",
|
|
172
|
+
}),
|
|
173
|
+
segment_type: "list_column",
|
|
174
|
+
hasContents: true,
|
|
175
|
+
colFields: fields,
|
|
176
|
+
},
|
|
177
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @category saltcorn-builder
|
|
3
|
+
* @module components/elements/ListColumns
|
|
4
|
+
* @subcategory components / elements
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import React, { useContext, Fragment } from "react";
|
|
8
|
+
|
|
9
|
+
import { Element, useNode } from "@craftjs/core";
|
|
10
|
+
import optionsCtx from "../context";
|
|
11
|
+
|
|
12
|
+
export /**
|
|
13
|
+
*
|
|
14
|
+
* @param {object} props
|
|
15
|
+
* @param {string} props.children
|
|
16
|
+
* @param {*} props.align
|
|
17
|
+
* @returns {div}
|
|
18
|
+
* @category saltcorn-builder
|
|
19
|
+
* @subcategory components
|
|
20
|
+
* @namespace
|
|
21
|
+
*/
|
|
22
|
+
const ListColumns = ({ children, align }) => {
|
|
23
|
+
const {
|
|
24
|
+
selected,
|
|
25
|
+
id,
|
|
26
|
+
connectors: { connect, drag },
|
|
27
|
+
} = useNode((node) => ({ selected: node.events.selected }));
|
|
28
|
+
return (
|
|
29
|
+
<div className={selected ? "selected-node" : ""}>
|
|
30
|
+
<div className={` ${id === "ROOT" ? "root-canvas" : ""}`}>{children}</div>
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export /**
|
|
36
|
+
* @returns {div}
|
|
37
|
+
* @category saltcorn-builder
|
|
38
|
+
* @subcategory components
|
|
39
|
+
* @namespace
|
|
40
|
+
*/
|
|
41
|
+
const ListColumnsSettings = () => {
|
|
42
|
+
useNode((node) => ({}));
|
|
43
|
+
return <div></div>;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* @type {object}
|
|
48
|
+
*/
|
|
49
|
+
ListColumns.craft = {
|
|
50
|
+
displayName: "ListColumns",
|
|
51
|
+
props: {},
|
|
52
|
+
rules: {
|
|
53
|
+
canDrag: () => false,
|
|
54
|
+
canDrop: () => false,
|
|
55
|
+
canMoveIn: (incoming) => {
|
|
56
|
+
return incoming?.data?.displayName === "ListColumn";
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
related: {
|
|
60
|
+
settings: ListColumnsSettings,
|
|
61
|
+
},
|
|
62
|
+
};
|
|
@@ -185,6 +185,7 @@ const TabsSettings = () => {
|
|
|
185
185
|
titles: node.data.props.titles,
|
|
186
186
|
showif: node.data.props.showif,
|
|
187
187
|
field: node.data.props.field,
|
|
188
|
+
acc_init_opens: node.data.props.acc_init_opens,
|
|
188
189
|
}));
|
|
189
190
|
const {
|
|
190
191
|
actions: { setProp },
|
|
@@ -200,6 +201,7 @@ const TabsSettings = () => {
|
|
|
200
201
|
tabId,
|
|
201
202
|
showif,
|
|
202
203
|
setting_tab_n,
|
|
204
|
+
acc_init_opens,
|
|
203
205
|
} = node;
|
|
204
206
|
const use_setting_tab_n = setting_tab_n || 0;
|
|
205
207
|
const options = useContext(optionsCtx);
|
|
@@ -450,6 +452,29 @@ const TabsSettings = () => {
|
|
|
450
452
|
</tr>
|
|
451
453
|
</Fragment>
|
|
452
454
|
) : null}
|
|
455
|
+
{tabsStyle === "Accordion" ? (
|
|
456
|
+
<tr>
|
|
457
|
+
<td colSpan="2">
|
|
458
|
+
<div className="form-check">
|
|
459
|
+
<input
|
|
460
|
+
className="form-check-input"
|
|
461
|
+
name="block"
|
|
462
|
+
type="checkbox"
|
|
463
|
+
checked={acc_init_opens?.[use_setting_tab_n] || false}
|
|
464
|
+
onChange={(e) => {
|
|
465
|
+
if (!e.target) return;
|
|
466
|
+
const value = e.target.checked;
|
|
467
|
+
setProp((prop) => {
|
|
468
|
+
if (!prop.acc_init_opens) prop.acc_init_opens = [];
|
|
469
|
+
prop.acc_init_opens[use_setting_tab_n] = value;
|
|
470
|
+
});
|
|
471
|
+
}}
|
|
472
|
+
/>
|
|
473
|
+
<label className="form-check-label">Initially open</label>
|
|
474
|
+
</div>
|
|
475
|
+
</td>
|
|
476
|
+
</tr>
|
|
477
|
+
) : null}
|
|
453
478
|
</Fragment>
|
|
454
479
|
)}
|
|
455
480
|
</tbody>
|
|
@@ -464,6 +489,7 @@ Tabs.craft = {
|
|
|
464
489
|
props: {
|
|
465
490
|
titles: ["Tab1", "Tab2"],
|
|
466
491
|
showif: [],
|
|
492
|
+
acc_init_opens: [],
|
|
467
493
|
ntabs: 2,
|
|
468
494
|
tabsStyle: "Tabs",
|
|
469
495
|
independent: false,
|
|
@@ -179,9 +179,11 @@ const TextSettings = () => {
|
|
|
179
179
|
} = node;
|
|
180
180
|
const { mode, fields } = useContext(optionsCtx);
|
|
181
181
|
const setAProp = setAPropGen(setProp);
|
|
182
|
+
const allowFormula = mode === "show" || mode === "list";
|
|
183
|
+
|
|
182
184
|
return (
|
|
183
185
|
<div>
|
|
184
|
-
{
|
|
186
|
+
{allowFormula && (
|
|
185
187
|
<div className="form-check">
|
|
186
188
|
<input
|
|
187
189
|
type="checkbox"
|
|
@@ -197,7 +199,7 @@ const TextSettings = () => {
|
|
|
197
199
|
</div>
|
|
198
200
|
)}
|
|
199
201
|
<label>Text to display</label>
|
|
200
|
-
{
|
|
202
|
+
{allowFormula && isFormula.text ? (
|
|
201
203
|
<input
|
|
202
204
|
type="text"
|
|
203
205
|
className="text-to-display form-control"
|
|
@@ -9,6 +9,7 @@ import { useNode } from "@craftjs/core";
|
|
|
9
9
|
import optionsCtx from "../context";
|
|
10
10
|
import previewCtx from "../preview_context";
|
|
11
11
|
import relationsCtx from "../relations_context";
|
|
12
|
+
import Select from "react-select";
|
|
12
13
|
|
|
13
14
|
import {
|
|
14
15
|
fetchViewPreview,
|
|
@@ -151,7 +152,7 @@ const ViewSettings = () => {
|
|
|
151
152
|
if (rest.startsWith(".")) viewname = prefix;
|
|
152
153
|
else viewname = rest;
|
|
153
154
|
}
|
|
154
|
-
if (viewname.includes(".")) viewname = viewname.split(".")[0];
|
|
155
|
+
if (viewname && viewname.includes(".")) viewname = viewname.split(".")[0];
|
|
155
156
|
|
|
156
157
|
if (
|
|
157
158
|
finder &&
|
|
@@ -176,7 +177,7 @@ const ViewSettings = () => {
|
|
|
176
177
|
: [undefined, undefined];
|
|
177
178
|
let safeRelation = null;
|
|
178
179
|
const subView = views.find((view) => view.name === viewname);
|
|
179
|
-
if (relation) {
|
|
180
|
+
if (relation && subView) {
|
|
180
181
|
const subTbl = tables.find((tbl) => tbl.id === subView.table_id);
|
|
181
182
|
safeRelation = new Relation(
|
|
182
183
|
relation,
|
|
@@ -186,7 +187,7 @@ const ViewSettings = () => {
|
|
|
186
187
|
}
|
|
187
188
|
if (
|
|
188
189
|
options.mode !== "filter" &&
|
|
189
|
-
subView
|
|
190
|
+
subView?.table_id &&
|
|
190
191
|
!safeRelation &&
|
|
191
192
|
!hasLegacyRelation &&
|
|
192
193
|
relationsData?.relations.length > 0
|
|
@@ -199,8 +200,8 @@ const ViewSettings = () => {
|
|
|
199
200
|
const helpContext = { view_name: viewname };
|
|
200
201
|
if (options.tableName) helpContext.srcTable = options.tableName;
|
|
201
202
|
const set_view_name = (e) => {
|
|
202
|
-
if (e
|
|
203
|
-
const target_value = e.target.value;
|
|
203
|
+
if (e?.target?.value || e?.value) {
|
|
204
|
+
const target_value = e.target?.value || e.value;
|
|
204
205
|
if (target_value !== viewname) {
|
|
205
206
|
if (options.mode === "filter") {
|
|
206
207
|
setProp((prop) => {
|
|
@@ -237,25 +238,27 @@ const ViewSettings = () => {
|
|
|
237
238
|
}
|
|
238
239
|
}
|
|
239
240
|
};
|
|
240
|
-
|
|
241
|
+
const viewOptions = options.views.map(({ name, label }) => ({
|
|
242
|
+
label,
|
|
243
|
+
value: name,
|
|
244
|
+
}));
|
|
245
|
+
const selectedView = viewOptions.find((v) => v.value === viewname);
|
|
241
246
|
return (
|
|
242
247
|
<div>
|
|
243
248
|
{relationsData ? (
|
|
244
249
|
<Fragment>
|
|
245
250
|
<div>
|
|
246
251
|
<label>View to {options.mode === "show" ? "embed" : "show"}</label>
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
))}
|
|
258
|
-
</select>
|
|
252
|
+
{options.inJestTestingMode ? null : (
|
|
253
|
+
<Select
|
|
254
|
+
options={viewOptions}
|
|
255
|
+
value={selectedView}
|
|
256
|
+
onChange={set_view_name}
|
|
257
|
+
onBlur={set_view_name}
|
|
258
|
+
menuPortalTarget={document.body}
|
|
259
|
+
styles={{ menuPortal: (base) => ({ ...base, zIndex: 19999 }) }}
|
|
260
|
+
></Select>
|
|
261
|
+
)}
|
|
259
262
|
</div>
|
|
260
263
|
{options.mode !== "filter" && (
|
|
261
264
|
<div>
|
|
@@ -287,18 +290,20 @@ const ViewSettings = () => {
|
|
|
287
290
|
) : (
|
|
288
291
|
<div>
|
|
289
292
|
<label>View to {options.mode === "show" ? "embed" : "show"}</label>
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
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
|
+
menuPortalTarget={document.body}
|
|
304
|
+
styles={{ menuPortal: (base) => ({ ...base, zIndex: 19999 }) }}
|
|
305
|
+
></Select>
|
|
306
|
+
)}
|
|
302
307
|
</div>
|
|
303
308
|
)}
|
|
304
309
|
{options.mode !== "edit" && (
|
|
@@ -339,7 +344,7 @@ const ViewSettings = () => {
|
|
|
339
344
|
)}
|
|
340
345
|
</Fragment>
|
|
341
346
|
)}
|
|
342
|
-
{
|
|
347
|
+
{
|
|
343
348
|
<Fragment>
|
|
344
349
|
<label>
|
|
345
350
|
Extra state Formula
|
|
@@ -357,7 +362,7 @@ const ViewSettings = () => {
|
|
|
357
362
|
</small>
|
|
358
363
|
) : null}
|
|
359
364
|
</Fragment>
|
|
360
|
-
|
|
365
|
+
}
|
|
361
366
|
{view ? (
|
|
362
367
|
<a
|
|
363
368
|
className="d-block mt-2"
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
|
|
25
25
|
import { RelationBadges } from "./RelationBadges";
|
|
26
26
|
import { RelationOnDemandPicker } from "./RelationOnDemandPicker";
|
|
27
|
+
import Select from "react-select";
|
|
27
28
|
|
|
28
29
|
import {
|
|
29
30
|
RelationsFinder,
|
|
@@ -201,8 +202,8 @@ const ViewLinkSettings = () => {
|
|
|
201
202
|
});
|
|
202
203
|
}
|
|
203
204
|
const set_view_name = (e) => {
|
|
204
|
-
if (e
|
|
205
|
-
const target_value = e.target.value;
|
|
205
|
+
if (e?.target?.value || e?.value) {
|
|
206
|
+
const target_value = e.target?.value || e.value;
|
|
206
207
|
if (target_value !== use_view_name) {
|
|
207
208
|
const newRelations = finder.findRelations(
|
|
208
209
|
tableName,
|
|
@@ -236,6 +237,11 @@ const ViewLinkSettings = () => {
|
|
|
236
237
|
};
|
|
237
238
|
const helpContext = { view_name: use_view_name };
|
|
238
239
|
if (tableName) helpContext.srcTable = tableName;
|
|
240
|
+
const viewOptions = options.views.map(({ name, label }) => ({
|
|
241
|
+
label,
|
|
242
|
+
value: name,
|
|
243
|
+
}));
|
|
244
|
+
const selectedView = viewOptions.find((v) => v.value === use_view_name);
|
|
239
245
|
return (
|
|
240
246
|
<div>
|
|
241
247
|
<table className="w-100">
|
|
@@ -243,18 +249,18 @@ const ViewLinkSettings = () => {
|
|
|
243
249
|
<tr>
|
|
244
250
|
<td colSpan="2">
|
|
245
251
|
<label>View to link to</label>
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
{
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
252
|
+
{options.inJestTestingMode ? null : (
|
|
253
|
+
<Select
|
|
254
|
+
options={viewOptions}
|
|
255
|
+
value={selectedView}
|
|
256
|
+
onChange={set_view_name}
|
|
257
|
+
onBlur={set_view_name}
|
|
258
|
+
menuPortalTarget={document.body}
|
|
259
|
+
styles={{
|
|
260
|
+
menuPortal: (base) => ({ ...base, zIndex: 19999 }),
|
|
261
|
+
}}
|
|
262
|
+
></Select>
|
|
263
|
+
)}
|
|
258
264
|
</td>
|
|
259
265
|
</tr>
|
|
260
266
|
<tr>
|
|
@@ -323,6 +329,7 @@ const ViewLinkSettings = () => {
|
|
|
323
329
|
values={node}
|
|
324
330
|
linkFirst={true}
|
|
325
331
|
linkIsBlank={true}
|
|
332
|
+
allowRunOnLoad={false}
|
|
326
333
|
/>
|
|
327
334
|
</tbody>
|
|
328
335
|
</table>
|