@mwater/visualization 5.1.0 → 5.2.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 (101) hide show
  1. package/lib/GlobalFilter.d.ts +13 -0
  2. package/lib/GlobalFilter.js +2 -0
  3. package/lib/MWaterCompleteTableSelectComponent.d.ts +2 -9
  4. package/lib/MWaterContextComponent.d.ts +15 -3
  5. package/lib/MWaterContextComponent.js +38 -13
  6. package/lib/MWaterCustomTablesetListComponent.js +9 -3
  7. package/lib/MWaterGlobalFiltersComponent.d.ts +6 -5
  8. package/lib/MWaterGlobalFiltersComponent.js +4 -4
  9. package/lib/MWaterLoaderComponent.d.ts +12 -2
  10. package/lib/MWaterLoaderComponent.js +9 -1
  11. package/lib/axes/Axis.d.ts +20 -25
  12. package/lib/axes/AxisBuilder.js +9 -7
  13. package/lib/axes/AxisComponent.d.ts +4 -4
  14. package/lib/dashboards/DashboardComponent.d.ts +0 -5
  15. package/lib/dashboards/DashboardComponent.js +2 -29
  16. package/lib/dashboards/DashboardDesign.d.ts +2 -17
  17. package/lib/dashboards/DashboardViewComponent.js +3 -4
  18. package/lib/dashboards/LayoutOptionsComponent.js +4 -3
  19. package/lib/dashboards/SettingsModalComponent.d.ts +4 -15
  20. package/lib/dashboards/SettingsModalComponent.js +24 -38
  21. package/lib/datagrids/DatagridComponent.d.ts +2 -9
  22. package/lib/datagrids/DatagridDataSource.d.ts +3 -3
  23. package/lib/datagrids/DatagridDataSource.js +0 -14
  24. package/lib/datagrids/DatagridDesignerComponent.d.ts +2 -93
  25. package/lib/datagrids/DatagridDesignerComponent.js +8 -6
  26. package/lib/datagrids/DatagridViewComponent.js +1 -1
  27. package/lib/datagrids/FindReplaceModalComponent.d.ts +4 -20
  28. package/lib/datagrids/FindReplaceModalComponent.js +27 -13
  29. package/lib/datagrids/ServerDatagridDataSource.d.ts +1 -1
  30. package/lib/datagrids/ServerDatagridDataSource.js +1 -3
  31. package/lib/demo.js +1 -1
  32. package/lib/index.d.ts +1 -0
  33. package/lib/layouts/blocks/BlocksDisplayComponent.d.ts +2 -1
  34. package/lib/layouts/grid/GridLayoutManager.d.ts +2 -1
  35. package/lib/maps/BufferLayer.js +3 -1
  36. package/lib/maps/ClusterLayer.js +3 -1
  37. package/lib/maps/GridLayer.js +5 -3
  38. package/lib/maps/GridLayerDesigner.js +0 -1
  39. package/lib/maps/LayerSwitcherComponent.js +1 -1
  40. package/lib/maps/MapComponent.d.ts +2 -7
  41. package/lib/maps/MapDesign.d.ts +2 -13
  42. package/lib/maps/MapFiltersDesignerComponent.d.ts +0 -4
  43. package/lib/maps/MapFiltersDesignerComponent.js +4 -5
  44. package/lib/maps/RasterMapViewComponent.d.ts +2 -9
  45. package/lib/maps/RegionSelectComponent.d.ts +2 -1
  46. package/lib/maps/ServerMapDataSource.d.ts +1 -1
  47. package/lib/maps/vectorMaps.d.ts +1 -0
  48. package/lib/maps/vectorMaps.js +10 -2
  49. package/lib/quickfilter/QuickfilterCompiler.d.ts +1 -1
  50. package/lib/widgets/IFrameWidgetComponent.d.ts +2 -9
  51. package/lib/widgets/ImageWidgetComponent.d.ts +6 -24
  52. package/lib/widgets/MapWidget.d.ts +2 -7
  53. package/lib/widgets/MarkdownWidget.d.ts +2 -7
  54. package/lib/widgets/TOCWidget.d.ts +2 -9
  55. package/lib/widgets/charts/ChartWidget.d.ts +3 -15
  56. package/lib/widgets/charts/imagemosaic/ImagePopupComponent.d.ts +2 -7
  57. package/lib/widgets/charts/layered/LayeredChartDesignerComponent.d.ts +2 -31
  58. package/lib/widgets/charts/layered/LayeredChartLayerDesignerComponent.d.ts +2 -7
  59. package/lib/widgets/charts/pivot/IntersectionDesignerComponent.d.ts +73 -66
  60. package/lib/widgets/charts/pivot/PivotChartDesignerComponent.d.ts +10 -6
  61. package/lib/widgets/charts/pivot/PivotChartViewComponent.d.ts +3 -22
  62. package/lib/widgets/charts/pivot/SegmentDesignerComponent.d.ts +55 -58
  63. package/lib/widgets/charts/table/TableChartViewComponent.js +21 -7
  64. package/lib/widgets/text/ExprInsertModalComponent.d.ts +2 -13
  65. package/lib/widgets/text/ExprUpdateModalComponent.d.ts +2 -13
  66. package/lib/widgets/text/TextWidgetDesign.d.ts +3 -1
  67. package/package.json +1 -1
  68. package/src/GlobalFilter.ts +17 -0
  69. package/src/MWaterContextComponent.tsx +37 -19
  70. package/src/MWaterCustomTablesetListComponent.tsx +21 -3
  71. package/src/MWaterGlobalFiltersComponent.ts +8 -8
  72. package/src/MWaterLoaderComponent.ts +8 -1
  73. package/src/axes/Axis.ts +24 -25
  74. package/src/axes/AxisBuilder.ts +9 -8
  75. package/src/dashboards/DashboardComponent.tsx +2 -40
  76. package/src/dashboards/DashboardDesign.ts +2 -22
  77. package/src/dashboards/DashboardViewComponent.ts +4 -5
  78. package/src/dashboards/LayoutOptionsComponent.tsx +6 -4
  79. package/src/dashboards/SettingsModalComponent.tsx +170 -0
  80. package/src/datagrids/DatagridDataSource.ts +6 -12
  81. package/src/datagrids/DatagridDesignerComponent.tsx +22 -18
  82. package/src/datagrids/DatagridViewComponent.ts +3 -3
  83. package/src/datagrids/ExprCellComponent.ts +0 -1
  84. package/src/datagrids/FindReplaceModalComponent.ts +39 -22
  85. package/src/datagrids/ServerDatagridDataSource.ts +1 -2
  86. package/src/demo.ts +1 -1
  87. package/src/index.ts +1 -0
  88. package/src/maps/BufferLayer.ts +3 -1
  89. package/src/maps/ClusterLayer.ts +3 -1
  90. package/src/maps/GridLayer.ts +5 -3
  91. package/src/maps/GridLayerDesigner.tsx +0 -1
  92. package/src/maps/LayerSwitcherComponent.tsx +1 -1
  93. package/src/maps/MapDesign.ts +2 -17
  94. package/src/maps/{MapFiltersDesignerComponent.ts → MapFiltersDesignerComponent.tsx} +25 -25
  95. package/src/maps/ServerMapDataSource.ts +1 -1
  96. package/src/maps/VectorMapViewComponent.tsx +0 -1
  97. package/src/maps/vectorMaps.tsx +10 -1
  98. package/src/quickfilter/QuickfilterCompiler.ts +1 -1
  99. package/src/widgets/charts/table/TableChartViewComponent.ts +21 -7
  100. package/src/widgets/text/TextWidgetDesign.ts +4 -1
  101. package/src/dashboards/SettingsModalComponent.ts +0 -169
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
+ import * as ui from "@mwater/react-library/lib/bootstrap";
2
3
  import { DataSource, Schema } from "@mwater/expressions";
