@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.
- package/lib/MWaterAddRelatedFormComponent.d.ts +1 -1
- package/lib/MWaterAddRelatedFormComponent.js +10 -17
- package/lib/MWaterContextComponent.d.ts +17 -7
- package/lib/MWaterContextComponent.js +51 -67
- package/lib/MWaterLoaderComponent.d.ts +2 -2
- package/lib/MWaterLoaderComponent.js +1 -1
- package/lib/MWaterTableSelectComponent.d.ts +0 -1
- package/lib/MWaterTableSelectComponent.js +20 -41
- package/lib/axes/RangesComponent.d.ts +12 -6
- package/lib/axes/RangesComponent.js +21 -10
- package/lib/dashboards/DashboardComponent.d.ts +1 -9
- package/lib/dashboards/DashboardComponent.js +16 -27
- package/lib/dashboards/ServerDashboardDataSource.d.ts +1 -0
- package/lib/dashboards/ServerDashboardDataSource.js +3 -0
- package/lib/datagrids/DatagridComponent.d.ts +8 -4
- package/lib/datagrids/DatagridComponent.js +27 -5
- package/lib/datagrids/DatagridDataSource.d.ts +1 -0
- package/lib/datagrids/DatagridDataSource.js +3 -0
- package/lib/datagrids/DatagridDesign.d.ts +2 -0
- package/lib/datagrids/DatagridDesignerComponent.js +3 -2
- package/lib/datagrids/DatagridViewComponent.js +1 -1
- package/lib/datagrids/DirectDatagridDataSource.d.ts +1 -0
- package/lib/datagrids/DirectDatagridDataSource.js +26 -0
- package/lib/datagrids/ServerDatagridDataSource.d.ts +1 -0
- package/lib/datagrids/ServerDatagridDataSource.js +15 -0
- package/lib/index.d.ts +0 -1
- package/lib/index.js +2 -4
- package/lib/layouts/blocks/BlocksDisplayComponent.js +2 -2
- package/lib/layouts/grid/LegoLayoutEngine.d.ts +1 -1
- package/lib/maps/BufferLayerDesignerComponent.js +2 -2
- package/lib/maps/ChoroplethLayerDesigner.js +2 -2
- package/lib/maps/ClusterLayerDesignerComponent.js +2 -2
- package/lib/maps/DirectMapDataSource.js +1 -2
- package/lib/maps/GridLayerDesigner.js +2 -2
- package/lib/maps/MapDesignerComponent.d.ts +1 -12
- package/lib/maps/MapDesignerComponent.js +5 -12
- package/lib/maps/MarkersLayerDesignerComponent.js +2 -2
- package/lib/maps/PopupFilterJoinsUtils.d.ts +6 -1
- package/lib/maps/PopupFilterJoinsUtils.js +4 -3
- package/lib/maps/UtfGridLayer.js +1 -1
- package/lib/widgets/ImageWidgetComponent.js +2 -2
- package/lib/widgets/charts/calendar/CalendarChartDesignerComponent.js +2 -2
- package/lib/widgets/charts/imagemosaic/ImageMosaicChart.d.ts +1 -1
- package/lib/widgets/charts/imagemosaic/ImageMosaicChart.js +1 -1
- package/lib/widgets/charts/imagemosaic/ImageMosaicChartDesignerComponent.js +2 -2
- package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.js +2 -2
- package/lib/widgets/charts/pivot/PivotChartDesignerComponent.js +2 -2
- package/lib/widgets/charts/table/TableChartDesignerComponent.js +2 -2
- package/lib/widgets/text/ExprItemEditorComponent.js +2 -2
- package/package.json +1 -1
- package/src/MWaterAddRelatedFormComponent.ts +15 -20
- package/src/MWaterContextComponent.tsx +140 -0
- package/src/MWaterLoaderComponent.ts +2 -2
- package/src/{MWaterTableSelectComponent.ts → MWaterTableSelectComponent.tsx} +61 -66
- package/src/axes/AxisBuilder.ts +1 -1
- package/src/axes/RangesComponent.ts +27 -16
- package/src/dashboards/{DashboardComponent.ts → DashboardComponent.tsx} +37 -40
- package/src/dashboards/ServerDashboardDataSource.ts +16 -12
- package/src/datagrids/DatagridComponent.ts +45 -14
- package/src/datagrids/DatagridDataSource.ts +8 -0
- package/src/datagrids/DatagridDesign.ts +3 -0
- package/src/datagrids/DatagridDesignerComponent.tsx +9 -1
- package/src/datagrids/DatagridViewComponent.ts +1 -1
- package/src/datagrids/DirectDatagridDataSource.ts +35 -0
- package/src/datagrids/ServerDatagridDataSource.ts +22 -4
- package/src/index.ts +0 -2
- package/src/layouts/blocks/BlocksDisplayComponent.ts +2 -2
- package/src/layouts/grid/LegoLayoutEngine.ts +2 -2
- package/src/layouts/grid/WidgetContainerComponent.ts +2 -2
- package/src/maps/BingLayer.ts +2 -2
- package/src/maps/BufferLayerDesignerComponent.ts +1 -1
- package/src/maps/ChoroplethLayerDesigner.tsx +1 -1
- package/src/maps/ClusterLayerDesignerComponent.ts +1 -1
- package/src/maps/DirectMapDataSource.ts +1 -2
- package/src/maps/GridLayerDesigner.tsx +1 -1
- package/src/maps/LegendGroup.ts +1 -1
- package/src/maps/MWaterServerLayer.ts +2 -2
- package/src/maps/{MapDesignerComponent.ts → MapDesignerComponent.tsx} +8 -16
- package/src/maps/MarkersLayerDesignerComponent.ts +1 -1
- package/src/maps/PopupFilterJoinsUtils.ts +4 -4
- package/src/maps/ServerMapDataSource.ts +6 -6
- package/src/maps/SwitchableTileUrlLayerDesigner.tsx +1 -13
- package/src/maps/UtfGridLayer.ts +4 -4
- package/src/maps/mapboxUtils.ts +2 -2
- package/src/richtext/ExprItemsHtmlConverter.ts +1 -1
- package/src/richtext/FontColorPaletteItem.ts +1 -1
- package/src/richtext/FontSizePaletteItem.ts +1 -1
- package/src/richtext/ItemsHtmlConverter.ts +2 -2
- package/src/widgets/ImageWidgetComponent.ts +1 -1
- package/src/widgets/charts/calendar/CalendarChartDesignerComponent.ts +1 -1
- package/src/widgets/charts/imagemosaic/ImageMosaicChart.ts +1 -1
- package/src/widgets/charts/imagemosaic/ImageMosaicChartDesignerComponent.ts +1 -1
- package/src/widgets/charts/layered/LayeredChartLayerDesignerComponent.tsx +1 -1
- package/src/widgets/charts/pivot/PivotChartDesignerComponent.tsx +1 -1
- package/src/widgets/charts/table/TableChartDesignerComponent.ts +1 -1
- package/src/widgets/text/ExprItemEditorComponent.tsx +1 -1
- package/src/MWaterContextComponent.ts +0 -141
- 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
|
|
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(
|
|
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
|
|
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(
|
|
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
|
@@ -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 {
|
|
13
|
+
import { Form, FormDesign } from "@mwater/forms"
|
|
14
14
|
|
|
15
15
|
export interface MWaterAddRelatedFormComponentProps {
|
|
16
|
-
/** Entities
|
|
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
|
|
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
|
|
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({
|
|
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
|
|
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
|
-
|
|
163
|
-
}).fail((xhr) => {
|
|
164
|
-
|
|
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
|
|
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
|
|
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[] =
|
|
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
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
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
|
}
|
package/src/axes/AxisBuilder.ts
CHANGED
|
@@ -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
|
|
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:
|
|
106
|
-
onChange:
|
|
107
|
-
onRemove:
|
|
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
|
-
|
|
118
|
-
|
|
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
|
-
|
|
122
|
-
|
|
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
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
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
|
}
|