@saltcorn/builder 0.9.4-beta.14 → 0.9.4-beta.15

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.4-beta.14",
3
+ "version": "0.9.4-beta.15",
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.14",
23
+ "@saltcorn/common-code": "0.9.4-beta.15",
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",
@@ -39,6 +39,7 @@
39
39
  "react-bootstrap-icons": "1.5.0",
40
40
  "react-contenteditable": "3.3.5",
41
41
  "react-dom": "16.13.1",
42
+ "react-select": "4.3.1",
42
43
  "react-test-renderer": "16.13.1",
43
44
  "react-transition-group": "4.4.1",
44
45
  "@tippyjs/react": "4.2.6",
@@ -18,7 +18,7 @@ import { JoinField } from "./elements/JoinField";
18
18
  import { Aggregation } from "./elements/Aggregation";
19
19
  import { LineBreak } from "./elements/LineBreak";
20
20
  import { ViewLink } from "./elements/ViewLink";
21
- import { Columns } from "./elements/Columns";
21
+ import { Columns, ntimes } from "./elements/Columns";
22
22
  import { SearchBar } from "./elements/SearchBar";
23
23
  import { HTMLCode } from "./elements/HTMLCode";
24
24
  import { Action } from "./elements/Action";
@@ -37,6 +37,7 @@ import {
37
37
  ToolboxEdit,
38
38
  ToolboxPage,
39
39
  ToolboxFilter,
40
+ ToolboxList,
40
41
  } from "./Toolbox";
41
42
  import { craftToSaltcorn, layoutToNodes } from "./storage";
42
43
  import { Card } from "./elements/Card";
@@ -53,6 +54,7 @@ import {
53
54
  faTrashAlt,
54
55
  faSave,
55
56
  faExclamationTriangle,
57
+ faPlus,
56
58
  } from "@fortawesome/free-solid-svg-icons";
