@mwater/visualization 5.1.0 → 5.3.0

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 (305) 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/GlobalFilter.d.ts +13 -0
  10. package/lib/GlobalFilter.js +2 -0
  11. package/lib/LocaleContextInjector.d.ts +5 -11
  12. package/lib/LocaleContextInjector.js +4 -12
  13. package/lib/MWaterAddRelatedFormComponent.js +3 -3
  14. package/lib/MWaterAddRelatedIndicatorComponent.d.ts +1 -4
  15. package/lib/MWaterAddRelatedIndicatorComponent.js +6 -6
  16. package/lib/MWaterCompleteTableSelectComponent.d.ts +7 -25
  17. package/lib/MWaterCompleteTableSelectComponent.js +36 -36
  18. package/lib/MWaterContextComponent.d.ts +19 -9
  19. package/lib/MWaterContextComponent.js +38 -22
  20. package/lib/MWaterCustomTablesetListComponent.js +9 -3
  21. package/lib/MWaterGlobalFiltersComponent.d.ts +6 -5
  22. package/lib/MWaterGlobalFiltersComponent.js +4 -4
  23. package/lib/MWaterLoaderComponent.d.ts +15 -3
  24. package/lib/MWaterLoaderComponent.js +11 -2
  25. package/lib/MWaterTableSelectComponent.d.ts +1 -4
  26. package/lib/MWaterTableSelectComponent.js +10 -12
  27. package/lib/UIComponents.d.ts +2 -2
  28. package/lib/UIComponents.js +4 -12
  29. package/lib/axes/Axis.d.ts +20 -25
  30. package/lib/axes/AxisBuilder.d.ts +7 -4
  31. package/lib/axes/AxisBuilder.js +12 -8
  32. package/lib/axes/AxisComponent.d.ts +6 -9
  33. package/lib/axes/AxisComponent.js +1 -2
  34. package/lib/axes/ColorPaletteCollectionComponent.d.ts +5 -12
  35. package/lib/axes/ColorPaletteCollectionComponent.js +67 -36
  36. package/lib/dashboards/DashboardComponent.d.ts +4 -17
  37. package/lib/dashboards/DashboardComponent.js +20 -67
  38. package/lib/dashboards/DashboardDesign.d.ts +5 -20
  39. package/lib/dashboards/DashboardUpgrader.js +36 -1
  40. package/lib/dashboards/DashboardViewComponent.d.ts +5 -34
  41. package/lib/dashboards/DashboardViewComponent.js +112 -136
  42. package/lib/dashboards/FontStyleEditor.d.ts +8 -0
  43. package/lib/dashboards/FontStyleEditor.js +130 -0
  44. package/lib/dashboards/LayoutOptionsComponent.d.ts +0 -1
  45. package/lib/dashboards/LayoutOptionsComponent.js +209 -39
  46. package/lib/dashboards/ServerDashboardDataSource.d.ts +1 -2
  47. package/lib/dashboards/ServerDashboardDataSource.js +52 -33
  48. package/lib/dashboards/SettingsModalComponent.d.ts +4 -15
  49. package/lib/dashboards/SettingsModalComponent.js +24 -38
  50. package/lib/dashboards/WidgetComponent.d.ts +3 -3
  51. package/lib/dashboards/WidgetComponent.js +3 -6
  52. package/lib/dashboards/WidgetDataSourcePrioritizer.d.ts +20 -0
  53. package/lib/dashboards/WidgetDataSourcePrioritizer.js +72 -0
  54. package/lib/dashboards/layoutOptions.d.ts +83 -0
  55. package/lib/dashboards/layoutOptions.js +436 -10
  56. package/lib/datagrids/DatagridComponent.d.ts +2 -9
  57. package/lib/datagrids/DatagridDataSource.d.ts +3 -3
  58. package/lib/datagrids/DatagridDataSource.js +0 -14
  59. package/lib/datagrids/DatagridDesign.d.ts +7 -6
  60. package/lib/datagrids/DatagridDesignerComponent.d.ts +2 -93
  61. package/lib/datagrids/DatagridDesignerComponent.js +8 -6
  62. package/lib/datagrids/DatagridViewComponent.js +1 -1
  63. package/lib/datagrids/FindReplaceModalComponent.d.ts +4 -20
  64. package/lib/datagrids/FindReplaceModalComponent.js +27 -13
  65. package/lib/datagrids/ServerDatagridDataSource.d.ts +8 -7
  66. package/lib/datagrids/ServerDatagridDataSource.js +88 -36
  67. package/lib/demo.js +4 -4
  68. package/lib/index.css +5 -0
  69. package/lib/index.d.ts +2 -1
  70. package/lib/index.js +0 -1
  71. package/lib/layouts/LayoutManager.d.ts +33 -29
  72. package/lib/layouts/LayoutManager.js +2 -8
  73. package/lib/layouts/blocks/BlocksDisplayComponent.d.ts +26 -56
  74. package/lib/layouts/blocks/BlocksDisplayComponent.js +122 -205
  75. package/lib/layouts/blocks/BlocksLayoutManager.d.ts +6 -22
  76. package/lib/layouts/blocks/BlocksLayoutManager.js +5 -14
  77. package/lib/layouts/blocks/HorizontalBlockComponent.d.ts +5 -4
  78. package/lib/layouts/blocks/HorizontalBlockComponent.js +5 -5
  79. package/lib/layouts/grid/GridLayoutManager.d.ts +2 -1
  80. package/lib/mWaterLoader.d.ts +2 -0
  81. package/lib/mWaterLoader.js +2 -1
  82. package/lib/maps/AddLayerComponent.d.ts +6 -8
  83. package/lib/maps/AddLayerComponent.js +6 -6
  84. package/lib/maps/BingLayer.js +10 -20
  85. package/lib/maps/BufferLayer.js +5 -2
  86. package/lib/maps/ChoroplethLayer.js +2 -1
  87. package/lib/maps/ClusterLayer.js +3 -1
  88. package/lib/maps/DirectMapDataSource.d.ts +5 -2
  89. package/lib/maps/DirectMapDataSource.js +2 -1
  90. package/lib/maps/EditPopupComponent.js +2 -1
  91. package/lib/maps/GridLayer.js +5 -3
  92. package/lib/maps/GridLayerDesigner.js +0 -1
  93. package/lib/maps/LayerSwitcherComponent.js +1 -1
  94. package/lib/maps/MapComponent.d.ts +3 -11
  95. package/lib/maps/MapComponent.js +3 -3
  96. package/lib/maps/MapDesign.d.ts +2 -13
  97. package/lib/maps/MapFiltersDesignerComponent.d.ts +0 -4
  98. package/lib/maps/MapFiltersDesignerComponent.js +4 -5
  99. package/lib/maps/MarkersLayer.js +30 -25
  100. package/lib/maps/RasterMapViewComponent.d.ts +3 -13
  101. package/lib/maps/RasterMapViewComponent.js +3 -3
  102. package/lib/maps/RegionSelectComponent.d.ts +2 -1
  103. package/lib/maps/ServerMapDataSource.d.ts +3 -4
  104. package/lib/maps/ServerMapDataSource.js +5 -5
  105. package/lib/maps/VectorMapViewComponent.js +2 -1
  106. package/lib/maps/mapSymbols.js +2 -0
  107. package/lib/maps/symbols/font-awesome/cloud-rain.png +0 -0
  108. package/lib/maps/vectorMaps.d.ts +1 -0
  109. package/lib/maps/vectorMaps.js +70 -56
  110. package/lib/quickfilter/QuickfilterCompiler.d.ts +1 -1
  111. package/lib/quickfilter/QuickfiltersComponent.d.ts +1 -4
  112. package/lib/quickfilter/QuickfiltersComponent.js +3 -3
  113. package/lib/richtext/DropdownPaletteItem.d.ts +32 -0
  114. package/lib/richtext/DropdownPaletteItem.js +82 -0
  115. package/lib/richtext/FontColorPaletteItem.d.ts +1 -5
  116. package/lib/richtext/FontColorPaletteItem.js +32 -27
  117. package/lib/richtext/ItemsHtmlConverter.js +12 -3
  118. package/lib/richtext/RichTextComponent.d.ts +26 -52
  119. package/lib/richtext/RichTextComponent.js +166 -128
  120. package/lib/valueFormatter.js +6 -1
  121. package/lib/wellknown.d.ts +5 -0
  122. package/lib/wellknown.js +288 -0
  123. package/lib/widgets/DropdownWidgetComponent.d.ts +8 -25
  124. package/lib/widgets/DropdownWidgetComponent.js +48 -25
  125. package/lib/widgets/IFrameWidgetComponent.d.ts +3 -11
  126. package/lib/widgets/ImageWidgetComponent.d.ts +8 -27
  127. package/lib/widgets/MapWidget.d.ts +4 -7
  128. package/lib/widgets/MapWidget.js +2 -1
  129. package/lib/widgets/MarkdownWidget.d.ts +2 -7
  130. package/lib/widgets/TOCWidget.d.ts +2 -9
  131. package/lib/widgets/TOCWidget.js +2 -1
  132. package/lib/widgets/Widget.d.ts +2 -0
  133. package/lib/widgets/WidgetDataSource.d.ts +3 -1
  134. package/lib/widgets/charts/Chart.d.ts +0 -1
  135. package/lib/widgets/charts/ChartViewComponent.d.ts +4 -0
  136. package/lib/widgets/charts/ChartViewComponent.js +11 -3
  137. package/lib/widgets/charts/ChartWidget.d.ts +1 -74
  138. package/lib/widgets/charts/ChartWidget.js +4 -183
  139. package/lib/widgets/charts/ChartWidgetComponent.d.ts +51 -0
  140. package/lib/widgets/charts/ChartWidgetComponent.js +167 -0
  141. package/lib/widgets/charts/calendar/CalendarChartViewComponent.d.ts +1 -4
  142. package/lib/widgets/charts/calendar/CalendarChartViewComponent.js +4 -4
  143. package/lib/widgets/charts/imagemosaic/ImagePopupComponent.d.ts +2 -7
  144. package/lib/widgets/charts/layered/LayeredChart.d.ts +5 -10
  145. package/lib/widgets/charts/layered/LayeredChart.js +6 -7
  146. package/lib/widgets/charts/layered/LayeredChartCompiler.d.ts +4 -2
  147. package/lib/widgets/charts/layered/LayeredChartCompiler.js +46 -32
  148. package/lib/widgets/charts/layered/LayeredChartDesign.d.ts +4 -0
  149. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.d.ts +5 -31
  150. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.js +21 -3
  151. package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.d.ts +1 -7
  152. package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.js +2 -1
  153. package/lib/widgets/charts/layered/LayeredChartViewComponent.d.ts +1 -4
  154. package/lib/widgets/charts/layered/LayeredChartViewComponent.js +89 -38
  155. package/lib/widgets/charts/pivot/IntersectionDesignerComponent.d.ts +5 -105
  156. package/lib/widgets/charts/pivot/IntersectionDesignerComponent.js +122 -166
  157. package/lib/widgets/charts/pivot/PivotChart.d.ts +6 -0
  158. package/lib/widgets/charts/pivot/PivotChart.js +47 -17
  159. package/lib/widgets/charts/pivot/PivotChartDesign.d.ts +11 -0
  160. package/lib/widgets/charts/pivot/PivotChartDesignerComponent.d.ts +11 -7
  161. package/lib/widgets/charts/pivot/PivotChartDesignerComponent.js +1 -1
  162. package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.d.ts +2 -2
  163. package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.js +20 -36
  164. package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +0 -1
  165. package/lib/widgets/charts/pivot/PivotChartQueryBuilder.d.ts +23 -2
  166. package/lib/widgets/charts/pivot/PivotChartQueryBuilder.js +215 -181
  167. package/lib/widgets/charts/pivot/PivotChartUtils.d.ts +2 -2
  168. package/lib/widgets/charts/pivot/PivotChartViewComponent.d.ts +9 -47
  169. package/lib/widgets/charts/pivot/PivotChartViewComponent.js +20 -60
  170. package/lib/widgets/charts/pivot/SegmentDesignerComponent.d.ts +55 -58
  171. package/lib/widgets/charts/table/TableChart.js +8 -4
  172. package/lib/widgets/charts/table/TableChartDesignerComponent.js +3 -3
  173. package/lib/widgets/charts/table/TableChartViewComponent.js +30 -16
  174. package/lib/widgets/text/ExprInsertModalComponent.d.ts +2 -13
  175. package/lib/widgets/text/ExprUpdateModalComponent.d.ts +2 -13
  176. package/lib/widgets/text/TextComponent.d.ts +5 -12
  177. package/lib/widgets/text/TextComponent.js +19 -39
  178. package/lib/widgets/text/TextWidget.d.ts +2 -1
  179. package/lib/widgets/text/TextWidget.js +5 -1
  180. package/lib/widgets/text/TextWidgetComponent.d.ts +15 -3
  181. package/lib/widgets/text/TextWidgetComponent.js +76 -19
  182. package/lib/widgets/text/TextWidgetDesign.d.ts +16 -2
  183. package/lib/widgets/text/TextWidgetDesign.js +6 -0
  184. package/package.json +4 -4
  185. package/src/ColorComponent.tsx +177 -0
  186. package/src/ColorSchemeFactory.ts +12 -6
  187. package/src/CustomColorsContext.tsx +8 -0
  188. package/src/FiltersDesignerComponent.ts +3 -4
  189. package/src/GlobalFilter.ts +17 -0
  190. package/src/LocaleContextInjector.tsx +14 -13
  191. package/src/MWaterAddRelatedFormComponent.ts +3 -3
  192. package/src/MWaterAddRelatedIndicatorComponent.ts +6 -6
  193. package/src/MWaterCompleteTableSelectComponent.tsx +36 -36
  194. package/src/MWaterContextComponent.tsx +42 -33
  195. package/src/MWaterCustomTablesetListComponent.tsx +21 -3
  196. package/src/MWaterGlobalFiltersComponent.ts +8 -8
  197. package/src/MWaterLoaderComponent.ts +14 -4
  198. package/src/MWaterTableSelectComponent.tsx +11 -12
  199. package/src/{UIComponents.ts → UIComponents.tsx} +7 -15
  200. package/src/axes/Axis.ts +24 -25
  201. package/src/axes/AxisBuilder.ts +16 -13
  202. package/src/axes/AxisComponent.ts +3 -4
  203. package/src/axes/{ColorPaletteCollectionComponent.ts → ColorPaletteCollectionComponent.tsx} +87 -61
  204. package/src/dashboards/DashboardComponent.tsx +73 -147
  205. package/src/dashboards/DashboardDesign.ts +5 -25
  206. package/src/dashboards/DashboardUpgrader.ts +41 -1
  207. package/src/dashboards/DashboardViewComponent.tsx +313 -0
  208. package/src/dashboards/FontStyleEditor.tsx +166 -0
  209. package/src/dashboards/LayoutOptionsComponent.tsx +377 -71
  210. package/src/dashboards/ServerDashboardDataSource.ts +52 -33
  211. package/src/dashboards/SettingsModalComponent.tsx +170 -0
  212. package/src/dashboards/WidgetComponent.tsx +6 -12
  213. package/src/dashboards/WidgetDataSourcePrioritizer.ts +82 -0
  214. package/src/dashboards/layoutOptions.tsx +581 -0
  215. package/src/datagrids/DatagridDataSource.ts +6 -12
  216. package/src/datagrids/DatagridDesign.ts +8 -3
  217. package/src/datagrids/DatagridDesignerComponent.tsx +22 -18
  218. package/src/datagrids/DatagridViewComponent.ts +3 -3
  219. package/src/datagrids/ExprCellComponent.ts +0 -1
  220. package/src/datagrids/FindReplaceModalComponent.ts +39 -22
  221. package/src/datagrids/ServerDatagridDataSource.ts +107 -45
  222. package/src/demo.ts +4 -4
  223. package/src/index.css +5 -0
  224. package/src/index.ts +2 -1
  225. package/src/layouts/LayoutManager.ts +44 -42
  226. package/src/layouts/blocks/BlocksDisplayComponent.tsx +498 -0
  227. package/src/layouts/blocks/BlocksLayoutManager.ts +6 -15
  228. package/src/layouts/blocks/HorizontalBlockComponent.ts +9 -8
  229. package/src/mWaterLoader.ts +4 -1
  230. package/src/maps/AddLayerComponent.ts +9 -9
  231. package/src/maps/BingLayer.ts +16 -26
  232. package/src/maps/BufferLayer.ts +5 -2
  233. package/src/maps/ChoroplethLayer.ts +2 -1
  234. package/src/maps/ClusterLayer.ts +3 -1
  235. package/src/maps/DirectMapDataSource.ts +12 -3
  236. package/src/maps/EditPopupComponent.ts +2 -1
  237. package/src/maps/GridLayer.ts +5 -3
  238. package/src/maps/GridLayerDesigner.tsx +0 -1
  239. package/src/maps/LayerSwitcherComponent.tsx +1 -1
  240. package/src/maps/MapComponent.ts +3 -3
  241. package/src/maps/MapDesign.ts +2 -17
  242. package/src/maps/{MapFiltersDesignerComponent.ts → MapFiltersDesignerComponent.tsx} +25 -25
  243. package/src/maps/MarkersLayer.ts +38 -41
  244. package/src/maps/RasterMapViewComponent.ts +3 -3
  245. package/src/maps/ServerMapDataSource.ts +8 -8
  246. package/src/maps/VectorMapViewComponent.tsx +2 -2
  247. package/src/maps/mapSymbols.ts +2 -0
  248. package/src/maps/symbols/font-awesome/cloud-rain.png +0 -0
  249. package/src/maps/vectorMaps.tsx +88 -74
  250. package/src/quickfilter/QuickfilterCompiler.ts +1 -1
  251. package/src/quickfilter/QuickfiltersComponent.ts +3 -3
  252. package/src/richtext/DropdownPaletteItem.tsx +144 -0
  253. package/src/richtext/FontColorPaletteItem.tsx +160 -0
  254. package/src/richtext/ItemsHtmlConverter.ts +15 -5
  255. package/src/richtext/RichTextComponent.tsx +274 -232
  256. package/src/valueFormatter.ts +5 -1
  257. package/src/wellknown.ts +286 -0
  258. package/src/widgets/DropdownWidgetComponent.tsx +75 -0
  259. package/src/widgets/MapWidget.ts +5 -2
  260. package/src/widgets/TOCWidget.ts +2 -1
  261. package/src/widgets/Widget.ts +3 -0
  262. package/src/widgets/WidgetDataSource.ts +3 -1
  263. package/src/widgets/charts/Chart.ts +1 -1
  264. package/src/widgets/charts/ChartViewComponent.ts +16 -3
  265. package/src/widgets/charts/ChartWidget.ts +3 -275
  266. package/src/widgets/charts/ChartWidgetComponent.tsx +281 -0
  267. package/src/widgets/charts/calendar/CalendarChartViewComponent.tsx +4 -4
  268. package/src/widgets/charts/layered/LayeredChart.ts +4 -6
  269. package/src/widgets/charts/layered/LayeredChartCompiler.ts +80 -63
  270. package/src/widgets/charts/layered/LayeredChartDesign.ts +7 -1
  271. package/src/widgets/charts/layered/LayeredChartDesignerComponent.tsx +43 -10
  272. package/src/widgets/charts/layered/LayeredChartLayerDesignerComponent.tsx +6 -6
  273. package/src/widgets/charts/layered/LayeredChartViewComponent.ts +140 -88
  274. package/src/widgets/charts/pivot/IntersectionDesignerComponent.tsx +305 -221
  275. package/src/widgets/charts/pivot/PivotChart.ts +56 -18
  276. package/src/widgets/charts/pivot/PivotChartDesign.ts +12 -0
  277. package/src/widgets/charts/pivot/PivotChartDesignerComponent.tsx +4 -3
  278. package/src/widgets/charts/pivot/PivotChartLayoutBuilder.ts +39 -76
  279. package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +0 -1
  280. package/src/widgets/charts/pivot/PivotChartQueryBuilder.ts +230 -189
  281. package/src/widgets/charts/pivot/PivotChartUtils.ts +4 -4
  282. package/src/widgets/charts/pivot/{PivotChartViewComponent.ts → PivotChartViewComponent.tsx} +86 -89
  283. package/src/widgets/charts/table/TableChart.ts +8 -4
  284. package/src/widgets/charts/table/TableChartDesignerComponent.ts +4 -4
  285. package/src/widgets/charts/table/TableChartViewComponent.ts +32 -19
  286. package/src/widgets/text/TextComponent.tsx +47 -49
  287. package/src/widgets/text/TextWidget.ts +8 -3
  288. package/src/widgets/text/TextWidgetComponent.tsx +249 -0
  289. package/src/widgets/text/TextWidgetDesign.ts +26 -2
  290. package/src/ColorComponent.ts +0 -117
  291. package/src/dashboards/DashboardViewComponent.ts +0 -304
  292. package/src/dashboards/SettingsModalComponent.ts +0 -169
  293. package/src/dashboards/layoutOptions.ts +0 -40
  294. package/src/layout-styles.css +0 -263
  295. package/src/layouts/blocks/BlocksDisplayComponent.ts +0 -461
  296. package/src/layouts/grid/GridLayoutComponent.ts +0 -67
  297. package/src/layouts/grid/GridLayoutManager.ts +0 -185
  298. package/src/layouts/grid/LegoLayoutEngine.ts +0 -142
  299. package/src/layouts/grid/PaletteItemComponent.ts +0 -28
  300. package/src/layouts/grid/README.md +0 -14
  301. package/src/layouts/grid/WidgetContainerComponent.ts +0 -420
  302. package/src/richtext/FontColorPaletteItem.ts +0 -172
  303. package/src/richtext/FontSizePaletteItem.ts +0 -110
  304. package/src/widgets/DropdownWidgetComponent.ts +0 -78
  305. 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
