@mwater/visualization 5.5.0 → 5.6.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 (222) hide show
  1. package/lib/MWaterContextComponent.d.ts +1 -1
  2. package/lib/MWaterGlobalFiltersComponent.d.ts +2 -2
  3. package/lib/MWaterGlobalFiltersComponent.js +11 -20
  4. package/lib/MWaterLoaderComponent.d.ts +4 -13
  5. package/lib/MWaterLoaderComponent.js +2 -11
  6. package/lib/UndoStack.d.ts +2 -1
  7. package/lib/UndoStack.js +12 -6
  8. package/lib/dashboards/DashboardComponent.js +5 -4
  9. package/lib/dashboards/DashboardDesign.d.ts +1 -1
  10. package/lib/dashboards/ServerDashboardDataSource.js +0 -10
  11. package/lib/dashboards/SettingsModalComponent.js +1 -1
  12. package/lib/datagrids/DatagridComponent.js +22 -2
  13. package/lib/datagrids/DatagridDesignerComponent.d.ts +2 -3
  14. package/lib/datagrids/DatagridDesignerComponent.js +108 -120
  15. package/lib/datagrids/DatagridViewComponent.js +3 -2
  16. package/lib/datagrids/OrderBysDesignerComponent.d.ts +7 -7
  17. package/lib/datagrids/OrderBysDesignerComponent.js +19 -28
  18. package/lib/index.css +45 -2
  19. package/lib/index.d.ts +5 -5
  20. package/lib/index.js +2 -3
  21. package/lib/layouts/blocks/BlocksDisplayComponent.d.ts +8 -1
  22. package/lib/layouts/blocks/BlocksDisplayComponent.js +46 -4
  23. package/lib/maps/BufferLayer.js +12 -0
  24. package/lib/maps/BufferLayerDesign.d.ts +1 -1
  25. package/lib/maps/BufferLayerDesignerComponent.js +2 -2
  26. package/lib/maps/ChoroplethLayer.js +12 -0
  27. package/lib/maps/ChoroplethLayerDesign.d.ts +5 -2
  28. package/lib/maps/ChoroplethLayerDesigner.d.ts +10 -32
  29. package/lib/maps/ChoroplethLayerDesigner.js +58 -89
  30. package/lib/maps/DirectMapDataSource.js +0 -10
  31. package/lib/maps/EditHoverOver.d.ts +4 -3
  32. package/lib/maps/EditHoverOver.js +3 -3
  33. package/lib/maps/HoverContent.js +1 -1
  34. package/lib/maps/LeafletMapComponent.js +10 -19
  35. package/lib/maps/MapComponent.js +0 -1
  36. package/lib/maps/MapUtils.js +10 -1
  37. package/lib/maps/MarkersLayer.js +18 -2
  38. package/lib/maps/MarkersLayerDesign.d.ts +1 -1
  39. package/lib/maps/MarkersLayerDesignerComponent.d.ts +12 -41
  40. package/lib/maps/MarkersLayerDesignerComponent.js +81 -111
  41. package/lib/maps/ServerMapDataSource.js +0 -10
  42. package/lib/maps/VectorMapViewComponent.js +1 -9
  43. package/lib/maps/symbols/font-awesome/asterisk.png +0 -0
  44. package/lib/maps/symbols/font-awesome/ban.png +0 -0
  45. package/lib/maps/symbols/font-awesome/beer.png +0 -0
  46. package/lib/maps/symbols/font-awesome/bell.png +0 -0
  47. package/lib/maps/symbols/font-awesome/bolt.png +0 -0
  48. package/lib/maps/symbols/font-awesome/building.png +0 -0
  49. package/lib/maps/symbols/font-awesome/bullseye.png +0 -0
  50. package/lib/maps/symbols/font-awesome/bus.png +0 -0
  51. package/lib/maps/symbols/font-awesome/caret-up.png +0 -0
  52. package/lib/maps/symbols/font-awesome/certificate.png +0 -0
  53. package/lib/maps/symbols/font-awesome/check-circle.png +0 -0
  54. package/lib/maps/symbols/font-awesome/check.png +0 -0
  55. package/lib/maps/symbols/font-awesome/chevron-circle-down.png +0 -0
  56. package/lib/maps/symbols/font-awesome/chevron-circle-up.png +0 -0
  57. package/lib/maps/symbols/font-awesome/cloud-rain.png +0 -0
  58. package/lib/maps/symbols/font-awesome/cloud.png +0 -0
  59. package/lib/maps/symbols/font-awesome/comment.png +0 -0
  60. package/lib/maps/symbols/font-awesome/crosshairs.png +0 -0
  61. package/lib/maps/symbols/font-awesome/dot-circle-o.png +0 -0
  62. package/lib/maps/symbols/font-awesome/exclamation-circle.png +0 -0
  63. package/lib/maps/symbols/font-awesome/exclamation-triangle.png +0 -0
  64. package/lib/maps/symbols/font-awesome/female.png +0 -0
  65. package/lib/maps/symbols/font-awesome/file.png +0 -0
  66. package/lib/maps/symbols/font-awesome/flag.png +0 -0
  67. package/lib/maps/symbols/font-awesome/flask.png +0 -0
  68. package/lib/maps/symbols/font-awesome/h-square.png +0 -0
  69. package/lib/maps/symbols/font-awesome/home.png +0 -0
  70. package/lib/maps/symbols/font-awesome/info-circle.png +0 -0
  71. package/lib/maps/symbols/font-awesome/male.png +0 -0
  72. package/lib/maps/symbols/font-awesome/medkit.png +0 -0
  73. package/lib/maps/symbols/font-awesome/mobile.png +0 -0
  74. package/lib/maps/symbols/font-awesome/plus-circle.png +0 -0
  75. package/lib/maps/symbols/font-awesome/plus-square.png +0 -0
  76. package/lib/maps/symbols/font-awesome/plus.png +0 -0
  77. package/lib/maps/symbols/font-awesome/square.png +0 -0
  78. package/lib/maps/symbols/font-awesome/star.png +0 -0
  79. package/lib/maps/symbols/font-awesome/thumbs-down.png +0 -0
  80. package/lib/maps/symbols/font-awesome/thumbs-up.png +0 -0
  81. package/lib/maps/symbols/font-awesome/ticket.png +0 -0
  82. package/lib/maps/symbols/font-awesome/times-circle.png +0 -0
  83. package/lib/maps/symbols/font-awesome/times.png +0 -0
  84. package/lib/maps/symbols/font-awesome/tint.png +0 -0
  85. package/lib/maps/symbols/font-awesome/tree.png +0 -0
  86. package/lib/maps/symbols/font-awesome/university.png +0 -0
  87. package/lib/maps/symbols/font-awesome/usd.png +0 -0
  88. package/lib/maps/symbols/font-awesome/user.png +0 -0
  89. package/lib/maps/symbols/font-awesome/users.png +0 -0
  90. package/lib/maps/symbols/font-awesome/wheelchair.png +0 -0
  91. package/lib/maps/symbols/sdf-ize.sh +93 -0
  92. package/lib/maps/vectorMaps.d.ts +1 -0
  93. package/lib/maps/vectorMaps.js +20 -36
  94. package/lib/mwater_table_selection/IndicatorsListComponent.d.ts +4 -2
  95. package/lib/mwater_table_selection/IndicatorsListComponent.js +103 -34
  96. package/lib/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.d.ts +18 -0
  97. package/lib/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.js +80 -0
  98. package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.d.ts +26 -0
  99. package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.js +237 -51
  100. package/lib/mwater_table_selection/MWaterTableSelectComponent.d.ts +2 -2
  101. package/lib/mwater_table_selection/MWaterTableSelectComponent.js +9 -4
  102. package/lib/mwater_table_selection/MWaterWorkflowsSelectComponent.d.ts +19 -0
  103. package/lib/mwater_table_selection/MWaterWorkflowsSelectComponent.js +111 -0
  104. package/lib/quickfilter/QuickfiltersComponent.d.ts +3 -102
  105. package/lib/quickfilter/QuickfiltersComponent.js +53 -110
  106. package/lib/quickfilter/TextLiteralComponent.d.ts +23 -47
  107. package/lib/quickfilter/TextLiteralComponent.js +85 -82
  108. package/lib/widgets/MapWidget.js +4 -2
  109. package/lib/widgets/text/ExprItemEditorComponent.d.ts +3 -8
  110. package/lib/widgets/text/ExprItemEditorComponent.js +36 -33
  111. package/lib/widgets/text/ExprUpdateModalComponent.d.ts +1 -0
  112. package/package.json +2 -3
  113. package/src/MWaterContextComponent.tsx +1 -1
  114. package/src/{MWaterGlobalFiltersComponent.ts → MWaterGlobalFiltersComponent.tsx} +32 -33
  115. package/src/{MWaterLoaderComponent.ts → MWaterLoaderComponent.tsx} +17 -18
  116. package/src/UndoStack.ts +14 -6
  117. package/src/dashboards/DashboardComponent.tsx +5 -4
  118. package/src/dashboards/DashboardDesign.ts +1 -1
  119. package/src/dashboards/ServerDashboardDataSource.ts +0 -12
  120. package/src/dashboards/SettingsModalComponent.tsx +1 -1
  121. package/src/datagrids/DatagridComponent.tsx +30 -2
  122. package/src/datagrids/DatagridDesignerComponent.tsx +241 -229
  123. package/src/datagrids/DatagridViewComponent.tsx +3 -2
  124. package/src/datagrids/OrderBysDesignerComponent.tsx +61 -70
  125. package/src/index.css +45 -2
  126. package/src/index.ts +5 -11
  127. package/src/layouts/blocks/BlocksDisplayComponent.tsx +60 -5
  128. package/src/maps/BufferLayer.ts +14 -1
  129. package/src/maps/BufferLayerDesign.ts +1 -1
  130. package/src/maps/BufferLayerDesignerComponent.tsx +2 -1
  131. package/src/maps/ChoroplethLayer.ts +20 -7
  132. package/src/maps/ChoroplethLayerDesign.ts +5 -2
  133. package/src/maps/ChoroplethLayerDesigner.tsx +169 -165
  134. package/src/maps/DirectMapDataSource.ts +0 -12
  135. package/src/maps/EditHoverOver.tsx +9 -5
  136. package/src/maps/HoverContent.tsx +1 -1
  137. package/src/maps/LeafletMapComponent.tsx +10 -19
  138. package/src/maps/MapComponent.ts +0 -1
  139. package/src/maps/MapUtils.ts +13 -1
  140. package/src/maps/MarkersLayer.ts +22 -5
  141. package/src/maps/MarkersLayerDesign.ts +1 -1
  142. package/src/maps/MarkersLayerDesignerComponent.tsx +360 -0
  143. package/src/maps/ServerMapDataSource.ts +0 -12
  144. package/src/maps/VectorMapViewComponent.tsx +2 -13
  145. package/src/maps/symbols/font-awesome/asterisk.png +0 -0
  146. package/src/maps/symbols/font-awesome/ban.png +0 -0
  147. package/src/maps/symbols/font-awesome/beer.png +0 -0
  148. package/src/maps/symbols/font-awesome/bell.png +0 -0
  149. package/src/maps/symbols/font-awesome/bolt.png +0 -0
  150. package/src/maps/symbols/font-awesome/building.png +0 -0
  151. package/src/maps/symbols/font-awesome/bullseye.png +0 -0
  152. package/src/maps/symbols/font-awesome/bus.png +0 -0
  153. package/src/maps/symbols/font-awesome/caret-up.png +0 -0
  154. package/src/maps/symbols/font-awesome/certificate.png +0 -0
  155. package/src/maps/symbols/font-awesome/check-circle.png +0 -0
  156. package/src/maps/symbols/font-awesome/check.png +0 -0
  157. package/src/maps/symbols/font-awesome/chevron-circle-down.png +0 -0
  158. package/src/maps/symbols/font-awesome/chevron-circle-up.png +0 -0
  159. package/src/maps/symbols/font-awesome/cloud-rain.png +0 -0
  160. package/src/maps/symbols/font-awesome/cloud.png +0 -0
  161. package/src/maps/symbols/font-awesome/comment.png +0 -0
  162. package/src/maps/symbols/font-awesome/crosshairs.png +0 -0
  163. package/src/maps/symbols/font-awesome/dot-circle-o.png +0 -0
  164. package/src/maps/symbols/font-awesome/exclamation-circle.png +0 -0
  165. package/src/maps/symbols/font-awesome/exclamation-triangle.png +0 -0
  166. package/src/maps/symbols/font-awesome/female.png +0 -0
  167. package/src/maps/symbols/font-awesome/file.png +0 -0
  168. package/src/maps/symbols/font-awesome/flag.png +0 -0
  169. package/src/maps/symbols/font-awesome/flask.png +0 -0
  170. package/src/maps/symbols/font-awesome/h-square.png +0 -0
  171. package/src/maps/symbols/font-awesome/home.png +0 -0
  172. package/src/maps/symbols/font-awesome/info-circle.png +0 -0
  173. package/src/maps/symbols/font-awesome/male.png +0 -0
  174. package/src/maps/symbols/font-awesome/medkit.png +0 -0
  175. package/src/maps/symbols/font-awesome/mobile.png +0 -0
  176. package/src/maps/symbols/font-awesome/plus-circle.png +0 -0
  177. package/src/maps/symbols/font-awesome/plus-square.png +0 -0
  178. package/src/maps/symbols/font-awesome/plus.png +0 -0
  179. package/src/maps/symbols/font-awesome/square.png +0 -0
  180. package/src/maps/symbols/font-awesome/star.png +0 -0
  181. package/src/maps/symbols/font-awesome/thumbs-down.png +0 -0
  182. package/src/maps/symbols/font-awesome/thumbs-up.png +0 -0
  183. package/src/maps/symbols/font-awesome/ticket.png +0 -0
  184. package/src/maps/symbols/font-awesome/times-circle.png +0 -0
  185. package/src/maps/symbols/font-awesome/times.png +0 -0
  186. package/src/maps/symbols/font-awesome/tint.png +0 -0
  187. package/src/maps/symbols/font-awesome/tree.png +0 -0
  188. package/src/maps/symbols/font-awesome/university.png +0 -0
  189. package/src/maps/symbols/font-awesome/usd.png +0 -0
  190. package/src/maps/symbols/font-awesome/user.png +0 -0
  191. package/src/maps/symbols/font-awesome/users.png +0 -0
  192. package/src/maps/symbols/font-awesome/wheelchair.png +0 -0
  193. package/src/maps/symbols/sdf-ize.sh +93 -0
  194. package/src/maps/vectorMaps.tsx +20 -44
  195. package/src/mwater_table_selection/IndicatorsListComponent.tsx +165 -37
  196. package/src/mwater_table_selection/MWaterCalculatedDataSourcesListComponent.tsx +111 -0
  197. package/src/mwater_table_selection/MWaterCompleteTableSelectComponent.tsx +373 -37
  198. package/src/mwater_table_selection/MWaterTableSelectComponent.tsx +12 -8
  199. package/src/mwater_table_selection/MWaterWorkflowsSelectComponent.tsx +159 -0
  200. package/src/quickfilter/{QuickfiltersComponent.ts → QuickfiltersComponent.tsx} +165 -158
  201. package/src/quickfilter/TextLiteralComponent.tsx +197 -0
  202. package/src/widgets/MapWidget.tsx +9 -1
  203. package/src/widgets/text/ExprItemEditorComponent.tsx +83 -77
  204. package/src/widgets/text/ExprUpdateModalComponent.tsx +1 -0
  205. package/test/UndoStackTests.ts +52 -1
  206. package/.storybook/config.js +0 -7
  207. package/.storybook/head.html +0 -3
  208. package/.storybook/webpack.config.js +0 -15
  209. package/src/maps/BingLayer.ts +0 -146
  210. package/src/maps/MarkersLayerDesignerComponent.ts +0 -374
  211. package/src/quickfilter/TextLiteralComponent.ts +0 -165
  212. package/stories/UpdateableComponent.js +0 -29
  213. package/stories/consoles.js +0 -202
  214. package/stories/dashboards.js +0 -217
  215. package/stories/datagridDesign.js +0 -114
  216. package/stories/datagrids.js +0 -69
  217. package/stories/dates.js +0 -80
  218. package/stories/exprcomponent.js +0 -43
  219. package/stories/index.js +0 -18
  220. package/stories/leaflet.js +0 -59
  221. package/stories/maps.js +0 -24
  222. package/stories/pivotChart.js +0 -235
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const lodash_1 = __importDefault(require("lodash"));
7
7
  const react_1 = __importDefault(require("react"));
