@mwater/visualization 5.4.1 → 5.4.2

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 (269) 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 +6 -0
  21. package/lib/dashboards/DashboardComponent.js +44 -12
  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/layouts/blocks/HorizontalBlockComponent.js +2 -2
  47. package/lib/mWaterLoader.d.ts +1 -1
  48. package/lib/maps/BufferLayer.d.ts +7 -5
  49. package/lib/maps/BufferLayer.js +69 -48
  50. package/lib/maps/BufferLayerDesign.d.ts +21 -14
  51. package/lib/maps/BufferLayerDesignerComponent.d.ts +16 -31
  52. package/lib/maps/BufferLayerDesignerComponent.js +68 -102
  53. package/lib/maps/ChoroplethLayer.d.ts +5 -4
  54. package/lib/maps/ChoroplethLayer.js +32 -9
  55. package/lib/maps/ChoroplethLayerDesign.d.ts +6 -2
  56. package/lib/maps/ChoroplethLayerDesigner.js +4 -2
  57. package/lib/maps/ClusterLayer.d.ts +3 -4
  58. package/lib/maps/ClusterLayer.js +2 -1
  59. package/lib/maps/DetailLevelSelectComponent.js +1 -1
  60. package/lib/maps/DirectMapDataSource.js +2 -1
  61. package/lib/maps/EditPopupComponent.js +5 -3
  62. package/lib/maps/GridLayer.d.ts +3 -4
  63. package/lib/maps/GridLayer.js +2 -1
  64. package/lib/maps/GridLayerDesigner.js +5 -3
  65. package/lib/maps/HoverContent.d.ts +11 -3
  66. package/lib/maps/HoverContent.js +25 -9
  67. package/lib/maps/Layer.d.ts +24 -3
  68. package/lib/maps/Layer.js +5 -1
  69. package/lib/maps/LayerFactory.js +0 -8
  70. package/lib/maps/LayerLegendComponent.js +0 -1
  71. package/lib/maps/LayerSwitcherComponent.d.ts +1 -0
  72. package/lib/maps/LayerSwitcherComponent.js +1 -1
  73. package/lib/maps/LeafletMapComponent.js +3 -1
  74. package/lib/maps/LegendComponent.d.ts +1 -0
  75. package/lib/maps/LegendComponent.js +9 -1
  76. package/lib/maps/MWaterServerLayer.d.ts +2 -2
  77. package/lib/maps/MWaterServerLayer.js +2 -2
  78. package/lib/maps/MapComponent.js +3 -3
  79. package/lib/maps/MapDesign.d.ts +2 -0
  80. package/lib/maps/MapDesignerComponent.d.ts +4 -3
  81. package/lib/maps/MapDesignerComponent.js +68 -74
  82. package/lib/maps/MapLayerViewDesignerComponent.js +2 -2
  83. package/lib/maps/MapUtils.d.ts +4 -0
  84. package/lib/maps/MapUtils.js +19 -0
  85. package/lib/maps/MapViewComponent.d.ts +8 -3
  86. package/lib/maps/MarkersLayer.d.ts +5 -4
  87. package/lib/maps/MarkersLayer.js +33 -7
  88. package/lib/maps/MarkersLayerDesign.d.ts +19 -16
  89. package/lib/maps/PopupFilterJoinsUtils.d.ts +6 -3
  90. package/lib/maps/PopupFilterJoinsUtils.js +0 -6
  91. package/lib/maps/RasterMapViewComponent.d.ts +3 -31
  92. package/lib/maps/RasterMapViewComponent.js +7 -2
  93. package/lib/maps/ServerMapDataSource.js +2 -1
  94. package/lib/maps/SwitchableTileUrlLayer.d.ts +3 -3
  95. package/lib/maps/SwitchableTileUrlLayer.js +2 -1
  96. package/lib/maps/TileUrlLayer.d.ts +4 -5
  97. package/lib/maps/TileUrlLayer.js +2 -1
  98. package/lib/maps/VectorMapViewComponent.d.ts +5 -37
  99. package/lib/maps/VectorMapViewComponent.js +19 -8
  100. package/lib/maps/maps.d.ts +3 -0
  101. package/lib/quickfilter/QuickfiltersComponent.d.ts +2 -0
  102. package/lib/quickfilter/QuickfiltersComponent.js +9 -7
  103. package/lib/quickfilter/QuickfiltersDesignComponent.d.ts +1 -1
  104. package/lib/quickfilter/QuickfiltersDesignComponent.js +19 -35
  105. package/lib/richtext/ExprItemsHtmlConverter.d.ts +5 -2
  106. package/lib/richtext/ExprItemsHtmlConverter.js +4 -4
  107. package/lib/richtext/ExprItemsTranslator.d.ts +5 -0
  108. package/lib/richtext/ExprItemsTranslator.js +149 -0
  109. package/lib/richtext/ItemsHtmlConverter.d.ts +1 -1
  110. package/lib/richtext/ItemsHtmlConverter.js +31 -15
  111. package/lib/wellknown.js +12 -9
  112. package/lib/widgets/IFrameWidget.d.ts +4 -4
  113. package/lib/widgets/ImageWidget.d.ts +7 -4
  114. package/lib/widgets/ImageWidget.js +9 -1
  115. package/lib/widgets/ImageWidgetComponent.d.ts +1 -0
  116. package/lib/widgets/ImageWidgetComponent.js +1 -1
  117. package/lib/widgets/MapWidget.d.ts +5 -48
  118. package/lib/widgets/MapWidget.js +26 -63
  119. package/lib/widgets/MarkdownWidget.d.ts +3 -0
  120. package/lib/widgets/MarkdownWidget.js +3 -0
  121. package/lib/widgets/TOCWidget.d.ts +15 -27
  122. package/lib/widgets/TOCWidget.js +107 -183
  123. package/lib/widgets/Widget.d.ts +18 -7
  124. package/lib/widgets/Widget.js +4 -0
  125. package/lib/widgets/WidgetScopesViewComponent.js +1 -1
  126. package/lib/widgets/charts/Chart.d.ts +10 -1
  127. package/lib/widgets/charts/Chart.js +22 -11
  128. package/lib/widgets/charts/ChartViewComponent.d.ts +4 -0
  129. package/lib/widgets/charts/ChartViewComponent.js +6 -3
  130. package/lib/widgets/charts/ChartWidget.d.ts +2 -0
  131. package/lib/widgets/charts/ChartWidget.js +9 -1
  132. package/lib/widgets/charts/ChartWidgetComponent.d.ts +4 -0
  133. package/lib/widgets/charts/ChartWidgetComponent.js +2 -2
  134. package/lib/widgets/charts/calendar/CalendarChart.d.ts +1 -0
  135. package/lib/widgets/charts/calendar/CalendarChart.js +26 -0
  136. package/lib/widgets/charts/calendar/CalendarChartViewComponent.js +3 -1
  137. package/lib/widgets/charts/imagemosaic/ImageMosaicChart.d.ts +1 -0
  138. package/lib/widgets/charts/imagemosaic/ImageMosaicChart.js +8 -0
  139. package/lib/widgets/charts/layered/LayeredChart.d.ts +2 -0
  140. package/lib/widgets/charts/layered/LayeredChart.js +63 -3
  141. package/lib/widgets/charts/layered/LayeredChartCompiler.d.ts +1 -1
  142. package/lib/widgets/charts/layered/LayeredChartCompiler.js +1 -1
  143. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.js +2 -2
  144. package/lib/widgets/charts/layered/LayeredChartViewComponent.js +8 -3
  145. package/lib/widgets/charts/pivot/PivotChart.d.ts +1 -0
  146. package/lib/widgets/charts/pivot/PivotChart.js +63 -0
  147. package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +1 -1
  148. package/lib/widgets/charts/pivot/SegmentDesignerComponent.js +7 -4
  149. package/lib/widgets/charts/table/OrderingsComponent.js +1 -1
  150. package/lib/widgets/charts/table/TableChart.d.ts +1 -0
  151. package/lib/widgets/charts/table/TableChart.js +15 -0
  152. package/lib/widgets/text/TextComponent.d.ts +11 -4
  153. package/lib/widgets/text/TextComponent.js +11 -8
  154. package/lib/widgets/text/TextWidget.d.ts +6 -3
  155. package/lib/widgets/text/TextWidget.js +7 -1
  156. package/lib/widgets/text/TextWidgetComponent.d.ts +4 -0
  157. package/lib/widgets/text/TextWidgetComponent.js +7 -1
  158. package/lib/widgets/text/TextWidgetDesign.d.ts +2 -4
  159. package/lib/widgets/text/TextWidgetDesign.js +1 -1
  160. package/package.json +7 -8
  161. package/src/ColorComponent.tsx +1 -2
  162. package/src/IdSelection.ts +62 -0
  163. package/src/MWaterAddRelatedIndicatorComponent.ts +3 -2
  164. package/src/MWaterCompleteTableSelectComponent.tsx +36 -46
  165. package/src/MWaterLoaderComponent.ts +28 -26
  166. package/src/MWaterResponsesFilterComponent.ts +5 -2
  167. package/src/MWaterTableSelectComponent.tsx +5 -9
  168. package/src/autotranslate.ts +141 -0
  169. package/src/axes/AxisBuilder.ts +3 -3
  170. package/src/axes/AxisColorEditorComponent.tsx +5 -0
  171. package/src/axes/{AxisComponent.ts → AxisComponent.tsx} +106 -106
  172. package/src/axes/CategoryMapComponent.ts +4 -4
  173. package/src/axes/RangesComponent.ts +3 -2
  174. package/src/dashboards/DashboardComponent.tsx +79 -14
  175. package/src/dashboards/DashboardDesign.ts +9 -2
  176. package/src/dashboards/DashboardUtils.ts +39 -0
  177. package/src/dashboards/DashboardViewComponent.tsx +22 -3
  178. package/src/dashboards/ServerDashboardDataSource.ts +2 -1
  179. package/src/dashboards/SettingsModalComponent.tsx +450 -35
  180. package/src/dashboards/WidgetComponent.tsx +12 -6
  181. package/src/datagrids/CellEditor.tsx +354 -0
  182. package/src/datagrids/DatagridComponent.tsx +646 -0
  183. package/src/datagrids/DatagridViewComponent.tsx +539 -0
  184. package/src/datagrids/DirectDatagridDataSource.ts +2 -3
  185. package/src/datagrids/{ExprCellComponent.ts → ExprCellComponent.tsx} +28 -23
  186. package/src/datagrids/{FindReplaceModalComponent.ts → FindReplaceModalComponent.tsx} +109 -122
  187. package/src/index.css +1 -1
  188. package/src/index.ts +0 -1
  189. package/src/layouts/blocks/HorizontalBlockComponent.ts +2 -2
  190. package/src/mWaterLoader.ts +1 -1
  191. package/src/maps/BufferLayer.ts +83 -60
  192. package/src/maps/BufferLayerDesign.ts +20 -14
  193. package/src/maps/BufferLayerDesignerComponent.tsx +309 -0
  194. package/src/maps/ChoroplethLayer.ts +40 -19
  195. package/src/maps/ChoroplethLayerDesign.ts +4 -2
  196. package/src/maps/ChoroplethLayerDesigner.tsx +4 -2
  197. package/src/maps/ClusterLayer.ts +4 -10
  198. package/src/maps/DetailLevelSelectComponent.ts +1 -1
  199. package/src/maps/DirectMapDataSource.ts +2 -1
  200. package/src/maps/EditPopupComponent.ts +7 -3
  201. package/src/maps/GridLayer.ts +4 -10
  202. package/src/maps/GridLayerDesigner.tsx +5 -3
  203. package/src/maps/HoverContent.tsx +40 -16
  204. package/src/maps/Layer.ts +28 -10
  205. package/src/maps/LayerFactory.ts +0 -8
  206. package/src/maps/LayerLegendComponent.ts +2 -4
  207. package/src/maps/LayerSwitcherComponent.tsx +6 -2
  208. package/src/maps/LeafletMapComponent.tsx +3 -1
  209. package/src/maps/LegendComponent.tsx +10 -1
  210. package/src/maps/MWaterServerLayer.ts +3 -3
  211. package/src/maps/MapComponent.ts +3 -3
  212. package/src/maps/MapDesign.ts +3 -0
  213. package/src/maps/MapDesignerComponent.tsx +165 -162
  214. package/src/maps/MapLayerViewDesignerComponent.ts +2 -2
  215. package/src/maps/MapUtils.ts +24 -0
  216. package/src/maps/MapViewComponent.tsx +11 -3
  217. package/src/maps/MarkersLayer.ts +44 -18
  218. package/src/maps/MarkersLayerDesign.ts +19 -16
  219. package/src/maps/PopupFilterJoinsUtils.ts +6 -2
  220. package/src/maps/RasterMapViewComponent.ts +9 -45
  221. package/src/maps/ServerMapDataSource.ts +2 -2
  222. package/src/maps/SwitchableTileUrlLayer.tsx +4 -10
  223. package/src/maps/TileUrlLayer.tsx +4 -10
  224. package/src/maps/VectorMapViewComponent.tsx +28 -55
  225. package/src/maps/maps.ts +3 -0
  226. package/src/quickfilter/QuickfiltersComponent.ts +13 -7
  227. package/src/quickfilter/QuickfiltersDesignComponent.tsx +56 -74
  228. package/src/richtext/ExprItemsHtmlConverter.ts +9 -5
  229. package/src/richtext/ExprItemsTranslator.ts +176 -0
  230. package/src/richtext/ItemsHtmlConverter.ts +33 -18
  231. package/src/wellknown.ts +33 -30
  232. package/src/widgets/ImageWidget.ts +10 -1
  233. package/src/widgets/ImageWidgetComponent.ts +3 -2
  234. package/src/widgets/{MapWidget.ts → MapWidget.tsx} +90 -101
  235. package/src/widgets/MarkdownWidget.ts +3 -0
  236. package/src/widgets/TOCWidget.tsx +281 -0
  237. package/src/widgets/Widget.ts +25 -5
  238. package/src/widgets/WidgetScopesViewComponent.ts +2 -1
  239. package/src/widgets/charts/Chart.ts +31 -12
  240. package/src/widgets/charts/ChartViewComponent.ts +13 -3
  241. package/src/widgets/charts/ChartWidget.ts +11 -1
  242. package/src/widgets/charts/ChartWidgetComponent.tsx +9 -1
  243. package/src/widgets/charts/calendar/CalendarChart.ts +29 -0
  244. package/src/widgets/charts/calendar/CalendarChartViewComponent.tsx +3 -1
  245. package/src/widgets/charts/imagemosaic/ImageMosaicChart.ts +9 -0
  246. package/src/widgets/charts/layered/LayeredChart.ts +71 -3
  247. package/src/widgets/charts/layered/LayeredChartCompiler.ts +2 -2
  248. package/src/widgets/charts/layered/LayeredChartDesignerComponent.tsx +4 -2
  249. package/src/widgets/charts/layered/LayeredChartViewComponent.ts +10 -4
  250. package/src/widgets/charts/pivot/PivotChart.ts +73 -0
  251. package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +1 -1
  252. package/src/widgets/charts/pivot/SegmentDesignerComponent.tsx +6 -4
  253. package/src/widgets/charts/table/OrderingsComponent.tsx +2 -1
  254. package/src/widgets/charts/table/TableChart.ts +17 -0
  255. package/src/widgets/text/TextComponent.tsx +22 -12
  256. package/src/widgets/text/TextWidget.ts +9 -2
  257. package/src/widgets/text/TextWidgetComponent.tsx +16 -1
  258. package/src/widgets/text/TextWidgetDesign.ts +4 -7
  259. package/test/IdSelectionTests.ts +54 -0
  260. package/test/LayeredChartCompilerTests.ts +0 -2
  261. package/test/richtext/ExprItemsTranslatorTests.ts +144 -0
  262. package/test/wellknownTests.ts +144 -0
  263. package/src/datagrids/DatagridComponent.ts +0 -478
  264. package/src/datagrids/DatagridViewComponent.ts +0 -464
  265. package/src/datagrids/EditExprCellComponent.tsx +0 -305
  266. package/src/datagrids/README.md +0 -3
  267. package/src/maps/BufferLayerDesignerComponent.ts +0 -311
  268. package/src/widgets/TOCWidget.ts +0 -326
  269. package/test/LegoLayoutEngineTests.ts +0 -69
