@mwater/visualization 5.4.2 → 5.4.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.
@@ -2,7 +2,6 @@ import React, { ReactNode } from "react";
2
2
  import { DataSource, Schema } from "@mwater/expressions";
3
3
  import UndoStack from "../UndoStack";
4
4
  import { DashboardViewComponentHandle } from "./DashboardViewComponent";
5
- import QuickfiltersComponent from "../quickfilter/QuickfiltersComponent";
6
5
  import SettingsModalComponent from "./SettingsModalComponent";
7
6
  import { DashboardDesign } from "./DashboardDesign";
8
7
  import DashboardDataSource from "./DashboardDataSource";
@@ -78,25 +77,12 @@ export default class DashboardComponent extends React.Component<DashboardCompone
78
77
  getCompiledFilters(): JsonQLFilter[];
79
78
  /** Translate function to use for display. Do not use when editing. */
80
79
  translate: (input: string) => string;
81
- renderEditingSwitch(): React.DetailedReactHTMLElement<{
82
- key: string;
83
- className: string;
84
- onClick: () => void;
85
- }, HTMLElement>;
86
- renderStyle(): React.DetailedReactHTMLElement<{
87
- type: string;
88
- key: string;
89
- className: string;
90
- onClick: () => void;
91
- }, HTMLElement>;
92
- renderActionLinks(): React.DetailedReactHTMLElement<React.HTMLAttributes<HTMLElement>, HTMLElement>;
93
- renderTitleBar(): React.DetailedReactHTMLElement<{
94
- style: {
95
- height: number;
96
- padding: number;
97
- };
98
- }, HTMLElement>;
99
- renderQuickfilter(): React.CElement<import("../quickfilter/QuickfiltersComponent").QuickfiltersComponentProps, QuickfiltersComponent>;
80
+ renderEditingSwitch(): React.JSX.Element;
81
+ renderStyle(): React.JSX.Element;
82
+ renderActionLinks(): React.JSX.Element;
83
+ renderTitleBar(): React.JSX.Element;
84
+ renderQuickfilter(): React.JSX.Element;
85
+ renderFloatingShowQuickfiltersButton(): React.JSX.Element | null;
100
86
  refDashboardView: (el: any) => void;
101
87
  render(): React.JSX.Element;
102
88
  }
@@ -28,7 +28,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const lodash_1 = __importDefault(require("lodash"));
30
30
  const react_1 = __importDefault(require("react"));
31
- const R = react_1.default.createElement;
32
31
  const UndoStack_1 = __importDefault(require("../UndoStack"));
33
32
  const DashboardUtils = __importStar(require("./DashboardUtils"));
34
33
  const DashboardViewComponent_1 = __importDefault(require("./DashboardViewComponent"));
@@ -162,66 +161,98 @@ class DashboardComponent extends react_1.default.Component {
162
161
  return this.props.design.translations?.[displayLocale]?.[input] ?? input;
163
162
  };
164
163
  renderEditingSwitch() {
165
- return R("a", {
166
- key: "edit",
167
- className: `btn btn-primary btn-sm ${this.state.editing ? "active" : ""}`,
168
- onClick: this.handleToggleEditing
169
- }, R("span", { className: "fas fa-pencil-alt" }), " ", this.state.editing ? T `Editing` : T `Edit`);
164
+ return (react_1.default.createElement("a", { key: "edit", className: `btn btn-primary btn-sm ${this.state.editing ? "active" : ""}`, onClick: this.handleToggleEditing },
165
+ react_1.default.createElement("span", { className: "fas fa-pencil-alt" }),
166
+ " ",
167
+ this.state.editing ? T `Editing` : T `Edit`));
170
168
  }
171
169
  renderStyle() {
172
- return R("button", { type: "button", key: "style", className: "btn btn-link btn-sm", onClick: this.handleOpenLayoutOptions }, R("span", { className: "fa fa-mobile" }), R("span", { className: "hide-600px" }, " ", T `Layout`));
170
+ return (react_1.default.createElement("button", { type: "button", key: "style", className: "btn btn-link btn-sm", onClick: this.handleOpenLayoutOptions },
171
+ react_1.default.createElement("span", { className: "fa fa-mobile" }),
172
+ react_1.default.createElement("span", { className: "hide-600px" },
173
+ " ",
174
+ T `Layout`)));
173
175
  }
