@mwater/visualization 5.5.0 → 5.6.1

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 (275) hide show
  1. package/lib/ColorComponent.js +2 -2
  2. package/lib/MWaterContextComponent.d.ts +1 -1
  3. package/lib/MWaterGlobalFiltersComponent.d.ts +2 -2
  4. package/lib/MWaterGlobalFiltersComponent.js +11 -20
  5. package/lib/MWaterLoaderComponent.d.ts +4 -13
  6. package/lib/MWaterLoaderComponent.js +2 -11
  7. package/lib/TranslationsTabComponent.d.ts +34 -0
  8. package/lib/TranslationsTabComponent.js +256 -0
  9. package/lib/UndoStack.d.ts +2 -1
  10. package/lib/UndoStack.js +12 -6
  11. package/lib/dashboards/DashboardComponent.js +6 -5
  12. package/lib/dashboards/DashboardDesign.d.ts +1 -1
  13. package/lib/dashboards/ServerDashboardDataSource.d.ts +0 -1
  14. package/lib/dashboards/ServerDashboardDataSource.js +0 -25
  15. package/lib/dashboards/SettingsModalComponent.js +9 -233
  16. package/lib/datagrids/DatagridComponent.js +27 -2
  17. package/lib/datagrids/DatagridDesignerComponent.d.ts +2 -3
  18. package/lib/datagrids/DatagridDesignerComponent.js +108 -120
  19. package/lib/datagrids/DatagridViewComponent.js +33 -6
  20. package/lib/datagrids/OrderBysDesignerComponent.d.ts +7 -7
  21. package/lib/datagrids/OrderBysDesignerComponent.js +19 -28
  22. package/lib/index.css +45 -2
  23. package/lib/index.d.ts +5 -5
  24. package/lib/index.js +2 -3
  25. package/lib/layouts/blocks/BlocksDisplayComponent.d.ts +8 -1
  26. package/lib/layouts/blocks/BlocksDisplayComponent.js +46 -4
  27. package/lib/maps/BufferLayer.d.ts +0 -13
  28. package/lib/maps/BufferLayer.js +24 -237
  29. package/lib/maps/BufferLayerDesign.d.ts +1 -1
  30. package/lib/maps/BufferLayerDesignerComponent.d.ts +1 -1
  31. package/lib/maps/BufferLayerDesignerComponent.js +2 -7
  32. package/lib/maps/ChoroplethLayer.d.ts +1 -16
  33. package/lib/maps/ChoroplethLayer.js +25 -358
  34. package/lib/maps/ChoroplethLayerDesign.d.ts +5 -2
  35. package/lib/maps/ChoroplethLayerDesigner.d.ts +10 -32
  36. package/lib/maps/ChoroplethLayerDesigner.js +58 -89
  37. package/lib/maps/ClusterLayer.d.ts +0 -9
  38. package/lib/maps/ClusterLayer.js +0 -250
  39. package/lib/maps/DirectMapDataSource.js +1 -48
  40. package/lib/maps/EditHoverOver.d.ts +4 -3
  41. package/lib/maps/EditHoverOver.js +3 -3
  42. package/lib/maps/GridLayer.d.ts +0 -15
  43. package/lib/maps/GridLayer.js +0 -212
  44. package/lib/maps/HoverContent.js +1 -1
  45. package/lib/maps/Layer.d.ts +1 -26
  46. package/lib/maps/Layer.js +0 -13
  47. package/lib/maps/LeafletMapComponent.js +10 -19
  48. package/lib/maps/MapComponent.d.ts +19 -35
  49. package/lib/maps/MapComponent.js +135 -77
  50. package/lib/maps/MapControlComponent.d.ts +4 -5
  51. package/lib/maps/MapControlComponent.js +5 -12
  52. package/lib/maps/MapDesign.d.ts +8 -0
  53. package/lib/maps/MapDesignerComponent.d.ts +2 -0
  54. package/lib/maps/MapDesignerComponent.js +7 -2
  55. package/lib/maps/MapLayerDataSource.d.ts +0 -4
  56. package/lib/maps/MapLayerViewDesignerComponent.d.ts +3 -1
  57. package/lib/maps/MapLayerViewDesignerComponent.js +5 -1
  58. package/lib/maps/MapLayersDesignerComponent.d.ts +2 -0
  59. package/lib/maps/MapLayersDesignerComponent.js +2 -1
  60. package/lib/maps/MapTranslationsTab.d.ts +15 -0
  61. package/lib/maps/MapTranslationsTab.js +47 -0
  62. package/lib/maps/MapUtils.d.ts +11 -0
  63. package/lib/maps/MapUtils.js +57 -1
  64. package/lib/maps/MapViewComponent.d.ts +1 -1
  65. package/lib/maps/MapViewComponent.js +1 -8
  66. package/lib/maps/MarkersLayer.d.ts +1 -14
  67. package/lib/maps/MarkersLayer.js +89 -254
  68. package/lib/maps/MarkersLayerDesign.d.ts +5 -1
  69. package/lib/maps/MarkersLayerDesignerComponent.d.ts +32 -57
  70. package/lib/maps/MarkersLayerDesignerComponent.js +158 -134
  71. package/lib/maps/ServerMapDataSource.d.ts +0 -1
  72. package/lib/maps/ServerMapDataSource.js +0 -25
  73. package/lib/maps/SwitchableTileUrlLayer.d.ts +0 -2
  74. package/lib/maps/SwitchableTileUrlLayer.js +0 -9
  75. package/lib/maps/TileUrlLayer.d.ts +0 -1
  76. package/lib/maps/TileUrlLayer.js +0 -5
  77. package/lib/maps/VectorMapViewComponent.js +13 -10
  78. package/lib/maps/symbols/font-awesome/asterisk.png +0 -0
  79. package/lib/maps/symbols/font-awesome/ban.png +0 -0
  80. package/lib/maps/symbols/font-awesome/beer.png +0 -0
  81. package/lib/maps/symbols/font-awesome/bell.png +0 -0
  82. package/lib/maps/symbols/font-awesome/bolt.png +0 -0
  83. package/lib/maps/symbols/font-awesome/building.png +0 -0
  84. package/lib/maps/symbols/font-awesome/bullseye.png +0 -0
  85. package/lib/maps/symbols/font-awesome/bus.png +0 -0
  86. package/lib/maps/symbols/font-awesome/caret-up.png +0 -0
  87. package/lib/maps/symbols/font-awesome/certificate.png +0 -0
  88. package/lib/maps/symbols/font-awesome/check-circle.png +0 -0
  89. package/lib/maps/symbols/font-awesome/check.png +0 -0
  90. package/lib/maps/symbols/font-awesome/chevron-circle-down.png +0 -0
  91. package/lib/maps/symbols/font-awesome/chevron-circle-up.png +0 -0
  92. package/lib/maps/symbols/font-awesome/cloud-rain.png +0 -0
  93. package/lib/maps/symbols/font-awesome/cloud.png +0 -0
  94. package/lib/maps/symbols/font-awesome/comment.png +0 -0
  95. package/lib/maps/symbols/font-awesome/crosshairs.png +0 -0
  96. package/lib/maps/symbols/font-awesome/dot-circle-o.png +0 -0
  97. package/lib/maps/symbols/font-awesome/exclamation-circle.png +0 -0
  98. package/lib/maps/symbols/font-awesome/exclamation-triangle.png +0 -0
  99. package/lib/maps/symbols/font-awesome/female.png +0 -0
  100. package/lib/maps/symbols/font-awesome/file.png +0 -0
  101. package/lib/maps/symbols/font-awesome/flag.png +0 -0
  102. package/lib/maps/symbols/font-awesome/flask.png +0 -0
  103. package/lib/maps/symbols/font-awesome/h-square.png +0 -0
  104. package/lib/maps/symbols/font-awesome/home.png +0 -0
  105. package/lib/maps/symbols/font-awesome/info-circle.png +0 -0
  106. package/lib/maps/symbols/font-awesome/male.png +0 -0
  107. package/lib/maps/symbols/font-awesome/medkit.png +0 -0
  108. package/lib/maps/symbols/font-awesome/mobile.png +0 -0
  109. package/lib/maps/symbols/font-awesome/plus-circle.png +0 -0
  110. package/lib/maps/symbols/font-awesome/plus-square.png +0 -0
  111. package/lib/maps/symbols/font-awesome/plus.png +0 -0
  112. package/lib/maps/symbols/font-awesome/square.png +0 -0
  113. package/lib/maps/symbols/font-awesome/star.png +0 -0
  114. package/lib/maps/symbols/font-awesome/thumbs-down.png +0 -0
  115. package/lib/maps/symbols/font-awesome/thumbs-up.png +0 -0
  116. package/lib/maps/symbols/font-awesome/ticket.png +0 -0
  117. package/lib/maps/symbols/font-awesome/times-circle.png +0 -0
  118. package/lib/maps/symbols/font-awesome/times.png +0 -0
  119. package/lib/maps/symbols/font-awesome/tint.png +0 -0
  120. package/lib/maps/symbols/font-awesome/tree.png +0 -0
  121. package/lib/maps/symbols/font-awesome/university.png +0 -0
  122. package/lib/maps/symbols/font-awesome/usd.png +0 -0
  123. package/lib/maps/symbols/font-awesome/user.png +0 -0
  124. package/lib/maps/symbols/font-awesome/users.png +0 -0
  125. package/lib/maps/symbols/font-awesome/wheelchair.png +0 -0
  126. package/lib/maps/symbols/sdf-ize.sh +93 -0
  127. package/lib/maps/vectorMaps.d.ts +6 -6
  128. package/lib/maps/vectorMaps.js +33 -45
  129. package/lib/mwater_table_selection/IndicatorsListComponent.d.ts +4 -2
  130. package/lib/mwater_table_selection/IndicatorsListComponent.js +103 -34
  131. package/lib/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.d.ts +18 -0
  132. package/lib/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.js +80 -0
  133. package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.d.ts +26 -0
  134. package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.js +237 -51
  135. package/lib/mwater_table_selection/MWaterTableSelectComponent.d.ts +2 -2
  136. package/lib/mwater_table_selection/MWaterTableSelectComponent.js +9 -4
  137. package/lib/mwater_table_selection/MWaterWorkflowsSelectComponent.d.ts +19 -0
  138. package/lib/mwater_table_selection/MWaterWorkflowsSelectComponent.js +111 -0
  139. package/lib/quickfilter/QuickfiltersComponent.d.ts +3 -102
  140. package/lib/quickfilter/QuickfiltersComponent.js +53 -110
  141. package/lib/quickfilter/TextLiteralComponent.d.ts +23 -47
  142. package/lib/quickfilter/TextLiteralComponent.js +85 -82
  143. package/lib/widgets/MapWidget.js +6 -3
  144. package/lib/widgets/text/ExprItemEditorComponent.d.ts +3 -8
  145. package/lib/widgets/text/ExprItemEditorComponent.js +36 -33
  146. package/lib/widgets/text/ExprUpdateModalComponent.d.ts +1 -0
  147. package/package.json +3 -4
  148. package/src/ColorComponent.tsx +2 -2
  149. package/src/MWaterContextComponent.tsx +1 -1
  150. package/src/{MWaterGlobalFiltersComponent.ts → MWaterGlobalFiltersComponent.tsx} +32 -33
  151. package/src/{MWaterLoaderComponent.ts → MWaterLoaderComponent.tsx} +17 -18
  152. package/src/TranslationsTabComponent.tsx +429 -0
  153. package/src/UndoStack.ts +14 -6
  154. package/src/dashboards/DashboardComponent.tsx +6 -5
  155. package/src/dashboards/DashboardDesign.ts +1 -1
  156. package/src/dashboards/ServerDashboardDataSource.ts +0 -31
  157. package/src/dashboards/SettingsModalComponent.tsx +27 -383
  158. package/src/datagrids/DatagridComponent.tsx +36 -2
  159. package/src/datagrids/DatagridDesignerComponent.tsx +241 -229
  160. package/src/datagrids/DatagridViewComponent.tsx +44 -7
  161. package/src/datagrids/OrderBysDesignerComponent.tsx +61 -70
  162. package/src/index.css +45 -2
  163. package/src/index.ts +5 -11
  164. package/src/layouts/blocks/BlocksDisplayComponent.tsx +60 -5
  165. package/src/maps/BufferLayer.ts +30 -263
  166. package/src/maps/BufferLayerDesign.ts +1 -1
  167. package/src/maps/BufferLayerDesignerComponent.tsx +2 -7
  168. package/src/maps/ChoroplethLayer.ts +30 -394
  169. package/src/maps/ChoroplethLayerDesign.ts +5 -2
  170. package/src/maps/ChoroplethLayerDesigner.tsx +169 -165
  171. package/src/maps/ClusterLayer.ts +0 -274
  172. package/src/maps/DirectMapDataSource.ts +2 -61
  173. package/src/maps/EditHoverOver.tsx +9 -5
  174. package/src/maps/GridLayer.ts +0 -224
  175. package/src/maps/HoverContent.tsx +1 -1
  176. package/src/maps/Layer.ts +1 -35
  177. package/src/maps/LeafletMapComponent.tsx +10 -19
  178. package/src/maps/MapComponent.tsx +448 -0
  179. package/src/maps/MapControlComponent.tsx +41 -0
  180. package/src/maps/MapDesign.ts +6 -0
  181. package/src/maps/MapDesignerComponent.tsx +18 -1
  182. package/src/maps/MapLayerDataSource.ts +0 -5
  183. package/src/maps/MapLayerViewDesignerComponent.ts +9 -2
  184. package/src/maps/MapLayersDesignerComponent.ts +4 -1
  185. package/src/maps/MapTranslationsTab.tsx +53 -0
  186. package/src/maps/MapUtils.ts +61 -1
  187. package/src/maps/MapViewComponent.tsx +2 -8
  188. package/src/maps/MarkersLayer.ts +101 -275
  189. package/src/maps/MarkersLayerDesign.ts +7 -1
  190. package/src/maps/MarkersLayerDesignerComponent.tsx +436 -0
  191. package/src/maps/ServerMapDataSource.ts +0 -31
  192. package/src/maps/SwitchableTileUrlLayer.tsx +0 -11
  193. package/src/maps/TileUrlLayer.tsx +0 -6
  194. package/src/maps/VectorMapViewComponent.tsx +15 -15
  195. package/src/maps/symbols/font-awesome/asterisk.png +0 -0
  196. package/src/maps/symbols/font-awesome/ban.png +0 -0
  197. package/src/maps/symbols/font-awesome/beer.png +0 -0
  198. package/src/maps/symbols/font-awesome/bell.png +0 -0
  199. package/src/maps/symbols/font-awesome/bolt.png +0 -0
  200. package/src/maps/symbols/font-awesome/building.png +0 -0
  201. package/src/maps/symbols/font-awesome/bullseye.png +0 -0
  202. package/src/maps/symbols/font-awesome/bus.png +0 -0
  203. package/src/maps/symbols/font-awesome/caret-up.png +0 -0
  204. package/src/maps/symbols/font-awesome/certificate.png +0 -0
  205. package/src/maps/symbols/font-awesome/check-circle.png +0 -0
  206. package/src/maps/symbols/font-awesome/check.png +0 -0
  207. package/src/maps/symbols/font-awesome/chevron-circle-down.png +0 -0
  208. package/src/maps/symbols/font-awesome/chevron-circle-up.png +0 -0
  209. package/src/maps/symbols/font-awesome/cloud-rain.png +0 -0
  210. package/src/maps/symbols/font-awesome/cloud.png +0 -0
  211. package/src/maps/symbols/font-awesome/comment.png +0 -0
  212. package/src/maps/symbols/font-awesome/crosshairs.png +0 -0
  213. package/src/maps/symbols/font-awesome/dot-circle-o.png +0 -0
  214. package/src/maps/symbols/font-awesome/exclamation-circle.png +0 -0
  215. package/src/maps/symbols/font-awesome/exclamation-triangle.png +0 -0
  216. package/src/maps/symbols/font-awesome/female.png +0 -0
  217. package/src/maps/symbols/font-awesome/file.png +0 -0
  218. package/src/maps/symbols/font-awesome/flag.png +0 -0
  219. package/src/maps/symbols/font-awesome/flask.png +0 -0
  220. package/src/maps/symbols/font-awesome/h-square.png +0 -0
  221. package/src/maps/symbols/font-awesome/home.png +0 -0
  222. package/src/maps/symbols/font-awesome/info-circle.png +0 -0
  223. package/src/maps/symbols/font-awesome/male.png +0 -0
  224. package/src/maps/symbols/font-awesome/medkit.png +0 -0
  225. package/src/maps/symbols/font-awesome/mobile.png +0 -0
  226. package/src/maps/symbols/font-awesome/plus-circle.png +0 -0
  227. package/src/maps/symbols/font-awesome/plus-square.png +0 -0
  228. package/src/maps/symbols/font-awesome/plus.png +0 -0
  229. package/src/maps/symbols/font-awesome/square.png +0 -0
  230. package/src/maps/symbols/font-awesome/star.png +0 -0
  231. package/src/maps/symbols/font-awesome/thumbs-down.png +0 -0
  232. package/src/maps/symbols/font-awesome/thumbs-up.png +0 -0
  233. package/src/maps/symbols/font-awesome/ticket.png +0 -0
  234. package/src/maps/symbols/font-awesome/times-circle.png +0 -0
  235. package/src/maps/symbols/font-awesome/times.png +0 -0
  236. package/src/maps/symbols/font-awesome/tint.png +0 -0
  237. package/src/maps/symbols/font-awesome/tree.png +0 -0
  238. package/src/maps/symbols/font-awesome/university.png +0 -0
  239. package/src/maps/symbols/font-awesome/usd.png +0 -0
  240. package/src/maps/symbols/font-awesome/user.png +0 -0
  241. package/src/maps/symbols/font-awesome/users.png +0 -0
  242. package/src/maps/symbols/font-awesome/wheelchair.png +0 -0
  243. package/src/maps/symbols/sdf-ize.sh +93 -0
  244. package/src/maps/vectorMaps.tsx +32 -53
  245. package/src/mwater_table_selection/IndicatorsListComponent.tsx +165 -37
  246. package/src/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.tsx +111 -0
  247. package/src/mwater_table_selection/MWaterCompleteTableSelectComponent.tsx +373 -37
  248. package/src/mwater_table_selection/MWaterTableSelectComponent.tsx +12 -8
  249. package/src/mwater_table_selection/MWaterWorkflowsSelectComponent.tsx +159 -0
  250. package/src/quickfilter/{QuickfiltersComponent.ts → QuickfiltersComponent.tsx} +165 -158
  251. package/src/quickfilter/TextLiteralComponent.tsx +197 -0
  252. package/src/widgets/MapWidget.tsx +11 -1
  253. package/src/widgets/text/ExprItemEditorComponent.tsx +83 -77
  254. package/src/widgets/text/ExprUpdateModalComponent.tsx +1 -0
  255. package/test/UndoStackTests.ts +52 -1
  256. package/.storybook/config.js +0 -7
  257. package/.storybook/head.html +0 -3
  258. package/.storybook/webpack.config.js +0 -15
  259. package/src/maps/BingLayer.ts +0 -146
  260. package/src/maps/MapComponent.ts +0 -312
  261. package/src/maps/MapControlComponent.ts +0 -46
  262. package/src/maps/MarkersLayerDesignerComponent.ts +0 -374
  263. package/src/maps/RasterMapViewComponent.ts +0 -345
  264. package/src/quickfilter/TextLiteralComponent.ts +0 -165
  265. package/stories/UpdateableComponent.js +0 -29
  266. package/stories/consoles.js +0 -202
  267. package/stories/dashboards.js +0 -217
  268. package/stories/datagridDesign.js +0 -114
  269. package/stories/datagrids.js +0 -69
  270. package/stories/dates.js +0 -80
  271. package/stories/exprcomponent.js +0 -43
  272. package/stories/index.js +0 -18
  273. package/stories/leaflet.js +0 -59
  274. package/stories/maps.js +0 -24
  275. package/stories/pivotChart.js +0 -235
