@mwater/visualization 5.5.0 → 5.6.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/MWaterContextComponent.d.ts +1 -1
- package/lib/MWaterGlobalFiltersComponent.d.ts +2 -2
- package/lib/MWaterGlobalFiltersComponent.js +11 -20
- package/lib/MWaterLoaderComponent.d.ts +4 -13
- package/lib/MWaterLoaderComponent.js +2 -11
- package/lib/UndoStack.d.ts +2 -1
- package/lib/UndoStack.js +12 -6
- package/lib/dashboards/DashboardComponent.js +5 -4
- package/lib/dashboards/DashboardDesign.d.ts +1 -1
- package/lib/dashboards/ServerDashboardDataSource.js +0 -10
- package/lib/dashboards/SettingsModalComponent.js +1 -1
- package/lib/datagrids/DatagridComponent.js +22 -2
- package/lib/datagrids/DatagridDesignerComponent.d.ts +2 -3
- package/lib/datagrids/DatagridDesignerComponent.js +108 -120
- package/lib/datagrids/DatagridViewComponent.js +3 -2
- package/lib/datagrids/OrderBysDesignerComponent.d.ts +7 -7
- package/lib/datagrids/OrderBysDesignerComponent.js +19 -28
- package/lib/index.css +45 -2
- package/lib/index.d.ts +5 -5
- package/lib/index.js +2 -3
- package/lib/layouts/blocks/BlocksDisplayComponent.d.ts +8 -1
- package/lib/layouts/blocks/BlocksDisplayComponent.js +46 -4
- package/lib/maps/BufferLayer.js +12 -0
- package/lib/maps/BufferLayerDesign.d.ts +1 -1
- package/lib/maps/BufferLayerDesignerComponent.js +2 -2
- package/lib/maps/ChoroplethLayer.js +12 -0
- package/lib/maps/ChoroplethLayerDesign.d.ts +5 -2
- package/lib/maps/ChoroplethLayerDesigner.d.ts +10 -32
- package/lib/maps/ChoroplethLayerDesigner.js +58 -89
- package/lib/maps/DirectMapDataSource.js +0 -10
- package/lib/maps/EditHoverOver.d.ts +4 -3
- package/lib/maps/EditHoverOver.js +3 -3
- package/lib/maps/HoverContent.js +1 -1
- package/lib/maps/LeafletMapComponent.js +10 -19
- package/lib/maps/MapComponent.js +0 -1
- package/lib/maps/MapUtils.js +10 -1
- package/lib/maps/MarkersLayer.js +18 -2
- package/lib/maps/MarkersLayerDesign.d.ts +1 -1
- package/lib/maps/MarkersLayerDesignerComponent.d.ts +12 -41
- package/lib/maps/MarkersLayerDesignerComponent.js +81 -111
- package/lib/maps/ServerMapDataSource.js +0 -10
- package/lib/maps/VectorMapViewComponent.js +1 -9
- package/lib/maps/symbols/font-awesome/asterisk.png +0 -0
- package/lib/maps/symbols/font-awesome/ban.png +0 -0
- package/lib/maps/symbols/font-awesome/beer.png +0 -0
- package/lib/maps/symbols/font-awesome/bell.png +0 -0
- package/lib/maps/symbols/font-awesome/bolt.png +0 -0
- package/lib/maps/symbols/font-awesome/building.png +0 -0
- package/lib/maps/symbols/font-awesome/bullseye.png +0 -0
- package/lib/maps/symbols/font-awesome/bus.png +0 -0
- package/lib/maps/symbols/font-awesome/caret-up.png +0 -0
- package/lib/maps/symbols/font-awesome/certificate.png +0 -0
- package/lib/maps/symbols/font-awesome/check-circle.png +0 -0
- package/lib/maps/symbols/font-awesome/check.png +0 -0
- package/lib/maps/symbols/font-awesome/chevron-circle-down.png +0 -0
- package/lib/maps/symbols/font-awesome/chevron-circle-up.png +0 -0
- package/lib/maps/symbols/font-awesome/cloud-rain.png +0 -0
- package/lib/maps/symbols/font-awesome/cloud.png +0 -0
- package/lib/maps/symbols/font-awesome/comment.png +0 -0
- package/lib/maps/symbols/font-awesome/crosshairs.png +0 -0
- package/lib/maps/symbols/font-awesome/dot-circle-o.png +0 -0
- package/lib/maps/symbols/font-awesome/exclamation-circle.png +0 -0
- package/lib/maps/symbols/font-awesome/exclamation-triangle.png +0 -0
- package/lib/maps/symbols/font-awesome/female.png +0 -0
- package/lib/maps/symbols/font-awesome/file.png +0 -0
- package/lib/maps/symbols/font-awesome/flag.png +0 -0
- package/lib/maps/symbols/font-awesome/flask.png +0 -0
- package/lib/maps/symbols/font-awesome/h-square.png +0 -0
- package/lib/maps/symbols/font-awesome/home.png +0 -0
- package/lib/maps/symbols/font-awesome/info-circle.png +0 -0
- package/lib/maps/symbols/font-awesome/male.png +0 -0
- package/lib/maps/symbols/font-awesome/medkit.png +0 -0
- package/lib/maps/symbols/font-awesome/mobile.png +0 -0
- package/lib/maps/symbols/font-awesome/plus-circle.png +0 -0
- package/lib/maps/symbols/font-awesome/plus-square.png +0 -0
- package/lib/maps/symbols/font-awesome/plus.png +0 -0
- package/lib/maps/symbols/font-awesome/square.png +0 -0
- package/lib/maps/symbols/font-awesome/star.png +0 -0
- package/lib/maps/symbols/font-awesome/thumbs-down.png +0 -0
- package/lib/maps/symbols/font-awesome/thumbs-up.png +0 -0
- package/lib/maps/symbols/font-awesome/ticket.png +0 -0
- package/lib/maps/symbols/font-awesome/times-circle.png +0 -0
- package/lib/maps/symbols/font-awesome/times.png +0 -0
- package/lib/maps/symbols/font-awesome/tint.png +0 -0
- package/lib/maps/symbols/font-awesome/tree.png +0 -0
- package/lib/maps/symbols/font-awesome/university.png +0 -0
- package/lib/maps/symbols/font-awesome/usd.png +0 -0
- package/lib/maps/symbols/font-awesome/user.png +0 -0
- package/lib/maps/symbols/font-awesome/users.png +0 -0
- package/lib/maps/symbols/font-awesome/wheelchair.png +0 -0
- package/lib/maps/symbols/sdf-ize.sh +93 -0
- package/lib/maps/vectorMaps.d.ts +1 -0
- package/lib/maps/vectorMaps.js +20 -36
- package/lib/mwater_table_selection/IndicatorsListComponent.d.ts +4 -2
- package/lib/mwater_table_selection/IndicatorsListComponent.js +103 -34
- package/lib/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.d.ts +18 -0
- package/lib/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.js +80 -0
- package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.d.ts +26 -0
- package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.js +237 -51
- package/lib/mwater_table_selection/MWaterTableSelectComponent.d.ts +2 -2
- package/lib/mwater_table_selection/MWaterTableSelectComponent.js +9 -4
- package/lib/mwater_table_selection/MWaterWorkflowsSelectComponent.d.ts +19 -0
- package/lib/mwater_table_selection/MWaterWorkflowsSelectComponent.js +111 -0
- package/lib/quickfilter/QuickfiltersComponent.d.ts +3 -102
- package/lib/quickfilter/QuickfiltersComponent.js +53 -110
- package/lib/quickfilter/TextLiteralComponent.d.ts +23 -47
- package/lib/quickfilter/TextLiteralComponent.js +85 -82
- package/lib/widgets/MapWidget.js +4 -2
- package/lib/widgets/text/ExprItemEditorComponent.d.ts +3 -8
- package/lib/widgets/text/ExprItemEditorComponent.js +36 -33
- package/lib/widgets/text/ExprUpdateModalComponent.d.ts +1 -0
- package/package.json +2 -3
- package/src/MWaterContextComponent.tsx +1 -1
- package/src/{MWaterGlobalFiltersComponent.ts → MWaterGlobalFiltersComponent.tsx} +32 -33
- package/src/{MWaterLoaderComponent.ts → MWaterLoaderComponent.tsx} +17 -18
- package/src/UndoStack.ts +14 -6
- package/src/dashboards/DashboardComponent.tsx +5 -4
- package/src/dashboards/DashboardDesign.ts +1 -1
- package/src/dashboards/ServerDashboardDataSource.ts +0 -12
- package/src/dashboards/SettingsModalComponent.tsx +1 -1
- package/src/datagrids/DatagridComponent.tsx +30 -2
- package/src/datagrids/DatagridDesignerComponent.tsx +241 -229
- package/src/datagrids/DatagridViewComponent.tsx +3 -2
- package/src/datagrids/OrderBysDesignerComponent.tsx +61 -70
- package/src/index.css +45 -2
- package/src/index.ts +5 -11
- package/src/layouts/blocks/BlocksDisplayComponent.tsx +60 -5
- package/src/maps/BufferLayer.ts +14 -1
- package/src/maps/BufferLayerDesign.ts +1 -1
- package/src/maps/BufferLayerDesignerComponent.tsx +2 -1
- package/src/maps/ChoroplethLayer.ts +20 -7
- package/src/maps/ChoroplethLayerDesign.ts +5 -2
- package/src/maps/ChoroplethLayerDesigner.tsx +169 -165
- package/src/maps/DirectMapDataSource.ts +0 -12
- package/src/maps/EditHoverOver.tsx +9 -5
- package/src/maps/HoverContent.tsx +1 -1
- package/src/maps/LeafletMapComponent.tsx +10 -19
- package/src/maps/MapComponent.ts +0 -1
- package/src/maps/MapUtils.ts +13 -1
- package/src/maps/MarkersLayer.ts +22 -5
- package/src/maps/MarkersLayerDesign.ts +1 -1
- package/src/maps/MarkersLayerDesignerComponent.tsx +360 -0
- package/src/maps/ServerMapDataSource.ts +0 -12
- package/src/maps/VectorMapViewComponent.tsx +2 -13
- package/src/maps/symbols/font-awesome/asterisk.png +0 -0
- package/src/maps/symbols/font-awesome/ban.png +0 -0
- package/src/maps/symbols/font-awesome/beer.png +0 -0
- package/src/maps/symbols/font-awesome/bell.png +0 -0
- package/src/maps/symbols/font-awesome/bolt.png +0 -0
- package/src/maps/symbols/font-awesome/building.png +0 -0
- package/src/maps/symbols/font-awesome/bullseye.png +0 -0
- package/src/maps/symbols/font-awesome/bus.png +0 -0
- package/src/maps/symbols/font-awesome/caret-up.png +0 -0
- package/src/maps/symbols/font-awesome/certificate.png +0 -0
- package/src/maps/symbols/font-awesome/check-circle.png +0 -0
- package/src/maps/symbols/font-awesome/check.png +0 -0
- package/src/maps/symbols/font-awesome/chevron-circle-down.png +0 -0
- package/src/maps/symbols/font-awesome/chevron-circle-up.png +0 -0
- package/src/maps/symbols/font-awesome/cloud-rain.png +0 -0
- package/src/maps/symbols/font-awesome/cloud.png +0 -0
- package/src/maps/symbols/font-awesome/comment.png +0 -0
- package/src/maps/symbols/font-awesome/crosshairs.png +0 -0
- package/src/maps/symbols/font-awesome/dot-circle-o.png +0 -0
- package/src/maps/symbols/font-awesome/exclamation-circle.png +0 -0
- package/src/maps/symbols/font-awesome/exclamation-triangle.png +0 -0
- package/src/maps/symbols/font-awesome/female.png +0 -0
- package/src/maps/symbols/font-awesome/file.png +0 -0
- package/src/maps/symbols/font-awesome/flag.png +0 -0
- package/src/maps/symbols/font-awesome/flask.png +0 -0
- package/src/maps/symbols/font-awesome/h-square.png +0 -0
- package/src/maps/symbols/font-awesome/home.png +0 -0
- package/src/maps/symbols/font-awesome/info-circle.png +0 -0
- package/src/maps/symbols/font-awesome/male.png +0 -0
- package/src/maps/symbols/font-awesome/medkit.png +0 -0
- package/src/maps/symbols/font-awesome/mobile.png +0 -0
- package/src/maps/symbols/font-awesome/plus-circle.png +0 -0
- package/src/maps/symbols/font-awesome/plus-square.png +0 -0
- package/src/maps/symbols/font-awesome/plus.png +0 -0
- package/src/maps/symbols/font-awesome/square.png +0 -0
- package/src/maps/symbols/font-awesome/star.png +0 -0
- package/src/maps/symbols/font-awesome/thumbs-down.png +0 -0
- package/src/maps/symbols/font-awesome/thumbs-up.png +0 -0
- package/src/maps/symbols/font-awesome/ticket.png +0 -0
- package/src/maps/symbols/font-awesome/times-circle.png +0 -0
- package/src/maps/symbols/font-awesome/times.png +0 -0
- package/src/maps/symbols/font-awesome/tint.png +0 -0
- package/src/maps/symbols/font-awesome/tree.png +0 -0
- package/src/maps/symbols/font-awesome/university.png +0 -0
- package/src/maps/symbols/font-awesome/usd.png +0 -0
- package/src/maps/symbols/font-awesome/user.png +0 -0
- package/src/maps/symbols/font-awesome/users.png +0 -0
- package/src/maps/symbols/font-awesome/wheelchair.png +0 -0
- package/src/maps/symbols/sdf-ize.sh +93 -0
- package/src/maps/vectorMaps.tsx +20 -44
- package/src/mwater_table_selection/IndicatorsListComponent.tsx +165 -37
- package/src/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.tsx +111 -0
- package/src/mwater_table_selection/MWaterCompleteTableSelectComponent.tsx +373 -37
- package/src/mwater_table_selection/MWaterTableSelectComponent.tsx +12 -8
- package/src/mwater_table_selection/MWaterWorkflowsSelectComponent.tsx +159 -0
- package/src/quickfilter/{QuickfiltersComponent.ts → QuickfiltersComponent.tsx} +165 -158
- package/src/quickfilter/TextLiteralComponent.tsx +197 -0
- package/src/widgets/MapWidget.tsx +9 -1
- package/src/widgets/text/ExprItemEditorComponent.tsx +83 -77
- package/src/widgets/text/ExprUpdateModalComponent.tsx +1 -0
- package/test/UndoStackTests.ts +52 -1
- package/.storybook/config.js +0 -7
- package/.storybook/head.html +0 -3
- package/.storybook/webpack.config.js +0 -15
- package/src/maps/BingLayer.ts +0 -146
- package/src/maps/MarkersLayerDesignerComponent.ts +0 -374
- package/src/quickfilter/TextLiteralComponent.ts +0 -165
- package/stories/UpdateableComponent.js +0 -29
- package/stories/consoles.js +0 -202
- package/stories/dashboards.js +0 -217
- package/stories/datagridDesign.js +0 -114
- package/stories/datagrids.js +0 -69
- package/stories/dates.js +0 -80
- package/stories/exprcomponent.js +0 -43
- package/stories/index.js +0 -18
- package/stories/leaflet.js +0 -59
- package/stories/maps.js +0 -24
- package/stories/pivotChart.js +0 -235
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
# https://stackoverflow.com/questions/63299999/how-can-i-create-sdf-icons-used-in-mapbox-from-png#63314688
|
|
5
|
+
|
|
6
|
+
set -o pipefail
|
|
7
|
+
set -exu
|
|
8
|
+
|
|
9
|
+
cd "$(dirname "$0")"
|
|
10
|
+
|
|
11
|
+
MKTEMP="$(which gmktemp || which mktemp)"
|
|
12
|
+
TMPDIR1="$("$MKTEMP" -d)"
|
|
13
|
+
TMPDIR2="$("$MKTEMP" -d)"
|
|
14
|
+
|
|
15
|
+
trap "rm -rf '$TMPDIR1' '$TMPDIR2' ; pkill -P '$$'" EXIT
|
|
16
|
+
|
|
17
|
+
declare -a IMGFILES
|
|
18
|
+
|
|
19
|
+
IMGFILES=(
|
|
20
|
+
asterisk.png
|
|
21
|
+
ban.png
|
|
22
|
+
beer.png
|
|
23
|
+
bell.png
|
|
24
|
+
bolt.png
|
|
25
|
+
building.png
|
|
26
|
+
bullseye.png
|
|
27
|
+
bus.png
|
|
28
|
+
caret-up.png
|
|
29
|
+
certificate.png
|
|
30
|
+
check-circle.png
|
|
31
|
+
check.png
|
|
32
|
+
chevron-circle-down.png
|
|
33
|
+
chevron-circle-up.png
|
|
34
|
+
cloud-rain.png
|
|
35
|
+
cloud.png
|
|
36
|
+
comment.png
|
|
37
|
+
crosshairs.png
|
|
38
|
+
dot-circle-o.png
|
|
39
|
+
exclamation-circle.png
|
|
40
|
+
exclamation-triangle.png
|
|
41
|
+
female.png
|
|
42
|
+
file.png
|
|
43
|
+
flag.png
|
|
44
|
+
flask.png
|
|
45
|
+
h-square.png
|
|
46
|
+
home.png
|
|
47
|
+
info-circle.png
|
|
48
|
+
male.png
|
|
49
|
+
medkit.png
|
|
50
|
+
mobile.png
|
|
51
|
+
plus-circle.png
|
|
52
|
+
plus-square.png
|
|
53
|
+
plus.png
|
|
54
|
+
square.png
|
|
55
|
+
star.png
|
|
56
|
+
thumbs-down.png
|
|
57
|
+
thumbs-up.png
|
|
58
|
+
ticket.png
|
|
59
|
+
times-circle.png
|
|
60
|
+
times.png
|
|
61
|
+
tint.png
|
|
62
|
+
tree.png
|
|
63
|
+
university.png
|
|
64
|
+
usd.png
|
|
65
|
+
user.png
|
|
66
|
+
users.png
|
|
67
|
+
wheelchair.png
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
SVGINDIR="$(realpath -e "../../../../../apps/mwater-server/lib/routes/maps/marker-symbols/font-awesome")"
|
|
71
|
+
PNGOUTDIR="$(realpath "./font-awesome")"
|
|
72
|
+
|
|
73
|
+
rm -rvf "$PNGOUTDIR"
|
|
74
|
+
mkdir -pv "$PNGOUTDIR"
|
|
75
|
+
|
|
76
|
+
which image-sdf || npm install -g image-sdf
|
|
77
|
+
|
|
78
|
+
for IMGFILE in "${IMGFILES[@]}"
|
|
79
|
+
do
|
|
80
|
+
BASENAME="$(basename "$IMGFILE" .png)"
|
|
81
|
+
nice magick "$SVGINDIR/$BASENAME.svg" -channel RGB -negate -size 2000x2000 "$TMPDIR1/$BASENAME.png"
|
|
82
|
+
image-sdf "$TMPDIR1/$BASENAME.png" --spread 32 --downscale 2 --color black --output "$TMPDIR2/$BASENAME.png" &
|
|
83
|
+
done
|
|
84
|
+
wait
|
|
85
|
+
|
|
86
|
+
for IMGFILE in "$TMPDIR2"/*.png
|
|
87
|
+
do
|
|
88
|
+
magick "$IMGFILE" -resize 20x20 "$PNGOUTDIR/$(basename "$IMGFILE")" &
|
|
89
|
+
done
|
|
90
|
+
wait
|
|
91
|
+
|
|
92
|
+
cd "$PNGOUTDIR"
|
|
93
|
+
identify ./*.png
|
package/src/maps/vectorMaps.tsx
CHANGED
|
@@ -43,8 +43,9 @@ export function useVectorMap(options: {
|
|
|
43
43
|
scrollZoom?: boolean
|
|
44
44
|
dragPan?: boolean
|
|
45
45
|
touchZoomRotate?: boolean
|
|
46
|
+
padding?: number
|
|
46
47
|
}) {
|
|
47
|
-
const { divRef, bounds, scrollZoom, dragPan, touchZoomRotate } = options
|
|
48
|
+
const { divRef, bounds, scrollZoom, dragPan, touchZoomRotate, padding } = options
|
|
48
49
|
|
|
49
50
|
// Maplibre map
|
|
50
51
|
const [map, setMap] = useState<maplibregl.Map>()
|
|
@@ -89,9 +90,8 @@ export function useVectorMap(options: {
|
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
try {
|
|
92
|
-
const
|
|
93
|
+
const mapConstructorOptions: maplibregl.MapOptions = {
|
|
93
94
|
container: divRef,
|
|
94
|
-
bounds: bounds,
|
|
95
95
|
scrollZoom: scrollZoom === false ? false : true,
|
|
96
96
|
dragPan: dragPan === false ? false : true,
|
|
97
97
|
touchZoomRotate: touchZoomRotate === false ? false : true,
|
|
@@ -102,13 +102,21 @@ export function useVectorMap(options: {
|
|
|
102
102
|
layers: [],
|
|
103
103
|
sources: {}
|
|
104
104
|
},
|
|
105
|
-
// Prevent scrolling outside of world bounds
|
|
106
105
|
maxBounds: [
|
|
107
106
|
[-179.9, -85], // Southwest coordinates
|
|
108
107
|
[179.9, 85] // Northeast coordinates
|
|
109
108
|
],
|
|
110
109
|
preserveDrawingBuffer: printingModeEnabled
|
|
111
|
-
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (bounds) {
|
|
113
|
+
mapConstructorOptions.bounds = bounds
|
|
114
|
+
if (padding !== undefined) {
|
|
115
|
+
mapConstructorOptions.fitBoundsOptions = { padding }
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const m = new maplibregl.Map(mapConstructorOptions)
|
|
112
120
|
|
|
113
121
|
setHasWebGLContext(true)
|
|
114
122
|
|
|
@@ -240,9 +248,8 @@ export function useBaseStyle(baseLayer: BaseLayer) {
|
|
|
240
248
|
} else if (baseLayer == "bing_road") {
|
|
241
249
|
loadStyle(`https://api.maptiler.com/maps/streets-v2/style.json?key=${mapTilerApiKey}`)
|
|
242
250
|
} else if (baseLayer == "bing_aerial") {
|
|
243
|
-
//
|
|
244
|
-
|
|
245
|
-
// loadStyle(`https://api.maptiler.com/maps/hybrid/style.json?key=${mapTilerApiKey}`)
|
|
251
|
+
// Stadia Maps
|
|
252
|
+
loadStyle("https://tiles.stadiamaps.com/styles/alidade_satellite.json?api_key=835a418e-91f9-4eb8-9856-0883c3656c9d")
|
|
246
253
|
} else if (baseLayer == "blank") {
|
|
247
254
|
setBaseStyle({
|
|
248
255
|
version: 8,
|
|
@@ -310,7 +317,10 @@ export function AttributionControl(props: {
|
|
|
310
317
|
if (props.baseLayer == "bing_aerial") {
|
|
311
318
|
return (
|
|
312
319
|
<div className="newmap-attribution-control">
|
|
313
|
-
|
|
320
|
+
© <a href="https://stadiamaps.com/" target="_blank">Stadia Maps</a>
|
|
321
|
+
© <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a>
|
|
322
|
+
© <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>
|
|
323
|
+
© CNES, Distribution Airbus DS, © Airbus DS, © PlanetObserver (Contains Copernicus Data)
|
|
314
324
|
{props.extraText ? " " + props.extraText : null}
|
|
315
325
|
</div>
|
|
316
326
|
)
|
|
@@ -338,10 +348,7 @@ export function VectorMapLogo(props: {
|
|
|
338
348
|
}
|
|
339
349
|
|
|
340
350
|
if (props.baseLayer == "bing_aerial") {
|
|
341
|
-
return
|
|
342
|
-
src="https://dev.virtualearth.net/Branding/logo_powered_by.png"
|
|
343
|
-
style={{ position: "absolute", bottom: 38, left: 11, height: 22, zIndex: 1000, pointerEvents: "none" }}
|
|
344
|
-
/>
|
|
351
|
+
return null
|
|
345
352
|
}
|
|
346
353
|
|
|
347
354
|
return <img
|
|
@@ -350,36 +357,6 @@ export function VectorMapLogo(props: {
|
|
|
350
357
|
/>
|
|
351
358
|
}
|
|
352
359
|
|
|
353
|
-
async function loadBingBasemap(basemapType: "AerialWithLabels", opacity: number): Promise<maplibregl.StyleSpecification> {
|
|
354
|
-
// Load metadata
|
|
355
|
-
const bingApiKey = "Ao26dWY2IC8PjorsJKFaoR85EPXCnCohrJdisCWXIULAXFo0JAXquGauppTMQbyU"
|
|
356
|
-
|
|
357
|
-
const metadata = await fetch(`https://dev.virtualearth.net/REST/v1/Imagery/Metadata/${basemapType}?key=${bingApiKey}`).then((response) => response.json())
|
|
358
|
-
const resource = metadata.resourceSets[0].resources[0]
|
|
359
|
-
|
|
360
|
-
return {
|
|
361
|
-
sources: {
|
|
362
|
-
"bing_raster": {
|
|
363
|
-
type: "raster",
|
|
364
|
-
tiles: resource.imageUrlSubdomains.map((subdomain: string) =>
|
|
365
|
-
resource.imageUrl.replace("{subdomain}", subdomain).replace("{culture}", "").replace("http:", "https:")),
|
|
366
|
-
tileSize: resource.imageHeight,
|
|
367
|
-
}
|
|
368
|
-
},
|
|
369
|
-
layers: [
|
|
370
|
-
{
|
|
371
|
-
id: "bing_raster",
|
|
372
|
-
type: "raster",
|
|
373
|
-
source: "bing_raster",
|
|
374
|
-
paint: {
|
|
375
|
-
"raster-opacity": opacity
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
],
|
|
379
|
-
version: 8
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
360
|
/** Persists map bounds to local storage */
|
|
384
361
|
export function usePersistedMapBounds(map: Map | undefined, localStorageKey: string) {
|
|
385
362
|
const [bounds, setBounds] = useState<{ n: number, e: number, s: number, w: number } | null>(null)
|
|
@@ -421,4 +398,3 @@ export function usePersistedMapBounds(map: Map | undefined, localStorageKey: str
|
|
|
421
398
|
}
|
|
422
399
|
}, [map])
|
|
423
400
|
}
|
|
424
|
-
|
|
@@ -6,7 +6,7 @@ import * as uiComponents from "../UIComponents"
|
|
|
6
6
|
import { ExprUtils, Schema } from "@mwater/expressions"
|
|
7
7
|
import ModalPopupComponent from "@mwater/react-library/lib/ModalPopupComponent"
|
|
8
8
|
|
|
9
|
-
interface IndicatorsListComponentProps {
|
|
9
|
+
export interface IndicatorsListComponentProps {
|
|
10
10
|
/** Url to hit api */
|
|
11
11
|
apiUrl: string
|
|
12
12
|
/** Optional client */
|
|
@@ -31,7 +31,7 @@ interface IndicatorsListComponentState {
|
|
|
31
31
|
export class IndicatorsListComponent extends React.Component<IndicatorsListComponentProps, IndicatorsListComponentState> {
|
|
32
32
|
addIndicatorConfirmPopup: AddIndicatorConfirmPopupComponent | null
|
|
33
33
|
|
|
34
|
-
constructor(props:
|
|
34
|
+
constructor(props: IndicatorsListComponentProps) {
|
|
35
35
|
super(props)
|
|
36
36
|
this.state = {
|
|
37
37
|
indicators: null,
|
|
@@ -42,7 +42,7 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
|
|
|
42
42
|
componentDidMount() {
|
|
43
43
|
// Get names and basic of forms
|
|
44
44
|
const query: any = {}
|
|
45
|
-
query.fields = JSON.stringify({ "design.name": 1, "design.desc": 1, "design.recommended": 1, deprecated: 1 })
|
|
45
|
+
query.fields = JSON.stringify({ "design.name": 1, "design.desc": 1, "design.recommended": 1, deprecated: 1, "design.category": 1, "design.subcategory": 1, "design.code": 1, "design.organization": 1 })
|
|
46
46
|
query.client = this.props.client
|
|
47
47
|
|
|
48
48
|
// Get list of all indicator names
|
|
@@ -62,11 +62,7 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
|
|
|
62
62
|
)
|
|
63
63
|
|
|
64
64
|
return this.setState({
|
|
65
|
-
indicators:
|
|
66
|
-
id: indicator._id,
|
|
67
|
-
name: ExprUtils.localizeString(indicator.design.name, T.locale),
|
|
68
|
-
desc: ExprUtils.localizeString(indicator.design.desc, T.locale)
|
|
69
|
-
}))
|
|
65
|
+
indicators: indicators
|
|
70
66
|
})
|
|
71
67
|
}).fail((xhr: any) => {
|
|
72
68
|
return this.setState({ error: xhr.responseText })
|
|
@@ -102,25 +98,110 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
|
|
|
102
98
|
this.addIndicatorConfirmPopup!.show(tableId)
|
|
103
99
|
}
|
|
104
100
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
101
|
+
handleOpenIndicator = (id: string) => {
|
|
102
|
+
this.handleSelect("indicator_values:" + id)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Render a simplified version of IndicatorListComponent from mwater-portal
|
|
106
|
+
renderIndicatorList(indicators: any[], searchText: string) {
|
|
107
|
+
// Filter indicators based on search text
|
|
108
|
+
let filteredIndicators = indicators
|
|
109
|
+
if (searchText) {
|
|
110
|
+
const searchTerms = searchText.toLowerCase().split(" ")
|
|
111
|
+
filteredIndicators = indicators.filter(indicator => {
|
|
112
|
+
const searchFields = [
|
|
113
|
+
ExprUtils.localizeString(indicator.design.name, T.locale),
|
|
114
|
+
indicator.design.code,
|
|
115
|
+
indicator.design.organization,
|
|
116
|
+
indicator.design.category,
|
|
117
|
+
indicator.design.subcategory
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
return searchTerms.every(term =>
|
|
121
|
+
searchFields.some(field =>
|
|
122
|
+
field && field.toLowerCase().includes(term)
|
|
123
|
+
)
|
|
124
|
+
)
|
|
125
|
+
})
|
|
109
126
|
}
|
|
110
127
|
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
128
|
+
// Split into recommended and all indicators
|
|
129
|
+
const recommendedIndicators = filteredIndicators.filter(indicator => indicator.design.recommended)
|
|
130
|
+
const otherIndicators = filteredIndicators.filter(indicator => !indicator.design.recommended)
|
|
114
131
|
|
|
115
|
-
|
|
132
|
+
// Group by category
|
|
133
|
+
const groupByCategory = (indicators: any[]) => {
|
|
134
|
+
const categories: Record<string, any[]> = {}
|
|
116
135
|
|
|
117
|
-
indicators
|
|
118
|
-
|
|
119
|
-
|
|
136
|
+
indicators.forEach(indicator => {
|
|
137
|
+
const category = indicator.design.category || T`Uncategorized`
|
|
138
|
+
if (!categories[category]) {
|
|
139
|
+
categories[category] = []
|
|
140
|
+
}
|
|
141
|
+
categories[category].push(indicator)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
return categories
|
|
120
145
|
}
|
|
121
146
|
|
|
122
|
-
|
|
123
|
-
|
|
147
|
+
const recommendedByCategory = groupByCategory(recommendedIndicators)
|
|
148
|
+
const otherByCategory = groupByCategory(otherIndicators)
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<div>
|
|
152
|
+
{recommendedIndicators.length > 0 && (
|
|
153
|
+
<div>
|
|
154
|
+
<h4>{T`Recommended Indicators`}</h4>
|
|
155
|
+
{_.map(recommendedByCategory, (categoryIndicators, category) => (
|
|
156
|
+
<div key={category}>
|
|
157
|
+
<h5>{category}</h5>
|
|
158
|
+
<table className="table table-hover">
|
|
159
|
+
<tbody>
|
|
160
|
+
{_.map(categoryIndicators, indicator => (
|
|
161
|
+
<tr key={indicator._id} onClick={() => this.handleOpenIndicator(indicator._id)}>
|
|
162
|
+
<td>
|
|
163
|
+
<IndicatorListItemComponent
|
|
164
|
+
indicator={indicator}
|
|
165
|
+
onClick={() => this.handleOpenIndicator(indicator._id)}
|
|
166
|
+
/>
|
|
167
|
+
</td>
|
|
168
|
+
</tr>
|
|
169
|
+
))}
|
|
170
|
+
</tbody>
|
|
171
|
+
</table>
|
|
172
|
+
</div>
|
|
173
|
+
))}
|
|
174
|
+
</div>
|
|
175
|
+
)}
|
|
176
|
+
|
|
177
|
+
<h4>{T`All Indicators`}</h4>
|
|
178
|
+
{_.map(otherByCategory, (categoryIndicators, category) => (
|
|
179
|
+
<div key={category}>
|
|
180
|
+
<h5>{category}</h5>
|
|
181
|
+
<table className="table table-hover">
|
|
182
|
+
<tbody>
|
|
183
|
+
{_.map(categoryIndicators, indicator => (
|
|
184
|
+
<tr key={indicator._id} onClick={() => this.handleOpenIndicator(indicator._id)}>
|
|
185
|
+
<td>
|
|
186
|
+
<IndicatorListItemComponent
|
|
187
|
+
indicator={indicator}
|
|
188
|
+
onClick={() => this.handleOpenIndicator(indicator._id)}
|
|
189
|
+
/>
|
|
190
|
+
</td>
|
|
191
|
+
</tr>
|
|
192
|
+
))}
|
|
193
|
+
</tbody>
|
|
194
|
+
</table>
|
|
195
|
+
</div>
|
|
196
|
+
))}
|
|
197
|
+
</div>
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
render() {
|
|
202
|
+
if (this.state.error) {
|
|
203
|
+
return <div className="alert alert-danger">{this.state.error}</div>
|
|
204
|
+
}
|
|
124
205
|
|
|
125
206
|
let tables = _.filter(
|
|
126
207
|
this.props.schema.getTables(),
|
|
@@ -142,14 +223,12 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
|
|
|
142
223
|
<label>{T`Included Indicators:`}</label>
|
|
143
224
|
{tables.length > 0 ? (
|
|
144
225
|
<uiComponents.OptionListComponent
|
|
145
|
-
items={_.map(tables, (table) => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
})}
|
|
226
|
+
items={_.map(tables, (table) => ({
|
|
227
|
+
name: ExprUtils.localizeString(table.name, T.locale),
|
|
228
|
+
desc: ExprUtils.localizeString(table.desc, T.locale),
|
|
229
|
+
onClick: () => this.handleSelect(table.id),
|
|
230
|
+
onRemove: () => this.handleTableRemove(table)
|
|
231
|
+
}))}
|
|
153
232
|
/>
|
|
154
233
|
) : (
|
|
155
234
|
<div>{T`None`}</div>
|
|
@@ -161,7 +240,7 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
|
|
|
161
240
|
{!this.state.indicators || this.state.indicators.length === 0 ? (
|
|
162
241
|
<div className="alert alert-info">
|
|
163
242
|
<i className="fa fa-spinner fa-spin" />
|
|
164
|
-
|
|
243
|
+
{"\u00A0" + T`Loading...`}
|
|
165
244
|
</div>
|
|
166
245
|
) : (
|
|
167
246
|
<>
|
|
@@ -176,13 +255,7 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
|
|
|
176
255
|
onChange={(ev: any) => this.setState({ search: ev.target.value })}
|
|
177
256
|
/>
|
|
178
257
|
|
|
179
|
-
|
|
180
|
-
items={_.map(indicators, (indicator) => ({
|
|
181
|
-
name: indicator.name,
|
|
182
|
-
desc: indicator.desc,
|
|
183
|
-
onClick: this.handleSelect.bind(null, "indicator_values:" + indicator.id)
|
|
184
|
-
}))}
|
|
185
|
-
/>
|
|
258
|
+
{this.renderIndicatorList(this.state.indicators, this.state.search)}
|
|
186
259
|
</>
|
|
187
260
|
)}
|
|
188
261
|
</div>
|
|
@@ -190,6 +263,7 @@ export class IndicatorsListComponent extends React.Component<IndicatorsListCompo
|
|
|
190
263
|
}
|
|
191
264
|
}
|
|
192
265
|
|
|
266
|
+
|
|
193
267
|
interface AddIndicatorConfirmPopupComponentProps {
|
|
194
268
|
schema: Schema
|
|
195
269
|
/** Called with table selected */
|
|
@@ -281,3 +355,57 @@ are certain that you want to use the raw indicator table`}
|
|
|
281
355
|
)
|
|
282
356
|
}
|
|
283
357
|
}
|
|
358
|
+
|
|
359
|
+
// Single indicator item in a list
|
|
360
|
+
// Local port of the class found in mwater-portal
|
|
361
|
+
class IndicatorListItemComponent extends React.Component<{
|
|
362
|
+
indicator: any
|
|
363
|
+
onClick: any
|
|
364
|
+
}> {
|
|
365
|
+
|
|
366
|
+
renderIcon() {
|
|
367
|
+
switch (this.props.indicator.type) {
|
|
368
|
+
case "expression":
|
|
369
|
+
// R 'i', className: "text-muted fa fa-fw fa-calculator"
|
|
370
|
+
return null
|
|
371
|
+
case "response":
|
|
372
|
+
// R 'i', className: "text-muted fa fa-fw fa-list-alt"
|
|
373
|
+
return null
|
|
374
|
+
case "set":
|
|
375
|
+
return (
|
|
376
|
+
<span className="fa-stack" style={{ paddingRight: 6 }}>
|
|
377
|
+
<i className="fa fa-th-list fa-stack-1x text-muted" />
|
|
378
|
+
<i className="fa fa-circle fa-stack-1x" style={{ color: "white", paddingLeft: 15 }} />
|
|
379
|
+
<i className="fa fa-check-circle fa-stack-1x text-primary" style={{ paddingLeft: 15 }} />
|
|
380
|
+
</span>
|
|
381
|
+
)
|
|
382
|
+
}
|
|
383
|
+
return null
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
render() {
|
|
387
|
+
return (
|
|
388
|
+
<div onClick={this.props.onClick} style={{ cursor: "pointer" }}>
|
|
389
|
+
<div key="name" style={{ fontWeight: "bold" }}>
|
|
390
|
+
{this.renderIcon()}
|
|
391
|
+
{ExprUtils.localizeString(this.props.indicator.design.name, T.locale)}
|
|
392
|
+
{this.props.indicator.design.code ? ` (${this.props.indicator.design.code})` : undefined}
|
|
393
|
+
{this.props.indicator.design.organization ? (
|
|
394
|
+
<span className="text-muted"> {T`by ${this.props.indicator.design.organization}`}</span>
|
|
395
|
+
) : undefined}
|
|
396
|
+
</div>
|
|
397
|
+
|
|
398
|
+
<div key="desc" className="text-muted">
|
|
399
|
+
{ExprUtils.localizeString(this.props.indicator.design.desc, T.locale)}
|
|
400
|
+
{this.props.indicator.design.category
|
|
401
|
+
? [
|
|
402
|
+
` (${this.props.indicator.design.category}`,
|
|
403
|
+
this.props.indicator.design.subcategory ? `/${this.props.indicator.design.subcategory}` : undefined,
|
|
404
|
+
`)`
|
|
405
|
+
]
|
|
406
|
+
: undefined}
|
|
407
|
+
</div>
|
|
408
|
+
</div>
|
|
409
|
+
)
|
|
410
|
+
}
|
|
411
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import _ from "lodash"
|
|
2
|
+
import { Schema, ExprUtils } from "@mwater/expressions"
|
|
3
|
+
import { useState, useEffect } from "react"
|
|
4
|
+
import React from "react"
|
|
5
|
+
import { OptionListComponent } from "../UIComponents"
|
|
6
|
+
import { TextInput } from "@mwater/react-library/lib/bootstrap"
|
|
7
|
+
|
|
8
|
+
interface MWaterCalculatedDataSourcesListComponentProps {
|
|
9
|
+
apiUrl: string
|
|
10
|
+
schema: Schema
|
|
11
|
+
client?: string
|
|
12
|
+
user?: string
|
|
13
|
+
onChange: (tableId: string | null) => void
|
|
14
|
+
extraTables: string[]
|
|
15
|
+
onExtraTableAdd: (tableId: string) => void
|
|
16
|
+
onExtraTableRemove: (tableId: string) => void
|
|
17
|
+
locale?: string
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A list of calculated data sources that can be selected.
|
|
22
|
+
*/
|
|
23
|
+
export const MWaterCalculatedDataSourcesListComponent = (props: MWaterCalculatedDataSourcesListComponentProps) => {
|
|
24
|
+
const [calculatedSources, setCalculatedSources] = useState<CalculatedSource[]>()
|
|
25
|
+
const [search, setSearch] = useState<string | null>("")
|
|
26
|
+
const [extraTableNeeded, setExtraTableNeeded] = useState<string>()
|
|
27
|
+
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
fetch(`${props.apiUrl}calculated_data_sources?client=${props.client || ""}`)
|
|
30
|
+
.then((response) => response.json())
|
|
31
|
+
.then((body: CalculatedSource[]) => {
|
|
32
|
+
// Filter out calculated data sources that have never been calculated
|
|
33
|
+
const calculatedSources = body.filter((s) => s.last_calculated)
|
|
34
|
+
|
|
35
|
+
setCalculatedSources(
|
|
36
|
+
_.sortByAll(calculatedSources, [
|
|
37
|
+
(s) => (props.extraTables.some((t) => t == `calculated:${s._sid}`) ? 0 : 1),
|
|
38
|
+
(s) => ExprUtils.localizeString(s.name, props.locale)
|
|
39
|
+
])
|
|
40
|
+
)
|
|
41
|
+
})
|
|
42
|
+
}, [])
|
|
43
|
+
|
|
44
|
+
useEffect(() => {
|
|
45
|
+
if (extraTableNeeded && props.schema.getTable(extraTableNeeded)) {
|
|
46
|
+
props.onChange(extraTableNeeded)
|
|
47
|
+
}
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
const selectTable = (source: CalculatedSource) => {
|
|
51
|
+
const qualifiedTableId = `calculated:${source._sid}`
|
|
52
|
+
|
|
53
|
+
if (props.schema.getTable(qualifiedTableId)) {
|
|
54
|
+
props.onChange(qualifiedTableId)
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
setExtraTableNeeded(qualifiedTableId)
|
|
59
|
+
props.onExtraTableAdd(qualifiedTableId)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const handleRemove = (source: CalculatedSource) => {
|
|
63
|
+
const match = props.extraTables.find((t) => t == `calculated:${source._sid}`)
|
|
64
|
+
if (match) {
|
|
65
|
+
if (confirm(T`Remove this table? Some widgets may not work correctly.`)) {
|
|
66
|
+
props.onChange(null)
|
|
67
|
+
props.onExtraTableRemove(match)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!calculatedSources || extraTableNeeded) {
|
|
73
|
+
return (
|
|
74
|
+
<div>
|
|
75
|
+
<i className="fa fa-spin fa-spinner" /> {T`Loading...`}
|
|
76
|
+
</div>
|
|
77
|
+
)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const renderCalculatedSources = () => {
|
|
81
|
+
const items = calculatedSources
|
|
82
|
+
.map((s) => {
|
|
83
|
+
const alreadyIncluded = props.extraTables.some((t) => t == `calculated:${s._sid}`)
|
|
84
|
+
return {
|
|
85
|
+
name: ExprUtils.localizeString(s.name, props.locale) || "",
|
|
86
|
+
desc: s.description ? ExprUtils.localizeString(s.description, props.locale) || "" : undefined,
|
|
87
|
+
onClick: () => selectTable(s),
|
|
88
|
+
onRemove: alreadyIncluded ? handleRemove.bind(null, s) : undefined
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
.filter((item) => !search || item.name.toLowerCase().includes(search.toLowerCase()))
|
|
92
|
+
|
|
93
|
+
return <OptionListComponent items={items} />
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return (
|
|
97
|
+
<div>
|
|
98
|
+
<TextInput value={search} onChange={setSearch} placeholder={T`Search...`} searchIcon />
|
|
99
|
+
<br/>
|
|
100
|
+
{renderCalculatedSources()}
|
|
101
|
+
</div>
|
|
102
|
+
)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
interface CalculatedSource {
|
|
106
|
+
_id: string
|
|
107
|
+
_sid: number
|
|
108
|
+
name: { _base: string; [code: string]: string }
|
|
109
|
+
description?: { _base: string; [code: string]: string }
|
|
110
|
+
last_calculated?: string
|
|
111
|
+
}
|