@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
@@ -0,0 +1,249 @@
1
+ import React from "react"
2
+ import _ from "lodash"
3
+ import TextComponent from "./TextComponent"
4
+ import TextWidget from "./TextWidget"
5
+ import AsyncLoadComponent from "@mwater/react-library/lib/AsyncLoadComponent"
6
+ import { DataSource, Schema } from "@mwater/expressions"
7
+ import { JsonQLFilter } from "../../JsonQLFilter"
8
+ import { TextWidgetDesign } from "./TextWidgetDesign"
9
+ import { HtmlItem } from "../../richtext/ItemsHtmlConverter"
10
+ import { HtmlItemExpr } from "../../richtext/ExprItemsHtmlConverter"
11
+ import DropdownWidgetComponent from "../DropdownWidgetComponent"
12
+ import ActionCancelModalComponent from "@mwater/react-library/lib/ActionCancelModalComponent"
13
+ import { FormGroup } from "@mwater/react-library/lib/bootstrap"
14
+ import ColorComponent from "../../ColorComponent"
15
+ import { Select } from "@mwater/react-library/lib/bootstrap"
16
+
17
+ export interface TextWidgetComponentProps {
18
+ design: TextWidgetDesign
19
+ /** Called with new design. null/undefined for readonly */
20
+ onDesignChange?: (design: TextWidgetDesign) => void
21
+ filters: JsonQLFilter[]
22
+ schema: Schema
23
+ /** Data source to use for chart */
24
+ dataSource: DataSource
25
+ widgetDataSource: any
26
+ width?: number
27
+ height?: number
28
+ /** Table that is filtered to have one row */
29
+ singleRowTable?: string
30
+ namedStrings?: any
31
+ /** A key that changes when the widget should be refreshed */
32
+ refreshKey?: any
33
+ }
34
+
35
+ // Widget which displays styled text with embedded expressions
36
+ export default class TextWidgetComponent extends AsyncLoadComponent<TextWidgetComponentProps, { loading: boolean, exprValues: any, error: any, cacheExpiry: any, editModalOpen: boolean }> {
37
+ divComp: HTMLElement | null
38
+ constructor(props: TextWidgetComponentProps) {
39
+ super(props)
40
+
41
+ this.state = {
42
+ loading: false,
43
+ // Map of expression id to expression value
44
+ exprValues: {},
45
+ error: null,
46
+ cacheExpiry: props.dataSource.getCacheExpiry(), // Save cache expiry to see if changes
47
+ editModalOpen: false
48
+ }
49
+ }
50
+
51
+ // Override to determine if a load is needed. Not called on mounting
52
+ isLoadNeeded(newProps: any, oldProps: any) {
53
+ // Get expression items recursively
54
+ function getExprItems(items: HtmlItem[]): HtmlItemExpr[] {
55
+ let exprItems: HtmlItemExpr[] = []
56
+ for (let item of items || []) {
57
+ if (typeof item === "object") {
58
+ if (item.type === "expr") {
59
+ exprItems.push(item as HtmlItemExpr)
60
+ }
61
+ if (item.items) {
62
+ exprItems = exprItems.concat(getExprItems(item.items))
63
+ }
64
+ }
65
+ }
66
+ return exprItems
67
+ }
68
+
69
+ // Reload if filters or expressions have changed or cache expiry
70
+ return (
71
+ !_.isEqual(newProps.filters, oldProps.filters) ||
72
+ !_.isEqual(getExprItems(newProps.design.items), getExprItems(oldProps.design.items)) ||
73
+ newProps.dataSource.getCacheExpiry() !== this.state.cacheExpiry ||
74
+ newProps.refreshKey !== oldProps.refreshKey
75
+ )
76
+ }
77
+
78
+ // Call callback with state changes
79
+ load(props: TextWidgetComponentProps, prevProps: TextWidgetComponentProps, callback: any) {
80
+ // Shortcut if no expressions in text widget
81
+ const widget = new TextWidget()
82
+ if (widget.getExprItems(props.design.items).length === 0) {
83
+ callback({ error: null, exprValues: {} }, props.dataSource.getCacheExpiry())
84
+ return
85
+ }
86
+
87
+ // Get data
88
+ props.widgetDataSource.getData(props.design, props.filters, (error: any, data: any) => {
89
+ callback({ error, exprValues: data || {}, cacheExpiry: props.dataSource.getCacheExpiry() })
90
+ })
91
+ }
92
+
93
+ scrollToTOCEntry(entryId: any) {
94
+ // Find entry in divComp
95
+ const entries = this.divComp!.querySelectorAll("h1,h2,h3,h4,h5,h6,h7,h8,h9")
96
+
97
+ const entry = entries[entryId]
98
+ if (entry) {
99
+ return entry.scrollIntoView(true)
100
+ }
101
+ }
102
+
103
+ handleEditClick = () => {
104
+ this.setState({ editModalOpen: true })
105
+ }
106
+
107
+ handleEditModalClose = () => {
108
+ this.setState({ editModalOpen: false })
109
+ }
110
+
111
+ handleBackgroundColorChange = (color: string | null) => {
112
+ const newDesign = { ...this.props.design, backgroundColor: color }
113
+ this.props.onDesignChange!(newDesign)
114
+ }
115
+
116
+ handleSpacingChange = (spacing: number | null) => {
117
+ const newDesign = { ...this.props.design, padding: spacing ?? undefined }
118
+ this.props.onDesignChange!(newDesign)
119
+ }
120
+
121
+ handleBorderColorChange = (color: string | null) => {
122
+ const newDesign = { ...this.props.design, borderColor: color }
123
+ this.props.onDesignChange!(newDesign)
124
+ }
125
+
126
+ handleBorderThicknessChange = (thickness: number | null) => {
127
+ const newDesign = { ...this.props.design, borderThickness: thickness }
128
+ this.props.onDesignChange!(newDesign)
129
+ }
130
+
131
+ handleBorderRadiusChange = (radius: number | null) => {
132
+ const newDesign = { ...this.props.design, borderRadius: radius }
133
+ this.props.onDesignChange!(newDesign)
134
+ }
135
+
136
+ renderEditModal() {
137
+ if (!this.state.editModalOpen) {
138
+ return null
139
+ }
140
+
141
+ const spacingOptions = [0, 5, 10, 15, 20, 25, 30, 35, 40].map(value => ({ value, label: `${value}px` }))
142
+ const borderThicknessOptions = [0, 1, 2, 3, 4, 5].map(value => ({ value, label: value === 0 ? "None" : `${value}px` }))
143
+
144
+ return (
145
+ <ActionCancelModalComponent
146
+ title="Edit Text Widget"
147
+ onCancel={this.handleEditModalClose}
148
+ onAction={this.handleEditModalClose}
149
+ >
150
+ <FormGroup label="Background Color">
151
+ <ColorComponent
152
+ color={this.props.design.backgroundColor || null}
153
+ onChange={this.handleBackgroundColorChange}
154
+ />
155
+ <div className="text-muted">
156
+ Choose a background color for the text widget
157
+ </div>
158
+ </FormGroup>
159
+ <FormGroup label="Padding">
160
+ <Select
161
+ value={this.props.design.padding ?? 0}
162
+ onChange={this.handleSpacingChange}
163
+ options={spacingOptions}
164
+ />
165
+ <div className="text-muted">
166
+ Choose extra padding for the text widget
167
+ </div>
168
+ </FormGroup>
169
+ <FormGroup label="Border Thickness" help="Choose the border thickness for the text widget">
170
+ <Select
171
+ value={this.props.design.borderThickness ?? 0}
172
+ onChange={this.handleBorderThicknessChange}
173
+ options={borderThicknessOptions}
174
+ />
175
+ </FormGroup>
176
+ {this.props.design.borderThickness &&
177
+ <FormGroup label="Border Color" help="Choose the border color for the text widget">
178
+ <ColorComponent
179
+ color={this.props.design.borderColor || null}
180
+ onChange={this.handleBorderColorChange}
181
+ />
182
+ </FormGroup>
183
+ }
184
+ {this.props.design.borderThickness &&
185
+ <FormGroup label="Border Radius" help="Choose the border radius for the text widget">
186
+ <Select
187
+ value={this.props.design.borderRadius ?? 0}
188
+ onChange={this.handleBorderRadiusChange}
189
+ options={spacingOptions}
190
+ />
191
+ </FormGroup>
192
+ }
193
+ </ActionCancelModalComponent>
194
+ )
195
+ }
196
+
197
+ renderTextComponent() {
198
+ // If loading, don't display old values
199
+ const exprValues = !this.state.loading ? this.state.exprValues : {}
200
+
201
+ const padding = this.props.design.padding ?? 0
202
+
203
+ return (
204
+ <TextComponent
205
+ design={this.props.design}
206
+ onDesignChange={this.props.onDesignChange}
207
+ schema={this.props.schema}
208
+ dataSource={this.props.dataSource}
209
+ exprValues={exprValues}
210
+ width={this.props.width ? this.props.width - padding * 2 : undefined}
211
+ height={this.props.height ? this.props.height - padding * 2 : undefined}
212
+ singleRowTable={this.props.singleRowTable}
213
+ namedStrings={this.props.namedStrings}
214
+ />
215
+ )
216
+ }
217
+
218
+ render() {
219
+ const borderStyle = this.props.design.borderThickness && this.props.design.borderColor
220
+ ? `${this.props.design.borderThickness}px solid ${this.props.design.borderColor}`
221
+ : undefined
222
+
223
+ return (
224
+ <div
225
+ style={{
226
+ backgroundColor: this.props.design.backgroundColor ?? undefined,
227
+ padding: this.props.design.padding != null ? `${this.props.design.padding}px` : undefined,
228
+ border: borderStyle,
229
+ borderRadius: this.props.design.borderRadius != null ? `${this.props.design.borderRadius}px` : undefined
230
+ }}
231
+ ref={comp => this.divComp = comp}
232
+ >
233
+ {this.props.onDesignChange ? (
234
+ <DropdownWidgetComponent
235
+ dropdownItems={[{
236
+ label: "Edit",
237
+ onClick: this.handleEditClick
238
+ }]}
239
+ >
240
+ {this.renderTextComponent()}
241
+ </DropdownWidgetComponent>
242
+ ) : (
243
+ this.renderTextComponent()
244
+ )}
245
+ {this.renderEditModal()}
246
+ </div>
247
+ )
248
+ }
249
+ }
@@ -6,5 +6,26 @@ export interface TextWidgetDesign {
6
6
  items: (HtmlItem | HtmlItemExpr)[]
7
7
 
8
8
  /** "title" for title block. default is "default" */
9
- style?: "title" | "default"
9
+ style?: "title" | "default" | "header" | "footer"
10
+
11
+ /** Background color of the text widget (optional) */
12
+ backgroundColor?: string | null
13
+
14
+ /** Extra padding for the text widget */
15
+ padding?: number
16
+
17
+ /** Border color of the text widget (optional) */
18
+ borderColor?: string | null
19
+
20
+ /** Border thickness of the text widget (optional) */
21
+ borderThickness?: number | null
22
+
23
+ /** Border radius of the text widget (optional) */
24
+ borderRadius?: number | null
10
25
  }