@@ -15,7 +15,7 @@ import ModalWindowComponent from "@mwater/react-library/lib/ModalWindowComponent
15
15
  import { getLayoutOptions } from "./layoutOptions"
16
16
  import { DashboardDesign } from "./DashboardDesign"
17
17
  import DashboardDataSource from "./DashboardDataSource"
18
- import { JsonQLFilter } from ".."
18
+ import { JsonQLFilter, languages } from ".."
19
19
  import { ActiveTablesContext, LocaleContext } from "@mwater/expressions-ui"
20
20
 
21
21
  export interface DashboardComponentProps {
@@ -61,6 +61,9 @@ export interface DashboardComponentProps {
61
61
 
62
62
  /** Called when the edit mode changes */
63
63
  onEditModeChange?: (editing: boolean) => void
64
+
65
+ /** Locale to prefer if available */
66
+ preferredLocale?: string
64
67
  }
65
68
 
66
69
  export interface DashboardComponentState {
@@ -70,6 +73,8 @@ export interface DashboardComponentState {
70
73
  layoutOptionsOpen: boolean
71
74
  hideQuickfilters: boolean
72
75
  refreshKey: number
76
+ /** Locale to use for display. Ignored if in edit mode */
77
+ locale: string
73
78
  }
74
79
 
75
80
  /** Dashboard component that includes an action bar at the top
@@ -87,6 +92,15 @@ export default class DashboardComponent extends React.Component<DashboardCompone
87
92
 
88
93
  const layoutOptions = getLayoutOptions(props.design)
89
94
 
95
+ // Prefer the T.en locale if available when loading the dashboard
96
+ let initialLocale = props.design.locale || "en"
97
+ const otherLocales = props.design.otherLocales || []
98
+ if (props.preferredLocale && otherLocales.includes(props.preferredLocale)) {
99
+ initialLocale = props.preferredLocale
100
+ } else if (otherLocales.includes(T.locale)) {
101
+ initialLocale = T.locale
102
+ }
103
+
90
104
  this.state = {
91
105
  undoStack: new UndoStack().push(props.design),
92
106
  quickfiltersValues: props.quickfiltersValues || null,
@@ -96,7 +110,8 @@ export default class DashboardComponent extends React.Component<DashboardCompone
96
110
  layoutOptionsOpen: false,
97
111
  hideQuickfilters:
98
112
  layoutOptions.hideQuickfiltersWidth != null && layoutOptions.hideQuickfiltersWidth > document.body.clientWidth,
99
- refreshKey: 1
113
+ refreshKey: 1,
114
+ locale: initialLocale
100
115
  }
101
116
 
102
117
  if (props.onEditModeChange) {
@@ -207,6 +222,16 @@ export default class DashboardComponent extends React.Component<DashboardCompone
207
222
  return compiledFilters
208
223
  }
209
224
 
225
+ /** Translate function to use for display. Do not use when editing. */
226
+ translate = (input: string) => {
227
+ const designLocale = this.props.design.locale ?? "en"
228
+ const displayLocale = this.state.editing ? designLocale : (this.state.locale ?? designLocale ?? "en")
229
+ if (designLocale === displayLocale) {
230
+ return input
231
+ }
232
+ return this.props.design.translations?.[displayLocale]?.[input] ?? input
233
+ }
234
+
210
235
  renderEditingSwitch() {
211
236
  return R(
212
237
  "a",
@@ -216,7 +241,8 @@ export default class DashboardComponent extends React.Component<DashboardCompone
216
241
  onClick: this.handleToggleEditing
217
242
  },
218
243
  R("span", { className: "fas fa-pencil-alt" }),
219
- this.state.editing ? T` Editing` : T` Edit`
244
+ " ",
245
+ this.state.editing ? T`Editing` : T`Edit`
220
246
  )
221
247
  }
222
248
 
@@ -225,7 +251,7 @@ export default class DashboardComponent extends React.Component<DashboardCompone
225
251
  "button",
226
252
  { type: "button", key: "style", className: "btn btn-link btn-sm", onClick: this.handleOpenLayoutOptions },
227
253
  R("span", { className: "fa fa-mobile" }),
228
- R("span", { className: "hide-600px" }, T` Layout `)
254
+ R("span", { className: "hide-600px" }, " ", T`Layout`)
229
255
  )
