@mwater/visualization 5.4.4 → 5.5.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 (136) hide show
  1. package/.storybook/head.html +0 -1
  2. package/lib/MWaterContextComponent.js +1 -1
  3. package/lib/MWaterLoaderComponent.d.ts +2 -2
  4. package/lib/dashboards/DashboardComponent.js +2 -1
  5. package/lib/dashboards/LayoutOptionsComponent.js +18 -11
  6. package/lib/dashboards/ServerDashboardDataSource.d.ts +10 -1
  7. package/lib/dashboards/ServerDashboardDataSource.js +29 -0
  8. package/lib/dashboards/layoutOptions.d.ts +5 -1
  9. package/lib/datagrids/DatagridComponent.js +1 -1
  10. package/lib/datagrids/ExprCellComponent.d.ts +1 -0
  11. package/lib/datagrids/ExprCellComponent.js +22 -20
  12. package/lib/maps/BufferLayer.d.ts +18 -0
  13. package/lib/maps/BufferLayer.js +24 -14
  14. package/lib/maps/ChoroplethLayer.d.ts +18 -0
  15. package/lib/maps/ChoroplethLayer.js +34 -25
  16. package/lib/maps/ChoroplethLayerDesign.d.ts +3 -2
  17. package/lib/maps/ChoroplethLayerDesigner.d.ts +11 -1
  18. package/lib/maps/DirectMapDataSource.js +17 -0
  19. package/lib/maps/EditHoverOver.d.ts +1 -1
  20. package/lib/maps/EditHoverOver.js +62 -33
  21. package/lib/maps/HoverContent.d.ts +10 -5
  22. package/lib/maps/HoverContent.js +6 -35
  23. package/lib/maps/Layer.d.ts +37 -0
  24. package/lib/maps/Layer.js +30 -4
  25. package/lib/maps/MWaterServerLayer.d.ts +2 -2
  26. package/lib/maps/MWaterServerLayer.js +6 -6
  27. package/lib/maps/MapLayerDataSource.d.ts +9 -0
  28. package/lib/maps/MapUtils.d.ts +19 -1
  29. package/lib/maps/MapUtils.js +71 -1
  30. package/lib/maps/MarkersLayer.d.ts +18 -0
  31. package/lib/maps/MarkersLayer.js +24 -24
  32. package/lib/maps/MarkersLayerDesignerComponent.d.ts +14 -1
  33. package/lib/maps/RasterMapViewComponent.js +1 -1
  34. package/lib/maps/ServerMapDataSource.d.ts +9 -0
  35. package/lib/maps/ServerMapDataSource.js +29 -0
  36. package/lib/maps/VectorMapViewComponent.js +6 -6
  37. package/lib/maps/maps.d.ts +4 -2
  38. package/lib/mwater_table_selection/FormsListComponent.d.ts +33 -0
  39. package/lib/mwater_table_selection/FormsListComponent.js +141 -0
  40. package/lib/mwater_table_selection/IndicatorsListComponent.d.ts +47 -0
  41. package/lib/mwater_table_selection/IndicatorsListComponent.js +182 -0
  42. package/lib/mwater_table_selection/IssuesListComponent.d.ts +29 -0
  43. package/lib/mwater_table_selection/IssuesListComponent.js +123 -0
  44. package/lib/mwater_table_selection/MWaterAccountingSystemListComponent.d.ts +20 -0
  45. package/lib/mwater_table_selection/MWaterAccountingSystemListComponent.js +157 -0
  46. package/lib/mwater_table_selection/MWaterAssetSystemsListComponent.d.ts +17 -0
  47. package/lib/mwater_table_selection/MWaterAssetSystemsListComponent.js +79 -0
  48. package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.d.ts +37 -0
  49. package/lib/mwater_table_selection/MWaterCompleteTableSelectComponent.js +275 -0
  50. package/lib/mwater_table_selection/MWaterCustomTablesetListComponent.d.ts +17 -0
  51. package/lib/mwater_table_selection/MWaterCustomTablesetListComponent.js +94 -0
  52. package/lib/mwater_table_selection/MWaterMetricsTableListComponent.d.ts +17 -0
  53. package/lib/mwater_table_selection/MWaterMetricsTableListComponent.js +80 -0
  54. package/lib/mwater_table_selection/MWaterTableSelectComponent.d.ts +32 -0
  55. package/lib/mwater_table_selection/MWaterTableSelectComponent.js +158 -0
  56. package/lib/quickfilter/Quickfilter.d.ts +2 -0
  57. package/lib/quickfilter/QuickfiltersDesignComponent.js +18 -10
  58. package/lib/widgets/charts/Chart.d.ts +11 -0
  59. package/lib/widgets/charts/Chart.js +15 -0
  60. package/lib/widgets/charts/ChartWidgetComponent.d.ts +1 -0
  61. package/lib/widgets/charts/ChartWidgetComponent.js +27 -1
  62. package/lib/widgets/charts/layered/LayeredChartDesign.d.ts +1 -1
  63. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.d.ts +1 -1
  64. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.js +5 -12
  65. package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.d.ts +43 -57
  66. package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.js +113 -110
  67. package/lib/widgets/charts/layered/LayeredChartUtils.d.ts +2 -1
  68. package/lib/widgets/charts/layered/LayeredChartUtils.js +0 -2
  69. package/lib/widgets/charts/pivot/PivotChart.d.ts +2 -0
  70. package/lib/widgets/charts/pivot/PivotChart.js +156 -0
  71. package/lib/widgets/charts/pivot/PivotChartDesignerComponent.d.ts +5 -20
  72. package/lib/widgets/charts/pivot/PivotChartDesignerComponent.js +31 -61
  73. package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.d.ts +4 -0
  74. package/lib/widgets/charts/pivot/PivotChartLayoutBuilder.js +4 -2
  75. package/lib/widgets/charts/pivot/PivotChartLayoutComponent.d.ts +5 -44
  76. package/lib/widgets/charts/pivot/PivotChartLayoutComponent.js +38 -63
  77. package/lib/widgets/charts/pivot/SegmentDesignerComponent.d.ts +7 -68
  78. package/lib/widgets/charts/pivot/SegmentDesignerComponent.js +58 -106
  79. package/lib/widgets/charts/table/TableChart.d.ts +2 -0
  80. package/lib/widgets/charts/table/TableChart.js +172 -1
  81. package/lib/widgets/charts/table/TableChartDesignerComponent.d.ts +7 -17
  82. package/lib/widgets/charts/table/TableChartDesignerComponent.js +79 -95
  83. package/lib/widgets/charts/table/TableChartViewComponent.d.ts +1 -7
  84. package/lib/widgets/charts/table/TableChartViewComponent.js +19 -27
  85. package/package.json +3 -8
  86. package/src/MWaterContextComponent.tsx +1 -1
  87. package/src/MWaterLoaderComponent.ts +1 -1
  88. package/src/dashboards/DashboardComponent.tsx +2 -1
  89. package/src/dashboards/LayoutOptionsComponent.tsx +22 -10
  90. package/src/dashboards/ServerDashboardDataSource.ts +36 -1
  91. package/src/dashboards/layoutOptions.tsx +5 -1
  92. package/src/datagrids/DatagridComponent.tsx +1 -1
  93. package/src/datagrids/ExprCellComponent.tsx +23 -20
  94. package/src/maps/BufferLayer.ts +35 -20
  95. package/src/maps/ChoroplethLayer.ts +51 -33
  96. package/src/maps/ChoroplethLayerDesign.ts +3 -2
  97. package/src/maps/ChoroplethLayerDesigner.tsx +2 -2
  98. package/src/maps/DirectMapDataSource.ts +21 -1
  99. package/src/maps/EditHoverOver.tsx +91 -51
  100. package/src/maps/HoverContent.tsx +16 -47
  101. package/src/maps/Layer.ts +42 -4
  102. package/src/maps/MWaterServerLayer.ts +6 -6
  103. package/src/maps/MapLayerDataSource.ts +8 -0
  104. package/src/maps/MapUtils.ts +70 -3
  105. package/src/maps/MarkersLayer.ts +34 -24
  106. package/src/maps/RasterMapViewComponent.ts +1 -1
  107. package/src/maps/ServerMapDataSource.ts +35 -0
  108. package/src/maps/VectorMapViewComponent.tsx +6 -6
  109. package/src/maps/maps.ts +4 -2
  110. package/src/mwater_table_selection/FormsListComponent.tsx +188 -0
  111. package/src/mwater_table_selection/IndicatorsListComponent.tsx +283 -0
  112. package/src/mwater_table_selection/IssuesListComponent.tsx +167 -0
  113. package/src/mwater_table_selection/MWaterAccountingSystemListComponent.tsx +225 -0
  114. package/src/{MWaterAssetSystemsListComponent.tsx → mwater_table_selection/MWaterAssetSystemsListComponent.tsx} +2 -2
  115. package/src/mwater_table_selection/MWaterCompleteTableSelectComponent.tsx +377 -0
  116. package/src/{MWaterCustomTablesetListComponent.tsx → mwater_table_selection/MWaterCustomTablesetListComponent.tsx} +1 -1
  117. package/src/{MWaterMetricsTableListComponent.tsx → mwater_table_selection/MWaterMetricsTableListComponent.tsx} +1 -1
  118. package/src/{MWaterTableSelectComponent.tsx → mwater_table_selection/MWaterTableSelectComponent.tsx} +83 -86
  119. package/src/quickfilter/Quickfilter.ts +3 -0
  120. package/src/quickfilter/QuickfiltersDesignComponent.tsx +19 -14
  121. package/src/widgets/charts/Chart.ts +17 -0
  122. package/src/widgets/charts/ChartWidgetComponent.tsx +36 -1
  123. package/src/widgets/charts/layered/LayeredChartDesign.ts +1 -1
  124. package/src/widgets/charts/layered/LayeredChartDesignerComponent.tsx +23 -24
  125. package/src/widgets/charts/layered/LayeredChartLayerDesignerComponent.tsx +260 -211
  126. package/src/widgets/charts/layered/LayeredChartUtils.ts +7 -7
  127. package/src/widgets/charts/pivot/PivotChart.ts +191 -0
  128. package/src/widgets/charts/pivot/PivotChartDesignerComponent.tsx +124 -129
  129. package/src/widgets/charts/pivot/PivotChartLayoutBuilder.ts +4 -2
  130. package/src/widgets/charts/pivot/PivotChartLayoutComponent.tsx +120 -149
  131. package/src/widgets/charts/pivot/SegmentDesignerComponent.tsx +178 -198
  132. package/src/widgets/charts/table/TableChart.ts +177 -1
  133. package/src/widgets/charts/table/TableChartDesignerComponent.tsx +422 -0
  134. package/src/widgets/charts/table/{TableChartViewComponent.ts → TableChartViewComponent.tsx} +65 -60
  135. package/src/MWaterCompleteTableSelectComponent.tsx +0 -975
  136. package/src/widgets/charts/table/TableChartDesignerComponent.ts +0 -441