26
+
27
+
28
+ /** Returns true if the text widget design is empty. */
29
+ export function isEmptyTextWidgetDesign(design: TextWidgetDesign | undefined): boolean {
30
+ return design == null || design.items.length === 0
31
+ }
@@ -1,117 +0,0 @@
1
- import PropTypes from "prop-types"
2
- import React, { CSSProperties } from "react"
3
- const R = React.createElement
4
-
5
- import ClickOutHandler from "react-onclickout"
6
- import { SketchPicker } from "react-color"
7
- import { SwatchesPicker } from "react-color"
8
-
9
- interface ColorComponentProps {
10
- color: string | null | undefined
11
- onChange: (value: string | null) => void
12
- }
13
-
14
- interface ColorComponentState {
15
- open: any
16
- advanced: any
17
- }
18
-
19
- // Simple color well with popup
20
- export default class ColorComponent extends React.Component<ColorComponentProps, ColorComponentState> {
21
- constructor(props: any) {
22
- super(props)
23
- this.state = { open: false, advanced: false }
24
- }
25
-
26
- handleClick = () => {
27
- return this.setState({ open: !this.state.open, advanced: false })
28
- }
29
-
30
- handleClose = (color: any) => {
31
- return this.props.onChange(color.hex)
32
- }
33
-
34
- handleReset = () => {
35
- this.setState({ open: false })
36
- return this.props.onChange(null)
37
- }
38
-
39
- handleTransparent = () => {
40
- this.setState({ open: false })
41
- return this.props.onChange("transparent")
42
- }
43
-
44
- handleAdvanced = () => {
45
- return this.setState({ advanced: !this.state.advanced })
46
- }
47
-
48
- render() {
49
- const style: CSSProperties = {
50
- height: 20,
51
- width: 20,
52
- border: "solid 2px #888",
53
- borderRadius: 4,
54
- backgroundColor: this.props.color || undefined,
55
- cursor: "pointer",
56
- display: "inline-block"
57
- }
58
-
59
- if (!this.props.color) {
60
- // http://lea.verou.me/css3patterns/#diagonal-stripes
61
- style.backgroundColor = "#AAA"
62
- style.backgroundImage =
63
- "repeating-linear-gradient(45deg, transparent, transparent 2px, rgba(255,255,255,.7) 2px, rgba(255,255,255,.7) 4px)"
64
- }
65
-
66
- const popupPosition = {
67
- position: "absolute",
68
- top: 0,
69
- left: 30,
70
- zIndex: 1000,
71
- backgroundColor: "white",
72
- border: "solid 1px #DDD",
73
- borderRadius: 3
74
- }
75
-
76
- return R(
77
- "div",
78
- { style: { position: "relative", display: "inline-block" } },
79
- R("div", { style, onClick: this.handleClick }),
80
- this.state.open
81
- ? React.createElement(
82
- ClickOutHandler,
83
- { onClickOut: () => this.setState({ open: false }) },
84
- R(
85
- "div",
86
- { style: popupPosition },
87
- R(
88
- "button",
89
- { type: "button", className: "btn btn-link btn-sm", onClick: this.handleReset },
90
- R("i", { className: "fa fa-undo" }),
91
- " Reset Color"
92
- ),
93
- // R 'button', type: "button", className: "btn btn-link btn-sm", onClick: @handleTransparent,
94
- // R 'i', className: "fa fa-ban"
95
- // " None"
96
- R(
97
- "button",
98
- { type: "button", className: "btn btn-link btn-sm", onClick: this.handleAdvanced },
99
- this.state.advanced ? "Basic" : "Advanced"
100
- ),
101
-
102
- this.state.advanced
103
- ? React.createElement(SketchPicker, {
104
- color: this.props.color || undefined,
105
- disableAlpha: true,
106
- onChangeComplete: this.handleClose
107
- })
108
- : React.createElement(SwatchesPicker, {
109
- color: this.props.color || undefined,
110
- onChangeComplete: this.handleClose
111
- })
112
- )
113
- )
114
- : undefined
115
- )
116
- }
117
- }
@@ -1,303 +0,0 @@
1
- import _ from "lodash"
2
- import PropTypes from "prop-types"
3
- import React, { CSSProperties } from "react"
4
- const R = React.createElement
5
-
6
- import ImplicitFilterBuilder from "../ImplicitFilterBuilder"
7
- import * as DashboardUtils from "./DashboardUtils"
8
- import { DataSource, Schema } from "@mwater/expressions"
9
- import WidgetFactory from "../widgets/WidgetFactory"
10
- import WidgetScoper from "../widgets/WidgetScoper"
11
- import ReactElementPrinter from "@mwater/react-library/lib/ReactElementPrinter"
12
- import LayoutManager from "../layouts/LayoutManager"
13
- import WidgetScopesViewComponent from "../widgets/WidgetScopesViewComponent"
14
- import { getLayoutOptions } from "./layoutOptions"
15
- import { WidgetComponent } from "./WidgetComponent"
16
- import { DashboardDataSource, DashboardDesign, JsonQLFilter } from ".."
17
- import { setPrintingModeEnabled } from "../maps/vectorMaps"
18
-
19
- export interface DashboardViewComponentProps {
20
- /** schema to use */
21
- schema: Schema
22
- /** data source to use. Only used when designing, for display uses dashboardDataSource */
23
- dataSource: DataSource
24
- /** dashboard data source */
25
- dashboardDataSource: DashboardDataSource
26
-
27
- design: DashboardDesign
28
-
29
- /** Leave unset for readonly */
30
- onDesignChange?: (design: DashboardDesign) => void
31
-
32
- /** Called with (tableId, rowId) when item is clicked */
33
- onRowClick?: (tableId: string, rowId: any) => void
34
-
35
- /** Optional lookup of string name to value. Used for {{branding}} and other replacement strings in text widget */
36
- namedStrings?: { [key: string]: string }
37
-
38
- /** Filters to add to the dashboard (includes extra filters and any quickfilters from the dashboard component. Does not include dashboard level filters) */
39
- filters?: JsonQLFilter[]
40
-
41
- /** Entry to scroll to initially when dashboard is loaded */
42
- initialTOCEntryScroll?: { widgetId: string; entryId: any }
43
-
44
- /** True to hide scope display */
45
- hideScopes?: boolean
46
-
47
- /** True to render in print mode (prevents odd clipping issue) */
48
- printMode?: boolean
49
-
50
- /** Change to force a refresh */
51
- refreshKey?: any
52
- }
53
-
54
- /**
55
- * Displays a dashboard, handling removing of widgets. No title bar or other decorations.
56
- * Handles scoping and stores the state of scope
57
- */
58
- export default class DashboardViewComponent extends React.Component<
59
- DashboardViewComponentProps,
60
- { widgetScoper: WidgetScoper }
61
- > {
62
- static childContextTypes = { locale: PropTypes.string }
63
- widgetComps: { [widgetId: string]: any }
64
-
65
- // Pass locale down. Both here and DashboardViewComponent to ensure that quickfilters also get context
66
- getChildContext() {
67
- return { locale: this.props.design.locale }
68
- }
69
-
70
- constructor(props: any) {
71
- super(props)
72
- this.state = {
73
- widgetScoper: new WidgetScoper() // Empty scoping
74
- }
75
-
76
- this.widgetComps = {} // Lookup of widget components by id
77
- }
78
-
79
- componentDidMount() {
80
- if (this.props.initialTOCEntryScroll) {
81
- // Getting heights of widgets properly requires a 0 length timeout
82
- setTimeout(() => {
83
- return this.handleScrollToTOCEntry(
84
- this.props.initialTOCEntryScroll!.widgetId,
85
- this.props.initialTOCEntryScroll!.entryId
86
- )
87
- }, 0)
88
- }
89
-
90
- // Add listener to localstorage to update clipboard display
91
- return window.addEventListener("storage", this.handleStorageChange)
92
- }
93
-
94
- componentWillUnmount() {
95
- // Remove listener
96
- return window.addEventListener("storage", this.handleStorageChange)
97
- }
98
-
99
- handleStorageChange = () => {
100
- return this.forceUpdate()
101
- }
102
-
103
- handleScopeChange = (id: any, scope: any) => {
104
- return this.setState({ widgetScoper: this.state.widgetScoper.applyScope(id, scope) })
105
- }
106
-
107
- handleRemoveScope = (id: any) => {
108
- return this.setState({ widgetScoper: this.state.widgetScoper.applyScope(id, null) })
109
- }
110
-
111
- handleItemsChange = (items: any) => {
112
- const design = _.extend({}, this.props.design, { items }) as DashboardDesign
113
- return this.props.onDesignChange!(design)
114
- }
115
-
116
- // Handle a change of the clipboard and determine which tables the clipboard block uses
117
- handleClipboardChange = (block: any) => {
118
- try {
119
- // If empty, just set it
120
- if (!block) {
121
- window.localStorage.removeItem("DashboardViewComponent.clipboard")
122
- this.forceUpdate()
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(this.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
- return this.forceUpdate()
135
- } catch (err) {
136
- return alert("Clipboard not available")
137
- }
138
- }
139
-
140
- getClipboardContents() {
141
- try {
142
- return JSON.parse(window.localStorage.getItem("DashboardViewComponent.clipboard") || "null")
143
- } catch (err) {
144
- return null
145
- }
146
- }
147
-
148
- // Call to print the dashboard
149
- print = async () => {
150
- // Temporarily enable print mode for vector maps
151
- try {
152
- setPrintingModeEnabled(true)
153
-
154
- // Create element at 1080 wide (use as standard printing width)
155
- const elem = R(
156
- "div",
157
- { style: { width: 1080 } },
158
- R(DashboardViewComponent, _.extend({}, this.props, { onDesignChange: null, printMode: true }))
159
- )
160
-
161
- const printer = new ReactElementPrinter()
162
- await printer.print(elem, { delay: 5000 })
163
- } finally {
164
- setPrintingModeEnabled(false)
165
- }
166
- }
167
-
168
- // Get filters from props filters combined with dashboard filters
169
- getCompiledFilters() {
170
- let compiledFilters = DashboardUtils.getCompiledFilters(
171
- this.props.design,
172
- this.props.schema,
173
- DashboardUtils.getFilterableTables(this.props.design, this.props.schema)
174
- )
175
- compiledFilters = compiledFilters.concat(this.props.filters || [])
176
- return compiledFilters
177
- }
178
-
179
- // Get list of TOC entries
180
- getTOCEntries(layoutManager: any) {
181
- const entries = []
182
-
183
- for (let { id, type, design } of layoutManager.getAllWidgets(this.props.design.items)) {
184
- const widget = WidgetFactory.createWidget(type)
185
- // Add widgetId to each one
186
- for (let entry of widget.getTOCEntries(design, this.props.namedStrings)) {
187
- entries.push(_.extend({}, entry, { widgetId: id }))
188
- }
189
- }
190
-
191
- return entries
192
- }
193
-
194
- handleScrollToTOCEntry = (widgetId: any, entryId: any) => {
195
- const widgetComp = this.widgetComps[widgetId]
196
- if (!widgetComp) {
197
- return
198
- }
199
-
200
- // Call scrollToTOCEntry if present
201
- return widgetComp.scrollToTOCEntry?.(entryId)
202
- }
203
-
204
- renderScopes() {
205
- return R(WidgetScopesViewComponent, {
206
- scopes: this.state.widgetScoper.getScopes(),
207
- onRemoveScope: this.handleRemoveScope
208
- })
209
- }
210
-
211
- compRef = (widgetId: any, comp: any) => {
212
- return (this.widgetComps[widgetId] = comp)
213
- }
214
-
215
- render() {
216
- let cantPasteMessage = ""
217
- const layoutManager = LayoutManager.createLayoutManager(this.props.design.layout)
218
-
219
- const compiledFilters = this.getCompiledFilters()
220
-
221
- // Get filterable tables
222
- const filterableTables = DashboardUtils.getFilterableTables(this.props.design, this.props.schema)
223
-
224
- // Determine toc entries
225
- const tocEntries = this.getTOCEntries(layoutManager)
226
-
227
- // Get clipboard contents
228
- const clipboardContents = this.getClipboardContents()
229
-
230
- // Check if can't paste because of missing table
231
- if (clipboardContents && !_.all(clipboardContents.tables, (table: string) => this.props.schema.getTable(table))) {
232
- cantPasteMessage = "Dashboard is missing one or more data sources needed for the copied item."
233
- }
234
-
235
- const renderWidget = (options: any) => {
236
- const widget = WidgetFactory.createWidget(options.type)
237
-
238
- // Get filters (passed in plus dashboard widget scoper filters)
239
- let filters = compiledFilters.concat(this.state.widgetScoper.getFilters(options.id))
240
-
241
- // Extend the filters to include implicit filters (filter children in 1-n relationships)
242
- if (this.props.design.implicitFiltersEnabled || this.props.design.implicitFiltersEnabled == null) {
243
- // Default is true
244
- const implicitFilterBuilder = new ImplicitFilterBuilder(this.props.schema)
245
- filters = implicitFilterBuilder.extendFilters(filterableTables, filters)
246
- }
247
-
248
- const widgetElem = R(WidgetComponent, {
249
- key: options.id,
250
- id: options.id,
251
- type: options.type,
252
- schema: this.props.schema,
253
- dataSource: this.props.dataSource,
254
- dashboardDataSource: this.props.dashboardDataSource,
255
- design: options.design,
256
- scope: this.state.widgetScoper.getScope(options.id),
257
- filters,
258
- onScopeChange: this.handleScopeChange.bind(null, options.id),
259
- onDesignChange: options.onDesignChange,
260
- width: options.width,
261
- height: options.height,
262
- onRowClick: this.props.onRowClick,
263
- namedStrings: this.props.namedStrings,
264
- tocEntries,
265
- onScrollToTOCEntry: this.handleScrollToTOCEntry,
266
- // Keep references to widget elements
267
- widgetRef: this.compRef.bind(null, options.id),
268
- refreshKey: this.props.refreshKey
269
- })
270
-
271
- return widgetElem
272
- }
273
-
274
- const style: CSSProperties = {
275
- height: "100%",
276
- position: "relative"
277
- }
278
-
279
- if (!this.props.printMode) {
280
- // Prevent this block from taking up too much space. Scrolling handled by layout manager.
281
- // Setting overflow-x stops the inner div from becoming too tall
282
- style.overflowX = "auto"
283
- }
284
-
285
- // Render widget container
286
- return R(
287
- "div",
288
- { style },
289
- !this.props.hideScopes ? this.renderScopes() : undefined,
290
-
291
- layoutManager.renderLayout({
292
- items: this.props.design.items,
293
- onItemsChange: this.props.onDesignChange != null ? this.handleItemsChange : undefined,
294
- style: this.props.design.style || null,
295
- layoutOptions: getLayoutOptions(this.props.design),
296
- renderWidget,
297
- clipboard: clipboardContents?.block,
298
- onClipboardChange: this.handleClipboardChange,
299
- cantPasteMessage
300
- })
301
- )
302
- }
303
- }