@mwater/visualization 5.2.0 → 5.3.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 (254) hide show
  1. package/lib/ColorComponent.d.ts +10 -11
  2. package/lib/ColorComponent.js +78 -29
  3. package/lib/ColorSchemeFactory.d.ts +13 -2
  4. package/lib/ColorSchemeFactory.js +7 -5
  5. package/lib/CustomColorsContext.d.ts +6 -0
  6. package/lib/CustomColorsContext.js +6 -0
  7. package/lib/FiltersDesignerComponent.d.ts +1 -4
  8. package/lib/FiltersDesignerComponent.js +2 -3
  9. package/lib/LocaleContextInjector.d.ts +5 -11
  10. package/lib/LocaleContextInjector.js +4 -12
  11. package/lib/MWaterAddRelatedFormComponent.js +3 -3
  12. package/lib/MWaterAddRelatedIndicatorComponent.d.ts +1 -4
  13. package/lib/MWaterAddRelatedIndicatorComponent.js +6 -6
  14. package/lib/MWaterCompleteTableSelectComponent.d.ts +5 -16
  15. package/lib/MWaterCompleteTableSelectComponent.js +36 -36
  16. package/lib/MWaterContextComponent.d.ts +4 -6
  17. package/lib/MWaterContextComponent.js +4 -13
  18. package/lib/MWaterLoaderComponent.d.ts +5 -3
  19. package/lib/MWaterLoaderComponent.js +2 -1
  20. package/lib/MWaterTableSelectComponent.d.ts +1 -4
  21. package/lib/MWaterTableSelectComponent.js +10 -12
  22. package/lib/UIComponents.d.ts +2 -2
  23. package/lib/UIComponents.js +4 -12
  24. package/lib/axes/AxisBuilder.d.ts +7 -4
  25. package/lib/axes/AxisBuilder.js +3 -1
  26. package/lib/axes/AxisComponent.d.ts +2 -5
  27. package/lib/axes/AxisComponent.js +1 -2
  28. package/lib/axes/ColorPaletteCollectionComponent.d.ts +5 -12
  29. package/lib/axes/ColorPaletteCollectionComponent.js +67 -36
  30. package/lib/dashboards/DashboardComponent.d.ts +4 -12
  31. package/lib/dashboards/DashboardComponent.js +18 -38
  32. package/lib/dashboards/DashboardDesign.d.ts +3 -3
  33. package/lib/dashboards/DashboardUpgrader.js +36 -1
  34. package/lib/dashboards/DashboardViewComponent.d.ts +5 -34
  35. package/lib/dashboards/DashboardViewComponent.js +109 -132
  36. package/lib/dashboards/FontStyleEditor.d.ts +8 -0
  37. package/lib/dashboards/FontStyleEditor.js +130 -0
  38. package/lib/dashboards/LayoutOptionsComponent.d.ts +0 -1
  39. package/lib/dashboards/LayoutOptionsComponent.js +211 -42
  40. package/lib/dashboards/ServerDashboardDataSource.d.ts +1 -2
  41. package/lib/dashboards/ServerDashboardDataSource.js +52 -33
  42. package/lib/dashboards/WidgetComponent.d.ts +3 -3
  43. package/lib/dashboards/WidgetComponent.js +3 -6
  44. package/lib/dashboards/WidgetDataSourcePrioritizer.d.ts +20 -0
  45. package/lib/dashboards/WidgetDataSourcePrioritizer.js +72 -0
  46. package/lib/dashboards/layoutOptions.d.ts +83 -0
  47. package/lib/dashboards/layoutOptions.js +436 -10
  48. package/lib/datagrids/DatagridDesign.d.ts +7 -6
  49. package/lib/datagrids/ServerDatagridDataSource.d.ts +7 -6
  50. package/lib/datagrids/ServerDatagridDataSource.js +87 -33
  51. package/lib/demo.js +3 -3
  52. package/lib/index.css +5 -0
  53. package/lib/index.d.ts +1 -1
  54. package/lib/index.js +0 -1
  55. package/lib/layouts/LayoutManager.d.ts +33 -29
  56. package/lib/layouts/LayoutManager.js +2 -8
  57. package/lib/layouts/blocks/BlocksDisplayComponent.d.ts +26 -57
  58. package/lib/layouts/blocks/BlocksDisplayComponent.js +122 -205
  59. package/lib/layouts/blocks/BlocksLayoutManager.d.ts +6 -22
  60. package/lib/layouts/blocks/BlocksLayoutManager.js +5 -14
  61. package/lib/layouts/blocks/HorizontalBlockComponent.d.ts +5 -4
  62. package/lib/layouts/blocks/HorizontalBlockComponent.js +5 -5
  63. package/lib/mWaterLoader.d.ts +2 -0
  64. package/lib/mWaterLoader.js +2 -1
  65. package/lib/maps/AddLayerComponent.d.ts +6 -8
  66. package/lib/maps/AddLayerComponent.js +6 -6
  67. package/lib/maps/BingLayer.js +10 -20
  68. package/lib/maps/BufferLayer.js +2 -1
  69. package/lib/maps/ChoroplethLayer.js +2 -1
  70. package/lib/maps/DirectMapDataSource.d.ts +5 -2
  71. package/lib/maps/DirectMapDataSource.js +2 -1
  72. package/lib/maps/EditPopupComponent.js +2 -1
  73. package/lib/maps/MapComponent.d.ts +1 -4
  74. package/lib/maps/MapComponent.js +3 -3
  75. package/lib/maps/MarkersLayer.js +30 -25
  76. package/lib/maps/RasterMapViewComponent.d.ts +1 -4
  77. package/lib/maps/RasterMapViewComponent.js +3 -3
  78. package/lib/maps/ServerMapDataSource.d.ts +2 -3
  79. package/lib/maps/ServerMapDataSource.js +5 -5
  80. package/lib/maps/VectorMapViewComponent.js +2 -1
  81. package/lib/maps/mapSymbols.js +2 -0
  82. package/lib/maps/symbols/font-awesome/cloud-rain.png +0 -0
  83. package/lib/maps/vectorMaps.js +61 -55
  84. package/lib/quickfilter/QuickfiltersComponent.d.ts +1 -4
  85. package/lib/quickfilter/QuickfiltersComponent.js +3 -3
  86. package/lib/richtext/DropdownPaletteItem.d.ts +32 -0
  87. package/lib/richtext/DropdownPaletteItem.js +82 -0
  88. package/lib/richtext/FontColorPaletteItem.d.ts +1 -5
  89. package/lib/richtext/FontColorPaletteItem.js +32 -27
  90. package/lib/richtext/ItemsHtmlConverter.js +12 -3
  91. package/lib/richtext/RichTextComponent.d.ts +26 -52
  92. package/lib/richtext/RichTextComponent.js +166 -128
  93. package/lib/valueFormatter.js +6 -1
  94. package/lib/wellknown.d.ts +5 -0
  95. package/lib/wellknown.js +288 -0
  96. package/lib/widgets/DropdownWidgetComponent.d.ts +8 -25
  97. package/lib/widgets/DropdownWidgetComponent.js +48 -25
  98. package/lib/widgets/IFrameWidgetComponent.d.ts +1 -2
  99. package/lib/widgets/ImageWidgetComponent.d.ts +2 -3
  100. package/lib/widgets/MapWidget.d.ts +2 -0
  101. package/lib/widgets/MapWidget.js +2 -1
  102. package/lib/widgets/TOCWidget.js +2 -1
  103. package/lib/widgets/Widget.d.ts +2 -0
  104. package/lib/widgets/WidgetDataSource.d.ts +3 -1
  105. package/lib/widgets/charts/Chart.d.ts +0 -1
  106. package/lib/widgets/charts/ChartViewComponent.d.ts +4 -0
  107. package/lib/widgets/charts/ChartViewComponent.js +11 -3
  108. package/lib/widgets/charts/ChartWidget.d.ts +1 -62
  109. package/lib/widgets/charts/ChartWidget.js +4 -183
  110. package/lib/widgets/charts/ChartWidgetComponent.d.ts +51 -0
  111. package/lib/widgets/charts/ChartWidgetComponent.js +167 -0
  112. package/lib/widgets/charts/calendar/CalendarChartViewComponent.d.ts +1 -4
  113. package/lib/widgets/charts/calendar/CalendarChartViewComponent.js +4 -4
  114. package/lib/widgets/charts/layered/LayeredChart.d.ts +5 -10
  115. package/lib/widgets/charts/layered/LayeredChart.js +6 -7
  116. package/lib/widgets/charts/layered/LayeredChartCompiler.d.ts +4 -2
  117. package/lib/widgets/charts/layered/LayeredChartCompiler.js +46 -32
  118. package/lib/widgets/charts/layered/LayeredChartDesign.d.ts +4 -0
  119. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.d.ts +3 -0
  120. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.js +21 -3
  121. package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.d.ts +1 -2
  122. package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.js +2 -1
  123. package/lib/widgets/charts/layered/LayeredChartViewComponent.d.ts +1 -4
  124. package/lib/widgets/charts/layered/LayeredChartViewComponent.js +89 -38
  125. package/lib/widgets/charts/pivot/IntersectionDesignerComponent.d.ts +5 -112
  126. package/lib/widgets/charts/pivot/IntersectionDesignerComponent.js +122 -166
  127. package/lib/widgets/charts/pivot/PivotChart.d.ts +6 -0
  128. package/lib/widgets/charts/pivot/PivotChart.js +47 -17
  129. package/lib/widgets/charts/pivot/PivotChartDesign.d.ts +11 -0
  130. package/lib/widgets/charts/pivot/PivotChartDesignerComponent.d.ts +1 -1
  131. package/lib/widgets/charts/pivot/PivotChartDesignerComponent.js +1 -1
  132. package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.d.ts +2 -2
  133. package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.js +20 -36
  134. package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +0 -1
  135. package/lib/widgets/charts/pivot/PivotChartQueryBuilder.d.ts +23 -2
  136. package/lib/widgets/charts/pivot/PivotChartQueryBuilder.js +215 -181
  137. package/lib/widgets/charts/pivot/PivotChartUtils.d.ts +2 -2
  138. package/lib/widgets/charts/pivot/PivotChartViewComponent.d.ts +9 -28
  139. package/lib/widgets/charts/pivot/PivotChartViewComponent.js +20 -60
  140. package/lib/widgets/charts/table/TableChart.js +8 -4
  141. package/lib/widgets/charts/table/TableChartDesignerComponent.js +3 -3
  142. package/lib/widgets/charts/table/TableChartViewComponent.js +11 -11
  143. package/lib/widgets/text/TextComponent.d.ts +5 -12
  144. package/lib/widgets/text/TextComponent.js +19 -39
  145. package/lib/widgets/text/TextWidget.d.ts +2 -1
  146. package/lib/widgets/text/TextWidget.js +5 -1
  147. package/lib/widgets/text/TextWidgetComponent.d.ts +15 -3
  148. package/lib/widgets/text/TextWidgetComponent.js +76 -19
  149. package/lib/widgets/text/TextWidgetDesign.d.ts +13 -1
  150. package/lib/widgets/text/TextWidgetDesign.js +6 -0
  151. package/package.json +4 -4
  152. package/src/ColorComponent.tsx +177 -0
  153. package/src/ColorSchemeFactory.ts +12 -6
  154. package/src/CustomColorsContext.tsx +9 -0
  155. package/src/FiltersDesignerComponent.ts +3 -4
  156. package/src/LocaleContextInjector.tsx +14 -13
  157. package/src/MWaterAddRelatedFormComponent.ts +3 -3
  158. package/src/MWaterAddRelatedIndicatorComponent.ts +6 -6
  159. package/src/MWaterCompleteTableSelectComponent.tsx +36 -36
  160. package/src/MWaterContextComponent.tsx +8 -17
  161. package/src/MWaterLoaderComponent.ts +6 -3
  162. package/src/MWaterTableSelectComponent.tsx +11 -12
  163. package/src/{UIComponents.ts → UIComponents.tsx} +7 -15
  164. package/src/axes/AxisBuilder.ts +7 -5
  165. package/src/axes/AxisComponent.ts +3 -4
  166. package/src/axes/{ColorPaletteCollectionComponent.ts → ColorPaletteCollectionComponent.tsx} +87 -61
  167. package/src/dashboards/DashboardComponent.tsx +71 -107
  168. package/src/dashboards/DashboardDesign.ts +3 -3
  169. package/src/dashboards/DashboardUpgrader.ts +41 -1
  170. package/src/dashboards/DashboardViewComponent.tsx +313 -0
  171. package/src/dashboards/FontStyleEditor.tsx +166 -0
  172. package/src/dashboards/LayoutOptionsComponent.tsx +380 -75
  173. package/src/dashboards/ServerDashboardDataSource.ts +52 -33
  174. package/src/dashboards/WidgetComponent.tsx +6 -12
  175. package/src/dashboards/WidgetDataSourcePrioritizer.ts +82 -0
  176. package/src/dashboards/layoutOptions.tsx +581 -0
  177. package/src/datagrids/DatagridDesign.ts +8 -3
  178. package/src/datagrids/ServerDatagridDataSource.ts +106 -43
  179. package/src/demo.ts +3 -3
  180. package/src/index.css +5 -0
  181. package/src/index.ts +1 -1
  182. package/src/layouts/LayoutManager.ts +44 -42
  183. package/src/layouts/blocks/BlocksDisplayComponent.tsx +498 -0
  184. package/src/layouts/blocks/BlocksLayoutManager.ts +6 -15
  185. package/src/layouts/blocks/HorizontalBlockComponent.ts +9 -8
  186. package/src/mWaterLoader.ts +4 -1
  187. package/src/maps/AddLayerComponent.ts +9 -9
  188. package/src/maps/BingLayer.ts +16 -26
  189. package/src/maps/BufferLayer.ts +2 -1
  190. package/src/maps/ChoroplethLayer.ts +2 -1
  191. package/src/maps/DirectMapDataSource.ts +12 -3
  192. package/src/maps/EditPopupComponent.ts +2 -1
  193. package/src/maps/MapComponent.ts +3 -3
  194. package/src/maps/MarkersLayer.ts +38 -41
  195. package/src/maps/RasterMapViewComponent.ts +3 -3
  196. package/src/maps/ServerMapDataSource.ts +7 -7
  197. package/src/maps/VectorMapViewComponent.tsx +2 -1
  198. package/src/maps/mapSymbols.ts +2 -0
  199. package/src/maps/symbols/font-awesome/cloud-rain.png +0 -0
  200. package/src/maps/vectorMaps.tsx +79 -74
  201. package/src/quickfilter/QuickfiltersComponent.ts +3 -3
  202. package/src/richtext/DropdownPaletteItem.tsx +144 -0
  203. package/src/richtext/FontColorPaletteItem.tsx +160 -0
  204. package/src/richtext/ItemsHtmlConverter.ts +15 -5
  205. package/src/richtext/RichTextComponent.tsx +274 -232
  206. package/src/valueFormatter.ts +5 -1
  207. package/src/wellknown.ts +286 -0
  208. package/src/widgets/DropdownWidgetComponent.tsx +75 -0
  209. package/src/widgets/MapWidget.ts +5 -2
  210. package/src/widgets/TOCWidget.ts +2 -1
  211. package/src/widgets/Widget.ts +3 -0
  212. package/src/widgets/WidgetDataSource.ts +3 -1
  213. package/src/widgets/charts/Chart.ts +1 -1
  214. package/src/widgets/charts/ChartViewComponent.ts +16 -3
  215. package/src/widgets/charts/ChartWidget.ts +3 -275
  216. package/src/widgets/charts/ChartWidgetComponent.tsx +281 -0
  217. package/src/widgets/charts/calendar/CalendarChartViewComponent.tsx +4 -4
  218. package/src/widgets/charts/layered/LayeredChart.ts +4 -6
  219. package/src/widgets/charts/layered/LayeredChartCompiler.ts +80 -63
  220. package/src/widgets/charts/layered/LayeredChartDesign.ts +7 -1
  221. package/src/widgets/charts/layered/LayeredChartDesignerComponent.tsx +43 -10
  222. package/src/widgets/charts/layered/LayeredChartLayerDesignerComponent.tsx +6 -6
  223. package/src/widgets/charts/layered/LayeredChartViewComponent.ts +140 -88
  224. package/src/widgets/charts/pivot/IntersectionDesignerComponent.tsx +305 -221
  225. package/src/widgets/charts/pivot/PivotChart.ts +56 -18
  226. package/src/widgets/charts/pivot/PivotChartDesign.ts +12 -0
  227. package/src/widgets/charts/pivot/PivotChartDesignerComponent.tsx +4 -3
  228. package/src/widgets/charts/pivot/PivotChartLayoutBuilder.ts +39 -76
  229. package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +0 -1
  230. package/src/widgets/charts/pivot/PivotChartQueryBuilder.ts +230 -189
  231. package/src/widgets/charts/pivot/PivotChartUtils.ts +4 -4
  232. package/src/widgets/charts/pivot/{PivotChartViewComponent.ts → PivotChartViewComponent.tsx} +86 -89
  233. package/src/widgets/charts/table/TableChart.ts +8 -4
  234. package/src/widgets/charts/table/TableChartDesignerComponent.ts +4 -4
  235. package/src/widgets/charts/table/TableChartViewComponent.ts +13 -14
  236. package/src/widgets/text/TextComponent.tsx +47 -49
  237. package/src/widgets/text/TextWidget.ts +8 -3
  238. package/src/widgets/text/TextWidgetComponent.tsx +249 -0
  239. package/src/widgets/text/TextWidgetDesign.ts +22 -1
  240. package/src/ColorComponent.ts +0 -117
  241. package/src/dashboards/DashboardViewComponent.ts +0 -303
  242. package/src/dashboards/layoutOptions.ts +0 -40
  243. package/src/layout-styles.css +0 -263
  244. package/src/layouts/blocks/BlocksDisplayComponent.ts +0 -461
  245. package/src/layouts/grid/GridLayoutComponent.ts +0 -67
  246. package/src/layouts/grid/GridLayoutManager.ts +0 -185
  247. package/src/layouts/grid/LegoLayoutEngine.ts +0 -142
  248. package/src/layouts/grid/PaletteItemComponent.ts +0 -28
  249. package/src/layouts/grid/README.md +0 -14
  250. package/src/layouts/grid/WidgetContainerComponent.ts +0 -420
  251. package/src/richtext/FontColorPaletteItem.ts +0 -172
  252. package/src/richtext/FontSizePaletteItem.ts +0 -110
  253. package/src/widgets/DropdownWidgetComponent.ts +0 -78
  254. package/src/widgets/text/TextWidgetComponent.ts +0 -120
