@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
@@ -473,7 +473,7 @@ export default class LayeredChartCompiler {
473
473
  }
474
474
 
475
475
  // Compiles data for a polar chart (pie/donut) with no x axis
476
- compileDataPolar(design: LayeredChartDesign, data: C3ChartData, locale: any): C3Data {
476
+ compileDataPolar(design: LayeredChartDesign, data: C3ChartData, locale?: string): C3Data {
477
477
  let order: "asc" | "desc" | null
478
478
  const columns: any = []
479
479
  const types: { [key: string]: ChartTypes } = {}
@@ -670,7 +670,7 @@ export default class LayeredChartCompiler {
670
670
  const trendlineSeries = seriesY + ":trendline"
671
671
  columns.push([trendlineSeries].concat(calculateLinearRegression(yValues, xValues)))
672
672
  types[trendlineSeries] = line ? line() : "line"
673
- names[trendlineSeries] = names[seriesY] + T` Trendline`
673
+ names[trendlineSeries] = names[seriesY] + " " + T`Trendline`
674
674
  xs[trendlineSeries] = seriesX
675
675
  colors[trendlineSeries] = layer.color || defaultColors[layerIndex]
676
676
  legendHide.push(trendlineSeries) // Hide in legend
@@ -270,7 +270,8 @@ export default class LayeredChartDesignerComponent extends React.Component<Layer
270
270
  "button",
271
271
  { className: "btn btn-link", type: "button", onClick: this.handleAddLayer },
272
272
  R("span", { className: "fas fa-plus" }),
273
- T` Add Another Series`
273
+ " ",
274
+ T`Add Another Series`
274
275
  )
275
276
  : undefined
276
277
  )
@@ -481,7 +482,8 @@ class ThresholdsComponent extends React.Component<{
481
482
  "button",
482
483
  { type: "button", className: "btn btn-sm btn-link", onClick: this.handleAdd },
483
484
  R("i", { className: "fa fa-plus" }),
484
- T` Add Y Threshold`
485
+ " ",
486
+ T`Add Y Threshold`
485
487
  )
486
488
  )
487
489
  }
@@ -105,7 +105,8 @@ export default class LayeredChartViewComponent extends React.Component<
105
105
  schema: this.props.schema,
106
106
  dataSource: this.props.dataSource,
107
107
  exprValues: this.props.data.header || {},
108
- width: this.props.width
108
+ width: this.props.width,
109
+ locale: this.context
109
110
  })
110
111
  )
111
112
  }
@@ -125,7 +126,8 @@ export default class LayeredChartViewComponent extends React.Component<
125
126
  schema: this.props.schema,
126
127
  dataSource: this.props.dataSource,
127
128
  exprValues: this.props.data.footer || {},
128
- width: this.props.width
129
+ width: this.props.width,
130
+ locale: this.context
129
131
  })
130
132
  )
131
133
  }