8
- const R = react_1.default.createElement;
9
8
  const react_select_1 = __importDefault(require("react-select"));
10
9
  const expressions_1 = require("@mwater/expressions");
11
10
  const expressions_2 = require("@mwater/expressions");
@@ -25,9 +24,10 @@ class QuickfiltersComponent extends react_1.default.Component {
25
24
  let values = this.props.values || [];
26
25
  let itemValue = values[index];
27
26
  // Translate label
28
- const label = this.props.translate?.(item.label) ?? item.label;
27
+ const label = this.props.translate?.(item.label ?? "") ?? item.label ?? "";
28
+ const exprCleaner = new expressions_2.ExprCleaner(this.props.schema);
29
29
  // Clean expression first
30
- const expr = new expressions_2.ExprCleaner(this.props.schema).cleanExpr(item.expr);
30
+ const expr = exprCleaner.cleanExpr(item.expr);
31
31
  // Do not render if nothing
32
32
  if (!expr) {
33
33
  return null;
@@ -37,6 +37,22 @@ class QuickfiltersComponent extends react_1.default.Component {
37
37
  if (!type) {
38
38
  return null;
39
39
  }
40
+ // If this quickfilter is text or text[] and has subsequent merged quickfilters, gather their expressions
41
+ let exprsToPass = [expr];
42
+ if (["text", "text[]"].includes(type)) {
43
+ for (let i2 = index + 1; i2 < this.props.design.length; i2++) {
44
+ const nextItem = this.props.design[i2];
45
+ if (nextItem.merged) {
46
+ const cleaned = exprCleaner.cleanExpr(nextItem.expr);
47
+ if (cleaned) {
48
+ exprsToPass.push(cleaned);
49
+ }
50
+ }
51
+ else {
52
+ break;
53
+ }
54
+ }
55
+ }
40
56
  // Determine if locked
41
57
  const lock = lodash_1.default.find(this.props.locks || [], (lock) => lodash_1.default.isEqual(lock.expr, expr));
42
58
  if (lock) {
@@ -73,67 +89,19 @@ class QuickfiltersComponent extends react_1.default.Component {
73
89
  const otherQuickfilterFilters = compiler.compile(otherDesign, otherValues, otherLocks);
74
90
  const filters = (this.props.filters || []).concat(otherQuickfilterFilters);
75
91
  if (["enum", "enumset"].includes(type)) {
76
- return R(EnumQuickfilterComponent, {
77
- key: JSON.stringify(item),
78
- label,
79
- schema: this.props.schema,
80
- options: new expressions_1.ExprUtils(this.props.schema).getExprEnumValues(expr),
81
- value: itemValue,
82
- onValueChange,
83
- multi: item.multi
84
- });
92
+ return react_1.default.createElement(EnumQuickfilterComponent, { key: JSON.stringify(item), label: label, schema: this.props.schema, options: new expressions_1.ExprUtils(this.props.schema).getExprEnumValues(expr), value: itemValue, onValueChange: onValueChange, multi: item.multi });
85
93
  }
86
94
  if (type === "text") {
87
- return R(TextQuickfilterComponent, {
88
- key: JSON.stringify(item),
89
- index,
90
- label,
91
- expr,
92
- schema: this.props.schema,
93
- quickfiltersDataSource: this.props.quickfiltersDataSource,
94
- value: itemValue,
95
- onValueChange,
96
- filters,
97
- multi: item.multi
98
- });
95
+ return react_1.default.createElement(TextQuickfilterComponent, { key: JSON.stringify(item), index: index, label: label, expr: exprsToPass, schema: this.props.schema, quickfiltersDataSource: this.props.quickfiltersDataSource, value: itemValue, onValueChange: onValueChange, filters: filters, multi: item.multi });
99
96
  }
100
97
  if (["date", "datetime"].includes(type)) {
101
- return R(DateQuickfilterComponent, {
102
- key: JSON.stringify(item),
103
- label,
104
- expr,
105
- schema: this.props.schema,
106
- value: itemValue,
107
- onValueChange
108
- });
98
+ return react_1.default.createElement(DateQuickfilterComponent, { key: JSON.stringify(item), label: label, expr: expr, schema: this.props.schema, value: itemValue, onValueChange: onValueChange });
109
99
  }
110
100
  if (type === "id[]") {
111
- return R(IdArrayQuickfilterComponent_1.default, {
112
- key: JSON.stringify(item),
113
- index,
114
- label,
115
- expr,
116
- schema: this.props.schema,
117
- dataSource: this.props.dataSource,
118
- value: itemValue,
119
- onValueChange,
120
- filters,
121
- multi: item.multi
122
- });
101
+ return react_1.default.createElement(IdArrayQuickfilterComponent_1.default, { key: JSON.stringify(item), index: index, label: label, expr: expr, schema: this.props.schema, dataSource: this.props.dataSource, value: itemValue, onValueChange: onValueChange, filters: filters, multi: item.multi });
123
102
  }
124
103
  if (type === "text[]") {
125
- return R(TextArrayQuickfilterComponent, {
126
- key: JSON.stringify(item),
127
- index,
128
- label,
129
- expr,
130
- schema: this.props.schema,
131
- quickfiltersDataSource: this.props.quickfiltersDataSource,
132
- value: itemValue,
133
- onValueChange,
134
- filters,
135
- multi: item.multi
136
- });
104
+ return react_1.default.createElement(TextArrayQuickfilterComponent, { key: JSON.stringify(item), index: index, label: label, expr: exprsToPass, schema: this.props.schema, quickfiltersDataSource: this.props.quickfiltersDataSource, value: itemValue, onValueChange: onValueChange, filters: filters, multi: item.multi });
137
105
  }
138
106
  return null;
139
107
  }
@@ -141,15 +109,14 @@ class QuickfiltersComponent extends react_1.default.Component {
141
109
  if (!this.props.design || this.props.design.length === 0) {
142
110
  return null;
143
111
  }
144
- return R("div", {
145
- style: {
112
+ return (react_1.default.createElement("div", { style: {
146
113
  borderTop: !this.props.hideTopBorder ? "solid 1px #E8E8E8" : undefined,
147
114
  borderBottom: "solid 1px #E8E8E8",
148
115
  padding: 5
149
- }
150
- }, lodash_1.default.map(this.props.design, (item, i) => this.renderQuickfilter(item, i)), this.props.onHide
151
- ? R("button", { className: "btn btn-sm btn-link", onClick: this.props.onHide }, R("i", { className: "fa fa-angle-double-up" }))
152
- : undefined);
116
+ } },
117
+ lodash_1.default.map(this.props.design, (item, i) => this.renderQuickfilter(item, i)),
118
+ this.props.onHide ? (react_1.default.createElement("button", { className: "btn btn-sm btn-link", onClick: this.props.onHide },
119
+ react_1.default.createElement("i", { className: "fa fa-angle-double-up" }))) : undefined));
153
120
  }
154
121
  }
155
122
  exports.default = QuickfiltersComponent;
@@ -173,37 +140,20 @@ class EnumQuickfilterComponent extends react_1.default.Component {
173
140
  }
174
141
  };
175
142
  renderSingleSelect(options) {
176
- return R(react_select_1.default, {
177
- placeholder: T `All`,
178
- value: lodash_1.default.findWhere(options, { value: this.props.value }) || null,
179
- options,
180
- isClearable: true,
181
- onChange: (value) => {
143
+ return react_1.default.createElement(react_select_1.default, { placeholder: T `All`, value: lodash_1.default.findWhere(options, { value: this.props.value }) || null, options: options, isClearable: true, onChange: (value) => {
182
144
  if (this.props.onValueChange) {
183
145
  return this.handleSingleChange(value?.value);
184
146
  }
185
- },
186
- isDisabled: this.props.onValueChange == null,
187
- styles: {
147
+ }, isDisabled: this.props.onValueChange == null, styles: {
188
148
  // Keep menu above fixed data table headers
189
149
  menu: (style) => lodash_1.default.extend({}, style, { zIndex: 2000 })
190
- }
191
- });
150
+ } });
192
151
  }
193
152
  renderMultiSelect(options) {
194
- return R(react_select_1.default, {
195
- placeholder: T `All`,
196
- value: lodash_1.default.map(this.props.value, (v) => lodash_1.default.find(options, (o) => o.value === v)),
197
- isClearable: true,
198
- isMulti: true,
199
- options,
200
- onChange: this.props.onValueChange ? this.handleMultiChange : undefined,
201
- isDisabled: this.props.onValueChange == null,
202
- styles: {
153
+ return react_1.default.createElement(react_select_1.default, { placeholder: T `All`, value: lodash_1.default.map(this.props.value, (v) => lodash_1.default.find(options, (o) => o.value === v)), isClearable: true, isMulti: true, options: options, onChange: this.props.onValueChange ? this.handleMultiChange : undefined, isDisabled: this.props.onValueChange == null, styles: {
203
154
  // Keep menu above fixed data table headers
204
155
  menu: (style) => lodash_1.default.extend({}, style, { zIndex: 2000 })
205
- }
206
- });
156
+ } });
207
157
  }
208
158
  render() {
209
159
  const options = lodash_1.default.map(this.props.options, (opt) => ({
@@ -214,46 +164,39 @@ class EnumQuickfilterComponent extends react_1.default.Component {
214
164
  let width = lodash_1.default.max(options, (o) => o.label.length)?.label?.length;
215
165
  width = width ? width * 8 + 120 : 280;
216
166
  const minWidth = width > 280 || this.props.multi ? "280px" : `${width}px`;
217
- return R("div", { style: { display: "inline-block", paddingRight: 10 } }, this.props.label ? R("span", { style: { color: "gray" } }, this.props.label + ":\u00a0") : undefined, R("div", { style: { display: "inline-block", minWidth, verticalAlign: "middle" } }, this.props.multi ? this.renderMultiSelect(options) : this.renderSingleSelect(options)), !this.props.onValueChange ? R("i", { className: "text-warning fa fa-fw fa-lock" }) : undefined);
167
+ return (react_1.default.createElement("div", { style: { display: "inline-block", paddingRight: 10 } },
168
+ this.props.label ? react_1.default.createElement("span", { style: { color: "gray" } }, this.props.label + ":\u00a0") : undefined,
169
+ react_1.default.createElement("div", { style: { display: "inline-block", minWidth, verticalAlign: "middle" } }, this.props.multi ? this.renderMultiSelect(options) : this.renderSingleSelect(options)),
170
+ !this.props.onValueChange ? react_1.default.createElement("i", { className: "text-warning fa fa-fw fa-lock" }) : undefined));
218
171
  }
219
172
  }
220
173
  // Quickfilter for a text value
221
174
  class TextQuickfilterComponent extends react_1.default.Component {
222
175
  render() {
223
- return R("div", { style: { display: "inline-block", paddingRight: 10 } }, this.props.label ? R("span", { style: { color: "gray" } }, this.props.label + ":\u00a0") : undefined, R("div", { style: { display: "inline-block", minWidth: "280px", verticalAlign: "middle" } }, R(TextLiteralComponent_1.default, {
224
- value: this.props.value,
225
- onChange: this.props.onValueChange,
226
- schema: this.props.schema,
227
- expr: this.props.expr,
228
- index: this.props.index,
229
- multi: this.props.multi,
230
- quickfiltersDataSource: this.props.quickfiltersDataSource,
231
- filters: this.props.filters
232
- })), !this.props.onValueChange ? R("i", { className: "text-warning fa fa-fw fa-lock" }) : undefined);
176
+ return (react_1.default.createElement("div", { style: { display: "inline-block", paddingRight: 10 } },
177
+ this.props.label ? react_1.default.createElement("span", { style: { color: "gray" } }, this.props.label + ":\u00a0") : undefined,
178
+ react_1.default.createElement("div", { style: { display: "inline-block", minWidth: "280px", verticalAlign: "middle" } },
179
+ react_1.default.createElement(TextLiteralComponent_1.default, { value: this.props.value, onChange: this.props.onValueChange, schema: this.props.schema, expr: this.props.expr, index: this.props.index, multi: this.props.multi, quickfiltersDataSource: this.props.quickfiltersDataSource, filters: this.props.filters })),
180
+ !this.props.onValueChange ? react_1.default.createElement("i", { className: "text-warning fa fa-fw fa-lock" }) : undefined));
233
181
  }
234
182
  }
235
183
  // Quickfilter for a date value
236
184
  class DateQuickfilterComponent extends react_1.default.Component {
237
185
  render() {
238
- return R("div", { style: { display: "inline-block", paddingRight: 10 } }, this.props.label ? R("span", { style: { color: "gray" } }, this.props.label + ":\u00a0") : undefined, R("div", { style: { display: "inline-block", minWidth: "280px", verticalAlign: "middle" } }, R(DateExprComponent_1.default, {
239
- datetime: new expressions_1.ExprUtils(this.props.schema).getExprType(this.props.expr) === "datetime",
240
- value: this.props.value,
241
- onChange: this.props.onValueChange
242
- })), !this.props.onValueChange ? R("i", { className: "text-warning fa fa-fw fa-lock" }) : undefined);
186
+ return (react_1.default.createElement("div", { style: { display: "inline-block", paddingRight: 10 } },
187
+ this.props.label ? react_1.default.createElement("span", { style: { color: "gray" } }, this.props.label + ":\u00a0") : undefined,
188
+ react_1.default.createElement("div", { style: { display: "inline-block", minWidth: "280px", verticalAlign: "middle" } },
189
+ react_1.default.createElement(DateExprComponent_1.default, { datetime: new expressions_1.ExprUtils(this.props.schema).getExprType(this.props.expr) === "datetime", value: this.props.value, onChange: this.props.onValueChange })),
190
+ !this.props.onValueChange ? react_1.default.createElement("i", { className: "text-warning fa fa-fw fa-lock" }) : undefined));
243
191
  }
244
192
  }
245
193
  /** Quickfilter for a text value */
246
194
  class TextArrayQuickfilterComponent extends react_1.default.Component {
247
195
  render() {
248
- return R("div", { style: { display: "inline-block", paddingRight: 10 } }, this.props.label ? R("span", { style: { color: "gray" } }, this.props.label + ":\u00a0") : undefined, R("div", { style: { display: "inline-block", minWidth: "280px", verticalAlign: "middle" } }, R(TextLiteralComponent_1.default, {
249
- value: this.props.value,
250
- onChange: this.props.onValueChange,
251
- schema: this.props.schema,
252
- expr: this.props.expr,
253
- index: this.props.index,
254
- multi: this.props.multi,
255
- quickfiltersDataSource: this.props.quickfiltersDataSource,
256
- filters: this.props.filters
257
- })), !this.props.onValueChange ? R("i", { className: "text-warning fa fa-fw fa-lock" }) : undefined);
196
+ return (react_1.default.createElement("div", { style: { display: "inline-block", paddingRight: 10 } },
197
+ this.props.label ? react_1.default.createElement("span", { style: { color: "gray" } }, this.props.label + ":\u00a0") : undefined,
198
+ react_1.default.createElement("div", { style: { display: "inline-block", minWidth: "280px", verticalAlign: "middle" } },
199
+ react_1.default.createElement(TextLiteralComponent_1.default, { value: this.props.value, onChange: this.props.onValueChange, schema: this.props.schema, expr: this.props.expr, index: this.props.index, multi: this.props.multi, quickfiltersDataSource: this.props.quickfiltersDataSource, filters: this.props.filters })),
200
+ !this.props.onValueChange ? react_1.default.createElement("i", { className: "text-warning fa fa-fw fa-lock" }) : undefined));
258
201
  }
259
202
  }
@@ -1,14 +1,19 @@
1
1
  import React from "react";
2
- import { Schema } from "@mwater/expressions";
2
+ import { Expr, Schema } from "@mwater/expressions";
3
3
  import { JsonQLFilter } from "../JsonQLFilter";
4
4
  import { QuickfiltersDataSource } from "./QuickfiltersDataSource";
5
5
  export interface TextLiteralComponentProps {
6
- value?: any;
7
- onChange?: any;
6
+ value?: string | string[] | null;
7
+ onChange?: (value: string | string[] | null) => void;
8
8
  schema: Schema;
9
9
  /** See QuickfiltersDataSource */
10
10
  quickfiltersDataSource: QuickfiltersDataSource;
11
- expr: any;
11
+ /**
12
+ * One or more expressions whose values should be combined into a single option list.
13
+ * Each subsequent expression represents another quickfilter that is merged with this one.
14
+ * The first expression is the main quickfilter, and the subsequent expressions are merged with it.
15
+ */
16
+ expr: Expr[];
12
17
  index: number;
13
18
  /** true to display multiple values */
14
19
  multi?: boolean;
@@ -19,47 +24,18 @@ export interface TextLiteralComponentProps {
19
24
  * The expression can be type `text` or `text[]`
20
25
  */
21
26
  export default class TextLiteralComponent extends React.Component<TextLiteralComponentProps> {
22
- handleSingleChange: (val: any) => any;
23
- handleMultipleChange: (val: any) => any;
24
- getOptions: (input: any, cb: any) => void;
25
- renderSingle(): React.FunctionComponentElement<{
26
- key: string;
27
- placeholder: string;
28
- value: {
29
- value: any;
30
- label: any;
31
- } | null;
32
- loadOptions: (input: any, cb: any) => void;
33
- onChange: ((val: any) => any) | undefined;
34
- isClearable: boolean;
35
- defaultOptions: boolean;
36
- isDisabled: boolean;
37
- noOptionsMessage: () => string;
38
- styles: {
39
- menu: (style: import("react-select").CSSObjectWithLabel) => import("react-select").CSSObjectWithLabel;
40
- };
41
- }>;
42
- renderMultiple(): React.FunctionComponentElement<{
43
- placeholder: string;
44
- value: {
45
- value: unknown;
46
- label: unknown;
47
- }[] | null;
48
- key: string;
49
- isMulti: boolean;
50
- loadOptions: (input: any, cb: any) => void;
51
- defaultOptions: boolean;
52
- onChange: ((val: any) => any) | undefined;
53
- isClearable: boolean;
54
- isDisabled: boolean;
55
- noOptionsMessage: () => string;
56
- styles: {
57
- menu: (style: import("react-select").CSSObjectWithLabel) => import("react-select").CSSObjectWithLabel;
58
- };
59
- }>;
60
- render(): React.DetailedReactHTMLElement<{
61
- style: {
62
- width: string;
63
- };
64
- }, HTMLElement>;
27
+ handleSingleChange: (val: any) => void | undefined;
28
+ handleMultipleChange: (val: any) => void | undefined;
29
+ /**
30
+ * Load the options for the select. If multiple expressions are supplied, each
31
+ * is queried independently and the union of the results (unique values) is
32
+ * returned.
33
+ */
34
+ getOptions: (input: string, cb: (rows: {
35
+ value: string;
36
+ label: string;
37
+ }[]) => void) => void;
38
+ renderSingle(): React.JSX.Element;
39
+ renderMultiple(): React.JSX.Element;
40
+ render(): React.JSX.Element;
65
41
  }
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const lodash_1 = __importDefault(require("lodash"));
7
7
  const react_1 = __importDefault(require("react"));
8
- const R = react_1.default.createElement;
9
8
  const async_1 = __importDefault(require("react-select/async"));
10
9
  const expressions_1 = require("@mwater/expressions");
11
10
  const expressions_2 = require("@mwater/expressions");
@@ -15,114 +14,118 @@ const expressions_2 = require("@mwater/expressions");
15
14
  class TextLiteralComponent extends react_1.default.Component {
16
15
  handleSingleChange = (val) => {
17
16
  const value = val ? val.value || null : null; // Blank is null
18
- return this.props.onChange(value);
17
+ return this.props.onChange?.(value);
19
18
  };
20
19
  handleMultipleChange = (val) => {
21
20
  const value = val ? lodash_1.default.pluck(val, "value") : [];
22
21
  if (value.length > 0) {
23
- return this.props.onChange(value);
22
+ return this.props.onChange?.(value);
24
23
  }
25
24
  else {
26
- return this.props.onChange(null);
25
+ return this.props.onChange?.(null);
27
26
  }
28
27
  };
28
+ /**
29
+ * Load the options for the select. If multiple expressions are supplied, each
30
+ * is queried independently and the union of the results (unique values) is
31
+ * returned.
32
+ */
29
33
  getOptions = (input, cb) => {
30
- // Determine type of expression
31
- const filters = (this.props.filters || []).slice();
32
- const exprUtils = new expressions_2.ExprUtils(this.props.schema);
33
- const exprType = exprUtils.getExprType(this.props.expr);
34
- // Create query to get matches
35
- const exprCompiler = new expressions_1.ExprCompiler(this.props.schema);
36
- if (!this.props.expr.table) {
34
+ // Normalise to array so we can treat single and multiple uniformly
35
+ const exprs = this.props.expr;
36
+ // Keep the unique set of text values that come back from each expression
37
+ const uniqueValues = new Set();
38
+ // Early exit if no expressions
39
+ if (exprs.length === 0) {
40
+ cb([]);
37
41
  return;
38
42
  }
39
- // Add filter for input (simple if just text)
40
- if (exprType === "text") {
41
- if (input) {
42
- filters.push({
43
- table: this.props.expr.table,
44
- jsonql: {
45
- type: "op",
46
- op: "~*",
47
- exprs: [
48
- exprCompiler.compileExpr({ expr: this.props.expr, tableAlias: "{alias}" }),
49
- escapeRegex(input) // Don't use _.escapeRegExp as adds weird backslashes that postgres doesn't like
50
- ]
51
- }
52
- });
43
+ let remaining = exprs.length;
44
+ // Helper that is called after each async query completes
45
+ const maybeFinish = () => {
46
+ remaining -= 1;
47
+ if (remaining === 0) {
48
+ const result = Array.from(uniqueValues).map((value) => ({ value, label: value }));
49
+ cb(result);
53
50
  }
54
- }
55
- else if (exprType === "text[]") {
56
- // Special filter for text[]
57
- if (input) {
58
- filters.push({
59
- table: "values",
60
- jsonql: {
61
- type: "op",
62
- op: "~*",
63
- exprs: [
64
- { type: "field", tableAlias: "{alias}", column: "value" },
65
- "^" + escapeRegex(input) // Don't use _.escapeRegExp as adds weird backslashes that postgres doesn't like
66
- ]
67
- }
68
- });
51
+ };
52
+ // Execute a query for each expression
53
+ for (let i = 0; i < exprs.length; i++) {
54
+ const expr = exprs[i];
55
+ // Clone base filters for this expression so that each expression gets its own copy
56
+ const filters = (this.props.filters || []).slice();
57
+ const exprUtils = new expressions_2.ExprUtils(this.props.schema);
58
+ const exprType = exprUtils.getExprType(expr);
59
+ // Create query to get matches
60
+ const exprCompiler = new expressions_1.ExprCompiler(this.props.schema);
61
+ const exprTable = exprUtils.getExprTable(expr);
62
+ if (!exprTable) {
63
+ maybeFinish();
64
+ return;
69
65
  }
70
- }
71
- else {
72
- return;
73
- }
74
- // Execute query
75
- this.props.quickfiltersDataSource.getValues(this.props.index, this.props.expr, filters, null, 250, (err, values) => {
76
- if (err) {
66
+ // Add filter for the input text depending on expression type
67
+ if (exprType === "text") {
68
+ if (input) {
69
+ filters.push({
70
+ table: exprTable,
71
+ jsonql: {
72
+ type: "op",
73
+ op: "~*",
74
+ exprs: [
75
+ exprCompiler.compileExpr({ expr, tableAlias: "{alias}" }),
76
+ escapeRegex(input) // Avoid _.escapeRegExp to prevent extra backslashes that Postgres dislikes
77
+ ]
78
+ }
79
+ });
80
+ }
81
+ }
82
+ else if (exprType === "text[]") {
83
+ if (input) {
84
+ filters.push({
85
+ table: "values",
86
+ jsonql: {
87
+ type: "op",
88
+ op: "~*",
89
+ exprs: [
90
+ { type: "field", tableAlias: "{alias}", column: "value" },
91
+ "^" + escapeRegex(input) // Avoid _.escapeRegExp to prevent extra backslashes that Postgres dislikes
92
+ ]
93
+ }
94
+ });
95
+ }
96
+ }
97
+ else {
98
+ // Unsupported type – skip this expression
99
+ maybeFinish();
77
100
  return;
78
101
  }
79
- // Filter null and blank
80
- values = lodash_1.default.filter(values, (value) => value);
81
- return cb(lodash_1.default.map(values, (value) => ({
82
- value,
83
- label: value
84
- })));
85
- });
102
+ // Execute the data source query for this expression
103
+ this.props.quickfiltersDataSource.getValues(this.props.index + i, // Index of this quickfilter in the design
104
+ expr, filters, null, 250, (err, values = []) => {
105
+ if (!err && values) {
106
+ // Filter out null / blank and add to unique set
107
+ lodash_1.default.filter(values, (v) => v).forEach((v) => uniqueValues.add(v));
108
+ }
109
+ maybeFinish();
110
+ });
111
+ }
86
112
  };
87
113
  renderSingle() {
88
114
  const currentValue = this.props.value ? { value: this.props.value, label: this.props.value } : null;
89
- return R(async_1.default, {
90
- key: JSON.stringify(this.props.filters), // Include to force a change when filters change
91
- placeholder: T `All`,
92
- value: currentValue,
93
- loadOptions: this.getOptions,
94
- onChange: this.props.onChange ? this.handleSingleChange : undefined,
95
- isClearable: true,
96
- defaultOptions: true,
97
- isDisabled: this.props.onChange == null,
98
- noOptionsMessage: () => T `Type to search`,
99
- styles: {
115
+ return react_1.default.createElement(async_1.default, { key: JSON.stringify(this.props.filters), placeholder: T `All`, value: currentValue, loadOptions: this.getOptions, onChange: this.props.onChange ? this.handleSingleChange : undefined, isClearable: true, defaultOptions: true, isDisabled: this.props.onChange == null, noOptionsMessage: () => T `Type to search`, styles: {
100
116
  // Keep menu above fixed data table headers
101
117
  menu: (style) => lodash_1.default.extend({}, style, { zIndex: 2000 })
102
- }
103
- });
118
+ } });
104
119
  }
105
120
  renderMultiple() {
106
121
  const currentValue = this.props.value ? lodash_1.default.map(this.props.value, (v) => ({ value: v, label: v })) : null;
107
- return R(async_1.default, {
108
- placeholder: T `All`,
109
- value: currentValue,
110
- key: JSON.stringify(this.props.filters), // Include to force a change when filters change
111
- isMulti: true,
112
- loadOptions: this.getOptions,
113
- defaultOptions: true,
114
- onChange: this.props.onChange ? this.handleMultipleChange : undefined,
115
- isClearable: true,
116
- isDisabled: this.props.onChange == null,
117
- noOptionsMessage: () => T `Type to search`,
118
- styles: {
122
+ return react_1.default.createElement(async_1.default, { placeholder: T `All`, value: currentValue, key: JSON.stringify(this.props.filters), isMulti: true, loadOptions: this.getOptions, defaultOptions: true, onChange: this.props.onChange ? this.handleMultipleChange : undefined, isClearable: true, isDisabled: this.props.onChange == null, noOptionsMessage: () => T `Type to search`, styles: {
119
123
  // Keep menu above fixed data table headers
120
124
  menu: (style) => lodash_1.default.extend({}, style, { zIndex: 2000 })
121
- }
122
- });
125
+ } });
123
126
  }
124
127
  render() {
125
- return R("div", { style: { width: "100%" } }, this.props.multi ? this.renderMultiple() : this.renderSingle());
128
+ return react_1.default.createElement("div", { style: { width: "100%" } }, this.props.multi ? this.renderMultiple() : this.renderSingle());
126
129
  }
127
130
  }
128
131
  exports.default = TextLiteralComponent;
@@ -123,9 +123,11 @@ class MapWidgetComponent extends react_1.default.Component {
123
123
  dropdownItems.push({ label: T `Edit`, icon: "pencil", onClick: this.handleStartEditing });
124
124
  }
125
125
  const handleDesignChange = (d) => this.setState({ transientDesign: d });
126
+ // Only allow single click to edit if there are no layers
127
+ const handleClick = this.props.onDesignChange != null && this.state.editDesign === null && this.props.design.layerViews.length == 0 ? this.handleStartEditing : undefined;
126
128
  // Wrap in a simple widget
127
- return react_1.default.createElement("div", null,
129
+ return (react_1.default.createElement("div", { onClick: handleClick, style: { position: "relative", width: this.props.width } },
128
130
  this.props.onDesignChange != null ? this.renderEditor() : undefined,
129
- react_1.default.createElement(DropdownWidgetComponent_1.default, { width: this.props.width, height: this.props.height, dropdownItems: dropdownItems }, this.renderContent(this.state.transientDesign, handleDesignChange, this.props.width, this.props.height)));
131
+ react_1.default.createElement(DropdownWidgetComponent_1.default, { width: this.props.width, height: this.props.height, dropdownItems: dropdownItems }, this.renderContent(this.state.transientDesign, handleDesignChange, this.props.width, this.props.height))));
130
132
  }
131
133
  }
@@ -10,6 +10,7 @@ export interface ExprItemEditorComponentProps {
10
10
  exprItem: HtmlItemExpr;
11
11
  /** Called with expr item */
12
12
  onChange: (exprItem: HtmlItemExpr) => void;
13
+ /** Optional table that will be filtered to have a single row present. Widget designer should optionally account for this */
13
14
  singleRowTable?: string;
14
15
  }
15
16
  interface ExprItemEditorComponentState {
@@ -22,13 +23,7 @@ export default class ExprItemEditorComponent extends React.Component<ExprItemEdi
22
23
  handleIncludeLabelChange: (value: any) => void;
23
24
  handleLabelTextChange: (ev: any) => void;
24
25
  handleFormatChange: (ev: any) => void;
25
- renderFormat(): React.DetailedReactHTMLElement<{
26
- className: string;
27
- }, HTMLElement> | null;
28
- render(): React.DetailedReactHTMLElement<{
29
- style: {
30
- paddingBottom: number;
31
- };
32
- }, HTMLElement>;
26
+ renderFormat(): React.JSX.Element | null;
27
+ render(): React.JSX.Element;
33
28
  }
34
29
  export {};