230
256
  }
231
257
 
@@ -243,7 +269,7 @@ export default class DashboardComponent extends React.Component<DashboardCompone
243
269
  onClick: this.handleUndo
244
270
  },
245
271
  R("span", { className: "fas fa-caret-left" }),
246
- R("span", { className: "hide-600px" }, T` Undo`)
272
+ R("span", { className: "hide-600px" }, " ", T`Undo`)
247
273
  ),
248
274
  " ",
249
275
  R(
@@ -254,28 +280,62 @@ export default class DashboardComponent extends React.Component<DashboardCompone
254
280
  onClick: this.handleRedo
255
281
  },
256
282
  R("span", { className: "fas fa-caret-right" }),
257
- R("span", { className: "hide-600px" }, T` Redo`)
283
+ R("span", { className: "hide-600px" }, " ", T`Redo`)
258
284
  )
259
285
  ]
260
286
  : undefined,
287
+ !this.state.editing && this.props.design.otherLocales && this.props.design.otherLocales.length > 0
288
+ ? R(
289
+ "div",
290
+ { key: "translations", className: "dropdown d-inline-block" },
291
+ R(
292
+ "a",
293
+ {
294
+ className: "btn btn-link btn-sm dropdown-toggle",
295
+ "data-bs-toggle": "dropdown"
296
+ },
297
+ R("span", { className: "fal fa-globe" }),
298
+ " ",
299
+ this.state.locale
300
+ ),
301
+ R(
302
+ "ul",
303
+ { className: "dropdown-menu dropdown-menu-end" },
304
+ [this.props.design.locale || "en", ...this.props.design.otherLocales].map(locale =>
305
+ R(
306
+ "li",
307
+ { key: locale },
308
+ R(
309
+ "a",
310
+ {
311
+ className: "dropdown-item",
312
+ onClick: () => this.setState({ locale: locale })
313
+ },
314
+ languages.find(l => l.code === locale)?.name || locale
315
+ )
316
+ )
317
+ )
318
+ )
319
+ )
320
+ : undefined,
261
321
  R(
262
322
  "a",
263
323
  { key: "print", className: "btn btn-link btn-sm", onClick: this.handlePrint },
264
324
  R("span", { className: "fas fa-print" }),
265
- R("span", { className: "hide-600px" }, T` Print`)
325
+ R("span", { className: "hide-600px" }, " ", T`Print`)
266
326
  ),