@@ -26,11 +26,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
26
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
27
27
  };
28
28
  Object.defineProperty(exports, "__esModule", { value: true });
29
- const lodash_1 = __importDefault(require("lodash"));
30
29
  const react_1 = __importStar(require("react"));
31
- const languages_1 = require("../languages");
32
30
  const ui = __importStar(require("@mwater/react-library/lib/bootstrap"));
33
- const react_select_1 = __importDefault(require("react-select"));
34
31
  const DashboardUtils = __importStar(require("./DashboardUtils"));
35
32
  const ActionCancelModalComponent_1 = __importDefault(require("@mwater/react-library/lib/ActionCancelModalComponent"));
36
33
  const QuickfiltersDesignComponent_1 = __importDefault(require("../quickfilter/QuickfiltersDesignComponent"));
@@ -38,9 +35,7 @@ const FiltersDesignerComponent_1 = __importDefault(require("../FiltersDesignerCo
38
35
  const MWaterContextComponent_1 = require("../MWaterContextComponent");
39
36
  const immer_1 = __importDefault(require("immer"));
40
37
  const TabbedComponent_1 = __importDefault(require("@mwater/react-library/lib/TabbedComponent"));
41
- const file_saver_1 = __importDefault(require("file-saver"));
42
- const localizeUtils = __importStar(require("ez-localize/lib/utils"));
43
- const autotranslate_1 = require("../autotranslate");
38
+ const TranslationsTabComponent_1 = require("../TranslationsTabComponent");
44
39
  /** Popup with settings for dashboard */
45
40
  class SettingsModalComponent extends react_1.default.Component {
46
41
  constructor(props) {
@@ -127,233 +122,14 @@ function FiltersTab({ design, onDesignChange, schema, dataSource }) {
127
122
  draft.implicitFiltersEnabled = value;
128
123
  })) }, T `Enable Implicit Filtering (leave unchecked for new dashboards)`)))));