@@ -1,25 +1,22 @@
1
- import PropTypes from "prop-types"
2
1
  import _ from "lodash"
3
2
  import React, { ReactNode } from "react"
4
3
  const R = React.createElement
5
4
 
6
5
  import { DataSource, ExprCompiler, Schema } from "@mwater/expressions"
7
- import { ExprCleaner } from "@mwater/expressions"
8
6
  import UndoStack from "../UndoStack"
9
7
  import * as DashboardUtils from "./DashboardUtils"
10
- import DashboardViewComponent from "./DashboardViewComponent"
8
+ import DashboardViewComponent, { DashboardViewComponentHandle } from "./DashboardViewComponent"
11
9
  import QuickfiltersComponent from "../quickfilter/QuickfiltersComponent"
12
10
  import QuickfilterCompiler from "../quickfilter/QuickfilterCompiler"
13
11
  import SettingsModalComponent from "./SettingsModalComponent"
14
12
  import LayoutManager from "../layouts/LayoutManager"
15
- import DashboardUpgrader from "./DashboardUpgrader"
16
13
  import { LayoutOptionsComponent } from "./LayoutOptionsComponent"
17
14
  import ModalWindowComponent from "@mwater/react-library/lib/ModalWindowComponent"
18
15
  import { getLayoutOptions } from "./layoutOptions"
