@mwater/visualization 5.5.0 → 5.6.1
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/ColorComponent.js +2 -2
- 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/TranslationsTabComponent.d.ts +34 -0
- package/lib/TranslationsTabComponent.js +256 -0
- package/lib/UndoStack.d.ts +2 -1
- package/lib/UndoStack.js +12 -6
- package/lib/dashboards/DashboardComponent.js +6 -5
- package/lib/dashboards/DashboardDesign.d.ts +1 -1
- package/lib/dashboards/ServerDashboardDataSource.d.ts +0 -1
- package/lib/dashboards/ServerDashboardDataSource.js +0 -25
- package/lib/dashboards/SettingsModalComponent.js +9 -233
- package/lib/datagrids/DatagridComponent.js +27 -2
- package/lib/datagrids/DatagridDesignerComponent.d.ts +2 -3
- package/lib/datagrids/DatagridDesignerComponent.js +108 -120
- package/lib/datagrids/DatagridViewComponent.js +33 -6
- 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.d.ts +0 -13
- package/lib/maps/BufferLayer.js +24 -237
- package/lib/maps/BufferLayerDesign.d.ts +1 -1
- package/lib/maps/BufferLayerDesignerComponent.d.ts +1 -1
- package/lib/maps/BufferLayerDesignerComponent.js +2 -7
- package/lib/maps/ChoroplethLayer.d.ts +1 -16
- package/lib/maps/ChoroplethLayer.js +25 -358
- 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/ClusterLayer.d.ts +0 -9
- package/lib/maps/ClusterLayer.js +0 -250
- package/lib/maps/DirectMapDataSource.js +1 -48
- package/lib/maps/EditHoverOver.d.ts +4 -3
- package/lib/maps/EditHoverOver.js +3 -3
- package/lib/maps/GridLayer.d.ts +0 -15
- package/lib/maps/GridLayer.js +0 -212
- package/lib/maps/HoverContent.js +1 -1
- package/lib/maps/Layer.d.ts +1 -26
- package/lib/maps/Layer.js +0 -13
- package/lib/maps/LeafletMapComponent.js +10 -19
- package/lib/maps/MapComponent.d.ts +19 -35
- package/lib/maps/MapComponent.js +135 -77
- package/lib/maps/MapControlComponent.d.ts +4 -5
- package/lib/maps/MapControlComponent.js +5 -12
- package/lib/maps/MapDesign.d.ts +8 -0
- package/lib/maps/MapDesignerComponent.d.ts +2 -0
- package/lib/maps/MapDesignerComponent.js +7 -2
- package/lib/maps/MapLayerDataSource.d.ts +0 -4
- package/lib/maps/MapLayerViewDesignerComponent.d.ts +3 -1
- package/lib/maps/MapLayerViewDesignerComponent.js +5 -1
- package/lib/maps/MapLayersDesignerComponent.d.ts +2 -0
- package/lib/maps/MapLayersDesignerComponent.js +2 -1
- package/lib/maps/MapTranslationsTab.d.ts +15 -0
- package/lib/maps/MapTranslationsTab.js +47 -0
- package/lib/maps/MapUtils.d.ts +11 -0
- package/lib/maps/MapUtils.js +57 -1
- package/lib/maps/MapViewComponent.d.ts +1 -1
- package/lib/maps/MapViewComponent.js +1 -8
- package/lib/maps/MarkersLayer.d.ts +1 -14
- package/lib/maps/MarkersLayer.js +89 -254
- package/lib/maps/MarkersLayerDesign.d.ts +5 -1
- package/lib/maps/MarkersLayerDesignerComponent.d.ts +32 -57
- package/lib/maps/MarkersLayerDesignerComponent.js +158 -134
- package/lib/maps/ServerMapDataSource.d.ts +0 -1
- package/lib/maps/ServerMapDataSource.js +0 -25
- package/lib/maps/SwitchableTileUrlLayer.d.ts +0 -2
- package/lib/maps/SwitchableTileUrlLayer.js +0 -9
- package/lib/maps/TileUrlLayer.d.ts +0 -1
- package/lib/maps/TileUrlLayer.js +0 -5
- package/lib/maps/VectorMapViewComponent.js +13 -10
- 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 +6 -6
- package/lib/maps/vectorMaps.js +33 -45
- 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 +6 -3
- 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 +3 -4
- package/src/ColorComponent.tsx +2 -2
- package/src/MWaterContextComponent.tsx +1 -1
- package/src/{MWaterGlobalFiltersComponent.ts → MWaterGlobalFiltersComponent.tsx} +32 -33
- package/src/{MWaterLoaderComponent.ts → MWaterLoaderComponent.tsx} +17 -18
- package/src/TranslationsTabComponent.tsx +429 -0
- package/src/UndoStack.ts +14 -6
- package/src/dashboards/DashboardComponent.tsx +6 -5
- package/src/dashboards/DashboardDesign.ts +1 -1
- package/src/dashboards/ServerDashboardDataSource.ts +0 -31
- package/src/dashboards/SettingsModalComponent.tsx +27 -383
- package/src/datagrids/DatagridComponent.tsx +36 -2
- package/src/datagrids/DatagridDesignerComponent.tsx +241 -229
- package/src/datagrids/DatagridViewComponent.tsx +44 -7
- 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 +30 -263
- package/src/maps/BufferLayerDesign.ts +1 -1
- package/src/maps/BufferLayerDesignerComponent.tsx +2 -7
- package/src/maps/ChoroplethLayer.ts +30 -394
- package/src/maps/ChoroplethLayerDesign.ts +5 -2
- package/src/maps/ChoroplethLayerDesigner.tsx +169 -165
- package/src/maps/ClusterLayer.ts +0 -274
- package/src/maps/DirectMapDataSource.ts +2 -61
- package/src/maps/EditHoverOver.tsx +9 -5
- package/src/maps/GridLayer.ts +0 -224
- package/src/maps/HoverContent.tsx +1 -1
- package/src/maps/Layer.ts +1 -35
- package/src/maps/LeafletMapComponent.tsx +10 -19
- package/src/maps/MapComponent.tsx +448 -0
- package/src/maps/MapControlComponent.tsx +41 -0
- package/src/maps/MapDesign.ts +6 -0
- package/src/maps/MapDesignerComponent.tsx +18 -1
- package/src/maps/MapLayerDataSource.ts +0 -5
- package/src/maps/MapLayerViewDesignerComponent.ts +9 -2
- package/src/maps/MapLayersDesignerComponent.ts +4 -1
- package/src/maps/MapTranslationsTab.tsx +53 -0
- package/src/maps/MapUtils.ts +61 -1
- package/src/maps/MapViewComponent.tsx +2 -8
- package/src/maps/MarkersLayer.ts +101 -275
- package/src/maps/MarkersLayerDesign.ts +7 -1
- package/src/maps/MarkersLayerDesignerComponent.tsx +436 -0
- package/src/maps/ServerMapDataSource.ts +0 -31
- package/src/maps/SwitchableTileUrlLayer.tsx +0 -11
- package/src/maps/TileUrlLayer.tsx +0 -6
- package/src/maps/VectorMapViewComponent.tsx +15 -15
- 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 +32 -53
- 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 +11 -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/MapComponent.ts +0 -312
- package/src/maps/MapControlComponent.ts +0 -46
- package/src/maps/MarkersLayerDesignerComponent.ts +0 -374
- package/src/maps/RasterMapViewComponent.ts +0 -345
- 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
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -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
|
@@ -7,6 +7,9 @@ import "maplibre-gl/dist/maplibre-gl.css"
|
|
|
7
7
|
import "./VectorMapViewComponent.css"
|
|
8
8
|
import React from "react"
|
|
9
9
|
|
|
10
|
+
// Re-export maplibregl for consumers
|
|
11
|
+
export { default as maplibregl } from "maplibre-gl"
|
|
12
|
+
|
|
10
13
|
/** Set to true to enable printing by preserving the drawing buffer */
|
|
11
14
|
let printingModeEnabled = false
|
|
12
15
|
|
|
@@ -29,11 +32,6 @@ export function getMapTilerApiKey(): string {
|
|
|
29
32
|
return mapTilerApiKey
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
/** Check if vector maps are enabled by setting API key */
|
|
33
|
-
export function areVectorMapsEnabled() {
|
|
34
|
-
return mapTilerApiKey !== ""
|
|
35
|
-
}
|
|
36
|
-
|
|
37
35
|
export type BaseLayer = "bing_road" | "bing_aerial" | "cartodb_positron" | "cartodb_dark_matter" | "blank"
|
|
38
36
|
|
|
39
37
|
/** Loads a vector map, refreshing the WebGL context as needed */
|
|
@@ -43,8 +41,9 @@ export function useVectorMap(options: {
|
|
|
43
41
|
scrollZoom?: boolean
|
|
44
42
|
dragPan?: boolean
|
|
45
43
|
touchZoomRotate?: boolean
|
|
44
|
+
padding?: number
|
|
46
45
|
}) {
|
|
47
|
-
const { divRef, bounds, scrollZoom, dragPan, touchZoomRotate } = options
|
|
46
|
+
const { divRef, bounds, scrollZoom, dragPan, touchZoomRotate, padding } = options
|
|
48
47
|
|
|
49
48
|
// Maplibre map
|
|
50
49
|
const [map, setMap] = useState<maplibregl.Map>()
|
|
@@ -89,9 +88,8 @@ export function useVectorMap(options: {
|
|
|
89
88
|
}
|
|
90
89
|
|
|
91
90
|
try {
|
|
92
|
-
const
|
|
91
|
+
const mapConstructorOptions: maplibregl.MapOptions = {
|
|
93
92
|
container: divRef,
|
|
94
|
-
bounds: bounds,
|
|
95
93
|
scrollZoom: scrollZoom === false ? false : true,
|
|
96
94
|
dragPan: dragPan === false ? false : true,
|
|
97
95
|
touchZoomRotate: touchZoomRotate === false ? false : true,
|
|
@@ -102,13 +100,24 @@ export function useVectorMap(options: {
|
|
|
102
100
|
layers: [],
|
|
103
101
|
sources: {}
|
|
104
102
|
},
|
|
105
|
-
// Prevent scrolling outside of world bounds
|
|
106
103
|
maxBounds: [
|
|
107
104
|
[-179.9, -85], // Southwest coordinates
|
|
108
105
|
[179.9, 85] // Northeast coordinates
|
|
109
106
|
],
|
|
110
|
-
|
|
111
|
-
|
|
107
|
+
// In maplibre-gl v5+, WebGL context options must be in canvasContextAttributes
|
|
108
|
+
canvasContextAttributes: {
|
|
109
|
+
preserveDrawingBuffer: printingModeEnabled
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (bounds) {
|
|
114
|
+
mapConstructorOptions.bounds = bounds
|
|
115
|
+
if (padding !== undefined) {
|
|
116
|
+
mapConstructorOptions.fitBoundsOptions = { padding }
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const m = new maplibregl.Map(mapConstructorOptions)
|
|
112
121
|
|
|
113
122
|
setHasWebGLContext(true)
|
|
114
123
|
|
|
@@ -135,10 +144,12 @@ export function useVectorMap(options: {
|
|
|
135
144
|
// Check if known
|
|
136
145
|
const mapSymbol = getMapSymbols().find((s) => s.value == ev.id)
|
|
137
146
|
if (mapSymbol) {
|
|
138
|
-
m.loadImage(mapSymbol.url
|
|
139
|
-
if (
|
|
140
|
-
m.addImage(mapSymbol.value,
|
|
147
|
+
m.loadImage(mapSymbol.url).then((response) => {
|
|
148
|
+
if (response && response.data && !m.hasImage(mapSymbol.value)) {
|
|
149
|
+
m.addImage(mapSymbol.value, response.data, { sdf: true })
|
|
141
150
|
}
|
|
151
|
+
}).catch((err) => {
|
|
152
|
+
console.error("Error loading map symbol:", err)
|
|
142
153
|
})
|
|
143
154
|
}
|
|
144
155
|
})
|
|
@@ -240,9 +251,8 @@ export function useBaseStyle(baseLayer: BaseLayer) {
|
|
|
240
251
|
} else if (baseLayer == "bing_road") {
|
|
241
252
|
loadStyle(`https://api.maptiler.com/maps/streets-v2/style.json?key=${mapTilerApiKey}`)
|
|
242
253
|
} else if (baseLayer == "bing_aerial") {
|
|
243
|
-
//
|
|
244
|
-
|
|
245
|
-
// loadStyle(`https://api.maptiler.com/maps/hybrid/style.json?key=${mapTilerApiKey}`)
|
|
254
|
+
// Stadia Maps
|
|
255
|
+
loadStyle("https://tiles.stadiamaps.com/styles/alidade_satellite.json?api_key=835a418e-91f9-4eb8-9856-0883c3656c9d")
|
|
246
256
|
} else if (baseLayer == "blank") {
|
|
247
257
|
setBaseStyle({
|
|
248
258
|
version: 8,
|
|
@@ -310,7 +320,10 @@ export function AttributionControl(props: {
|
|
|
310
320
|
if (props.baseLayer == "bing_aerial") {
|
|
311
321
|
return (
|
|
312
322
|
<div className="newmap-attribution-control">
|
|
313
|
-
|
|
323
|
+
© <a href="https://stadiamaps.com/" target="_blank">Stadia Maps</a>
|
|
324
|
+
© <a href="https://openmaptiles.org/" target="_blank">OpenMapTiles</a>
|
|
325
|
+
© <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>
|
|
326
|
+
© CNES, Distribution Airbus DS, © Airbus DS, © PlanetObserver (Contains Copernicus Data)
|
|
314
327
|
{props.extraText ? " " + props.extraText : null}
|
|
315
328
|
</div>
|
|
316
329
|
)
|
|
@@ -338,10 +351,7 @@ export function VectorMapLogo(props: {
|
|
|
338
351
|
}
|
|
339
352
|
|
|
340
353
|
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
|
-
/>
|
|
354
|
+
return null
|
|
345
355
|
}
|
|
346
356
|
|
|
347
357
|
return <img
|
|
@@ -350,36 +360,6 @@ export function VectorMapLogo(props: {
|
|
|
350
360
|
/>
|
|
351
361
|
}
|
|
352
362
|
|
|
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
363
|
/** Persists map bounds to local storage */
|
|
384
364
|
export function usePersistedMapBounds(map: Map | undefined, localStorageKey: string) {
|
|
385
365
|
const [bounds, setBounds] = useState<{ n: number, e: number, s: number, w: number } | null>(null)
|
|
@@ -421,4 +401,3 @@ export function usePersistedMapBounds(map: Map | undefined, localStorageKey: str
|
|
|
421
401
|
}
|
|
422
402
|
}, [map])
|
|
423
403
|
}
|
|
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
|
+
}
|