174
176
  renderActionLinks() {
175
- return R("div", null, this.state.editing
176
- ? [
177
- R("a", {
178
- key: "undo",
179
- className: `btn btn-link btn-sm ${!this.state.undoStack.canUndo() ? "disabled" : ""}`,
180
- onClick: this.handleUndo
181
- }, R("span", { className: "fas fa-caret-left" }), R("span", { className: "hide-600px" }, " ", T `Undo`)),
182
- " ",
183
- R("a", {
184
- key: "redo",
185
- className: `btn btn-link btn-sm ${!this.state.undoStack.canRedo() ? "disabled" : ""}`,
186
- onClick: this.handleRedo
187
- }, R("span", { className: "fas fa-caret-right" }), R("span", { className: "hide-600px" }, " ", T `Redo`))
188
- ]
189
- : undefined, !this.state.editing && this.props.design.otherLocales && this.props.design.otherLocales.length > 0
190
- ? R("div", { key: "translations", className: "dropdown d-inline-block" }, R("a", {
191
- className: "btn btn-link btn-sm dropdown-toggle",
192
- "data-bs-toggle": "dropdown"
193
- }, R("span", { className: "fal fa-globe" }), " ", this.state.locale), R("ul", { className: "dropdown-menu dropdown-menu-end" }, [this.props.design.locale || "en", ...this.props.design.otherLocales].map(locale => R("li", { key: locale }, R("a", {
194
- className: "dropdown-item",
195
- onClick: () => this.setState({ locale: locale })
196
- }, __1.languages.find(l => l.code === locale)?.name || locale)))))
197
- : undefined, R("a", { key: "print", className: "btn btn-link btn-sm", onClick: this.handlePrint }, R("span", { className: "fas fa-print" }), R("span", { className: "hide-600px" }, " ", T `Print`)), R("a", { key: "refresh", className: "btn btn-link btn-sm", onClick: this.handleRefreshData }, R("span", { className: "fas fa-sync" }), R("span", { className: "hide-600px" }, " ", T `Refresh`)), this.state.hideQuickfilters && this.props.design.quickfilters && this.props.design.quickfilters.length > 0
198
- ? R("a", { key: "showQuickfilters", className: "btn btn-link btn-sm", onClick: this.handleShowQuickfilters }, R("span", { className: "fa fa-filter" }), R("span", { className: "hide-600px" }, " ", T `Show Quickfilters`))
199
- : undefined,
200
- // R 'a', key: "export", className: "btn btn-link btn-sm", onClick: @handleSaveDesignFile,
201
- // R('span', className: "glyphicon glyphicon-download-alt")
202
- // " Export"
203
- this.state.editing
204
- ? R("a", { key: "settings", className: "btn btn-link btn-sm", onClick: this.handleSettings }, R("span", { className: "fas fa-cog" }), R("span", { className: "hide-600px" }, " ", T `Settings`))
205
- : undefined, this.state.editing ? this.renderStyle() : undefined, this.props.extraTitleButtonsElem, this.props.onDesignChange != null ? this.renderEditingSwitch() : undefined);
177
+ return (react_1.default.createElement("div", null,
178
+ this.state.editing
179
+ ? [
180
+ react_1.default.createElement("a", { key: "undo", className: `btn btn-link btn-sm ${!this.state.undoStack.canUndo() ? "disabled" : ""}`, onClick: this.handleUndo },
181
+ react_1.default.createElement("span", { className: "fas fa-caret-left" }),
182
+ react_1.default.createElement("span", { className: "hide-600px" },
183
+ " ",
184
+ T `Undo`)),
185
+ " ",
186
+ react_1.default.createElement("a", { key: "redo", className: `btn btn-link btn-sm ${!this.state.undoStack.canRedo() ? "disabled" : ""}`, onClick: this.handleRedo },
187
+ react_1.default.createElement("span", { className: "fas fa-caret-right" }),
188
+ react_1.default.createElement("span", { className: "hide-600px" },
189
+ " ",
190
+ T `Redo`))
191
+ ]
192
+ : undefined,
193
+ !this.state.editing && this.props.design.otherLocales && this.props.design.otherLocales.length > 0
194
+ ? react_1.default.createElement("div", { key: "translations", className: "dropdown d-inline-block" },
195
+ react_1.default.createElement("a", { className: "btn btn-link btn-sm dropdown-toggle", "data-bs-toggle": "dropdown" },
196
+ react_1.default.createElement("span", { className: "fal fa-globe" }),
197
+ " ",
198
+ this.state.locale),
199
+ react_1.default.createElement("ul", { className: "dropdown-menu dropdown-menu-end" }, [this.props.design.locale || "en", ...this.props.design.otherLocales].map(locale => react_1.default.createElement("li", { key: locale },
200
+ react_1.default.createElement("a", { className: "dropdown-item", onClick: () => this.setState({ locale: locale }) }, __1.languages.find(l => l.code === locale)?.name || locale)))))
201
+ : undefined,
202
+ react_1.default.createElement("a", { key: "print", className: "btn btn-link btn-sm", onClick: this.handlePrint },
203
+ react_1.default.createElement("span", { className: "fas fa-print" }),
204
+ react_1.default.createElement("span", { className: "hide-600px" },
205
+ " ",
206
+ T `Print`)),
207
+ react_1.default.createElement("a", { key: "refresh", className: "btn btn-link btn-sm", onClick: this.handleRefreshData },
208
+ react_1.default.createElement("span", { className: "fas fa-sync" }),
209
+ react_1.default.createElement("span", { className: "hide-600px" },
210
+ " ",
211
+ T `Refresh`)),
212
+ this.state.hideQuickfilters && this.props.design.quickfilters && this.props.design.quickfilters.length > 0
213
+ ? react_1.default.createElement("a", { key: "showQuickfilters", className: "btn btn-link btn-sm", onClick: this.handleShowQuickfilters },
214
+ react_1.default.createElement("span", { className: "fa fa-filter" }),
215
+ react_1.default.createElement("span", { className: "hide-600px" },
216
+ " ",
217
+ T `Show Quickfilters`))
218
+ : undefined,
219
+ this.state.editing
220
+ ? react_1.default.createElement("a", { key: "settings", className: "btn btn-link btn-sm", onClick: this.handleSettings },
221
+ react_1.default.createElement("span", { className: "fas fa-cog" }),
222
+ react_1.default.createElement("span", { className: "hide-600px" },
223
+ " ",
224
+ T `Settings`))
225
+ : undefined,
226
+ this.state.editing ? this.renderStyle() : undefined,
227
+ this.props.extraTitleButtonsElem,
228
+ this.props.onDesignChange != null ? this.renderEditingSwitch() : undefined));
206
229
  }
207
230
  renderTitleBar() {
208
- return R("div", { style: { height: 40, padding: 4 } }, R("div", { style: { float: "right" } }, this.renderActionLinks()), this.props.titleElem);
231
+ return (react_1.default.createElement("div", { style: { height: 40, padding: 4 } },
232
+ react_1.default.createElement("div", { style: { float: "right" } }, this.renderActionLinks()),
233
+ this.props.titleElem));
209
234
  }
210
235
  renderQuickfilter() {
211
- return R(QuickfiltersComponent_1.default, {
212
- design: this.props.design.quickfilters || [],
213
- schema: this.props.schema,
214
- dataSource: this.props.dataSource,
215
- quickfiltersDataSource: this.props.dashboardDataSource.getQuickfiltersDataSource(),
216
- values: this.state.quickfiltersValues || undefined,
217
- onValuesChange: (values) => this.setState({ quickfiltersValues: values }),
218
- locks: this.props.quickfilterLocks,
219
- filters: this.getCompiledFilters(),
220
- hideTopBorder: this.props.hideTitleBar,
236
+ return react_1.default.createElement(QuickfiltersComponent_1.default, { design: this.props.design.quickfilters || [], schema: this.props.schema, dataSource: this.props.dataSource, quickfiltersDataSource: this.props.dashboardDataSource.getQuickfiltersDataSource(), values: this.state.quickfiltersValues || undefined, onValuesChange: (values) => this.setState({ quickfiltersValues: values }), locks: this.props.quickfilterLocks, filters: this.getCompiledFilters(), hideTopBorder: this.props.hideTitleBar,
221
237
  // Don't hide if title bar is hidden as it can't be shown again
222
- onHide: () => !this.props.hideTitleBar ? this.setState({ hideQuickfilters: true }) : undefined,
223
- translate: this.translate
224
- });
238
+ onHide: () => this.setState({ hideQuickfilters: true }), translate: this.translate });
239
+ }
240
+ renderFloatingShowQuickfiltersButton() {
241
+ // Only show if:
242
+ // 1. Quick filters exist
243
+ // 2. Quick filters are hidden
244
+ // 3. Title bar is hidden (since otherwise button is in title bar)
245
+ if (!this.props.design.quickfilters?.length || !this.state.hideQuickfilters || !this.props.hideTitleBar) {
246
+ return null;
247
+ }
248
+ return (react_1.default.createElement("div", { style: {
249
+ position: "absolute",
250
+ top: 5,
251
+ right: 20,
252
+ zIndex: 1000
253
+ } },
254
+ react_1.default.createElement("button", { className: "btn btn-link btn-sm", onClick: () => this.setState({ hideQuickfilters: false }) },
255
+ react_1.default.createElement("i", { className: "fa fa-angle-double-down" }))));
225
256
  }