19
16
  import { DashboardDesign } from "./DashboardDesign"
20
17
  import DashboardDataSource from "./DashboardDataSource"
21
18
  import { JsonQLFilter } from ".."
22
- import { ActiveTablesContext } from "@mwater/expressions-ui"
19
+ import { ActiveTablesContext, LocaleContext } from "@mwater/expressions-ui"
23
20
 
24
21
  export interface DashboardComponentProps {
25
22
  design: DashboardDesign
@@ -75,31 +72,20 @@ export interface DashboardComponentState {
75
72
  * Manages undo stack and quickfilter value
76
73
  */
77
74
  export default class DashboardComponent extends React.Component<DashboardComponentProps, DashboardComponentState> {
78
- dashboardView: DashboardViewComponent | null
75
+ dashboardView: DashboardViewComponentHandle | null
79
76
 
80
77
  static defaultProps = { printScaling: true }
81
78
 
82
- static childContextTypes = {
83
- locale: PropTypes.string,
84
- }
85
-
86
79
  settings: SettingsModalComponent | null
87
80
 
88
- getChildContext() {
89
- return {
90
- // Pass locale down. Both here and DashboardViewComponent to ensure that quickfilters also get context
91
- locale: this.props.design.locale,
92
- }
93
- }
94
-
95
- constructor(props: any) {
81
+ constructor(props: DashboardComponentProps) {
96
82
  super(props)
97
83
 
98
84
  const layoutOptions = getLayoutOptions(props.design)
99
85
 
100
86
  this.state = {
101
87
  undoStack: new UndoStack().push(props.design),
102
- quickfiltersValues: props.quickfiltersValues,
88
+ quickfiltersValues: props.quickfiltersValues || null,
103
89
  editing:
104
90
  LayoutManager.createLayoutManager(props.design.layout).isEmpty(props.design.items) &&
105
91
  props.onDesignChange != null,
@@ -138,7 +124,7 @@ export default class DashboardComponent extends React.Component<DashboardCompone
138
124
  }
139
125
 
140
126
  handlePrint = () => {
141
- this.dashboardView!.print()
127
+ this.dashboardView?.print()
142
128
  }
143
129
 
144
130
  handleUndo = () => {
@@ -198,21 +184,6 @@ export default class DashboardComponent extends React.Component<DashboardCompone
198
184
  return this.setState({ hideQuickfilters: false })
199
185
  }
200
186
 
201
- handleUpgrade = () => {
202
- if (
203
- !confirm(
204
- "This will upgrade your dashboard to the new kind with enhanced features. You can click Undo immediately afterwards if you wish to revert it. Continue?"
205
- )
206
- ) {
207
- return
208
- }
209
-
210
- const design = new DashboardUpgrader().upgrade(this.props.design)
211
- this.props.onDesignChange!(design)
212
-
213
- alert("Upgrade completed. Some widgets may need to be resized. Click Undo to revert back to old dashboard style.")
214
- }
215
-
216
187
  // Get filters from props filters combined with dashboard filters
217
188
  getCompiledFilters() {
218
189
  let compiledFilters = DashboardUtils.getCompiledFilters(
@@ -250,37 +221,30 @@ export default class DashboardComponent extends React.Component<DashboardCompone
250
221
  return R(
251
222
  "div",
252
223
  null,
253
- this.state.editing && (this.props.design.layout || "grid") === "grid"
254
- ? R(
255
- "a",
256
- { key: "upgrade", className: "btn btn-info btn-sm", onClick: this.handleUpgrade },
257
- "Upgrade Dashboard..."
258
- )
259
- : undefined,
260
224
  this.state.editing
261
225
  ? [
262
- R(
263
- "a",
264
- {
265
- key: "undo",
266
- className: `btn btn-link btn-sm ${!this.state.undoStack.canUndo() ? "disabled" : ""}`,
267
- onClick: this.handleUndo
268
- },
269
- R("span", { className: "fas fa-caret-left" }),
270
- R("span", { className: "hide-600px" }, " Undo")
271
- ),
272
- " ",
273
- R(
274
- "a",
275
- {
276
- key: "redo",
277
- className: `btn btn-link btn-sm ${!this.state.undoStack.canRedo() ? "disabled" : ""}`,
278
- onClick: this.handleRedo
279
- },
280
- R("span", { className: "fas fa-caret-right" }),
281
- R("span", { className: "hide-600px" }, " Redo")
282
- )
283
- ]
226
+ R(
227
+ "a",
228
+ {
229
+ key: "undo",
230
+ className: `btn btn-link btn-sm ${!this.state.undoStack.canUndo() ? "disabled" : ""}`,
231
+ onClick: this.handleUndo
232
+ },
233
+ R("span", { className: "fas fa-caret-left" }),
234
+ R("span", { className: "hide-600px" }, " Undo")
235
+ ),
236
+ " ",
237
+ R(
238
+ "a",
239
+ {
240
+ key: "redo",
241
+ className: `btn btn-link btn-sm ${!this.state.undoStack.canRedo() ? "disabled" : ""}`,
242
+ onClick: this.handleRedo
243
+ },
244
+ R("span", { className: "fas fa-caret-right" }),
245
+ R("span", { className: "hide-600px" }, " Redo")
246
+ )
247
+ ]
284
248
  : undefined,
285
249
  R(
286
250
  "a",
@@ -296,11 +260,11 @@ export default class DashboardComponent extends React.Component<DashboardCompone
296
260
  ),
297
261
  this.state.hideQuickfilters && this.props.design.quickfilters && this.props.design.quickfilters.length > 0
298
262
  ? R(
299
- "a",
300
- { key: "showQuickfilters", className: "btn btn-link btn-sm", onClick: this.handleShowQuickfilters },
301
- R("span", { className: "fa fa-filter" }),
302
- R("span", { className: "hide-600px" }, " Show Quickfilters")
303
- )
263
+ "a",
264
+ { key: "showQuickfilters", className: "btn btn-link btn-sm", onClick: this.handleShowQuickfilters },
265
+ R("span", { className: "fa fa-filter" }),
266
+ R("span", { className: "hide-600px" }, " Show Quickfilters")
267
+ )
304
268
  : undefined,
305
269
 
306
270
  // R 'a', key: "export", className: "btn btn-link btn-sm", onClick: @handleSaveDesignFile,
@@ -308,11 +272,11 @@ export default class DashboardComponent extends React.Component<DashboardCompone
308
272
  // " Export"
309
273
  this.state.editing
310
274
  ? R(
311
- "a",
312
- { key: "settings", className: "btn btn-link btn-sm", onClick: this.handleSettings },
313
- R("span", { className: "fas fa-cog" }),
314
- R("span", { className: "hide-600px" }, " Settings")
315
- )
275
+ "a",
276
+ { key: "settings", className: "btn btn-link btn-sm", onClick: this.handleSettings },
277
+ R("span", { className: "fas fa-cog" }),
278
+ R("span", { className: "hide-600px" }, " Settings")
279
+ )
316
280
  : undefined,
317
281
  this.state.editing ? this.renderStyle() : undefined,
318
282
  this.props.extraTitleButtonsElem,
@@ -346,7 +310,7 @@ export default class DashboardComponent extends React.Component<DashboardCompone
346
310
  }
347
311
 
348
312
  refDashboardView = (el: any) => {
349
- return (this.dashboardView = el)
313
+ this.dashboardView = el
350
314
  }
351
315
 
352
316
  render() {
@@ -389,39 +353,39 @@ export default class DashboardComponent extends React.Component<DashboardCompone
389
353
 
390
354
 
391
355
  // Pass active tables down to table select components so they can present a shorter list
392
- return <ActiveTablesContext.Provider
356
+ return <ActiveTablesContext.Provider
393
357
  value={DashboardUtils.getFilterableTables(this.props.design, this.props.schema)}>
394
-
395
- <div style={{
396
- display: "grid",
397
- gridTemplateRows: this.props.hideTitleBar ? "auto 1fr" : "auto auto 1fr",
398
- height: "100%"
399
- }}>
400
- {!this.props.hideTitleBar ? this.renderTitleBar() : undefined}
401
- <div>{!this.state.hideQuickfilters ? this.renderQuickfilter() : undefined}</div>
402
- {dashboardView}
403
- {this.props.onDesignChange != null && (
404
- <SettingsModalComponent
405
- onDesignChange={this.handleDesignChange}
406
- schema={this.props.schema}
407
- dataSource={this.props.dataSource}
408
- ref={(c: SettingsModalComponent | null) => {
409
- this.settings = c
410
- }}
411
- />
412
- )}
413
- {this.state.layoutOptionsOpen && (
414
- <ModalWindowComponent isOpen={true} outerPadding={10} innerPadding={10}>
415
- <LayoutOptionsComponent
416
- design={this.props.design}
417
- onDesignChange={this.props.onDesignChange!}
418
- onClose={() => this.setState({ layoutOptionsOpen: false })}
419
- dashboardView={readonlyDashboardView}
420
- quickfiltersView={this.renderQuickfilter()}
421
- />
422
- </ModalWindowComponent>
423
- )}
424
- </div>
358
+ <LocaleContext.Provider value={this.props.design.locale ?? "en"}>
359
+ <div style={{
360
+ display: "grid",
361
+ gridTemplateRows: this.props.hideTitleBar ? "auto 1fr" : "auto auto 1fr",
362
+ height: "100%"
363
+ }}>
364
+ {!this.props.hideTitleBar ? this.renderTitleBar() : undefined}
365
+ <div>{!this.state.hideQuickfilters ? this.renderQuickfilter() : undefined}</div>
366
+ {dashboardView}
367
+ {this.props.onDesignChange != null && (
368
+ <SettingsModalComponent
369
+ onDesignChange={this.handleDesignChange}
370
+ schema={this.props.schema}
371
+ dataSource={this.props.dataSource}
372
+ ref={(c: SettingsModalComponent | null) => {
373
+ this.settings = c
374
+ }}
375
+ />
376
+ )}
377
+ {this.state.layoutOptionsOpen && (
378
+ <ModalWindowComponent isOpen={true} outerPadding={10} innerPadding={10} onRequestClose={() => this.setState({ layoutOptionsOpen: false })}>
379
+ <LayoutOptionsComponent
380
+ design={this.props.design}
381
+ onDesignChange={this.props.onDesignChange!}
382
+ dashboardView={readonlyDashboardView}
383
+ quickfiltersView={this.renderQuickfilter()}
384
+ />
385
+ </ModalWindowComponent>
386
+ )}
387
+ </div>
388
+ </LocaleContext.Provider>
425
389
  </ActiveTablesContext.Provider>
426
390
  }
427
391
  }
@@ -15,13 +15,13 @@ export interface DashboardDesign {
15
15
  quickfilters?: Quickfilter[]
16
16
 
17
17
  /** layout engine to use (`blocks` is new default) */
18
- layout: "blocks" | "grid"
18
+ layout: "blocks"
19
19
 
20
- /** optional theme to use */
20
+ /** Optional theme to use. Defaults to "default" theme. */
21
21
  style?: DashboardTheme
22
22
 
23
23
  /** Options for layout including responsiveness, scaling, etc */
24
- layoutOptions?: BlocksLayoutOptions
24
+ layoutOptions?: Partial<BlocksLayoutOptions>
25
25
 
26
26
  /** filter expression indexed by table. e.g. { sometable: logical expression, etc. } */
27
27
  filters?: { [tableId: string]: Expr }
@@ -60,7 +60,47 @@ export default class DashboardUpgrader {
60
60
  delete items[li]
61
61
  }
62
62
  } else if (lineItems.length === 1) {
63
- newItems.blocks.push(convertBlock(lineItems[0], items[lineItems[0]]))
63
+ const item = items[lineItems[0]]
64
+ const convertedBlock = convertBlock(lineItems[0], item)
65
+
66
+ // If widget goes all the way across
67
+ if (item.layout.x + item.layout.w == 24) {
68
+ newItems.blocks.push(convertedBlock)
69
+ } else {
70
+ const leftSpacerWidth = item.layout.x
71
+ const rightSpacerWidth = 24 - (item.layout.x + item.layout.w)
72
+ const blocks = []
73
+ const weights = []
74
+
75
+ if (leftSpacerWidth > 0) {
76
+ blocks.push({
77
+ id: uuid(),
78
+ type: "spacer",
79
+ aspectRatio: 3,
80
+ })
81
+ weights.push(leftSpacerWidth)
82
+ }
83
+
84
+ blocks.push(convertedBlock)
85
+ weights.push(item.layout.w)
86
+
87
+ if (rightSpacerWidth > 0) {
88
+ blocks.push({
89
+ id: uuid(),
90
+ type: "spacer",
91
+ aspectRatio: 3,
92
+ })
93
+ weights.push(rightSpacerWidth)
94
+ }
95
+
96
+ newItems.blocks.push({
97
+ id: uuid(),
98
+ type: "horizontal",
99
+ blocks,
100
+ weights,
101
+ })
102
+ }
103
+
64
104
  delete items[lineItems[0]]
65
105
  }
66
106
 
@@ -0,0 +1,313 @@
1
+ import _ from "lodash"
2
+ import React, { CSSProperties, useEffect, useImperativeHandle, useRef, useMemo, useState } from "react"
3
+
4
+ import ImplicitFilterBuilder from "../ImplicitFilterBuilder"
5
+ import * as DashboardUtils from "./DashboardUtils"
6
+ import { DataSource, Schema } from "@mwater/expressions"
7
+ import WidgetFactory from "../widgets/WidgetFactory"
8
+ import WidgetScoper from "../widgets/WidgetScoper"
9
+ import ReactElementPrinter from "@mwater/react-library/lib/ReactElementPrinter"
10
+ import LayoutManager, { RenderWidgetOptions } from "../layouts/LayoutManager"
11
+ import WidgetScopesViewComponent from "../widgets/WidgetScopesViewComponent"
12
+ import { getLayoutOptions } from "./layoutOptions"
13
+ import { WidgetComponent } from "./WidgetComponent"
14
+ import { DashboardDataSource, DashboardDesign, JsonQLFilter } from ".."
15
+ import { setPrintingModeEnabled } from "../maps/vectorMaps"
16
+ import { WidgetDataSourcePrioritizer } from "./WidgetDataSourcePrioritizer"
17
+ import { LocaleContext } from "@mwater/expressions-ui/lib/contexts"
18
+
19
+ export interface DashboardViewComponentProps {
20
+ /** schema to use */
21
+ schema: Schema
22
+
23
+ /** data source to use. Only used when designing, for display uses dashboardDataSource */
24
+ dataSource: DataSource
25
+
26
+ /** dashboard data source */
27
+ dashboardDataSource: DashboardDataSource
28
+
29
+ design: DashboardDesign
30
+
31
+ /** Leave unset for readonly */
32
+ onDesignChange?: (design: DashboardDesign) => void
33
+
34
+ /** Called with (tableId, rowId) when item is clicked */
35
+ onRowClick?: (tableId: string, rowId: any) => void
36
+
37
+ /** Optional lookup of string name to value. Used for {{branding}} and other replacement strings in text widget */
38
+ namedStrings?: { [key: string]: string }
39
+
40
+ /** Filters to add to the dashboard (includes extra filters and any quickfilters from the dashboard component. Does not include dashboard level filters) */
41
+ filters?: JsonQLFilter[]
42
+
43
+ /** Entry to scroll to initially when dashboard is loaded */
44
+ initialTOCEntryScroll?: { widgetId: string; entryId: any }
45
+
46
+ /** True to hide scope display */
47
+ hideScopes?: boolean
48
+
49
+ /** True to render in print mode (prevents odd clipping issue) */
50
+ printMode?: boolean
51
+
52
+ /** Change to force a refresh */
53
+ refreshKey?: any
54
+ }
55
+
56
+ export interface DashboardViewComponentHandle {
57
+ print: () => Promise<void>
58
+ }
59
+
60
+ /**
61
+ * Displays a dashboard, handling removing of widgets. No title bar or other decorations.
62
+ * Handles scoping and stores the state of scope
63
+ */
64
+ const DashboardViewComponent = React.forwardRef<DashboardViewComponentHandle, DashboardViewComponentProps>((props, ref) => {
65
+ const [widgetScoper, setWidgetScoper] = useState(new WidgetScoper())
66
+ const widgetComps = useRef<{ [widgetId: string]: any }>({})
67
+ const [forceUpdate, setForceUpdate] = useState(0)
68
+
69
+ const widgetDataSourcePrioritizer = useMemo(() => {
70
+ return new WidgetDataSourcePrioritizer(props.dashboardDataSource, 10)
71
+ }, [props.dashboardDataSource])
72
+
73
+ useEffect(() => {
74
+ return () => {
75
+ // Clear queue on component unmount
76
+ widgetDataSourcePrioritizer.cancel()
77
+ }
78
+ }, [widgetDataSourcePrioritizer])
79
+
80
+ useEffect(() => {
81
+ if (props.initialTOCEntryScroll) {
82
+ // Getting heights of widgets properly requires a 0 length timeout
83
+ setTimeout(() => {
84
+ handleScrollToTOCEntry(
85
+ props.initialTOCEntryScroll!.widgetId,
86
+ props.initialTOCEntryScroll!.entryId
87
+ )
88
+ }, 0)
89
+ }
90
+
91
+ // Add listener to localstorage to update clipboard display
92
+ window.addEventListener("storage", handleStorageChange)
93
+
94
+ return () => {
95
+ // Remove listener
96
+ window.removeEventListener("storage", handleStorageChange)
97
+ }
98
+ }, [props.initialTOCEntryScroll])
99
+
100
+ const handleStorageChange = () => {
101
+ setForceUpdate(forceUpdate + 1)
102
+ }
103
+
104
+ const handleScopeChange = (id: any, scope: any) => {
105
+ setWidgetScoper(widgetScoper.applyScope(id, scope))
106
+ }
107
+
108
+ const handleRemoveScope = (id: any) => {
109
+ setWidgetScoper(widgetScoper.applyScope(id, null))
110
+ }
111
+
112
+ const handleItemsChange = (items: any) => {
113
+ const design = _.extend({}, props.design, { items }) as DashboardDesign
114
+ props.onDesignChange!(design)
115
+ }
116
+
117
+ const handleClipboardChange = (block: any) => {
118
+ try {
119
+ // If empty, just set it
120
+ if (!block) {
121
+ window.localStorage.removeItem("DashboardViewComponent.clipboard")
122
+ setForceUpdate(forceUpdate + 1)
123
+ return
124
+ }
125
+
126
+ // Determine which tables are used (just peek for any uses of the table name. Not ideal, but easy)
127
+ const tables = _.pluck(
128
+ _.filter(props.schema.getTables(), (table) => JSON.stringify(block).includes(JSON.stringify(table.id))),
129
+ "id"
130
+ )
131
+
132
+ // Store in clipboard
133
+ window.localStorage.setItem("DashboardViewComponent.clipboard", JSON.stringify({ block, tables }))
134
+ setForceUpdate(forceUpdate + 1)
135
+ } catch (err) {
136
+ return alert("Clipboard not available")
137
+ }
138
+ }
139
+
140
+ const getClipboardContents = () => {
141
+ try {
142
+ return JSON.parse(window.localStorage.getItem("DashboardViewComponent.clipboard") || "null")
143
+ } catch (err) {
144
+ return null
145
+ }
146
+ }
147
+
148
+ const print = async () => {
149
+ // Temporarily enable print mode for vector maps
150
+ try {
151
+ setPrintingModeEnabled(true)
152
+
153
+ // Create element at 1080 wide (use as standard printing width)
154
+ const elem = (
155
+ <div style={{ width: 1080 }}>
156
+ <DashboardViewComponent {...props} onDesignChange={undefined} printMode={true} />
157
+ </div>
158
+ )
159
+
160
+ const printer = new ReactElementPrinter()
161
+ await printer.print(elem, { delay: 5000 })
162
+ } finally {
163
+ setPrintingModeEnabled(false)
164
+ }
165
+ }
166
+
167
+ useImperativeHandle(ref, () => ({
168
+ print
169
+ }))
170
+
171
+ const getCompiledFilters = () => {
172
+ let compiledFilters = DashboardUtils.getCompiledFilters(
173
+ props.design,
174
+ props.schema,
175
+ DashboardUtils.getFilterableTables(props.design, props.schema)
176
+ )
177
+ compiledFilters = compiledFilters.concat(props.filters || [])
178
+ return compiledFilters
179
+ }
180
+
181
+ const getTOCEntries = (layoutManager: any) => {
182
+ const entries = []
183
+
184
+ for (let { id, type, design } of layoutManager.getAllWidgets(props.design.items)) {
185
+ const widget = WidgetFactory.createWidget(type)
186
+ // Add widgetId to each one
187
+ for (let entry of widget.getTOCEntries(design, props.namedStrings)) {
188
+ entries.push(_.extend({}, entry, { widgetId: id }))
189
+ }
190
+ }
191
+
192
+ return entries
193
+ }
194
+
195
+ const handleScrollToTOCEntry = (widgetId: any, entryId: any) => {
196
+ const widgetComp = widgetComps.current[widgetId]
197
+ if (!widgetComp) {
198
+ return
199
+ }
200
+
201
+ // Call scrollToTOCEntry if present
202
+ return widgetComp.scrollToTOCEntry?.(entryId)
203
+ }
204
+
205
+ const renderScopes = () => {
206
+ return (
207
+ <WidgetScopesViewComponent
208
+ scopes={widgetScoper.getScopes()}
209
+ onRemoveScope={handleRemoveScope}
210
+ />
211
+ )
212
+ }
213
+
214
+ const compRef = (widgetId: any, comp: any) => {
215
+ return (widgetComps.current[widgetId] = comp)
216
+ }
217
+
218
+ let cantPasteMessage = ""
219
+ const layoutManager = LayoutManager.createLayoutManager(props.design.layout)
220
+
221
+ const compiledFilters = getCompiledFilters()
222
+
223
+ // Get filterable tables
224
+ const filterableTables = DashboardUtils.getFilterableTables(props.design, props.schema)
225
+
226
+ // Determine toc entries
227
+ const tocEntries = getTOCEntries(layoutManager)
228
+
229
+ // Get clipboard contents
230
+ const clipboardContents = getClipboardContents()
231
+
232
+ // Check if can't paste because of missing table
233
+ if (clipboardContents && !_.all(clipboardContents.tables, (table: string) => props.schema.getTable(table))) {
234
+ cantPasteMessage = "Dashboard is missing one or more data sources needed for the copied item."
235
+ }
236
+
237
+ const renderWidget = (options: RenderWidgetOptions) => {
238
+ const widgetDataSource = widgetDataSourcePrioritizer.getWidgetDataSource(
239
+ options.type,
240
+ options.id,
241
+ options.priority ?? 0
242
+ )
243
+
244
+ // Get filters (passed in plus dashboard widget scoper filters)
245
+ let filters = compiledFilters.concat(widgetScoper.getFilters(options.id))
246
+
247
+ // Extend the filters to include implicit filters (filter children in 1-n relationships)
248
+ if (props.design.implicitFiltersEnabled || props.design.implicitFiltersEnabled == null) {
249
+ // Default is true
250
+ const implicitFilterBuilder = new ImplicitFilterBuilder(props.schema)
251
+ filters = implicitFilterBuilder.extendFilters(filterableTables, filters)
252
+ }
253
+
254
+ const widgetElem = (
255
+ <WidgetComponent
256
+ key={options.id}
257
+ id={options.id}
258
+ type={options.type}
259
+ schema={props.schema}
260
+ dataSource={props.dataSource}
261
+ widgetDataSource={widgetDataSource}
262
+ design={options.design}
263
+ scope={widgetScoper.getScope(options.id)}
264
+ filters={filters}
265
+ onScopeChange={handleScopeChange.bind(null, options.id)}
266
+ onDesignChange={options.onDesignChange}
267
+ width={options.width}
268
+ height={options.height}
269
+ onRowClick={props.onRowClick}
270
+ namedStrings={props.namedStrings}
271
+ tocEntries={tocEntries}
272
+ onScrollToTOCEntry={handleScrollToTOCEntry}
273
+ // Keep references to widget elements
274
+ widgetRef={compRef.bind(null, options.id)}
275
+ refreshKey={props.refreshKey}
276
+ />
277
+ )
278
+
279
+ return widgetElem
280
+ }
281
+
282
+ const style: CSSProperties = {
283
+ height: "100%",
284
+ position: "relative"
285
+ }
286
+
287
+ if (!props.printMode) {
288
+ // Prevent this block from taking up too much space. Scrolling handled by layout manager.
289
+ // Setting overflow-x stops the inner div from becoming too tall
290
+ style.overflowX = "auto"
291
+ }
292
+
293
+ // Render widget container
294
+ return (
295
+ <LocaleContext.Provider value={props.design.locale ?? "en"}>
296
+ <div style={style}>
297
+ {!props.hideScopes ? renderScopes() : undefined}
298
+
299
+ {layoutManager.renderLayout({
300
+ items: props.design.items,
301
+ onItemsChange: props.onDesignChange != null ? handleItemsChange : undefined,
302
+ layoutOptions: getLayoutOptions(props.design),
303
+ renderWidget,
304
+ clipboard: clipboardContents?.block,
305
+ onClipboardChange: handleClipboardChange,
306
+ cantPasteMessage
307
+ })}
308
+ </div>
309
+ </LocaleContext.Provider>
310
+ )
311
+ })
312
+
313
+ export default DashboardViewComponent