129
124
  }
125
+ /** Wrapper around TranslationsTabComponent for dashboard-specific usage */
130
126
  function LanguageTab({ design, onDesignChange, schema }) {
131
- const fileInputRef = (0, react_1.useRef)(null);
132
- const locale = design.locale || "en";
133
- const localeOptions = (0, react_1.useMemo)(() => {
134
- return lodash_1.default.sortBy(lodash_1.default.map(languages_1.languages, (language) => ({
135
- value: language.code,
136
- label: `${language.en} (${language.name})`
137
- })), 'label');
138
- }, [languages_1.languages]);
139
- // Get available languages that aren't already selected
140
- const availableLocaleOptions = (0, react_1.useMemo)(() => {
141
- const selectedLocales = new Set([design.locale, ...(design.otherLocales || [])]);
142
- return localeOptions.filter(opt => !selectedLocales.has(opt.value));
143
- }, [localeOptions, design.locale, design.otherLocales]);
144
127
  const translatableStrings = (0, react_1.useMemo)(() => DashboardUtils.getTranslatableStringsFromDashboard(design, schema), [design, schema]);
145
- // Calculate percentage of strings translated for each locale
146
- const translationPercentages = (0, react_1.useMemo)(() => {
147
- const percentages = {};
148
- const totalStrings = translatableStrings.length;
149
- for (const locale of design.otherLocales || []) {
150
- const translatedCount = translatableStrings.filter(str => design.translations?.[locale]?.[str] != null).length;
151
- // Round down to nearest percent
152
- percentages[locale] = Math.floor((translatedCount / totalStrings) * 100);
153
- }
154
- return percentages;
155
- }, [design.translations, design.otherLocales, translatableStrings]);
156
- const handleAddLocale = (locale) => {
157
- onDesignChange((0, immer_1.default)(design, draft => {
158
- draft.otherLocales = [...(draft.otherLocales || []), locale.value];
159
- // Initialize empty translations object if needed
160
- if (!draft.translations) {
161
- draft.translations = {};
162
- }
163
- if (!draft.translations[locale.value]) {
164
- draft.translations[locale.value] = {};
165
- }
166
- }));
167
- };
168
- const handleRemoveLocale = (localeToRemove) => {
169
- onDesignChange((0, immer_1.default)(design, draft => {
170
- draft.otherLocales = (draft.otherLocales || []).filter(locale => locale !== localeToRemove);
171
- // Remove translations for this locale
172
- if (draft.translations) {
173
- delete draft.translations[localeToRemove];
174
- }
175
- }));
176
- };
177
- // Convert dashboard translations to LocalizedString format
178
- const getLocalizedStrings = () => {
179
- // For each string, create a localized string
180
- const localizedStrings = [];
181
- for (const str of translatableStrings) {
182
- const localizedString = { _base: locale };
183
- localizedString[locale] = str;
184
- // Only add translations for other locales if they exist
185
- for (const otherLocale of design.otherLocales || []) {
186
- if (design.translations?.[otherLocale]?.[str]) {
187
- localizedString[otherLocale] = design.translations?.[otherLocale]?.[str];
188
- }
189
- }
190
- localizedStrings.push(localizedString);
191
- }
192
- return localizedStrings;
193
- };
194
- // Convert LocalizedString format back to dashboard translations
195
- const updateFromLocalizedStrings = (localizedStrings) => {
196
- const newTranslations = {};
197
- // Get all locales except base
198
- const locales = design.otherLocales || [];
199
- // Initialize translations object
200
- for (const locale of locales) {
201
- newTranslations[locale] = {};
202
- }
203
- // Add all translations
204
- for (const str of localizedStrings) {
205
- for (const locale of locales) {
206
- if (str[locale]) {
207
- newTranslations[locale][str[str._base]] = str[locale];
208
- }
209
- }
210
- }
211
- return newTranslations;
212
- };
213
- const handleDownload = () => {
214
- // Get strings in LocalizedString format
215
- const strings = getLocalizedStrings();
216
- // Create xlsx base64 using all locales (primary + other)
217
- const locales = [{ code: locale, name: locale }]
218
- .concat((design.otherLocales || []).map(code => ({ code, name: code })));
219
- const base64 = localizeUtils.exportXlsx(locales, strings);
220
- // Download
221
- file_saver_1.default.saveAs(b64toBlob(base64, "application/octet-stream"), "Dashboard Translations.xlsx");
222
- };
223
- const handleUpload = () => {
224
- fileInputRef.current?.click();
225
- };
226
- const handleUploadChange = (evt) => {
227
- const reader = new FileReader();
228
- reader.onload = (file) => {
229
- if (!file.target?.result) {
230
- return;
231
- }
232
- const base64 = file.target.result.split(",")[1];
233
- try {
234
- // Create locales array for import
235
- const locales = [{ code: locale, name: locale }]
236
- .concat((design.otherLocales || []).map(code => ({ code, name: code })));
237
- // Import updates
238
- const updates = localizeUtils.importXlsx(locales, base64);
239
- // If nothing localized
240
- if (updates.length === 0) {
241
- alert(T `No translation data found in file`);
242
- return;
243
- }
244
- // Convert back to dashboard format and update
245
- const newTranslations = updateFromLocalizedStrings(updates);
246
- onDesignChange((0, immer_1.default)(design, draft => {
247
- draft.translations = newTranslations;
248
- }));
249
- alert(T `${updates.length} translations applied`);
250
- }
251
- catch (error) {
252
- console.error("Invalid xlsx file:", error);
253
- alert(T `Invalid xlsx file`);
254
- }
255
- };
256
- if (evt.target.files?.[0]) {
257
- reader.readAsDataURL(evt.target.files[0]);
258
- }
259
- };
260
- return (react_1.default.createElement(react_1.default.Fragment, null,
261
- react_1.default.createElement("h4", null, T `Base Language`),
262
- react_1.default.createElement("div", { className: "mb-2" }, T `This is the language that the dashboard is written in.`),
263
- react_1.default.createElement(react_select_1.default, { value: lodash_1.default.findWhere(localeOptions, { value: design.locale || "en" }) || null, options: localeOptions, onChange: (locale) => onDesignChange((0, immer_1.default)(design, draft => {
264
- draft.locale = locale.value;
265
- })) }),
266
- react_1.default.createElement("h4", { className: "mt-4" }, T `Additional Languages`),
267
- react_1.default.createElement("div", { className: "mb-2" }, T `Add languages that this dashboard will be translated into`),
268
- react_1.default.createElement("table", null,
269
- react_1.default.createElement("tbody", null, (design.otherLocales || []).map(locale => {
270
- const localeOption = lodash_1.default.findWhere(localeOptions, { value: locale });
271
- if (!localeOption) {
272
- return null;
273
- }
274
- return (react_1.default.createElement("tr", { key: locale },
275
- react_1.default.createElement("td", { style: { paddingRight: 10 } }, localeOption.label),
276
- react_1.default.createElement("td", { className: translationPercentages[locale] === 100 ? "text-success" : "text-warning", style: { textAlign: "right" } }, T `${translationPercentages[locale]}% translated`),
277
- react_1.default.createElement("td", null, translationPercentages[locale] < 100 && (react_1.default.createElement(AutoTranslateLink, { locale: locale, baseLocale: design.locale || "en", strings: translatableStrings, existingTranslations: design.translations?.[locale] || {}, onTranslationsChange: (newTranslations) => {
278
- onDesignChange((0, immer_1.default)(design, draft => {
279
- if (!draft.translations) {
280
- draft.translations = {};
281
- }
282
- draft.translations[locale] = newTranslations;
283
- }));
284
- } }))),
285
- react_1.default.createElement("td", null,
286
- react_1.default.createElement("button", { type: "button", className: "btn btn-sm btn-link", onClick: () => handleRemoveLocale(locale) },
287
- react_1.default.createElement("i", { className: "fa fa-times" })))));
288
- }))),
289
- availableLocaleOptions.length > 0 && (react_1.default.createElement("div", { className: "mt-3" },
290
- react_1.default.createElement(react_select_1.default, { value: null, options: availableLocaleOptions, onChange: handleAddLocale, placeholder: T `Add language...` }))),
291
- (design.otherLocales || []).length > 0 && (react_1.default.createElement(react_1.default.Fragment, null,
292
- react_1.default.createElement("h4", { className: "mt-4" }, T `Manage Translations`),
293
- react_1.default.createElement("p", null, T `Download and re-upload an Excel spreadsheet of text to translate:`),
294
- react_1.default.createElement("div", null,
295
- react_1.default.createElement("button", { type: "button", className: "btn btn-secondary", onClick: handleDownload },
296
- react_1.default.createElement("i", { className: "fas fa-download me-2" }),
297
- T `Download XLSX`)),
298
- react_1.default.createElement("div", { className: "text-muted mt-2" }, T `This creates a spreadsheet that can be sent to a translator. Please do not change the first column or first row of the spreadsheet.`),
299
- react_1.default.createElement("br", null),
300
- react_1.default.createElement("p", null, T `Once translation is complete, upload the file back using the button below:`),
301
- react_1.default.createElement("div", null,
302
- react_1.default.createElement("button", { type: "button", className: "btn btn-secondary", onClick: handleUpload },
303
- react_1.default.createElement("i", { className: "fas fa-upload me-2" }),
304
- T `Upload Translated XLSX`)),
305
- react_1.default.createElement("input", { type: "file", ref: fileInputRef, style: { display: "none" }, onChange: handleUploadChange, accept: ".xlsx" })))));
306
- }
307
- /** Helper function for base64 to blob conversion */
308
- function b64toBlob(b64Data, contentType = "", sliceSize = 512) {
309
- const byteCharacters = atob(b64Data);
310
- const byteArrays = [];
311
- for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
312
- const slice = byteCharacters.slice(offset, offset + sliceSize);
313
- const byteNumbers = new Array(slice.length);
314
- for (let i = 0; i < slice.length; i++) {
315
- byteNumbers[i] = slice.charCodeAt(i);
316
- }
317
- const byteArray = new Uint8Array(byteNumbers);
318
- byteArrays.push(byteArray);
319
- }
320
- return new Blob(byteArrays, { type: contentType });
321
- }
322
- function AutoTranslateLink(props) {
323
- const { locale, baseLocale, strings, existingTranslations, onTranslationsChange } = props;
324
- const [isTranslating, setIsTranslating] = (0, react_1.useState)(false);
325
- const untranslatedStrings = (0, react_1.useMemo)(() => {
326
- return strings.filter(str => !existingTranslations[str]);
327
- }, [strings, existingTranslations]);
328
- const handleClick = async () => {
329
- if (isTranslating) {
330
- return;
331
- }
332
- setIsTranslating(true);
333
- try {
334
- const translatedStrings = await (0, autotranslate_1.translateStrings)(untranslatedStrings, baseLocale, locale);
335
- const newTranslations = { ...existingTranslations };
336
- for (let i = 0; i < untranslatedStrings.length; i++) {
337
- newTranslations[untranslatedStrings[i]] = translatedStrings[i];
338
- }
339
- onTranslationsChange(newTranslations);
340
- }
341
- catch (error) {
342
- console.error("Error translating strings:", error);
343
- alert(T `Error translating strings`);
344
- }
345
- finally {
346
- setIsTranslating(false);
347
- }
348
- };
349
- if (untranslatedStrings.length === 0) {
350
- return null;
351
- }
352
- if (!(0, autotranslate_1.canAutoTranslate)(locale)) {
353
- return null;
354
- }
355
- return (react_1.default.createElement("button", { type: "button", className: "btn btn-sm btn-link", onClick: handleClick, disabled: isTranslating, style: { marginLeft: 5, padding: "0 5px" } }, isTranslating ? (react_1.default.createElement("span", null,
356
- react_1.default.createElement("i", { className: "fa fa-spinner fa-spin" }),
357
- " ",
358
- T `Translating...`)) : (T `Autotranslate`)));
128
+ return (react_1.default.createElement(TranslationsTabComponent_1.TranslationsTabComponent, { locale: design.locale || "en", otherLocales: design.otherLocales || [], translations: design.translations || {}, translatableStrings: translatableStrings, onLocaleChange: (locale) => onDesignChange((0, immer_1.default)(design, draft => {
129
+ draft.locale = locale;
130
+ })), onOtherLocalesChange: (otherLocales) => onDesignChange((0, immer_1.default)(design, draft => {
131
+ draft.otherLocales = otherLocales;
132
+ })), onTranslationsChange: (translations) => onDesignChange((0, immer_1.default)(design, draft => {
133
+ draft.translations = translations;
134
+ })), downloadFilename: "Dashboard Translations.xlsx", baseLanguageDescription: T `This is the language that the dashboard is written in.` }));
359
135
  }
