@mwater/visualization 5.1.0 → 5.2.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 (101) hide show
  1. package/lib/GlobalFilter.d.ts +13 -0
  2. package/lib/GlobalFilter.js +2 -0
  3. package/lib/MWaterCompleteTableSelectComponent.d.ts +2 -9
  4. package/lib/MWaterContextComponent.d.ts +15 -3
  5. package/lib/MWaterContextComponent.js +38 -13
  6. package/lib/MWaterCustomTablesetListComponent.js +9 -3
  7. package/lib/MWaterGlobalFiltersComponent.d.ts +6 -5
  8. package/lib/MWaterGlobalFiltersComponent.js +4 -4
  9. package/lib/MWaterLoaderComponent.d.ts +12 -2
  10. package/lib/MWaterLoaderComponent.js +9 -1
  11. package/lib/axes/Axis.d.ts +20 -25
  12. package/lib/axes/AxisBuilder.js +9 -7
  13. package/lib/axes/AxisComponent.d.ts +4 -4
  14. package/lib/dashboards/DashboardComponent.d.ts +0 -5
  15. package/lib/dashboards/DashboardComponent.js +2 -29
  16. package/lib/dashboards/DashboardDesign.d.ts +2 -17
  17. package/lib/dashboards/DashboardViewComponent.js +3 -4
  18. package/lib/dashboards/LayoutOptionsComponent.js +4 -3
  19. package/lib/dashboards/SettingsModalComponent.d.ts +4 -15
  20. package/lib/dashboards/SettingsModalComponent.js +24 -38
  21. package/lib/datagrids/DatagridComponent.d.ts +2 -9
  22. package/lib/datagrids/DatagridDataSource.d.ts +3 -3
  23. package/lib/datagrids/DatagridDataSource.js +0 -14
  24. package/lib/datagrids/DatagridDesignerComponent.d.ts +2 -93
  25. package/lib/datagrids/DatagridDesignerComponent.js +8 -6
  26. package/lib/datagrids/DatagridViewComponent.js +1 -1
  27. package/lib/datagrids/FindReplaceModalComponent.d.ts +4 -20
  28. package/lib/datagrids/FindReplaceModalComponent.js +27 -13
  29. package/lib/datagrids/ServerDatagridDataSource.d.ts +1 -1
  30. package/lib/datagrids/ServerDatagridDataSource.js +1 -3
  31. package/lib/demo.js +1 -1
  32. package/lib/index.d.ts +1 -0
  33. package/lib/layouts/blocks/BlocksDisplayComponent.d.ts +2 -1
  34. package/lib/layouts/grid/GridLayoutManager.d.ts +2 -1
  35. package/lib/maps/BufferLayer.js +3 -1
  36. package/lib/maps/ClusterLayer.js +3 -1
  37. package/lib/maps/GridLayer.js +5 -3
  38. package/lib/maps/GridLayerDesigner.js +0 -1
  39. package/lib/maps/LayerSwitcherComponent.js +1 -1
  40. package/lib/maps/MapComponent.d.ts +2 -7
  41. package/lib/maps/MapDesign.d.ts +2 -13
  42. package/lib/maps/MapFiltersDesignerComponent.d.ts +0 -4
  43. package/lib/maps/MapFiltersDesignerComponent.js +4 -5
  44. package/lib/maps/RasterMapViewComponent.d.ts +2 -9
  45. package/lib/maps/RegionSelectComponent.d.ts +2 -1
  46. package/lib/maps/ServerMapDataSource.d.ts +1 -1
  47. package/lib/maps/vectorMaps.d.ts +1 -0
  48. package/lib/maps/vectorMaps.js +10 -2
  49. package/lib/quickfilter/QuickfilterCompiler.d.ts +1 -1
  50. package/lib/widgets/IFrameWidgetComponent.d.ts +2 -9
  51. package/lib/widgets/ImageWidgetComponent.d.ts +6 -24
  52. package/lib/widgets/MapWidget.d.ts +2 -7
  53. package/lib/widgets/MarkdownWidget.d.ts +2 -7
  54. package/lib/widgets/TOCWidget.d.ts +2 -9
  55. package/lib/widgets/charts/ChartWidget.d.ts +3 -15
  56. package/lib/widgets/charts/imagemosaic/ImagePopupComponent.d.ts +2 -7
  57. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.d.ts +2 -31
  58. package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.d.ts +2 -7
  59. package/lib/widgets/charts/pivot/IntersectionDesignerComponent.d.ts +73 -66
  60. package/lib/widgets/charts/pivot/PivotChartDesignerComponent.d.ts +10 -6
  61. package/lib/widgets/charts/pivot/PivotChartViewComponent.d.ts +3 -22
  62. package/lib/widgets/charts/pivot/SegmentDesignerComponent.d.ts +55 -58
  63. package/lib/widgets/charts/table/TableChartViewComponent.js +21 -7
  64. package/lib/widgets/text/ExprInsertModalComponent.d.ts +2 -13
  65. package/lib/widgets/text/ExprUpdateModalComponent.d.ts +2 -13
  66. package/lib/widgets/text/TextWidgetDesign.d.ts +3 -1
  67. package/package.json +1 -1
  68. package/src/GlobalFilter.ts +17 -0
  69. package/src/MWaterContextComponent.tsx +37 -19
  70. package/src/MWaterCustomTablesetListComponent.tsx +21 -3
  71. package/src/MWaterGlobalFiltersComponent.ts +8 -8
  72. package/src/MWaterLoaderComponent.ts +8 -1
  73. package/src/axes/Axis.ts +24 -25
  74. package/src/axes/AxisBuilder.ts +9 -8
  75. package/src/dashboards/DashboardComponent.tsx +2 -40
  76. package/src/dashboards/DashboardDesign.ts +2 -22
  77. package/src/dashboards/DashboardViewComponent.ts +4 -5
  78. package/src/dashboards/LayoutOptionsComponent.tsx +6 -4
  79. package/src/dashboards/SettingsModalComponent.tsx +170 -0
  80. package/src/datagrids/DatagridDataSource.ts +6 -12
  81. package/src/datagrids/DatagridDesignerComponent.tsx +22 -18
  82. package/src/datagrids/DatagridViewComponent.ts +3 -3
  83. package/src/datagrids/ExprCellComponent.ts +0 -1
  84. package/src/datagrids/FindReplaceModalComponent.ts +39 -22
  85. package/src/datagrids/ServerDatagridDataSource.ts +1 -2
  86. package/src/demo.ts +1 -1
  87. package/src/index.ts +1 -0
  88. package/src/maps/BufferLayer.ts +3 -1
  89. package/src/maps/ClusterLayer.ts +3 -1
  90. package/src/maps/GridLayer.ts +5 -3
  91. package/src/maps/GridLayerDesigner.tsx +0 -1
  92. package/src/maps/LayerSwitcherComponent.tsx +1 -1
  93. package/src/maps/MapDesign.ts +2 -17
  94. package/src/maps/{MapFiltersDesignerComponent.ts → MapFiltersDesignerComponent.tsx} +25 -25
  95. package/src/maps/ServerMapDataSource.ts +1 -1
  96. package/src/maps/VectorMapViewComponent.tsx +0 -1
  97. package/src/maps/vectorMaps.tsx +10 -1
  98. package/src/quickfilter/QuickfilterCompiler.ts +1 -1
  99. package/src/widgets/charts/table/TableChartViewComponent.ts +21 -7
  100. package/src/widgets/text/TextWidgetDesign.ts +4 -1
  101. package/src/dashboards/SettingsModalComponent.ts +0 -169
