@mwater/visualization 5.4.0 → 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 (271) 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 +3 -3
  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/PivotChartDesignerComponent.d.ts +1 -0
  148. package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +1 -1
  149. package/lib/widgets/charts/pivot/SegmentDesignerComponent.d.ts +6 -0
  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 +79 -14
  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/layouts/blocks/HorizontalBlockComponent.ts +2 -2
  192. package/src/mWaterLoader.ts +1 -1
  193. package/src/maps/BufferLayer.ts +83 -60
  194. package/src/maps/BufferLayerDesign.ts +20 -14
  195. package/src/maps/BufferLayerDesignerComponent.tsx +309 -0
  196. package/src/maps/ChoroplethLayer.ts +40 -19
  197. package/src/maps/ChoroplethLayerDesign.ts +4 -2
  198. package/src/maps/ChoroplethLayerDesigner.tsx +4 -2
  199. package/src/maps/ClusterLayer.ts +4 -10
  200. package/src/maps/DetailLevelSelectComponent.ts +1 -1
  201. package/src/maps/DirectMapDataSource.ts +2 -1
  202. package/src/maps/EditPopupComponent.ts +7 -3
  203. package/src/maps/GridLayer.ts +4 -10
  204. package/src/maps/GridLayerDesigner.tsx +5 -3
  205. package/src/maps/HoverContent.tsx +40 -16
  206. package/src/maps/Layer.ts +28 -10
  207. package/src/maps/LayerFactory.ts +0 -8
  208. package/src/maps/LayerLegendComponent.ts +2 -4
  209. package/src/maps/LayerSwitcherComponent.tsx +6 -2
  210. package/src/maps/LeafletMapComponent.tsx +3 -1
  211. package/src/maps/LegendComponent.tsx +10 -1
  212. package/src/maps/MWaterServerLayer.ts +3 -3
  213. package/src/maps/MapComponent.ts +3 -3
  214. package/src/maps/MapDesign.ts +3 -0
  215. package/src/maps/MapDesignerComponent.tsx +165 -162
  216. package/src/maps/MapLayerViewDesignerComponent.ts +2 -2
  217. package/src/maps/MapUtils.ts +24 -0
  218. package/src/maps/MapViewComponent.tsx +11 -3
  219. package/src/maps/MarkersLayer.ts +44 -18
  220. package/src/maps/MarkersLayerDesign.ts +19 -16
  221. package/src/maps/PopupFilterJoinsUtils.ts +6 -2
  222. package/src/maps/RasterMapViewComponent.ts +9 -45
  223. package/src/maps/ServerMapDataSource.ts +2 -2
  224. package/src/maps/SwitchableTileUrlLayer.tsx +4 -10
  225. package/src/maps/TileUrlLayer.tsx +4 -10
  226. package/src/maps/VectorMapViewComponent.tsx +28 -55
  227. package/src/maps/maps.ts +3 -0
  228. package/src/quickfilter/QuickfiltersComponent.ts +13 -7
  229. package/src/quickfilter/QuickfiltersDesignComponent.tsx +56 -74
  230. package/src/richtext/ExprItemsHtmlConverter.ts +9 -5
  231. package/src/richtext/ExprItemsTranslator.ts +176 -0
  232. package/src/richtext/ItemsHtmlConverter.ts +33 -18
  233. package/src/wellknown.ts +33 -30
  234. package/src/widgets/ImageWidget.ts +10 -1
  235. package/src/widgets/ImageWidgetComponent.ts +3 -2
  236. package/src/widgets/{MapWidget.ts → MapWidget.tsx} +90 -101
  237. package/src/widgets/MarkdownWidget.ts +3 -0
  238. package/src/widgets/TOCWidget.tsx +281 -0
  239. package/src/widgets/Widget.ts +25 -5
  240. package/src/widgets/WidgetScopesViewComponent.ts +2 -1
  241. package/src/widgets/charts/Chart.ts +31 -12
  242. package/src/widgets/charts/ChartViewComponent.ts +13 -3
  243. package/src/widgets/charts/ChartWidget.ts +11 -1
  244. package/src/widgets/charts/ChartWidgetComponent.tsx +9 -1
  245. package/src/widgets/charts/calendar/CalendarChart.ts +29 -0
  246. package/src/widgets/charts/calendar/CalendarChartViewComponent.tsx +3 -1
  247. package/src/widgets/charts/imagemosaic/ImageMosaicChart.ts +9 -0
  248. package/src/widgets/charts/layered/LayeredChart.ts +71 -3
  249. package/src/widgets/charts/layered/LayeredChartCompiler.ts +4 -4
  250. package/src/widgets/charts/layered/LayeredChartDesignerComponent.tsx +4 -2
  251. package/src/widgets/charts/layered/LayeredChartViewComponent.ts +10 -4
  252. package/src/widgets/charts/pivot/PivotChart.ts +73 -0
  253. package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +1 -1
  254. package/src/widgets/charts/pivot/SegmentDesignerComponent.tsx +6 -4
  255. package/src/widgets/charts/table/OrderingsComponent.tsx +2 -1
  256. package/src/widgets/charts/table/TableChart.ts +17 -0
  257. package/src/widgets/text/TextComponent.tsx +22 -12
  258. package/src/widgets/text/TextWidget.ts +9 -2
  259. package/src/widgets/text/TextWidgetComponent.tsx +16 -1
  260. package/src/widgets/text/TextWidgetDesign.ts +4 -7
  261. package/test/IdSelectionTests.ts +54 -0
  262. package/test/LayeredChartCompilerTests.ts +0 -2
  263. package/test/richtext/ExprItemsTranslatorTests.ts +144 -0
  264. package/test/wellknownTests.ts +144 -0
  265. package/src/datagrids/DatagridComponent.ts +0 -478
  266. package/src/datagrids/DatagridViewComponent.ts +0 -464
  267. package/src/datagrids/EditExprCellComponent.tsx +0 -305
  268. package/src/datagrids/README.md +0 -3
  269. package/src/maps/BufferLayerDesignerComponent.ts +0 -311
  270. package/src/widgets/TOCWidget.ts +0 -326
  271. package/test/LegoLayoutEngineTests.ts +0 -69