@@ -182,6 +182,35 @@ class ServerLayerDataSource {
182
182
  }
183
183
  return url;
184
184
  }
185
+ /** Gets hover over data for hover over items
186
+ * @param design The design of the layer
187
+ * @param data The data of the current item being hovered over. e.g. { id: 123 }
188
+ * @param filters The filters to apply to the layer does not include filters that narrow down to a specific item
189
+ * @returns A promise that resolves to the hover over data, indexed by the id of the hover over item
190
+ */
191
+ async getHoverOverData(design, data, filters) {
192
+ const query = {
193
+ client: this.options.client,
194
+ share: this.options.share,
195
+ filters: (0, compressJson_1.default)(filters || []),
196
+ data: (0, compressJson_1.default)(data),
197
+ rev: this.options.rev
198
+ };
199
+ const url = `${this.options.apiUrl}maps/${this.options.mapId}/layers/${this.options.layerView.id}/hoverdata?` +
200
+ querystring_1.default.stringify(query);
201
+ const response = await fetch(url, {
202
+ method: "GET",
203
+ headers: {
204
+ Accept: "application/json"
205
+ }
206
+ });
207
+ if (!response.ok) {
208
+ const errorText = await response.text();
209
+ console.error(errorText);
210
+ throw new Error(`Error fetching hover data: ${response.statusText}`);
211
+ }
212
+ return await response.json();
213
+ }
185
214
  }