57
59
  import {
58
60
  faCaretSquareLeft,
@@ -65,6 +67,8 @@ import {
65
67
  } from "./elements/utils";
66
68
  import { InitNewElement, Library } from "./Library";
67
69
  import { RenderNode } from "./RenderNode";
70
+ import { ListColumn } from "./elements/ListColumn";
71
+ import { ListColumns } from "./elements/ListColumns";
68
72
  const { Provider } = optionsCtx;
69
73
 
70
74
  /**
@@ -253,58 +257,20 @@ const SettingsPanel = () => {
253
257
  );
254
258
  };
255
259
 
256
- /**
257
- * @returns {button}
258
- * @category saltcorn-builder
259
- * @subcategory components
260
- * @namespace
261
- */
262
- const SaveButton = () => {
260
+ const AddColumnButton = () => {
263
261
  const { query, actions } = useEditor(() => {});
264
262
  const options = useContext(optionsCtx);
265
-
266
- /**
267
- * @returns {void}
268
- */
269
- const onClick = () => {
270
- const data = craftToSaltcorn(JSON.parse(query.serialize()));
271
- const urlroot = options.page_id ? "pageedit" : "viewedit";
272
- fetch(`/${urlroot}/savebuilder/${options.page_id || options.view_id}`, {
273
- method: "POST", // or 'PUT'
274
- headers: {
275
- "Content-Type": "application/json",
276
- "CSRF-Token": options.csrfToken,
277
- },
278
- body: JSON.stringify(data),
279
- });
263
+ const addColumn = () => {
264
+ actions.addNodeTree(
265
+ query.parseReactElement(<ListColumn />).toNodeTree(),
266
+ "ROOT"
267
+ );
280
268
  };
281
- return options.page_id || options.view_id ? (
282
- <button
283
- className="btn btn-sm btn-outline-secondary me-2 builder-save-ajax"
284
- onClick={onClick}
285
- >
286
- Save
269
+ return (
270
+ <button className="btn btn-primary mt-2" onClick={addColumn}>
271
+ <FontAwesomeIcon icon={faPlus} className="me-2" />
272
+ Add column
287
273
  </button>
288
- ) : (
289
- ""
290
- );
291
- };
292
-
293
- /**
294
- * @returns {a|""}
295
- * @category saltcorn-builder
296
- * @subcategory components
297
- * @namespace
298
- */
299
- const ViewPageLink = () => {
300
- const { query, actions } = useEditor(() => {});
301
- const options = useContext(optionsCtx);
302
- return options.page_id ? (
303
- <a target="_blank" className="d-block" href={`/page/${options.page_name}`}>
304
- View page in new tab &raquo;
305
- </a>
306
- ) : (
307
- ""
308
274
  );
309
275
  };
310
276
 
@@ -357,14 +323,18 @@ const NextButton = ({ layout }) => {
357
323
  const options = useContext(optionsCtx);
358
324
 
359
325
  useEffect(() => {
360
- layoutToNodes(layout, query, actions);
326
+ layoutToNodes(layout, query, actions, "ROOT", options);
361
327
  }, []);
362
328
 
363
329
  /**
364
330
  * @returns {void}
365
331
  */
366
332
  const onClick = () => {
367
- const { columns, layout } = craftToSaltcorn(JSON.parse(query.serialize()));
333
+ const { columns, layout } = craftToSaltcorn(
334
+ JSON.parse(query.serialize()),
335
+ "ROOT",
336
+ options
337
+ );
368
338
  document
369
339
  .querySelector("form#scbuildform input[name=columns]")
370
340
  .setAttribute("value", encodeURIComponent(JSON.stringify(columns)));
@@ -430,6 +400,7 @@ const Builder = ({ options, layout, mode }) => {
430
400
  <div className="card mt-1" accordiontitle="Components">
431
401
  {{
432
402
  show: <ToolboxShow expanded={isLeftEnlarged} />,
403
+ list: <ToolboxList expanded={isLeftEnlarged} />,
433
404
  edit: <ToolboxEdit expanded={isLeftEnlarged} />,
434
405
  page: <ToolboxPage expanded={isLeftEnlarged} />,
435
406
  filter: <ToolboxFilter expanded={isLeftEnlarged} />,
@@ -442,7 +413,7 @@ const Builder = ({ options, layout, mode }) => {
442
413
  </div>
443
414
  <div
444
415
  className="card toolbox-card pe-0"
445
- style={isLeftEnlarged ? { width: "12.35rem" } : {}}
416
+ style={isLeftEnlarged ? { width: "13.4rem" } : {}}
446
417
  >
447
418
  <div className="card-header p-2 d-flex justify-content-between">
448
419
  <div>Layers</div>
@@ -466,7 +437,9 @@ const Builder = ({ options, layout, mode }) => {
466
437
  </div>
467
438
  <div
468
439
  id="builder-main-canvas"
469
- className={`col builder-mode-${options.mode}`}
440
+ className={`col builder-mode-${options.mode} ${
441
+ options.mode !== "list" ? "emptymsg" : ""
442
+ }`}
470
443
  >
471
444
  <div>
472
445
  <Frame
@@ -493,10 +466,17 @@ const Builder = ({ options, layout, mode }) => {
493
466
  Tabs,
494
467
  Table,
495
468
  ToggleFilter,
469
+ ListColumn,
470
+ ListColumns,
496
471
  }}
497
472
  >
498
- <Element canvas is={Column}></Element>
473
+ {options.mode === "list" ? (
474
+ <Element canvas is={ListColumns}></Element>
475
+ ) : (
476
+ <Element canvas is={Column}></Element>
477
+ )}
499
478
  </Frame>
479
+ {options.mode === "list" ? <AddColumnButton /> : null}
500
480
  </div>
501
481
  </div>
502
482
  <div className="col-sm-auto builder-sidebar">
@@ -93,7 +93,11 @@ const InitNewElement = ({ nodekeys, savingState, setSavingState }) => {
93
93
  const doSave = (query) => {
94
94
  if (!query.serialize) return;
95
95
 
96
- const data = craftToSaltcorn(JSON.parse(query.serialize()));
96
+ const data = craftToSaltcorn(
97
+ JSON.parse(query.serialize()),
98
+ "ROOT",
99
+ options
100
+ );
97
101
  const urlroot = options.page_id ? "pageedit" : "viewedit";
98
102
  if (savedData.current === false) {
99
103
  //do not save on first call
@@ -160,7 +164,8 @@ const InitNewElement = ({ nodekeys, savingState, setSavingState }) => {
160
164
  layout.layout ? layout.layout : layout,
161
165
  query,
162
166
  actions,
163
- node.parent
167
+ node.parent,
168
+ options
164
169
  );
165
170
  setTimeout(() => {
166
171
  actions.delete(id);
@@ -212,7 +217,11 @@ const Library = ({ expanded }) => {
212
217
  * @returns {void}
213
218
  */
214
219
  const addSelected = () => {
215
- const layout = craftToSaltcorn(JSON.parse(query.serialize()), selected);
220
+ const layout = craftToSaltcorn(
221
+ JSON.parse(query.serialize()),
222
+ selected,
223
+ options
224
+ );
216
225
  const data = { layout, icon, name: newName };
217
226
  fetch(`/library/savefrombuilder`, {
218
227
  method: "POST", // or 'PUT'
@@ -80,6 +80,11 @@ const RenderNode = ({ render }) => {
80
80
  currentDOM.style.left = left;
81
81
  }, [dom, getPos]);
82
82
 
83
+ useEffect(() => {
84
+ if (name === "Column" && parent && parent !== "ROOT")
85
+ actions.selectNode(parent);
86
+ }, [isActive]);
87
+
83
88
  useEffect(() => {
84
89
  document
85
90
  .getElementById("builder-main-canvas")
@@ -570,6 +570,54 @@ const ToolboxShow = ({ expanded }) => {
570
570
  expanded
571
571
  );
572
572
  };
573
+ export /**
574
+ * @returns {Fragment}
575
+ * @category saltcorn-builder
576
+ * @subcategory components / Toolbox
577
+ * @namespace
578
+ */
579
+ const ToolboxList = ({ expanded }) => {
580
+ const { connectors, query } = useEditor();
581
+ const options = useContext(optionsCtx);
582
+ const {
583
+ fields,
584
+ field_view_options,
585
+ child_field_list,
586
+ agg_field_opts,
587
+ views,
588
+ images,
589
+ } = options;
590
+ return chunkToolBox(
591
+ [
592
+ <TextElem connectors={connectors} />,
593
+ <FieldElem
594
+ connectors={connectors}
595
+ fields={fields}
596
+ field_view_options={field_view_options}
597
+ />,
598
+ <JoinFieldElem connectors={connectors} options={options} />,
599
+ <ViewLinkElem connectors={connectors} options={options} />,
600
+ <ActionElem connectors={connectors} options={options} />,
601
+ <LinkElem connectors={connectors} />,
602
+ <AggregationElem
603
+ connectors={connectors}
604
+ child_field_list={child_field_list}
605
+ agg_field_opts={agg_field_opts}
606
+ />,
607
+ // <ViewElem connectors={connectors} views={views} />,
608
+ // <ContainerElem connectors={connectors} />,
609
+ // <CardElem connectors={connectors} />,
610
+ // <TabsElem connectors={connectors} />,
611
+ <HTMLElem connectors={connectors} />,
612
+ <DropMenuElem connectors={connectors} />,
613
+ // <TableElem connectors={connectors} />,
614
+ ...(options.allowMultipleElementsPerColumn
615
+ ? [<LineBreakElem connectors={connectors} />]
616
+ : []),
617
+ ],
618
+ expanded
619
+ );
620
+ };
573
621
 
574
622
  export /**
575
623
  * @returns {Fragment}
@@ -141,13 +141,15 @@ const AggregationSettings = () => {
141
141
  )}
142
142
  {options.fields
143
143
  .filter((f) => f.type === "Date" || f.type.name === "Date")
144
- .map((f) => (
145
- <option value={`Latest ${f.name}`}>Latest {f.name}</option>
144
+ .map((f, ix) => (
145
+ <option key={ix} value={`Latest ${f.name}`}>
146
+ Latest {f.name}
147
+ </option>
146
148
  ))}
147
149
  {options.fields
148
150
  .filter((f) => f.type === "Date" || f.type.name === "Date")
149
- .map((f) => (
150
- <option value={`Earliest ${f.name}`}>
151
+ .map((f, ix) => (
152
+ <option key={ix} value={`Earliest ${f.name}`}>
151
153
  Earliest {f.name}
152
154
  </option>
153
155
  ))}
@@ -25,12 +25,20 @@ const Column = ({ children, align }) => {
25
25
  id,
26
26
  connectors: { connect, drag },
27
27
  } = useNode((node) => ({ selected: node.events.selected }));
28
+ const options = useContext(optionsCtx);
29
+
28
30
  return (
29
31
  <div
30
- className={selected ? "selected-node" : ""}
32
+ className={`${selected ? "selected-node" : ""} ${
33
+ options.mode === "list" ? "flex-50 list-col-contents" : ""
34
+ }`}
31
35
  ref={(dom) => connect(drag(dom))}
32
36
  >
33
- <div className={`canvas ${id === "ROOT" ? "root-canvas" : ""}`}>
37
+ <div
38
+ className={`canvas ${id === "ROOT" ? "root-canvas" : ""} ${
39
+ options.mode === "list" ? "list-empty-msg list-col-canvas" : ""
40
+ }`}
41
+ >
34
42
  {children}
35
43
  </div>
36
44
  </div>
@@ -56,6 +64,12 @@ Column.craft = {
56
64
  props: {},
57
65
  rules: {
58
66
  canDrag: () => true,
67
+ canMoveIn: (incomming, current) => {
68
+ if (current?.data?.props?.singleOccupancy && current.data.nodes?.length)
69
+ return false;
70
+
71
+ return true;
72
+ },
59
73
  },
60
74
  related: {
61
75
  settings: ColumnSettings,
@@ -46,7 +46,7 @@ const fields = (mode) => {
46
46
  type: "textarea",
47
47
  segment_name: "contents",
48
48
  sublabel:
49
- mode === "show"
49
+ mode === "show" || mode === "list"
50
50
  ? "Access fields with <code>{{ var_name }}</code>"
51
51
  : undefined,
52
52
  },
@@ -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
+ };
@@ -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
- {mode === "show" && (
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
- {mode === "show" && isFormula.text ? (
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,
@@ -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.target) {
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
- <select
248
- value={viewname}
249
- className="form-control form-select"
250
- onChange={set_view_name}
251
- onBlur={set_view_name}
252
- >
253
- {options.views.map((v, ix) => (
254
- <option key={ix} value={v.name}>
255
- {v.label}
256
- </option>
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>