@@ -24,7 +24,7 @@ export interface FindReplaceModalComponentProps {
24
24
 
25
25
  /** Update cell values by updating set of expressions and values */
26
26
  updateExprValues: (tableId: string, rowUpdates: RowUpdate[]) => Promise<void>
27
-
27
+
28
28
  onUpdate: () => void
29
29
  }
30
30
 
@@ -73,6 +73,18 @@ export default class FindReplaceModalComponent extends React.Component<
73
73
  // Get expr of replace column
74
74
  const replaceExpr = _.findWhere(this.props.design.columns, { id: this.state.replaceColumn })!.expr
75
75
 
76
+ const exprType = exprUtils.getExprType(this.state.withExpr)
77
+ let compiledWithExpr = exprCompiler.compileExpr({ expr: this.state.withExpr, tableAlias: "main" })
78
+ if (exprType === "geometry") {
79
+ compiledWithExpr = {
80
+ type: "op",
81
+ op: "ST_AsGeoJSON",
82
+ exprs: [
83
+ { type: "op", op: "ST_Transform", exprs: [{ type: "op", op: "::geometry", exprs: [compiledWithExpr] }, 4326] }
84
+ ]
85
+ }
86
+ }
87
+
76
88
  // Get ids and with value, filtered by filters, design.filter and conditionExpr (if present)
77
89
  const query: JsonQLSelectQuery = {
78
90
  type: "query",
@@ -88,7 +100,7 @@ export default class FindReplaceModalComponent extends React.Component<
88
100
  },
