@truedat/dd 4.53.0 → 4.53.2

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.
package/CHANGELOG.md CHANGED
@@ -1,7 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.53.2] 2022-10-07
4
+
5
+ ### Changed
6
+
7
+ - [TD-5226] Use `useOperators` hook to load operators
8
+
9
+ ## [4.53.1] 2022-10-05
10
+
11
+ ### Changed
12
+
13
+ - [TD-5098] Improve modifiers behaviour
14
+ - Fix field type selector for StructureFieldsDrowdown
15
+ - Fix fields applied modifiers for StructureFieldsDrowdown
16
+ - Allow multiple modifiers in ruleImplementationOperators reducer
17
+
3
18
  ## [4.52.5] 2022-09-30
4
19
 
20
+ ### Added
21
+
5
22
  - [TD-2430] Add join type selection when defining an implementation dataset
6
23
 
7
24
  ## [4.52.3] 2022-09-22
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dd",
3
- "version": "4.53.0",
3
+ "version": "4.53.2",
4
4
  "description": "Truedat Web Data Dictionary",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -34,7 +34,7 @@
34
34
  "@testing-library/jest-dom": "^5.16.4",
35
35
  "@testing-library/react": "^12.0.0",
36
36
  "@testing-library/user-event": "^13.2.1",
37
- "@truedat/test": "4.53.0",
37
+ "@truedat/test": "4.53.2",
38
38
  "babel-jest": "^28.1.0",
39
39
  "babel-plugin-dynamic-import-node": "^2.3.3",
40
40
  "babel-plugin-lodash": "^3.3.4",
@@ -88,9 +88,9 @@
88
88
  },
89
89
  "dependencies": {
90
90
  "@apollo/client": "^3.6.4",
91
- "@truedat/auth": "4.53.0",
92
- "@truedat/core": "4.53.0",
93
- "@truedat/df": "4.53.0",
91
+ "@truedat/auth": "4.53.2",
92
+ "@truedat/core": "4.53.2",
93
+ "@truedat/df": "4.53.2",
94
94
  "lodash": "^4.17.21",
95
95
  "path-to-regexp": "^1.7.0",
96
96
  "prop-types": "^15.8.1",
@@ -112,5 +112,5 @@
112
112
  "react-dom": ">= 16.8.6 < 17",
113
113
  "semantic-ui-react": ">= 0.88.2 < 2.1"
114
114
  },
115
- "gitHead": "c13d72dea3b93ba4f21b455dc2aaf9f289261dd3"
115
+ "gitHead": "e29af66624aad6ecce065ced88c8cc2e320d67e2"
116
116
  }