3
4
  export interface PivotChartDesignerComponentProps {
4
5
  design: any;
@@ -25,12 +26,15 @@ export default class PivotChartDesignerComponent extends React.Component<PivotCh
25
26
  className: string;
26
27
  }, HTMLElement> | null;
27
28
  renderStriping(): React.CElement<{
28
- labelMuted: boolean;
29
- label: string;
30
- }, React.Component<{
31
- labelMuted: boolean;
32
- label: string;
33
- }, any, any>> | null;
29
+ label: React.ReactNode;
30
+ labelMuted?: boolean | undefined;
31
+ hint?: React.ReactNode;
32
+ help?: React.ReactNode;
33
+ required?: boolean | undefined;
34
+ hasSuccess?: boolean | undefined;
35
+ hasWarnings?: boolean | undefined;
36
+ hasErrors?: boolean | undefined;
37
+ }, ui.FormGroup> | null;
34
38
  renderSetup(): React.DetailedReactHTMLElement<React.HTMLAttributes<HTMLElement>, HTMLElement>;
35
39
  render(): React.DetailedReactHTMLElement<React.HTMLAttributes<HTMLElement>, HTMLElement>;
36
40
  }
@@ -1,5 +1,6 @@
1
1
  import PropTypes from "prop-types";
2
2
  import React from "react";