@@ -85,6 +85,11 @@ exports.default = (0, react_1.forwardRef)(function DatagridComponent(props, ref)
85
85
  return;
86
86
  }
87
87
  let activeFilters = filters || [];
88
+ // Clean before counting
89
+ const cleanedDesign = new DatagridUtils_1.default(schema).cleanDesign(design);
90
+ if (new DatagridUtils_1.default(schema).validateDesign(cleanedDesign)) {
91
+ return;
92
+ }
88
93
  // Compile quickfilters
89
94
  activeFilters = activeFilters.concat(getQuickfilterFilters());
90
95
  datagridDataSource.countRows(design, activeFilters, (error, count) => {
@@ -342,8 +347,28 @@ exports.default = (0, react_1.forwardRef)(function DatagridComponent(props, ref)
342
347
  return (react_1.default.createElement(DatagridViewComponent_1.default, { ref: datagridViewRef, width: size.width - 1, height: size.height - 1, pageSize: 100, schema: schema, dataSource: dataSource, datagridDataSource: datagridDataSource, design: cleanedDesign, filters: activeFilters, onDesignChange: onDesignChange, onRowClick: onRowClick, onRowDoubleClick: onRowDoubleClick, selectedRows: dataEditingEnabled && props.onRowsDelete != null ? selectedRows : undefined, onSelectedRowsChange: dataEditingEnabled && props.onRowsDelete != null ? setSelectedRows : undefined, canEditExpr: dataEditingEnabled ? canEditExpr : undefined, updateExprValues: dataEditingEnabled ? updateExprValues : undefined, refreshKey: refreshKey }));
343
348
  }
344
349
  else if (onDesignChange) {
345
- return (react_1.default.createElement("div", { style: { textAlign: "center", marginTop: size.height / 2 } },
346
- react_1.default.createElement("a", { className: "btn btn-link", onClick: handleEdit }, T `Click Here to Configure`)));
350
+ return (react_1.default.createElement("div", { style: {
351
+ display: "flex",
352
+ flexDirection: "column",
353
+ alignItems: "center",
354
+ justifyContent: "center",
355
+ height: "100%",
356
+ padding: "40px"
357
+ } },
358
+ react_1.default.createElement("div", { style: {
359
+ textAlign: "center",
360
+ marginBottom: "24px"
361
+ } },
362
+ react_1.default.createElement("i", { className: "fas fa-table text-muted", style: {
363
+ fontSize: "48px",
364
+ marginBottom: "16px"
365
+ } }),
366
+ react_1.default.createElement("div", { style: {
367
+ fontSize: "14px"
368
+ }, className: "text-muted" }, T `Configure a data source and columns to get started.`)),
369
+ react_1.default.createElement("button", { className: "btn btn-primary", onClick: handleEdit },
370
+ react_1.default.createElement("i", { className: "fas fa-cog", style: { marginRight: "8px" } }),
371
+ T `Configure`)));
347
372
  }
348
373
  else {
349
374
  return null;
@@ -1,6 +1,5 @@
1
1
  import React from "react";
2
2
  import { DataSource, Schema } from "@mwater/expressions";
3
- import TabbedComponent from "@mwater/react-library/lib/TabbedComponent";
4
3
  import { DatagridDesign } from "..";
5
4
  export interface DatagridDesignerComponentProps {
6
5
  /** schema to use */
@@ -18,6 +17,6 @@ export default class DatagridDesignerComponent extends React.Component<DatagridD
18
17
  handleFilterChange: (filter: any) => void;
19
18
  handleGlobalFiltersChange: (globalFilters: any) => void;
20
19
  handleOrderBysChange: (orderBys: any) => void;
21
- renderTabs(): React.CElement<any, TabbedComponent>;
22
- render(): React.DetailedReactHTMLElement<React.HTMLAttributes<HTMLElement>, HTMLElement>;
20
+ renderTabs(): React.JSX.Element;
21
+ render(): React.JSX.Element;
23
22
  }