@@ -8,34 +8,36 @@ import LoadingComponent from "@mwater/react-library/lib/LoadingComponent"
8
8
  import mWaterLoader from "./mWaterLoader"
9
9
  import MWaterContextComponent, { AddLayerElementFactory } from "./MWaterContextComponent"
10
10
 
11
+ export interface MWaterLoaderComponentProps {
12
+ apiUrl: string
13
+ client?: string
14
+ share?: string
15
+ /** user id of logged in user */
16
+ user?: string
17
+ /** Load schema as a specific user (for shared dashboards, etc) */
18
+ asUser?: string
19
+ /** Extra tables to load in schema. Forms are not loaded by default as they are too many */
20
+ extraTables?: string[]
21
+ /** Called when extra tables are changed and schema will be reloaded */
22
+ onExtraTablesChange?: (extraTables: string[]) => void
23
+ /** Locales of the schema to load. Default is all. */
24
+ locales?: string[]
25
+ /** Override default add layer component. See AddLayerComponent for details */
26
+ addLayerElementFactory?: AddLayerElementFactory
27
+ children: (error: any, config?: { schema: Schema; dataSource: DataSource }) => ReactElement<any>
28
+ /** Custom error formatter that returns React node or string, gets passed the error response from server */
29
+ errorFormatter?: (data: any, defaultError: string) => string
30
+ /** Origin of usage. e.g. "dashboards:43445364..." */
31
+ origin?: string
32
+ }
33
+
11
34
  /**
12
35
  * Loads an mWater schema from the server and creates child with schema and dataSource
13
36
  * Also creates context to allow selecting of a table in an mWater-friendly way
14
37
  * and several other context items
15
38
  */
16
39
  export default class MWaterLoaderComponent extends AsyncLoadComponent<