3
+ import ActionCancelModalComponent from "@mwater/react-library/lib/ActionCancelModalComponent";
3
4
  import { DataSource, Schema } from "@mwater/expressions";
4
5
  import { JsonQLFilter, WidgetScope } from "../../..";
5
6
  import { PivotChartDesign } from "./PivotChartDesign";
@@ -52,28 +53,8 @@ export default class PivotChartViewComponent extends React.Component<PivotChartV
52
53
  paddingRight: number;
53
54
  };
54
55
  }, HTMLElement>;
55
- renderEditSegmentModal(): React.CElement<{
56
- title: string;
57
- onAction: () => void;
58
- onCancel: () => void;
59
- size: string;
60
- }, React.Component<{
61
- title: string;
62
- onAction: () => void;
63
- onCancel: () => void;
64
- size: string;
65
- }, any, any>> | undefined;
66
- renderEditIntersectionModal(): React.CElement<{
67
- title: string;
68
- onAction: () => void;
69
- onCancel: () => void;
70
- size: string;
71
- }, React.Component<{
72
- title: string;
73
- onAction: () => void;
74
- onCancel: () => void;
75
- size: string;
76
- }, any, any>> | undefined;
56
+ renderEditSegmentModal(): React.CElement<import("@mwater/react-library/lib/ActionCancelModalComponent").ActionCancelModalComponentProps, ActionCancelModalComponent> | undefined;
57
+ renderEditIntersectionModal(): React.CElement<import("@mwater/react-library/lib/ActionCancelModalComponent").ActionCancelModalComponentProps, ActionCancelModalComponent> | undefined;
77
58
  render(): React.DetailedReactHTMLElement<{
78
59
  style: {
79
60
  width: number;
@@ -1,4 +1,5 @@
1
1
  import React from "react";
2
+ import * as ui from "@mwater/react-library/lib/bootstrap";
2
3
  import { DataSource, Schema } from "@mwater/expressions";
3
4
  import { PivotChartSegment } from "./PivotChartDesign";
4
5
  export interface SegmentDesignerComponentProps {
@@ -27,70 +28,66 @@ export default class SegmentDesignerComponent extends React.Component<SegmentDes
27
28
  handleOrderExprChange: (orderExpr: any) => any;
28
29
  handleOrderDirChange: (orderDir: any) => any;
29
30
  renderMode(): React.CElement<{
30
- labelMuted: boolean;
31
- label: string;
32
- }, React.Component<{
33
- labelMuted: boolean;
34
- label: string;
35
- }, any, any>>;
31
+ label: React.ReactNode;
32
+ labelMuted?: boolean | undefined;
33
+ hint?: React.ReactNode;
34
+ help?: React.ReactNode;
35
+ required?: boolean | undefined;
36
+ hasSuccess?: boolean | undefined;
37
+ hasWarnings?: boolean | undefined;
38
+ hasErrors?: boolean | undefined;
39
+ }, ui.FormGroup>;
36
40
  renderLabel(): React.CElement<{
37
- labelMuted: boolean;
38
- label: string;
39
- help: string | undefined;
40
- }, React.Component<{
41
- labelMuted: boolean;
42
- label: string;
43
- help: string | undefined;
44
- }, any, any>>;
41
+ label: React.ReactNode;
42
+ labelMuted?: boolean | undefined;
43
+ hint?: React.ReactNode;
44
+ help?: React.ReactNode;
45
+ required?: boolean | undefined;
46
+ hasSuccess?: boolean | undefined;
47
+ hasWarnings?: boolean | undefined;
48
+ hasErrors?: boolean | undefined;
49
+ }, ui.FormGroup>;
45
50
  renderValueAxis(): React.JSX.Element;
46
51
  renderFilter(): React.CElement<{
47
- labelMuted: boolean;
48
- label: (string | React.CElement<{
49
- id: string;
50
- }, React.Component<{
51
- id: string;
52
- }, any, any>>)[];
53
- hint: string;
54
- }, React.Component<{
55
- labelMuted: boolean;
56
- label: (string | React.CElement<{
57
- id: string;
58
- }, React.Component<{
59
- id: string;
60
- }, any, any>>)[];
61
- hint: string;
62
- }, any, any>>;
52
+ label: React.ReactNode;
53
+ labelMuted?: boolean | undefined;
54
+ hint?: React.ReactNode;
55
+ help?: React.ReactNode;
56
+ required?: boolean | undefined;
57
+ hasSuccess?: boolean | undefined;
58
+ hasWarnings?: boolean | undefined;
59
+ hasErrors?: boolean | undefined;
60
+ }, ui.FormGroup>;
63
61
  renderStyling(): React.CElement<{
64
- labelMuted: boolean;
65
- label: string;
66
- }, React.Component<{
67
- labelMuted: boolean;
68
- label: string;
69
- }, any, any>>;
62
+ label: React.ReactNode;
63
+ labelMuted?: boolean | undefined;
64
+ hint?: React.ReactNode;
65
+ help?: React.ReactNode;
66
+ required?: boolean | undefined;
67
+ hasSuccess?: boolean | undefined;
68
+ hasWarnings?: boolean | undefined;
69
+ hasErrors?: boolean | undefined;
70
+ }, ui.FormGroup>;
70
71
  renderBorders(): React.CElement<{
71
- labelMuted: boolean;
72
- label: string;
73
- }, React.Component<{
74
- labelMuted: boolean;
75
- label: string;
76
- }, any, any>>;
72
+ label: React.ReactNode;
73
+ labelMuted?: boolean | undefined;
74
+ hint?: React.ReactNode;
75
+ help?: React.ReactNode;
76
+ required?: boolean | undefined;
77
+ hasSuccess?: boolean | undefined;
78
+ hasWarnings?: boolean | undefined;
79
+ hasErrors?: boolean | undefined;
80
+ }, ui.FormGroup>;
77
81
  renderOrderExpr(): React.CElement<{
78
- labelMuted: boolean;
79
- label: (string | React.CElement<{
80
- id: string;
81
- }, React.Component<{
82
- id: string;
83
- }, any, any>>)[];
84
- hint: string;
85
- }, React.Component<{
86
- labelMuted: boolean;
87
- label: (string | React.CElement<{
88
- id: string;
89
- }, React.Component<{
90
- id: string;
91
- }, any, any>>)[];
92
- hint: string;
93
- }, any, any>>;
82
+ label: React.ReactNode;
83
+ labelMuted?: boolean | undefined;
84
+ hint?: React.ReactNode;
85
+ help?: React.ReactNode;
86
+ required?: boolean | undefined;
87
+ hasSuccess?: boolean | undefined;
88
+ hasWarnings?: boolean | undefined;
89
+ hasErrors?: boolean | undefined;
90
+ }, ui.FormGroup>;
94
91
  render(): React.DetailedReactHTMLElement<React.HTMLAttributes<HTMLElement>, HTMLElement>;