267
327
  R(
268
328
  "a",
269
329
  { key: "refresh", className: "btn btn-link btn-sm", onClick: this.handleRefreshData },
270
330
  R("span", { className: "fas fa-sync" }),
271
- R("span", { className: "hide-600px" }, T` Refresh`)
331
+ R("span", { className: "hide-600px" }, " ", T`Refresh`)
272
332
  ),
273
333
  this.state.hideQuickfilters && this.props.design.quickfilters && this.props.design.quickfilters.length > 0
274
334
  ? R(
275
335
  "a",
276
336
  { key: "showQuickfilters", className: "btn btn-link btn-sm", onClick: this.handleShowQuickfilters },
277
337
  R("span", { className: "fa fa-filter" }),
278
- R("span", { className: "hide-600px" }, T` Show Quickfilters`)
338
+ R("span", { className: "hide-600px" }, " ", T`Show Quickfilters`)
279
339
  )
280
340
  : undefined,
281
341
 
@@ -287,7 +347,7 @@ export default class DashboardComponent extends React.Component<DashboardCompone
287
347
  "a",
288
348
  { key: "settings", className: "btn btn-link btn-sm", onClick: this.handleSettings },
289
349
  R("span", { className: "fas fa-cog" }),
290
- R("span", { className: "hide-600px" }, T` Settings`)
350
+ R("span", { className: "hide-600px" }, " ", T`Settings`)
291
351
  )
