@mwater/visualization 5.4.1 → 5.4.3

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 (273) hide show
  1. package/lib/ColorComponent.js +2 -1
  2. package/lib/IdSelection.d.ts +16 -0
  3. package/lib/IdSelection.js +59 -0
  4. package/lib/MWaterAddRelatedIndicatorComponent.js +2 -2
  5. package/lib/MWaterCompleteTableSelectComponent.d.ts +3 -8
  6. package/lib/MWaterCompleteTableSelectComponent.js +36 -42
  7. package/lib/MWaterLoaderComponent.d.ts +11 -10
  8. package/lib/MWaterLoaderComponent.js +1 -1
  9. package/lib/MWaterResponsesFilterComponent.js +1 -1
  10. package/lib/MWaterTableSelectComponent.d.ts +0 -1
  11. package/lib/MWaterTableSelectComponent.js +4 -6
  12. package/lib/autotranslate.d.ts +20 -0
  13. package/lib/autotranslate.js +122 -0
  14. package/lib/axes/AxisBuilder.js +3 -3
  15. package/lib/axes/AxisColorEditorComponent.js +4 -0
  16. package/lib/axes/AxisComponent.d.ts +8 -12
  17. package/lib/axes/AxisComponent.js +32 -80
  18. package/lib/axes/CategoryMapComponent.js +4 -4
  19. package/lib/axes/RangesComponent.js +2 -2
  20. package/lib/dashboards/DashboardComponent.d.ts +12 -20
  21. package/lib/dashboards/DashboardComponent.js +109 -69
  22. package/lib/dashboards/DashboardDesign.d.ts +11 -2
  23. package/lib/dashboards/DashboardUtils.d.ts +5 -0
  24. package/lib/dashboards/DashboardUtils.js +30 -0
  25. package/lib/dashboards/DashboardViewComponent.d.ts +2 -0
  26. package/lib/dashboards/DashboardViewComponent.js +16 -3
  27. package/lib/dashboards/ServerDashboardDataSource.js +2 -1
  28. package/lib/dashboards/SettingsModalComponent.d.ts +1 -1
  29. package/lib/dashboards/SettingsModalComponent.js +256 -19
  30. package/lib/dashboards/WidgetComponent.d.ts +6 -3
  31. package/lib/dashboards/WidgetComponent.js +3 -1
  32. package/lib/datagrids/CellEditor.d.ts +19 -0
  33. package/lib/datagrids/CellEditor.js +223 -0
  34. package/lib/datagrids/DatagridComponent.d.ts +18 -87
  35. package/lib/datagrids/DatagridComponent.js +304 -222
  36. package/lib/datagrids/DatagridViewComponent.d.ts +15 -53
  37. package/lib/datagrids/DatagridViewComponent.js +256 -257
  38. package/lib/datagrids/DirectDatagridDataSource.js +2 -3
  39. package/lib/datagrids/ExprCellComponent.d.ts +8 -15
  40. package/lib/datagrids/ExprCellComponent.js +11 -15
  41. package/lib/datagrids/FindReplaceModalComponent.d.ts +4 -6
  42. package/lib/datagrids/FindReplaceModalComponent.js +38 -75
  43. package/lib/index.css +1 -1
  44. package/lib/index.d.ts +0 -1
  45. package/lib/index.js +0 -1
  46. package/lib/languages.js +6 -1
  47. package/lib/layouts/blocks/HorizontalBlockComponent.js +2 -2
  48. package/lib/mWaterLoader.d.ts +1 -1
  49. package/lib/maps/BufferLayer.d.ts +7 -5
  50. package/lib/maps/BufferLayer.js +69 -48
  51. package/lib/maps/BufferLayerDesign.d.ts +21 -14
  52. package/lib/maps/BufferLayerDesignerComponent.d.ts +16 -31
  53. package/lib/maps/BufferLayerDesignerComponent.js +68 -102
  54. package/lib/maps/ChoroplethLayer.d.ts +5 -4
  55. package/lib/maps/ChoroplethLayer.js +32 -9
  56. package/lib/maps/ChoroplethLayerDesign.d.ts +6 -2
  57. package/lib/maps/ChoroplethLayerDesigner.js +4 -2
  58. package/lib/maps/ClusterLayer.d.ts +3 -4
  59. package/lib/maps/ClusterLayer.js +2 -1
  60. package/lib/maps/DetailLevelSelectComponent.js +1 -1
  61. package/lib/maps/DirectMapDataSource.js +2 -1
  62. package/lib/maps/EditPopupComponent.js +5 -3
  63. package/lib/maps/GridLayer.d.ts +3 -4
  64. package/lib/maps/GridLayer.js +2 -1
  65. package/lib/maps/GridLayerDesigner.js +5 -3
  66. package/lib/maps/HoverContent.d.ts +11 -3
  67. package/lib/maps/HoverContent.js +25 -9
  68. package/lib/maps/Layer.d.ts +24 -3
  69. package/lib/maps/Layer.js +5 -1
  70. package/lib/maps/LayerFactory.js +0 -8
  71. package/lib/maps/LayerLegendComponent.js +0 -1
  72. package/lib/maps/LayerSwitcherComponent.d.ts +1 -0
  73. package/lib/maps/LayerSwitcherComponent.js +1 -1
  74. package/lib/maps/LeafletMapComponent.js +3 -1
  75. package/lib/maps/LegendComponent.d.ts +1 -0
  76. package/lib/maps/LegendComponent.js +9 -1
  77. package/lib/maps/MWaterServerLayer.d.ts +2 -2
  78. package/lib/maps/MWaterServerLayer.js +2 -2
  79. package/lib/maps/MapComponent.js +3 -3
  80. package/lib/maps/MapDesign.d.ts +2 -0
  81. package/lib/maps/MapDesignerComponent.d.ts +4 -3
  82. package/lib/maps/MapDesignerComponent.js +68 -74
  83. package/lib/maps/MapLayerViewDesignerComponent.js +2 -2
  84. package/lib/maps/MapUtils.d.ts +4 -0
  85. package/lib/maps/MapUtils.js +19 -0
  86. package/lib/maps/MapViewComponent.d.ts +8 -3
  87. package/lib/maps/MarkersLayer.d.ts +5 -4
  88. package/lib/maps/MarkersLayer.js +33 -7
  89. package/lib/maps/MarkersLayerDesign.d.ts +19 -16
  90. package/lib/maps/PopupFilterJoinsUtils.d.ts +6 -3
  91. package/lib/maps/PopupFilterJoinsUtils.js +0 -6
  92. package/lib/maps/RasterMapViewComponent.d.ts +3 -31
  93. package/lib/maps/RasterMapViewComponent.js +7 -2
  94. package/lib/maps/ServerMapDataSource.js +2 -1
  95. package/lib/maps/SwitchableTileUrlLayer.d.ts +3 -3
  96. package/lib/maps/SwitchableTileUrlLayer.js +2 -1
  97. package/lib/maps/TileUrlLayer.d.ts +4 -5
  98. package/lib/maps/TileUrlLayer.js +2 -1
  99. package/lib/maps/VectorMapViewComponent.d.ts +5 -37
  100. package/lib/maps/VectorMapViewComponent.js +19 -8
  101. package/lib/maps/maps.d.ts +3 -0
  102. package/lib/quickfilter/Quickfilter.d.ts +2 -0
  103. package/lib/quickfilter/QuickfiltersComponent.d.ts +2 -0
  104. package/lib/quickfilter/QuickfiltersComponent.js +9 -7
  105. package/lib/quickfilter/QuickfiltersDesignComponent.d.ts +5 -30
  106. package/lib/quickfilter/QuickfiltersDesignComponent.js +56 -63
  107. package/lib/richtext/ExprItemsHtmlConverter.d.ts +5 -2
  108. package/lib/richtext/ExprItemsHtmlConverter.js +4 -4
  109. package/lib/richtext/ExprItemsTranslator.d.ts +5 -0
  110. package/lib/richtext/ExprItemsTranslator.js +149 -0
  111. package/lib/richtext/ItemsHtmlConverter.d.ts +1 -1
  112. package/lib/richtext/ItemsHtmlConverter.js +31 -15
  113. package/lib/wellknown.js +12 -9
  114. package/lib/widgets/IFrameWidget.d.ts +4 -4
  115. package/lib/widgets/ImageWidget.d.ts +7 -4
  116. package/lib/widgets/ImageWidget.js +9 -1
  117. package/lib/widgets/ImageWidgetComponent.d.ts +1 -0
  118. package/lib/widgets/ImageWidgetComponent.js +1 -1
  119. package/lib/widgets/MapWidget.d.ts +5 -48
  120. package/lib/widgets/MapWidget.js +26 -63
  121. package/lib/widgets/MarkdownWidget.d.ts +3 -0
  122. package/lib/widgets/MarkdownWidget.js +3 -0
  123. package/lib/widgets/TOCWidget.d.ts +15 -27
  124. package/lib/widgets/TOCWidget.js +107 -183
  125. package/lib/widgets/Widget.d.ts +18 -7
  126. package/lib/widgets/Widget.js +4 -0
  127. package/lib/widgets/WidgetScopesViewComponent.js +1 -1
  128. package/lib/widgets/charts/Chart.d.ts +10 -1
  129. package/lib/widgets/charts/Chart.js +22 -11
  130. package/lib/widgets/charts/ChartViewComponent.d.ts +4 -0
  131. package/lib/widgets/charts/ChartViewComponent.js +6 -3
  132. package/lib/widgets/charts/ChartWidget.d.ts +2 -0
  133. package/lib/widgets/charts/ChartWidget.js +9 -1
  134. package/lib/widgets/charts/ChartWidgetComponent.d.ts +4 -0
  135. package/lib/widgets/charts/ChartWidgetComponent.js +2 -2
  136. package/lib/widgets/charts/calendar/CalendarChart.d.ts +1 -0
  137. package/lib/widgets/charts/calendar/CalendarChart.js +26 -0
  138. package/lib/widgets/charts/calendar/CalendarChartViewComponent.js +3 -1
  139. package/lib/widgets/charts/imagemosaic/ImageMosaicChart.d.ts +1 -0
  140. package/lib/widgets/charts/imagemosaic/ImageMosaicChart.js +8 -0
  141. package/lib/widgets/charts/layered/LayeredChart.d.ts +2 -0
  142. package/lib/widgets/charts/layered/LayeredChart.js +63 -3
  143. package/lib/widgets/charts/layered/LayeredChartCompiler.d.ts +1 -1
  144. package/lib/widgets/charts/layered/LayeredChartCompiler.js +1 -1
  145. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.js +2 -2
  146. package/lib/widgets/charts/layered/LayeredChartViewComponent.js +8 -3
  147. package/lib/widgets/charts/pivot/PivotChart.d.ts +1 -0
  148. package/lib/widgets/charts/pivot/PivotChart.js +63 -0
  149. package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +1 -1
  150. package/lib/widgets/charts/pivot/SegmentDesignerComponent.js +7 -4
  151. package/lib/widgets/charts/table/OrderingsComponent.js +1 -1
  152. package/lib/widgets/charts/table/TableChart.d.ts +1 -0
  153. package/lib/widgets/charts/table/TableChart.js +15 -0
  154. package/lib/widgets/text/TextComponent.d.ts +11 -4
  155. package/lib/widgets/text/TextComponent.js +11 -8
  156. package/lib/widgets/text/TextWidget.d.ts +6 -3
  157. package/lib/widgets/text/TextWidget.js +7 -1
  158. package/lib/widgets/text/TextWidgetComponent.d.ts +4 -0
  159. package/lib/widgets/text/TextWidgetComponent.js +7 -1
  160. package/lib/widgets/text/TextWidgetDesign.d.ts +2 -4
  161. package/lib/widgets/text/TextWidgetDesign.js +1 -1
  162. package/package.json +7 -8
  163. package/src/ColorComponent.tsx +1 -2
  164. package/src/IdSelection.ts +62 -0
  165. package/src/MWaterAddRelatedIndicatorComponent.ts +3 -2
  166. package/src/MWaterCompleteTableSelectComponent.tsx +36 -46
  167. package/src/MWaterLoaderComponent.ts +28 -26
  168. package/src/MWaterResponsesFilterComponent.ts +5 -2
  169. package/src/MWaterTableSelectComponent.tsx +5 -9
  170. package/src/autotranslate.ts +141 -0
  171. package/src/axes/AxisBuilder.ts +3 -3
  172. package/src/axes/AxisColorEditorComponent.tsx +5 -0
  173. package/src/axes/{AxisComponent.ts → AxisComponent.tsx} +106 -106
  174. package/src/axes/CategoryMapComponent.ts +4 -4
  175. package/src/axes/RangesComponent.ts +3 -2
  176. package/src/dashboards/DashboardComponent.tsx +189 -125
  177. package/src/dashboards/DashboardDesign.ts +9 -2
  178. package/src/dashboards/DashboardUtils.ts +39 -0
  179. package/src/dashboards/DashboardViewComponent.tsx +22 -3
  180. package/src/dashboards/ServerDashboardDataSource.ts +2 -1
  181. package/src/dashboards/SettingsModalComponent.tsx +450 -35
  182. package/src/dashboards/WidgetComponent.tsx +12 -6
  183. package/src/datagrids/CellEditor.tsx +354 -0
  184. package/src/datagrids/DatagridComponent.tsx +646 -0
  185. package/src/datagrids/DatagridViewComponent.tsx +539 -0
  186. package/src/datagrids/DirectDatagridDataSource.ts +2 -3
  187. package/src/datagrids/{ExprCellComponent.ts → ExprCellComponent.tsx} +28 -23
  188. package/src/datagrids/{FindReplaceModalComponent.ts → FindReplaceModalComponent.tsx} +109 -122
  189. package/src/index.css +1 -1
  190. package/src/index.ts +0 -1
  191. package/src/languages.ts +6 -1
  192. package/src/layouts/blocks/HorizontalBlockComponent.ts +2 -2
  193. package/src/mWaterLoader.ts +1 -1
  194. package/src/maps/BufferLayer.ts +83 -60
  195. package/src/maps/BufferLayerDesign.ts +20 -14
  196. package/src/maps/BufferLayerDesignerComponent.tsx +309 -0
  197. package/src/maps/ChoroplethLayer.ts +40 -19
  198. package/src/maps/ChoroplethLayerDesign.ts +4 -2
  199. package/src/maps/ChoroplethLayerDesigner.tsx +4 -2
  200. package/src/maps/ClusterLayer.ts +4 -10
  201. package/src/maps/DetailLevelSelectComponent.ts +1 -1
  202. package/src/maps/DirectMapDataSource.ts +2 -1
  203. package/src/maps/EditPopupComponent.ts +7 -3
  204. package/src/maps/GridLayer.ts +4 -10
  205. package/src/maps/GridLayerDesigner.tsx +5 -3
  206. package/src/maps/HoverContent.tsx +40 -16
  207. package/src/maps/Layer.ts +28 -10
  208. package/src/maps/LayerFactory.ts +0 -8
  209. package/src/maps/LayerLegendComponent.ts +2 -4
  210. package/src/maps/LayerSwitcherComponent.tsx +6 -2
  211. package/src/maps/LeafletMapComponent.tsx +3 -1
  212. package/src/maps/LegendComponent.tsx +10 -1
  213. package/src/maps/MWaterServerLayer.ts +3 -3
  214. package/src/maps/MapComponent.ts +3 -3
  215. package/src/maps/MapDesign.ts +3 -0
  216. package/src/maps/MapDesignerComponent.tsx +165 -162
  217. package/src/maps/MapLayerViewDesignerComponent.ts +2 -2
  218. package/src/maps/MapUtils.ts +24 -0
  219. package/src/maps/MapViewComponent.tsx +11 -3
  220. package/src/maps/MarkersLayer.ts +44 -18
  221. package/src/maps/MarkersLayerDesign.ts +19 -16
  222. package/src/maps/PopupFilterJoinsUtils.ts +6 -2
  223. package/src/maps/RasterMapViewComponent.ts +9 -45
  224. package/src/maps/ServerMapDataSource.ts +2 -2
  225. package/src/maps/SwitchableTileUrlLayer.tsx +4 -10
  226. package/src/maps/TileUrlLayer.tsx +4 -10
  227. package/src/maps/VectorMapViewComponent.tsx +28 -55
  228. package/src/maps/maps.ts +3 -0
  229. package/src/quickfilter/Quickfilter.ts +3 -0
  230. package/src/quickfilter/QuickfiltersComponent.ts +13 -7
  231. package/src/quickfilter/QuickfiltersDesignComponent.tsx +127 -128
  232. package/src/richtext/ExprItemsHtmlConverter.ts +9 -5
  233. package/src/richtext/ExprItemsTranslator.ts +176 -0
  234. package/src/richtext/ItemsHtmlConverter.ts +33 -18
  235. package/src/wellknown.ts +33 -30
  236. package/src/widgets/ImageWidget.ts +10 -1
  237. package/src/widgets/ImageWidgetComponent.ts +3 -2
  238. package/src/widgets/{MapWidget.ts → MapWidget.tsx} +90 -101
  239. package/src/widgets/MarkdownWidget.ts +3 -0
  240. package/src/widgets/TOCWidget.tsx +281 -0
  241. package/src/widgets/Widget.ts +25 -5
  242. package/src/widgets/WidgetScopesViewComponent.ts +2 -1
  243. package/src/widgets/charts/Chart.ts +31 -12
  244. package/src/widgets/charts/ChartViewComponent.ts +13 -3
  245. package/src/widgets/charts/ChartWidget.ts +11 -1
  246. package/src/widgets/charts/ChartWidgetComponent.tsx +9 -1
  247. package/src/widgets/charts/calendar/CalendarChart.ts +29 -0
  248. package/src/widgets/charts/calendar/CalendarChartViewComponent.tsx +3 -1
  249. package/src/widgets/charts/imagemosaic/ImageMosaicChart.ts +9 -0
  250. package/src/widgets/charts/layered/LayeredChart.ts +71 -3
  251. package/src/widgets/charts/layered/LayeredChartCompiler.ts +2 -2
  252. package/src/widgets/charts/layered/LayeredChartDesignerComponent.tsx +4 -2
  253. package/src/widgets/charts/layered/LayeredChartViewComponent.ts +10 -4
  254. package/src/widgets/charts/pivot/PivotChart.ts +73 -0
  255. package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +1 -1
  256. package/src/widgets/charts/pivot/SegmentDesignerComponent.tsx +6 -4
  257. package/src/widgets/charts/table/OrderingsComponent.tsx +2 -1
  258. package/src/widgets/charts/table/TableChart.ts +17 -0
  259. package/src/widgets/text/TextComponent.tsx +22 -12
  260. package/src/widgets/text/TextWidget.ts +9 -2
  261. package/src/widgets/text/TextWidgetComponent.tsx +16 -1
  262. package/src/widgets/text/TextWidgetDesign.ts +4 -7
  263. package/test/IdSelectionTests.ts +54 -0
  264. package/test/LayeredChartCompilerTests.ts +0 -2
  265. package/test/richtext/ExprItemsTranslatorTests.ts +144 -0
  266. package/test/wellknownTests.ts +144 -0
  267. package/src/datagrids/DatagridComponent.ts +0 -478
  268. package/src/datagrids/DatagridViewComponent.ts +0 -464
  269. package/src/datagrids/EditExprCellComponent.tsx +0 -305
  270. package/src/datagrids/README.md +0 -3
  271. package/src/maps/BufferLayerDesignerComponent.ts +0 -311
  272. package/src/widgets/TOCWidget.ts +0 -326
  273. package/test/LegoLayoutEngineTests.ts +0 -69