+ }
@@ -1,7 +1,31 @@
1
+ import { HtmlItemExpr } from "../../richtext/ExprItemsHtmlConverter"
2
+ import { HtmlItem } from "../../richtext/ItemsHtmlConverter"
3
+
1
4
  export interface TextWidgetDesign {
2
5
  /** Text widget stores its content as array of items. See ItemsHtmlConverter TODO */
3
- items: any[]
6
+ items: (HtmlItem | HtmlItemExpr)[]
4
7
 
5
8
  /** "title" for title block. default is "default" */
6
- 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
7
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,304 +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 { getMapTilerApiKey, setMapTilerApiKey } 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 disable vector maps as WebGL is not supported in print mode
151
- const mapTilerAPIKey = getMapTilerApiKey()
152
- try {
153
- setMapTilerApiKey("")
154
-
155
- // Create element at 1080 wide (use as standard printing width)
156
- const elem = R(
157
- "div",
158
- { style: { width: 1080 } },
159
- R(DashboardViewComponent, _.extend({}, this.props, { onDesignChange: null, printMode: true }))
160
- )
161
-
162
- const printer = new ReactElementPrinter()
163
- await printer.print(elem, { delay: 5000 })
164
- } finally {
165
- setMapTilerApiKey(mapTilerAPIKey)
166
- }
167
- }
168
-
169
- // Get filters from props filters combined with dashboard filters
170
- getCompiledFilters() {
171
- let compiledFilters = DashboardUtils.getCompiledFilters(
172
- this.props.design,
173
- this.props.schema,
174
- DashboardUtils.getFilterableTables(this.props.design, this.props.schema)
175
- )
176
- compiledFilters = compiledFilters.concat(this.props.filters || [])
177
- return compiledFilters
178
- }
179
-
180
- // Get list of TOC entries
181
- getTOCEntries(layoutManager: any) {
182
- const entries = []
183
-
184
- for (let { id, type, design } of layoutManager.getAllWidgets(this.props.design.items)) {
185
- const widget = WidgetFactory.createWidget(type)
186
- // Add widgetId to each one
187
- for (let entry of widget.getTOCEntries(design, this.props.namedStrings)) {
188
- entries.push(_.extend({}, entry, { widgetId: id }))
189
- }
190
- }
191
-
192
- return entries
193
- }
194
-
195
- handleScrollToTOCEntry = (widgetId: any, entryId: any) => {
196
- const widgetComp = this.widgetComps[widgetId]
197
- if (!widgetComp) {
198
- return
199
- }
200
-
201
- // Call scrollToTOCEntry if present
202
- return widgetComp.scrollToTOCEntry?.(entryId)
203
- }
204
-
205
- renderScopes() {
206
- return R(WidgetScopesViewComponent, {
207
- scopes: this.state.widgetScoper.getScopes(),
208
- onRemoveScope: this.handleRemoveScope
209
- })
210
- }
211
-
212
- compRef = (widgetId: any, comp: any) => {
213
- return (this.widgetComps[widgetId] = comp)
214
- }
215
-
216
- render() {
217
- let cantPasteMessage = ""
218
- const layoutManager = LayoutManager.createLayoutManager(this.props.design.layout)
219
-
220
- const compiledFilters = this.getCompiledFilters()
221
-
222
- // Get filterable tables
223
- const filterableTables = DashboardUtils.getFilterableTables(this.props.design, this.props.schema)
224
-
225
- // Determine toc entries
226
- const tocEntries = this.getTOCEntries(layoutManager)
227
-
228
- // Get clipboard contents
229
- const clipboardContents = this.getClipboardContents()
230
-
231
- // Check if can't paste because of missing table
232
- if (clipboardContents && !_.all(clipboardContents.tables, (table: string) => this.props.schema.getTable(table))) {
233
- cantPasteMessage = "Dashboard is missing one or more data sources needed for the copied item."
234
- }
235
-
236
- const renderWidget = (options: any) => {
237
- const widget = WidgetFactory.createWidget(options.type)
238
-
239
- // Get filters (passed in plus dashboard widget scoper filters)
240
- let filters = compiledFilters.concat(this.state.widgetScoper.getFilters(options.id))
241
-
242
- // Extend the filters to include implicit filters (filter children in 1-n relationships)
243
- if (this.props.design.implicitFiltersEnabled || this.props.design.implicitFiltersEnabled == null) {
244
- // Default is true
245
- const implicitFilterBuilder = new ImplicitFilterBuilder(this.props.schema)
246
- filters = implicitFilterBuilder.extendFilters(filterableTables, filters)
247
- }
248
-
249
- const widgetElem = R(WidgetComponent, {
250
- key: options.id,
251
- id: options.id,
252
- type: options.type,
253
- schema: this.props.schema,
254
- dataSource: this.props.dataSource,
255
- dashboardDataSource: this.props.dashboardDataSource,
256
- design: options.design,
257
- scope: this.state.widgetScoper.getScope(options.id),
258
- filters,
259
- onScopeChange: this.handleScopeChange.bind(null, options.id),
260
- onDesignChange: options.onDesignChange,
261
- width: options.width,
262
- height: options.height,
263
- onRowClick: this.props.onRowClick,
264
- namedStrings: this.props.namedStrings,
265
- tocEntries,
266
- onScrollToTOCEntry: this.handleScrollToTOCEntry,
267
- // Keep references to widget elements
268
- widgetRef: this.compRef.bind(null, options.id),
269
- refreshKey: this.props.refreshKey
270
- })
271
-
272
- return widgetElem
273
- }
274
-
275
- const style: CSSProperties = {
276
- height: "100%",
277
- position: "relative"
278
- }
279
-
280
- if (!this.props.printMode) {
281
- // Prevent this block from taking up too much space. Scrolling handled by layout manager.
282
- // Setting overflow-x stops the inner div from becoming too tall
283
- style.overflowX = "auto"
284
- }
285
-
286
- // Render widget container
287
- return R(
288
- "div",
289
- { style },
290
- !this.props.hideScopes ? this.renderScopes() : undefined,
291
-
292
- layoutManager.renderLayout({
293
- items: this.props.design.items,
294
- onItemsChange: this.props.onDesignChange != null ? this.handleItemsChange : undefined,
295
- style: this.props.design.style || null,
296
- layoutOptions: getLayoutOptions(this.props.design),
297
- renderWidget,
298
- clipboard: clipboardContents?.block,
299
- onClipboardChange: this.handleClipboardChange,
300
- cantPasteMessage
301
- })
302
- )
303
- }
304
- }