@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.
Files changed (222) hide show
  1. package/lib/MWaterContextComponent.d.ts +1 -1
  2. package/lib/MWaterGlobalFiltersComponent.d.ts +2 -2
  3. package/lib/MWaterGlobalFiltersComponent.js +11 -20
  4. package/lib/MWaterLoaderComponent.d.ts +4 -13
  5. package/lib/MWaterLoaderComponent.js +2 -11
  6. package/lib/UndoStack.d.ts +2 -1
  7. package/lib/UndoStack.js +12 -6
  8. package/lib/dashboards/DashboardComponent.js +5 -4
  9. package/lib/dashboards/DashboardDesign.d.ts +1 -1
  10. package/lib/dashboards/ServerDashboardDataSource.js +0 -10
  11. package/lib/dashboards/SettingsModalComponent.js +1 -1
  12. package/lib/datagrids/DatagridComponent.js +22 -2
  13. package/lib/datagrids/DatagridDesignerComponent.d.ts +2 -3
  14. package/lib/datagrids/DatagridDesignerComponent.js +108 -120
  15. package/lib/datagrids/DatagridViewComponent.js +3 -2
  16. package/lib/datagrids/OrderBysDesignerComponent.d.ts +7 -7
  17. package/lib/datagrids/OrderBysDesignerComponent.js +19 -28
  18. package/lib/index.css +45 -2
  19. package/lib/index.d.ts +5 -5
  20. package/lib/index.js +2 -3
  21. package/lib/layouts/blocks/BlocksDisplayComponent.d.ts +8 -1
  22. package/lib/layouts/blocks/BlocksDisplayComponent.js +46 -4
  23. package/lib/maps/BufferLayer.js +12 -0
  24. package/lib/maps/BufferLayerDesign.d.ts +1 -1
  25. package/lib/maps/BufferLayerDesignerComponent.js +2 -2
  26. package/lib/maps/ChoroplethLayer.js +12 -0
  27. package/lib/maps/ChoroplethLayerDesign.d.ts +5 -2
  28. package/lib/maps/ChoroplethLayerDesigner.d.ts +10 -32
  29. package/lib/maps/ChoroplethLayerDesigner.js +58 -89
  30. package/lib/maps/DirectMapDataSource.js +0 -10
  31. package/lib/maps/EditHoverOver.d.ts +4 -3
  32. package/lib/maps/EditHoverOver.js +3 -3
  33. package/lib/maps/HoverContent.js +1 -1
  34. package/lib/maps/LeafletMapComponent.js +10 -19
  35. package/lib/maps/MapComponent.js +0 -1
  36. package/lib/maps/MapUtils.js +10 -1
  37. package/lib/maps/MarkersLayer.js +18 -2
  38. package/lib/maps/MarkersLayerDesign.d.ts +1 -1
  39. package/lib/maps/MarkersLayerDesignerComponent.d.ts +12 -41
  40. package/lib/maps/MarkersLayerDesignerComponent.js +81 -111
  41. package/lib/maps/ServerMapDataSource.js +0 -10
  42. package/lib/maps/VectorMapViewComponent.js +1 -9
  43. package/lib/maps/symbols/font-awesome/asterisk.png +0 -0
  44. package/lib/maps/symbols/font-awesome/ban.png +0 -0
  45. package/lib/maps/symbols/font-awesome/beer.png +0 -0
  46. package/lib/maps/symbols/font-awesome/bell.png +0 -0
  47. package/lib/maps/symbols/font-awesome/bolt.png +0 -0
  48. package/lib/maps/symbols/font-awesome/building.png +0 -0
  49. package/lib/maps/symbols/font-awesome/bullseye.png +0 -0
  50. package/lib/maps/symbols/font-awesome/bus.png +0 -0
  51. package/lib/maps/symbols/font-awesome/caret-up.png +0 -0
  52. package/lib/maps/symbols/font-awesome/certificate.png +0 -0
  53. package/lib/maps/symbols/font-awesome/check-circle.png +0 -0
  54. package/lib/maps/symbols/font-awesome/check.png +0 -0
  55. package/lib/maps/symbols/font-awesome/chevron-circle-down.png +0 -0
  56. package/lib/maps/symbols/font-awesome/chevron-circle-up.png +0 -0
  57. package/lib/maps/symbols/font-awesome/cloud-rain.png +0 -0
  58. package/lib/maps/symbols/font-awesome/cloud.png +0 -0
  59. package/lib/maps/symbols/font-awesome/comment.png +0 -0
  60. package/lib/maps/symbols/font-awesome/crosshairs.png +0 -0
  61. package/lib/maps/symbols/font-awesome/dot-circle-o.png +0 -0
  62. package/lib/maps/symbols/font-awesome/exclamation-circle.png +0 -0
  63. package/lib/maps/symbols/font-awesome/exclamation-triangle.png +0 -0
  64. package/lib/maps/symbols/font-awesome/female.png +0 -0
  65. package/lib/maps/symbols/font-awesome/file.png +0 -0
  66. package/lib/maps/symbols/font-awesome/flag.png +0 -0
  67. package/lib/maps/symbols/font-awesome/flask.png +0 -0
  68. package/lib/maps/symbols/font-awesome/h-square.png +0 -0
  69. package/lib/maps/symbols/font-awesome/home.png +0 -0
  70. package/lib/maps/symbols/font-awesome/info-circle.png +0 -0
  71. package/lib/maps/symbols/font-awesome/male.png +0 -0
  72. package/lib/maps/symbols/font-awesome/medkit.png +0 -0
  73. package/lib/maps/symbols/font-awesome/mobile.png +0 -0
  74. package/lib/maps/symbols/font-awesome/plus-circle.png +0 -0
  75. package/lib/maps/symbols/font-awesome/plus-square.png +0 -0
  76. package/lib/maps/symbols/font-awesome/plus.png +0 -0
  77. package/lib/maps/symbols/font-awesome/square.png +0 -0
  78. package/lib/maps/symbols/font-awesome/star.png +0 -0
  79. package/lib/maps/symbols/font-awesome/thumbs-down.png +0 -0
  80. package/lib/maps/symbols/font-awesome/thumbs-up.png +0 -0
  81. package/lib/maps/symbols/font-awesome/ticket.png +0 -0
  82. package/lib/maps/symbols/font-awesome/times-circle.png +0 -0
  83. package/lib/maps/symbols/font-awesome/times.png +0 -0
  84. package/lib/maps/symbols/font-awesome/tint.png +0 -0
  85. package/lib/maps/symbols/font-awesome/tree.png +0 -0
  86. package/lib/maps/symbols/font-awesome/university.png +0 -0
  87. package/lib/maps/symbols/font-awesome/usd.png +0 -0
  88. package/lib/maps/symbols/font-awesome/user.png +0 -0
  89. package/lib/maps/symbols/font-awesome/users.png +0 -0
  90. package/lib/maps/symbols/font-awesome/wheelchair.png +0 -0
  91. package/lib/maps/symbols/sdf-ize.sh +93 -0
  92. package/lib/maps/vectorMaps.d.ts +1 -0
  93. package/lib/maps/vectorMaps.js +20 -36
  94. package/lib/mwater_table_selection/IndicatorsListComponent.d.ts +4 -2
  95. package/lib/mwater_table_selection/IndicatorsListComponent.js +103 -34
  96. package/lib/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.d.ts +18 -0
  97. package/lib/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.js +80 -0
  98. package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.d.ts +26 -0
  99. package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.js +237 -51
  100. package/lib/mwater_table_selection/MWaterTableSelectComponent.d.ts +2 -2
  101. package/lib/mwater_table_selection/MWaterTableSelectComponent.js +9 -4
  102. package/lib/mwater_table_selection/MWaterWorkflowsSelectComponent.d.ts +19 -0
  103. package/lib/mwater_table_selection/MWaterWorkflowsSelectComponent.js +111 -0
  104. package/lib/quickfilter/QuickfiltersComponent.d.ts +3 -102
  105. package/lib/quickfilter/QuickfiltersComponent.js +53 -110
  106. package/lib/quickfilter/TextLiteralComponent.d.ts +23 -47
  107. package/lib/quickfilter/TextLiteralComponent.js +85 -82
  108. package/lib/widgets/MapWidget.js +4 -2
  109. package/lib/widgets/text/ExprItemEditorComponent.d.ts +3 -8
  110. package/lib/widgets/text/ExprItemEditorComponent.js +36 -33
  111. package/lib/widgets/text/ExprUpdateModalComponent.d.ts +1 -0
  112. package/package.json +2 -3
  113. package/src/MWaterContextComponent.tsx +1 -1
  114. package/src/{MWaterGlobalFiltersComponent.ts → MWaterGlobalFiltersComponent.tsx} +32 -33
  115. package/src/{MWaterLoaderComponent.ts → MWaterLoaderComponent.tsx} +17 -18
  116. package/src/UndoStack.ts +14 -6
  117. package/src/dashboards/DashboardComponent.tsx +5 -4
  118. package/src/dashboards/DashboardDesign.ts +1 -1
  119. package/src/dashboards/ServerDashboardDataSource.ts +0 -12
  120. package/src/dashboards/SettingsModalComponent.tsx +1 -1
  121. package/src/datagrids/DatagridComponent.tsx +30 -2
  122. package/src/datagrids/DatagridDesignerComponent.tsx +241 -229
  123. package/src/datagrids/DatagridViewComponent.tsx +3 -2
  124. package/src/datagrids/OrderBysDesignerComponent.tsx +61 -70
  125. package/src/index.css +45 -2
  126. package/src/index.ts +5 -11
  127. package/src/layouts/blocks/BlocksDisplayComponent.tsx +60 -5
  128. package/src/maps/BufferLayer.ts +14 -1
  129. package/src/maps/BufferLayerDesign.ts +1 -1
  130. package/src/maps/BufferLayerDesignerComponent.tsx +2 -1
  131. package/src/maps/ChoroplethLayer.ts +20 -7
  132. package/src/maps/ChoroplethLayerDesign.ts +5 -2
  133. package/src/maps/ChoroplethLayerDesigner.tsx +169 -165
  134. package/src/maps/DirectMapDataSource.ts +0 -12
  135. package/src/maps/EditHoverOver.tsx +9 -5
  136. package/src/maps/HoverContent.tsx +1 -1
  137. package/src/maps/LeafletMapComponent.tsx +10 -19
  138. package/src/maps/MapComponent.ts +0 -1
  139. package/src/maps/MapUtils.ts +13 -1
  140. package/src/maps/MarkersLayer.ts +22 -5
  141. package/src/maps/MarkersLayerDesign.ts +1 -1
  142. package/src/maps/MarkersLayerDesignerComponent.tsx +360 -0
  143. package/src/maps/ServerMapDataSource.ts +0 -12
  144. package/src/maps/VectorMapViewComponent.tsx +2 -13
  145. package/src/maps/symbols/font-awesome/asterisk.png +0 -0
  146. package/src/maps/symbols/font-awesome/ban.png +0 -0
  147. package/src/maps/symbols/font-awesome/beer.png +0 -0
  148. package/src/maps/symbols/font-awesome/bell.png +0 -0
  149. package/src/maps/symbols/font-awesome/bolt.png +0 -0
  150. package/src/maps/symbols/font-awesome/building.png +0 -0
  151. package/src/maps/symbols/font-awesome/bullseye.png +0 -0
  152. package/src/maps/symbols/font-awesome/bus.png +0 -0
  153. package/src/maps/symbols/font-awesome/caret-up.png +0 -0
  154. package/src/maps/symbols/font-awesome/certificate.png +0 -0
  155. package/src/maps/symbols/font-awesome/check-circle.png +0 -0
  156. package/src/maps/symbols/font-awesome/check.png +0 -0
  157. package/src/maps/symbols/font-awesome/chevron-circle-down.png +0 -0
  158. package/src/maps/symbols/font-awesome/chevron-circle-up.png +0 -0
  159. package/src/maps/symbols/font-awesome/cloud-rain.png +0 -0
  160. package/src/maps/symbols/font-awesome/cloud.png +0 -0
  161. package/src/maps/symbols/font-awesome/comment.png +0 -0
  162. package/src/maps/symbols/font-awesome/crosshairs.png +0 -0
  163. package/src/maps/symbols/font-awesome/dot-circle-o.png +0 -0
  164. package/src/maps/symbols/font-awesome/exclamation-circle.png +0 -0
  165. package/src/maps/symbols/font-awesome/exclamation-triangle.png +0 -0
  166. package/src/maps/symbols/font-awesome/female.png +0 -0
  167. package/src/maps/symbols/font-awesome/file.png +0 -0
  168. package/src/maps/symbols/font-awesome/flag.png +0 -0
  169. package/src/maps/symbols/font-awesome/flask.png +0 -0
  170. package/src/maps/symbols/font-awesome/h-square.png +0 -0
  171. package/src/maps/symbols/font-awesome/home.png +0 -0
  172. package/src/maps/symbols/font-awesome/info-circle.png +0 -0
  173. package/src/maps/symbols/font-awesome/male.png +0 -0
  174. package/src/maps/symbols/font-awesome/medkit.png +0 -0
  175. package/src/maps/symbols/font-awesome/mobile.png +0 -0
  176. package/src/maps/symbols/font-awesome/plus-circle.png +0 -0
  177. package/src/maps/symbols/font-awesome/plus-square.png +0 -0
  178. package/src/maps/symbols/font-awesome/plus.png +0 -0
  179. package/src/maps/symbols/font-awesome/square.png +0 -0
  180. package/src/maps/symbols/font-awesome/star.png +0 -0
  181. package/src/maps/symbols/font-awesome/thumbs-down.png +0 -0
  182. package/src/maps/symbols/font-awesome/thumbs-up.png +0 -0
  183. package/src/maps/symbols/font-awesome/ticket.png +0 -0
  184. package/src/maps/symbols/font-awesome/times-circle.png +0 -0
  185. package/src/maps/symbols/font-awesome/times.png +0 -0
  186. package/src/maps/symbols/font-awesome/tint.png +0 -0
  187. package/src/maps/symbols/font-awesome/tree.png +0 -0
  188. package/src/maps/symbols/font-awesome/university.png +0 -0
  189. package/src/maps/symbols/font-awesome/usd.png +0 -0
  190. package/src/maps/symbols/font-awesome/user.png +0 -0
  191. package/src/maps/symbols/font-awesome/users.png +0 -0
  192. package/src/maps/symbols/font-awesome/wheelchair.png +0 -0
  193. package/src/maps/symbols/sdf-ize.sh +93 -0
  194. package/src/maps/vectorMaps.tsx +20 -44
  195. package/src/mwater_table_selection/IndicatorsListComponent.tsx +165 -37
  196. package/src/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.tsx +111 -0
  197. package/src/mwater_table_selection/MWaterCompleteTableSelectComponent.tsx +373 -37
  198. package/src/mwater_table_selection/MWaterTableSelectComponent.tsx +12 -8
  199. package/src/mwater_table_selection/MWaterWorkflowsSelectComponent.tsx +159 -0
  200. package/src/quickfilter/{QuickfiltersComponent.ts → QuickfiltersComponent.tsx} +165 -158
  201. package/src/quickfilter/TextLiteralComponent.tsx +197 -0
  202. package/src/widgets/MapWidget.tsx +9 -1
  203. package/src/widgets/text/ExprItemEditorComponent.tsx +83 -77
  204. package/src/widgets/text/ExprUpdateModalComponent.tsx +1 -0
  205. package/test/UndoStackTests.ts +52 -1
  206. package/.storybook/config.js +0 -7
  207. package/.storybook/head.html +0 -3
  208. package/.storybook/webpack.config.js +0 -15
  209. package/src/maps/BingLayer.ts +0 -146
  210. package/src/maps/MarkersLayerDesignerComponent.ts +0 -374
  211. package/src/quickfilter/TextLiteralComponent.ts +0 -165
  212. package/stories/UpdateableComponent.js +0 -29
  213. package/stories/consoles.js +0 -202
  214. package/stories/dashboards.js +0 -217
  215. package/stories/datagridDesign.js +0 -114
  216. package/stories/datagrids.js +0 -69
  217. package/stories/dates.js +0 -80
  218. package/stories/exprcomponent.js +0 -43
  219. package/stories/index.js +0 -18
  220. package/stories/leaflet.js +0 -59
  221. package/stories/maps.js +0 -24
  222. 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
