@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
package/src/axes/Axis.ts
CHANGED
|
@@ -5,37 +5,19 @@ import { Expr } from "@mwater/expressions"
|
|
|
5
5
|
An axis is an expression with optional aggregation, transform and color mapping
|
|
6
6
|
In ggplot2 parlance, an "aesthetic"
|
|
7
7
|
|
|
8
|
-
It contains:
|
|
9
|
-
expr: expression
|
|
10
|
-
aggr: DEPRECATED: optional aggregation (e.g. sum)
|
|
11
|
-
xform: optional transformation to be applied. object with `type` field. See below
|
|
12
|
-
colorMap: optional array of color mappings. See below
|
|
13
|
-
excludedValues: Array of post-xform values to exclude when displaying.
|
|
14
|
-
format: optional d3-format format for numeric values. Default if null is ","
|
|
15
|
-
|
|
16
|
-
## Xforms
|
|
17
|
-
|
|
18
|
-
types:
|
|
19
|
-
|
|
20
|
-
|
|
21
8
|
*/
|
|
22
9
|
export interface Axis {
|
|
10
|
+
/** Expression to be displayed on axis */
|
|
23
11
|
expr: Expr
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
*
|
|
27
|
-
* `year`: year only e.g. `2015-01-01`. type date
|
|
28
|
-
* `yearmonth`: year and month only e.g. `2015-02-01`. type date
|
|
29
|
-
* `yearquarter`: year and quarter only e.g. `2015-01`. type enum
|
|
30
|
-
* `yearweek`: year and week (ISO) only e.g. `2015-31`. type enum
|
|
31
|
-
* `month`: month only e.g. `02`. type enum
|
|
32
|
-
* `week`: ISO week of year e.g. `01` for the first week that contains January 4th
|
|
33
|
-
* `ranges`: convert to ranges. type enum. `ranges` is array of { id (unique id), label (optional label), minValue (null for none), maxValue (null for none), minOpen (true for >, false for >=), maxOpen (true for <, false for <=) }
|
|
34
|
-
* `floor`: convert to floor. type enum
|
|
12
|
+
|
|
13
|
+
/** Optional transformation to be applied. If a date is used, for example, it's generally
|
|
14
|
+
* better to use a transform to convert to a year or month rather than creating an expression.
|
|
35
15
|
*/
|
|
36
16
|
xform?: AxisXform
|
|
37
17
|
|
|
18
|
+
/** optional array of color mappings */
|
|
38
19
|
colorMap?: ColorMap
|
|
20
|
+
|
|
39
21
|
/** optional array of category values which define the order in which categories should be rendered */
|
|
40
22
|
drawOrder?: any[]
|
|
41
23
|
|
|
@@ -45,12 +27,16 @@ export interface Axis {
|
|
|
45
27
|
/** optional string for null category */
|
|
46
28
|
nullLabel?: string
|
|
47
29
|
|
|
30
|
+
/** Array of post-xform values to exclude when displaying. */
|
|
48
31
|
excludedValues?: any[]
|
|
32
|
+
|
|
33
|
+
/** optional d3-format format for numeric values. Default if null is "," */
|
|
49
34
|
format?: string
|
|
50
35
|
|
|
51
|
-
/** @deprecated */
|
|
36
|
+
/** @deprecated optional aggregation (e.g. sum) */
|
|
52
37
|
aggr?: string
|
|
53
38
|
}
|
|
39
|
+
|
|
54
40
|
/**
|
|
55
41
|
* Color map
|
|
56
42
|
* Array of { value: post-transform value of expression, color: html color }
|
|
@@ -70,6 +56,19 @@ export interface AxisCategory {
|
|
|
70
56
|
}
|
|
71
57
|
|
|
72
58
|
export interface AxisXform {
|
|
59
|
+
/**
|
|
60
|
+
* Type of transformation
|
|
61
|
+
* `bin`: convert into bins. always has `numBins` integer and `min` and `max`. Can have `excludeUpper` and/or `excludeLower` to remove open bin on top or bottem. type enum
|
|
62
|
+
* `date`: convert to complete date e.g. `2015-02-08`. type date
|
|
63
|
+
* `year`: year only e.g. `2015-01-01`. type date
|
|
64
|
+
* `yearmonth`: year and month only e.g. `2015-02-01`. type date
|
|
65
|
+
* `yearquarter`: year and quarter only e.g. `2015-01`. type enum
|
|
66
|
+
* `yearweek`: year and week (ISO) only e.g. `2015-31`. type enum
|
|
67
|
+
* `month`: month only e.g. `02`. type enum
|
|
68
|
+
* `week`: ISO week of year e.g. `01` for the first week that contains January 4th
|
|
69
|
+
* `ranges`: convert to ranges. type enum. `ranges` is array of { id (unique id), label (optional label), minValue (null for none), maxValue (null for none), minOpen (true for >, false for >=), maxOpen (true for <, false for <=) }
|
|
70
|
+
* `floor`: convert to floor. type enum
|
|
71
|
+
*/
|
|
73
72
|
type: "bin" | "date" | "year" | "yearmonth" | "month" | "week" | "ranges" | "yearweek" | "yearquarter" | "floor"
|
|
74
73
|
numBins?: number
|
|
75
74
|
min?: number
|
package/src/axes/AxisBuilder.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { default as produce } from "immer"
|
|
|
12
12
|
import { formatValue } from "../valueFormatter"
|
|
13
13
|
import { Axis, AxisCategory } from "./Axis"
|
|
14
14
|
import { JsonQLExpr, JsonQLSelectQuery } from "@mwater/jsonql"
|
|
15
|
+
import dayjs from '../dayjs'
|
|
15
16
|
|
|
16
17
|
const xforms: { type: string; input: LiteralType; output: LiteralType }[] = [
|
|
17
18
|
{ type: "bin", input: "number", output: "enum" },
|
|
@@ -913,10 +914,9 @@ export default class AxisBuilder {
|
|
|
913
914
|
if (values.length === 0) {
|
|
914
915
|
return [noneCategory]
|
|
915
916
|
}
|
|
916
|
-
|
|
917
917
|
if (options.onlyValuesPresent) {
|
|
918
918
|
// Sort and take only present
|
|
919
|
-
categories = _.sortBy(_.uniq(values), item => item).map(value => ({ value, label:
|
|
919
|
+
categories = _.sortBy(_.uniq(values), item => item).map(value => ({ value, label: formatValue("date", value, axis.format)}))
|
|
920
920
|
|
|
921
921
|
if (hasNone) {
|
|
922
922
|
categories.push(noneCategory)
|
|
@@ -930,12 +930,12 @@ export default class AxisBuilder {
|
|
|
930
930
|
max = values.sort().slice(-1)[0]
|
|
931
931
|
|
|
932
932
|
// Use moment to get range
|
|
933
|
-
current =
|
|
934
|
-
end =
|
|
933
|
+
current = dayjs(min)
|
|
934
|
+
end = dayjs(max)
|
|
935
935
|
categories = []
|
|
936
936
|
while (!current.isAfter(end)) {
|
|
937
|
-
categories.push({ value: current.format("YYYY-MM-DD"), label: current.format("ll") })
|
|
938
|
-
current.add(1, "days")
|
|
937
|
+
categories.push({ value: current.format("YYYY-MM-DD"), label: current.format(axis.format ?? "ll") })
|
|
938
|
+
current = current.add(1, "days")
|
|
939
939
|
if (categories.length >= 1000) {
|
|
940
940
|
break
|
|
941
941
|
}
|
|
@@ -1055,9 +1055,10 @@ export default class AxisBuilder {
|
|
|
1055
1055
|
_.map(value as string[], (v, i) => R("div", { key: i }, v))
|
|
1056
1056
|
)
|
|
1057
1057
|
case "date":
|
|
1058
|
-
|
|
1058
|
+
console.log(axis)
|
|
1059
|
+
return formatValue(type, value, axis.format)
|
|
1059
1060
|
case "datetime":
|
|
1060
|
-
return
|
|
1061
|
+
return formatValue(type, value, axis.format)
|
|
1061
1062
|
}
|
|
1062
1063
|
|
|
1063
1064
|
return "" + value
|
|
@@ -237,45 +237,6 @@ export default class DashboardComponent extends React.Component<DashboardCompone
|
|
|
237
237
|
)
|
|
238
238
|
}
|
|
239
239
|
|
|
240
|
-
renderStyleItem(style: any) {
|
|
241
|
-
const isActive = (this.props.design.style || "default") === style
|
|
242
|
-
|
|
243
|
-
const content = (() => {
|
|
244
|
-
switch (style) {
|
|
245
|
-
case "default":
|
|
246
|
-
return [
|
|
247
|
-
R("h4", { key: "name", className: "list-group-item-heading" }, "Classic Dashboard"),
|
|
248
|
-
R("p", { key: "description", className: "" }, "Ideal for data display with minimal text")
|
|
249
|
-
]
|
|
250
|
-
case "greybg":
|
|
251
|
-
return [
|
|
252
|
-
R("h4", { key: "name", className: "list-group-item-heading" }, "Framed Dashboard"),
|
|
253
|
-
R("p", { key: "description", className: "" }, "Each widget is white on a grey background")
|
|
254
|
-
]
|
|
255
|
-
case "story":
|
|
256
|
-
return [
|
|
257
|
-
R("h4", { key: "name", className: "list-group-item-heading" }, "Story"),
|
|
258
|
-
R(
|
|
259
|
-
"p",
|
|
260
|
-
{ key: "description", className: "" },
|
|
261
|
-
"Ideal for data-driven storytelling with lots of text. Responsive and mobile-friendly"
|
|
262
|
-
)
|
|
263
|
-
]
|
|
264
|
-
}
|
|
265
|
-
return null
|
|
266
|
-
})()
|
|
267
|
-
|
|
268
|
-
return R(
|
|
269
|
-
"a",
|
|
270
|
-
{
|
|
271
|
-
key: style,
|
|
272
|
-
className: `list-group-item ${isActive ? "active" : ""}`,
|
|
273
|
-
onClick: this.handleStyleChange.bind(null, style)
|
|
274
|
-
},
|
|
275
|
-
content
|
|
276
|
-
)
|
|
277
|
-
}
|
|
278
|
-
|
|
279
240
|
renderStyle() {
|
|
280
241
|
return R(
|
|
281
242
|
"button",
|
|
@@ -379,7 +340,8 @@ export default class DashboardComponent extends React.Component<DashboardCompone
|
|
|
379
340
|
locks: this.props.quickfilterLocks,
|
|
380
341
|
filters: this.getCompiledFilters(),
|
|
381
342
|
hideTopBorder: this.props.hideTitleBar,
|
|
382
|
-
|
|
343
|
+
// Don't hide if title bar is hidden as it can't be shown again
|
|
344
|
+
onHide: () => !this.props.hideTitleBar ? this.setState({ hideQuickfilters: true }) : undefined
|
|
383
345
|
})
|
|
384
346
|
}
|
|
385
347
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { JsonQLFilter } from "../JsonQLFilter"
|
|
2
1
|
import { Quickfilter } from "../quickfilter/Quickfilter"
|
|
3
|
-
import {
|
|
2
|
+
import { Expr } from "@mwater/expressions"
|
|
4
3
|
import { BlocksLayoutOptions, DashboardTheme } from "./layoutOptions"
|
|
4
|
+
import { GlobalFilter } from "../GlobalFilter"
|
|
5
5
|
|
|
6
6
|
/** Dashboard design
|
|
7
7
|
* Each understands enough of the dashboard design to create widgets.
|
|
@@ -35,23 +35,3 @@ export interface DashboardDesign {
|
|
|
35
35
|
/** array of global filters. See below. */
|
|
36
36
|
globalFilters?: GlobalFilter[]
|
|
37
37
|
}
|
|
38
|
-
|
|
39
|
-
/** Global Filters:
|
|
40
|
-
|
|
41
|
-
Global filters apply to multiple tables at once if a certain column is present. User-interface to set them is application-specific
|
|
42
|
-
and the default (non-mWater) dashboard applies them but does not allow editing.
|
|
43
|
-
|
|
44
|
-
*/
|
|
45
|
-
export interface GlobalFilter {
|
|
46
|
-
/** id of column to filter */
|
|
47
|
-
columnId: string
|
|
48
|
-
|
|
49
|
-
/** type of column to filter (to ensure that consistent) */
|
|
50
|
-
columnType: LiteralType
|
|
51
|
-
|
|
52
|
-
/** op of expression for filtering */
|
|
53
|
-
op: string
|
|
54
|
-
|
|
55
|
-
/** array of expressions to use for filtering. field expression for column will be injected as expression 0 in the resulting filter expression */
|
|
56
|
-
exprs: Expr[]
|
|
57
|
-
}
|
|
@@ -14,7 +14,7 @@ import WidgetScopesViewComponent from "../widgets/WidgetScopesViewComponent"
|
|
|
14
14
|
import { getLayoutOptions } from "./layoutOptions"
|
|
15
15
|
import { WidgetComponent } from "./WidgetComponent"
|
|
16
16
|
import { DashboardDataSource, DashboardDesign, JsonQLFilter } from ".."
|
|
17
|
-
import {
|
|
17
|
+
import { setPrintingModeEnabled } from "../maps/vectorMaps"
|
|
18
18
|
|
|
19
19
|
export interface DashboardViewComponentProps {
|
|
20
20
|
/** schema to use */
|
|
@@ -147,10 +147,9 @@ export default class DashboardViewComponent extends React.Component<
|
|
|
147
147
|
|
|
148
148
|
// Call to print the dashboard
|
|
149
149
|
print = async () => {
|
|
150
|
-
// Temporarily
|
|
151
|
-
const mapTilerAPIKey = getMapTilerApiKey()
|
|
150
|
+
// Temporarily enable print mode for vector maps
|
|
152
151
|
try {
|
|
153
|
-
|
|
152
|
+
setPrintingModeEnabled(true)
|
|
154
153
|
|
|
155
154
|
// Create element at 1080 wide (use as standard printing width)
|
|
156
155
|
const elem = R(
|
|
@@ -162,7 +161,7 @@ export default class DashboardViewComponent extends React.Component<
|
|
|
162
161
|
const printer = new ReactElementPrinter()
|
|
163
162
|
await printer.print(elem, { delay: 5000 })
|
|
164
163
|
} finally {
|
|
165
|
-
|
|
164
|
+
setPrintingModeEnabled(false)
|
|
166
165
|
}
|
|
167
166
|
}
|
|
168
167
|
|
|
@@ -137,7 +137,7 @@ export function LayoutOptionsComponent(props: {
|
|
|
137
137
|
<div style={{ height: "100%", display: "grid", gridTemplateRows: "auto 1fr" }}>
|
|
138
138
|
<div key="quickfilters">
|
|
139
139
|
{layoutOptions.hideQuickfiltersWidth == null ||
|
|
140
|
-
|
|
140
|
+
sizeOptions[previewSize].value.width > layoutOptions.hideQuickfiltersWidth
|
|
141
141
|
? props.quickfiltersView
|
|
142
142
|
: null}
|
|
143
143
|
</div>
|
|
@@ -196,9 +196,11 @@ function ThemeToggle(props: { theme?: DashboardTheme; onChange: (theme: Dashboar
|
|
|
196
196
|
|
|
197
197
|
return (
|
|
198
198
|
<FormGroup label="Theme">
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
199
|
+
<div className="list-group">
|
|
200
|
+
{renderStyleItem("default")}
|
|
201
|
+
{renderStyleItem("greybg")}
|
|
202
|
+
{renderStyleItem("story")}
|
|
203
|
+
</div>
|
|
202
204
|
</FormGroup>
|
|
203
205
|
)
|
|
204
206
|
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import _ from "lodash"
|
|
2
|
+
import React from "react"
|
|
3
|
+
const R = React.createElement
|
|
4
|
+
import update from "update-object"
|
|
5
|
+
import { languages } from "../languages"
|
|
6
|
+
import * as ui from "@mwater/react-library/lib/bootstrap"
|
|
7
|
+
import { default as ReactSelect } from "react-select"
|
|
8
|
+
import * as DashboardUtils from "./DashboardUtils"
|
|
9
|
+
import ActionCancelModalComponent from "@mwater/react-library/lib/ActionCancelModalComponent"
|
|
10
|
+
import QuickfiltersDesignComponent from "../quickfilter/QuickfiltersDesignComponent"
|
|
11
|
+
import FiltersDesignerComponent from "../FiltersDesignerComponent"
|
|
12
|
+
import { DataSource, Schema } from "@mwater/expressions"
|
|
13
|
+
import { DashboardDesign } from "./DashboardDesign"
|
|
14
|
+
import { GlobalFiltersElementFactoryContext } from "../MWaterContextComponent"
|
|
15
|
+
|
|
16
|
+
export interface SettingsModalComponentProps {
|
|
17
|
+
onDesignChange: any
|
|
18
|
+
schema: Schema
|
|
19
|
+
dataSource: DataSource
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface SettingsModalComponentState {
|
|
23
|
+
design: DashboardDesign | null
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Popup with settings for dashboard
|
|
27
|
+
export default class SettingsModalComponent extends React.Component<
|
|
28
|
+
SettingsModalComponentProps,
|
|
29
|
+
SettingsModalComponentState
|
|
30
|
+
> {
|
|
31
|
+
constructor(props: SettingsModalComponentProps) {
|
|
32
|
+
super(props)
|
|
33
|
+
this.state = {
|
|
34
|
+
design: null // Set when being edited
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
show(design: any) {
|
|
39
|
+
return this.setState({ design })
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
handleSave = () => {
|
|
43
|
+
this.props.onDesignChange(this.state.design)
|
|
44
|
+
return this.setState({ design: null })
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
handleCancel = () => {
|
|
48
|
+
return this.setState({ design: null })
|
|
49
|
+
}
|
|
50
|
+
handleDesignChange = (design: any) => {
|
|
51
|
+
return this.setState({ design })
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
handleFiltersChange = (filters: any) => {
|
|
55
|
+
const design = _.extend({}, this.state.design, { filters })
|
|
56
|
+
return this.handleDesignChange(design)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
handleGlobalFiltersChange = (globalFilters: any) => {
|
|
60
|
+
const design = _.extend({}, this.state.design, { globalFilters })
|
|
61
|
+
return this.handleDesignChange(design)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
render() {
|
|
65
|
+
// Don't show if not editing
|
|
66
|
+
if (!this.state.design) {
|
|
67
|
+
return null
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Get filterable tables
|
|
71
|
+
const filterableTables = DashboardUtils.getFilterableTables(this.state.design, this.props.schema)
|
|
72
|
+
|
|
73
|
+
const localeOptions = _.map(languages, (language) => {
|
|
74
|
+
return {
|
|
75
|
+
value: language.code,
|
|
76
|
+
label: language.en + " (" + language.name + ")"
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<ActionCancelModalComponent
|
|
82
|
+
size="large"
|
|
83
|
+
onCancel={this.handleCancel}
|
|
84
|
+
onAction={this.handleSave}
|
|
85
|
+
>
|
|
86
|
+
<div style={{ paddingBottom: 200 }}>
|
|
87
|
+
<h4>Quick Filters</h4>
|
|
88
|
+
<div className="text-muted">
|
|
89
|
+
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.
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
{filterableTables.length > 0 ? (
|
|
93
|
+
<QuickfiltersDesignComponent
|
|
94
|
+
design={this.state.design.quickfilters || []}
|
|
95
|
+
onDesignChange={(design: any) =>
|
|
96
|
+
this.handleDesignChange(update(this.state.design, { quickfilters: { $set: design } }))
|
|
97
|
+
}
|
|
98
|
+
schema={this.props.schema}
|
|
99
|
+
dataSource={this.props.dataSource}
|
|
100
|
+
tables={filterableTables}
|
|
101
|
+
/>
|
|
102
|
+
) : (
|
|
103
|
+
"Nothing to quickfilter. Add widgets to the dashboard"
|
|
104
|
+
)}
|
|
105
|
+
|
|
106
|
+
<h4 style={{ paddingTop: 10 }}>Filters</h4>
|
|
107
|
+
<div className="text-muted">
|
|
108
|
+
Filters are built in to the dashboard and cannot be changed by viewers of the dashboard.
|
|
109
|
+
</div>
|
|
110
|
+
|
|
111
|
+
{filterableTables.length > 0 ? (
|
|
112
|
+
<FiltersDesignerComponent
|
|
113
|
+
schema={this.props.schema}
|
|
114
|
+
dataSource={this.props.dataSource}
|
|
115
|
+
filters={this.state.design.filters}
|
|
116
|
+
onFiltersChange={this.handleFiltersChange}
|
|
117
|
+
filterableTables={filterableTables}
|
|
118
|
+
/>
|
|
119
|
+
) : (
|
|
120
|
+
"Nothing to filter. Add widgets to the dashboard"
|
|
121
|
+
)}
|
|
122
|
+
|
|
123
|
+
<GlobalFiltersElementFactoryContext.Consumer>
|
|
124
|
+
{globalFiltersElementFactory =>
|
|
125
|
+
globalFiltersElementFactory ? (
|
|
126
|
+
<div>
|
|
127
|
+
<h4 style={{ paddingTop: 10 }}>Global Filters</h4>
|
|
128
|
+
{globalFiltersElementFactory({
|
|
129
|
+
schema: this.props.schema,
|
|
130
|
+
dataSource: this.props.dataSource,
|
|
131
|
+
filterableTables,
|
|
132
|
+
globalFilters: this.state.design!.globalFilters || [],
|
|
133
|
+
onChange: this.handleGlobalFiltersChange
|
|
134
|
+
})}
|
|
135
|
+
</div>
|
|
136
|
+
) : undefined
|
|
137
|
+
}
|
|
138
|
+
</GlobalFiltersElementFactoryContext.Consumer>
|
|
139
|
+
|
|
140
|
+
<h4 style={{ paddingTop: 10 }}>Language</h4>
|
|
141
|
+
<div className="text-muted">
|
|
142
|
+
Controls the preferred language of widgets and uses specified language when available
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<ReactSelect
|
|
146
|
+
value={_.findWhere(localeOptions, { value: this.state.design.locale || "en" }) || null}
|
|
147
|
+
options={localeOptions}
|
|
148
|
+
onChange={(locale: any) =>
|
|
149
|
+
this.handleDesignChange(update(this.state.design, { locale: { $set: locale.value } }))
|
|
150
|
+
}
|
|
151
|
+
/>
|
|
152
|
+
|
|
153
|
+
{this.state.design.implicitFiltersEnabled && (
|
|
154
|
+
<>
|
|
155
|
+
<h4 style={{ paddingTop: 10 }}>Advanced</h4>
|
|
156
|
+
<ui.Checkbox
|
|
157
|
+
value={this.state.design.implicitFiltersEnabled != null ? this.state.design.implicitFiltersEnabled : true}
|
|
158
|
+
onChange={(value: boolean) =>
|
|
159
|
+
this.handleDesignChange(update(this.state.design, { implicitFiltersEnabled: { $set: value } }))
|
|
160
|
+
}
|
|
161
|
+
>
|
|
162
|
+
Enable Implicit Filtering (leave unchecked for new dashboards)
|
|
163
|
+
</ui.Checkbox>
|
|
164
|
+
</>
|
|
165
|
+
)}
|
|
166
|
+
</div>
|
|
167
|
+
</ActionCancelModalComponent>
|
|
168
|
+
)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
@@ -2,28 +2,22 @@ import { Row } from "@mwater/expressions"
|
|
|
2
2
|
import { DatagridDesign, JsonQLFilter } from ".."
|
|
3
3
|
import { QuickfiltersDataSource } from "../quickfilter/QuickfiltersDataSource"
|
|
4
4
|
|
|
5
|
-
export default
|
|
5
|
+
export default interface DatagridDataSource {
|
|
6
6
|
/** Gets the rows specified */
|
|
7
7
|
getRows(
|
|
8
8
|
design: DatagridDesign,
|
|
9
9
|
offset: number,
|
|
10
10
|
limit: number,
|
|
11
11
|
filters: JsonQLFilter[] | undefined,
|
|
12
|
-
callback: (error: any, rows
|
|
13
|
-
): void
|
|
14
|
-
throw new Error("Not implemented")
|
|
15
|
-
}
|
|
12
|
+
callback: (error: any, rows?: Row[]) => void
|
|
13
|
+
): void
|
|
16
14
|
|
|
17
15
|
countRows(
|
|
18
16
|
design: DatagridDesign,
|
|
19
17
|
filters: JsonQLFilter[] | undefined,
|
|
20
|
-
callback: (error: any, numRows
|
|
21
|
-
): void
|
|
22
|
-
throw new Error("Not implemented")
|
|
23
|
-
}
|
|
18
|
+
callback: (error: any, numRows?: number) => void
|
|
19
|
+
): void
|
|
24
20
|
|
|
25
21
|
/** Gets the quickfilters data source */
|
|
26
|
-
getQuickfiltersDataSource(): QuickfiltersDataSource
|
|
27
|
-
throw new Error("Not implemented")
|
|
28
|
-
}
|
|
22
|
+
getQuickfiltersDataSource(): QuickfiltersDataSource
|
|
29
23
|
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import PropTypes from "prop-types"
|
|
2
1
|
import _ from "lodash"
|
|
3
2
|
import React, { useMemo } from "react"
|
|
4
3
|
const R = React.createElement
|
|
@@ -22,6 +21,7 @@ import { getFormatOptions } from "../valueFormatter"
|
|
|
22
21
|
import { getDefaultFormat } from "../valueFormatter"
|
|
23
22
|
import { DatagridDesignColumn } from "./DatagridDesign"
|
|
24
23
|
import { DatagridDesign } from ".."
|
|
24
|
+
import { GlobalFiltersElementFactoryContext } from "../MWaterContextComponent"
|
|
25
25
|
|
|
26
26
|
export interface DatagridDesignerComponentProps {
|
|
27
27
|
/** schema to use */
|
|
@@ -36,8 +36,6 @@ export interface DatagridDesignerComponentProps {
|
|
|
36
36
|
|
|
37
37
|
// Designer for the datagrid. Currenly allows only single-table designs (no subtable rows)
|
|
38
38
|
export default class DatagridDesignerComponent extends React.Component<DatagridDesignerComponentProps> {
|
|
39
|
-
static contextTypes = { globalFiltersElementFactory: PropTypes.func }
|
|
40
|
-
|
|
41
39
|
handleTableChange = (table: any) => {
|
|
42
40
|
const design = {
|
|
43
41
|
table,
|
|
@@ -93,20 +91,24 @@ export default class DatagridDesignerComponent extends React.Component<DatagridD
|
|
|
93
91
|
value: this.props.design.filter,
|
|
94
92
|
onChange: this.handleFilterChange
|
|
95
93
|
}),
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
94
|
+
<GlobalFiltersElementFactoryContext.Consumer>
|
|
95
|
+
{(globalFiltersElementFactory) =>
|
|
96
|
+
globalFiltersElementFactory
|
|
97
|
+
? R(
|
|
98
|
+
"div",
|
|
99
|
+
{ style: { marginTop: 20 } },
|
|
100
|
+
globalFiltersElementFactory({
|
|
101
|
+
schema: this.props.schema,
|
|
102
|
+
dataSource: this.props.dataSource,
|
|
103
|
+
filterableTables: [this.props.design.table!],
|
|
104
|
+
globalFilters: this.props.design.globalFilters,
|
|
105
|
+
onChange: this.handleGlobalFiltersChange,
|
|
106
|
+
nullIfIrrelevant: true
|
|
107
|
+
})
|
|
108
|
+
)
|
|
109
|
+
: undefined
|
|
110
|
+
}
|
|
111
|
+
</GlobalFiltersElementFactoryContext.Consumer>
|
|
110
112
|
)
|
|
111
113
|
},
|
|
112
114
|
{
|
|
@@ -562,7 +564,9 @@ class ColumnDesignerComponent extends React.Component<ColumnDesignerComponentPro
|
|
|
562
564
|
}),
|
|
563
565
|
this.renderSplit(),
|
|
564
566
|
this.renderFormat(),
|
|
565
|
-
error ?
|
|
567
|
+
error ? <span className="text-danger">
|
|
568
|
+
<i className="fa fa-exclamation-circle" /> {error}
|
|
569
|
+
</span> : undefined
|
|
566
570
|
),
|
|
567
571
|
|
|
568
572
|
R(
|
|
@@ -191,8 +191,8 @@ export default class DatagridViewComponent extends React.Component<
|
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
const newRows = produce(this.state.rows, draft => {
|
|
194
|
-
if (rows[0]) {
|
|
195
|
-
draft[rowIndex] = rows[0]
|
|
194
|
+
if (rows![0]) {
|
|
195
|
+
draft[rowIndex] = rows![0]
|
|
196
196
|
}
|
|
197
197
|
else {
|
|
198
198
|
// If row missing, remove it from list
|
|
@@ -308,7 +308,7 @@ export default class DatagridViewComponent extends React.Component<
|
|
|
308
308
|
}
|
|
309
309
|
|
|
310
310
|
handleRowDoubleClick = (ev: any, rowIndex: any) => {
|
|
311
|
-
if (this.props.onRowDoubleClick != null && this.state.rows[rowIndex]
|
|
311
|
+
if (this.props.onRowDoubleClick != null && this.state.rows[rowIndex]?.id) {
|
|
312
312
|
this.props.onRowDoubleClick(this.props.design.table!, this.state.rows[rowIndex].id, rowIndex)
|
|
313
313
|
}
|
|
314
314
|
}
|