@mwater/visualization 5.0.1 → 5.1.0

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.
Files changed (98) hide show
  1. package/lib/MWaterAddRelatedFormComponent.d.ts +1 -1
  2. package/lib/MWaterAddRelatedFormComponent.js +10 -17
  3. package/lib/MWaterContextComponent.d.ts +17 -7
  4. package/lib/MWaterContextComponent.js +51 -67
  5. package/lib/MWaterLoaderComponent.d.ts +2 -2
  6. package/lib/MWaterLoaderComponent.js +1 -1
  7. package/lib/MWaterTableSelectComponent.d.ts +0 -1
  8. package/lib/MWaterTableSelectComponent.js +20 -41
  9. package/lib/axes/RangesComponent.d.ts +12 -6
  10. package/lib/axes/RangesComponent.js +21 -10
  11. package/lib/dashboards/DashboardComponent.d.ts +1 -9
  12. package/lib/dashboards/DashboardComponent.js +16 -27
  13. package/lib/dashboards/ServerDashboardDataSource.d.ts +1 -0
  14. package/lib/dashboards/ServerDashboardDataSource.js +3 -0
  15. package/lib/datagrids/DatagridComponent.d.ts +8 -4
  16. package/lib/datagrids/DatagridComponent.js +27 -5
  17. package/lib/datagrids/DatagridDataSource.d.ts +1 -0
  18. package/lib/datagrids/DatagridDataSource.js +3 -0
  19. package/lib/datagrids/DatagridDesign.d.ts +2 -0
  20. package/lib/datagrids/DatagridDesignerComponent.js +3 -2
  21. package/lib/datagrids/DatagridViewComponent.js +1 -1
  22. package/lib/datagrids/DirectDatagridDataSource.d.ts +1 -0
  23. package/lib/datagrids/DirectDatagridDataSource.js +26 -0
  24. package/lib/datagrids/ServerDatagridDataSource.d.ts +1 -0
  25. package/lib/datagrids/ServerDatagridDataSource.js +15 -0
  26. package/lib/index.d.ts +0 -1
  27. package/lib/index.js +2 -4
  28. package/lib/layouts/blocks/BlocksDisplayComponent.js +2 -2
  29. package/lib/layouts/grid/LegoLayoutEngine.d.ts +1 -1
  30. package/lib/maps/BufferLayerDesignerComponent.js +2 -2
  31. package/lib/maps/ChoroplethLayerDesigner.js +2 -2
  32. package/lib/maps/ClusterLayerDesignerComponent.js +2 -2
  33. package/lib/maps/DirectMapDataSource.js +1 -2
  34. package/lib/maps/GridLayerDesigner.js +2 -2
  35. package/lib/maps/MapDesignerComponent.d.ts +1 -12
  36. package/lib/maps/MapDesignerComponent.js +5 -12
  37. package/lib/maps/MarkersLayerDesignerComponent.js +2 -2
  38. package/lib/maps/PopupFilterJoinsUtils.d.ts +6 -1
  39. package/lib/maps/PopupFilterJoinsUtils.js +4 -3
  40. package/lib/maps/UtfGridLayer.js +1 -1
  41. package/lib/widgets/ImageWidgetComponent.js +2 -2
  42. package/lib/widgets/charts/calendar/CalendarChartDesignerComponent.js +2 -2
  43. package/lib/widgets/charts/imagemosaic/ImageMosaicChart.d.ts +1 -1
  44. package/lib/widgets/charts/imagemosaic/ImageMosaicChart.js +1 -1
  45. package/lib/widgets/charts/imagemosaic/ImageMosaicChartDesignerComponent.js +2 -2
  46. package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.js +2 -2
  47. package/lib/widgets/charts/pivot/PivotChartDesignerComponent.js +2 -2
  48. package/lib/widgets/charts/table/TableChartDesignerComponent.js +2 -2
  49. package/lib/widgets/text/ExprItemEditorComponent.js +2 -2
  50. package/package.json +1 -1
  51. package/src/MWaterAddRelatedFormComponent.ts +15 -20
  52. package/src/MWaterContextComponent.tsx +140 -0
  53. package/src/MWaterLoaderComponent.ts +2 -2
  54. package/src/{MWaterTableSelectComponent.ts → MWaterTableSelectComponent.tsx} +61 -66
  55. package/src/axes/AxisBuilder.ts +1 -1
  56. package/src/axes/RangesComponent.ts +27 -16
  57. package/src/dashboards/{DashboardComponent.ts → DashboardComponent.tsx} +37 -40
  58. package/src/dashboards/ServerDashboardDataSource.ts +16 -12
  59. package/src/datagrids/DatagridComponent.ts +45 -14
  60. package/src/datagrids/DatagridDataSource.ts +8 -0
  61. package/src/datagrids/DatagridDesign.ts +3 -0
  62. package/src/datagrids/DatagridDesignerComponent.tsx +9 -1
  63. package/src/datagrids/DatagridViewComponent.ts +1 -1
  64. package/src/datagrids/DirectDatagridDataSource.ts +35 -0
  65. package/src/datagrids/ServerDatagridDataSource.ts +22 -4
  66. package/src/index.ts +0 -2
  67. package/src/layouts/blocks/BlocksDisplayComponent.ts +2 -2
  68. package/src/layouts/grid/LegoLayoutEngine.ts +2 -2
  69. package/src/layouts/grid/WidgetContainerComponent.ts +2 -2
  70. package/src/maps/BingLayer.ts +2 -2
  71. package/src/maps/BufferLayerDesignerComponent.ts +1 -1
  72. package/src/maps/ChoroplethLayerDesigner.tsx +1 -1
  73. package/src/maps/ClusterLayerDesignerComponent.ts +1 -1
  74. package/src/maps/DirectMapDataSource.ts +1 -2
  75. package/src/maps/GridLayerDesigner.tsx +1 -1
  76. package/src/maps/LegendGroup.ts +1 -1
  77. package/src/maps/MWaterServerLayer.ts +2 -2
  78. package/src/maps/{MapDesignerComponent.ts → MapDesignerComponent.tsx} +8 -16
  79. package/src/maps/MarkersLayerDesignerComponent.ts +1 -1
  80. package/src/maps/PopupFilterJoinsUtils.ts +4 -4
  81. package/src/maps/ServerMapDataSource.ts +6 -6
  82. package/src/maps/SwitchableTileUrlLayerDesigner.tsx +1 -13
  83. package/src/maps/UtfGridLayer.ts +4 -4
  84. package/src/maps/mapboxUtils.ts +2 -2
  85. package/src/richtext/ExprItemsHtmlConverter.ts +1 -1
  86. package/src/richtext/FontColorPaletteItem.ts +1 -1
  87. package/src/richtext/FontSizePaletteItem.ts +1 -1
  88. package/src/richtext/ItemsHtmlConverter.ts +2 -2
  89. package/src/widgets/ImageWidgetComponent.ts +1 -1
  90. package/src/widgets/charts/calendar/CalendarChartDesignerComponent.ts +1 -1
  91. package/src/widgets/charts/imagemosaic/ImageMosaicChart.ts +1 -1
  92. package/src/widgets/charts/imagemosaic/ImageMosaicChartDesignerComponent.ts +1 -1
  93. package/src/widgets/charts/layered/LayeredChartLayerDesignerComponent.tsx +1 -1
  94. package/src/widgets/charts/pivot/PivotChartDesignerComponent.tsx +1 -1
  95. package/src/widgets/charts/table/TableChartDesignerComponent.ts +1 -1
  96. package/src/widgets/text/ExprItemEditorComponent.tsx +1 -1
  97. package/src/MWaterContextComponent.ts +0 -141
  98. package/src/TableSelectComponent.ts +0 -60