226
257
  refDashboardView = (el) => {
227
258
  this.dashboardView = el;
@@ -231,32 +262,8 @@ class DashboardComponent extends react_1.default.Component {
231
262
  // Compile quickfilters
232
263
  filters = filters.concat(new QuickfilterCompiler_1.default(this.props.schema).compile(this.props.design.quickfilters || [], this.state.quickfiltersValues, this.props.quickfilterLocks));
233
264
  const displayLocale = this.state.editing ? this.props.design.locale || "en" : this.state.locale;
234
- const dashboardView = R(DashboardViewComponent_1.default, {
235
- schema: this.props.schema,
236
- dataSource: this.props.dataSource,
237
- dashboardDataSource: this.props.dashboardDataSource,
238
- ref: this.refDashboardView,
239
- design: this.props.design,
240
- onDesignChange: this.state.editing ? this.props.onDesignChange : undefined,
241
- filters,
242
- onRowClick: this.props.onRowClick,
243
- namedStrings: this.props.namedStrings,
244
- hideScopes: this.state.hideQuickfilters,
245
- refreshKey: this.state.refreshKey,
246
- locale: displayLocale
247
- });
248
- const readonlyDashboardView = R(DashboardViewComponent_1.default, {
249
- schema: this.props.schema,
250
- dataSource: this.props.dataSource,
251
- dashboardDataSource: this.props.dashboardDataSource,
252
- ref: this.refDashboardView,
253
- design: this.props.design,
254
- filters,
255
- onRowClick: this.props.onRowClick,
256
- namedStrings: this.props.namedStrings,
257
- hideScopes: this.state.hideQuickfilters,
258
- locale: displayLocale
259
- });
265
+ const dashboardView = react_1.default.createElement(DashboardViewComponent_1.default, { schema: this.props.schema, dataSource: this.props.dataSource, dashboardDataSource: this.props.dashboardDataSource, ref: this.refDashboardView, design: this.props.design, onDesignChange: this.state.editing ? this.props.onDesignChange : undefined, filters: filters, onRowClick: this.props.onRowClick, namedStrings: this.props.namedStrings, hideScopes: this.state.hideQuickfilters, refreshKey: this.state.refreshKey, locale: displayLocale });
266
+ const readonlyDashboardView = react_1.default.createElement(DashboardViewComponent_1.default, { schema: this.props.schema, dataSource: this.props.dataSource, dashboardDataSource: this.props.dashboardDataSource, ref: this.refDashboardView, design: this.props.design, filters: filters, onRowClick: this.props.onRowClick, namedStrings: this.props.namedStrings, hideScopes: this.state.hideQuickfilters, locale: displayLocale });
260
267
  // Pass active tables down to table select components so they can present a shorter list
261
268
  return react_1.default.createElement(expressions_ui_1.ActiveTablesContext.Provider, { value: DashboardUtils.getFilterableTables(this.props.design, this.props.schema) },
262
269
  react_1.default.createElement(expressions_ui_1.LocaleContext.Provider, { value: displayLocale },
@@ -268,6 +275,7 @@ class DashboardComponent extends react_1.default.Component {
268
275
  !this.props.hideTitleBar ? this.renderTitleBar() : undefined,
269
276
  react_1.default.createElement("div", null, !this.state.hideQuickfilters ? this.renderQuickfilter() : undefined),
270
277
  dashboardView,
278
+ this.renderFloatingShowQuickfiltersButton(),
271
279
  this.props.onDesignChange != null && (react_1.default.createElement(SettingsModalComponent_1.default, { onDesignChange: this.handleDesignChange, schema: this.props.schema, dataSource: this.props.dataSource, ref: (c) => {
272
280
  this.settings = c;
273
281
  } })),
package/lib/languages.js CHANGED
@@ -816,7 +816,12 @@ exports.languages = [
816
816
  {
817
817
  "code": "tl",
818
818
  "name": "Tagalog",
819
- "en": "Tagalog / Filipino"
819
+ "en": "Tagalog"
820
+ },
821
+ {
822
+ "code": "fil",
823
+ "name": "Filipino",
824
+ "en": "Filipino"
820
825
  },
821
826
  {
822
827
  "code": "tn",
@@ -3,6 +3,8 @@ import { Expr } from "@mwater/expressions";
3
3
  design is an array of quick filters (user-selectable filters).
4
4
  */
5
5
  export interface Quickfilter {
6
+ /** Optional id for the quickfilter. If not present, a random id will be generated the first time the quickfilter is modified. */
7
+ id?: string;
6
8
  /** filter expression (left hand side only. Usually enum, enumset, text, date, datetime, id[], text[]) */
7
9
  expr: Expr;
8
10
  /** optional label */
@@ -12,35 +12,10 @@ export interface QuickfiltersDesignComponentProps {
12
12
  tables: string[];
13
13
  }
14
14
  export default class QuickfiltersDesignComponent extends React.Component<QuickfiltersDesignComponentProps> {
15
- handleDesignChange: (design: any) => void;
16
- isMergeable(design: any, index: any): boolean;
17
- renderQuickfilter: (item: any, index: any) => React.CElement<any, QuickfilterDesignComponent>;
15
+ handleDesignChange: (design: Quickfilter[]) => void;
16
+ isMergeable(design: Quickfilter[], index: number): boolean;
17
+ renderQuickfilter: (item: Quickfilter, index: number) => React.JSX.Element;
18
18
  handleAdd: () => void;
19
- handleRemove: (index: any) => void;
20
- render(): React.DetailedReactHTMLElement<React.HTMLAttributes<HTMLElement>, HTMLElement>;
21
- }
22
- interface QuickfilterDesignComponentProps {
23
- /** Design of a single quickfilters. See README.md */
24
- design: Quickfilter;
25
- onChange: (design: Quickfilter) => void;
26
- onRemove: () => void;
27
- /** True if can be merged */
28
- mergeable?: boolean;
29
- schema: Schema;
30
- dataSource: DataSource;
31
- tables: string[];
32
- }
33
- interface QuickfilterDesignComponentState {
34
- table: any;
35
- }
36
- /** Single quickfilter design component */
37
- declare class QuickfilterDesignComponent extends React.Component<QuickfilterDesignComponentProps, QuickfilterDesignComponentState> {
38
- constructor(props: any);
39
- handleTableChange: (table: any) => void;
40
- handleExprChange: (expr: any) => void;
41
- handleLabelChange: (ev: any) => void;
42
- handleMergedChange: (merged: any) => void;
43
- handleMultiChange: (multi: any) => void;
19
+ handleRemove: (index: number) => void;
44
20
  render(): React.JSX.Element;
45
21
  }
46
- export {};
@@ -28,8 +28,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
29
  const lodash_1 = __importDefault(require("lodash"));
30
30
  const react_1 = __importDefault(require("react"));
31
- const R = react_1.default.createElement;
32
- const update_object_1 = __importDefault(require("update-object"));
31
+ const uuid_1 = __importDefault(require("uuid"));
32
+ const immer_1 = require("immer");
33
33
  const expressions_ui_1 = require("@mwater/expressions-ui");
34
34
  const expressions_1 = require("@mwater/expressions");
35
35
  const ui = __importStar(require("@mwater/react-library/lib/bootstrap"));
@@ -37,14 +37,22 @@ const ListEditorComponent_1 = require("@mwater/react-library/lib/ListEditorCompo
37
37
  // Displays quick filters and allows their value to be modified
38
38
  class QuickfiltersDesignComponent extends react_1.default.Component {
39
39
  handleDesignChange = (design) => {
40
- design = design.slice();
41
- // Update merged, clearing if not mergeable
42
- for (let index = 0, end = design.length, asc = 0 <= end; asc ? index < end : index > end; asc ? index++ : index--) {
43
- if (design[index].merged && !this.isMergeable(design, index)) {
44
- design[index] = lodash_1.default.extend({}, design[index], { merged: false });
40
+ // Use immer produce to create immutable update
41
+ const newDesign = (0, immer_1.produce)(design, draft => {
42
+ // Add UUID if missing
43
+ for (let i = 0; i < draft.length; i++) {
44
+ if (!draft[i].id) {
45
+ draft[i].id = uuid_1.default.v4();
46
+ }
45
47
  }
46
- }
47
- return this.props.onDesignChange(design);
48
+ // Update merged flag, clearing if not mergeable
49
+ for (let i = 0; i < draft.length; i++) {
50
+ if (draft[i].merged && !this.isMergeable(draft, i)) {
51
+ draft[i].merged = false;
52
+ }
53
+ }
54
+ });
55
+ this.props.onDesignChange(newDesign);
48
56
  };
49
57
  // Determine if quickfilter at index is mergeable with previous (same type, id table and enum values)
50
58
  isMergeable(design, index) {
@@ -75,35 +83,28 @@ class QuickfiltersDesignComponent extends react_1.default.Component {
75
83
  return true;
76
84
  }
77
85
  renderQuickfilter = (item, index) => {
78
- return R(QuickfilterDesignComponent, {
79
- key: index,
80
- design: item,
81
- schema: this.props.schema,
82
- dataSource: this.props.dataSource,
83
- tables: this.props.tables,
84
- mergeable: this.isMergeable(this.props.design, index),
85
- onChange: (newItem) => {
86
+ return react_1.default.createElement(QuickfilterDesignComponent, { key: index, design: item, schema: this.props.schema, dataSource: this.props.dataSource, tables: this.props.tables, mergeable: this.isMergeable(this.props.design, index), onChange: (newItem) => {
86
87
  const design = this.props.design.slice();
87
88
  design[index] = newItem;
88
89
  return this.handleDesignChange(design);
89
- },
90
- onRemove: this.handleRemove.bind(null, index)
91
- });
90
+ }, onRemove: this.handleRemove.bind(null, index) });
92
91
  };
93
92
  handleAdd = () => {
94
93
  // Add blank to end
95
94
  const design = this.props.design.concat([{ expr: null }]);
96
- return this.props.onDesignChange(design);
95
+ this.props.onDesignChange(design);
97
96
  };
98
97
  handleRemove = (index) => {
99
98
  const design = this.props.design.slice();
100
99
  design.splice(index, 1);
101
- return this.props.onDesignChange(design);
100
+ this.props.onDesignChange(design);
102
101
  };
103
102
  render() {
104
- return R("div", null, react_1.default.createElement(ListEditorComponent_1.ListEditorComponent, { items: this.props.design, onItemsChange: this.handleDesignChange, renderItem: this.renderQuickfilter, getReorderableKey: (item, index) => index }), this.props.tables.length > 0
105
- ? R("button", { type: "button", className: "btn btn-sm btn-link", onClick: this.handleAdd }, R("span", { className: "fas fa-plus me-1" }), T `Add Quick Filter`)
106
- : undefined);
103
+ return (react_1.default.createElement("div", null,
104
+ react_1.default.createElement(ListEditorComponent_1.ListEditorComponent, { items: this.props.design, onItemsChange: this.handleDesignChange, renderItem: this.renderQuickfilter, getReorderableKey: (item, index) => item.id || index }),
105
+ this.props.tables.length > 0 ? (react_1.default.createElement("button", { type: "button", className: "btn btn-sm btn-link", onClick: this.handleAdd },
106
+ react_1.default.createElement("span", { className: "fas fa-plus me-1" }),
107
+ T `Add Quick Filter`)) : undefined));
107
108
  }
108
109
  }
109
110
  exports.default = QuickfiltersDesignComponent;
@@ -124,16 +125,24 @@ class QuickfilterDesignComponent extends react_1.default.Component {
124
125
  return this.props.onChange(design);
125
126
  };
126
127
  handleExprChange = (expr) => {
127
- return this.props.onChange((0, update_object_1.default)(this.props.design, { expr: { $set: expr } }));
128
+ this.props.onChange((0, immer_1.produce)(this.props.design, draft => {
129
+ draft.expr = expr;
130
+ }));
128
131
  };
129
132
  handleLabelChange = (ev) => {
130
- return this.props.onChange((0, update_object_1.default)(this.props.design, { label: { $set: ev.target.value } }));
133
+ this.props.onChange((0, immer_1.produce)(this.props.design, draft => {
134
+ draft.label = ev.target.value;
135
+ }));
131
136
  };
132
137
  handleMergedChange = (merged) => {
133
- return this.props.onChange((0, update_object_1.default)(this.props.design, { merged: { $set: merged } }));
138
+ this.props.onChange((0, immer_1.produce)(this.props.design, draft => {
139
+ draft.merged = merged;
140
+ }));
134
141
  };
135
142
  handleMultiChange = (multi) => {
136
- return this.props.onChange((0, update_object_1.default)(this.props.design, { multi: { $set: multi } }));
143
+ this.props.onChange((0, immer_1.produce)(this.props.design, draft => {
144
+ draft.multi = multi;
145
+ }));
137
146
  };
138
147
  render() {
139
148
  // Determine type of expression
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mwater/visualization",
3
- "version": "5.4.2",
3
+ "version": "5.4.3",
4
4
  "description": "Visualization library",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -1,7 +1,5 @@
1
1
  import _ from "lodash"
2
2
  import React, { ReactNode } from "react"
3
- const R = React.createElement
4
-
5
3
  import { DataSource, ExprCompiler, Schema } from "@mwater/expressions"
6
4
  import UndoStack from "../UndoStack"
7
5
  import * as DashboardUtils from "./DashboardUtils"
@@ -233,153 +231,154 @@ export default class DashboardComponent extends React.Component<DashboardCompone
233
231
  }
234
232
 
235
233
  renderEditingSwitch() {
236
- return R(
237
- "a",
238
- {
239
- key: "edit",
240
- className: `btn btn-primary btn-sm ${this.state.editing ? "active" : ""}`,
241
- onClick: this.handleToggleEditing
242
- },
243
- R("span", { className: "fas fa-pencil-alt" }),
244
- " ",
245
- this.state.editing ? T`Editing` : T`Edit`
234
+ return (
235
+ <a
236
+ key="edit"
237
+ className={`btn btn-primary btn-sm ${this.state.editing ? "active" : ""}`}
238
+ onClick={this.handleToggleEditing}
239
+ >
240
+ <span className="fas fa-pencil-alt"/>
241
+ {" "}
242
+ {this.state.editing ? T`Editing` : T`Edit`}
243
+ </a>
246
244
  )
247
245
  }
248
246
 
249
247
  renderStyle() {
250
- return R(
251
- "button",
252
- { type: "button", key: "style", className: "btn btn-link btn-sm", onClick: this.handleOpenLayoutOptions },
253
- R("span", { className: "fa fa-mobile" }),
254
- R("span", { className: "hide-600px" }, " ", T`Layout`)
248
+ return (
249
+ <button type="button" key="style" className="btn btn-link btn-sm" onClick={this.handleOpenLayoutOptions}>
250
+ <span className="fa fa-mobile"/>
251
+ <span className="hide-600px"> {T`Layout`}</span>
252
+ </button>
255
253
  )
256
254
  }
257
255
 
258
256
  renderActionLinks() {
259
- return R(
260
- "div",
261
- null,
262
- this.state.editing
263
- ? [
264
- R(
265
- "a",
266
- {
267
- key: "undo",
268
- className: `btn btn-link btn-sm ${!this.state.undoStack.canUndo() ? "disabled" : ""}`,
269
- onClick: this.handleUndo
270
- },
271
- R("span", { className: "fas fa-caret-left" }),
272
- R("span", { className: "hide-600px" }, " ", T`Undo`)
273
- ),
274
- " ",
275
- R(
276
- "a",
277
- {
278
- key: "redo",
279
- className: `btn btn-link btn-sm ${!this.state.undoStack.canRedo() ? "disabled" : ""}`,
280
- onClick: this.handleRedo
281
- },
282
- R("span", { className: "fas fa-caret-right" }),
283
- R("span", { className: "hide-600px" }, " ", T`Redo`)
284
- )
285
- ]
286
- : undefined,
287
- !this.state.editing && this.props.design.otherLocales && this.props.design.otherLocales.length > 0
288
- ? R(
289
- "div",
290
- { key: "translations", className: "dropdown d-inline-block" },
291
- R(
292
- "a",
293
- {
294
- className: "btn btn-link btn-sm dropdown-toggle",
295
- "data-bs-toggle": "dropdown"
296
- },
297
- R("span", { className: "fal fa-globe" }),
257
+ return (
258
+ <div>
259
+ {this.state.editing
260
+ ? [
261
+ <a
262
+ key="undo"
263
+ className={`btn btn-link btn-sm ${!this.state.undoStack.canUndo() ? "disabled" : ""}`}
264
+ onClick={this.handleUndo}
265
+ >
266
+ <span className="fas fa-caret-left"/>
267
+ <span className="hide-600px"> {T`Undo`}</span>
268
+ </a>,
298
269
  " ",
299
- this.state.locale
300
- ),
301
- R(
302
- "ul",
303
- { className: "dropdown-menu dropdown-menu-end" },
304
- [this.props.design.locale || "en", ...this.props.design.otherLocales].map(locale =>
305
- R(
306
- "li",
307
- { key: locale },
308
- R(
309
- "a",
310
- {
311
- className: "dropdown-item",
312
- onClick: () => this.setState({ locale: locale })
313
- },
314
- languages.find(l => l.code === locale)?.name || locale
315
- )
316
- )
317
- )
318
- )
319
- )
320
- : undefined,
321
- R(
322
- "a",
323
- { key: "print", className: "btn btn-link btn-sm", onClick: this.handlePrint },
324
- R("span", { className: "fas fa-print" }),
325
- R("span", { className: "hide-600px" }, " ", T`Print`)
326
- ),
327
- R(
328
- "a",
329
- { key: "refresh", className: "btn btn-link btn-sm", onClick: this.handleRefreshData },
330
- R("span", { className: "fas fa-sync" }),
331
- R("span", { className: "hide-600px" }, " ", T`Refresh`)
332
- ),
333
- this.state.hideQuickfilters && this.props.design.quickfilters && this.props.design.quickfilters.length > 0
334
- ? R(
335
- "a",
336
- { key: "showQuickfilters", className: "btn btn-link btn-sm", onClick: this.handleShowQuickfilters },
337
- R("span", { className: "fa fa-filter" }),
338
- R("span", { className: "hide-600px" }, " ", T`Show Quickfilters`)
339
- )
340
- : undefined,
341
-
342
- // R 'a', key: "export", className: "btn btn-link btn-sm", onClick: @handleSaveDesignFile,
343
- // R('span', className: "glyphicon glyphicon-download-alt")
344
- // " Export"
345
- this.state.editing
346
- ? R(
347
- "a",
348
- { key: "settings", className: "btn btn-link btn-sm", onClick: this.handleSettings },
349
- R("span", { className: "fas fa-cog" }),
350
- R("span", { className: "hide-600px" }, " ", T`Settings`)
351
- )
352
- : undefined,
353
- this.state.editing ? this.renderStyle() : undefined,
354
- this.props.extraTitleButtonsElem,
355
- this.props.onDesignChange != null ? this.renderEditingSwitch() : undefined
270
+ <a
271
+ key="redo"
272
+ className={`btn btn-link btn-sm ${!this.state.undoStack.canRedo() ? "disabled" : ""}`}
273
+ onClick={this.handleRedo}
274
+ >
275
+ <span className="fas fa-caret-right"/>
276
+ <span className="hide-600px"> {T`Redo`}</span>
277
+ </a>
278
+ ]
279
+ : undefined}
280
+ {!this.state.editing && this.props.design.otherLocales && this.props.design.otherLocales.length > 0
281
+ ? <div key="translations" className="dropdown d-inline-block">
282
+ <a
283
+ className="btn btn-link btn-sm dropdown-toggle"
284
+ data-bs-toggle="dropdown"
285
+ >
286
+ <span className="fal fa-globe"/>
287
+ {" "}
288
+ {this.state.locale}
289
+ </a>
290
+ <ul className="dropdown-menu dropdown-menu-end">
291
+ {[this.props.design.locale || "en", ...this.props.design.otherLocales].map(locale =>
292
+ <li key={locale}>
293
+ <a
294
+ className="dropdown-item"
295
+ onClick={() => this.setState({ locale: locale })}
296
+ >
297
+ {languages.find(l => l.code === locale)?.name || locale}
298
+ </a>
299
+ </li>
300
+ )}
301
+ </ul>
302
+ </div>
303
+ : undefined}
304
+ <a key="print" className="btn btn-link btn-sm" onClick={this.handlePrint}>
305
+ <span className="fas fa-print"/>
306
+ <span className="hide-600px"> {T`Print`}</span>
307
+ </a>
308
+ <a key="refresh" className="btn btn-link btn-sm" onClick={this.handleRefreshData}>
309
+ <span className="fas fa-sync"/>
310
+ <span className="hide-600px"> {T`Refresh`}</span>
311
+ </a>
312
+ {this.state.hideQuickfilters && this.props.design.quickfilters && this.props.design.quickfilters.length > 0
313
+ ? <a key="showQuickfilters" className="btn btn-link btn-sm" onClick={this.handleShowQuickfilters}>
314
+ <span className="fa fa-filter"/>
315
+ <span className="hide-600px"> {T`Show Quickfilters`}</span>
316
+ </a>
317
+ : undefined}
318
+
319
+ {this.state.editing
320
+ ? <a key="settings" className="btn btn-link btn-sm" onClick={this.handleSettings}>
321
+ <span className="fas fa-cog"/>
322
+ <span className="hide-600px"> {T`Settings`}</span>
323
+ </a>
324
+ : undefined}
325
+ {this.state.editing ? this.renderStyle() : undefined}
326
+ {this.props.extraTitleButtonsElem}
327
+ {this.props.onDesignChange != null ? this.renderEditingSwitch() : undefined}
328
+ </div>
356
329
  )
357
330
  }
358
331
 
359
332
  renderTitleBar() {
360
- return R(
361
- "div",
362
- { style: { height: 40, padding: 4 } },
363
- R("div", { style: { float: "right" } }, this.renderActionLinks()),
364
- this.props.titleElem
333
+ return (
334
+ <div style={{ height: 40, padding: 4 }}>
335
+ <div style={{ float: "right" }}>{this.renderActionLinks()}</div>
336
+ {this.props.titleElem}
337
+ </div>
365
338
  )
366
339
  }
367
340
 
368
341
  renderQuickfilter() {
369
- return R(QuickfiltersComponent, {
370
- design: this.props.design.quickfilters || [],
371
- schema: this.props.schema,
372
- dataSource: this.props.dataSource,
373
- quickfiltersDataSource: this.props.dashboardDataSource.getQuickfiltersDataSource(),
374
- values: this.state.quickfiltersValues || undefined,
375
- onValuesChange: (values: any) => this.setState({ quickfiltersValues: values }),
376
- locks: this.props.quickfilterLocks,
377
- filters: this.getCompiledFilters(),
378
- hideTopBorder: this.props.hideTitleBar,
342
+ return <QuickfiltersComponent
343
+ design={this.props.design.quickfilters || []}
344
+ schema={this.props.schema}
345
+ dataSource={this.props.dataSource}
346
+ quickfiltersDataSource={this.props.dashboardDataSource.getQuickfiltersDataSource()}
347
+ values={this.state.quickfiltersValues || undefined}
348
+ onValuesChange={(values: any) => this.setState({ quickfiltersValues: values })}
349
+ locks={this.props.quickfilterLocks}
350
+ filters={this.getCompiledFilters()}
351
+ hideTopBorder={this.props.hideTitleBar}
379
352
  // Don't hide if title bar is hidden as it can't be shown again
380
- onHide: () => !this.props.hideTitleBar ? this.setState({ hideQuickfilters: true }) : undefined,
381
- translate: this.translate
382
- })
353
+ onHide={() => this.setState({ hideQuickfilters: true })}
354
+ translate={this.translate}
355
+ />
356
+ }
357
+
358
+ renderFloatingShowQuickfiltersButton() {
359
+ // Only show if:
360
+ // 1. Quick filters exist
361
+ // 2. Quick filters are hidden
362
+ // 3. Title bar is hidden (since otherwise button is in title bar)
363
+ if (!this.props.design.quickfilters?.length || !this.state.hideQuickfilters || !this.props.hideTitleBar) {
364
+ return null
365
+ }
366
+
367
+ return (
368
+ <div style={{
369
+ position: "absolute",
370
+ top: 5,
371
+ right: 20,
372
+ zIndex: 1000
373
+ }}>
374
+ <button
375
+ className="btn btn-link btn-sm"
376
+ onClick={() => this.setState({ hideQuickfilters: false })}
377
+ >
378
+ <i className="fa fa-angle-double-down"/>
379
+ </button>
380
+ </div>
381
+ )
383
382
  }
384
383
 
385
384
  refDashboardView = (el: any) => {
@@ -400,34 +399,33 @@ export default class DashboardComponent extends React.Component<DashboardCompone
400
399
 
401
400
  const displayLocale = this.state.editing ? this.props.design.locale || "en" : this.state.locale
402
401
 
403
- const dashboardView = R(DashboardViewComponent, {
404
- schema: this.props.schema,
405
- dataSource: this.props.dataSource,
406
- dashboardDataSource: this.props.dashboardDataSource,
407
- ref: this.refDashboardView,
408
- design: this.props.design,
409
- onDesignChange: this.state.editing ? this.props.onDesignChange : undefined,
410
- filters,
411
- onRowClick: this.props.onRowClick,
412
- namedStrings: this.props.namedStrings,
413
- hideScopes: this.state.hideQuickfilters,
414
- refreshKey: this.state.refreshKey,
415
- locale: displayLocale
416
- })
417
-
418
- const readonlyDashboardView = R(DashboardViewComponent, {
419
- schema: this.props.schema,
420
- dataSource: this.props.dataSource,
421
- dashboardDataSource: this.props.dashboardDataSource,
422
- ref: this.refDashboardView,
423
- design: this.props.design,
424
- filters,
425
- onRowClick: this.props.onRowClick,
426
- namedStrings: this.props.namedStrings,
427
- hideScopes: this.state.hideQuickfilters,
428
- locale: displayLocale
429
- })
430
-
402
+ const dashboardView = <DashboardViewComponent
403
+ schema={this.props.schema}
404
+ dataSource={this.props.dataSource}
405
+ dashboardDataSource={this.props.dashboardDataSource}
406
+ ref={this.refDashboardView}
407
+ design={this.props.design}
408
+ onDesignChange={this.state.editing ? this.props.onDesignChange : undefined}
409
+ filters={filters}
410
+ onRowClick={this.props.onRowClick}
411
+ namedStrings={this.props.namedStrings}
412
+ hideScopes={this.state.hideQuickfilters}
413
+ refreshKey={this.state.refreshKey}
414
+ locale={displayLocale}
415
+ />
416
+
417
+ const readonlyDashboardView = <DashboardViewComponent
418
+ schema={this.props.schema}
419
+ dataSource={this.props.dataSource}
420
+ dashboardDataSource={this.props.dashboardDataSource}
421
+ ref={this.refDashboardView}
422
+ design={this.props.design}
423
+ filters={filters}
424
+ onRowClick={this.props.onRowClick}
425
+ namedStrings={this.props.namedStrings}
426
+ hideScopes={this.state.hideQuickfilters}
427
+ locale={displayLocale}
428
+ />
431
429
 
432
430
  // Pass active tables down to table select components so they can present a shorter list
433
431
  return <ActiveTablesContext.Provider
@@ -441,6 +439,7 @@ export default class DashboardComponent extends React.Component<DashboardCompone
441
439
  {!this.props.hideTitleBar ? this.renderTitleBar() : undefined}
442
440
  <div>{!this.state.hideQuickfilters ? this.renderQuickfilter() : undefined}</div>
443
441
  {dashboardView}
442
+ {this.renderFloatingShowQuickfiltersButton()}
444
443
  {this.props.onDesignChange != null && (
445
444
  <SettingsModalComponent
446
445
  onDesignChange={this.handleDesignChange}
package/src/languages.ts CHANGED
@@ -821,7 +821,12 @@ export const languages: {
821
821
  {
822
822
  "code": "tl",
823
823
  "name": "Tagalog",
824
- "en": "Tagalog / Filipino"
824
+ "en": "Tagalog"
825
+ },
826
+ {
827
+ "code": "fil",
828
+ "name": "Filipino",
829
+ "en": "Filipino"
825
830
  },
826
831
  {
827
832
  "code": "tn",
@@ -4,6 +4,9 @@ import { Expr } from "@mwater/expressions"
4
4
  design is an array of quick filters (user-selectable filters).
5
5
  */
6
6
  export interface Quickfilter {
7
+ /** Optional id for the quickfilter. If not present, a random id will be generated the first time the quickfilter is modified. */
8
+ id?: string
9
+
7
10
  // `table`: (deprecated) table of filter
8
11
 
9
12
  /** filter expression (left hand side only. Usually enum, enumset, text, date, datetime, id[], text[]) */
@@ -1,9 +1,9 @@
1
1
  import _ from "lodash"
2
2
  import React from "react"
3
- const R = React.createElement
4
- import update from "update-object"
3
+ import uuid from "uuid"
4
+ import { produce } from "immer"
5
5
  import { ExprComponent } from "@mwater/expressions-ui"
6
- import { DataSource, ExprUtils, Schema } from "@mwater/expressions"
6
+ import { DataSource, Expr, ExprUtils, FieldExpr, Schema } from "@mwater/expressions"
7
7
  import * as ui from "@mwater/react-library/lib/bootstrap"
8
8
  import { ListEditorComponent } from "@mwater/react-library/lib/ListEditorComponent"
9
9
  import { Quickfilter } from "./Quickfilter"
@@ -21,21 +21,29 @@ export interface QuickfiltersDesignComponentProps {
21
21
 
22
22
  // Displays quick filters and allows their value to be modified
23
23
  export default class QuickfiltersDesignComponent extends React.Component<QuickfiltersDesignComponentProps> {
24
- handleDesignChange = (design: any) => {
25
- design = design.slice()
24
+ handleDesignChange = (design: Quickfilter[]) => {
25
+ // Use immer produce to create immutable update
26
+ const newDesign = produce(design, draft => {
27
+ // Add UUID if missing
28
+ for (let i = 0; i < draft.length; i++) {
29
+ if (!draft[i].id) {
30
+ draft[i].id = uuid.v4()
31
+ }
32
+ }
26
33
 
27
- // Update merged, clearing if not mergeable
28
- for (let index = 0, end = design.length, asc = 0 <= end; asc ? index < end : index > end; asc ? index++ : index--) {
29
- if (design[index].merged && !this.isMergeable(design, index)) {
30
- design[index] = _.extend({}, design[index], { merged: false })
34
+ // Update merged flag, clearing if not mergeable
35
+ for (let i = 0; i < draft.length; i++) {
36
+ if (draft[i].merged && !this.isMergeable(draft, i)) {
37
+ draft[i].merged = false
38
+ }
31
39
  }
32
- }
40
+ })
33
41
 
34
- return this.props.onDesignChange(design)
42
+ this.props.onDesignChange(newDesign)
35
43
  }
36
44
 
37
45
  // Determine if quickfilter at index is mergeable with previous (same type, id table and enum values)
38
- isMergeable(design: any, index: any) {
46
+ isMergeable(design: Quickfilter[], index: number) {
39
47
  if (index === 0) {
40
48
  return false
41
49
  }
@@ -73,54 +81,51 @@ export default class QuickfiltersDesignComponent extends React.Component<Quickfi
73
81
  return true
74
82
  }
75
83
 
76
- renderQuickfilter = (item: any, index: any) => {
77
- return R(QuickfilterDesignComponent, {
78
- key: index,
79
- design: item,
80
- schema: this.props.schema,
81
- dataSource: this.props.dataSource,
82
- tables: this.props.tables,
83
- mergeable: this.isMergeable(this.props.design, index),
84
- onChange: (newItem: any) => {
84
+ renderQuickfilter = (item: Quickfilter, index: number) => {
85
+ return <QuickfilterDesignComponent
86
+ key={index}
87
+ design={item}
88
+ schema={this.props.schema}
89
+ dataSource={this.props.dataSource}
90
+ tables={this.props.tables}
91
+ mergeable={this.isMergeable(this.props.design, index)}
92
+ onChange={(newItem: Quickfilter) => {
85
93
  const design = this.props.design.slice()
86
94
  design[index] = newItem
87
95
  return this.handleDesignChange(design)
88
- },
89
-
90
- onRemove: this.handleRemove.bind(null, index)
91
- })
96
+ }}
97
+ onRemove={this.handleRemove.bind(null, index)}
98
+ />
92
99
  }
93
100
 
94
101
  handleAdd = () => {
95
102
  // Add blank to end
96
103
  const design = this.props.design.concat([{ expr: null }])
97
- return this.props.onDesignChange(design)
104
+ this.props.onDesignChange(design)
98
105
  }
99
106
 
100
- handleRemove = (index: any) => {
107
+ handleRemove = (index: number) => {
101
108
  const design = this.props.design.slice()
102
109
  design.splice(index, 1)
103
- return this.props.onDesignChange(design)
110
+ this.props.onDesignChange(design)
104
111
  }
105
112
 
106
113
  render() {
107
- return R(
108
- "div",
109
- null,
110
- <ListEditorComponent
111
- items={this.props.design}
112
- onItemsChange={this.handleDesignChange}
113
- renderItem={this.renderQuickfilter}
114
- getReorderableKey={(item, index) => index}
115
- />,
116
- this.props.tables.length > 0
117
- ? R(
118
- "button",
119
- { type: "button", className: "btn btn-sm btn-link", onClick: this.handleAdd },
120
- R("span", { className: "fas fa-plus me-1" }),
121
- T`Add Quick Filter`
122
- )
123
- : undefined
114
+ return (
115
+ <div>
116
+ <ListEditorComponent
117
+ items={this.props.design}
118
+ onItemsChange={this.handleDesignChange}
119
+ renderItem={this.renderQuickfilter}
120
+ getReorderableKey={(item, index) => item.id || index}
121
+ />
122
+ {this.props.tables.length > 0 ? (
123
+ <button type="button" className="btn btn-sm btn-link" onClick={this.handleAdd}>
124
+ <span className="fas fa-plus me-1" />
125
+ {T`Add Quick Filter`}
126
+ </button>
127
+ ) : undefined}
128
+ </div>
124
129
  )
125
130
  }
126
131
  }
@@ -138,7 +143,7 @@ interface QuickfilterDesignComponentProps {
138
143
  }
139
144
 
140
145
  interface QuickfilterDesignComponentState {
141
- table: any
146
+ table: string
142
147
  }
143
148
 
144
149
  /** Single quickfilter design component */
@@ -146,16 +151,16 @@ class QuickfilterDesignComponent extends React.Component<
146
151
  QuickfilterDesignComponentProps,
147
152
  QuickfilterDesignComponentState
148
153
  > {
149
- constructor(props: any) {
154
+ constructor(props: QuickfilterDesignComponentProps) {
150
155
  super(props)
151
156
 
152
157
  // Store table to allow selecting table first, then expression
153
158
  this.state = {
154
- table: props.design.expr?.table || props.tables[0]
159
+ table: (props.design.expr as FieldExpr)?.table || props.tables[0]
155
160
  }
156
161
  }
157
162
 
158
- handleTableChange = (table: any) => {
163
+ handleTableChange = (table: string) => {
159
164
  this.setState({ table })
160
165
  const design = {
161
166
  expr: null
@@ -163,18 +168,30 @@ class QuickfilterDesignComponent extends React.Component<
163
168
  return this.props.onChange(design)
164
169
  }
165
170
 
166
- handleExprChange = (expr: any) => {
167
- return this.props.onChange(update(this.props.design, { expr: { $set: expr } }))
171
+ handleExprChange = (expr: Expr) => {
172
+ this.props.onChange(produce(this.props.design, draft => {
173
+ draft.expr = expr
174
+ }))
168
175
  }
176
+
169
177
  handleLabelChange = (ev: any) => {
170
- return this.props.onChange(update(this.props.design, { label: { $set: ev.target.value } }))
178
+ this.props.onChange(produce(this.props.design, draft => {
179
+ draft.label = ev.target.value
180
+ }))
171
181
  }
172
- handleMergedChange = (merged: any) => {
173
- return this.props.onChange(update(this.props.design, { merged: { $set: merged } }))
182
+
183
+ handleMergedChange = (merged: boolean) => {
184
+ this.props.onChange(produce(this.props.design, draft => {
185
+ draft.merged = merged
186
+ }))
174
187
  }
175
- handleMultiChange = (multi: any) => {
176
- return this.props.onChange(update(this.props.design, { multi: { $set: multi } }))
188
+
189
+ handleMultiChange = (multi: boolean) => {
190
+ this.props.onChange(produce(this.props.design, draft => {
191
+ draft.multi = multi
192
+ }))
177
193
  }
194
+
178
195
  render() {
179
196
  // Determine type of expression
180
197
  const exprType = new ExprUtils(this.props.schema).getExprType(this.props.design.expr)