17
- {
18
- apiUrl: string
19
- client?: string
20
- share?: string
21
- /** user id of logged in user */
22
- user?: string
23
- /** Load schema as a specific user (for shared dashboards, etc) */
24
- asUser?: string
25
- /** Extra tables to load in schema. Forms are not loaded by default as they are too many */
26
- extraTables?: string[]
27
- /** Called when extra tables are changed and schema will be reloaded */
28
- onExtraTablesChange?: (extraTables: string[]) => void
29
- /** Locales of the schema to load. Default is all. */
30
- locales?: string[]
31
- /** Override default add layer component. See AddLayerComponent for details */
32
- addLayerElementFactory?: AddLayerElementFactory
33
- children: (error: any, config?: { schema: Schema; dataSource: DataSource }) => ReactElement<any>
34
- /** Custom error formatter that returns React node or string, gets passed the error response from server */
35
- errorFormatter?: (data: any, defaultError: string) => string
36
- /** Origin of usage. e.g. "dashboards:43445364..." */
37
- origin?: string
38
- },
40
+ MWaterLoaderComponentProps,
39
41
  {
40
42
  error: any
41
43
  schema: Schema | null
@@ -45,7 +47,7 @@ export default class MWaterLoaderComponent extends AsyncLoadComponent<
45
47
  > {
46
48
  mounted: boolean
47
49
 
48
- constructor(props: any) {
50
+ constructor(props: MWaterLoaderComponentProps) {
49
51
  super(props)
50
52
  this.state = {
51
53
  error: null,
@@ -58,7 +60,7 @@ export default class MWaterLoaderComponent extends AsyncLoadComponent<
58
60
  }
59
61
 
60
62
  // Override to determine if a load is needed. Not called on mounting
61
- isLoadNeeded(newProps: any, oldProps: any) {
63
+ isLoadNeeded(newProps: MWaterLoaderComponentProps, oldProps: MWaterLoaderComponentProps) {
62
64
  return !_.isEqual(
63
65
  _.pick(newProps, "apiUrl", "client", "user", "share", "asUser", "extraTables", "locales"),
64
66
  _.pick(oldProps, "apiUrl", "client", "user", "share", "asUser", "extraTables", "locales")
@@ -66,9 +68,9 @@ export default class MWaterLoaderComponent extends AsyncLoadComponent<
66
68
  }
67
69
 
68
70
  // Call callback with state changes
69
- load(props: any, prevProps: any, callback: any) {
71
+ load(props: MWaterLoaderComponentProps, prevProps: MWaterLoaderComponentProps, callback: any) {
70
72
  // Load schema and data source
71
- return mWaterLoader(
73
+ mWaterLoader(
72
74
  {
73
75
  apiUrl: props.apiUrl,
74
76
  client: props.client,
@@ -173,9 +173,12 @@ export default class MWaterResponsesFilterComponent extends React.Component<MWat
173
173
  return R(
174
174
  ui.Radio,
175
175
  { key: column.id, value: siteColumnId, radioValue: column.id, onChange: this.handleSiteChange },
176
- T`Show only the latest response for each `,
176
+ T`Show only the latest response for each`,
177
+ " ",
177
178
  R("i", null, `${ExprUtils.localizeString(this.props.schema.getTable(column.join.toTable)?.name)}`),
178
- T` in the question `,
179
+ " ",
180
+ T`in the question`,
181
+ " ",
179
182
  R("i", null, `'${ExprUtils.localizeString(column.name)}'`)
180
183
  )
181
184
  })
@@ -6,7 +6,7 @@ import { ExprUtils, Schema } from "@mwater/expressions"
6
6
  import MWaterResponsesFilterComponent from "./MWaterResponsesFilterComponent"
7
7
  import ModalPopupComponent from "@mwater/react-library/lib/ModalPopupComponent"
8
8
  import MWaterCompleteTableSelectComponent from "./MWaterCompleteTableSelectComponent"
9
- import { ActiveTablesContext, LocaleContext } from "@mwater/expressions-ui"
9
+ import { ActiveTablesContext } from "@mwater/expressions-ui"
10
10
 
11
11
  export interface MWaterTableSelectComponentProps {
12
12
  /** Url to hit api */
@@ -35,8 +35,6 @@ export default class MWaterTableSelectComponent extends React.Component<
35
35
  MWaterTableSelectComponentProps,
36
36
  MWaterTableSelectComponentState
37
37
  > {
38
- static contextType = LocaleContext
39
-
40
38
  toggleEdit: any
41
39
 
42
40
  constructor(props: MWaterTableSelectComponentProps) {
@@ -136,7 +134,7 @@ export default class MWaterTableSelectComponent extends React.Component<
136
134
  },
137
135
  forceOpen: !this.props.table, // Must have table
138
136
  label: this.props.table
139
- ? ExprUtils.localizeString(this.props.schema.getTable(this.props.table)?.name, this.context)
137
+ ? ExprUtils.localizeString(this.props.schema.getTable(this.props.table)?.name, T.locale)
140
138
  : "",
141
139
  editor,
142
140
  onRemove: () => {
@@ -184,8 +182,6 @@ class EditModeTableSelectComponent extends React.Component<
184
182
  EditModeTableSelectComponentProps,
185
183
  EditModeTableSelectComponentState
186
184
  > {
187
- static contextType = LocaleContext
188
-
189
185
  constructor(props: any) {
190
186
  super(props)
191
187
 
@@ -235,7 +231,7 @@ class EditModeTableSelectComponent extends React.Component<
235
231
 
236
232
  // Sort by name
237
233
  tables = _.sortBy(tables, (tableId) =>
238
- ExprUtils.localizeString(this.props.schema.getTable(tableId)!.name, this.context)
234
+ ExprUtils.localizeString(this.props.schema.getTable(tableId)!.name, T.locale)
239
235
  )
240
236
 
241
237
  return tables
@@ -277,8 +273,8 @@ class EditModeTableSelectComponent extends React.Component<
277
273
  <OptionListComponent items={this.getTableShortlist(activeTables).map((tableId) => {
278
274
  const table = this.props.schema.getTable(tableId)!
279
275
  return {
280
- name: ExprUtils.localizeString(table.name, this.context),
281
- desc: ExprUtils.localizeString(table.desc, this.context),
276
+ name: ExprUtils.localizeString(table.name, T.locale),
277
+ desc: ExprUtils.localizeString(table.desc, T.locale),
282
278
  onClick: () => this.props.onChange(table.id)
283
279
  }
284
280
  })} />
@@ -0,0 +1,141 @@
1
+ import { LocalizedString, Locale } from "ez-localize/lib/utils"
2
+
3
+ /** Translates an array of strings from a source language to a target language using the mWater translation API.
4
+ * @param strings Array of strings to translate
5
+ * @param sourceLanguage Source language code (e.g. "en")
6
+ * @param targetLanguage Target language code to translate to
7
+ * @returns Promise that resolves to array of translated strings in same order as input
8
+ * @throws Error if translation fails
9
+ */
10
+ export async function translateStrings(
11
+ strings: string[],
12
+ sourceLanguage: string,
13
+ targetLanguage: string
14
+ ): Promise<string[]> {
15
+ // Call translation API
16
+ const response = await fetch(
17
+ `https://api.mwater.co/v3/translate?source_language=${sourceLanguage}&target_language=${targetLanguage}`,
18
+ {
19
+ method: "POST",
20
+ headers: {
21
+ "Content-Type": "application/json"
22
+ },
23
+ body: JSON.stringify({
24
+ phrases: strings
25
+ })
26
+ }
27
+ )
28
+
29
+ if (!response.ok) {
30
+ throw new Error("Translation failed")
31
+ }
32
+
33
+ const result = await response.json()
34
+ return result.phrases
35
+ }
36
+
37
+ /** Ensures that all LocalizedString objects have translations for all specified locales.
38
+ * Only translates missing translations, preserving existing ones and base strings.
39
+ * Each string's _base property is used as the source language for translations.
40
+ * @param strings Array of LocalizedString objects to ensure are fully translated
41
+ * @param locales Array of language codes specifying which languages to ensure exist
42
+ * @param baseLanguage Language code of the _base strings (e.g. "en", "fr", etc)
43
+ * @returns Promise that resolves to array of fully translated LocalizedString objects
44
+ */
45
+ export async function translateLocalizedStrings(
46
+ strings: LocalizedString[],
47
+ locales: string[],
48
+ baseLanguage: string
49
+ ): Promise<LocalizedString[]> {
50
+ // Create copy of strings to modify
51
+ const translatedStrings = strings.map(str => ({ ...str }))
52
+
53
+ // For each locale
54
+ for (const locale of locales) {
55
+ // Skip if it's the base language
56
+ if (locale === baseLanguage) {
57
+ continue
58
+ }
59
+
60
+ // Group strings by their current source language
61
+ // Start with base language strings
62
+ const stringsBySourceLang = new Map<string, { str: LocalizedString; index: number }[]>()
63
+
64
+ translatedStrings.forEach((str, index) => {
65
+ // Skip if translation already exists
66
+ if (str[locale]) {
67
+ return
68
+ }
69
+
70
+ // Add to list to translate from base language
71
+ if (!stringsBySourceLang.has(baseLanguage)) {
72
+ stringsBySourceLang.set(baseLanguage, [])
73
+ }
74
+ stringsBySourceLang.get(baseLanguage)!.push({ str, index })
75
+ })
76
+
77
+ // Translate each group
78
+ for (const [sourceLang, stringsToTranslate] of stringsBySourceLang.entries()) {
79
+ try {
80
+ // Get source strings
81
+ const sourceStrings = stringsToTranslate.map(item => item.str[item.str._base])
82
+
83
+ // Translate all strings at once
84
+ const translations = await translateStrings(sourceStrings, sourceLang, locale)
85
+
86
+ // Add translations back to strings
87
+ translations.forEach((translation, i) => {
88
+ translatedStrings[stringsToTranslate[i].index][locale] = translation
89
+ })
90
+ } catch (error) {
91
+ console.error(`Failed to translate from ${sourceLang} to ${locale}:`, error)
92
+ throw error
93
+ }
94
+ }
95
+ }
96
+
97
+ return translatedStrings
98
+ }
99
+
100
+ /** Returns true if the given language code can be automatically translated. */
101
+ export function canAutoTranslate(languageCode: string) {
102
+ const languageCodes = [
103
+ "en", // English
104
+ "fr", // French
105
+ "es", // Spanish
106
+ "pt", // Portuguese
107
+ "sw", // Swahili
108
+ "id", // Indonesian
109
+ "hi", // Hindi
110
+ "ne", // Nepali
111
+ "rw", // Kinyarwanda
112
+ "sd", // Sindhi
113
+ "tet", // Tetum
114
+ "ur", // Urdu
115
+ "ja", // Japanese
116
+ "de", // German
117
+ "it", // Italian
118
+ "su", // Sundanese
119
+ "ar", // Arabic
120
+ "vi", // Vietnamese
121
+ "mg", // Malagasy
122
+ "tl", // Tagalog/Filipino
123
+ "ht", // Haitian Creole
124
+ "fi", // Finnish
125
+ "bn", // Bangla
126
+ "my", // Burmese
127
+ "km", // Khmer
128
+ "so", // Somali
129
+ "jv", // Javanese
130
+ "ko", // Korean
131
+ "zh", // Chinese
132
+ "ru", // Russian
133
+ "tr", // Turkish
134
+ "nl", // Dutch
135
+ "pl", // Polish
136
+ "hu", // Hungarian
137
+ "cs", // Czech
138
+ "sk" // Slovak
139
+ ]
140
+ return languageCodes.includes(languageCode)
141
+ }
@@ -532,7 +532,7 @@ export default class AxisBuilder {
532
532
 
533
533
  if (range.maxValue != null) {
534
534
  if (label) {
535
- label += T` and `
535
+ label += ` ${T`and`} `
536
536
  }
537
537
  if (range.maxOpen) {
538
538
  label += `< ${range.maxValue}`
@@ -1024,7 +1024,7 @@ export default class AxisBuilder {
1024
1024
  if (category) {
1025
1025
  return this.formatCategory(axis, category)
1026
1026
  } else {
1027
- return T`???`
1027
+ return `???`
1028
1028
  }
1029
1029
  }).join(", ")
1030
1030
  } else {
@@ -1032,7 +1032,7 @@ export default class AxisBuilder {
1032
1032
  if (category) {
1033
1033
  return this.formatCategory(axis, category)
1034
1034
  } else {
1035
- return T`???`
1035
+ return `???`
1036
1036
  }
1037
1037
  }
1038
1038
  }
@@ -86,6 +86,11 @@ export default class AxisColorEditorComponent extends React.Component<
86
86
  axisBuilder.isCategorical(this.props.axis)
87
87
  )
88
88
  colorMap = (this.props.axis.colorMap || []).concat(missingColorMap)
89
+
90
+ // If there are categories present, remove any color map values that are not in the categories
91
+ if (this.props.categories.length > 0) {
92
+ colorMap = _.filter(colorMap, (cm) => this.props.categories!.find((c) => c.value === cm.value))
93
+ }
89
94
  } else {
90
95
  // Keep existing
91
96
  const existing = _.indexBy(this.props.axis.colorMap || [], "value")
@@ -1,6 +1,5 @@
1
1
  import _ from "lodash"
2
2
  import React from "react"
3
- const R = React.createElement
4
3
  import uuid from "uuid"
5
4
  import AsyncLoadComponent from "@mwater/react-library/lib/AsyncLoadComponent"
6
5
  import { ExprComponent, LocaleContext } from "@mwater/expressions-ui"
@@ -16,7 +15,7 @@ import { injectTableAlias } from "@mwater/expressions"
16
15
  import { getFormatOptions } from "../valueFormatter"
17
16
  import { getDefaultFormat } from "../valueFormatter"
18
17
  import { JsonQLFilter } from "../JsonQLFilter"
19
- import { Axis, AxisXform, AxisXformRange } from "./Axis"
18
+ import { Axis, AxisCategory, AxisXform, AxisXformRange } from "./Axis"
20
19
  import produce from "immer"
21
20
  import { JsonQLSelectQuery } from "@mwater/jsonql"
22
21
 
@@ -54,7 +53,7 @@ export interface AxisComponentProps {
54
53
  // Axis component that allows designing of an axis
55
54
  export default class AxisComponent extends AsyncLoadComponent<
56
55
  AxisComponentProps,
57
- { categories: any; loading: boolean }
56
+ { categories: AxisCategory[] | null; loading: boolean }
58
57
  > {
59
58
  static defaultProps = {
60
59
  reorderable: false,
@@ -146,14 +145,14 @@ export default class AxisComponent extends AsyncLoadComponent<
146
145
  valuesQuery.where = whereClauses[0]
147
146
  }
148
147
 
149
- return props.dataSource.performQuery(valuesQuery, (error: any, rows: any) => {
148
+ props.dataSource.performQuery(valuesQuery, (error: any, rows: any) => {
150
149
  if (error) {
151
150
  return // Ignore errors
152
151
  }
153
152
 
154
153
  // Get categories (value + label)
155
154
  categories = axisBuilder.getCategories(axis, _.pluck(rows, "val"))
156
- return callback({ categories })
155
+ callback({ categories })
157
156
  })
158
157
  }
159
158
 
@@ -254,37 +253,37 @@ export default class AxisComponent extends AsyncLoadComponent<
254
253
  if (axis.xform && ["bin", "ranges", "floor"].includes(axis.xform.type)) {
255
254
  let comp
256
255
  if (axis.xform.type === "ranges") {
257
- comp = R(RangesComponent, {
258
- schema: this.props.schema,
259
- expr: axis.expr,
260
- xform: axis.xform,
261
- onChange: this.handleXformChange
262
- })
256
+ comp = <RangesComponent
257
+ schema={this.props.schema}
258
+ expr={axis.expr}
259
+ xform={axis.xform}
260
+ onChange={this.handleXformChange}
261
+ />
263
262
  } else if (axis.xform.type === "bin") {
264
- comp = R(BinsComponent, {
265
- schema: this.props.schema,
266
- dataSource: this.props.dataSource,
267
- expr: axis.expr,
268
- xform: axis.xform,
269
- onChange: this.handleXformChange
270
- })
263
+ comp = <BinsComponent
264
+ schema={this.props.schema}
265
+ dataSource={this.props.dataSource}
266
+ expr={axis.expr}
267
+ xform={axis.xform}
268
+ onChange={this.handleXformChange}
269
+ />
271
270
  } else {
272
271
  comp = null
273
272
  }
274
273
 
275
- return R(
276
- "div",
277
- null,
278
- R(ui.RadioToggleComponent, {
279
- value: axis.xform ? axis.xform.type : null,
280
- options: [
281
- { value: "bin", label: T`Equal Bins` },
282
- { value: "ranges", label: T`Custom Ranges` },
283
- { value: "floor", label: T`Whole Numbers` }
284
- ],
285
- onChange: this.handleXformTypeChange
286
- }),
287
- comp
274
+ return (
275
+ <div>
276
+ <ui.RadioToggleComponent
277
+ value={axis.xform ? axis.xform.type : null}
278
+ options={[
279
+ { value: "bin", label: T`Equal Bins` },
280
+ { value: "ranges", label: T`Custom Ranges` },
281
+ { value: "floor", label: T`Whole Numbers` }
282
+ ]}
283
+ onChange={this.handleXformTypeChange}
284
+ />
285
+ {comp}
286
+ </div>
288
287
  )
289
288
  }
290
289
 
@@ -293,9 +292,9 @@ export default class AxisComponent extends AsyncLoadComponent<
293
292
 
294
293
  switch (exprType) {
295
294
  case "date":
296
- return R(ui.RadioToggleComponent, {
297
- value: axis.xform ? axis.xform.type : null,
298
- options: [
295
+ return <ui.RadioToggleComponent
296
+ value={axis.xform ? axis.xform.type : null}
297
+ options={[
299
298
  { value: null, label: T`Exact Date` },
300
299
  { value: "year", label: T`Year` },
301
300
  { value: "yearmonth", label: T`Year/Month` },
@@ -303,13 +302,13 @@ export default class AxisComponent extends AsyncLoadComponent<
303
302
  { value: "week", label: T`Week` },
304
303
  { value: "yearweek", label: T`Year/Week` },
305
304
  { value: "yearquarter", label: T`Year/Quarter` }
306
- ],
307
- onChange: this.handleXformTypeChange
308
- })
305
+ ]}
306
+ onChange={this.handleXformTypeChange}
307
+ />
309
308
  case "datetime":
310
- return R(ui.RadioToggleComponent, {
311
- value: axis.xform ? axis.xform.type : null,
312
- options: [
309
+ return <ui.RadioToggleComponent
310
+ value={axis.xform ? axis.xform.type : null}
311
+ options={[
313
312
  { value: "date", label: T`Date` },
314
313
  { value: "year", label: T`Year` },
315
314
  { value: "yearmonth", label: T`Year/Month` },
@@ -317,9 +316,9 @@ export default class AxisComponent extends AsyncLoadComponent<
317
316
  { value: "week", label: T`Week` },
318
317
  { value: "yearweek", label: T`Year/Week` },
319
318
  { value: "yearquarter", label: T`Year/Quarter` }
320
- ],
321
- onChange: this.handleXformTypeChange
322
- })
319
+ ]}
320
+ onChange={this.handleXformTypeChange}
321
+ />
323
322
  }
324
323
  return null
325
324
  }
@@ -329,20 +328,22 @@ export default class AxisComponent extends AsyncLoadComponent<
329
328
  return null
330
329
  }
331
330
 
332
- return [
333
- R("br"),
334
- R(AxisColorEditorComponent, {
335
- schema: this.props.schema,
336
- axis,
337
- categories: this.state.categories,
338
- onChange: this.props.onChange,
339
- reorderable: this.props.reorderable,
340
- defaultColor: this.props.defaultColor,
341
- allowExcludedValues: this.props.allowExcludedValues,
342
- autosetColors: this.props.autosetColors,
343
- initiallyExpanded: this.props.collapseCategories !== true
344
- })
345
- ]
331
+ return (
332
+ <>
333
+ <br/>
334
+ <AxisColorEditorComponent
335
+ schema={this.props.schema}
336
+ axis={axis}
337
+ categories={this.state.categories ?? undefined}
338
+ onChange={this.props.onChange}
339
+ reorderable={this.props.reorderable}
340
+ defaultColor={this.props.defaultColor ?? undefined}
341
+ allowExcludedValues={this.props.allowExcludedValues}
342
+ autosetColors={this.props.autosetColors}
343
+ initiallyExpanded={this.props.collapseCategories !== true}
344
+ />
345
+ </>
346
+ )
346
347
  }
347
348
 
348
349
  renderExcludedValues(axis: any) {
@@ -356,19 +357,21 @@ export default class AxisComponent extends AsyncLoadComponent<
356
357
  return null
357
358
  }
358
359
 
359
- return [
360
- R("br"),
361
- R(CategoryMapComponent, {
362
- schema: this.props.schema,
363
- axis,
364
- onChange: this.props.onChange,
365
- categories: this.state.categories,
366
- reorderable: false,
367
- showColorMap: false,
368
- allowExcludedValues: true,
369
- initiallyExpanded: this.props.collapseCategories !== true
370
- })
371
- ]
360
+ return (
361
+ <>
362
+ <br/>
363
+ <CategoryMapComponent
364
+ schema={this.props.schema}
365
+ axis={axis}
366
+ onChange={this.props.onChange}
367
+ categories={this.state.categories}
368
+ reorderable={false}
369
+ showColorMap={false}
370
+ allowExcludedValues={true}
371
+ initiallyExpanded={this.props.collapseCategories !== true}
372
+ />
373
+ </>
374
+ )
372
375
  }
373
376
 
374
377
  renderFormat(axis: any) {
@@ -384,21 +387,21 @@ export default class AxisComponent extends AsyncLoadComponent<
384
387
  return null
385
388
  }
386
389
 
387
- return R(
388
- "div",
389
- { className: "mb-3" },
390
- R("label", { className: "text-muted" }, T`Format`),
391
- ": ",
392
- R(
393
- "select",
394
- {
395
- value: axis.format != null ? axis.format : getDefaultFormat(valueType),
396
- className: "form-select",
397
- style: { width: "auto", display: "inline-block" },
398
- onChange: this.handleFormatChange
399
- },
400
- _.map(formats, (format) => R("option", { key: format.value, value: format.value }, format.label))
401
- )
390
+ return (
391
+ <div className="mb-3">
392
+ <label className="text-muted">{T`Format`}</label>
393
+ {": "}
394
+ <select
395
+ value={axis.format != null ? axis.format : getDefaultFormat(valueType)}
396
+ className="form-select"
397
+ style={{ width: "auto", display: "inline-block" }}
398
+ onChange={this.handleFormatChange}
399
+ >
400
+ {_.map(formats, (format) => (
401
+ <option key={format.value} value={format.value}>{format.label}</option>
402
+ ))}
403
+ </select>
404
+ </div>
402
405
  )
403
406
  }
404
407
 
@@ -422,27 +425,24 @@ export default class AxisComponent extends AsyncLoadComponent<
422
425
  break
423
426
  }
424
427
 
425
- return R(
426
- "div",
427
- null,
428
- R(
429
- "div",
430
- null,
431
- R(ExprComponent, {
432
- schema: this.props.schema,
433
- dataSource: this.props.dataSource,
434
- table: this.props.table,
435
- types: axisBuilder.getExprTypes(this.props.types),
436
- // preventRemove: @props.required
437
- onChange: this.handleExprChange,
438
- value: this.props.value ? this.props.value.expr : null,
439
- aggrStatuses
440
- })
441
- ),
442
- this.renderXform(axis),
443
- this.props.showFormat ? this.renderFormat(axis) : undefined,
444
- this.renderColorMap(axis),
445
- this.renderExcludedValues(axis)
428
+ return (
429
+ <div>
430
+ <div>
431
+ <ExprComponent
432
+ schema={this.props.schema}
433
+ dataSource={this.props.dataSource}
434
+ table={this.props.table}
435
+ types={axisBuilder.getExprTypes(this.props.types)}
436
+ onChange={this.handleExprChange}
437
+ value={this.props.value ? this.props.value.expr : null}
438
+ aggrStatuses={aggrStatuses}
439
+ />
440
+ </div>
441
+ {this.renderXform(axis)}
442
+ {this.props.showFormat ? this.renderFormat(axis) : undefined}
443
+ {this.renderColorMap(axis)}
444
+ {this.renderExcludedValues(axis)}
445
+ </div>
446
446
  )
447
447
  }
448
448
  }