@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.
- package/lib/GlobalFilter.d.ts +13 -0
- package/lib/GlobalFilter.js +2 -0
- package/lib/MWaterCompleteTableSelectComponent.d.ts +2 -9
- package/lib/MWaterContextComponent.d.ts +15 -3
- package/lib/MWaterContextComponent.js +38 -13
- package/lib/MWaterCustomTablesetListComponent.js +9 -3
- package/lib/MWaterGlobalFiltersComponent.d.ts +6 -5
- package/lib/MWaterGlobalFiltersComponent.js +4 -4
- package/lib/MWaterLoaderComponent.d.ts +12 -2
- package/lib/MWaterLoaderComponent.js +9 -1
- package/lib/axes/Axis.d.ts +20 -25
- package/lib/axes/AxisBuilder.js +9 -7
- package/lib/axes/AxisComponent.d.ts +4 -4
- package/lib/dashboards/DashboardComponent.d.ts +0 -5
- package/lib/dashboards/DashboardComponent.js +2 -29
- package/lib/dashboards/DashboardDesign.d.ts +2 -17
- package/lib/dashboards/DashboardViewComponent.js +3 -4
- package/lib/dashboards/LayoutOptionsComponent.js +4 -3
- package/lib/dashboards/SettingsModalComponent.d.ts +4 -15
- package/lib/dashboards/SettingsModalComponent.js +24 -38
- package/lib/datagrids/DatagridComponent.d.ts +2 -9
- package/lib/datagrids/DatagridDataSource.d.ts +3 -3
- package/lib/datagrids/DatagridDataSource.js +0 -14
- package/lib/datagrids/DatagridDesignerComponent.d.ts +2 -93
- package/lib/datagrids/DatagridDesignerComponent.js +8 -6
- package/lib/datagrids/DatagridViewComponent.js +1 -1
- package/lib/datagrids/FindReplaceModalComponent.d.ts +4 -20
- package/lib/datagrids/FindReplaceModalComponent.js +27 -13
- package/lib/datagrids/ServerDatagridDataSource.d.ts +1 -1
- package/lib/datagrids/ServerDatagridDataSource.js +1 -3
- package/lib/demo.js +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/layouts/blocks/BlocksDisplayComponent.d.ts +2 -1
- package/lib/layouts/grid/GridLayoutManager.d.ts +2 -1
- package/lib/maps/BufferLayer.js +3 -1
- package/lib/maps/ClusterLayer.js +3 -1
- package/lib/maps/GridLayer.js +5 -3
- package/lib/maps/GridLayerDesigner.js +0 -1
- package/lib/maps/LayerSwitcherComponent.js +1 -1
- package/lib/maps/MapComponent.d.ts +2 -7
- package/lib/maps/MapDesign.d.ts +2 -13
- package/lib/maps/MapFiltersDesignerComponent.d.ts +0 -4
- package/lib/maps/MapFiltersDesignerComponent.js +4 -5
- package/lib/maps/RasterMapViewComponent.d.ts +2 -9
- package/lib/maps/RegionSelectComponent.d.ts +2 -1
- package/lib/maps/ServerMapDataSource.d.ts +1 -1
- package/lib/maps/vectorMaps.d.ts +1 -0
- package/lib/maps/vectorMaps.js +10 -2
- package/lib/quickfilter/QuickfilterCompiler.d.ts +1 -1
- package/lib/widgets/IFrameWidgetComponent.d.ts +2 -9
- package/lib/widgets/ImageWidgetComponent.d.ts +6 -24
- package/lib/widgets/MapWidget.d.ts +2 -7
- package/lib/widgets/MarkdownWidget.d.ts +2 -7
- package/lib/widgets/TOCWidget.d.ts +2 -9
- package/lib/widgets/charts/ChartWidget.d.ts +3 -15
- package/lib/widgets/charts/imagemosaic/ImagePopupComponent.d.ts +2 -7
- package/lib/widgets/charts/layered/LayeredChartDesignerComponent.d.ts +2 -31
- package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.d.ts +2 -7
- package/lib/widgets/charts/pivot/IntersectionDesignerComponent.d.ts +73 -66
- package/lib/widgets/charts/pivot/PivotChartDesignerComponent.d.ts +10 -6
- package/lib/widgets/charts/pivot/PivotChartViewComponent.d.ts +3 -22
- package/lib/widgets/charts/pivot/SegmentDesignerComponent.d.ts +55 -58
- package/lib/widgets/charts/table/TableChartViewComponent.js +21 -7
- package/lib/widgets/text/ExprInsertModalComponent.d.ts +2 -13
- package/lib/widgets/text/ExprUpdateModalComponent.d.ts +2 -13
- package/lib/widgets/text/TextWidgetDesign.d.ts +3 -1
- package/package.json +1 -1
- package/src/GlobalFilter.ts +17 -0
- package/src/MWaterContextComponent.tsx +37 -19
- package/src/MWaterCustomTablesetListComponent.tsx +21 -3
- package/src/MWaterGlobalFiltersComponent.ts +8 -8
- package/src/MWaterLoaderComponent.ts +8 -1
- package/src/axes/Axis.ts +24 -25
- package/src/axes/AxisBuilder.ts +9 -8
- package/src/dashboards/DashboardComponent.tsx +2 -40
- package/src/dashboards/DashboardDesign.ts +2 -22
- package/src/dashboards/DashboardViewComponent.ts +4 -5
- package/src/dashboards/LayoutOptionsComponent.tsx +6 -4
- package/src/dashboards/SettingsModalComponent.tsx +170 -0
- package/src/datagrids/DatagridDataSource.ts +6 -12
- package/src/datagrids/DatagridDesignerComponent.tsx +22 -18
- package/src/datagrids/DatagridViewComponent.ts +3 -3
- package/src/datagrids/ExprCellComponent.ts +0 -1
- package/src/datagrids/FindReplaceModalComponent.ts +39 -22
- package/src/datagrids/ServerDatagridDataSource.ts +1 -2
- package/src/demo.ts +1 -1
- package/src/index.ts +1 -0
- package/src/maps/BufferLayer.ts +3 -1
- package/src/maps/ClusterLayer.ts +3 -1
- package/src/maps/GridLayer.ts +5 -3
- package/src/maps/GridLayerDesigner.tsx +0 -1
- package/src/maps/LayerSwitcherComponent.tsx +1 -1
- package/src/maps/MapDesign.ts +2 -17
- package/src/maps/{MapFiltersDesignerComponent.ts → MapFiltersDesignerComponent.tsx} +25 -25
- package/src/maps/ServerMapDataSource.ts +1 -1
- package/src/maps/VectorMapViewComponent.tsx +0 -1
- package/src/maps/vectorMaps.tsx +10 -1
- package/src/quickfilter/QuickfilterCompiler.ts +1 -1
- package/src/widgets/charts/table/TableChartViewComponent.ts +21 -7
- package/src/widgets/text/TextWidgetDesign.ts +4 -1
- 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:
|
|
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 = {
|
|
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(
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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 =
|
|
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
|
-
|
|
248
|
+
column => !column.subtable && exprUtils.getExprAggrStatus(column.expr) === "individual"
|
|
232
249
|
)
|
|
233
|
-
const replaceColumnOptions = _.map(replaceColumns,
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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 + "
|
|
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"
|
package/src/maps/BufferLayer.ts
CHANGED
|
@@ -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
|
|
package/src/maps/ClusterLayer.ts
CHANGED
|
@@ -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
|
|
package/src/maps/GridLayer.ts
CHANGED
|
@@ -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 (
|
|
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(
|
|
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 {
|
|
@@ -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
|
)
|
package/src/maps/MapDesign.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { Expr
|
|
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 {
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
}
|
package/src/maps/vectorMaps.tsx
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
281
|
+
if (_.isArray(value)) {
|
|
282
|
+
node = exprUtils.stringifyExprLiteral(column.textAxis?.expr, value, this.context.locale)
|
|
283
|
+
}
|
|
278
284
|
break
|
|
279
285
|
case "date":
|
|
280
|
-
|
|
286
|
+
if (_.isString(value)) {
|
|
287
|
+
node = formatValue(exprType, value, column.format)
|
|
288
|
+
}
|
|
281
289
|
break
|
|
282
290
|
case "datetime":
|
|
283
|
-
|
|
291
|
+
if (_.isString(value)) {
|
|
292
|
+
node = formatValue(exprType, value, column.format)
|
|
293
|
+
}
|
|
284
294
|
break
|
|
285
295
|
case "image":
|
|
286
|
-
|
|
296
|
+
if (_.isObject(value) && value.id != null) {
|
|
297
|
+
node = this.renderImage(value.id)
|
|
298
|
+
}
|
|
287
299
|
break
|
|
288
300
|
case "imagelist":
|
|
289
|
-
|
|
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:
|
|
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
|
-
}
|