@@ -1,7 +1,5 @@
1
1
  import _ from "lodash"
2
2
  import React, { ReactNode } from "react"
3
- const R = React.createElement
4
-
5
3
  import { DataSource, ExprCompiler, Schema } from "@mwater/expressions"
6
4
  import UndoStack from "../UndoStack"
7
5
  import * as DashboardUtils from "./DashboardUtils"
@@ -15,7 +13,7 @@ import ModalWindowComponent from "@mwater/react-library/lib/ModalWindowComponent
15
13
  import { getLayoutOptions } from "./layoutOptions"
16
14
  import { DashboardDesign } from "./DashboardDesign"
17
15
  import DashboardDataSource from "./DashboardDataSource"
18
- import { JsonQLFilter } from ".."
16
+ import { JsonQLFilter, languages } from ".."
19
17
  import { ActiveTablesContext, LocaleContext } from "@mwater/expressions-ui"
20
18
 
21
19
  export interface DashboardComponentProps {
@@ -61,6 +59,9 @@ export interface DashboardComponentProps {
61
59
 
62
60
  /** Called when the edit mode changes */
63
61
  onEditModeChange?: (editing: boolean) => void
62
+
63
+ /** Locale to prefer if available */
64
+ preferredLocale?: string
64
65
  }
65
66
 
66
67
  export interface DashboardComponentState {
@@ -70,6 +71,8 @@ export interface DashboardComponentState {
70
71
  layoutOptionsOpen: boolean
71
72
  hideQuickfilters: boolean
72
73
  refreshKey: number
74
+ /** Locale to use for display. Ignored if in edit mode */
75
+ locale: string
73
76
  }
74
77
 
75
78
  /** Dashboard component that includes an action bar at the top
@@ -87,6 +90,15 @@ export default class DashboardComponent extends React.Component<DashboardCompone
87
90
 
88
91
  const layoutOptions = getLayoutOptions(props.design)
89
92
 
93
+ // Prefer the T.en locale if available when loading the dashboard
94
+ let initialLocale = props.design.locale || "en"
95
+ const otherLocales = props.design.otherLocales || []
96
+ if (props.preferredLocale && otherLocales.includes(props.preferredLocale)) {
97
+ initialLocale = props.preferredLocale
98
+ } else if (otherLocales.includes(T.locale)) {
99
+ initialLocale = T.locale
100
+ }
101
+
90
102
  this.state = {
91
103
  undoStack: new UndoStack().push(props.design),
92
104
  quickfiltersValues: props.quickfiltersValues || null,
@@ -96,7 +108,8 @@ export default class DashboardComponent extends React.Component<DashboardCompone
96
108
  layoutOptionsOpen: false,
97
109
  hideQuickfilters:
98
110
  layoutOptions.hideQuickfiltersWidth != null && layoutOptions.hideQuickfiltersWidth > document.body.clientWidth,
99
- refreshKey: 1
111
+ refreshKey: 1,
112
+ locale: initialLocale
100
113
  }
101
114
 
102
115
  if (props.onEditModeChange) {
@@ -207,118 +220,165 @@ export default class DashboardComponent extends React.Component<DashboardCompone
207
220
  return compiledFilters
208
221
  }
209
222
 
223
+ /** Translate function to use for display. Do not use when editing. */
224
+ translate = (input: string) => {
225
+ const designLocale = this.props.design.locale ?? "en"
226
+ const displayLocale = this.state.editing ? designLocale : (this.state.locale ?? designLocale ?? "en")
227
+ if (designLocale === displayLocale) {
228
+ return input
229
+ }
230
+ return this.props.design.translations?.[displayLocale]?.[input] ?? input
231
+ }
232
+
210
233
  renderEditingSwitch() {
211
- return R(
212
- "a",
213
- {
214
- key: "edit",
215
- className: `btn btn-primary btn-sm ${this.state.editing ? "active" : ""}`,
216
- onClick: this.handleToggleEditing
217
- },
218
- R("span", { className: "fas fa-pencil-alt" }),
219
- this.state.editing ? T` Editing` : T` Edit`
234
+ return (
235
+ <a
236
+ key="edit"
237
+ className={`btn btn-primary btn-sm ${this.state.editing ? "active" : ""}`}
238
+ onClick={this.handleToggleEditing}
239
+ >
240
+ <span className="fas fa-pencil-alt"/>
241
+ {" "}
242
+ {this.state.editing ? T`Editing` : T`Edit`}
243
+ </a>
220
244
  )
221
245
  }
222
246
 
223
247
  renderStyle() {
224
- return R(
225
- "button",
226
- { type: "button", key: "style", className: "btn btn-link btn-sm", onClick: this.handleOpenLayoutOptions },
227
- R("span", { className: "fa fa-mobile" }),
228
- R("span", { className: "hide-600px" }, T` Layout `)
248
+ return (
249
+ <button type="button" key="style" className="btn btn-link btn-sm" onClick={this.handleOpenLayoutOptions}>
250
+ <span className="fa fa-mobile"/>
251
+ <span className="hide-600px"> {T`Layout`}</span>
252
+ </button>
229
253
  )
230
254
  }
231
255
 
232
256
  renderActionLinks() {
233
- return R(
234
- "div",
235
- null,
236
- this.state.editing
237
- ? [
238
- R(
239
- "a",
240
- {
241
- key: "undo",
242
- className: `btn btn-link btn-sm ${!this.state.undoStack.canUndo() ? "disabled" : ""}`,
243
- onClick: this.handleUndo
244
- },
245
- R("span", { className: "fas fa-caret-left" }),
246
- R("span", { className: "hide-600px" }, T` Undo`)
247
- ),
248
- " ",
249
- R(
250
- "a",
251
- {
252
- key: "redo",
253
- className: `btn btn-link btn-sm ${!this.state.undoStack.canRedo() ? "disabled" : ""}`,
254
- onClick: this.handleRedo
255
- },
256
- R("span", { className: "fas fa-caret-right" }),
257
- R("span", { className: "hide-600px" }, T` Redo`)
258
- )
259
- ]
260
- : undefined,
261
- R(
262
- "a",
263
- { key: "print", className: "btn btn-link btn-sm", onClick: this.handlePrint },
264
- R("span", { className: "fas fa-print" }),
265
- R("span", { className: "hide-600px" }, T` Print`)
266
- ),
267
- R(
268
- "a",
269
- { key: "refresh", className: "btn btn-link btn-sm", onClick: this.handleRefreshData },
270
- R("span", { className: "fas fa-sync" }),
271
- R("span", { className: "hide-600px" }, T` Refresh`)
272
- ),
273
- this.state.hideQuickfilters && this.props.design.quickfilters && this.props.design.quickfilters.length > 0
274
- ? R(
275
- "a",
276
- { key: "showQuickfilters", className: "btn btn-link btn-sm", onClick: this.handleShowQuickfilters },
277
- R("span", { className: "fa fa-filter" }),
278
- R("span", { className: "hide-600px" }, T` Show Quickfilters`)
279
- )
280
- : undefined,
281
-
282
- // R 'a', key: "export", className: "btn btn-link btn-sm", onClick: @handleSaveDesignFile,
283
- // R('span', className: "glyphicon glyphicon-download-alt")
284
- // " Export"
285
- this.state.editing
286
- ? R(
287
- "a",
288
- { key: "settings", className: "btn btn-link btn-sm", onClick: this.handleSettings },
289
- R("span", { className: "fas fa-cog" }),
290
- R("span", { className: "hide-600px" }, T` Settings`)
291
- )
292
- : undefined,
293
- this.state.editing ? this.renderStyle() : undefined,
294
- this.props.extraTitleButtonsElem,
295
- this.props.onDesignChange != null ? this.renderEditingSwitch() : undefined
257
+ return (
258
+ <div>
259
+ {this.state.editing
260
+ ? [
261
+ <a
262
+ key="undo"
263
+ className={`btn btn-link btn-sm ${!this.state.undoStack.canUndo() ? "disabled" : ""}`}
264
+ onClick={this.handleUndo}
265
+ >
266
+ <span className="fas fa-caret-left"/>
267
+ <span className="hide-600px"> {T`Undo`}</span>
268
+ </a>,
269
+ " ",
270
+ <a
271
+ key="redo"
272
+ className={`btn btn-link btn-sm ${!this.state.undoStack.canRedo() ? "disabled" : ""}`}
273
+ onClick={this.handleRedo}
274
+ >
275
+ <span className="fas fa-caret-right"/>
276
+ <span className="hide-600px"> {T`Redo`}</span>
277
+ </a>
278
+ ]
279
+ : undefined}
280
+ {!this.state.editing && this.props.design.otherLocales && this.props.design.otherLocales.length > 0
281
+ ? <div key="translations" className="dropdown d-inline-block">
282
+ <a
283
+ className="btn btn-link btn-sm dropdown-toggle"
284
+ data-bs-toggle="dropdown"
285
+ >
286
+ <span className="fal fa-globe"/>
287
+ {" "}
288
+ {this.state.locale}
289
+ </a>
290
+ <ul className="dropdown-menu dropdown-menu-end">
291
+ {[this.props.design.locale || "en", ...this.props.design.otherLocales].map(locale =>
292
+ <li key={locale}>
293
+ <a
294
+ className="dropdown-item"
295
+ onClick={() => this.setState({ locale: locale })}
296
+ >
297
+ {languages.find(l => l.code === locale)?.name || locale}
298
+ </a>
299
+ </li>
300
+ )}
301
+ </ul>
302
+ </div>
303
+ : undefined}
304
+ <a key="print" className="btn btn-link btn-sm" onClick={this.handlePrint}>
305
+ <span className="fas fa-print"/>
306
+ <span className="hide-600px"> {T`Print`}</span>
307
+ </a>
308
+ <a key="refresh" className="btn btn-link btn-sm" onClick={this.handleRefreshData}>
309
+ <span className="fas fa-sync"/>
310
+ <span className="hide-600px"> {T`Refresh`}</span>
311
+ </a>
312
+ {this.state.hideQuickfilters && this.props.design.quickfilters && this.props.design.quickfilters.length > 0
313
+ ? <a key="showQuickfilters" className="btn btn-link btn-sm" onClick={this.handleShowQuickfilters}>
314
+ <span className="fa fa-filter"/>
315
+ <span className="hide-600px"> {T`Show Quickfilters`}</span>
316
+ </a>
317
+ : undefined}
318
+
319
+ {this.state.editing
320
+ ? <a key="settings" className="btn btn-link btn-sm" onClick={this.handleSettings}>
321
+ <span className="fas fa-cog"/>
322
+ <span className="hide-600px"> {T`Settings`}</span>
323
+ </a>
324
+ : undefined}
325
+ {this.state.editing ? this.renderStyle() : undefined}
326
+ {this.props.extraTitleButtonsElem}
327
+ {this.props.onDesignChange != null ? this.renderEditingSwitch() : undefined}
328
+ </div>
296
329
  )
297
330
  }
298
331
 
299
332
  renderTitleBar() {
300
- return R(
301
- "div",
302
- { style: { height: 40, padding: 4 } },
303
- R("div", { style: { float: "right" } }, this.renderActionLinks()),
304
- this.props.titleElem
333
+ return (
334
+ <div style={{ height: 40, padding: 4 }}>
335
+ <div style={{ float: "right" }}>{this.renderActionLinks()}</div>
336
+ {this.props.titleElem}
337
+ </div>
305
338
  )
306
339
  }
307
340
 
308
341
  renderQuickfilter() {
309
- return R(QuickfiltersComponent, {
310
- design: this.props.design.quickfilters || [],
311
- schema: this.props.schema,
312
- dataSource: this.props.dataSource,
313
- quickfiltersDataSource: this.props.dashboardDataSource.getQuickfiltersDataSource(),
314
- values: this.state.quickfiltersValues || undefined,
315
- onValuesChange: (values: any) => this.setState({ quickfiltersValues: values }),
316
- locks: this.props.quickfilterLocks,
317
- filters: this.getCompiledFilters(),
318
- hideTopBorder: this.props.hideTitleBar,
342
+ return <QuickfiltersComponent
343
+ design={this.props.design.quickfilters || []}
344
+ schema={this.props.schema}
345
+ dataSource={this.props.dataSource}
346
+ quickfiltersDataSource={this.props.dashboardDataSource.getQuickfiltersDataSource()}
347
+ values={this.state.quickfiltersValues || undefined}
348
+ onValuesChange={(values: any) => this.setState({ quickfiltersValues: values })}
349
+ locks={this.props.quickfilterLocks}
350
+ filters={this.getCompiledFilters()}
351
+ hideTopBorder={this.props.hideTitleBar}
319
352
  // Don't hide if title bar is hidden as it can't be shown again
320
- onHide: () => !this.props.hideTitleBar ? this.setState({ hideQuickfilters: true }) : undefined
321
- })
353
+ onHide={() => this.setState({ hideQuickfilters: true })}
354
+ translate={this.translate}
355
+ />
356
+ }
357
+
358
+ renderFloatingShowQuickfiltersButton() {
359
+ // Only show if:
360
+ // 1. Quick filters exist
361
+ // 2. Quick filters are hidden
362
+ // 3. Title bar is hidden (since otherwise button is in title bar)
363
+ if (!this.props.design.quickfilters?.length || !this.state.hideQuickfilters || !this.props.hideTitleBar) {
364
+ return null
365
+ }
366
+
367
+ return (
368
+ <div style={{
369
+ position: "absolute",
370
+ top: 5,
371
+ right: 20,
372
+ zIndex: 1000
373
+ }}>
374
+ <button
375
+ className="btn btn-link btn-sm"
376
+ onClick={() => this.setState({ hideQuickfilters: false })}
377
+ >
378
+ <i className="fa fa-angle-double-down"/>
379
+ </button>
380
+ </div>
381
+ )
322
382
  }
323
383
 
324
384
  refDashboardView = (el: any) => {
@@ -337,37 +397,40 @@ export default class DashboardComponent extends React.Component<DashboardCompone
337
397
  )
338
398
  )
339
399
 
340
- const dashboardView = R(DashboardViewComponent, {
341
- schema: this.props.schema,
342
- dataSource: this.props.dataSource,
343
- dashboardDataSource: this.props.dashboardDataSource,
344
- ref: this.refDashboardView,
345
- design: this.props.design,
346
- onDesignChange: this.state.editing ? this.props.onDesignChange : undefined,
347
- filters,
348
- onRowClick: this.props.onRowClick,
349
- namedStrings: this.props.namedStrings,
350
- hideScopes: this.state.hideQuickfilters,
351
- refreshKey: this.state.refreshKey
352
- })
353
-
354
- const readonlyDashboardView = R(DashboardViewComponent, {
355
- schema: this.props.schema,
356
- dataSource: this.props.dataSource,
357
- dashboardDataSource: this.props.dashboardDataSource,
358
- ref: this.refDashboardView,
359
- design: this.props.design,
360
- filters,
361
- onRowClick: this.props.onRowClick,
362
- namedStrings: this.props.namedStrings,
363
- hideScopes: this.state.hideQuickfilters
364
- })
365
-
400
+ const displayLocale = this.state.editing ? this.props.design.locale || "en" : this.state.locale
401
+
402
+ const dashboardView = <DashboardViewComponent
403
+ schema={this.props.schema}
404
+ dataSource={this.props.dataSource}
405
+ dashboardDataSource={this.props.dashboardDataSource}
406
+ ref={this.refDashboardView}
407
+ design={this.props.design}
408
+ onDesignChange={this.state.editing ? this.props.onDesignChange : undefined}
409
+ filters={filters}
410
+ onRowClick={this.props.onRowClick}
411
+ namedStrings={this.props.namedStrings}
412
+ hideScopes={this.state.hideQuickfilters}
413
+ refreshKey={this.state.refreshKey}
414
+ locale={displayLocale}
415
+ />
416
+
417
+ const readonlyDashboardView = <DashboardViewComponent
418
+ schema={this.props.schema}
419
+ dataSource={this.props.dataSource}
420
+ dashboardDataSource={this.props.dashboardDataSource}
421
+ ref={this.refDashboardView}
422
+ design={this.props.design}
423
+ filters={filters}
424
+ onRowClick={this.props.onRowClick}
425
+ namedStrings={this.props.namedStrings}
426
+ hideScopes={this.state.hideQuickfilters}
427
+ locale={displayLocale}
428
+ />
366
429
 
367
430
  // Pass active tables down to table select components so they can present a shorter list
368
431
  return <ActiveTablesContext.Provider
369
432
  value={DashboardUtils.getFilterableTables(this.props.design, this.props.schema)}>
370
- <LocaleContext.Provider value={this.props.design.locale ?? "en"}>
433
+ <LocaleContext.Provider value={displayLocale}>
371
434
  <div style={{
372
435
  display: "grid",
373
436
  gridTemplateRows: this.props.hideTitleBar ? "auto 1fr" : "auto auto 1fr",
@@ -376,6 +439,7 @@ export default class DashboardComponent extends React.Component<DashboardCompone
376
439
  {!this.props.hideTitleBar ? this.renderTitleBar() : undefined}
377
440
  <div>{!this.state.hideQuickfilters ? this.renderQuickfilter() : undefined}</div>
378
441
  {dashboardView}
442
+ {this.renderFloatingShowQuickfiltersButton()}
379
443
  {this.props.onDesignChange != null && (
380
444
  <SettingsModalComponent
381
445
  onDesignChange={this.handleDesignChange}
@@ -2,6 +2,7 @@ import { Quickfilter } from "../quickfilter/Quickfilter"
2
2
  import { Expr } from "@mwater/expressions"
3
3
  import { BlocksLayoutOptions, DashboardTheme } from "./layoutOptions"
4
4
  import { GlobalFilter } from "../GlobalFilter"
5
+ import { LayoutBlock } from "../layouts/blocks/blockUtils"
5
6
 
6
7
  /** Dashboard design
7
8
  * Each understands enough of the dashboard design to create widgets.
@@ -9,7 +10,7 @@ import { GlobalFilter } from "../GlobalFilter"
9
10
  */
10
11
  export interface DashboardDesign {
11
12
  /** dashboard items. Format depends on layout of dashboard. See layouts/.../README.md */
12
- items: any // TODO
13
+ items: LayoutBlock
13
14
 
14
15
  /** array of quick filters (user-selectable filters). See quickfilter/README.md */
15
16
  quickfilters?: Quickfilter[]
@@ -26,9 +27,15 @@ export interface DashboardDesign {
26
27
  /** filter expression indexed by table. e.g. { sometable: logical expression, etc. } */
27
28
  filters?: { [tableId: string]: Expr }
28
29
 
29
- /** optional locale (e.g. "fr") to use for display */
30
+ /** optional locale (e.g. "fr") to use for display. Defaults to "en" */
30
31
  locale?: string
31
32
 
33
+ /** Other locales that the dashboard is available in. */
34
+ otherLocales?: string[]
35
+
36
+ /** Translation map for dashboard. Maps locale to translation map. Does not include default locale. */
37
+ translations?: { [locale: string]: { [key: string]: string } }
38
+
32
39
  /** true to enable implicit filtering (see ImplicitFilterBuilder). Defaults to true for older dashboards. */
33
40
  implicitFiltersEnabled?: boolean
34
41
 
@@ -25,6 +25,45 @@ export function getFilterableTables(design: DashboardDesign, schema: Schema) {
25
25
  return filterableTables
26
26
  }
27
27
 
28
+ /** Gets all translatable strings from a dashboard */
29
+ export function getTranslatableStringsFromDashboard(design: DashboardDesign, schema: Schema): string[] {
30
+ const layoutManager = LayoutManager.createLayoutManager(design.layout)
31
+
32
+ // Get translatable strings from layout manager
33
+ let strings = getTranslatableStringsFromLayoutManager(layoutManager, design.items, schema)
34
+
35
+ // Get translatable strings from quickfilters
36
+ if (design.quickfilters) {
37
+ for (let quickfilter of design.quickfilters) {
38
+ if (quickfilter.label) {
39
+ strings.push(quickfilter.label)
40
+ }
41
+ }
42
+ }
43
+
44
+ // Remove duplicates
45
+ return _.uniq(strings)
46
+ }
47
+
48
+ /** Gets translatable strings from a layout manager and items */
49
+ export function getTranslatableStringsFromLayoutManager(
50
+ layoutManager: LayoutManager,
51
+ items: any,
52
+ schema: Schema
53
+ ) {
54
+ let strings: string[] = []
55
+ for (let widgetItem of layoutManager.getAllWidgets(items)) {
56
+ // Create widget
57
+ const widget = WidgetFactory.createWidget(widgetItem.type)
58
+
59
+ // Get translatable strings
60
+ strings = strings.concat(widget.getTranslatableStrings(widgetItem.design, schema))
61
+ }
62
+
63
+ // Remove duplicates
64
+ return _.uniq(strings)
65
+ }
66
+
28
67
  /** Get filters from props filters combined with dashboard filters */
29
68
  export function getCompiledFilters(
30
69
  design: DashboardDesign,
@@ -1,5 +1,5 @@
1
1
  import _ from "lodash"
2
- import React, { CSSProperties, useEffect, useImperativeHandle, useRef, useMemo, useState } from "react"
2
+ import React, { CSSProperties, useEffect, useImperativeHandle, useRef, useMemo, useState, useCallback } from "react"
3
3
 
4
4
  import ImplicitFilterBuilder from "../ImplicitFilterBuilder"
5
5
  import * as DashboardUtils from "./DashboardUtils"
@@ -51,6 +51,9 @@ export interface DashboardViewComponentProps {
51
51
 
52
52
  /** Change to force a refresh */
53
53
  refreshKey?: any
54
+
55
+ /** Locale to use for display. Defaults to dashboard design locale. */
56
+ locale?: string
54
57
  }
55
58
 
56
59
  export interface DashboardViewComponentHandle {
@@ -211,6 +214,20 @@ const DashboardViewComponent = React.forwardRef<DashboardViewComponentHandle, Da
211
214
  )
212
215
  }
213
216
 
217
+ /** Locale that the dashboard design is in */
218
+ const designLocale = props.design.locale ?? "en"
219
+
220
+ /** Locale to display the dashboard in. If editing, always use design locale. */
221
+ const displayLocale = props.onDesignChange != null ? designLocale : (props.locale ?? designLocale ?? "en")
222
+
223
+ /** Translate function to use for display. Do not use when editing. */
224
+ const translate = useCallback((input: string) => {
225
+ if (designLocale === displayLocale) {
226
+ return input
227
+ }
228
+ return props.design.translations?.[displayLocale]?.[input] ?? input
229
+ }, [props.design.translations, designLocale, displayLocale])
230
+
214
231
  const compRef = (widgetId: any, comp: any) => {
215
232
  return (widgetComps.current[widgetId] = comp)
216
233
  }
@@ -254,7 +271,6 @@ const DashboardViewComponent = React.forwardRef<DashboardViewComponentHandle, Da
254
271
  const widgetElem = (
255
272
  <WidgetComponent
256
273
  key={options.id}
257
- id={options.id}
258
274
  type={options.type}
259
275
  schema={props.schema}
260
276
  dataSource={props.dataSource}
@@ -273,6 +289,9 @@ const DashboardViewComponent = React.forwardRef<DashboardViewComponentHandle, Da
273
289
  // Keep references to widget elements
274
290
  widgetRef={compRef.bind(null, options.id)}
275
291
  refreshKey={props.refreshKey}
292
+ // Use locale from props, design, or default to en
293
+ locale={displayLocale}
294
+ translate={translate}
276
295
  />
277
296
  )
278
297
 
@@ -292,7 +311,7 @@ const DashboardViewComponent = React.forwardRef<DashboardViewComponentHandle, Da
292
311
 
293
312
  // Render widget container
294
313
  return (
295
- <LocaleContext.Provider value={props.design.locale ?? "en"}>
314
+ <LocaleContext.Provider value={displayLocale}>
296
315
  <div style={style}>
297
316
  {!props.hideScopes ? renderScopes() : undefined}
298
317
 
@@ -377,7 +377,8 @@ class ServerWidgetLayerDataSource implements MapLayerDataSource {
377
377
  }
378
378
  const { token, expires } = await response.json()
379
379
 
380
- return { url: this.options.apiUrl + `vector_tiles/tiles/{z}/{x}/{y}?token=${token}`, expires }
380
+ // Client isn't necessary, but allows tracking of usage easier
381
+ return { url: this.options.apiUrl + `vector_tiles/tiles/{z}/{x}/{y}?token=${token}&client=${this.options.client ?? ""}`, expires }
381
382
  }
382
383
 
383
384
  // Gets widget data source for a popup widget