186
215
  class ServerMapLayerPopupWidgetDataSource {
187
216
  options;
@@ -66,7 +66,7 @@ function VectorMapViewComponent(props) {
66
66
  const [legendHidden, setLegendHidden] = (0, react_1.useState)(initialLegendDisplay == "closed" || (props.width < 500 && initialLegendDisplay == "closedIfSmall"));
67
67
  // Locale to use
68
68
  const locale = props.locale || props.design.locale || "en";
69
- // Translate function to use TODO
69
+ // Translate function to use
70
70
  const translate = props.translate || ((input) => input);
71
71
  // Last feature that mouse entered
72
72
  const lastFeature = (0, react_2.useRef)();
@@ -424,12 +424,12 @@ function VectorMapViewComponent(props) {
424
424
  return;
425
425
  }
426
426
  if (!props.design.autoBounds && props.design.bounds) {
427
- // If we set the new bounds, do not update map bounds
427
+ // If we set the new bounds, do not update map bounds unless they differ by more than 0.0001 degrees (roughly 10m)
428
428
  if (boundsRef.current == null ||
429
- props.design.bounds.n != boundsRef.current.n ||
430
- props.design.bounds.e != boundsRef.current.e ||
431
- props.design.bounds.s != boundsRef.current.s ||
432
- props.design.bounds.w != boundsRef.current.w) {
429
+ Math.abs(props.design.bounds.n - boundsRef.current.n) > 0.0001 ||
430
+ Math.abs(props.design.bounds.e - boundsRef.current.e) > 0.0001 ||
431
+ Math.abs(props.design.bounds.s - boundsRef.current.s) > 0.0001 ||
432
+ Math.abs(props.design.bounds.w - boundsRef.current.w) > 0.0001) {
433
433
  map.fitBounds([props.design.bounds.w, props.design.bounds.s, props.design.bounds.e, props.design.bounds.n]);
434
434
  boundsRef.current = props.design.bounds;
435
435
  }
@@ -1,5 +1,6 @@
1
1
  import { JsonQLQuery } from "@mwater/jsonql";
2
2
  import { Expr } from "@mwater/expressions";
3
+ import { ReactNode } from "react";
3
4
  export interface LayerDefinition {
4
5
  layers: Array<{
5
6
  /** Layer id */
@@ -16,6 +17,7 @@ export interface LayerDefinition {
16
17
  fields: string[];
17
18
  };
18
19
  }
20
+ /** Results from onGridClick that can be used to display a popup */
19
21
  export type OnGridClickResults = {
20
22
  scope?: any;
21
23
  row?: {
@@ -24,9 +26,9 @@ export type OnGridClickResults = {
24
26
  };
25
27
  popup?: React.ReactElement<{}>;
26
28
  } | null;
29
+ /** Results from onGridHover that can be used to display a hover over */
27
30
  export type OnGridHoverResults = {
28
- scope?: any;
29
- hoverOver?: React.ReactElement<{}>;
31
+ hoverOver?: ReactNode;
30
32
  } | null;
31
33
  /** Item in hover over */
32
34
  export interface HoverOverItem {
@@ -0,0 +1,33 @@
1
+ import React from "react";
2
+ import { Schema } from "@mwater/expressions";
3
+ interface FormsListComponentProps {
4
+ /** Url to hit api */
5
+ apiUrl: string;
6
+ /** Optional client */
7
+ client?: string;
8
+ schema: Schema;
9
+ /** User id */
10
+ user?: string;
11
+ /** Called with table selected */
12
+ onChange: any;
13
+ extraTables: any;
14
+ onExtraTableAdd: any;
15
+ onExtraTableRemove: any;
16
+ }
17
+ interface FormsListComponentState {
18
+ error?: any;
19
+ search: any;
20
+ forms: {
21
+ id: string;
22
+ name: string;
23
+ desc?: string;
24
+ }[] | null;
25
+ }
26
+ export declare class FormsListComponent extends React.Component<FormsListComponentProps, FormsListComponentState> {
27
+ constructor(props: any);
28
+ componentDidMount(): void;
29
+ handleTableRemove: (table: any) => any;
30
+ searchRef: (comp: any) => any;
31
+ render(): React.JSX.Element;
32
+ }
33
+ export {};
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.FormsListComponent = void 0;
30
+ const lodash_1 = __importDefault(require("lodash"));
31
+ const jquery_1 = __importDefault(require("jquery"));
32
+ const react_1 = __importDefault(require("react"));
33
+ const querystring_1 = __importDefault(require("querystring"));
34
+ const uiComponents = __importStar(require("../UIComponents"));
35
+ const expressions_1 = require("@mwater/expressions");
36
+ const moment_1 = __importDefault(require("moment"));
37
+ // Searchable list of forms
38
+ class FormsListComponent extends react_1.default.Component {
39
+ constructor(props) {
40
+ super(props);
41
+ this.state = {
42
+ forms: null,
43
+ search: ""
44
+ };
45
+ }
46
+ componentDidMount() {
47
+ // Get names and basic of forms
48
+ const query = {};
49
+ query.fields = JSON.stringify({
50
+ "design.name": 1,
51
+ "design.description": 1,
52
+ roles: 1,
53
+ created: 1,
54
+ modified: 1,
55
+ state: 1,
56
+ isMaster: 1
57
+ });
58
+ query.selector = JSON.stringify({ design: { $exists: true }, state: { $ne: "deleted" } });
59
+ query.client = this.props.client;
60
+ // Get list of all form names
61
+ jquery_1.default.getJSON(this.props.apiUrl + "forms?" + querystring_1.default.stringify(query), (forms) => {
62
+ // Sort by modified.on desc but first by user
63
+ forms = lodash_1.default.sortByOrder(forms, [
64
+ (form) => ((this.props.extraTables || []).includes("responses:" + form._id) ? 1 : 0),
65
+ (form) => (form.created.by === this.props.user ? 1 : 0),
66
+ (form) => form.modified?.on
67
+ ], ["desc", "desc", "desc"]);
68
+ // TODO use name instead of design.name
69
+ this.setState({
70
+ forms: lodash_1.default.map(forms, (form) => {
71
+ let desc = expressions_1.ExprUtils.localizeString(form.design.description, null) || "";
72
+ if (desc) {
73
+ desc += " - ";
74
+ }
75
+ desc += T `Modified ${(0, moment_1.default)(form.modified?.on, moment_1.default.ISO_8601).format("ll")}`;
76
+ return {
77
+ id: form._id,
78
+ name: expressions_1.ExprUtils.localizeString(form.design.name, null),
79
+ desc
80
+ };
81
+ })
82
+ });
83
+ }).fail((xhr) => {
84
+ this.setState({ error: xhr.responseText });
85
+ });
86
+ }
87
+ handleTableRemove = (table) => {
88
+ if (confirm(T `Remove ${expressions_1.ExprUtils.localizeString(table.name, T.locale)}? Any widgets that depend on it will no longer work properly.`)) {
89
+ return this.props.onExtraTableRemove(table.id);
90
+ }
91
+ };
92
+ searchRef = (comp) => {
93
+ // Focus
94
+ if (comp) {
95
+ return comp.focus();
96
+ }
97
+ };
98
+ render() {
99
+ let forms;
100
+ if (this.state.error) {
101
+ return react_1.default.createElement("div", { className: "alert alert-danger" }, this.state.error);
102
+ }
103
+ // Filter forms
104
+ if (this.state.search) {
105
+ const escapeRegExp = (s) => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
106
+ const searchStringRegExp = new RegExp(escapeRegExp(this.state.search), "i");
107
+ forms = lodash_1.default.filter(this.state.forms, (form) => form.name.match(searchStringRegExp));
108
+ }
109
+ else {
110
+ ;
111
+ ({ forms } = this.state);
112
+ }
113
+ // Remove if already included
114
+ forms = lodash_1.default.filter(forms || [], (f) => !(this.props.extraTables || []).includes(`responses:${f.id}`));
115
+ let tables = lodash_1.default.filter(this.props.schema.getTables(), (table) => (table.id.match(/^responses:/) || table.id.match(/^master_responses:/)) && !table.deprecated);
116
+ tables = lodash_1.default.sortBy(tables, (t) => t.name.en);
117
+ return (react_1.default.createElement("div", null,
118
+ react_1.default.createElement("label", null, T `Included Surveys:`),
119
+ tables.length > 0 ? (react_1.default.createElement(uiComponents.OptionListComponent, { items: lodash_1.default.map(tables, (table) => {
120
+ return {
121
+ name: expressions_1.ExprUtils.localizeString(table.name, T.locale),
122
+ desc: expressions_1.ExprUtils.localizeString(table.desc, T.locale),
123
+ onClick: this.props.onChange.bind(null, table.id),
124
+ onRemove: this.handleTableRemove.bind(null, table)
125
+ };
126
+ }) })) : (react_1.default.createElement("div", null, T `None`)),
127
+ react_1.default.createElement("br", null),
128
+ react_1.default.createElement("label", null, T `All Surveys:`),
129
+ !this.state.forms || this.state.forms.length === 0 ? (react_1.default.createElement("div", { className: "alert alert-info" },
130
+ react_1.default.createElement("i", { className: "fa fa-spinner fa-spin" }),
131
+ "\u00A0",
132
+ T `Loading...`)) : (react_1.default.createElement(react_1.default.Fragment, null,
133
+ react_1.default.createElement("input", { type: "text", className: "form-control form-control-sm", placeholder: T `Search...`, key: "search", ref: this.searchRef, style: { maxWidth: "20em", marginBottom: 10 }, value: this.state.search, onChange: (ev) => this.setState({ search: ev.target.value }) }),
134
+ react_1.default.createElement(uiComponents.OptionListComponent, { items: lodash_1.default.map(forms, (form) => ({
135
+ name: form.name,
136
+ desc: form.desc,
137
+ onClick: this.props.onChange.bind(null, "responses:" + form.id)
138
+ })) })))));
139
+ }
140
+ }
141
+ exports.FormsListComponent = FormsListComponent;
@@ -0,0 +1,47 @@
1
+ import React from "react";
2
+ import { Schema } from "@mwater/expressions";
3
+ interface IndicatorsListComponentProps {
4
+ /** Url to hit api */
5
+ apiUrl: string;
6
+ /** Optional client */
7
+ client?: string;
8
+ schema: Schema;
9
+ /** User id */
10
+ user?: string;
11
+ /** Called with table selected */
12
+ onChange: any;
13
+ extraTables: any;
14
+ onExtraTableAdd: any;
15
+ onExtraTableRemove: any;
16
+ }
17
+ interface IndicatorsListComponentState {
18
+ error?: any;
19
+ search: any;
20
+ indicators: any[] | null;
21
+ }
22
+ export declare class IndicatorsListComponent extends React.Component<IndicatorsListComponentProps, IndicatorsListComponentState> {
23
+ addIndicatorConfirmPopup: AddIndicatorConfirmPopupComponent | null;
24
+ constructor(props: any);
25
+ componentDidMount(): JQuery.jqXHR<any>;
26
+ handleTableRemove: (table: any) => any;
27
+ searchRef: (comp: any) => any;
28
+ handleSelect: (tableId: any) => void;
29
+ render(): React.JSX.Element;
30
+ }
31
+ interface AddIndicatorConfirmPopupComponentProps {
32
+ schema: Schema;
33
+ /** Called with table selected */
34
+ onChange: any;
35
+ onExtraTableAdd: any;
36
+ }
37
+ interface AddIndicatorConfirmPopupComponentState {
38
+ indicatorTable: any;
39
+ visible: any;
40
+ }
41
+ declare class AddIndicatorConfirmPopupComponent extends React.Component<AddIndicatorConfirmPopupComponentProps, AddIndicatorConfirmPopupComponentState> {
42
+ constructor(props: any);
43
+ show(indicatorTable: any): void;
44
+ renderContents(): React.JSX.Element;
45
+ render(): React.JSX.Element | null;
46
+ }
47
+ export {};
@@ -0,0 +1,182 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.IndicatorsListComponent = void 0;
30
+ const lodash_1 = __importDefault(require("lodash"));
31
+ const jquery_1 = __importDefault(require("jquery"));
32
+ const react_1 = __importDefault(require("react"));
33
+ const querystring_1 = __importDefault(require("querystring"));
34
+ const uiComponents = __importStar(require("../UIComponents"));
35
+ const expressions_1 = require("@mwater/expressions");
36
+ const ModalPopupComponent_1 = __importDefault(require("@mwater/react-library/lib/ModalPopupComponent"));
37
+ // Searchable list of indicators
38
+ class IndicatorsListComponent extends react_1.default.Component {
39
+ addIndicatorConfirmPopup;
40
+ constructor(props) {
41
+ super(props);
42
+ this.state = {
43
+ indicators: null,
44
+ search: ""
45
+ };
46
+ }
47
+ componentDidMount() {
48
+ // Get names and basic of forms
49
+ const query = {};
50
+ query.fields = JSON.stringify({ "design.name": 1, "design.desc": 1, "design.recommended": 1, deprecated: 1 });
51
+ query.client = this.props.client;
52
+ // Get list of all indicator names
53
+ return jquery_1.default.getJSON(this.props.apiUrl + "indicators?" + querystring_1.default.stringify(query), (indicators) => {
54
+ // Remove deprecated
55
+ indicators = lodash_1.default.filter(indicators, (indicator) => !indicator.deprecated);
56
+ // Sort by name
57
+ indicators = lodash_1.default.sortByOrder(indicators, [
58
+ (indicator) => ((this.props.extraTables || []).includes("indicator_values:" + indicator._id) ? 0 : 1),
59
+ (indicator) => (indicator.design.recommended ? 0 : 1),
60
+ (indicator) => expressions_1.ExprUtils.localizeString(indicator.design.name, T.locale)
61
+ ], ["asc", "asc", "asc"]);
62
+ return this.setState({
63
+ indicators: lodash_1.default.map(indicators, (indicator) => ({
64
+ id: indicator._id,
65
+ name: expressions_1.ExprUtils.localizeString(indicator.design.name, T.locale),
66
+ desc: expressions_1.ExprUtils.localizeString(indicator.design.desc, T.locale)
67
+ }))
68
+ });
69
+ }).fail((xhr) => {
70
+ return this.setState({ error: xhr.responseText });
71
+ });
72
+ }
73
+ handleTableRemove = (table) => {
74
+ if (confirm(T `Remove ${expressions_1.ExprUtils.localizeString(table.name, T.locale)}? Any widgets that depend on it will no longer work properly.`)) {
75
+ return this.props.onExtraTableRemove(table.id);
76
+ }
77
+ };
78
+ searchRef = (comp) => {
79
+ // Focus
80
+ if (comp) {
81
+ return comp.focus();
82
+ }
83
+ };
84
+ handleSelect = (tableId) => {
85
+ // Add table if not present
86
+ if (!this.props.schema.getTable(tableId)) {
87
+ this.props.onExtraTableAdd(tableId);
88
+ }
89
+ this.addIndicatorConfirmPopup.show(tableId);
90
+ };
91
+ render() {
92
+ let indicators;
93
+ if (this.state.error) {
94
+ return react_1.default.createElement("div", { className: "alert alert-danger" }, this.state.error);
95
+ }
96
+ // Filter indicators
97
+ if (this.state.search) {
98
+ const escapeRegExp = (s) => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
99
+ const searchStringRegExp = new RegExp(escapeRegExp(this.state.search), "i");
100
+ indicators = lodash_1.default.filter(this.state.indicators || [], (indicator) => indicator.name.match(searchStringRegExp));
101
+ }
102
+ else {
103
+ ;
104
+ ({ indicators } = this.state);
105
+ }
106
+ // Remove if already included
107
+ indicators = lodash_1.default.filter(indicators || [], (f) => !(this.props.extraTables || []).includes(`indicator_values:${f.id}`));
108
+ let tables = lodash_1.default.filter(this.props.schema.getTables(), (table) => table.id.match(/^indicator_values:/) && !table.deprecated);
109
+ tables = lodash_1.default.sortBy(tables, (t) => t.name.en);
110
+ return (react_1.default.createElement("div", null,
111
+ react_1.default.createElement(AddIndicatorConfirmPopupComponent, { schema: this.props.schema, onChange: this.props.onChange, onExtraTableAdd: this.props.onExtraTableAdd, ref: (c) => {
112
+ this.addIndicatorConfirmPopup = c;
113
+ } }),
114
+ react_1.default.createElement("label", null, T `Included Indicators:`),
115
+ tables.length > 0 ? (react_1.default.createElement(uiComponents.OptionListComponent, { items: lodash_1.default.map(tables, (table) => {
116
+ return {
117
+ name: expressions_1.ExprUtils.localizeString(table.name, T.locale),
118
+ desc: expressions_1.ExprUtils.localizeString(table.desc, T.locale),
119
+ onClick: this.handleSelect.bind(null, table.id),
120
+ onRemove: this.handleTableRemove.bind(null, table)
121
+ };
122
+ }) })) : (react_1.default.createElement("div", null, T `None`)),
123
+ react_1.default.createElement("br", null),
124
+ react_1.default.createElement("label", null, T `All Indicators:`),
125
+ !this.state.indicators || this.state.indicators.length === 0 ? (react_1.default.createElement("div", { className: "alert alert-info" },
126
+ react_1.default.createElement("i", { className: "fa fa-spinner fa-spin" }),
127
+ "\u00A0",
128
+ T `Loading...`)) : (react_1.default.createElement(react_1.default.Fragment, null,
129
+ react_1.default.createElement("input", { type: "text", className: "form-control form-control-sm", placeholder: T `Search...`, key: "search", ref: this.searchRef, style: { maxWidth: "20em", marginBottom: 10 }, value: this.state.search, onChange: (ev) => this.setState({ search: ev.target.value }) }),
130
+ react_1.default.createElement(uiComponents.OptionListComponent, { items: lodash_1.default.map(indicators, (indicator) => ({
131
+ name: indicator.name,
132
+ desc: indicator.desc,
133
+ onClick: this.handleSelect.bind(null, "indicator_values:" + indicator.id)
134
+ })) })))));
135
+ }
136
+ }
137
+ exports.IndicatorsListComponent = IndicatorsListComponent;
138
+ class AddIndicatorConfirmPopupComponent extends react_1.default.Component {
139
+ constructor(props) {
140
+ super(props);
141
+ this.state = {
142
+ visible: false,
143
+ indicatorTable: null
144
+ };
145
+ }
146
+ show(indicatorTable) {
147
+ return this.setState({ visible: true, indicatorTable });
148
+ }
149
+ renderContents() {
150
+ // Show loading if table not loaded
151
+ if (!this.props.schema.getTable(this.state.indicatorTable)) {
152
+ return (react_1.default.createElement("div", { className: "alert alert-info" },
153
+ react_1.default.createElement("i", { className: "fa fa-spinner fa-spin" }),
154
+ "\u00A0",
155
+ T `Loading...`));
156
+ }
157
+ // Find entity links
158
+ const entityColumns = lodash_1.default.filter(this.props.schema.getColumns(this.state.indicatorTable), (col) => col.join?.toTable?.match(/^entities\./));
159
+ return (react_1.default.createElement("div", null,
160
+ react_1.default.createElement("p", null, T `In general, it is better to get indicator values from the related site. Please select the site
161
+ below, then find the indicator values in the 'Related Indicators' section. Or click on 'Use Raw Indicator' if you
162
+ are certain that you want to use the raw indicator table`),
163
+ react_1.default.createElement(uiComponents.OptionListComponent, { items: lodash_1.default.map(entityColumns, (entityColumn) => ({
164
+ name: expressions_1.ExprUtils.localizeString(entityColumn.name, T.locale),
165
+ desc: expressions_1.ExprUtils.localizeString(entityColumn.desc, T.locale),
166
+ onClick: () => {
167
+ // Select table
168
+ this.props.onChange(entityColumn.join.toTable);
169
+ return this.setState({ visible: false });
170
+ }
171
+ })) }),
172
+ react_1.default.createElement("br", null),
173
+ react_1.default.createElement("div", null,
174
+ react_1.default.createElement("a", { className: "link-plain", onClick: this.props.onChange.bind(null, this.state.indicatorTable) }, T `Use Raw Indicator`))));
175
+ }
176
+ render() {
177
+ if (!this.state.visible) {
178
+ return null;
179
+ }
180
+ return (react_1.default.createElement(ModalPopupComponent_1.default, { showCloseX: true, onClose: () => this.setState({ visible: false }), header: T `Add Indicator` }, this.renderContents()));
181
+ }
182
+ }
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ import { Schema } from "@mwater/expressions";
3
+ interface IssuesListComponentProps {
4
+ /** Url to hit api */
5
+ apiUrl: string;
6
+ /** Optional client */
7
+ client?: string;
8
+ schema: Schema;
9
+ /** User id */
10
+ user?: string;
11
+ /** Called with table selected */
12
+ onChange: any;
13
+ extraTables: any;
14
+ onExtraTableAdd: any;
15
+ onExtraTableRemove: any;
16
+ }
17
+ interface IssuesListComponentState {
18
+ error?: any;
19
+ search: any;
20
+ issueTypes: any[] | null;
21
+ }
22
+ export declare class IssuesListComponent extends React.Component<IssuesListComponentProps, IssuesListComponentState> {
23
+ constructor(props: any);
24
+ componentDidMount(): JQuery.jqXHR<any>;
25
+ handleTableRemove: (table: any) => any;
26
+ searchRef: (comp: any) => any;
27
+ render(): React.JSX.Element;
28
+ }
29
+ export {};
@@ -0,0 +1,123 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ Object.defineProperty(exports, "__esModule", { value: true });
29
+ exports.IssuesListComponent = void 0;
30
+ const lodash_1 = __importDefault(require("lodash"));
31
+ const jquery_1 = __importDefault(require("jquery"));
32
+ const react_1 = __importDefault(require("react"));
33
+ const querystring_1 = __importDefault(require("querystring"));
34
+ const uiComponents = __importStar(require("../UIComponents"));
35
+ const expressions_1 = require("@mwater/expressions");
36
+ // Searchable list of issue types
37
+ class IssuesListComponent extends react_1.default.Component {
38
+ constructor(props) {
39
+ super(props);
40
+ this.state = {
41
+ issueTypes: null,
42
+ search: ""
43
+ };
44
+ }
45
+ componentDidMount() {
46
+ // Get names and basic of issueTypes
47
+ const query = {};
48
+ query.fields = JSON.stringify({ name: 1, desc: 1, roles: 1, created: 1, modified: 1 });
49
+ query.client = this.props.client;
50
+ // Get list of all issueType names
51
+ return jquery_1.default.getJSON(this.props.apiUrl + "issue_types?" + querystring_1.default.stringify(query), (issueTypes) => {
52
+ // Sort by modified.on desc but first by user
53
+ issueTypes = lodash_1.default.sortByOrder(issueTypes, [
54
+ (issueType) => ((this.props.extraTables || []).includes("issues:" + issueType._id) ? 0 : 1),
55
+ (issueType) => (issueType.created.by === this.props.user ? 0 : 1),
56
+ (issueType) => expressions_1.ExprUtils.localizeString(issueType.name, T.locale)
57
+ ], ["asc", "asc", "asc"]);
58
+ return this.setState({
59
+ issueTypes: lodash_1.default.map(issueTypes, (issueType) => ({
60
+ id: issueType._id,
61
+ name: expressions_1.ExprUtils.localizeString(issueType.name, T.locale),
62
+ desc: expressions_1.ExprUtils.localizeString(issueType.desc, T.locale)
63
+ }))
64
+ });
65
+ }).fail((xhr) => {
66
+ return this.setState({ error: xhr.responseText });
67
+ });
68
+ }
69
+ handleTableRemove = (table) => {
70
+ if (confirm(T `Remove ${expressions_1.ExprUtils.localizeString(table.name, T.locale)}? Any widgets that depend on it will no longer work properly.`)) {
71
+ return this.props.onExtraTableRemove(table.id);
72
+ }
73
+ };
74
+ searchRef = (comp) => {
75
+ // Focus
76
+ if (comp) {
77
+ return comp.focus();
78
+ }
79
+ };
80
+ render() {
81
+ let issueTypes;
82
+ if (this.state.error) {
83
+ return react_1.default.createElement("div", { className: "alert alert-danger" }, this.state.error);
84
+ }
85
+ // Filter issueTypes
86
+ if (this.state.search) {
87
+ const escapeRegExp = (s) => s.replace(/[-\/\\^$*+?.()|[\]{}]/g, "\\$&");
88
+ const searchStringRegExp = new RegExp(escapeRegExp(this.state.search), "i");
89
+ issueTypes = lodash_1.default.filter(this.state.issueTypes || [], (issueType) => issueType.name.match(searchStringRegExp));
90
+ }
91
+ else {
92
+ ;
93
+ ({ issueTypes } = this.state);
94
+ }
95
+ // Remove if already included
96
+ issueTypes = lodash_1.default.filter(issueTypes || [], (f) => !(this.props.extraTables || []).includes(`issues:${f.id}`));
97
+ let tables = lodash_1.default.filter(this.props.schema.getTables(), (table) => (table.id.match(/^issues:/) || table.id.match(/^issue_events:/)) && !table.deprecated);
98
+ tables = lodash_1.default.sortBy(tables, (t) => t.name.en);
99
+ return (react_1.default.createElement("div", null,
100
+ react_1.default.createElement("label", null, T `Included Issues:`),
101
+ tables.length > 0 ? (react_1.default.createElement(uiComponents.OptionListComponent, { items: lodash_1.default.map(tables, (table) => {
102
+ return {
103
+ name: expressions_1.ExprUtils.localizeString(table.name, T.locale),
104
+ desc: expressions_1.ExprUtils.localizeString(table.desc, T.locale),
105
+ onClick: this.props.onChange.bind(null, table.id),
106
+ onRemove: this.handleTableRemove.bind(null, table)
107
+ };
108
+ }) })) : (react_1.default.createElement("div", null, T `None`)),
109
+ react_1.default.createElement("br", null),
110
+ react_1.default.createElement("label", null, T `All Issues:`),
111
+ !this.state.issueTypes || this.state.issueTypes.length === 0 ? (react_1.default.createElement("div", { className: "alert alert-info" },
112
+ react_1.default.createElement("i", { className: "fa fa-spinner fa-spin" }),
113
+ "\u00A0",
114
+ T `Loading...`)) : (react_1.default.createElement(react_1.default.Fragment, null,
115
+ react_1.default.createElement("input", { type: "text", className: "form-control form-control-sm", placeholder: T `Search...`, key: "search", ref: this.searchRef, style: { maxWidth: "20em", marginBottom: 10 }, value: this.state.search, onChange: (ev) => this.setState({ search: ev.target.value }) }),
116
+ react_1.default.createElement(uiComponents.OptionListComponent, { items: lodash_1.default.map(issueTypes, (issueType) => ({
117
+ name: issueType.name,
118
+ desc: issueType.desc,
119
+ onClick: this.props.onChange.bind(null, "issues:" + issueType.id)
120
+ })) })))));
121
+ }
122
+ }
123
+ exports.IssuesListComponent = IssuesListComponent;