@@ -18,6 +18,7 @@ export declare function useVectorMap(options: {
18
18
  scrollZoom?: boolean;
19
19
  dragPan?: boolean;
20
20
  touchZoomRotate?: boolean;
21
+ padding?: number;
21
22
  }): Map | undefined;
22
23
  /** Sets cursor as pointer when over any layers with the specified ids */
23
24
  export declare function useHoverCursor(map: maplibregl.Map | undefined, layerIds: string[]): void;
@@ -43,7 +43,7 @@ function areVectorMapsEnabled() {
43
43
  }
44
44
  /** Loads a vector map, refreshing the WebGL context as needed */
45
45
  function useVectorMap(options) {
46
- const { divRef, bounds, scrollZoom, dragPan, touchZoomRotate } = options;
46
+ const { divRef, bounds, scrollZoom, dragPan, touchZoomRotate, padding } = options;
47
47
  // Maplibre map
48
48
  const [map, setMap] = (0, react_1.useState)();
49
49
  // Tracks if map div is visible
@@ -79,9 +79,8 @@ function useVectorMap(options) {
79
79
  return;
80
80
  }
81
81
  try {
82
- const m = new maplibre_gl_1.default.Map({
82
+ const mapConstructorOptions = {
83
83
  container: divRef,
84
- bounds: bounds,
85
84
  scrollZoom: scrollZoom === false ? false : true,
86
85
  dragPan: dragPan === false ? false : true,
87
86
  touchZoomRotate: touchZoomRotate === false ? false : true,
@@ -92,13 +91,19 @@ function useVectorMap(options) {
92
91
  layers: [],
93
92
  sources: {}
94
93
  },
95
- // Prevent scrolling outside of world bounds
96
94
  maxBounds: [
97
95
  [-179.9, -85], // Southwest coordinates
98
96
  [179.9, 85] // Northeast coordinates
99
97
  ],
100
98
  preserveDrawingBuffer: printingModeEnabled
101
- });
99
+ };
100
+ if (bounds) {
101
+ mapConstructorOptions.bounds = bounds;
102
+ if (padding !== undefined) {
103
+ mapConstructorOptions.fitBoundsOptions = { padding };
104
+ }
105
+ }
106
+ const m = new maplibre_gl_1.default.Map(mapConstructorOptions);
102
107
  setHasWebGLContext(true);
103
108
  // Add listener for losing context
104
109
  m.on("webglcontextlost", () => {
@@ -210,9 +215,8 @@ function useBaseStyle(baseLayer) {
210
215
  loadStyle(`https://api.maptiler.com/maps/streets-v2/style.json?key=${mapTilerApiKey}`);
211
216
  }
212
217
  else if (baseLayer == "bing_aerial") {
213
- // Switched to Bing for superior aerial imagery
214
- loadBingBasemap("AerialWithLabels", 1).then(setBaseStyle);
215
- // loadStyle(`https://api.maptiler.com/maps/hybrid/style.json?key=${mapTilerApiKey}`)
218
+ // Stadia Maps
219
+ loadStyle("https://tiles.stadiamaps.com/styles/alidade_satellite.json?api_key=835a418e-91f9-4eb8-9856-0883c3656c9d");
216
220
  }
217
221
  else if (baseLayer == "blank") {
218
222
  setBaseStyle({
@@ -263,7 +267,13 @@ function AttributionControl(props) {
263
267
  }
264
268
  if (props.baseLayer == "bing_aerial") {
265
269
  return (react_2.default.createElement("div", { className: "newmap-attribution-control" },
266
- "Copyright \u00A9 2022 Microsoft and its suppliers.",
270
+ "\u00A9 ",
271
+ react_2.default.createElement("a", { href: "https://stadiamaps.com/", target: "_blank" }, "Stadia Maps"),
272
+ "\u00A9 ",
273
+ react_2.default.createElement("a", { href: "https://openmaptiles.org/", target: "_blank" }, "OpenMapTiles"),
274
+ "\u00A9 ",
275
+ react_2.default.createElement("a", { href: "https://www.openstreetmap.org/copyright", target: "_blank" }, "OpenStreetMap"),
276
+ "\u00A9 CNES, Distribution Airbus DS, \u00A9 Airbus DS, \u00A9 PlanetObserver (Contains Copernicus Data)",
267
277
  props.extraText ? " " + props.extraText : null));
268
278
  }
269
279
  return (react_2.default.createElement("div", { className: "newmap-attribution-control" },
@@ -277,36 +287,10 @@ function VectorMapLogo(props) {
277
287
  return null;
278
288
  }
279
289
  if (props.baseLayer == "bing_aerial") {
280
- return react_2.default.createElement("img", { src: "https://dev.virtualearth.net/Branding/logo_powered_by.png", style: { position: "absolute", bottom: 38, left: 11, height: 22, zIndex: 1000, pointerEvents: "none" } });
290
+ return null;
281
291
  }
282
292
  return react_2.default.createElement("img", { src: require("./Maptiler-logo.png").default, style: { position: "absolute", bottom: 38, left: 11, height: 22, zIndex: 1000, pointerEvents: "none" } });
283
293
  }
284
- async function loadBingBasemap(basemapType, opacity) {
285
- // Load metadata
286
- const bingApiKey = "Ao26dWY2IC8PjorsJKFaoR85EPXCnCohrJdisCWXIULAXFo0JAXquGauppTMQbyU";
287
- const metadata = await fetch(`https://dev.virtualearth.net/REST/v1/Imagery/Metadata/${basemapType}?key=${bingApiKey}`).then((response) => response.json());
288
- const resource = metadata.resourceSets[0].resources[0];
289
- return {
290
- sources: {
291
- "bing_raster": {
292
- type: "raster",
293
- tiles: resource.imageUrlSubdomains.map((subdomain) => resource.imageUrl.replace("{subdomain}", subdomain).replace("{culture}", "").replace("http:", "https:")),
294
- tileSize: resource.imageHeight,
295
- }
296
- },
297
- layers: [
298
- {
299
- id: "bing_raster",
300
- type: "raster",
301
- source: "bing_raster",
302
- paint: {
303
- "raster-opacity": opacity
304
- }
305
- }
306
- ],
307
- version: 8
308
- };
309
- }
310
294
  /** Persists map bounds to local storage */
311
295
  function usePersistedMapBounds(map, localStorageKey) {
312
296
  const [bounds, setBounds] = (0, react_1.useState)(null);
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import { Schema } from "@mwater/expressions";
3
- interface IndicatorsListComponentProps {
3
+ export interface IndicatorsListComponentProps {
4
4
  /** Url to hit api */
5
5
  apiUrl: string;
6
6
  /** Optional client */
@@ -21,11 +21,13 @@ interface IndicatorsListComponentState {
21
21
  }
22
22
  export declare class IndicatorsListComponent extends React.Component<IndicatorsListComponentProps, IndicatorsListComponentState> {
23
23
  addIndicatorConfirmPopup: AddIndicatorConfirmPopupComponent | null;
24
- constructor(props: any);
24
+ constructor(props: IndicatorsListComponentProps);
25
25
  componentDidMount(): JQuery.jqXHR<any>;
26
26
  handleTableRemove: (table: any) => any;
27
27
  searchRef: (comp: any) => any;
28
28
  handleSelect: (tableId: any) => void;
29
+ handleOpenIndicator: (id: string) => void;
30
+ renderIndicatorList(indicators: any[], searchText: string): React.JSX.Element;
29
31
  render(): React.JSX.Element;
30
32
  }
31
33
  interface AddIndicatorConfirmPopupComponentProps {
@@ -47,7 +47,7 @@ class IndicatorsListComponent extends react_1.default.Component {
47
47
  componentDidMount() {
48
48
  // Get names and basic of forms
49
49
  const query = {};
50
- query.fields = JSON.stringify({ "design.name": 1, "design.desc": 1, "design.recommended": 1, deprecated: 1 });
50
+ 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 });
51
51
  query.client = this.props.client;
52
52
  // Get list of all indicator names
53
53
  return jquery_1.default.getJSON(this.props.apiUrl + "indicators?" + querystring_1.default.stringify(query), (indicators) => {
@@ -60,11 +60,7 @@ class IndicatorsListComponent extends react_1.default.Component {
60
60
  (indicator) => expressions_1.ExprUtils.localizeString(indicator.design.name, T.locale)
61
61
  ], ["asc", "asc", "asc"]);
62
62
  return this.setState({
63
- indicators: lodash_1.default.map(indicators, (indicator) => ({
64
- id: indicator._id,
65
- name: expressions_1.ExprUtils.localizeString(indicator.design.name, T.locale),
66
- desc: expressions_1.ExprUtils.localizeString(indicator.design.desc, T.locale)
67
- }))
63
+ indicators: indicators
68
64
  });
69
65
  }).fail((xhr) => {
70
66
  return this.setState({ error: xhr.responseText });
@@ -88,23 +84,64 @@ class IndicatorsListComponent extends react_1.default.Component {
88
84
  }
89
85
  this.addIndicatorConfirmPopup.show(tableId);
90
86
  };
87
+ handleOpenIndicator = (id) => {
88
+ this.handleSelect("indicator_values:" + id);
89
+ };
90
+ // Render a simplified version of IndicatorListComponent from mwater-portal
91
+ renderIndicatorList(indicators, searchText) {
92
+ // Filter indicators based on search text
93
+ let filteredIndicators = indicators;
94
+ if (searchText) {
95
+ const searchTerms = searchText.toLowerCase().split(" ");
96
+ filteredIndicators = indicators.filter(indicator => {
97
+ const searchFields = [
98
+ expressions_1.ExprUtils.localizeString(indicator.design.name, T.locale),
99
+ indicator.design.code,
100
+ indicator.design.organization,
101
+ indicator.design.category,
102
+ indicator.design.subcategory
103
+ ];
104
+ return searchTerms.every(term => searchFields.some(field => field && field.toLowerCase().includes(term)));
105
+ });
106
+ }
107
+ // Split into recommended and all indicators
108
+ const recommendedIndicators = filteredIndicators.filter(indicator => indicator.design.recommended);
109
+ const otherIndicators = filteredIndicators.filter(indicator => !indicator.design.recommended);
110
+ // Group by category
111
+ const groupByCategory = (indicators) => {
112
+ const categories = {};
113
+ indicators.forEach(indicator => {
114
+ const category = indicator.design.category || T `Uncategorized`;
115
+ if (!categories[category]) {
116
+ categories[category] = [];
117
+ }
118
+ categories[category].push(indicator);
119
+ });
120
+ return categories;
121
+ };
122
+ const recommendedByCategory = groupByCategory(recommendedIndicators);
123
+ const otherByCategory = groupByCategory(otherIndicators);
124
+ return (react_1.default.createElement("div", null,
125
+ recommendedIndicators.length > 0 && (react_1.default.createElement("div", null,
126
+ react_1.default.createElement("h4", null, T `Recommended Indicators`),
127
+ lodash_1.default.map(recommendedByCategory, (categoryIndicators, category) => (react_1.default.createElement("div", { key: category },
128
+ react_1.default.createElement("h5", null, category),
129
+ react_1.default.createElement("table", { className: "table table-hover" },
130
+ react_1.default.createElement("tbody", null, lodash_1.default.map(categoryIndicators, indicator => (react_1.default.createElement("tr", { key: indicator._id, onClick: () => this.handleOpenIndicator(indicator._id) },
131
+ react_1.default.createElement("td", null,
132
+ react_1.default.createElement(IndicatorListItemComponent, { indicator: indicator, onClick: () => this.handleOpenIndicator(indicator._id) })))))))))))),
133
+ react_1.default.createElement("h4", null, T `All Indicators`),
134
+ lodash_1.default.map(otherByCategory, (categoryIndicators, category) => (react_1.default.createElement("div", { key: category },
135
+ react_1.default.createElement("h5", null, category),
136
+ react_1.default.createElement("table", { className: "table table-hover" },
137
+ react_1.default.createElement("tbody", null, lodash_1.default.map(categoryIndicators, indicator => (react_1.default.createElement("tr", { key: indicator._id, onClick: () => this.handleOpenIndicator(indicator._id) },
138
+ react_1.default.createElement("td", null,
139
+ react_1.default.createElement(IndicatorListItemComponent, { indicator: indicator, onClick: () => this.handleOpenIndicator(indicator._id) }))))))))))));
140
+ }
91
141
  render() {
92
- let indicators;
93
142
  if (this.state.error) {
94
143
  return react_1.default.createElement("div", { className: "alert alert-danger" }, this.state.error);
95
144
  }
96
- // Filter indicators
97
- if (this.state.search) {
98
- const escapeRegExp = (s) => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
99
- const searchStringRegExp = new RegExp(escapeRegExp(this.state.search), "i");
100
- indicators = lodash_1.default.filter(this.state.indicators || [], (indicator) => indicator.name.match(searchStringRegExp));
101
- }
102
- else {
103
- ;
104
- ({ indicators } = this.state);
105
- }
106
- // Remove if already included
107
- indicators = lodash_1.default.filter(indicators || [], (f) => !(this.props.extraTables || []).includes(`indicator_values:${f.id}`));
108
145
  let tables = lodash_1.default.filter(this.props.schema.getTables(), (table) => table.id.match(/^indicator_values:/) && !table.deprecated);
109
146
  tables = lodash_1.default.sortBy(tables, (t) => t.name.en);
110
147
  return (react_1.default.createElement("div", null,
@@ -112,26 +149,19 @@ class IndicatorsListComponent extends react_1.default.Component {
112
149
  this.addIndicatorConfirmPopup = c;
113
150
  } }),
114
151
  react_1.default.createElement("label", null, T `Included Indicators:`),
115
- tables.length > 0 ? (react_1.default.createElement(uiComponents.OptionListComponent, { items: lodash_1.default.map(tables, (table) => {
116
- return {
117
- name: expressions_1.ExprUtils.localizeString(table.name, T.locale),
118
- desc: expressions_1.ExprUtils.localizeString(table.desc, T.locale),
119
- onClick: this.handleSelect.bind(null, table.id),
120
- onRemove: this.handleTableRemove.bind(null, table)
121
- };
122
- }) })) : (react_1.default.createElement("div", null, T `None`)),
152
+ tables.length > 0 ? (react_1.default.createElement(uiComponents.OptionListComponent, { items: lodash_1.default.map(tables, (table) => ({
153
+ name: expressions_1.ExprUtils.localizeString(table.name, T.locale),
154
+ desc: expressions_1.ExprUtils.localizeString(table.desc, T.locale),
155
+ onClick: () => this.handleSelect(table.id),
156
+ onRemove: () => this.handleTableRemove(table)
157
+ })) })) : (react_1.default.createElement("div", null, T `None`)),
123
158
  react_1.default.createElement("br", null),
124
159
  react_1.default.createElement("label", null, T `All Indicators:`),
125
160
  !this.state.indicators || this.state.indicators.length === 0 ? (react_1.default.createElement("div", { className: "alert alert-info" },
126
161
  react_1.default.createElement("i", { className: "fa fa-spinner fa-spin" }),
127
- "\u00A0",
128
- T `Loading...`)) : (react_1.default.createElement(react_1.default.Fragment, null,
162
+ "\u00A0" + T `Loading...`)) : (react_1.default.createElement(react_1.default.Fragment, null,
129
163
  react_1.default.createElement("input", { type: "text", className: "form-control form-control-sm", placeholder: T `Search...`, key: "search", ref: this.searchRef, style: { maxWidth: "20em", marginBottom: 10 }, value: this.state.search, onChange: (ev) => this.setState({ search: ev.target.value }) }),
130
- react_1.default.createElement(uiComponents.OptionListComponent, { items: lodash_1.default.map(indicators, (indicator) => ({
131
- name: indicator.name,
132
- desc: indicator.desc,
133
- onClick: this.handleSelect.bind(null, "indicator_values:" + indicator.id)
134
- })) })))));
164
+ this.renderIndicatorList(this.state.indicators, this.state.search)))));
135
165
  }
136
166
  }
137
167
  exports.IndicatorsListComponent = IndicatorsListComponent;
@@ -180,3 +210,42 @@ are certain that you want to use the raw indicator table`),
180
210
  return (react_1.default.createElement(ModalPopupComponent_1.default, { showCloseX: true, onClose: () => this.setState({ visible: false }), header: T `Add Indicator` }, this.renderContents()));
181
211
  }
182
212
  }
213
+ // Single indicator item in a list
214
+ // Local port of the class found in mwater-portal
215
+ class IndicatorListItemComponent extends react_1.default.Component {
216
+ renderIcon() {
217
+ switch (this.props.indicator.type) {
218
+ case "expression":
219
+ // R 'i', className: "text-muted fa fa-fw fa-calculator"
220
+ return null;
221
+ case "response":
222
+ // R 'i', className: "text-muted fa fa-fw fa-list-alt"
223
+ return null;
224
+ case "set":
225
+ return (react_1.default.createElement("span", { className: "fa-stack", style: { paddingRight: 6 } },
226
+ react_1.default.createElement("i", { className: "fa fa-th-list fa-stack-1x text-muted" }),
227
+ react_1.default.createElement("i", { className: "fa fa-circle fa-stack-1x", style: { color: "white", paddingLeft: 15 } }),
228
+ react_1.default.createElement("i", { className: "fa fa-check-circle fa-stack-1x text-primary", style: { paddingLeft: 15 } })));
229
+ }
230
+ return null;
231
+ }
232
+ render() {
233
+ return (react_1.default.createElement("div", { onClick: this.props.onClick, style: { cursor: "pointer" } },
234
+ react_1.default.createElement("div", { key: "name", style: { fontWeight: "bold" } },
235
+ this.renderIcon(),
236
+ expressions_1.ExprUtils.localizeString(this.props.indicator.design.name, T.locale),
237
+ this.props.indicator.design.code ? ` (${this.props.indicator.design.code})` : undefined,
238
+ this.props.indicator.design.organization ? (react_1.default.createElement("span", { className: "text-muted" },
239
+ " ",
240
+ T `by ${this.props.indicator.design.organization}`)) : undefined),
241
+ react_1.default.createElement("div", { key: "desc", className: "text-muted" },
242
+ expressions_1.ExprUtils.localizeString(this.props.indicator.design.desc, T.locale),
243
+ this.props.indicator.design.category
244
+ ? [
245
+ ` (${this.props.indicator.design.category}`,
246
+ this.props.indicator.design.subcategory ? `/${this.props.indicator.design.subcategory}` : undefined,
247
+ `)`
248
+ ]
249
+ : undefined)));
250
+ }
251
+ }
@@ -0,0 +1,18 @@
1
+ import { Schema } from "@mwater/expressions";
2
+ import React from "react";
3
+ interface MWaterCalculatedDataSourcesListComponentProps {
4
+ apiUrl: string;
5
+ schema: Schema;
6
+ client?: string;
7
+ user?: string;
8
+ onChange: (tableId: string | null) => void;
9
+ extraTables: string[];
10
+ onExtraTableAdd: (tableId: string) => void;
11
+ onExtraTableRemove: (tableId: string) => void;
12
+ locale?: string;
13
+ }
14
+ /**
15
+ * A list of calculated data sources that can be selected.
16
+ */
17
+ export declare const MWaterCalculatedDataSourcesListComponent: (props: MWaterCalculatedDataSourcesListComponentProps) => React.JSX.Element;
18
+ export {};
@@ -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.MWaterCalculatedDataSourcesListComponent = 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
+ /**
14
+ * A list of calculated data sources that can be selected.
15
+ */
16
+ const MWaterCalculatedDataSourcesListComponent = (props) => {
17
+ const [calculatedSources, setCalculatedSources] = (0, react_1.useState)();
18
+ const [search, setSearch] = (0, react_1.useState)("");
19
+ const [extraTableNeeded, setExtraTableNeeded] = (0, react_1.useState)();
20
+ (0, react_1.useEffect)(() => {
21
+ fetch(`${props.apiUrl}calculated_data_sources?client=${props.client || ""}`)
22
+ .then((response) => response.json())
23
+ .then((body) => {
24
+ // Filter out calculated data sources that have never been calculated
25
+ const calculatedSources = body.filter((s) => s.last_calculated);
26
+ setCalculatedSources(lodash_1.default.sortByAll(calculatedSources, [
27
+ (s) => (props.extraTables.some((t) => t == `calculated:${s._sid}`) ? 0 : 1),
28
+ (s) => expressions_1.ExprUtils.localizeString(s.name, props.locale)
29
+ ]));
30
+ });
31
+ }, []);
32
+ (0, react_1.useEffect)(() => {
33
+ if (extraTableNeeded && props.schema.getTable(extraTableNeeded)) {
34
+ props.onChange(extraTableNeeded);
35
+ }
36
+ });
37
+ const selectTable = (source) => {
38
+ const qualifiedTableId = `calculated:${source._sid}`;
39
+ if (props.schema.getTable(qualifiedTableId)) {
40
+ props.onChange(qualifiedTableId);
41
+ return;
42
+ }
43
+ setExtraTableNeeded(qualifiedTableId);
44
+ props.onExtraTableAdd(qualifiedTableId);
45
+ };
46
+ const handleRemove = (source) => {
47
+ const match = props.extraTables.find((t) => t == `calculated:${source._sid}`);
48
+ if (match) {
49
+ if (confirm(T `Remove this table? Some widgets may not work correctly.`)) {
50
+ props.onChange(null);
51
+ props.onExtraTableRemove(match);
52
+ }
53
+ }
54
+ };
55
+ if (!calculatedSources || extraTableNeeded) {
56
+ return (react_2.default.createElement("div", null,
57
+ react_2.default.createElement("i", { className: "fa fa-spin fa-spinner" }),
58
+ " ",
59
+ T `Loading...`));
60
+ }
61
+ const renderCalculatedSources = () => {
62
+ const items = calculatedSources
63
+ .map((s) => {
64
+ const alreadyIncluded = props.extraTables.some((t) => t == `calculated:${s._sid}`);
65
+ return {
66
+ name: expressions_1.ExprUtils.localizeString(s.name, props.locale) || "",
67
+ desc: s.description ? expressions_1.ExprUtils.localizeString(s.description, props.locale) || "" : undefined,
68
+ onClick: () => selectTable(s),
69
+ onRemove: alreadyIncluded ? handleRemove.bind(null, s) : undefined
70
+ };
71
+ })
72
+ .filter((item) => !search || item.name.toLowerCase().includes(search.toLowerCase()));
73
+ return react_2.default.createElement(UIComponents_1.OptionListComponent, { items: items });
74
+ };
75
+ return (react_2.default.createElement("div", null,
76
+ react_2.default.createElement(bootstrap_1.TextInput, { value: search, onChange: setSearch, placeholder: T `Search...`, searchIcon: true }),
77
+ react_2.default.createElement("br", null),
78
+ renderCalculatedSources()));
79
+ };
80
+ exports.MWaterCalculatedDataSourcesListComponent = MWaterCalculatedDataSourcesListComponent;
@@ -14,24 +14,50 @@ interface MWaterCompleteTableSelectComponentProps {
14
14
  extraTables: any;
15
15
  onExtraTablesChange: any;
16
16
  }
17
+ interface Category {
18
+ id: string;
19
+ name: string;
20
+ description: string;
21
+ icon: string;
22
+ render: () => JSX.Element;
23
+ }
24
+ /** Allows selection of a table. Card-based layout with categories */
17
25
  export default class MWaterCompleteTableSelectComponent extends React.Component<MWaterCompleteTableSelectComponentProps, {
26
+ selectedCategory: string | null;
18
27
  showLegacyAssets: boolean;
28
+ searchText: string;
19
29
  }> {
20
30
  constructor(props: MWaterCompleteTableSelectComponentProps);
21
31
  handleExtraTableAdd: (tableId: any) => any;
22
32
  handleExtraTableRemove: (tableId: any) => any;
33
+ handleCategorySelect: (categoryId: string) => void;
34
+ handleBackToCategories: () => void;
23
35
  renderSites(): React.JSX.Element;
24
36
  renderForms(): React.JSX.Element;
25
37
  renderIndicators(): React.JSX.Element;
26
38
  renderIssues(): React.JSX.Element;
39
+ renderWorkflows(): React.JSX.Element;
27
40
  renderSweetSense(): React.JSX.Element;
28
41
  renderTablesets(): React.JSX.Element;
29
42
  renderMetrics(): React.JSX.Element;
30
43
  renderAccountingSystems(): React.JSX.Element;
31
44
  renderAssets(): React.JSX.Element;
32
45
  renderLegacyAssets(): React.JSX.Element;
46
+ renderCalculated(): React.JSX.Element;
33
47
  renderOther(): React.JSX.Element;
34
48
  getSweetSenseTables(): import("@mwater/expressions").Table[];
49
+ /** Get all available categories */
50
+ getCategories(): Category[];
51
+ /** Render a single category card */
52
+ renderCategoryCard(category: Category): React.JSX.Element;
53
+ /** Get display name for an extra table (handles wildcards) */
54
+ getExtraTableDisplayName(tableId: string): string | null;
55
+ /** Render the currently included extra tables section */
56
+ renderExtraTables(): React.JSX.Element | null;
57
+ /** Render the landing page with all categories */
58
+ renderLandingPage(): React.JSX.Element;
59
+ /** Render a specific category view */
60
+ renderCategoryView(): React.JSX.Element | null;
35
61
  render(): React.JSX.Element;
36
62
  }
37
63
  export {};