89
101
  {
90
102
  type: "select",
91
- expr: exprCompiler.compileExpr({ expr: this.state.withExpr, tableAlias: "main" }),
103
+ expr: compiledWithExpr,
92
104
  alias: "withValue"
93
105
  }
94
106
  ],
@@ -120,7 +132,12 @@ export default class FindReplaceModalComponent extends React.Component<
120
132
  }
121
133
 
122
134
  // Create expr
123
- let expr: Expr = { type: "op", op: filter.op, table: design.table!, exprs: [columnExpr as Expr].concat(filter.exprs) }
135
+ let expr: Expr = {
136
+ type: "op",
137
+ op: filter.op,
138
+ table: design.table!,
139
+ exprs: [columnExpr as Expr].concat(filter.exprs)
140
+ }
124
141
 
125
142
  // Clean expr
126
143
  expr = exprCleaner.cleanExpr(expr, { table: design.table! })
@@ -147,16 +164,19 @@ export default class FindReplaceModalComponent extends React.Component<
147
164
  }
148
165
 
149
166
  // Perform updates
150
- await this.props.updateExprValues(this.props.design.table!, rows.map(row => ({
151
- primaryKey: row.id,
152
- expr: replaceExpr,
153
- value: row.withValue
154
- })))
155
-
167
+ await this.props.updateExprValues(
168
+ this.props.design.table!,
169
+ rows.map(row => ({
170
+ primaryKey: row.id,
171
+ expr: replaceExpr,
172
+ value: exprType === "geometry" ? JSON.parse(row.withValue) : row.withValue
173
+ }))
174
+ )
175
+
156
176
  alert(T("Successfully replaced {0} values", rows.length))
157
177
  this.setState({ open: false })
158
178
  this.props.onUpdate()
159
- } catch(error) {
179
+ } catch (error) {
160
180
  alert(`Error: ${error.message}`)
161
181
  } finally {
162
182
  this.setState({ busy: false })
@@ -183,7 +203,8 @@ export default class FindReplaceModalComponent extends React.Component<
183
203
  else: replaceColumn.expr
184
204
  }
185
205
 
186
- replaceColumn.label = replaceColumn.label || exprUtils.summarizeExpr(replaceColumn.expr, this.props.design.locale)
206
+ replaceColumn.label =
207
+ replaceColumn.label || exprUtils.summarizeExpr(replaceColumn.expr, this.props.design.locale)
187
208
  }
188
209
 
189
210
  // Add filter
@@ -193,13 +214,9 @@ export default class FindReplaceModalComponent extends React.Component<
193
214
  type: "op",
194
215
  op: "and",
195
216
  table: this.props.design.table!,
196
- exprs: [
197
- draft.filter,
198
- this.state.conditionExpr
199
- ]
217
+ exprs: [draft.filter, this.state.conditionExpr]
200
218
  }
201
- }
202
- else {
219
+ } else {
203
220
  draft.filter = this.state.conditionExpr
204
221
  }
205
222
  }
@@ -228,9 +245,9 @@ export default class FindReplaceModalComponent extends React.Component<
228
245
  // Determine which columns are replace-able. Excludes subtables and aggregates
229
246
  const replaceColumns = _.filter(
230
247
  this.props.design.columns,
231
- (column) => !column.subtable && exprUtils.getExprAggrStatus(column.expr) === "individual"
248
+ column => !column.subtable && exprUtils.getExprAggrStatus(column.expr) === "individual"
232
249
  )
233
- const replaceColumnOptions = _.map(replaceColumns, (column) => ({
250
+ const replaceColumnOptions = _.map(replaceColumns, column => ({
234
251
  value: column.id,
235
252
  label: column.label || exprUtils.summarizeExpr(column.expr, this.props.design.locale)
236
253
  }))
@@ -263,7 +280,7 @@ export default class FindReplaceModalComponent extends React.Component<
263
280
  placeholder: T("Select Column..."),
264
281
  styles: {
265
282
  // Keep menu above fixed data table headers
266
- menu: (style) => _.extend({}, style, { zIndex: 2 })
283
+ menu: style => _.extend({}, style, { zIndex: 2 })
267
284
  }
268
285
  })
269
286
  ),
@@ -282,7 +299,7 @@ export default class FindReplaceModalComponent extends React.Component<
282
299
  dataSource: this.props.dataSource,
283
300
  table: this.props.design.table!,
284
301
  value: this.state.withExpr,