@@ -36,7 +36,7 @@ const AxisBuilder_1 = __importDefault(require("../../../axes/AxisBuilder"));
36
36
  const expressions_ui_1 = require("@mwater/expressions-ui");
37
37
  const expressions_ui_2 = require("@mwater/expressions-ui");
38
38
  const OrderingsComponent_1 = __importDefault(require("./OrderingsComponent"));
39
- const TableSelectComponent_1 = __importDefault(require("../../../TableSelectComponent"));
39
+ const expressions_ui_3 = require("@mwater/expressions-ui");
40
40
  const ReorderableListComponent_1 = __importDefault(require("@mwater/react-library/lib/reorderable/ReorderableListComponent"));
41
41
  const ui = __importStar(require("@mwater/react-library/lib/bootstrap"));
42
42
  const valueFormatter_1 = require("../../../valueFormatter");
@@ -79,7 +79,7 @@ class TableChartDesignerComponent extends react_1.default.Component {
79
79
  this.updateDesign({ columns });
80
80
  };
81
81
  renderTable() {
82
- return R("div", { className: "mb-3" }, R("label", { className: "text-muted" }, R("i", { className: "fa fa-database" }), " ", "Data Source"), ": ", R(TableSelectComponent_1.default, {
82
+ return R("div", { className: "mb-3" }, R("label", { className: "text-muted" }, R("i", { className: "fa fa-database" }), " ", "Data Source"), ": ", R(expressions_ui_3.TableSelectComponent, {
83
83
  schema: this.props.schema,
84
84
  value: this.props.design.table,
85
85
  onChange: this.handleTableChange,
@@ -8,7 +8,7 @@ const react_1 = __importDefault(require("react"));
8
8
  const R = react_1.default.createElement;
9
9
  const expressions_1 = require("@mwater/expressions");
10
10
  const expressions_ui_1 = require("@mwater/expressions-ui");
11
- const TableSelectComponent_1 = __importDefault(require("../../TableSelectComponent"));
11
+ const expressions_ui_2 = require("@mwater/expressions-ui");
12
12
  const valueFormatter_1 = require("../../valueFormatter");
13
13
  const valueFormatter_2 = require("../../valueFormatter");
14
14
  const bootstrap_1 = require("@mwater/react-library/lib/bootstrap");
@@ -61,7 +61,7 @@ class ExprItemEditorComponent extends react_1.default.Component {
61
61
  }, lodash_1.default.map(formats, (format) => R("option", { key: format.value, value: format.value }, format.label))));
62
62
  }
63
63
  render() {
64
- return R("div", { style: { paddingBottom: 200 } }, R("div", { className: "mb-3" }, R("label", { className: "text-muted" }, R("i", { className: "fa fa-database" }), " ", "Data Source"), ": ", R(TableSelectComponent_1.default, {
64
+ return R("div", { style: { paddingBottom: 200 } }, R("div", { className: "mb-3" }, R("label", { className: "text-muted" }, R("i", { className: "fa fa-database" }), " ", "Data Source"), ": ", R(expressions_ui_2.TableSelectComponent, {
65
65
  schema: this.props.schema,
66
66
  value: this.state.table,
67
67
  onChange: this.handleTableChange
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mwater/visualization",
3
- "version": "5.0.1",
3
+ "version": "5.1.0",
4
4
  "description": "Visualization library",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -10,10 +10,10 @@ import querystring from "querystring"
10
10
  import { ExprUtils, Schema } from "@mwater/expressions"
11
11
  import * as ui from "./UIComponents"
12
12
  import * as formUtils from "@mwater/forms/lib/formUtils" // TODO requireing this directly because of bizarre backbone issue
13
- import { AssetQuestion, Form, FormDesign } from "@mwater/forms"
13
+ import { Form, FormDesign } from "@mwater/forms"
14
14
 
15
15
  export interface MWaterAddRelatedFormComponentProps {
16
- /** Entities or assets table id */
16
+ /** Entities table id */
17
17
  table: string
18
18
 
19
19
  apiUrl: string
@@ -33,7 +33,7 @@ interface MWaterAddRelatedFormComponentState {
33
33
  }
34
34
 
35
35
  // Link that when clicked popup up a modal window allowing user to select a form
36
- // with an Entity/Site question to the extraTables
36
+ // with an Site question to the extraTables
37
37
  export default class MWaterAddRelatedFormComponent extends React.Component<
38
38
  MWaterAddRelatedFormComponentProps,
39
39
  MWaterAddRelatedFormComponentState
@@ -91,7 +91,7 @@ export default class MWaterAddRelatedFormComponent extends React.Component<
91
91
  }
92
92
 
93
93
  interface AddRelatedFormModalComponentProps {
94
- /** Entities or assets table id */
94
+ /** Entities table id */
95
95
  table: string
96
96
 
97
97
  apiUrl: string
@@ -126,14 +126,19 @@ class AddRelatedFormModalComponent extends React.Component<
126
126
  }
127
127
 
128
128
  componentDidMount() {
129
- // Get all forms visible to user
129
+ // Get all forms visible to user that have _entity_types that include table
130
130
  const query: any = {}
131
- query.selector = JSON.stringify({ state: { $ne: "deleted" } })
131
+ query.selector = JSON.stringify({
132
+ state: { $ne: "deleted" },
133
+ _entity_types: { $in: [this.props.table.split(".")[1]] }
134
+ })
135
+ query.fields = JSON.stringify({ "_id": 1, "design.name": 1, "modified": 1, "created": 1 })
136
+
132
137
  if (this.props.client) {
133
138
  query.client = this.props.client
134
139
  }
135
140
 
136
- // Get list of all form names
141
+ // Get list of related forms
137
142
  return $.getJSON(this.props.apiUrl + "forms?" + querystring.stringify(query), (forms: Form[]) => {
138
143
  // Sort by modified.on desc but first by user
139
144
  forms = _.sortByOrder(
@@ -142,16 +147,6 @@ class AddRelatedFormModalComponent extends React.Component<
142
147
  ["desc", "desc"]
143
148
  )
144
149
 
145
- // Filter by Entity and Site questions of tableId type
146
- if (this.props.table.startsWith("entities.")) {
147
- forms = _.filter(forms, (form) => formUtils.findEntityQuestion(form.design, this.props.table.split(".")[1]))
148
- } else if (this.props.table.startsWith("assets:")) {
149
- const assetSystemId = parseInt(this.props.table.split(":")[1])
150
- forms = forms.filter((form) => {
151
- return formUtils.findAssetQuestion(form.design, assetSystemId) != null
152
- })
153
- }
154
-
155
150
  // Get _id, name, and description
156
151
  const items = _.map(forms, (form) => ({
157
152
  name: ExprUtils.localizeString(form.design.name, this.context.locale),
@@ -159,9 +154,9 @@ class AddRelatedFormModalComponent extends React.Component<
159
154
  onClick: this.props.onSelect.bind(null, "responses:" + form._id)
160
155
  }))
161
156
 
162
- return this.setState({ items })
163
- }).fail((xhr) => {
164
- return this.setState({ error: xhr.responseText })
157
+ this.setState({ items })
158
+ }).fail((xhr: any) => {
159
+ this.setState({ error: xhr.responseText })
165
160
  })
166
161
  }
167
162
 
@@ -0,0 +1,140 @@
1
+ import PropTypes from "prop-types"
2
+ import _ from "lodash"
3
+ import React from "react"
4
+ const R = React.createElement
5
+
6
+ import MWaterTableSelectComponent from "./MWaterTableSelectComponent"
7
+ import MWaterAddRelatedFormComponent from "./MWaterAddRelatedFormComponent"
8
+ import MWaterAddRelatedIndicatorComponent from "./MWaterAddRelatedIndicatorComponent"
9
+ import MWaterGlobalFiltersComponent from "./MWaterGlobalFiltersComponent"
10
+ import { Schema, Section } from "@mwater/expressions"
11
+ import { CustomTableSelectComponentFactoryContext, CustomTableSelectComponentFactoryOptions, DecorateScalarExprTreeSectionChildrenContext, DecorateScalarExprTreeSectionChildrenOptions } from "@mwater/expressions-ui"
12
+ import { IsScalarExprTreeSectionInitiallyOpenContext, IsScalarExprTreeSectionMatchContext } from "@mwater/expressions-ui"
13
+
14
+ /**
15
+ * Creates several contexts to allow selecting of a table in an mWater-friendly way
16
+ * and several other context items
17
+ */
18
+ export default class MWaterContextComponent extends React.Component<{
19
+ apiUrl: string
20
+ client?: string
21
+ /** user id of logged in user */
22
+ user?: string
23
+ schema: Schema
24
+ /** Extra tables to load in schema. Forms are not loaded by default as they are too many */
25
+ extraTables?: string[]
26
+ /** Called when extra tables are changed and schema will be reloaded */
27
+ onExtraTablesChange?: (extraTables: string[]) => void
28
+ /** Override default add layer component. See AddLayerComponent for details */
29
+ addLayerElementFactory?: any
30
+ }> {
31
+ static childContextTypes = {
32
+ addLayerElementFactory: PropTypes.func, // Call with props of AddLayerComponent
33
+ globalFiltersElementFactory: PropTypes.func, // Call with props { schema, dataSource, filterableTables, globalFilters, onChange, nullIfIrrelevant }.
34
+ // Displays a component to edit global filters. nullIfIrrelevant causes null element if not applicable to filterableTables
35
+ }
36
+
37
+ createTableSelectElementFactory = (options: CustomTableSelectComponentFactoryOptions) => {
38
+ return (
39
+ <MWaterTableSelectComponent
40
+ apiUrl={this.props.apiUrl}
41
+ client={this.props.client}
42
+ schema={options.schema}
43
+ user={this.props.user}
44
+ table={options.value ?? undefined}
45
+ onChange={options.onChange}
46
+ extraTables={this.props.extraTables}
47
+ onExtraTablesChange={this.props.onExtraTablesChange}
48
+ filter={options.filter}
49
+ onFilterChange={options.onFilterChange}
50
+ />
51
+ )
52
+ }
53
+
54
+ getChildContext() {
55
+ const context: any = {}
56
+
57
+ if (this.props.addLayerElementFactory) {
58
+ context.addLayerElementFactory = this.props.addLayerElementFactory
59
+ }
60
+
61
+ context.globalFiltersElementFactory = (props: any) => {
62
+ if (props.nullIfIrrelevant && !_.any(props.filterableTables, (t: string) => t.match(/^entities./))) {
63
+ return null
64
+ }
65
+
66
+ return React.createElement(MWaterGlobalFiltersComponent, props)
67
+ }
68
+
69
+ return context
70
+ }
71
+
72
+ isScalarExprTreeSectionMatch = (options: { tableId: string; section: Section; filter?: string }) => {
73
+ if (options.tableId.match(/^entities\./) && options.section.id === "!indicators") {
74
+ return true
75
+ }
76
+ return null
77
+ }
78
+
79
+ isScalarExprTreeSectionInitiallyOpen = (options: { tableId: string; section: Section; filter?: string }) => {
80
+ return false
81
+ }
82
+
83
+ decorateScalarExprTreeSectionChildren = (options: DecorateScalarExprTreeSectionChildrenOptions) => {
84
+ // If related forms section of entities table or assets table
85
+ if (options.tableId.match(/^entities\./) && options.section.id === "!related_forms") {
86
+ return R(
87
+ "div",
88
+ { key: "_add_related_form_parent" },
89
+ options.children,
90
+ R(MWaterAddRelatedFormComponent, {
91
+ key: "_add_related_form",
92
+ table: options.tableId,
93
+ apiUrl: this.props.apiUrl,
94
+ client: this.props.client,
95
+ user: this.props.user,
96
+ schema: this.props.schema,
97
+ onSelect: this.handleAddTable
98
+ })
99
+ )
100
+ }
101
+
102
+ // If indicators section of entities table
103
+ if (options.tableId.match(/^entities\./) && options.section.id === "!indicators") {
104
+ return R(
105
+ "div",
106
+ { key: "_add_related_indicator_parent" },
107
+ options.children,
108
+ R(MWaterAddRelatedIndicatorComponent, {
109
+ key: "_add_related_indicator",
110
+ table: options.tableId,
111
+ apiUrl: this.props.apiUrl,
112
+ client: this.props.client,
113
+ user: this.props.user,
114
+ schema: this.props.schema,
115
+ onSelect: this.handleAddTable,
116
+ filter: options.filter
117
+ })
118
+ )
119
+ } else {
120
+ return options.children
121
+ }
122
+ }
123
+
124
+ handleAddTable = (table: any) => {
125
+ const extraTables = _.union(this.props.extraTables || [], [table])
126
+ return this.props.onExtraTablesChange!(extraTables)
127
+ }
128
+
129
+ render() {
130
+ return <CustomTableSelectComponentFactoryContext.Provider value={this.createTableSelectElementFactory}>
131
+ <IsScalarExprTreeSectionMatchContext.Provider value={this.isScalarExprTreeSectionMatch}>
132
+ <IsScalarExprTreeSectionInitiallyOpenContext.Provider value={this.isScalarExprTreeSectionInitiallyOpen}>
133
+ <DecorateScalarExprTreeSectionChildrenContext.Provider value={this.decorateScalarExprTreeSectionChildren}>
134
+ {this.props.children}
135
+ </DecorateScalarExprTreeSectionChildrenContext.Provider>
136
+ </IsScalarExprTreeSectionInitiallyOpenContext.Provider>
137
+ </IsScalarExprTreeSectionMatchContext.Provider>
138
+ </CustomTableSelectComponentFactoryContext.Provider>
139
+ }
140
+ }
@@ -10,7 +10,7 @@ import MWaterContextComponent from "./MWaterContextComponent"
10
10
 
11
11
  /**
12
12
  * Loads an mWater schema from the server and creates child with schema and dataSource
13
- * Also creates a tableSelectElementFactory context to allow selecting of a table in an mWater-friendly way
13
+ * Also creates context to allow selecting of a table in an mWater-friendly way
14
14
  * and several other context items
15
15
  */
16
16
  export default class MWaterLoaderComponent extends AsyncLoadComponent<
@@ -32,7 +32,7 @@ export default class MWaterLoaderComponent extends AsyncLoadComponent<
32
32
  addLayerElementFactory?: any
33
33
  children: (error: any, config?: { schema: Schema; dataSource: DataSource }) => ReactElement<any>
34
34
  /** Custom error formatter that returns React node or string, gets passed the error response from server */
35
- errorFormatter: (data: any, defaultError: string) => string
35
+ errorFormatter?: (data: any, defaultError: string) => string
36
36
  },
37
37
  {
38
38
  error: any
@@ -7,6 +7,7 @@ import { ExprUtils, Schema } from "@mwater/expressions"
7
7
  import MWaterResponsesFilterComponent from "./MWaterResponsesFilterComponent"
8
8
  import ModalPopupComponent from "@mwater/react-library/lib/ModalPopupComponent"
9
9
  import MWaterCompleteTableSelectComponent from "./MWaterCompleteTableSelectComponent"
10
+ import { ActiveTablesContext } from "@mwater/expressions-ui"
10
11
 
11
12
  export interface MWaterTableSelectComponentProps {
12
13
  /** Url to hit api */
@@ -37,10 +38,8 @@ export default class MWaterTableSelectComponent extends React.Component<
37
38
  > {
38
39
  static contextTypes = {
39
40
  locale: PropTypes.string, // e.g. "en"
40
-
41
- // Optional list of tables (ids) being used. Use this to present an initially short list to select from
42
- activeTables: PropTypes.arrayOf(PropTypes.string.isRequired)
43
41
  }
42
+
44
43
  toggleEdit: any
45
44
 
46
45
  constructor(props: any) {
@@ -187,9 +186,6 @@ class EditModeTableSelectComponent extends React.Component<
187
186
  > {
188
187
  static contextTypes = {
189
188
  locale: PropTypes.string, // e.g. "en"
190
-
191
- // Optional list of tables (ids) being used. Use this to present an initially short list to select from
192
- activeTables: PropTypes.arrayOf(PropTypes.string.isRequired)
193
189
  }
194
190
 
195
191
  constructor(props: any) {
@@ -208,8 +204,8 @@ class EditModeTableSelectComponent extends React.Component<
208
204
  // Get list of tables that should be included in shortlist
209
205
  // This is all active tables and all responses tables in schema (so as to include rosters) and all extra tables
210
206
  // Also includes current table
211
- getTableShortlist(): string[] {
212
- let tables: string[] = this.context.activeTables || []
207
+ getTableShortlist(activeTables: string[]): string[] {
208
+ let tables: string[] = activeTables
213
209
 
214
210
  // Remove dead tables
215
211
  tables = tables.filter(
@@ -253,64 +249,63 @@ class EditModeTableSelectComponent extends React.Component<
253
249
  }
254
250
 
255
251
  render() {
256
- const items = _.map(this.getTableShortlist(), (tableId) => {
257
- const table = this.props.schema.getTable(tableId)!
258
-
259
- return {
260
- name: ExprUtils.localizeString(table.name, this.context.locale),
261
- desc: ExprUtils.localizeString(table.desc, this.context.locale),
262
- onClick: this.props.onChange.bind(null, table.id)
263
- }
264
- })
265
-
266
- return R(
267
- "div",
268
- null,
269
- this.state.completeMode
270
- ? R(
271
- ModalPopupComponent,
272
- {
273
- header: "Select Data Source",
274
- onClose: () => this.setState({ completeMode: false }),
275
- showCloseX: true,
276
- size: "x-large"
277
- },
278
- R(MWaterCompleteTableSelectComponent, {
279
- apiUrl: this.props.apiUrl,
280
- client: this.props.client,
281
- schema: this.props.schema,
282
- user: this.props.user,
283
- table: this.props.table,
284
- onChange: this.handleCompleteChange,
285
- extraTables: this.props.extraTables,
286
- onExtraTablesChange: this.props.onExtraTablesChange
287
- })
288
- )
289
- : undefined,
290
-
291
- items.length > 0
292
- ? [
293
- R("div", { className: "text-muted" }, "Select Data Source:"),
294
-
295
- R(OptionListComponent, { items }),
296
-
297
- R(
298
- "div",
299
- null,
300
- items.length > 0
301
- ? R(
302
- "button",
303
- { type: "button", className: "btn btn-link btn-sm", onClick: this.handleShowMore },
304
- "Show All Available Data Sources..."
305
- )
306
- : undefined
307
- )
308
- ]
309
- : R(
310
- "button",
311
- { type: "button", className: "btn btn-link", onClick: this.handleShowMore },
312
- "Select Data Source..."
313
- )
252
+ return (
253
+ <ActiveTablesContext.Consumer>
254
+ {activeTables => (
255
+ <div>
256
+ {this.state.completeMode ? (
257
+ <ModalPopupComponent
258
+ header="Select Data Source"
259
+ onClose={() => this.setState({ completeMode: false })}
260
+ showCloseX={true}
261
+ size="x-large"
262
+ >
263
+ <MWaterCompleteTableSelectComponent
264
+ apiUrl={this.props.apiUrl}
265
+ client={this.props.client}
266
+ schema={this.props.schema}
267
+ user={this.props.user}
268
+ table={this.props.table}
269
+ onChange={this.handleCompleteChange}
270
+ extraTables={this.props.extraTables}
271
+ onExtraTablesChange={this.props.onExtraTablesChange}
272
+ />
273
+ </ModalPopupComponent>
274
+ ) : null}
275
+
276
+ {this.getTableShortlist(activeTables).length > 0 ? (
277
+ <>
278
+ <div className="text-muted">Select Data Source:</div>
279
+ <OptionListComponent items={this.getTableShortlist(activeTables).map((tableId) => {
280
+ const table = this.props.schema.getTable(tableId)!
281
+ return {
282
+ name: ExprUtils.localizeString(table.name, this.context.locale),
283
+ desc: ExprUtils.localizeString(table.desc, this.context.locale),
284
+ onClick: () => this.props.onChange(table.id)
285
+ }
286
+ })} />
287
+ <div>
288
+ <button
289
+ type="button"
290
+ className="btn btn-link btn-sm"
291
+ onClick={this.handleShowMore}
292
+ >
293
+ Show All Available Data Sources...
294
+ </button>
295
+ </div>
296
+ </>
297
+ ) : (
298
+ <button
299
+ type="button"
300
+ className="btn btn-link"
301
+ onClick={this.handleShowMore}
302
+ >
303
+ Select Data Source...
304
+ </button>
305
+ )}
306
+ </div>
307
+ )}
308
+ </ActiveTablesContext.Consumer>
314
309
  )
315
310
  }
316
311
  }
@@ -253,7 +253,7 @@ export default class AxisBuilder {
253
253
  if (options.axis.xform.excludeUpper) {
254
254
  const thresholds = _.map(
255
255
  _.range(0, options.axis.xform.numBins),
256
- (bin) => min + ((max - min) * bin) / options.axis.xform!.numBins!
256
+ (bin) => min + ((max - min) * bin) / options.axis!.xform!.numBins!
257
257
  )
258
258
  thresholds.push(max + epsilon)
259
259
  compiledExpr = {
@@ -10,6 +10,7 @@ import NumberInputComponent from "@mwater/react-library/lib/NumberInputComponent
10
10
  import ReorderableListComponent from "@mwater/react-library/lib/reorderable/ReorderableListComponent"
11
11
  import { AxisXform, AxisXformRange } from "./Axis"
12
12
  import { Expr, Schema } from "@mwater/expressions"
13
+ import produce from "immer"
13
14
 
14
15
  export interface RangesComponentProps {
15
16
  schema: Schema
@@ -102,9 +103,9 @@ export default class RangesComponent extends React.Component<RangesComponentProp
102
103
 
103
104
  interface RangeComponentProps {
104
105
  /** Range to edit */
105
- range: any
106
- onChange: any
107
- onRemove: any
106
+ range: AxisXformRange
107
+ onChange: (range: AxisXformRange) => void
108
+ onRemove: () => void
108
109
  /** reorderable connector */
109
110
  connectDragSource: any
110
111
  /** reorderable connector */
@@ -114,14 +115,24 @@ interface RangeComponentProps {
114
115
 
115
116
  // Single range (row)
116
117
  class RangeComponent extends React.Component<RangeComponentProps> {
117
- handleMinOpenChange = (minOpen: any) => {
118
- return this.props.onChange(update(this.props.range, { minOpen: { $set: minOpen } }))
118
+ /**
119
+ * Handles change in minimum open value
120
+ */
121
+ handleMinOpenChange = (minOpen: boolean) => {
122
+ return this.props.onChange(produce(this.props.range, draft => {
123
+ draft.minOpen = minOpen
124
+ }))
119
125
  }
120
126
 
121
- handleMaxOpenChange = (maxOpen: any) => {
122
- return this.props.onChange(update(this.props.range, { maxOpen: { $set: maxOpen } }))
127
+ /**
128
+ * Handles change in maximum open value
129
+ */
130
+ handleMaxOpenChange = (maxOpen: boolean) => {
131
+ return this.props.onChange(produce(this.props.range, draft => {
132
+ draft.maxOpen = maxOpen
133
+ }))
123
134
  }
124
-
135
+
125
136
  render() {
126
137
  let placeholder = ""
127
138
  if (this.props.range.minValue != null) {
@@ -156,10 +167,10 @@ class RangeComponent extends React.Component<RangeComponentProps> {
156
167
  LinkComponent,
157
168
  {
158
169
  dropdownItems: [
159
- { id: true, name: "greater than" },
160
- { id: false, name: "greater than or equal to" }
170
+ { id: "true", name: "greater than" },
171
+ { id: "false", name: "greater than or equal to" }
161
172
  ],
162
- onDropdownItemClicked: this.handleMinOpenChange
173
+ onDropdownItemClicked: (id: string) => this.handleMinOpenChange(id === "true")
163
174
  },
164
175
  this.props.range.minOpen ? "greater than" : "greater than or equal to"
165
176
  )
@@ -169,7 +180,7 @@ class RangeComponent extends React.Component<RangeComponentProps> {
169
180
  "td",
170
181
  { key: "minValue" },
171
182
  R(NumberInputComponent, {
172
- value: this.props.range.minValue,
183
+ value: this.props.range.minValue ?? undefined,
173
184
  placeholder: "None",
174
185
  small: true,
175
186
  onChange: (v: any) => this.props.onChange(update(this.props.range, { minValue: { $set: v } }))
@@ -185,10 +196,10 @@ class RangeComponent extends React.Component<RangeComponentProps> {
185
196
  LinkComponent,
186
197
  {
187
198
  dropdownItems: [
188
- { id: true, name: "less than" },
189
- { id: false, name: "less than or equal to" }
199
+ { id: "true", name: "less than" },
200
+ { id: "false", name: "less than or equal to" }
190
201
  ],
191
- onDropdownItemClicked: this.handleMaxOpenChange
202
+ onDropdownItemClicked: (id: string) => this.handleMaxOpenChange(id === "true")
192
203
  },
193
204
  this.props.range.maxOpen ? "less than" : "less than or equal to"
194
205
  )
@@ -198,7 +209,7 @@ class RangeComponent extends React.Component<RangeComponentProps> {
198
209
  "td",
199
210
  { key: "maxValue" },
200
211
  R(NumberInputComponent, {
201
- value: this.props.range.maxValue,
212
+ value: this.props.range.maxValue ?? undefined,
202
213
  placeholder: "None",
203
214
  small: true,
204
215
  onChange: (v: any) => this.props.onChange(update(this.props.range, { maxValue: { $set: v } }))
@@ -19,6 +19,7 @@ import { getLayoutOptions } from "./layoutOptions"
19
19
  import { DashboardDesign } from "./DashboardDesign"
20
20
  import DashboardDataSource from "./DashboardDataSource"
21
21
  import { JsonQLFilter } from ".."
22
+ import { ActiveTablesContext } from "@mwater/expressions-ui"
22
23
 
23
24
  export interface DashboardComponentProps {
24
25
  design: DashboardDesign
@@ -80,7 +81,6 @@ export default class DashboardComponent extends React.Component<DashboardCompone
80
81
 
81
82
  static childContextTypes = {
82
83
  locale: PropTypes.string,
83
- activeTables: PropTypes.arrayOf(PropTypes.string.isRequired)
84
84
  }
85
85
 
86
86
  settings: SettingsModalComponent | null
@@ -89,9 +89,6 @@ export default class DashboardComponent extends React.Component<DashboardCompone
89
89
  return {
90
90
  // Pass locale down. Both here and DashboardViewComponent to ensure that quickfilters also get context
91
91
  locale: this.props.design.locale,
92
-
93
- // Pass active tables down to table select components so they can present a shorter list
94
- activeTables: DashboardUtils.getFilterableTables(this.props.design, this.props.schema)
95
92
  }
96
93
  }
97
94
 
@@ -428,41 +425,41 @@ export default class DashboardComponent extends React.Component<DashboardCompone
428
425
  hideScopes: this.state.hideQuickfilters
429
426
  })
430
427
 
431
- return R(
432
- "div",
433
- {
434
- style: {
435
- display: "grid",
436
- gridTemplateRows: this.props.hideTitleBar ? "auto 1fr" : "auto auto 1fr",
437
- height: "100%"
438
- }
439
- },
440
- !this.props.hideTitleBar ? this.renderTitleBar() : undefined,
441
- R("div", null, !this.state.hideQuickfilters ? this.renderQuickfilter() : undefined),
442
- dashboardView,
443
- this.props.onDesignChange != null
444
- ? R(SettingsModalComponent, {
445
- onDesignChange: this.handleDesignChange,
446
- schema: this.props.schema,
447
- dataSource: this.props.dataSource,
448
- ref: (c: SettingsModalComponent | null) => {
449
- this.settings = c
450
- }
451
- })
452
- : undefined,
453
- this.state.layoutOptionsOpen
454
- ? R(
455
- ModalWindowComponent,
456
- { isOpen: true, outerPadding: 10, innerPadding: 10 },
457
- R(LayoutOptionsComponent, {
458
- design: this.props.design,
459
- onDesignChange: this.props.onDesignChange!,
460
- onClose: () => this.setState({ layoutOptionsOpen: false }),
461
- dashboardView: readonlyDashboardView,
462
- quickfiltersView: this.renderQuickfilter()
463
- })
464
- )
465
- : undefined
466
- )
428
+
429
+ // Pass active tables down to table select components so they can present a shorter list
430
+ return <ActiveTablesContext.Provider
431
+ value={DashboardUtils.getFilterableTables(this.props.design, this.props.schema)}>
432
+
433
+ <div style={{
434
+ display: "grid",
435
+ gridTemplateRows: this.props.hideTitleBar ? "auto 1fr" : "auto auto 1fr",
436
+ height: "100%"
437
+ }}>
438
+ {!this.props.hideTitleBar ? this.renderTitleBar() : undefined}
439
+ <div>{!this.state.hideQuickfilters ? this.renderQuickfilter() : undefined}</div>
440
+ {dashboardView}
441
+ {this.props.onDesignChange != null && (
442
+ <SettingsModalComponent
443
+ onDesignChange={this.handleDesignChange}
444
+ schema={this.props.schema}
445
+ dataSource={this.props.dataSource}
446
+ ref={(c: SettingsModalComponent | null) => {
447
+ this.settings = c
448
+ }}
449
+ />
450
+ )}
451
+ {this.state.layoutOptionsOpen && (
452
+ <ModalWindowComponent isOpen={true} outerPadding={10} innerPadding={10}>
453
+ <LayoutOptionsComponent
454
+ design={this.props.design}
455
+ onDesignChange={this.props.onDesignChange!}
456
+ onClose={() => this.setState({ layoutOptionsOpen: false })}
457
+ dashboardView={readonlyDashboardView}
458
+ quickfiltersView={this.renderQuickfilter()}
459
+ />
460
+ </ModalWindowComponent>
461
+ )}
462
+ </div>
463
+ </ActiveTablesContext.Provider>
467
464
  }
468
465
  }