292
352
  : undefined,
293
353
  this.state.editing ? this.renderStyle() : undefined,
@@ -317,7 +377,8 @@ export default class DashboardComponent extends React.Component<DashboardCompone
317
377
  filters: this.getCompiledFilters(),
318
378
  hideTopBorder: this.props.hideTitleBar,
319
379
  // 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
380
+ onHide: () => !this.props.hideTitleBar ? this.setState({ hideQuickfilters: true }) : undefined,
381
+ translate: this.translate
321
382
  })
322
383
  }
323
384
 
@@ -337,6 +398,8 @@ export default class DashboardComponent extends React.Component<DashboardCompone
337
398
  )
338
399
  )
339
400
 
401
+ const displayLocale = this.state.editing ? this.props.design.locale || "en" : this.state.locale
402
+
340
403
  const dashboardView = R(DashboardViewComponent, {
341
404
  schema: this.props.schema,
342
405
  dataSource: this.props.dataSource,
@@ -348,7 +411,8 @@ export default class DashboardComponent extends React.Component<DashboardCompone
348
411
  onRowClick: this.props.onRowClick,
349
412
  namedStrings: this.props.namedStrings,
350
413
  hideScopes: this.state.hideQuickfilters,
351
- refreshKey: this.state.refreshKey
414
+ refreshKey: this.state.refreshKey,
415
+ locale: displayLocale
352
416
  })
353
417
 
354
418
  const readonlyDashboardView = R(DashboardViewComponent, {
@@ -360,14 +424,15 @@ export default class DashboardComponent extends React.Component<DashboardCompone
360
424
  filters,
361
425
  onRowClick: this.props.onRowClick,
362
426
  namedStrings: this.props.namedStrings,
363
- hideScopes: this.state.hideQuickfilters
427
+ hideScopes: this.state.hideQuickfilters,
428
+ locale: displayLocale
364
429
  })
365
430
 
366
431
 
367
432
  // Pass active tables down to table select components so they can present a shorter list
368
433
  return <ActiveTablesContext.Provider
369
434
  value={DashboardUtils.getFilterableTables(this.props.design, this.props.schema)}>
370
- <LocaleContext.Provider value={this.props.design.locale ?? "en"}>
435
+ <LocaleContext.Provider value={displayLocale}>
371
436
  <div style={{
372
437
  display: "grid",
373
438
  gridTemplateRows: this.props.hideTitleBar ? "auto 1fr" : "auto auto 1fr",
@@ -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