285
- onChange: (value) => this.setState({ withExpr: value }),
302
+ onChange: value => this.setState({ withExpr: value }),
286
303
  types: [exprUtils.getExprType(replaceExpr)!],
287
304
  enumValues: exprUtils.getExprEnumValues(replaceExpr) || undefined,
288
305
  idTable: exprUtils.getExprIdTable(replaceExpr) || undefined,
@@ -304,7 +321,7 @@ export default class FindReplaceModalComponent extends React.Component<
304
321
  dataSource: this.props.dataSource,
305
322
  table: this.props.design.table!,
306
323
  value: this.state.conditionExpr,
307
- onChange: (value) => this.setState({ conditionExpr: value }),
324
+ onChange: value => this.setState({ conditionExpr: value }),
308
325
  types: ["boolean"],
309
326
  placeholder: T("All Rows")
310
327
  })
@@ -22,7 +22,7 @@ export interface ServerDatagridDataSourceOptions {
22
22
  }
23
23
 
24
24
  /** Uses mWater server to get datagrid data to allow sharing with unprivileged users */
25
- export default class ServerDatagridDataSource extends DatagridDataSource {
25
+ export default class ServerDatagridDataSource implements DatagridDataSource {
26
26
  options: ServerDatagridDataSourceOptions
27
27
 
28
28
  // options:
@@ -32,7 +32,6 @@ export default class ServerDatagridDataSource extends DatagridDataSource {
32
32
  // datagridId: datagrid id to use on server
33
33
  // rev: revision to use to allow caching
34
34
  constructor(options: ServerDatagridDataSourceOptions) {
35
- super()
36
35
  this.options = options
37
36
  }
38
37
 
package/src/demo.ts CHANGED
@@ -471,7 +471,7 @@ class WaterOrgDashboardPane extends React.Component {
471
471
  }
472
472
 
473
473
  componentWillMount() {
474
- const url = this.props.apiUrl + "jsonql/schema"
474
+ const url = this.props.apiUrl + "schema"
475
475
  return $.getJSON(url, (schemaJson) => {
476
476
  const schema = new Schema(schemaJson)
477
477
  const dataSource = new MWaterDataSource(this.props.apiUrl, null, { serverCaching: false, localCaching: true })
package/src/index.ts CHANGED
@@ -75,6 +75,7 @@ export { default as AxisBuilder } from "./axes/AxisBuilder"
75
75
  export { default as ColorSchemeFactory } from "./ColorSchemeFactory"
76
76
  export { default as DatagridComponent } from "./datagrids/DatagridComponent"
77
77
  export { default as DatagridViewComponent } from "./datagrids/DatagridViewComponent"
78
+ export { default as DatagridDataSource } from "./datagrids/DatagridDataSource"
78
79
  export { default as ServerDashboardDataSource } from "./dashboards/ServerDashboardDataSource"
79
80
  export { default as ServerMapDataSource } from "./maps/ServerMapDataSource"
80
81
  export { default as DirectMapDataSource } from "./maps/DirectMapDataSource"
@@ -88,7 +88,9 @@ export default class BufferLayer extends Layer<BufferLayerDesign> {
88
88
  sourceLayers: [{ id: "circles", jsonql: jsonql }],
89
89
  ctes: [],
90
90
  mapLayers: mapLayers,
91
- mapLayersHandleClicks: [`${sourceId}:fill`]
91
+ mapLayersHandleClicks: [`${sourceId}:fill`],
92
+ minZoom: this.getMinZoom(design),
93
+ maxZoom: this.getMaxZoom(design)
92
94
  }
93
95
  }
94
96
 
@@ -79,7 +79,9 @@ export default class ClusterLayer extends Layer<ClusterLayerDesign> {
79
79
  sourceLayers: [{ id: "clusters", jsonql: jsonql }],
80
80
  ctes: [],
81
81
  mapLayers: mapLayers,
82
- mapLayersHandleClicks: [`${sourceId}:circles-single`, `${sourceId}:circles-multiple`]
82
+ mapLayersHandleClicks: [`${sourceId}:circles-single`, `${sourceId}:circles-multiple`],
83
+ minZoom: this.getMinZoom(design),
84
+ maxZoom: this.getMaxZoom(design)
83
85
  }
84
86
  }
85
87
 
@@ -75,7 +75,9 @@ export default class GridLayer extends Layer<GridLayerDesign> {
75
75
  sourceLayers: [{ id: "grid", jsonql: jsonql }],
76
76
  ctes: [],
77
77
  mapLayers: mapLayers,
78
- mapLayersHandleClicks: [`${sourceId}:fill`]
78
+ mapLayersHandleClicks: [`${sourceId}:fill`],
79
+ minZoom: this.getMinZoom(design),
80
+ maxZoom: this.getMaxZoom(design)
79
81
  }
80
82
  }
81
83
 
@@ -606,9 +608,9 @@ export default class GridLayer extends Layer<GridLayerDesign> {
606
608
 
607
609
  // Get min and max zoom levels
608
610
  getMinZoom(design: GridLayerDesign) {
609
- // Determine if too zoomed out to safely display (zoom 6 at 20000 is limit)
611
+ // Determine if too zoomed out to safely display (200x200, so size = 4e7/(2^zoom) < 200)
610
612
  if (design.sizeUnits === "meters") {
611
- const minSafeZoom = Math.log2(1280000.0 / (design.size || 20000))
613
+ const minSafeZoom = Math.log2(200000.0 / (design.size || 20000))
612
614
  if (design.minZoom) {
613
615
  return Math.max(design.minZoom, minSafeZoom)
614
616
  } else {
@@ -69,7 +69,6 @@ export default class GridLayerDesigner extends React.Component<{
69
69
  this.update((d) => {
70
70
  d.sizeUnits = sizeUnits
71
71
  d.size = 20000
72
- d.minZoom = 6
73
72
  })
74
73
  }
75
74
  }
@@ -60,7 +60,7 @@ export function LayerSwitcherComponent(props: { design: MapDesign; onDesignChang
60
60
  <i className="fas fa-layer-group fa-fw" />
61
61
  </div>
62
62
  {dropdownOpen ? (
63
- <div style={{ backgroundColor: "white", padding: 5 }}>{props.design.layerViews.map(renderLayerView)}</div>
63
+ <div style={{ backgroundColor: "white", padding: 5, textAlign: "left" }}>{props.design.layerViews.map(renderLayerView)}</div>
64
64
  ) : null}
65
65
  </div>
66
66
  )
@@ -1,5 +1,6 @@
1
- import { Expr, LiteralType } from "@mwater/expressions"
1
+ import { Expr } from "@mwater/expressions"
2
2
  import { Quickfilter } from "../quickfilter/Quickfilter"
3
+ import { GlobalFilter } from "../GlobalFilter"
3
4
 
4
5
  /** Maps are stored as a base layer, a series of layers and filters. */
5
6
  export interface MapDesign {
@@ -85,19 +86,3 @@ export interface MapLayerView {
85
86
  /** true to hide legend */
86
87
  hideLegend?: boolean
87
88
  }
88
-
89
- /** Global filters apply to multiple tables at once if a certain column is present. User-interface to set them is application-specific
90
- and the default (non-mWater) dashboard applies them but does not allow editing. */
91
- export interface GlobalFilter {
92
- /** id of column to filter */
93
- columnId: string
94
-
95
- /** type of column to filter (to ensure that consistent) */
96
- columnType: LiteralType
97
-
98
- /** op of expression for filtering */
99
- op: string
100
-
101
- /** array of expressions to use for filtering. field expression for column will be injected as expression 0 in the resulting filter expression */
102
- exprs: Expr[]
103
- }
@@ -1,13 +1,11 @@
1
1
  import _ from "lodash"
2
- import PropTypes from "prop-types"
3
2
  import React from "react"
4
3
  const R = React.createElement
5
- import { FilterExprComponent } from "@mwater/expressions-ui"
6
- import { DataSource, ExprCleaner, Schema } from "@mwater/expressions"
7
- import { ExprUtils } from "@mwater/expressions"
4
+ import { DataSource, Schema } from "@mwater/expressions"
8
5
  import PopoverHelpComponent from "@mwater/react-library/lib/PopoverHelpComponent"
9
6
  import FiltersDesignerComponent from "../FiltersDesignerComponent"
10
7
  import * as MapUtils from "./MapUtils"
8
+ import { GlobalFiltersElementFactoryContext } from "../MWaterContextComponent"
11
9
 
12
10
  export interface MapFiltersDesignerComponentProps {
13
11
  /** Schema to use */
@@ -22,8 +20,6 @@ export interface MapFiltersDesignerComponentProps {
22
20
 
23
21
  // Designer for filters for a map
24
22
  export default class MapFiltersDesignerComponent extends React.Component<MapFiltersDesignerComponentProps> {
25
- static contextTypes = { globalFiltersElementFactory: PropTypes.func }
26
-
27
23
  handleFiltersChange = (filters: any) => {
28
24
  const design = _.extend({}, this.props.design, { filters })
29
25
  return this.props.onDesignChange(design)
@@ -70,26 +66,30 @@ export default class MapFiltersDesignerComponent extends React.Component<MapFilt
70
66
  })
71
67
  )
72
68
  ),
69
+
70
+ <GlobalFiltersElementFactoryContext.Consumer>
71
+ {globalFiltersElementFactory =>
72
+ globalFiltersElementFactory
73
+ ? R(
74
+ "div",
75
+ { className: "mb-3" },
76
+ R("label", { className: "text-muted" }, "Global Filters "),
73
77
 
74
- this.context.globalFiltersElementFactory
75
- ? R(
76
- "div",
77
- { className: "mb-3" },
78
- R("label", { className: "text-muted" }, "Global Filters "),
79
-
80
- R(
81
- "div",
82
- { style: { margin: 5 } },
83
- this.context.globalFiltersElementFactory({
84
- schema: this.props.schema,
85
- dataSource: this.props.dataSource,
86
- filterableTables,
87
- globalFilters: this.props.design.globalFilters || [],
88
- onChange: this.handleGlobalFiltersChange
89
- })
90
- )
91
- )
92
- : undefined
78
+ R(
79
+ "div",
80
+ { style: { margin: 5 } },
81
+ globalFiltersElementFactory({
82
+ schema: this.props.schema,
83
+ dataSource: this.props.dataSource,
84
+ filterableTables,
85
+ globalFilters: this.props.design.globalFilters || [],
86
+ onChange: this.handleGlobalFiltersChange
87
+ })
88
+ )
89
+ )
90
+ : undefined
91
+ }
92
+ </GlobalFiltersElementFactoryContext.Consumer>
93
93
  )
94
94
  }
95
95
  }
@@ -35,7 +35,7 @@ interface ServerMapDataSourceOptions {
35
35
  mapId: string
36
36
 
37
37
  /** revision to use to allow caching */
38
- rev: string
38
+ rev: number
39
39
  }
40
40
 
41
41
  interface ServerMapLayerDataSourceOptions extends ServerMapDataSourceOptions {
@@ -14,7 +14,6 @@ import {
14
14
  getFilterableTables as utilsGetFilterableTables,
15
15
  MapScope
16
16
  } from "./MapUtils"
17
- import {Color} from '@maplibre/maplibre-gl-style-spec';
18
17
 
19
18
  import "maplibre-gl/dist/maplibre-gl.css"
20
19
  import "./VectorMapViewComponent.css"
@@ -7,6 +7,13 @@ import "maplibre-gl/dist/maplibre-gl.css"
7
7
  import "./VectorMapViewComponent.css"
8
8
  import React from "react"
9
9
 
10
+ /** Set to true to enable printing by preserving the drawing buffer */
11
+ let printingModeEnabled = false
12
+
13
+ export function setPrintingModeEnabled(val: boolean) {
14
+ printingModeEnabled = val
15
+ }
16
+
10
17
  /* Hooks and functions related to displaying a vector map */
11
18
 
12
19
  let mapTilerApiKey = ""
@@ -58,7 +65,8 @@ export function useVectorMap(options: {
58
65
  }
59
66
 
60
67
  const observer = new IntersectionObserver(function(entries) {
61
- setMapDivVisible(entries[0].isIntersecting)
68
+ // When in printing mode, always visible as we need to render the map
69
+ setMapDivVisible(entries[0].isIntersecting || printingModeEnabled)
62
70
  })
63
71
  observer.observe(divRef)
64
72
  return () => {
@@ -98,6 +106,7 @@ export function useVectorMap(options: {
98
106
  [-179.9, -85], // Southwest coordinates
99
107
  [179.9, 85] // Northeast coordinates
100
108
  ],
109
+ preserveDrawingBuffer: printingModeEnabled
101
110
  })
102
111
 
103
112
  setHasWebGLContext(true)
@@ -81,7 +81,7 @@ export default class QuickfilterCompiler {
81
81
  return filters
82
82
  }
83
83
 
84
- compileToFilterExpr(expr: any, value: any, multi: any): OpExpr | null {
84
+ compileToFilterExpr(expr: any, value: any, multi?: boolean): OpExpr | null {
85
85
  // Get type of expr
86
86
  const type = new ExprUtils(this.schema).getExprType(expr)
87
87
  const idTable = new ExprUtils(this.schema).getExprIdTable(expr)
@@ -223,7 +223,7 @@ class TableContentsComponent extends React.Component<TableContentsComponentProps
223
223
 
224
224
  renderImage(id: any) {
225
225
  const url = this.props.dataSource.getImageUrl(id)
226
- return R("a", { href: url, key: id, target: "_blank", style: { paddingLeft: 5, paddingRight: 5 } }, "Image")
226
+ return R("a", { href: url, onClick: (e) => {e.stopPropagation()}, key: id, target: "_blank", style: { paddingLeft: 5, paddingRight: 5 } }, "Image")
227
227
  }
228
228
 
229
229
  renderCell(rowIndex: any, columnIndex: any) {
@@ -264,7 +264,9 @@ class TableContentsComponent extends React.Component<TableContentsComponentProps
264
264
  // Convert to node based on type
265
265
  switch (exprType) {
266
266
  case "text":
267
- node = R(Linkify, { properties: { target: "_blank" } }, value)
267
+ if (_.isString(value)) {
268
+ node = R(Linkify, { properties: { target: "_blank" } }, value)
269
+ }
268
270
  break
269
271
  case "number":
270
272
  case "geometry":
@@ -272,21 +274,33 @@ class TableContentsComponent extends React.Component<TableContentsComponentProps
272
274
  break
273
275
  case "boolean":
274
276
  case "enum":
277
+ node = exprUtils.stringifyExprLiteral(column.textAxis?.expr, value, this.context.locale)
278
+ break
275
279
  case "enumset":
276
280
  case "text[]":
277
- node = exprUtils.stringifyExprLiteral(column.textAxis?.expr, value, this.context.locale)
281
+ if (_.isArray(value)) {
282
+ node = exprUtils.stringifyExprLiteral(column.textAxis?.expr, value, this.context.locale)
283
+ }
278
284
  break
279
285
  case "date":
280
- node = formatValue(exprType, value, column.format)
286
+ if (_.isString(value)) {
287
+ node = formatValue(exprType, value, column.format)
288
+ }
281
289
  break
282
290
  case "datetime":
283
- node = formatValue(exprType, value, column.format)
291
+ if (_.isString(value)) {
292
+ node = formatValue(exprType, value, column.format)
293
+ }
284
294
  break
285
295
  case "image":
286
- node = this.renderImage(value.id)
296
+ if (_.isObject(value) && value.id != null) {
297
+ node = this.renderImage(value.id)
298
+ }
287
299
  break
288
300
  case "imagelist":
289
- node = _.map(value, (v: Image) => this.renderImage(v.id))
301
+ if (_.isArray(value)) {
302
+ node = _.map(value, (v: Image) => this.renderImage(v.id))
303
+ }
290
304
  break
291
305
  default:
292
306
  node = "" + value
@@ -1,6 +1,9 @@
1
+ import { HtmlItemExpr } from "../../richtext/ExprItemsHtmlConverter"
2
+ import { HtmlItem } from "../../richtext/ItemsHtmlConverter"
3
+
1
4
  export interface TextWidgetDesign {
2
5
  /** Text widget stores its content as array of items. See ItemsHtmlConverter TODO */
3
- items: any[]
6
+ items: (HtmlItem | HtmlItemExpr)[]
4
7
 
5
8
  /** "title" for title block. default is "default" */
6
9
  style?: "title" | "default"
@@ -1,169 +0,0 @@
1
- import PropTypes from "prop-types"
2
- import _ from "lodash"
3
- import React from "react"
4
- const R = React.createElement
5
- import update from "update-object"
6
- import { languages } from "../languages"
7
- import * as ui from "@mwater/react-library/lib/bootstrap"
8
- import { default as ReactSelect } from "react-select"
9
- import * as DashboardUtils from "./DashboardUtils"
10
- import ActionCancelModalComponent from "@mwater/react-library/lib/ActionCancelModalComponent"
11
- import QuickfiltersDesignComponent from "../quickfilter/QuickfiltersDesignComponent"
12
- import FiltersDesignerComponent from "../FiltersDesignerComponent"
13
- import { DataSource, Schema } from "@mwater/expressions"
14
-
15
- export interface SettingsModalComponentProps {
16
- onDesignChange: any
17
- schema: Schema
18
- dataSource: DataSource
19
- }
20
-
21
- interface SettingsModalComponentState {
22
- design: any
23
- }
24
-
25
- // Popup with settings for dashboard
26
- export default class SettingsModalComponent extends React.Component<
27
- SettingsModalComponentProps,
28
- SettingsModalComponentState
29
- > {
30
- static contextTypes = { globalFiltersElementFactory: PropTypes.func }
31
-
32
- constructor(props: any) {
33
- super(props)
34
- this.state = {
35
- design: null // Set when being edited
36
- }
37
- }
38
-
39
- show(design: any) {
40
- return this.setState({ design })
41
- }
42
-
43
- handleSave = () => {
44
- this.props.onDesignChange(this.state.design)
45
- return this.setState({ design: null })
46
- }
47
-
48
- handleCancel = () => {
49
- return this.setState({ design: null })
50
- }
51
- handleDesignChange = (design: any) => {
52
- return this.setState({ design })
53
- }
54
-
55
- handleFiltersChange = (filters: any) => {
56
- const design = _.extend({}, this.state.design, { filters })
57
- return this.handleDesignChange(design)
58
- }
59
-
60
- handleGlobalFiltersChange = (globalFilters: any) => {
61
- const design = _.extend({}, this.state.design, { globalFilters })
62
- return this.handleDesignChange(design)
63
- }
64
-
65
- render() {
66
- // Don't show if not editing
67
- if (!this.state.design) {
68
- return null
69
- }
70
-
71
- // Get filterable tables
72
- const filterableTables = DashboardUtils.getFilterableTables(this.state.design, this.props.schema)
73
-
74
- const localeOptions = _.map(languages, (language) => {
75
- return {
76
- value: language.code,
77
- label: language.en + " (" + language.name + ")"
78
- }
79
- })
80
-
81
- return R(
82
- ActionCancelModalComponent,
83
- {
84
- size: "large",
85
- onCancel: this.handleCancel,
86
- onAction: this.handleSave
87
- },
88
- R(
89
- "div",
90
- { style: { paddingBottom: 200 } },
91
- R("h4", null, "Quick Filters"),
92
- R(
93
- "div",
94
- { className: "text-muted" },
95
- "Quick filters are shown to the user as a dropdown at the top of the dashboard and can be used to filter data of widgets."
96
- ),
97
-
98
- filterableTables.length > 0
99
- ? R(QuickfiltersDesignComponent, {
100
- design: this.state.design.quickfilters || [],
101
- onDesignChange: (design: any) =>
102
- this.handleDesignChange(update(this.state.design, { quickfilters: { $set: design } })),
103
- schema: this.props.schema,
104
- dataSource: this.props.dataSource,
105
- tables: filterableTables
106
- })
107
- : "Nothing to quickfilter. Add widgets to the dashboard",
108
-
109
- R("h4", { style: { paddingTop: 10 } }, "Filters"),
110
- R(
111
- "div",
112
- { className: "text-muted" },
113
- "Filters are built in to the dashboard and cannot be changed by viewers of the dashboard."
114
- ),
115
-
116
- filterableTables.length > 0
117
- ? R(FiltersDesignerComponent, {
118
- schema: this.props.schema,
119
- dataSource: this.props.dataSource,
120
- filters: this.state.design.filters,
121
- onFiltersChange: this.handleFiltersChange,
122
- filterableTables
123
- })
124
- : "Nothing to filter. Add widgets to the dashboard",
125
-
126
- this.context.globalFiltersElementFactory
127
- ? R(
128
- "div",
129
- null,
130
- R("h4", { style: { paddingTop: 10 } }, "Global Filters"),
131
-
132
- this.context.globalFiltersElementFactory({
133
- schema: this.props.schema,
134
- dataSource: this.props.dataSource,
135
- filterableTables,
136
- globalFilters: this.state.design.globalFilters || [],
137
- onChange: this.handleGlobalFiltersChange
138
- })
139
- )
140
- : undefined,
141
-
142
- R("h4", { style: { paddingTop: 10 } }, "Language"),
143
- R(
144
- "div",
145
- { className: "text-muted" },
146
- "Controls the preferred language of widgets and uses specified language when available"
147
- ),
148
-
149
- R(ReactSelect, {
150
- value: _.findWhere(localeOptions, { value: this.state.design.locale || "en" }) || null,
151
- options: localeOptions,
152
- onChange: (locale: any) =>
153
- this.handleDesignChange(update(this.state.design, { locale: { $set: locale.value } }))
154
- }),
155
-
156
- R("h4", { style: { paddingTop: 10 } }, "Advanced"),
157
- R(
158
- ui.Checkbox,
159
- {
160
- value: this.state.design.implicitFiltersEnabled != null ? this.state.design.implicitFiltersEnabled : true,
161
- onChange: (value) =>
162
- this.handleDesignChange(update(this.state.design, { implicitFiltersEnabled: { $set: value } }))
163
- },
164
- "Enable Implicit Filtering (leave unchecked for new dashboards)"
165
- )
166
- )
167
- )
168
- }
169
- }