95
92
  }
96
93
  export {};
@@ -124,7 +124,7 @@ class TableContentsComponent extends react_1.default.Component {
124
124
  }
125
125
  renderImage(id) {
126
126
  const url = this.props.dataSource.getImageUrl(id);
127
- return R("a", { href: url, key: id, target: "_blank", style: { paddingLeft: 5, paddingRight: 5 } }, "Image");
127
+ return R("a", { href: url, onClick: (e) => { e.stopPropagation(); }, key: id, target: "_blank", style: { paddingLeft: 5, paddingRight: 5 } }, "Image");
128
128
  }
129
129
  renderCell(rowIndex, columnIndex) {
130
130
  const axisBuilder = new AxisBuilder_1.default({ schema: this.props.schema });
@@ -162,7 +162,9 @@ class TableContentsComponent extends react_1.default.Component {
162
162
  // Convert to node based on type
163
163
  switch (exprType) {
164
164
  case "text":
165
- node = R(react_linkify_1.default, { properties: { target: "_blank" } }, value);
165
+ if (lodash_1.default.isString(value)) {
166
+ node = R(react_linkify_1.default, { properties: { target: "_blank" } }, value);
167
+ }
166
168
  break;
167
169
  case "number":
168
170
  case "geometry":
@@ -170,21 +172,33 @@ class TableContentsComponent extends react_1.default.Component {
170
172
  break;
171
173
  case "boolean":
172
174
  case "enum":
175
+ node = exprUtils.stringifyExprLiteral(column.textAxis?.expr, value, this.context.locale);
176
+ break;
173
177
  case "enumset":
174
178
  case "text[]":
175
- node = exprUtils.stringifyExprLiteral(column.textAxis?.expr, value, this.context.locale);
179
+ if (lodash_1.default.isArray(value)) {
180
+ node = exprUtils.stringifyExprLiteral(column.textAxis?.expr, value, this.context.locale);
181
+ }
176
182
  break;
177
183
  case "date":
178
- node = (0, valueFormatter_1.formatValue)(exprType, value, column.format);
184
+ if (lodash_1.default.isString(value)) {
185
+ node = (0, valueFormatter_1.formatValue)(exprType, value, column.format);
186
+ }
179
187
  break;
180
188
  case "datetime":
181
- node = (0, valueFormatter_1.formatValue)(exprType, value, column.format);
189
+ if (lodash_1.default.isString(value)) {
190
+ node = (0, valueFormatter_1.formatValue)(exprType, value, column.format);
191
+ }
182
192
  break;
183
193
  case "image":
184
- node = this.renderImage(value.id);
194
+ if (lodash_1.default.isObject(value) && value.id != null) {
195
+ node = this.renderImage(value.id);
196
+ }
185
197
  break;
186
198
  case "imagelist":
187
- node = lodash_1.default.map(value, (v) => this.renderImage(v.id));
199
+ if (lodash_1.default.isArray(value)) {
200
+ node = lodash_1.default.map(value, (v) => this.renderImage(v.id));
201
+ }
188
202
  break;
189
203
  default:
190
204
  node = "" + value;
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { DataSource, Schema } from "@mwater/expressions";
3
+ import ActionCancelModalComponent from "@mwater/react-library/lib/ActionCancelModalComponent";
3
4
  import { HtmlItemExpr } from "../../richtext/ExprItemsHtmlConverter";
4
5
  export interface ExprInsertModalComponentProps {
5
6
  /** Schema to use */
@@ -18,18 +19,6 @@ export default class ExprInsertModalComponent extends React.Component<ExprInsert
18
19
  constructor(props: ExprInsertModalComponentProps);
19
20
  open(): void;
20
21
  handleInsert: () => void;
21
- render(): React.CElement<{
22
- actionLabel: string;
23
- onAction: () => void;
24
- onCancel: () => void;
25
- title: string;
26
- size: string;
27
- }, React.Component<{
28
- actionLabel: string;
29
- onAction: () => void;
30
- onCancel: () => void;
31
- title: string;
32
- size: string;
33
- }, any, any>> | null;
22
+ render(): React.CElement<import("@mwater/react-library/lib/ActionCancelModalComponent").ActionCancelModalComponentProps, ActionCancelModalComponent> | null;
34
23
  }
35
24
  export {};
@@ -1,5 +1,6 @@
1
1
  import React from "react";
2
2
  import { DataSource, Schema } from "@mwater/expressions";
3
+ import ActionCancelModalComponent from "@mwater/react-library/lib/ActionCancelModalComponent";
3
4
  import { HtmlItemExpr } from "../../richtext/ExprItemsHtmlConverter";
4
5
  export interface ExprUpdateModalComponentProps {
5
6
  /** Schema to use */
@@ -16,18 +17,6 @@ interface ExprUpdateModalComponentState {
16
17
  export default class ExprUpdateModalComponent extends React.Component<ExprUpdateModalComponentProps, ExprUpdateModalComponentState> {
17
18
  constructor(props: any);
18
19
  open(item: any, onUpdate: any): void;
19
- render(): React.CElement<{
20
- actionLabel: string;
21
- onAction: () => void;
22
- onCancel: () => void;
23
- title: string;
24
- size: string;
25
- }, React.Component<{
26
- actionLabel: string;
27
- onAction: () => void;
28
- onCancel: () => void;
29
- title: string;
30
- size: string;
31
- }, any, any>> | null;
20
+ render(): React.CElement<import("@mwater/react-library/lib/ActionCancelModalComponent").ActionCancelModalComponentProps, ActionCancelModalComponent> | null;
32
21
  }
33
22
  export {};
@@ -1,6 +1,8 @@
1
+ import { HtmlItemExpr } from "../../richtext/ExprItemsHtmlConverter";
2
+ import { HtmlItem } from "../../richtext/ItemsHtmlConverter";
1
3
  export interface TextWidgetDesign {
2
4
  /** Text widget stores its content as array of items. See ItemsHtmlConverter TODO */
3
- items: any[];
5
+ items: (HtmlItem | HtmlItemExpr)[];
4
6
  /** "title" for title block. default is "default" */
5
7
  style?: "title" | "default";
6
8
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mwater/visualization",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
4
4
  "description": "Visualization library",
5
5
  "main": "lib/index.js",
6
6
  "scripts": {
@@ -0,0 +1,17 @@
1
+ import { Expr, LiteralType } from "@mwater/expressions"
2
+
3
+ /** Global filters apply to multiple tables at once if a certain column is present. User-interface to set them
4
+ * is application-specific and the default (non-mWater) dashboard applies them but does not allow editing. */
5
+ export interface GlobalFilter {
6
+ /** id of column to filter */
7
+ columnId: string
8
+
9
+ /** type of column to filter (to ensure that consistent) */
10
+ columnType: LiteralType
11
+
12
+ /** op of expression for filtering */
13
+ op: string
14
+
15
+ /** array of expressions to use for filtering. field expression for column will be injected as expression 0 in the resulting filter expression */
16
+ exprs: Expr[]
17
+ }
@@ -1,15 +1,33 @@
1
1
  import PropTypes from "prop-types"
2
2
  import _ from "lodash"
3
- import React from "react"
3
+ import React, { createContext } from "react"
4
4
  const R = React.createElement
5
5
 
6
6
  import MWaterTableSelectComponent from "./MWaterTableSelectComponent"
7
7
  import MWaterAddRelatedFormComponent from "./MWaterAddRelatedFormComponent"
8
8
  import MWaterAddRelatedIndicatorComponent from "./MWaterAddRelatedIndicatorComponent"
9
9
  import MWaterGlobalFiltersComponent from "./MWaterGlobalFiltersComponent"
10
- import { Schema, Section } from "@mwater/expressions"
10
+ import { DataSource, Schema, Section } from "@mwater/expressions"
11
11
  import { CustomTableSelectComponentFactoryContext, CustomTableSelectComponentFactoryOptions, DecorateScalarExprTreeSectionChildrenContext, DecorateScalarExprTreeSectionChildrenOptions } from "@mwater/expressions-ui"
12
12
  import { IsScalarExprTreeSectionInitiallyOpenContext, IsScalarExprTreeSectionMatchContext } from "@mwater/expressions-ui"
13
+ import { GlobalFilter } from "./GlobalFilter"
14
+
15
+
16
+ export interface GlobalFiltersElementFactoryProps {
17
+ schema: Schema
18
+ dataSource: DataSource
19
+ filterableTables: string[]
20
+ globalFilters?: GlobalFilter[]
21
+ onChange: (globalFilters: GlobalFilter[]) => void
22
+
23
+ /** If true, return null element if not applicable to filterableTables */
24
+ nullIfIrrelevant?: boolean
25
+ }
26
+
27
+ export type GlobalFiltersElementFactory = (props: GlobalFiltersElementFactoryProps) => React.ReactElement | null
28
+
29
+ export const GlobalFiltersElementFactoryContext = createContext<GlobalFiltersElementFactory | null>(null)
30
+
13
31
 
14
32
  /**
15
33
  * Creates several contexts to allow selecting of a table in an mWater-friendly way
@@ -18,7 +36,7 @@ import { IsScalarExprTreeSectionInitiallyOpenContext, IsScalarExprTreeSectionMat
18
36
  export default class MWaterContextComponent extends React.Component<{
19
37
  apiUrl: string
20
38
  client?: string
21
- /** user id of logged in user */
39
+ /** user id of logged in user */
22
40
  user?: string
23
41
  schema: Schema
24
42
  /** Extra tables to load in schema. Forms are not loaded by default as they are too many */
@@ -30,8 +48,6 @@ export default class MWaterContextComponent extends React.Component<{
30
48
  }> {
31
49
  static childContextTypes = {
32
50
  addLayerElementFactory: PropTypes.func, // Call with props of AddLayerComponent
33
- globalFiltersElementFactory: PropTypes.func, // Call with props { schema, dataSource, filterableTables, globalFilters, onChange, nullIfIrrelevant }.
34
- // Displays a component to edit global filters. nullIfIrrelevant causes null element if not applicable to filterableTables
35
51
  }
36
52
 
37
53
  createTableSelectElementFactory = (options: CustomTableSelectComponentFactoryOptions) => {
@@ -58,15 +74,15 @@ export default class MWaterContextComponent extends React.Component<{
58
74
  context.addLayerElementFactory = this.props.addLayerElementFactory
59
75
  }
60
76
 
61
- context.globalFiltersElementFactory = (props: any) => {
62
- if (props.nullIfIrrelevant && !_.any(props.filterableTables, (t: string) => t.match(/^entities./))) {
63
- return null
64
- }
77
+ return context
78
+ }
65
79
 
66
- return React.createElement(MWaterGlobalFiltersComponent, props)
80
+ createGlobalFiltersElementFactory = (props: GlobalFiltersElementFactoryProps) => {
81
+ if (props.nullIfIrrelevant && !_.any(props.filterableTables, (t: string) => t.match(/^entities./))) {
82
+ return null
67
83
  }
68
84
 
69
- return context
85
+ return <MWaterGlobalFiltersComponent {...props} />
70
86
  }
71
87
 
72
88
  isScalarExprTreeSectionMatch = (options: { tableId: string; section: Section; filter?: string }) => {
@@ -128,13 +144,15 @@ export default class MWaterContextComponent extends React.Component<{
128
144
 
129
145
  render() {
130
146
  return <CustomTableSelectComponentFactoryContext.Provider value={this.createTableSelectElementFactory}>
131
- <IsScalarExprTreeSectionMatchContext.Provider value={this.isScalarExprTreeSectionMatch}>
132
- <IsScalarExprTreeSectionInitiallyOpenContext.Provider value={this.isScalarExprTreeSectionInitiallyOpen}>
133
- <DecorateScalarExprTreeSectionChildrenContext.Provider value={this.decorateScalarExprTreeSectionChildren}>
134
- {this.props.children}
135
- </DecorateScalarExprTreeSectionChildrenContext.Provider>
136
- </IsScalarExprTreeSectionInitiallyOpenContext.Provider>
137
- </IsScalarExprTreeSectionMatchContext.Provider>
138
- </CustomTableSelectComponentFactoryContext.Provider>
147
+ <GlobalFiltersElementFactoryContext.Provider value={this.createGlobalFiltersElementFactory}>
148
+ <IsScalarExprTreeSectionMatchContext.Provider value={this.isScalarExprTreeSectionMatch}>
149
+ <IsScalarExprTreeSectionInitiallyOpenContext.Provider value={this.isScalarExprTreeSectionInitiallyOpen}>
150
+ <DecorateScalarExprTreeSectionChildrenContext.Provider value={this.decorateScalarExprTreeSectionChildren}>
151
+ {this.props.children}
152
+ </DecorateScalarExprTreeSectionChildrenContext.Provider>
153
+ </IsScalarExprTreeSectionInitiallyOpenContext.Provider>
154
+
155
+ </IsScalarExprTreeSectionMatchContext.Provider>
156
+ </GlobalFiltersElementFactoryContext.Provider> </CustomTableSelectComponentFactoryContext.Provider>
139
157
  }
140
158
  }
@@ -27,14 +27,19 @@ export const MWaterCustomTablesetListComponent = (props: {
27
27
  const [search, setSearch] = useState<string | null>("")
28
28
  const [extraTableNeeded, setExtraTableNeeded] = useState<string>()
29
29
 
30
+ const [showSystem, setShowSystem] = useState(false)
31
+
30
32
  // Get list of all tablesets
31
33
  useEffect(() => {
32
34
  fetch(`${props.apiUrl}custom_tablesets?client=${props.client || ""}`)
33
35
  .then((response) => response.json())
34
- .then((body) => {
36
+ .then((tablesets) => {
37
+ // Filter out non-normal
38
+ tablesets = tablesets.filter((ts: CustomTableset) => ts.type === "normal")
39
+
35
40
  // Put included ones first
36
41
  setTablesets(
37
- _.sortByAll(body, [
42
+ _.sortByAll(tablesets, [
38
43
  (ts) => (props.extraTables.some((t) => (t || "").startsWith(`custom.${ts.code}.`)) ? 0 : 1),
39
44
  (ts) => ExprUtils.localizeString(ts.design.name, props.locale)
40
45
  ])
@@ -117,10 +122,17 @@ export const MWaterCustomTablesetListComponent = (props: {
117
122
  )
118
123
  }
119
124
 
125
+ const visibleTablesets = tablesets.filter((ts) => (showSystem || !ts.design.system) && !ts.design.deprecated)
126
+
120
127
  return (
121
128
  <div>
122
129
  <TextInput value={search} onChange={setSearch} placeholder="Search..." />
123
- {tablesets.map((ts) => renderTableset(ts))}
130
+ {visibleTablesets.map((ts) => renderTableset(ts))}
131
+ <div>
132
+ <button className="btn btn-link btn-sm" onClick={() => setShowSystem(!showSystem)}>
133
+ {showSystem ? "Hide system tables" : "Show system tables"}
134
+ </button>
135
+ </div>
124
136
  </div>
125
137
  )
126
138
  }
@@ -137,5 +149,11 @@ interface CustomTableset {
137
149
  desc?: LocalizedString
138
150
 
139
151
  tables: Table[]
152
+
153
+ /** True if tableset is deprecated */
154
+ deprecated?: boolean
155
+
156
+ /** True if tableset is for system use and should only be visible to admins in the UI */
157
+ system?: boolean
140
158
  }
141
159
  }
@@ -2,19 +2,19 @@ import _ from "lodash"
2
2
  import React from "react"
3
3
  const R = React.createElement
4
4
 
5
- import querystring from "querystring"
6
5
  import * as ui from "@mwater/react-library/lib/bootstrap"
7
6
  import { IdLiteralComponent } from "@mwater/expressions-ui"
8
7
  import { DataSource, Schema } from "@mwater/expressions"
8
+ import { GlobalFilter } from "./GlobalFilter"
9
9
 
10
10
  export interface MWaterGlobalFiltersComponentProps {
11
11
  /** Schema of the database */
12
12
  schema: Schema
13
13
  /** Data source to use to get values */
14
14
  dataSource: DataSource
15
- filterableTables: any
16
- globalFilters?: any
17
- onChange: any
15
+ filterableTables: string[]
16
+ globalFilters?: GlobalFilter[]
17
+ onChange: (globalFilters: GlobalFilter[]) => void
18
18
  }
19
19
 
20
20
  // Control to edit the global filters (_managed_by and admin_region)
@@ -36,7 +36,7 @@ export default class MWaterGlobalFiltersComponent extends React.Component<MWater
36
36
  })
37
37
  }
38
38
 
39
- return this.props.onChange(globalFilters)
39
+ this.props.onChange(globalFilters)
40
40
  }
41
41
 
42
42
  handleManagedByChange = (managedBy: any) => {
@@ -56,13 +56,13 @@ export default class MWaterGlobalFiltersComponent extends React.Component<MWater
56
56
  })
57
57
  }
58
58
 
59
- return this.props.onChange(globalFilters)
59
+ this.props.onChange(globalFilters)
60
60
  }
61
61
 
62
62
  render() {
63
63
  // Find managed by
64
64
  let adminRegions, managedBy
65
- const managedByEntry = _.find(this.props.globalFilters, (gf) => gf.op === "within" && gf.columnId === "_managed_by")
65
+ const managedByEntry = _.find(this.props.globalFilters || [], (gf) => gf.op === "within" && gf.columnId === "_managed_by")
66
66
  if (managedByEntry) {
67
67
  managedBy = managedByEntry.exprs[0].value.split(":")[1]
68
68
  } else {
@@ -71,7 +71,7 @@ export default class MWaterGlobalFiltersComponent extends React.Component<MWater
71
71
 
72
72
  // Find admin region
73
73
  const adminRegionEntry = _.find(
74
- this.props.globalFilters,
74
+ this.props.globalFilters || [],
75
75
  (gf) => gf.op === "within any" && gf.columnId === "admin_region"
76
76
  )
77
77
  if (adminRegionEntry) {
@@ -79,7 +79,14 @@ export default class MWaterLoaderComponent extends AsyncLoadComponent<
79
79
  if (error) {
80
80
  const defaultError = `Cannot load one of the forms that this depends on. Perhaps the administrator has not shared the form with you? Details: ${error.message}`
81
81
  if (this.props.errorFormatter) {
82
- return callback({ error: this.props.errorFormatter(JSON.parse(error.message), defaultError) })
82
+ try {
83
+ const parsedError = JSON.parse(error.message)
84
+ if (parsedError) {
85
+ return callback({ error: this.props.errorFormatter(parsedError, defaultError) })
86
+ }
87
+ } catch (e) {
88
+ // Ignore
89
+ }
83
90
  }
84
91
  return callback({ error: defaultError })
85
92
  }