@@ -57,42 +57,47 @@ export const StructureFieldsDropdown = ({
57
57
  : field?.type === "reference_dataset_field"
58
58
  ? `${field.name}/${field.parent_index}`
59
59
  : `${field.data_structure_id}/${field.parent_index}`;
60
- const modifier = _.find({ sourceType: field.field_type })(
60
+ const modifiers = _.filter({ sourceType: field.field_type })(
61
61
  typeCastModifiers
62
62
  );
63
- if (modifier) {
64
- return {
65
- key: value,
66
- text: `${field.name} (${formatMessage({
67
- id: `filtersGrid.field.modifier.${modifier.name}`,
68
- })})`,
69
- modifier,
70
- value: value,
71
- icon: formatMessage({
72
- id: `field_type.icon.${field.field_type}`,
73
- defaultMessage: "hashtag",
74
- }),
75
- };
76
- }
77
-
78
- return {
79
- key: value,
80
- text: field.name,
63
+ const fieldsWithModifiers = _.map((modifier) => ({
64
+ key: `${value}#${modifier.name}`,
65
+ text: `${field.name} (${formatMessage({
66
+ id: `filtersGrid.field.modifier.${modifier.name}`,
67
+ })})`,
68
+ modifier,
81
69
  value: value,
82
70
  icon: formatMessage({
83
71
  id: `field_type.icon.${field.field_type}`,
84
72
  defaultMessage: "hashtag",
85
73
  }),
86
- };
74
+ }))(modifiers);
75
+
76
+ const rawField =
77
+ _.isEmpty(modifiers) || field.field_type === modifiers[0].type
78
+ ? [
79
+ {
80
+ key: value,
81
+ text: field.name,
82
+ value: value,
83
+ icon: formatMessage({
84
+ id: `field_type.icon.${field.field_type}`,
85
+ defaultMessage: "hashtag",
86
+ }),
87
+ },
88
+ ]
89
+ : [];
90
+
91
+ return rawField.concat(fieldsWithModifiers);
87
92
  };
88
93
  const toFieldOption = (field) =>
89
94
  _.has("options")(field)
90
95
  ? {
91
96
  icon: field?.isReferenceDataset ? "list ol" : "table",
92
97
  label: field.label,
93
- options: _.map(formatOption)(field.options),
98
+ options: _.flow(_.map(formatOption), _.flatten)(field.options),
94
99
  }
95
- : formatOption(field);
100
+ : _.flatten(formatOption(field));
96
101
 
97
102
  const getOptions = _.flow(
98
103
  _.sortBy(_.flow(_.prop("name"), _.toLower)),
@@ -3,7 +3,6 @@ import _ from "lodash/fp";
3
3
  import React, { useState, useEffect } from "react";
4
4
  import { Link, useLocation, useHistory } from "react-router-dom";
5
5
  import PropTypes from "prop-types";
6
- import { bindActionCreators } from "redux";
7
6
  import { connect } from "react-redux";
8
7
  import { useIntl } from "react-intl";
9
8
  import {
@@ -16,9 +15,10 @@ import {
16
15
  Grid,
17
16
  Form,
18
17
  } from "semantic-ui-react";
18
+ import { Loading } from "@truedat/core/components";
19
+ import { useOperators } from "@truedat/core/hooks";
19
20
  import { GRANTS_REQUESTS_CHECKOUT, STRUCTURES } from "@truedat/core/routes";
20
21
  import { FiltersGrid } from "@truedat/dq/components/ruleImplementationForm/FiltersGrid";
21
- import { getRuleImplementationOperators } from "@truedat/dq/selectors/getRuleImplementationOperators";
22
22
  import {
23
23
  removeGrantRequestFromCart,
24
24
  updateGrantRequestFilter,
@@ -142,22 +142,24 @@ StructureGrantCart.propTypes = {
142
142
  updateGrantRequestFilter: PropTypes.func,
143
143
  };
144
144
 
145
- const mapStateToProps = (state) => {
146
- const { structure, grantRequestsCart, userPermissions } = state;
147
- return {
148
- structure,
149
- grantRequestsCart,
150
- authorized: _.pathOr(false, "request_grant")(userPermissions),
151
- typeOperators: getRuleImplementationOperators(state),
152
- };
145
+ export const StructureGrantCartLoader = (props) => {
146
+ const { data, error, loading } = useOperators();
147
+ if (error) return null;
148
+ if (loading) return <Loading />;
149
+ return <StructureGrantCart typeOperators={data} {...props} />;
153
150
  };
154
- const mapDispatchToProps = (dispatch) =>
155
- bindActionCreators(
156
- {
157
- removeGrantRequestFromCart,
158
- updateGrantRequestFilter,
159
- },
160
- dispatch
161
- );
162
151
 
163
- export default connect(mapStateToProps, mapDispatchToProps)(StructureGrantCart);
152
+ export const mapStateToProps = ({
153
+ structure,
154
+ grantRequestsCart,
155
+ userPermissions,
156
+ }) => ({
157
+ structure,
158
+ grantRequestsCart,
159
+ authorized: _.pathOr(false, "request_grant")(userPermissions),
160
+ });
161
+
162
+ export default connect(mapStateToProps, {
163
+ removeGrantRequestFromCart,
164
+ updateGrantRequestFilter,
165
+ })(StructureGrantCartLoader);
@@ -0,0 +1,181 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import { render } from "@truedat/test/render";
4
+ import StructureFieldsDropdown from "../StructureFieldsDropdown";
5
+ import en from "../../messages/en";
6
+
7
+ const renderOpts = {
8
+ messages: {
9
+ en: {
10
+ ...en,
11
+ "filtersGrid.field.modifier.cast_as_date": "Cast as date",
12
+ "filtersGrid.field.modifier.to_timestamp": "Cast as timestamp",
13
+ "filtersGrid.field.modifier.cast_as_date.format": "Date format",
14
+ "filtersGrid.field.modifier.to_string": "To string",
15
+ "filtersGrid.field.modifier.to_real_string": "To real string",
16
+ "filtersGrid.field.modifier.substring": "Substring",
17
+ "filtersGrid.field.modifier.substring.start": "String start position",
18
+ "filtersGrid.field.modifier.substring.end": "String end position",
19
+ "structureFields.dropdown.placeholder": "Fields",
20
+ },
21
+ },
22
+ };
23
+
24
+ const parentStructures = [
25
+ {
26
+ external_id: "postgres://postgres/td_audit/public/notifications",
27
+ id: 4801143,
28
+ name: "notifications",
29
+ type: "Table",
30
+ alias: {
31
+ index: 1,
32
+ },
33
+ },
34
+ ];
35
+
36
+ const structureFields = [
37
+ {
38
+ data_structure_id: 4801152,
39
+ metadata: {
40
+ data_type_class: "number",
41
+ },
42
+ name: "id",
43
+ type: "Column",
44
+ label: "notifications",
45
+ parent_index: 1,
46
+ field_type: "number",
47
+ },
48
+ {
49
+ data_structure_id: 4801144,
50
+ metadata: {
51
+ data_type_class: "number",
52
+ },
53
+ name: "subscription_id",
54
+ type: "Column",
55
+ label: "notifications",
56
+ parent_index: 1,
57
+ field_type: "number",
58
+ },
59
+ {
60
+ data_structure_id: 4801145,
61
+ metadata: {
62
+ data_type_class: "timestamp",
63
+ },
64
+ name: "inserted_at",
65
+ type: "Column",
66
+ label: "notifications",
67
+ parent_index: 1,
68
+ field_type: "timestamp",
69
+ },
70
+ {
71
+ data_structure_id: 5732893,
72
+ metadata: {
73
+ data_type_class: "array",
74
+ },
75
+ name: "recipient_ids",
76
+ type: "Column",
77
+ label: "notifications",
78
+ parent_index: 1,
79
+ field_type: "string",
80
+ },
81
+ ];
82
+
83
+ const commonProps = {
84
+ multiple: false,
85
+ label: "Value",
86
+ inline: false,
87
+ parentStructures,
88
+ structureFields,
89
+ typeCastModifiers: [],
90
+ filters: {
91
+ field_type: ["string"],
92
+ },
93
+ };
94
+
95
+ const getEnabledOptions = ({ getAllByRole }) =>
96
+ _.flow(
97
+ getAllByRole,
98
+ _.reject((i) => i.className.includes("disabled")),
99
+ _.map((i) => i.textContent)
100
+ )("option");
101
+
102
+ describe("<StructureFieldsDropdown />", () => {
103
+ it("matches the latest snapshot for empty typeCastModifiers", async () => {
104
+ const props = { ...commonProps };
105
+ const component = render(
106
+ <StructureFieldsDropdown {...props} />,
107
+ renderOpts
108
+ );
109
+ const { container } = component;
110
+ const expectedOptions = ["recipient_ids"];
111
+ expect(container).toMatchSnapshot();
112
+ expect(getEnabledOptions(component)).toEqual(expectedOptions);
113
+ });
114
+
115
+ it("matches the latest snapshot for root fields of number type", async () => {
116
+ const props = {
117
+ ...commonProps,
118
+ filters: {
119
+ field_type: ["number"],
120
+ },
121
+ };
122
+ const component = render(
123
+ <StructureFieldsDropdown {...props} />,
124
+ renderOpts
125
+ );
126
+ const { container } = component;
127
+ const expectedOptions = ["id", "subscription_id"];
128
+ expect(container).toMatchSnapshot();
129
+ expect(getEnabledOptions(component)).toEqual(expectedOptions);
130
+ });
131
+
132
+ it("matches the latest snapshot for one typeCastModifiers of type string", async () => {
133
+ const props = {
134
+ ...commonProps,
135
+ typeCastModifiers: [
136
+ {
137
+ name: "to_real_string",
138
+ type: "string",
139
+ params: [],
140
+ sourceType: "string",
141
+ },
142
+ ],
143
+ };
144
+ const component = render(
145
+ <StructureFieldsDropdown {...props} />,
146
+ renderOpts
147
+ );
148
+ const { container } = component;
149
+ const expectedOptions = ["recipient_ids", "recipient_ids (To real string)"];
150
+ expect(container).toMatchSnapshot();
151
+ expect(getEnabledOptions(component)).toEqual(expectedOptions);
152
+ });
153
+
154
+ it("matches the latest snapshot for one typeCastModifiers of type timestamp", async () => {
155
+ const props = {
156
+ ...commonProps,
157
+ typeCastModifiers: [
158
+ {
159
+ name: "to_timestamp",
160
+ type: "timestamp",
161
+ params: [],
162
+ sourceType: "string",
163
+ },
164
+ ],
165
+ filters: {
166
+ field_type: ["timestamp"],
167
+ },
168
+ };
169
+ const component = render(
170
+ <StructureFieldsDropdown {...props} />,
171
+ renderOpts
172
+ );
173
+ const { container } = component;
174
+ const expectedOptions = [
175
+ "inserted_at",
176
+ "recipient_ids (Cast as timestamp)",
177
+ ];
178
+ expect(container).toMatchSnapshot();
179
+ expect(getEnabledOptions(component)).toEqual(expectedOptions);
180
+ });
181
+ });
@@ -0,0 +1,370 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`<StructureFieldsDropdown /> matches the latest snapshot for empty typeCastModifiers 1`] = `
4
+ <div>
5
+ <label>
6
+ Value
7
+ </label>
8
+ <div
9
+ aria-expanded="false"
10
+ class="ui search dropdown selection"
11
+ label="Value"
12
+ role="combobox"
13
+ >
14
+ <input
15
+ aria-autocomplete="list"
16
+ autocomplete="off"
17
+ class="search"
18
+ tabindex="0"
19
+ type="text"
20
+ value=""
21
+ />
22
+ <div
23
+ aria-atomic="true"
24
+ aria-live="polite"
25
+ class="divider default text"
26
+ role="alert"
27
+ >
28
+ Fields
29
+ </div>
30
+ <i
31
+ aria-hidden="true"
32
+ class="dropdown icon"
33
+ />
34
+ <div
35
+ aria-multiselectable="false"
36
+ class="menu transition"
37
+ role="listbox"
38
+ >
39
+ <div
40
+ aria-checked="false"
41
+ aria-disabled="true"
42
+ aria-selected="false"
43
+ class="disabled item"
44
+ role="option"
45
+ style="pointer-events: all;"
46
+ >
47
+ <div
48
+ class="divider"
49
+ />
50
+ <div
51
+ class="header"
52
+ >
53
+ <i
54
+ aria-hidden="true"
55
+ class="table icon"
56
+ />
57
+ notifications
58
+ </div>
59
+ </div>
60
+ <div
61
+ aria-checked="false"
62
+ aria-selected="true"
63
+ class="selected item group"
64
+ role="option"
65
+ style="pointer-events: all;"
66
+ >
67
+ <i
68
+ aria-hidden="true"
69
+ class="hashtag icon"
70
+ />
71
+ <span
72
+ class="text"
73
+ >
74
+ recipient_ids
75
+ </span>
76
+ </div>
77
+ </div>
78
+ </div>
79
+ </div>
80
+ `;
81
+
82
+ exports[`<StructureFieldsDropdown /> matches the latest snapshot for one typeCastModifiers of type string 1`] = `
83
+ <div>
84
+ <label>
85
+ Value
86
+ </label>
87
+ <div
88
+ aria-expanded="false"
89
+ class="ui search dropdown selection"
90
+ label="Value"
91
+ role="combobox"
92
+ >
93
+ <input
94
+ aria-autocomplete="list"
95
+ autocomplete="off"
96
+ class="search"
97
+ tabindex="0"
98
+ type="text"
99
+ value=""
100
+ />
101
+ <div
102
+ aria-atomic="true"
103
+ aria-live="polite"
104
+ class="divider default text"
105
+ role="alert"
106
+ >
107
+ Fields
108
+ </div>
109
+ <i
110
+ aria-hidden="true"
111
+ class="dropdown icon"
112
+ />
113
+ <div
114
+ aria-multiselectable="false"
115
+ class="menu transition"
116
+ role="listbox"
117
+ >
118
+ <div
119
+ aria-checked="false"
120
+ aria-disabled="true"
121
+ aria-selected="false"
122
+ class="disabled item"
123
+ role="option"
124
+ style="pointer-events: all;"
125
+ >
126
+ <div
127
+ class="divider"
128
+ />
129
+ <div
130
+ class="header"
131
+ >
132
+ <i
133
+ aria-hidden="true"
134
+ class="table icon"
135
+ />
136
+ notifications
137
+ </div>
138
+ </div>
139
+ <div
140
+ aria-checked="false"
141
+ aria-selected="true"
142
+ class="selected item group"
143
+ role="option"
144
+ style="pointer-events: all;"
145
+ >
146
+ <i
147
+ aria-hidden="true"
148
+ class="hashtag icon"
149
+ />
150
+ <span
151
+ class="text"
152
+ >
153
+ recipient_ids
154
+ </span>
155
+ </div>
156
+ <div
157
+ aria-checked="false"
158
+ aria-selected="false"
159
+ class="item group"
160
+ modifier="[object Object]"
161
+ role="option"
162
+ style="pointer-events: all;"
163
+ >
164
+ <i
165
+ aria-hidden="true"
166
+ class="hashtag icon"
167
+ />
168
+ <span
169
+ class="text"
170
+ >
171
+ recipient_ids (To real string)
172
+ </span>
173
+ </div>
174
+ </div>
175
+ </div>
176
+ </div>
177
+ `;
178
+
179
+ exports[`<StructureFieldsDropdown /> matches the latest snapshot for one typeCastModifiers of type timestamp 1`] = `
180
+ <div>
181
+ <label>
182
+ Value
183
+ </label>
184
+ <div
185
+ aria-expanded="false"
186
+ class="ui search dropdown selection"
187
+ label="Value"
188
+ role="combobox"
189
+ >
190
+ <input
191
+ aria-autocomplete="list"
192
+ autocomplete="off"
193
+ class="search"
194
+ tabindex="0"
195
+ type="text"
196
+ value=""
197
+ />
198
+ <div
199
+ aria-atomic="true"
200
+ aria-live="polite"
201
+ class="divider default text"
202
+ role="alert"
203
+ >
204
+ Fields
205
+ </div>
206
+ <i
207
+ aria-hidden="true"
208
+ class="dropdown icon"
209
+ />
210
+ <div
211
+ aria-multiselectable="false"
212
+ class="menu transition"
213
+ role="listbox"
214
+ >
215
+ <div
216
+ aria-checked="false"
217
+ aria-disabled="true"
218
+ aria-selected="false"
219
+ class="disabled item"
220
+ role="option"
221
+ style="pointer-events: all;"
222
+ >
223
+ <div
224
+ class="divider"
225
+ />
226
+ <div
227
+ class="header"
228
+ >
229
+ <i
230
+ aria-hidden="true"
231
+ class="table icon"
232
+ />
233
+ notifications
234
+ </div>
235
+ </div>
236
+ <div
237
+ aria-checked="false"
238
+ aria-selected="true"
239
+ class="selected item group"
240
+ role="option"
241
+ style="pointer-events: all;"
242
+ >
243
+ <i
244
+ aria-hidden="true"
245
+ class="hashtag icon"
246
+ />
247
+ <span
248
+ class="text"
249
+ >
250
+ inserted_at
251
+ </span>
252
+ </div>
253
+ <div
254
+ aria-checked="false"
255
+ aria-selected="false"
256
+ class="item group"
257
+ modifier="[object Object]"
258
+ role="option"
259
+ style="pointer-events: all;"
260
+ >
261
+ <i
262
+ aria-hidden="true"
263
+ class="hashtag icon"
264
+ />
265
+ <span
266
+ class="text"
267
+ >
268
+ recipient_ids (Cast as timestamp)
269
+ </span>
270
+ </div>
271
+ </div>
272
+ </div>
273
+ </div>
274
+ `;
275
+
276
+ exports[`<StructureFieldsDropdown /> matches the latest snapshot for root fields of number type 1`] = `
277
+ <div>
278
+ <label>
279
+ Value
280
+ </label>
281
+ <div
282
+ aria-expanded="false"
283
+ class="ui search dropdown selection"
284
+ label="Value"
285
+ role="combobox"
286
+ >
287
+ <input
288
+ aria-autocomplete="list"
289
+ autocomplete="off"
290
+ class="search"
291
+ tabindex="0"
292
+ type="text"
293
+ value=""
294
+ />
295
+ <div
296
+ aria-atomic="true"
297
+ aria-live="polite"
298
+ class="divider default text"
299
+ role="alert"
300
+ >
301
+ Fields
302
+ </div>
303
+ <i
304
+ aria-hidden="true"
305
+ class="dropdown icon"
306
+ />
307
+ <div
308
+ aria-multiselectable="false"
309
+ class="menu transition"
310
+ role="listbox"
311
+ >
312
+ <div
313
+ aria-checked="false"
314
+ aria-disabled="true"
315
+ aria-selected="false"
316
+ class="disabled item"
317
+ role="option"
318
+ style="pointer-events: all;"
319
+ >
320
+ <div
321
+ class="divider"
322
+ />
323
+ <div
324
+ class="header"
325
+ >
326
+ <i
327
+ aria-hidden="true"
328
+ class="table icon"
329
+ />
330
+ notifications
331
+ </div>
332
+ </div>
333
+ <div
334
+ aria-checked="false"
335
+ aria-selected="true"
336
+ class="selected item group"
337
+ role="option"
338
+ style="pointer-events: all;"
339
+ >
340
+ <i
341
+ aria-hidden="true"
342
+ class="hashtag icon"
343
+ />
344
+ <span
345
+ class="text"
346
+ >
347
+ id
348
+ </span>
349
+ </div>
350
+ <div
351
+ aria-checked="false"
352
+ aria-selected="false"
353
+ class="item group"
354
+ role="option"
355
+ style="pointer-events: all;"
356
+ >
357
+ <i
358
+ aria-hidden="true"
359
+ class="hashtag icon"
360
+ />
361
+ <span
362
+ class="text"
363
+ >
364
+ subscription_id
365
+ </span>
366
+ </div>
367
+ </div>
368
+ </div>
369
+ </div>
370
+ `;