@mwater/visualization 5.4.4 → 5.5.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/.storybook/head.html +0 -1
- package/lib/MWaterContextComponent.js +1 -1
- package/lib/MWaterLoaderComponent.d.ts +2 -2
- package/lib/dashboards/DashboardComponent.js +2 -1
- package/lib/dashboards/LayoutOptionsComponent.js +18 -11
- package/lib/dashboards/ServerDashboardDataSource.d.ts +10 -1
- package/lib/dashboards/ServerDashboardDataSource.js +29 -0
- package/lib/dashboards/layoutOptions.d.ts +5 -1
- package/lib/datagrids/DatagridComponent.js +1 -1
- package/lib/datagrids/ExprCellComponent.d.ts +1 -0
- package/lib/datagrids/ExprCellComponent.js +22 -20
- package/lib/maps/BufferLayer.d.ts +18 -0
- package/lib/maps/BufferLayer.js +24 -14
- package/lib/maps/ChoroplethLayer.d.ts +18 -0
- package/lib/maps/ChoroplethLayer.js +34 -25
- package/lib/maps/ChoroplethLayerDesign.d.ts +3 -2
- package/lib/maps/ChoroplethLayerDesigner.d.ts +11 -1
- package/lib/maps/DirectMapDataSource.js +17 -0
- package/lib/maps/EditHoverOver.d.ts +1 -1
- package/lib/maps/EditHoverOver.js +62 -33
- package/lib/maps/HoverContent.d.ts +10 -5
- package/lib/maps/HoverContent.js +6 -35
- package/lib/maps/Layer.d.ts +37 -0
- package/lib/maps/Layer.js +30 -4
- package/lib/maps/MWaterServerLayer.d.ts +2 -2
- package/lib/maps/MWaterServerLayer.js +6 -6
- package/lib/maps/MapLayerDataSource.d.ts +9 -0
- package/lib/maps/MapUtils.d.ts +19 -1
- package/lib/maps/MapUtils.js +71 -1
- package/lib/maps/MarkersLayer.d.ts +18 -0
- package/lib/maps/MarkersLayer.js +24 -24
- package/lib/maps/MarkersLayerDesignerComponent.d.ts +14 -1
- package/lib/maps/RasterMapViewComponent.js +1 -1
- package/lib/maps/ServerMapDataSource.d.ts +9 -0
- package/lib/maps/ServerMapDataSource.js +29 -0
- package/lib/maps/VectorMapViewComponent.js +6 -6
- package/lib/maps/maps.d.ts +4 -2
- package/lib/mwater_table_selection/FormsListComponent.d.ts +33 -0
- package/lib/mwater_table_selection/FormsListComponent.js +141 -0
- package/lib/mwater_table_selection/IndicatorsListComponent.d.ts +47 -0
- package/lib/mwater_table_selection/IndicatorsListComponent.js +182 -0
- package/lib/mwater_table_selection/IssuesListComponent.d.ts +29 -0
- package/lib/mwater_table_selection/IssuesListComponent.js +123 -0
- package/lib/mwater_table_selection/MWaterAccountingSystemListComponent.d.ts +20 -0
- package/lib/mwater_table_selection/MWaterAccountingSystemListComponent.js +157 -0
- package/lib/mwater_table_selection/MWaterAssetSystemsListComponent.d.ts +17 -0
- package/lib/mwater_table_selection/MWaterAssetSystemsListComponent.js +79 -0
- package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.d.ts +37 -0
- package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.js +275 -0
- package/lib/mwater_table_selection/MWaterCustomTablesetListComponent.d.ts +17 -0
- package/lib/mwater_table_selection/MWaterCustomTablesetListComponent.js +94 -0
- package/lib/mwater_table_selection/MWaterMetricsTableListComponent.d.ts +17 -0
- package/lib/mwater_table_selection/MWaterMetricsTableListComponent.js +80 -0
- package/lib/mwater_table_selection/MWaterTableSelectComponent.d.ts +32 -0
- package/lib/mwater_table_selection/MWaterTableSelectComponent.js +158 -0
- package/lib/quickfilter/Quickfilter.d.ts +2 -0
- package/lib/quickfilter/QuickfiltersDesignComponent.js +18 -10
- package/lib/widgets/charts/Chart.d.ts +11 -0
- package/lib/widgets/charts/Chart.js +15 -0
- package/lib/widgets/charts/ChartWidgetComponent.d.ts +1 -0
- package/lib/widgets/charts/ChartWidgetComponent.js +27 -1
- package/lib/widgets/charts/layered/LayeredChartDesign.d.ts +1 -1
- package/lib/widgets/charts/layered/LayeredChartDesignerComponent.d.ts +1 -1
- package/lib/widgets/charts/layered/LayeredChartDesignerComponent.js +5 -12
- package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.d.ts +43 -57
- package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.js +113 -110
- package/lib/widgets/charts/layered/LayeredChartUtils.d.ts +2 -1
- package/lib/widgets/charts/layered/LayeredChartUtils.js +0 -2
- package/lib/widgets/charts/pivot/PivotChart.d.ts +2 -0
- package/lib/widgets/charts/pivot/PivotChart.js +156 -0
- package/lib/widgets/charts/pivot/PivotChartDesignerComponent.d.ts +5 -20
- package/lib/widgets/charts/pivot/PivotChartDesignerComponent.js +31 -61
- package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.d.ts +4 -0
- package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.js +4 -2
- package/lib/widgets/charts/pivot/PivotChartLayoutComponent.d.ts +5 -44
- package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +38 -63
- package/lib/widgets/charts/pivot/SegmentDesignerComponent.d.ts +7 -68
- package/lib/widgets/charts/pivot/SegmentDesignerComponent.js +58 -106
- package/lib/widgets/charts/table/TableChart.d.ts +2 -0
- package/lib/widgets/charts/table/TableChart.js +172 -1
- package/lib/widgets/charts/table/TableChartDesignerComponent.d.ts +7 -17
- package/lib/widgets/charts/table/TableChartDesignerComponent.js +79 -95
- package/lib/widgets/charts/table/TableChartViewComponent.d.ts +1 -7
- package/lib/widgets/charts/table/TableChartViewComponent.js +19 -27
- package/package.json +3 -8
- package/src/MWaterContextComponent.tsx +1 -1
- package/src/MWaterLoaderComponent.ts +1 -1
- package/src/dashboards/DashboardComponent.tsx +2 -1
- package/src/dashboards/LayoutOptionsComponent.tsx +22 -10
- package/src/dashboards/ServerDashboardDataSource.ts +36 -1
- package/src/dashboards/layoutOptions.tsx +5 -1
- package/src/datagrids/DatagridComponent.tsx +1 -1
- package/src/datagrids/ExprCellComponent.tsx +23 -20
- package/src/maps/BufferLayer.ts +35 -20
- package/src/maps/ChoroplethLayer.ts +51 -33
- package/src/maps/ChoroplethLayerDesign.ts +3 -2
- package/src/maps/ChoroplethLayerDesigner.tsx +2 -2
- package/src/maps/DirectMapDataSource.ts +21 -1
- package/src/maps/EditHoverOver.tsx +91 -51
- package/src/maps/HoverContent.tsx +16 -47
- package/src/maps/Layer.ts +42 -4
- package/src/maps/MWaterServerLayer.ts +6 -6
- package/src/maps/MapLayerDataSource.ts +8 -0
- package/src/maps/MapUtils.ts +70 -3
- package/src/maps/MarkersLayer.ts +34 -24
- package/src/maps/RasterMapViewComponent.ts +1 -1
- package/src/maps/ServerMapDataSource.ts +35 -0
- package/src/maps/VectorMapViewComponent.tsx +6 -6
- package/src/maps/maps.ts +4 -2
- package/src/mwater_table_selection/FormsListComponent.tsx +188 -0
- package/src/mwater_table_selection/IndicatorsListComponent.tsx +283 -0
- package/src/mwater_table_selection/IssuesListComponent.tsx +167 -0
- package/src/mwater_table_selection/MWaterAccountingSystemListComponent.tsx +225 -0
- package/src/{MWaterAssetSystemsListComponent.tsx → mwater_table_selection/MWaterAssetSystemsListComponent.tsx} +2 -2
- package/src/mwater_table_selection/MWaterCompleteTableSelectComponent.tsx +377 -0
- package/src/{MWaterCustomTablesetListComponent.tsx → mwater_table_selection/MWaterCustomTablesetListComponent.tsx} +1 -1
- package/src/{MWaterMetricsTableListComponent.tsx → mwater_table_selection/MWaterMetricsTableListComponent.tsx} +1 -1
- package/src/{MWaterTableSelectComponent.tsx → mwater_table_selection/MWaterTableSelectComponent.tsx} +83 -86
- package/src/quickfilter/Quickfilter.ts +3 -0
- package/src/quickfilter/QuickfiltersDesignComponent.tsx +19 -14
- package/src/widgets/charts/Chart.ts +17 -0
- package/src/widgets/charts/ChartWidgetComponent.tsx +36 -1
- package/src/widgets/charts/layered/LayeredChartDesign.ts +1 -1
- package/src/widgets/charts/layered/LayeredChartDesignerComponent.tsx +23 -24
- package/src/widgets/charts/layered/LayeredChartLayerDesignerComponent.tsx +260 -211
- package/src/widgets/charts/layered/LayeredChartUtils.ts +7 -7
- package/src/widgets/charts/pivot/PivotChart.ts +191 -0
- package/src/widgets/charts/pivot/PivotChartDesignerComponent.tsx +124 -129
- package/src/widgets/charts/pivot/PivotChartLayoutBuilder.ts +4 -2
- package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +120 -149
- package/src/widgets/charts/pivot/SegmentDesignerComponent.tsx +178 -198
- package/src/widgets/charts/table/TableChart.ts +177 -1
- package/src/widgets/charts/table/TableChartDesignerComponent.tsx +422 -0
- package/src/widgets/charts/table/{TableChartViewComponent.ts → TableChartViewComponent.tsx} +65 -60
- package/src/MWaterCompleteTableSelectComponent.tsx +0 -975
- package/src/widgets/charts/table/TableChartDesignerComponent.ts +0 -441
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MWaterCustomTablesetListComponent = void 0;
|
|
7
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
+
const expressions_1 = require("@mwater/expressions");
|
|
9
|
+
const react_1 = require("react");
|
|
10
|
+
const react_2 = __importDefault(require("react"));
|
|
11
|
+
const UIComponents_1 = require("../UIComponents");
|
|
12
|
+
const bootstrap_1 = require("@mwater/react-library/lib/bootstrap");
|
|
13
|
+
/** Searchable list of custom tables */
|
|
14
|
+
const MWaterCustomTablesetListComponent = (props) => {
|
|
15
|
+
const [tablesets, setTablesets] = (0, react_1.useState)();
|
|
16
|
+
const [search, setSearch] = (0, react_1.useState)("");
|
|
17
|
+
const [extraTableNeeded, setExtraTableNeeded] = (0, react_1.useState)();
|
|
18
|
+
const [showSystem, setShowSystem] = (0, react_1.useState)(false);
|
|
19
|
+
// Get list of all tablesets
|
|
20
|
+
(0, react_1.useEffect)(() => {
|
|
21
|
+
fetch(`${props.apiUrl}custom_tablesets?client=${props.client || ""}`)
|
|
22
|
+
.then((response) => response.json())
|
|
23
|
+
.then((tablesets) => {
|
|
24
|
+
// Filter out non-normal
|
|
25
|
+
tablesets = tablesets.filter((ts) => ts.type === "normal");
|
|
26
|
+
// Put included ones first
|
|
27
|
+
setTablesets(lodash_1.default.sortByAll(tablesets, [
|
|
28
|
+
(ts) => (props.extraTables.some((t) => (t || "").startsWith(`custom.${ts.code}.`)) ? 0 : 1),
|
|
29
|
+
(ts) => expressions_1.ExprUtils.localizeString(ts.design.name, props.locale)
|
|
30
|
+
]));
|
|
31
|
+
});
|
|
32
|
+
}, []);
|
|
33
|
+
(0, react_1.useEffect)(() => {
|
|
34
|
+
if (extraTableNeeded && props.schema.getTable(extraTableNeeded)) {
|
|
35
|
+
props.onChange(extraTableNeeded);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
const selectTable = (ts, tableId) => {
|
|
39
|
+
const qualifiedTableId = `custom.${ts.code}.${tableId}`;
|
|
40
|
+
// If already included, select it
|
|
41
|
+
if (props.schema.getTable(qualifiedTableId)) {
|
|
42
|
+
props.onChange(qualifiedTableId);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Request extra tables as wildcard
|
|
46
|
+
setExtraTableNeeded(qualifiedTableId);
|
|
47
|
+
props.onExtraTableAdd(`custom.${ts.code}.*`);
|
|
48
|
+
};
|
|
49
|
+
const handleRemove = (ts) => {
|
|
50
|
+
// Remove from extra tables
|
|
51
|
+
const match = props.extraTables.find((t) => (t || "").startsWith(`custom.${ts.code}.`));
|
|
52
|
+
if (match) {
|
|
53
|
+
if (confirm(T `Remove this set of tables? Some widgets may not work correctly.`)) {
|
|
54
|
+
props.onChange(null);
|
|
55
|
+
props.onExtraTableRemove(match);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
if (!tablesets || extraTableNeeded) {
|
|
60
|
+
return (react_2.default.createElement("div", null,
|
|
61
|
+
react_2.default.createElement("i", { className: "fa fa-spin fa-spinner" }),
|
|
62
|
+
" ",
|
|
63
|
+
T `Loading...`));
|
|
64
|
+
}
|
|
65
|
+
const renderTableset = (ts) => {
|
|
66
|
+
const name = expressions_1.ExprUtils.localizeString(ts.design.name, props.locale) || "";
|
|
67
|
+
// Check search
|
|
68
|
+
if (search &&
|
|
69
|
+
!name.toLowerCase().includes(search.toLowerCase()) &&
|
|
70
|
+
!ts.design.tables.some((t) => expressions_1.ExprUtils.localizeString(t.name).toLowerCase().includes(search.toLowerCase()))) {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
const items = ts.design.tables
|
|
74
|
+
.filter((t) => !t.deprecated)
|
|
75
|
+
.map((t) => ({
|
|
76
|
+
name: expressions_1.ExprUtils.localizeString(t.name, props.locale),
|
|
77
|
+
onClick: () => selectTable(ts, t.id)
|
|
78
|
+
}));
|
|
79
|
+
const alreadyIncluded = props.extraTables.some((t) => (t || "").startsWith(`custom.${ts.code}.`));
|
|
80
|
+
return (react_2.default.createElement("div", { key: ts.code },
|
|
81
|
+
alreadyIncluded ? (react_2.default.createElement("div", { style: { float: "right" } },
|
|
82
|
+
react_2.default.createElement("button", { className: "btn btn-sm btn-link", type: "button", onClick: () => handleRemove(ts) },
|
|
83
|
+
react_2.default.createElement("i", { className: "fa fa-remove" })))) : null,
|
|
84
|
+
react_2.default.createElement("h4", { className: "text-muted" }, name),
|
|
85
|
+
react_2.default.createElement(UIComponents_1.OptionListComponent, { items: items })));
|
|
86
|
+
};
|
|
87
|
+
const visibleTablesets = tablesets.filter((ts) => (showSystem || !ts.design.system) && !ts.design.deprecated);
|
|
88
|
+
return (react_2.default.createElement("div", null,
|
|
89
|
+
react_2.default.createElement(bootstrap_1.TextInput, { value: search, onChange: setSearch, placeholder: T `Search...` }),
|
|
90
|
+
visibleTablesets.map((ts) => renderTableset(ts)),
|
|
91
|
+
react_2.default.createElement("div", null,
|
|
92
|
+
react_2.default.createElement("button", { className: "btn btn-link btn-sm", onClick: () => setShowSystem(!showSystem) }, showSystem ? T `Hide system tables` : T `Show system tables`))));
|
|
93
|
+
};
|
|
94
|
+
exports.MWaterCustomTablesetListComponent = MWaterCustomTablesetListComponent;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Schema } from "@mwater/expressions";
|
|
2
|
+
import React from "react";
|
|
3
|
+
/** Searchable list of metric tables */
|
|
4
|
+
export declare const MWaterMetricsTableListComponent: (props: {
|
|
5
|
+
apiUrl: string;
|
|
6
|
+
schema: Schema;
|
|
7
|
+
client?: string;
|
|
8
|
+
/** User id */
|
|
9
|
+
user?: string;
|
|
10
|
+
/** Called with table selected */
|
|
11
|
+
onChange: (tableId: string | null) => void;
|
|
12
|
+
extraTables: string[];
|
|
13
|
+
onExtraTableAdd: (tableId: string) => void;
|
|
14
|
+
onExtraTableRemove: (tableId: string) => void;
|
|
15
|
+
/** e.g. "en" */
|
|
16
|
+
locale?: string;
|
|
17
|
+
}) => React.JSX.Element;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.MWaterMetricsTableListComponent = void 0;
|
|
7
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
8
|
+
const expressions_1 = require("@mwater/expressions");
|
|
9
|
+
const react_1 = require("react");
|
|
10
|
+
const react_2 = __importDefault(require("react"));
|
|
11
|
+
const UIComponents_1 = require("../UIComponents");
|
|
12
|
+
const bootstrap_1 = require("@mwater/react-library/lib/bootstrap");
|
|
13
|
+
/** Searchable list of metric tables */
|
|
14
|
+
const MWaterMetricsTableListComponent = (props) => {
|
|
15
|
+
const [metrics, setMetrics] = (0, react_1.useState)();
|
|
16
|
+
const [search, setSearch] = (0, react_1.useState)("");
|
|
17
|
+
const [extraTableNeeded, setExtraTableNeeded] = (0, react_1.useState)();
|
|
18
|
+
// Get list of all metrics
|
|
19
|
+
(0, react_1.useEffect)(() => {
|
|
20
|
+
fetch(`${props.apiUrl}metrics?client=${props.client || ""}`)
|
|
21
|
+
.then((response) => response.json())
|
|
22
|
+
.then((body) => {
|
|
23
|
+
// Put included ones first
|
|
24
|
+
setMetrics(lodash_1.default.sortByAll(body, [
|
|
25
|
+
(m) => (props.extraTables.some((t) => (t = `metrics:${m._id}`)) ? 0 : 1),
|
|
26
|
+
(m) => expressions_1.ExprUtils.localizeString(m.design.name, props.locale)
|
|
27
|
+
]));
|
|
28
|
+
});
|
|
29
|
+
}, []);
|
|
30
|
+
(0, react_1.useEffect)(() => {
|
|
31
|
+
if (extraTableNeeded && props.schema.getTable(extraTableNeeded)) {
|
|
32
|
+
props.onChange(extraTableNeeded);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
const selectTable = (metric) => {
|
|
36
|
+
const qualifiedTableId = `metrics:${metric._id}`;
|
|
37
|
+
// If already included, select it
|
|
38
|
+
if (props.schema.getTable(qualifiedTableId)) {
|
|
39
|
+
props.onChange(qualifiedTableId);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
// Request extra tables as wildcard
|
|
43
|
+
setExtraTableNeeded(qualifiedTableId);
|
|
44
|
+
props.onExtraTableAdd(qualifiedTableId);
|
|
45
|
+
};
|
|
46
|
+
const handleRemove = (metric) => {
|
|
47
|
+
// Remove from extra tables
|
|
48
|
+
const match = props.extraTables.find((t) => t == `metrics:${metric._id}`);
|
|
49
|
+
if (match) {
|
|
50
|
+
if (confirm(T `Remove this table? Some widgets may not work correctly.`)) {
|
|
51
|
+
props.onChange(null);
|
|
52
|
+
props.onExtraTableRemove(match);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
if (!metrics || extraTableNeeded) {
|
|
57
|
+
return (react_2.default.createElement("div", null,
|
|
58
|
+
react_2.default.createElement("i", { className: "fa fa-spin fa-spinner" }),
|
|
59
|
+
" ",
|
|
60
|
+
T `Loading...`));
|
|
61
|
+
}
|
|
62
|
+
const renderMetrics = () => {
|
|
63
|
+
const items = metrics
|
|
64
|
+
.filter((m) => !m.design.deprecated)
|
|
65
|
+
.map((m) => {
|
|
66
|
+
const alreadyIncluded = props.extraTables.some((t) => t == `metrics:${m._id}`);
|
|
67
|
+
return {
|
|
68
|
+
name: expressions_1.ExprUtils.localizeString(m.design.name, props.locale) || "",
|
|
69
|
+
onClick: () => selectTable(m),
|
|
70
|
+
onRemove: alreadyIncluded ? handleRemove.bind(null, m) : undefined
|
|
71
|
+
};
|
|
72
|
+
})
|
|
73
|
+
.filter((item) => !search || !item.name.toLowerCase().includes(search.toLowerCase()));
|
|
74
|
+
return react_2.default.createElement(UIComponents_1.OptionListComponent, { items: items });
|
|
75
|
+
};
|
|
76
|
+
return (react_2.default.createElement("div", null,
|
|
77
|
+
react_2.default.createElement(bootstrap_1.TextInput, { value: search, onChange: setSearch, placeholder: T `Search...` }),
|
|
78
|
+
renderMetrics()));
|
|
79
|
+
};
|
|
80
|
+
exports.MWaterMetricsTableListComponent = MWaterMetricsTableListComponent;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ToggleEditComponent } from "../UIComponents";
|
|
3
|
+
import { Schema } from "@mwater/expressions";
|
|
4
|
+
export interface MWaterTableSelectComponentProps {
|
|
5
|
+
/** Url to hit api */
|
|
6
|
+
apiUrl: string;
|
|
7
|
+
/** Optional client */
|
|
8
|
+
client?: string;
|
|
9
|
+
schema: Schema;
|
|
10
|
+
/** User id */
|
|
11
|
+
user?: string;
|
|
12
|
+
table?: string;
|
|
13
|
+
/** Called with table selected */
|
|
14
|
+
onChange: (table: string | null) => void;
|
|
15
|
+
extraTables: string[];
|
|
16
|
+
onExtraTablesChange: (tables: string[]) => void;
|
|
17
|
+
/** Can also perform filtering for some types. Include these props to enable this */
|
|
18
|
+
filter?: any;
|
|
19
|
+
onFilterChange?: (filter: any) => void;
|
|
20
|
+
}
|
|
21
|
+
interface MWaterTableSelectComponentState {
|
|
22
|
+
pendingExtraTable: string | null;
|
|
23
|
+
}
|
|
24
|
+
export default class MWaterTableSelectComponent extends React.Component<MWaterTableSelectComponentProps, MWaterTableSelectComponentState> {
|
|
25
|
+
toggleEdit: ToggleEditComponent | null;
|
|
26
|
+
constructor(props: MWaterTableSelectComponentProps);
|
|
27
|
+
componentDidUpdate(prevProps: MWaterTableSelectComponentProps): void;
|
|
28
|
+
handleChange: (tableId: string | null) => void;
|
|
29
|
+
handleTableChange: (tableId: string | null) => void;
|
|
30
|
+
render(): React.JSX.Element;
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const lodash_1 = __importDefault(require("lodash"));
|
|
7
|
+
const react_1 = __importDefault(require("react"));
|
|
8
|
+
const UIComponents_1 = require("../UIComponents");
|
|
9
|
+
const expressions_1 = require("@mwater/expressions");
|
|
10
|
+
const MWaterResponsesFilterComponent_1 = __importDefault(require("../MWaterResponsesFilterComponent"));
|
|
11
|
+
const ModalPopupComponent_1 = __importDefault(require("@mwater/react-library/lib/ModalPopupComponent"));
|
|
12
|
+
const MWaterCompleteTableSelectComponent_1 = __importDefault(require("./MWaterCompleteTableSelectComponent"));
|
|
13
|
+
const expressions_ui_1 = require("@mwater/expressions-ui");
|
|
14
|
+
// Allows selection of a mwater-visualization table. Loads forms as well and calls event if modified
|
|
15
|
+
class MWaterTableSelectComponent extends react_1.default.Component {
|
|
16
|
+
toggleEdit = null;
|
|
17
|
+
constructor(props) {
|
|
18
|
+
super(props);
|
|
19
|
+
this.state = {
|
|
20
|
+
pendingExtraTable: null // Set when waiting for a table to load
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
componentDidUpdate(prevProps) {
|
|
24
|
+
// If received new schema with pending extra table, select it
|
|
25
|
+
let table = null;
|
|
26
|
+
if (this.state.pendingExtraTable) {
|
|
27
|
+
table = this.state.pendingExtraTable;
|
|
28
|
+
if (this.props.schema.getTable(table)) {
|
|
29
|
+
// No longer waiting
|
|
30
|
+
this.setState({ pendingExtraTable: null });
|
|
31
|
+
// Close toggle edit
|
|
32
|
+
this.toggleEdit?.close();
|
|
33
|
+
// Fire change
|
|
34
|
+
this.props.onChange(table);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
// If table is newly selected and is a responses table and no filters, set filters to final only
|
|
38
|
+
if (this.props.table &&
|
|
39
|
+
this.props.table.match(/responses:/) &&
|
|
40
|
+
this.props.table !== prevProps.table &&
|
|
41
|
+
!this.props.filter &&
|
|
42
|
+
this.props.onFilterChange) {
|
|
43
|
+
this.props.onFilterChange({
|
|
44
|
+
type: "op",
|
|
45
|
+
op: "= any",
|
|
46
|
+
table: this.props.table,
|
|
47
|
+
exprs: [
|
|
48
|
+
{ type: "field", table: this.props.table, column: "status" },
|
|
49
|
+
{ type: "literal", valueType: "enumset", value: ["final"] }
|
|
50
|
+
]
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
handleChange = (tableId) => {
|
|
55
|
+
// Close toggle edit
|
|
56
|
+
this.toggleEdit?.close();
|
|
57
|
+
// Call onChange if different
|
|
58
|
+
if (tableId !== this.props.table) {
|
|
59
|
+
return this.props.onChange(tableId);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
handleTableChange = (tableId) => {
|
|
63
|
+
// If not part of extra tables, add it and wait for new schema
|
|
64
|
+
if (tableId && !this.props.schema.getTable(tableId)) {
|
|
65
|
+
return this.setState({ pendingExtraTable: tableId }, () => {
|
|
66
|
+
return this.props.onExtraTablesChange(lodash_1.default.union(this.props.extraTables, [tableId]));
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
return this.handleChange(tableId);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
render() {
|
|
74
|
+
const editor = react_1.default.createElement(EditModeTableSelectComponent, { apiUrl: this.props.apiUrl, client: this.props.client, schema: this.props.schema, user: this.props.user, table: this.props.table, onChange: this.handleTableChange, extraTables: this.props.extraTables, onExtraTablesChange: this.props.onExtraTablesChange });
|
|
75
|
+
return (react_1.default.createElement("div", null,
|
|
76
|
+
this.state.pendingExtraTable ? (react_1.default.createElement("div", { className: "alert alert-info", key: "pendingExtraTable" },
|
|
77
|
+
react_1.default.createElement("i", { className: "fa fa-spinner fa-spin" }),
|
|
78
|
+
"\u00A0",
|
|
79
|
+
T `Please wait...`)) : undefined,
|
|
80
|
+
react_1.default.createElement(UIComponents_1.ToggleEditComponent, { ref: (c) => {
|
|
81
|
+
this.toggleEdit = c;
|
|
82
|
+
}, forceOpen: !this.props.table, label: this.props.table
|
|
83
|
+
? expressions_1.ExprUtils.localizeString(this.props.schema.getTable(this.props.table)?.name, T.locale)
|
|
84
|
+
: "", editor: editor, onRemove: () => {
|
|
85
|
+
this.props.onChange(null);
|
|
86
|
+
} }),
|
|
87
|
+
this.props.table &&
|
|
88
|
+
this.props.onFilterChange &&
|
|
89
|
+
this.props.table.match(/^responses:/) &&
|
|
90
|
+
this.props.schema.getTable(this.props.table) ? (react_1.default.createElement(MWaterResponsesFilterComponent_1.default, { schema: this.props.schema, table: this.props.table, filter: this.props.filter, onFilterChange: this.props.onFilterChange })) : undefined));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
exports.default = MWaterTableSelectComponent;
|
|
94
|
+
// Is the table select component when in edit mode. Toggles between complete list and simplified list
|
|
95
|
+
class EditModeTableSelectComponent extends react_1.default.Component {
|
|
96
|
+
constructor(props) {
|
|
97
|
+
super(props);
|
|
98
|
+
this.state = {
|
|
99
|
+
// True when in popup mode that shows all tables
|
|
100
|
+
completeMode: false
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
handleShowMore = () => {
|
|
104
|
+
return this.setState({ completeMode: true });
|
|
105
|
+
};
|
|
106
|
+
// Get list of tables that should be included in shortlist
|
|
107
|
+
// This is all active tables and all responses tables in schema (so as to include rosters) and all extra tables
|
|
108
|
+
// Also includes current table
|
|
109
|
+
getTableShortlist(activeTables) {
|
|
110
|
+
let tables = activeTables;
|
|
111
|
+
// Remove dead tables
|
|
112
|
+
tables = tables.filter((t) => this.props.schema.getTable(t) != null && !this.props.schema.getTable(t)?.deprecated);
|
|
113
|
+
tables = lodash_1.default.union(tables, lodash_1.default.filter(lodash_1.default.pluck(this.props.schema.getTables(), "id"), (t) => t.match(/^responses:/)));
|
|
114
|
+
if (this.props.table) {
|
|
115
|
+
tables = lodash_1.default.union(tables, [this.props.table]);
|
|
116
|
+
}
|
|
117
|
+
for (let extraTable of this.props.extraTables || []) {
|
|
118
|
+
// Check if wildcard
|
|
119
|
+
if (extraTable.match(/\*$/)) {
|
|
120
|
+
for (let table of this.props.schema.getTables()) {
|
|
121
|
+
if (table.id.startsWith(extraTable.substr(0, extraTable.length - 1)) && !table.deprecated) {
|
|
122
|
+
tables = lodash_1.default.union(tables, [table.id]);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
// Add if exists
|
|
128
|
+
if (this.props.schema.getTable(extraTable) && !this.props.schema.getTable(extraTable)?.deprecated) {
|
|
129
|
+
tables = lodash_1.default.union(tables, [extraTable]);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Sort by name
|
|
134
|
+
tables = lodash_1.default.sortBy(tables, (tableId) => expressions_1.ExprUtils.localizeString(this.props.schema.getTable(tableId)?.name, T.locale));
|
|
135
|
+
return tables;
|
|
136
|
+
}
|
|
137
|
+
handleCompleteChange = (tableId) => {
|
|
138
|
+
this.setState({ completeMode: false });
|
|
139
|
+
return this.props.onChange(tableId);
|
|
140
|
+
};
|
|
141
|
+
render() {
|
|
142
|
+
return (react_1.default.createElement(expressions_ui_1.ActiveTablesContext.Consumer, null, (activeTables) => (react_1.default.createElement("div", null,
|
|
143
|
+
this.state.completeMode ? (react_1.default.createElement(ModalPopupComponent_1.default, { header: T `Select Data Source`, onClose: () => this.setState({ completeMode: false }), showCloseX: true, size: "x-large" },
|
|
144
|
+
react_1.default.createElement(MWaterCompleteTableSelectComponent_1.default, { apiUrl: this.props.apiUrl, client: this.props.client, schema: this.props.schema, user: this.props.user, table: this.props.table, onChange: this.handleCompleteChange, extraTables: this.props.extraTables, onExtraTablesChange: this.props.onExtraTablesChange }))) : null,
|
|
145
|
+
this.getTableShortlist(activeTables).length > 0 ? (react_1.default.createElement(react_1.default.Fragment, null,
|
|
146
|
+
react_1.default.createElement("div", { className: "text-muted" }, T `Select Data Source:`),
|
|
147
|
+
react_1.default.createElement(UIComponents_1.OptionListComponent, { items: this.getTableShortlist(activeTables).map((tableId) => {
|
|
148
|
+
const table = this.props.schema.getTable(tableId);
|
|
149
|
+
return {
|
|
150
|
+
name: expressions_1.ExprUtils.localizeString(table?.name, T.locale),
|
|
151
|
+
desc: expressions_1.ExprUtils.localizeString(table?.desc, T.locale),
|
|
152
|
+
onClick: () => table && this.props.onChange(table.id)
|
|
153
|
+
};
|
|
154
|
+
}) }),
|
|
155
|
+
react_1.default.createElement("div", null,
|
|
156
|
+
react_1.default.createElement("button", { type: "button", className: "btn btn-link btn-sm", onClick: this.handleShowMore }, T `Show All Available Data Sources...`)))) : (react_1.default.createElement("button", { type: "button", className: "btn btn-link", onClick: this.handleShowMore }, T `Select Data Source...`))))));
|
|
157
|
+
}
|
|
158
|
+
}
|
|
@@ -3,6 +3,8 @@ import { Expr } from "@mwater/expressions";
|
|
|
3
3
|
design is an array of quick filters (user-selectable filters).
|
|
4
4
|
*/
|
|
5
5
|
export interface Quickfilter {
|
|
6
|
+
/** Optional id for the quickfilter. If not present, a random id will be generated the first time the quickfilter is edited. */
|
|
7
|
+
id?: string;
|
|
6
8
|
/** filter expression (left hand side only. Usually enum, enumset, text, date, datetime, id[], text[]) */
|
|
7
9
|
expr: Expr;
|
|
8
10
|
/** optional label */
|
|
@@ -29,6 +29,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
29
29
|
exports.default = QuickfiltersDesignComponent;
|
|
30
30
|
const lodash_1 = __importDefault(require("lodash"));
|
|
31
31
|
const react_1 = __importStar(require("react"));
|
|
32
|
+
const uuid_1 = __importDefault(require("uuid"));
|
|
32
33
|
const immer_1 = require("immer");
|
|
33
34
|
const expressions_ui_1 = require("@mwater/expressions-ui");
|
|
34
35
|
const expressions_1 = require("@mwater/expressions");
|
|
@@ -36,10 +37,19 @@ const ui = __importStar(require("@mwater/react-library/lib/bootstrap"));
|
|
|
36
37
|
const ListEditorComponent_1 = require("@mwater/react-library/lib/ListEditorComponent");
|
|
37
38
|
// Displays quick filters and allows their value to be modified
|
|
38
39
|
function QuickfiltersDesignComponent(props) {
|
|
39
|
-
//
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
// Add ids if not present
|
|
41
|
+
(0, react_1.useEffect)(() => {
|
|
42
|
+
if (props.design.some(qf => !qf.id)) {
|
|
43
|
+
const design = (0, immer_1.produce)(props.design, draft => {
|
|
44
|
+
for (let i = 0; i < draft.length; i++) {
|
|
45
|
+
if (!draft[i].id) {
|
|
46
|
+
draft[i].id = uuid_1.default.v4();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
props.onDesignChange(design);
|
|
51
|
+
}
|
|
52
|
+
}, [props.design]);
|
|
43
53
|
const handleDesignChange = (design) => {
|
|
44
54
|
const newDesign = (0, immer_1.produce)(design, draft => {
|
|
45
55
|
// Update merged flag, clearing if not mergeable
|
|
@@ -51,10 +61,6 @@ function QuickfiltersDesignComponent(props) {
|
|
|
51
61
|
});
|
|
52
62
|
props.onDesignChange(newDesign);
|
|
53
63
|
};
|
|
54
|
-
const handleReorder = (design) => {
|
|
55
|
-
setReorderCounter(c => c + 1);
|
|
56
|
-
handleDesignChange(design);
|
|
57
|
-
};
|
|
58
64
|
// Determine if quickfilter at index is mergeable with previous (same type, id table and enum values)
|
|
59
65
|
const isMergeable = (design, index) => {
|
|
60
66
|
if (index === 0) {
|
|
@@ -92,7 +98,9 @@ function QuickfiltersDesignComponent(props) {
|
|
|
92
98
|
};
|
|
93
99
|
const handleAdd = () => {
|
|
94
100
|
// Add blank to end
|
|
95
|
-
const design = props.design
|
|
101
|
+
const design = (0, immer_1.produce)(props.design, draft => {
|
|
102
|
+
draft.push({ expr: null, id: uuid_1.default.v4() });
|
|
103
|
+
});
|
|
96
104
|
props.onDesignChange(design);
|
|
97
105
|
};
|
|
98
106
|
const handleRemove = (index) => {
|
|
@@ -101,7 +109,7 @@ function QuickfiltersDesignComponent(props) {
|
|
|
101
109
|
props.onDesignChange(design);
|
|
102
110
|
};
|
|
103
111
|
return (react_1.default.createElement("div", null,
|
|
104
|
-
react_1.default.createElement(ListEditorComponent_1.ListEditorComponent, {
|
|
112
|
+
react_1.default.createElement(ListEditorComponent_1.ListEditorComponent, { items: props.design, onItemsChange: handleDesignChange, renderItem: renderQuickfilter, getReorderableKey: (item, index) => item.id ?? index }),
|
|
105
113
|
props.tables.length > 0 ? (react_1.default.createElement("button", { type: "button", className: "btn btn-sm btn-link", onClick: handleAdd },
|
|
106
114
|
react_1.default.createElement("span", { className: "fas fa-plus me-1" }),
|
|
107
115
|
T `Add Quick Filter`)) : undefined));
|
|
@@ -62,4 +62,15 @@ export default class Chart {
|
|
|
62
62
|
getTranslatableStrings(design: any, schema: Schema): string[];
|
|
63
63
|
/** Translates the design. Override in subclasses. Design is already cleaned. */
|
|
64
64
|
translateDesign(design: any, translate: (input: string) => string): any;
|
|
65
|
+
/** Determines if the chart supports exporting to XLSX format */
|
|
66
|
+
supportsXlsxExport(): boolean;
|
|
67
|
+
/** Creates a SheetJS workbook for the chart data
|
|
68
|
+
* @param design Chart design
|
|
69
|
+
* @param schema Schema to use
|
|
70
|
+
* @param dataSource Data source
|
|
71
|
+
* @param data Data from chart
|
|
72
|
+
* @param locale Locale to use
|
|
73
|
+
* @returns base64 encoded XLSX file
|
|
74
|
+
*/
|
|
75
|
+
createXlsxWorkbook(design: any, schema: Schema, dataSource: DataSource, data: any, locale: string): string;
|
|
65
76
|
}
|
|
@@ -90,5 +90,20 @@ class Chart {
|
|
|
90
90
|
translateDesign(design, translate) {
|
|
91
91
|
return design;
|
|
92
92
|
}
|
|
93
|
+
/** Determines if the chart supports exporting to XLSX format */
|
|
94
|
+
supportsXlsxExport() {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
/** Creates a SheetJS workbook for the chart data
|
|
98
|
+
* @param design Chart design
|
|
99
|
+
* @param schema Schema to use
|
|
100
|
+
* @param dataSource Data source
|
|
101
|
+
* @param data Data from chart
|
|
102
|
+
* @param locale Locale to use
|
|
103
|
+
* @returns base64 encoded XLSX file
|
|
104
|
+
*/
|
|
105
|
+
createXlsxWorkbook(design, schema, dataSource, data, locale) {
|
|
106
|
+
throw new Error("Not implemented");
|
|
107
|
+
}
|
|
93
108
|
}
|
|
94
109
|
exports.default = Chart;
|
|
@@ -44,6 +44,7 @@ export declare class ChartWidgetComponent extends React.PureComponent<ChartWidge
|
|
|
44
44
|
static contextType: React.Context<string>;
|
|
45
45
|
constructor(props: any);
|
|
46
46
|
handleSaveCsvFile: () => void | AbortController | undefined;
|
|
47
|
+
handleSaveXlsxFile: () => void;
|
|
47
48
|
handleStartEditing: () => void;
|
|
48
49
|
handleEndEditing: () => void;
|
|
49
50
|
handleCancelEditing: () => void;
|
|
@@ -69,6 +69,28 @@ class ChartWidgetComponent extends react_1.default.PureComponent {
|
|
|
69
69
|
return FileSaver.saveAs(blob, "Exported Data.csv");
|
|
70
70
|
});
|
|
71
71
|
};
|
|
72
|
+
// Saves an xlsx file to disk
|
|
73
|
+
handleSaveXlsxFile = () => {
|
|
74
|
+
// Get the data
|
|
75
|
+
this.props.widgetDataSource.getData(this.props.design, this.props.filters, (err, data) => {
|
|
76
|
+
if (err) {
|
|
77
|
+
console.error(err);
|
|
78
|
+
alert(T `Failed to get data: ${err.message}`);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
// Create workbook
|
|
83
|
+
const blob = this.props.chart.createXlsxWorkbook(this.props.design, this.props.schema, this.props.dataSource, data, this.context);
|
|
84
|
+
// Require at use as causes server problems
|
|
85
|
+
const FileSaver = require("file-saver");
|
|
86
|
+
FileSaver.saveAs(blob, "Exported Data.xlsx");
|
|
87
|
+
}
|
|
88
|
+
catch (ex) {
|
|
89
|
+
console.error(ex);
|
|
90
|
+
alert(T `Failed to export data: ${ex.message}`);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
};
|
|
72
94
|
handleStartEditing = () => {
|
|
73
95
|
// Can't edit if already editing
|
|
74
96
|
if (this.state.editDesign) {
|
|
@@ -149,7 +171,11 @@ class ChartWidgetComponent extends react_1.default.PureComponent {
|
|
|
149
171
|
// Create dropdown items
|
|
150
172
|
const dropdownItems = this.props.chart.createDropdownItems(design, this.props.schema, this.props.widgetDataSource, this.props.filters);
|
|
151
173
|
if (!designError) {
|
|
152
|
-
dropdownItems.push({ label: T `Export Data`, onClick: this.handleSaveCsvFile });
|
|
174
|
+
dropdownItems.push({ label: T `Export Data (CSV)`, onClick: this.handleSaveCsvFile });
|
|
175
|
+
// Add XLSX export option if supported
|
|
176
|
+
if (this.props.chart.supportsXlsxExport()) {
|
|
177
|
+
dropdownItems.push({ label: T `Export Data (XLSX)`, onClick: this.handleSaveXlsxFile });
|
|
178
|
+
}
|
|
153
179
|
}
|
|
154
180
|
if (this.props.onDesignChange != null) {
|
|
155
181
|
dropdownItems.unshift({
|
|
@@ -45,7 +45,7 @@ export interface LayeredChartDesign {
|
|
|
45
45
|
}
|
|
46
46
|
export interface LayeredChartDesignLayer {
|
|
47
47
|
/** bar/line/spline/scatter/area/pie/donut (overrides main one) */
|
|
48
|
-
type
|
|
48
|
+
type?: "bar" | "line" | "spline" | "scatter" | "area" | "pie" | "donut";
|
|
49
49
|
/** table of layer */
|
|
50
50
|
table: string;
|
|
51
51
|
/** label for layer (optional) */
|
|
@@ -36,7 +36,7 @@ export default class LayeredChartDesignerComponent extends React.Component<Layer
|
|
|
36
36
|
handleXAxisTickMultilineChange: (value: boolean) => void;
|
|
37
37
|
renderLabels(): React.DetailedReactHTMLElement<React.HTMLAttributes<HTMLElement>, HTMLElement> | undefined;
|
|
38
38
|
renderChartOptions(): React.JSX.Element;
|
|
39
|
-
renderType(): React.
|
|
39
|
+
renderType(): React.JSX.Element;
|
|
40
40
|
renderLayer: (index: any) => React.DetailedReactHTMLElement<{
|
|
41
41
|
style: {
|
|
42
42
|
paddingTop: number;
|
|
@@ -154,24 +154,17 @@ class LayeredChartDesignerComponent extends react_1.default.Component {
|
|
|
154
154
|
{ id: "scatter", name: T `Scatter`, desc: T `Show correlation between two number variables` },
|
|
155
155
|
{ id: "area", name: T `Area`, desc: T `For cumulative data over time` }
|
|
156
156
|
];
|
|
157
|
-
const current =
|
|
158
|
-
return
|
|
159
|
-
forceOpen: !this.props.design.type,
|
|
160
|
-
label: current ? current.name : "",
|
|
161
|
-
editor: (onClose) => {
|
|
162
|
-
return R(uiComponents.OptionListComponent, {
|
|
163
|
-
hint: T `Select a Chart Type`,
|
|
164
|
-
items: lodash_1.default.map(chartTypes, ct => ({
|
|
157
|
+
const current = chartTypes.find(ct => ct.id === this.props.design.type);
|
|
158
|
+
return (react_1.default.createElement(uiComponents.SectionComponent, { label: T `Chart Type` },
|
|
159
|
+
react_1.default.createElement(uiComponents.ToggleEditComponent, { forceOpen: !this.props.design.type, label: current ? current.name : "", editor: (onClose) => (react_1.default.createElement(uiComponents.OptionListComponent, { hint: T `Select a Chart Type`, items: chartTypes.map(ct => ({
|
|
165
160
|
name: ct.name,
|
|
166
161
|
desc: ct.desc,
|
|
167
162
|
onClick: () => {
|
|
168
163
|
onClose(); // Close editor first
|
|
169
164
|
return this.handleTypeChange(ct.id);
|
|
170
165
|
}
|
|
171
|
-
}))
|
|
172
|
-
|
|
173
|
-
}
|
|
174
|
-
}), this.renderOptions());
|
|
166
|
+
})) })) }),
|
|
167
|
+
this.renderOptions()));
|
|
175
168
|
}
|
|
176
169
|
renderLayer = (index) => {
|
|
177
170
|
const style = {
|