@@ -171,7 +173,7 @@ interface C3ChartComponentProps {
171
173
  class C3ChartComponent extends React.Component<C3ChartComponentProps> {
172
174
  throttledCreateChart: ((props: C3ChartComponentProps) => any) & _.Cancelable
173
175
  chart: any
174
- chartDiv: any
176
+ chartDiv: HTMLDivElement | null
175
177
 
176
178
  constructor(props: C3ChartComponentProps) {
177
179
  super(props)
@@ -190,6 +192,10 @@ class C3ChartComponent extends React.Component<C3ChartComponentProps> {
190
192
  this.chart.destroy()
191
193
  }
192
194
 
195
+ if (!this.chartDiv) {
196
+ return
197
+ }
198
+
193
199
  const compiler = new LayeredChartCompiler({ schema: props.schema })
194
200
  const chartOptions: any = compiler.createChartOptions({
195
201
  design: this.props.design,
@@ -531,7 +537,7 @@ class C3ChartComponent extends React.Component<C3ChartComponentProps> {
531
537
 
532
538
  return R("div", {
533
539
  ref: c => {
534
- return (this.chartDiv = c)
540
+ this.chartDiv = c
535
541
  }
536
542
  })
537
543
  }
@@ -14,6 +14,7 @@ import PivotChartLayoutBuilder from "./PivotChartLayoutBuilder"
14
14
  import { WidgetDataSource } from "../../WidgetDataSource"
15
15
  import { PivotChartDesign, PivotChartSegment } from "./PivotChartDesign"
16
16
  import { JsonQLFilter } from "../../../JsonQLFilter"
17
+ import { translateHtmlItems } from "../../../richtext/ExprItemsTranslator"
17
18
 
18
19
  // Store true as a weakly cached value if a design is already clean
19
20
  const cleanDesignCache = new WeakCache()
@@ -422,4 +423,76 @@ export default class PivotChart extends Chart {
422
423
  getPlaceholderIcon() {
423
424
  return "fa-magic"
424
425
  }
426
+
427
+ translateDesign(design: PivotChartDesign, translate: (input: string) => string) {
428
+ return produce(design, draft => {
429
+ // Helper function to translate a segment and its children
430
+ const translateSegment = (segment: PivotChartSegment) => {
431
+ // Translate segment label
432
+ if (segment.label) {
433
+ segment.label = translate(segment.label)
434
+ }
435
+
436
+ // Translate value axis labels
437
+ if (segment.valueAxis?.categoryLabels) {
438
+ for (const key in segment.valueAxis.categoryLabels) {
439
+ segment.valueAxis.categoryLabels[key] = translate(segment.valueAxis.categoryLabels[key])
440
+ }
441
+ }
442
+
443
+ // Translate null label
444
+ if (segment.valueAxis?.nullLabel) {
445
+ segment.valueAxis.nullLabel = translate(segment.valueAxis.nullLabel)
446
+ }
447
+
448
+ // Recursively translate children
449
+ if (segment.children) {
450
+ segment.children.forEach(translateSegment)
451
+ }
452
+ }
453
+
454
+ // Translate all row segments
455
+ draft.rows.forEach(translateSegment)
456
+
457
+ // Translate all column segments
458
+ draft.columns.forEach(translateSegment)
459
+
460
+ // Translate all intersections
461
+ for (const intersection of Object.values(draft.intersections)) {
462
+ // Translate value axis labels
463
+ if (intersection.valueAxis?.categoryLabels) {
464
+ for (const key in intersection.valueAxis.categoryLabels) {
465
+ intersection.valueAxis.categoryLabels[key] = translate(intersection.valueAxis.categoryLabels[key])
466
+ }
467
+ }
468
+
469
+ // Translate null label
470
+ if (intersection.valueAxis?.nullLabel) {
471
+ intersection.valueAxis.nullLabel = translate(intersection.valueAxis.nullLabel)
472
+ }
473
+
474
+ // Translate segment value axis override labels
475
+ if (intersection.segmentValueAxisOverrides) {
476
+ for (const axis of Object.values(intersection.segmentValueAxisOverrides)) {
477
+ if (axis?.categoryLabels) {
478
+ for (const key in axis.categoryLabels) {
479
+ axis.categoryLabels[key] = translate(axis.categoryLabels[key])
480
+ }
481
+ }
482
+ if (axis?.nullLabel) {
483
+ axis.nullLabel = translate(axis.nullLabel)
484
+ }
485
+ }
486
+ }
487
+ }
488
+
489
+ // Translate header and footer using ExprItemsTranslator
490
+ if (draft.header?.items) {
491
+ draft.header.items = translateHtmlItems(draft.header.items, translate)
492
+ }
493
+ if (draft.footer?.items) {
494
+ draft.footer.items = translateHtmlItems(draft.footer.items, translate)
495
+ }
496
+ })
497
+ }
425
498
  }
@@ -393,7 +393,7 @@ class LayoutCellComponent extends React.Component<LayoutCellComponentProps> {
393
393
  R("a", { className: "link-plain", onClick: this.props.onEditSection }, T`Edit`),
394
394
  cell.summarize
395
395
  ? [
396
- R("span", { className: "text-muted" }, T` / `),
396
+ R("span", { className: "text-muted" }, ` / `),
397
397
  R("a", { className: "link-plain", onClick: this.props.onSummarizeSegment }, T`Summarize`)
398
398
  ]
399
399
  : undefined
@@ -95,13 +95,15 @@ export default class SegmentDesignerComponent extends React.Component<
95
95
  <ui.Radio key="single" value={this.state.mode} radioValue={"single"} onChange={this.handleMode}>
96
96
  {T`Single ${this.props.segmentType}`}
97
97
  <span className="text-muted">
98
- {T` - used for summary ${this.props.segmentType}s and empty ${this.props.segmentType}s`}
98
+ {` - `}
99
+ {T`used for summary ${this.props.segmentType}s and empty ${this.props.segmentType}s`}
99
100
  </span>
100
101
  </ui.Radio>,
101
102
 
102
103
  <ui.Radio key="multiple" value={this.state.mode} radioValue={"multiple"} onChange={this.handleMode}>
103
104
  {T`Multiple ${this.props.segmentType}s`}
104
- <span className="text-muted">{T` - disaggregate data by a field`}</span>
105
+ {" - "}
106
+ <span className="text-muted">{T`disaggregate data by a field`}</span>
105
107
  </ui.Radio>
106
108
  )
107
109
  }
@@ -170,7 +172,7 @@ export default class SegmentDesignerComponent extends React.Component<
170
172
  ui.FormGroup,
171
173
  {
172
174
  labelMuted: true,
173
- label: [R(ui.Icon, { id: "glyphicon-filter" }), T` Filters`],
175
+ label: [R(ui.Icon, { id: "glyphicon-filter" }), " ", T`Filters`],
174
176
  hint: T`Filters all data associated with this ${this.props.segmentType}`
175
177
  },
176
178
  R(FilterExprComponent, {
@@ -265,7 +267,7 @@ export default class SegmentDesignerComponent extends React.Component<
265
267
  ui.FormGroup,
266
268
  {
267
269
  labelMuted: true,
268
- label: [R(ui.Icon, { id: "fa-sort-amount-asc" }), T` Sort`],
270
+ label: [R(ui.Icon, { id: "fa-sort-amount-asc" }), " ", T`Sort`],
269
271
  hint: T`Sorts the display of this ${this.props.segmentType}`
270
272
  },
271
273
  R(ExprComponent, {
@@ -56,7 +56,8 @@ export default class OrderingsComponent extends React.Component<OrderingsCompone
56
56
  "button",
57
57
  { type: "button", className: "btn btn-sm btn-secondary", onClick: this.handleAdd, key: "add" },
58
58
  R("span", { className: "fas fa-plus" }),
59
- T` Add Ordering`
59
+ " ",
60
+ T`Add Ordering`
60
61
  )
61
62
  )
62
63
  }
@@ -431,4 +431,21 @@ export default class TableChart extends Chart {
431
431
  getPlaceholderIcon() {
432
432
  return "fa-table"
433
433
  }
434
+
435
+ translateDesign(design: TableChartDesign, translate: (input: string) => string) {
436
+ return produce(design, draft => {
437
+ // Translate title text
438
+ if (draft.titleText) {
439
+ draft.titleText = translate(draft.titleText)
440
+ }
441
+
442
+ // Translate column headers and axis labels
443
+ for (const column of draft.columns) {
444
+ // Translate header text
445
+ if (column.headerText) {
446
+ column.headerText = translate(column.headerText)
447
+ }
448
+ }
449
+ })
450
+ }
434
451
  }
@@ -3,18 +3,22 @@ import _ from "lodash"
3
3
  import RichTextComponent from "../../richtext/RichTextComponent"
4
4
  import ExprInsertModalComponent from "./ExprInsertModalComponent"
5
5
  import ExprUpdateModalComponent from "./ExprUpdateModalComponent"
6
- import ExprItemsHtmlConverter from "../../richtext/ExprItemsHtmlConverter"
6
+ import ExprItemsHtmlConverter, { HtmlItemExpr, HtmlItemOrExpr } from "../../richtext/ExprItemsHtmlConverter"
7
7
  import { TextWidgetDesign } from "./TextWidgetDesign"
8
8
  import { DataSource, Schema } from "@mwater/expressions"
9
9
  import { LocaleContext } from "@mwater/expressions-ui"
10
10
 
11
11
  export interface TextComponentProps {
12
12
  design: TextWidgetDesign
13
+
14
+ /** Called when design changes. If not set, will be in display mode, otherwise in edit mode */
13
15
  onDesignChange?: (design: TextWidgetDesign) => void
14
16
  schema: Schema
15
17
  dataSource: DataSource
18
+
16
19
  /** Expression values */
17
20
  exprValues: { [key: string]: any }
21
+
18
22
  width?: number
19
23
  height?: number
20
24
 
@@ -23,10 +27,15 @@ export interface TextComponentProps {
23
27
 
24
28
  /** Optional lookup of string name to value. Used for {{branding}} and other replacement strings in text widget */
25
29
  namedStrings?: { [key: string]: string }
30
+
31
+ /** Locale to use for display */
32
+ locale: string
26
33
  }
27
34
 
28
- // Text component which is provided with the data it needs, rather than loading it.
29
- // Used by TextWidgetComponent and also by other components that embed text fields
35
+ /**
36
+ * Text component which is provided with the data it needs, rather than loading it.
37
+ * Used by TextWidgetComponent and also by other components that embed text fields
38
+ */
30
39
  export default class TextComponent extends React.Component<TextComponentProps> {
31
40
  static contextType = LocaleContext
32
41
  exprInsertModal: ExprInsertModalComponent | null = null
@@ -38,7 +47,7 @@ export default class TextComponent extends React.Component<TextComponentProps> {
38
47
  this.props.schema,
39
48
  this.props.onDesignChange != null,
40
49
  this.props.exprValues,
41
- // Display summaries if in design more and singleRowTable is set
50
+ // Display summaries if in design mode and singleRowTable is set
42
51
  this.props.onDesignChange != null && this.props.singleRowTable != null,
43
52
  // Only replace named strings if not editing
44
53
  this.props.onDesignChange == null ? this.props.namedStrings : undefined,
@@ -46,12 +55,12 @@ export default class TextComponent extends React.Component<TextComponentProps> {
46
55
  )
47
56
  }
48
57
 
49
- handleItemsChange = (items: any) => {
58
+ handleItemsChange = (items: HtmlItemOrExpr[]) => {
50
59
  const design = { ...this.props.design, items }
51
60
  return this.props.onDesignChange!(design)
52
61
  }
53
62
 
54
- handleInsertExpr = (item: any) => {
63
+ handleInsertExpr = (item: HtmlItemExpr) => {
55
64
  const html = '<div data-embed="' + _.escape(JSON.stringify(item)) + '"></div>'
56
65
 
57
66
  return this.editor!.pasteHTML(html)
@@ -70,26 +79,27 @@ export default class TextComponent extends React.Component<TextComponentProps> {
70
79
  })
71
80
 
72
81
  const items = replaceItemInItems(this.props.design.items || [], item)
73
- return this.props.onDesignChange!({ ...this.props.design, items })
82
+ this.props.onDesignChange!({ ...this.props.design, items })
74
83
  }
75
84
 
76
- handleItemClick = (item: any) => {
77
- return this.exprUpdateModal!.open(item, (item: any) => {
85
+ handleItemClick = (item: HtmlItemExpr) => {
86
+ this.exprUpdateModal!.open(item, (item) => {
78
87
  // Replace in items
79
- return this.replaceItem(item)
88
+ this.replaceItem(item)
80
89
  })
81
90
  }
82
91
 
83
92
  handleAddExpr = (ev: React.MouseEvent<HTMLDivElement>) => {
84
93
  ev.preventDefault()
85
- return this.exprInsertModal!.open()
94
+ this.exprInsertModal!.open()
86
95
  }
87
96
 
88
97
  renderExtraPaletteButtons() {
89
98
  return (
90
99
  <div key="expr" className="mwater-visualization-text-palette-item" onMouseDown={this.handleAddExpr}>
91
100
  <i className="fa fa-plus" />
92
- {T` Expression`}
101
+ {" "}
102
+ {T`Expression`}
93
103
  </div>
94
104
  )
95
105
  }
@@ -12,6 +12,7 @@ import { JsonQLSelectQuery } from "@mwater/jsonql"
12
12
  import { HtmlItem } from "../../richtext/ItemsHtmlConverter"
13
13
  import { HtmlItemExpr } from "../../richtext/ExprItemsHtmlConverter"
14
14
  import { TextWidgetDesign } from "./TextWidgetDesign"
15
+ import { getHtmlItemsStrings } from "../../richtext/ExprItemsTranslator"
15
16
 
16
17
  export default class TextWidget extends Widget {
17
18
  // Creates a React element that is a view of the widget
@@ -44,7 +45,9 @@ export default class TextWidget extends Widget {
44
45
  singleRowTable: options.singleRowTable,
45
46
  namedStrings: options.namedStrings,
46
47
  ref: options.widgetRef,
47
- refreshKey: options.refreshKey
48
+ refreshKey: options.refreshKey,
49
+ locale: options.locale,
50
+ translate: options.translate
48
51
  })
49
52
  }
50
53
 
@@ -191,7 +194,7 @@ export default class TextWidget extends Widget {
191
194
  }
192
195
 
193
196
  // Get expression items recursively
194
- getExprItems(items: HtmlItem[]): HtmlItemExpr[] {
197
+ getExprItems(items?: HtmlItem[]): HtmlItemExpr[] {
195
198
  let exprItems: any[] = []
196
199
  for (let item of items || []) {
197
200
  if ((item as any).type === "expr") {
@@ -267,4 +270,8 @@ export default class TextWidget extends Widget {
267
270
 
268
271
  return entries
269
272
  }
273
+
274
+ getTranslatableStrings(design: TextWidgetDesign, schema: Schema): string[] {
275
+ return getHtmlItemsStrings(design.items || [])
276
+ }
270
277
  }
@@ -13,6 +13,7 @@ import ActionCancelModalComponent from "@mwater/react-library/lib/ActionCancelMo
13
13
  import { FormGroup } from "@mwater/react-library/lib/bootstrap"
14
14
  import ColorComponent from "../../ColorComponent"
15
15
  import { Select } from "@mwater/react-library/lib/bootstrap"
16
+ import { translateHtmlItems } from "../../richtext/ExprItemsTranslator"
16
17
 
17
18
  export interface TextWidgetComponentProps {
18
19
  design: TextWidgetDesign
@@ -28,8 +29,15 @@ export interface TextWidgetComponentProps {
28
29
  /** Table that is filtered to have one row */
29
30
  singleRowTable?: string
30
31
  namedStrings?: any
32
+
31
33
  /** A key that changes when the widget should be refreshed */
32
34
  refreshKey?: any
35
+
36
+ /** Locale to use for display */
37
+ locale: string
38
+
39
+ /** Translate function to use for display. Returns same string when editing. */
40
+ translate: (input: string) => string
33
41
  }
34
42
 
35
43
  // Widget which displays styled text with embedded expressions
@@ -200,9 +208,15 @@ export default class TextWidgetComponent extends AsyncLoadComponent<TextWidgetCo
200
208
 
201
209
  const padding = this.props.design.padding ?? 0
202
210
 
211
+ // Translate items if needed
212
+ const translatedDesign = this.props.onDesignChange ? this.props.design : {
213
+ ...this.props.design,
214
+ items: translateHtmlItems(this.props.design.items || [], this.props.translate)
215
+ }
216
+
203
217
  return (
204
218
  <TextComponent
205
- design={this.props.design}
219
+ design={translatedDesign}
206
220
  onDesignChange={this.props.onDesignChange}
207
221
  schema={this.props.schema}
208
222
  dataSource={this.props.dataSource}
@@ -211,6 +225,7 @@ export default class TextWidgetComponent extends AsyncLoadComponent<TextWidgetCo
211
225
  height={this.props.height ? this.props.height - padding * 2 : undefined}
212
226
  singleRowTable={this.props.singleRowTable}
213
227
  namedStrings={this.props.namedStrings}
228
+ locale={this.props.locale}
214
229
  />
215
230
  )
216
231
  }
@@ -1,11 +1,8 @@
1
- import { HtmlItemExpr } from "../../richtext/ExprItemsHtmlConverter"
2
- import { HtmlItem } from "../../richtext/ItemsHtmlConverter"
3
-
4
- export type TextWidgetItem = HtmlItem | HtmlItemExpr
1
+ import { HtmlItemOrExpr } from "../../richtext/ExprItemsHtmlConverter"
5
2
 
6
3
  export interface TextWidgetDesign {
7
4
  /** Text widget stores its content as array of items. See ItemsHtmlConverter TODO */
8
- items: TextWidgetItem[]
5
+ items?: HtmlItemOrExpr[]
9
6
 
10
7
  /** "title" for title block. default is "default" */
11
8
  style?: "title" | "default" | "header" | "footer"
@@ -29,5 +26,5 @@ export interface TextWidgetDesign {
29
26
 
30
27
  /** Returns true if the text widget design is empty. */
31
28
  export function isEmptyTextWidgetDesign(design: TextWidgetDesign | undefined): boolean {
32
- return design == null || design.items.length === 0
33
- }
29
+ return design == null || (design.items != null && design.items.length === 0)
30
+ }
@@ -0,0 +1,54 @@
1
+ import { assert } from "chai"
2
+ import IdSelection from "../src/IdSelection"
3
+
4
+ describe("IdSelection", function () {
5
+ beforeEach(function(this: any) {
6
+ this.sel = new IdSelection()
7
+ })
8
+
9
+ it("adds id", function(this: any) {
10
+ const sel = this.sel.add("1")
11
+ assert.isTrue(sel.isSelected("1"))
12
+ assert.isFalse(sel.isSelected("2"))
13
+ })
14
+
15
+ it("removes id", function(this: any) {
16
+ let sel = this.sel.add("1")
17
+ sel = sel.remove("1")
18
+ assert.isFalse(sel.isSelected("1"))
19
+ assert.isFalse(sel.isSelected("2"))
20
+ })
21
+
22
+ it("toggles id", function(this: any) {
23
+ let sel = this.sel.toggle("1")
24
+ assert.isTrue(sel.isSelected("1"))
25
+ sel = sel.toggle("1")
26
+ assert.isFalse(sel.isSelected("1"))
27
+ })
28
+
29
+ it("inverts", function(this: any) {
30
+ let sel = this.sel.add("1")
31
+ sel = sel.invert()
32
+ assert.isTrue(sel.isSelected("2"))
33
+ assert.isFalse(sel.isSelected("1"))
34
+ })
35
+
36
+ it("adds in inverts", function(this: any) {
37
+ let sel = this.sel.add("1")
38
+ sel = sel.invert()
39
+ sel = sel.add("1")
40
+ assert.isTrue(sel.isSelected("1"))
41
+ })
42
+
43
+ it("none", function(this: any) {
44
+ let sel = this.sel.add("1")
45
+ sel = sel.none()
46
+ assert.isFalse(sel.isSelected("1"))
47
+ })
48
+
49
+ return it("all", function(this: any) {
50
+ const sel = this.sel.all("1")
51
+ assert.isTrue(sel.isSelected("1"))
52
+ assert.isTrue(sel.isSelected("2"))
53
+ })
54
+ })
@@ -1,5 +1,3 @@
1
- // TODO: This file was created by bulk-decaffeinate.
2
- // Sanity-check the conversion and remove this comment.
3
1
  import _ from "lodash"
4
2
  import { assert } from "chai"
5
3
  import * as fixtures from "./fixtures"
@@ -0,0 +1,144 @@
1
+ import { assert } from "chai"
2
+ import { translateHtmlItems, getHtmlItemsStrings } from "../../src/richtext/ExprItemsTranslator"
3
+ import { HtmlItemElement } from "../../src/richtext/ItemsHtmlConverter"
4
+ import { HtmlItemExpr, HtmlItemOrExpr } from "../../src/richtext/ExprItemsHtmlConverter"
5
+
6
+ describe("ExprItemsTranslator", function () {
7
+ describe("translateHtmlItems", function () {
8
+ it("should translate simple strings", function () {
9
+ const items: HtmlItemOrExpr[] = ["Hello ", "World"]
10
+ const translatedItems = translateHtmlItems(items, (input) => input.toUpperCase())
11
+ assert.deepEqual(translatedItems, ["HELLO WORLD"])
12
+ })
13
+
14
+ it("should translate nested items", function () {
15
+ const items: HtmlItemOrExpr[] = [
16
+ {
17
+ type: "element",
18
+ tag: "p",
19
+ items: ["Hello", { type: "element", tag: "b", items: ["World"] } as HtmlItemElement]
20
+ } as HtmlItemElement
21
+ ]
22
+ const translatedItems = translateHtmlItems(items, (input) => input.toUpperCase())
23
+ assert.deepEqual(translatedItems, [
24
+ {
25
+ type: "element",
26
+ tag: "p",
27
+ items: ["HELLO", { type: "element", tag: "b", items: ["WORLD"] } as HtmlItemElement]
28
+ } as HtmlItemElement
29
+ ])
30
+ })
31
+
32
+ it("should translate expression items", function () {
33
+ const items: HtmlItemOrExpr[] = [
34
+ {
35
+ type: "expr",
36
+ id: "1",
37
+ expr: { type: "literal", valueType: "text", value: "Hello" },
38
+ labelText: "Greeting"
39
+ } as HtmlItemExpr
40
+ ]
41
+ const translatedItems = translateHtmlItems(items, (input) => input.toUpperCase())
42
+ assert.deepEqual(translatedItems, [
43
+ {
44
+ type: "expr",
45
+ id: "1",
46
+ expr: { type: "literal", valueType: "text", value: "Hello" },
47
+ labelText: "GREETING"
48
+ } as HtmlItemExpr
49
+ ])
50
+ })
51
+
52
+ it("should translate expression items within a string", function () {
53
+ const items: HtmlItemOrExpr[] = [
54
+ "Hello, ",
55
+ {
56
+ type: "expr",
57
+ id: "1",
58
+ expr: { type: "literal", valueType: "text", value: "Hello" },
59
+ labelText: "Greeting"
60
+ } as HtmlItemExpr,
61
+ "!"
62
+ ]
63
+ const translatedItems = translateHtmlItems(items, (input) => input.toUpperCase())
64
+ assert.deepEqual(translatedItems, [
65
+ "HELLO, ",
66
+ {
67
+ type: "expr",
68
+ id: "1",
69
+ expr: { type: "literal", valueType: "text", value: "Hello" },
70
+ labelText: "GREETING"
71
+ } as HtmlItemExpr,
72
+ "!"
73
+ ])
74
+ })
75
+
76
+ it("should translate links while preserving the href", function () {
77
+ const items: HtmlItemOrExpr[] = [
78
+ "Hello, ",
79
+ {
80
+ type: "element",
81
+ tag: "a",
82
+ items: ["there"],
83
+ href: "https://example.com"
84
+ } as HtmlItemElement,
85
+ "!"
86
+ ]
87
+ const translatedItems = translateHtmlItems(items, (input) => input.toUpperCase())
88
+ assert.deepEqual(translatedItems, [
89
+ "HELLO, ",
90
+ {
91
+ type: "element",
92
+ tag: "a",
93
+ items: ["THERE"],
94
+ href: "HTTPS://EXAMPLE.COM"
95
+ } as HtmlItemElement,
96
+ "!"
97
+ ])
98
+ })
99
+
100
+ it("should collect all unique strings", function () {
101
+ const items: HtmlItemOrExpr[] = [
102
+ "Start ",
103
+ {
104
+ type: "element",
105
+ tag: "p",
106
+ items: ["Hello ", { type: "element", tag: "b", items: ["World"] }]
107
+ } as HtmlItemElement,
108
+ " This is a ",
109
+ {
110
+ type: "expr",
111
+ id: "1",
112
+ expr: { type: "literal", valueType: "text", value: "Hello" },
113
+ labelText: "Greeting"
114
+ } as HtmlItemExpr,
115
+ "!"
116
+ ]
117
+ const strings = getHtmlItemsStrings(items)
118
+ assert.deepEqual(strings, ["Start", "Hello <b>World</b>", "Greeting", "This is a {0}!"])
119
+ })
120
+ })
121
+
122
+ describe("getHtmlItemsStrings", function () {
123
+ it("should collect all unique strings", function () {
124
+ const items: HtmlItemOrExpr[] = [
125
+ "Start ",
126
+ {
127
+ type: "element",
128
+ tag: "p",
129
+ items: ["Hello ", { type: "element", tag: "b", items: ["World"] }]
130
+ } as HtmlItemElement,
131
+ " This is a ",
132
+ {
133
+ type: "expr",
134
+ id: "1",
135
+ expr: { type: "literal", valueType: "text", value: "Hello" },
136
+ labelText: "Greeting"
137
+ } as HtmlItemExpr,
138
+ "!"
139
+ ]
140
+ const strings = getHtmlItemsStrings(items)
141
+ assert.deepEqual(strings, ["Start", "Hello <b>World</b>", "Greeting", "This is a {0}!"])
142
+ })
143
+ })
144
+ })