@truedat/dq 4.53.6 → 4.53.8

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 (27) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/package.json +5 -5
  3. package/src/api/mutations.js +8 -0
  4. package/src/components/ConditionSummary.js +35 -26
  5. package/src/components/ImplementationActions.js +16 -0
  6. package/src/components/ImplementationSearchResults.js +9 -1
  7. package/src/components/ImplementationSummary.js +20 -14
  8. package/src/components/ImplementationsRoutes.js +12 -0
  9. package/src/components/NewRuleImplementation.js +62 -40
  10. package/src/components/QualityRoutes.js +7 -0
  11. package/src/components/RuleImplementation.js +1 -9
  12. package/src/components/__tests__/ImplementationSummary.spec.js +1 -1
  13. package/src/components/__tests__/NewRuleImplementation.spec.js +49 -45
  14. package/src/components/__tests__/__fixtures__/NewRuleImplementationProps.js +25 -23
  15. package/src/components/__tests__/__fixtures__/newRuleImplementationHelper.js +11 -12
  16. package/src/components/__tests__/__snapshots__/NewRuleImplementation.spec.js.snap +62 -1
  17. package/src/components/ruleImplementationForm/FiltersGrid.js +1 -1
  18. package/src/components/ruleImplementationForm/FiltersGroup.js +22 -20
  19. package/src/components/ruleImplementationForm/RuleImplementationForm.js +62 -25
  20. package/src/components/ruleImplementationForm/ValidationsForm.js +1 -2
  21. package/src/messages/en.js +9 -3
  22. package/src/messages/es.js +9 -3
  23. package/src/reducers/ruleImplementation.js +4 -1
  24. package/src/reducers/ruleRedirect.js +3 -0
  25. package/src/routines.js +1 -0
  26. package/src/sagas/index.js +3 -0
  27. package/src/sagas/restoreImplementation.js +24 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.53.8] 2022-10-17
4
+
5
+ ### Added
6
+
7
+ - [TD-5027] support for restoring deprecated `Implementations`
8
+
9
+ ## [4.53.7] 2022-10-14
10
+
11
+ ### Added
12
+
13
+ - [TD-3087] Add OR/AND in implementations validations
14
+
3
15
  ## [4.53.6] 2022-10-13
4
16
 
5
17
  ### Fixed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dq",
3
- "version": "4.53.6",
3
+ "version": "4.53.8",
4
4
  "description": "Truedat Web Data Quality Module",
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.6",
37
+ "@truedat/test": "4.53.8",
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",
@@ -93,8 +93,8 @@
93
93
  },
94
94
  "dependencies": {
95
95
  "@apollo/client": "^3.6.4",
96
- "@truedat/core": "4.53.6",
97
- "@truedat/df": "4.53.6",
96
+ "@truedat/core": "4.53.8",
97
+ "@truedat/df": "4.53.8",
98
98
  "graphql": "^15.5.3",
99
99
  "path-to-regexp": "^1.7.0",
100
100
  "prop-types": "^15.8.1",
@@ -114,5 +114,5 @@
114
114
  "react-dom": ">= 16.8.6 < 17",
115
115
  "semantic-ui-react": ">= 0.88.2 < 2.1"
116
116
  },
117
- "gitHead": "ff29c0e4f51c049077545c425533dd45a704e440"
117
+ "gitHead": "56190c74eddc249134cb973cc21470c36a4701d0"
118
118
  }
@@ -23,3 +23,11 @@ export const PUBLISH_IMPLEMENTATION = gql`
23
23
  }
24
24
  }
25
25
  `;
26
+
27
+ export const RESTORE_IMPLEMENTATION = gql`
28
+ mutation restoreImplementation($id: ID!) {
29
+ restoreImplementation(id: $id) {
30
+ id
31
+ }
32
+ }
33
+ `;
@@ -1,7 +1,7 @@
1
1
  import _ from "lodash/fp";
2
2
  import React, { Fragment } from "react";
3
3
  import PropTypes from "prop-types";
4
- import { Header, Icon, Segment, Table } from "semantic-ui-react";
4
+ import { Divider, Header, Icon, Segment, Table } from "semantic-ui-react";
5
5
  import { Link } from "react-router-dom";
6
6
  import { FormattedMessage } from "react-intl";
7
7
  import { useIntl } from "react-intl";
@@ -235,7 +235,7 @@ export const ConditionSummary = ({ rows, type, icon, alias }) => {
235
235
  <Header.Content>
236
236
  {areMultidimensionalRows ? (
237
237
  <FormattedMessage
238
- id={`ruleImplementations.summary.headers.${type}s`}
238
+ id={`ruleImplementations.summary.headers.${type}.plural`}
239
239
  />
240
240
  ) : (
241
241
  <FormattedMessage
@@ -245,30 +245,39 @@ export const ConditionSummary = ({ rows, type, icon, alias }) => {
245
245
  </Header.Content>
246
246
  </Header>
247
247
  {wrappedRows.map((rows, i) => (
248
- <Segment key={i}>
249
- <Table basic="very">
250
- <Table.Header>
251
- <Table.Row>
252
- <Table.HeaderCell>
253
- <FormattedMessage id={`ruleImplementation.summary.field`} />
254
- </Table.HeaderCell>
255
- <Table.HeaderCell>
256
- <FormattedMessage
257
- id={`ruleImplementation.summary.operator`}
258
- />
259
- </Table.HeaderCell>
260
- <Table.HeaderCell>
261
- <FormattedMessage id={`ruleImplementation.summary.values`} />
262
- </Table.HeaderCell>
263
- </Table.Row>
264
- </Table.Header>
265
- <Table.Body>
266
- {rows.map((row, i) => (
267
- <ConditionCell key={i} row={row} alias={alias} />
268
- ))}
269
- </Table.Body>
270
- </Table>
271
- </Segment>
248
+ <Fragment key={i}>
249
+ <Segment>
250
+ <Table basic="very">
251
+ <Table.Header>
252
+ <Table.Row>
253
+ <Table.HeaderCell>
254
+ <FormattedMessage id={`ruleImplementation.summary.field`} />
255
+ </Table.HeaderCell>
256
+ <Table.HeaderCell>
257
+ <FormattedMessage
258
+ id={`ruleImplementation.summary.operator`}
259
+ />
260
+ </Table.HeaderCell>
261
+ <Table.HeaderCell>
262
+ <FormattedMessage
263
+ id={`ruleImplementation.summary.values`}
264
+ />
265
+ </Table.HeaderCell>
266
+ </Table.Row>
267
+ </Table.Header>
268
+ <Table.Body>
269
+ {rows.map((row, i) => (
270
+ <ConditionCell key={i} row={row} alias={alias} />
271
+ ))}
272
+ </Table.Body>
273
+ </Table>
274
+ </Segment>
275
+ {i < wrappedRows.length - 1 ? (
276
+ <Divider horizontal>
277
+ <FormattedMessage id={"ruleImplementations.or"} />
278
+ </Divider>
279
+ ) : null}
280
+ </Fragment>
272
281
  ))}
273
282
  </>
274
283
  );
@@ -12,6 +12,7 @@ import {
12
12
  submitImplementation,
13
13
  publishImplementation,
14
14
  rejectImplementation,
15
+ restoreImplementation,
15
16
  deleteImplementation,
16
17
  } from "../routines";
17
18
  import ExecutionPopup from "./ExecutionPopup";
@@ -59,6 +60,7 @@ export const ImplementationActions = ({
59
60
  deleteImplementation,
60
61
  publishImplementation,
61
62
  rejectImplementation,
63
+ restoreImplementation,
62
64
  ruleImplementation,
63
65
  submitImplementation,
64
66
  }) => {
@@ -96,6 +98,18 @@ export const ImplementationActions = ({
96
98
  }
97
99
  />
98
100
  ) : null}
101
+ {actions?.restore ? (
102
+ <Button
103
+ primary
104
+ content={formatMessage({ id: "actions.restore" })}
105
+ onClick={() =>
106
+ restoreImplementation({
107
+ id,
108
+ redirectUrl: linkTo.IMPLEMENTATION({ implementation_id: id }),
109
+ })
110
+ }
111
+ />
112
+ ) : null}
99
113
  {actions?.reject ? (
100
114
  <Button
101
115
  secondary
@@ -132,6 +146,7 @@ ImplementationActions.propTypes = {
132
146
  deleteImplementation: PropTypes.func,
133
147
  publishImplementation: PropTypes.func,
134
148
  rejectImplementation: PropTypes.func,
149
+ restoreImplementation: PropTypes.func,
135
150
  ruleImplementation: PropTypes.object,
136
151
  submitImplementation: PropTypes.func,
137
152
  };
@@ -149,5 +164,6 @@ export default connect(mapStateToProps, {
149
164
  deleteImplementation,
150
165
  publishImplementation,
151
166
  rejectImplementation,
167
+ restoreImplementation,
152
168
  submitImplementation,
153
169
  })(ImplementationActions);
@@ -5,7 +5,10 @@ import { connect } from "react-redux";
5
5
  import { Dimmer, Header, Icon, Loader, Segment } from "semantic-ui-react";
6
6
  import { FormattedMessage } from "react-intl";
7
7
  import { useActiveRoute } from "@truedat/core/hooks";
8
- import { IMPLEMENTATIONS_PENDING } from "@truedat/core/routes";
8
+ import {
9
+ IMPLEMENTATIONS_PENDING,
10
+ IMPLEMENTATIONS_DEPRECATED,
11
+ } from "@truedat/core/routes";
9
12
  import { getExecutionQuery } from "../selectors";
10
13
  import RuleImplementationsActions from "./RuleImplementationsActions";
11
14
  import RuleImplementationsLabelResults from "./RuleImplementationsLabelResults";
@@ -24,11 +27,16 @@ const usePrevious = (value) => {
24
27
 
25
28
  export const ImplementationSearchResultsHeader = () => {
26
29
  const pending = useActiveRoute(IMPLEMENTATIONS_PENDING);
30
+ const deprecated = useActiveRoute(IMPLEMENTATIONS_DEPRECATED);
27
31
  const header = pending
28
32
  ? "implementations.header.manage"
33
+ : deprecated
34
+ ? "implementations.header.deprecated"
29
35
  : "implementations.header";
30
36
  const subheader = pending
31
37
  ? "implementations.subheader.manage"
38
+ : deprecated
39
+ ? "implementations.subheader.deprecated"
32
40
  : "implementations.subheader";
33
41
  return (
34
42
  <Header as="h2">
@@ -117,16 +117,22 @@ const DatasetSummary = ({ rows, alias }) =>
117
117
  {_.has("structure")(row) && (
118
118
  <Table.Cell>
119
119
  {_.path("structure.type")(row) !== "reference_dataset" ? (
120
- <Link
121
- to={linkTo.STRUCTURE({
122
- id: _.pathOr("", "structure.id")(row),
123
- })}
124
- >
125
- <p className="highlighted">
126
- <Icon name="table" size="small" />
127
- {`"${path(_.propOr({}, "structure")(row))}"`}
128
- </p>
129
- </Link>
120
+ _.path("structure.id")(row) ? (
121
+ <Link
122
+ to={linkTo.STRUCTURE({
123
+ id: _.path("structure.id")(row),
124
+ })}
125
+ >
126
+ <p className="highlighted">
127
+ <Icon name="table" size="small" />
128
+ {`"${path(_.propOr({}, "structure")(row))}"`}
129
+ </p>
130
+ </Link>
131
+ ) : (
132
+ <FormattedMessage
133
+ id={`ruleImplementation.summary.invalid_structure`}
134
+ />
135
+ )
130
136
  ) : (
131
137
  <span>
132
138
  <Icon name="list ol" size="small" />{" "}
@@ -173,22 +179,22 @@ export const ImplementationSummary = ({ ruleImplementation, activeSteps }) => {
173
179
  alias={alias}
174
180
  />
175
181
  ) : null}
176
- {validations && _.includes("validations")(steps) && (
182
+ {validations && _.includes("validations")(steps) ? (
177
183
  <ConditionSummary
178
184
  type="validations"
179
185
  icon="setting"
180
186
  rows={validations}
181
187
  alias={alias}
182
188
  />
183
- )}
184
- {segments && _.includes("segments")(steps) && (
189
+ ) : null}
190
+ {segments && _.includes("segments")(steps) ? (
185
191
  <FieldSummary
186
192
  type="segments"
187
193
  icon="grid layout"
188
194
  rows={segments}
189
195
  alias={alias}
190
196
  />
191
- )}
197
+ ) : null}
192
198
  </>
193
199
  );
194
200
  };
@@ -23,6 +23,7 @@ import {
23
23
  IMPLEMENTATION_STRUCTURES,
24
24
  IMPLEMENTATION,
25
25
  IMPLEMENTATIONS,
26
+ IMPLEMENTATIONS_DEPRECATED,
26
27
  IMPLEMENTATIONS_PENDING,
27
28
  } from "@truedat/core/routes";
28
29
  import {
@@ -340,6 +341,17 @@ export const ImplementationsRoutes = ({
340
341
  />
341
342
  )}
342
343
  />
344
+ <Route
345
+ exact
346
+ path={IMPLEMENTATIONS_DEPRECATED}
347
+ render={() => (
348
+ <Implementations
349
+ defaultFilters={{
350
+ status: ["deprecated"],
351
+ }}
352
+ />
353
+ )}
354
+ />
343
355
  </Switch>
344
356
  );
345
357
  };
@@ -98,8 +98,8 @@ const conditionAttributes = (condition) =>
98
98
  _.map(updateConditionKey)
99
99
  )(condition);
100
100
 
101
- const populationsAttributes = (populations) =>
102
- _.flow(_.map(conditionAttributes))(populations);
101
+ const conditionsAttributes = (conditions) =>
102
+ _.flow(_.map(conditionAttributes))(conditions);
103
103
 
104
104
  const fieldTypeFromStructure = (row, structures, operators, scope) => {
105
105
  const structure = _.prop("structure")(row);
@@ -287,17 +287,22 @@ export const NewRuleImplementation = ({
287
287
  )
288
288
  )
289
289
  )(ruleImplementationProps),
290
- validations: withConditionDefaultAlias(
291
- addFieldType(
292
- ruleImplementationProps,
293
- structuresFields,
294
- structuresSiblings,
295
- "validations",
296
- "validation",
297
- operators
298
- ),
299
- precalculatedDataset
300
- ),
290
+ validations: _.flow(
291
+ _.pathOr([], "validations"),
292
+ _.map((validation) =>
293
+ withConditionDefaultAlias(
294
+ addFieldType(
295
+ { validation: validation },
296
+ structuresFields,
297
+ structuresSiblings,
298
+ "validation",
299
+ "validation",
300
+ operators
301
+ ),
302
+ precalculatedDataset
303
+ )
304
+ )
305
+ )(ruleImplementationProps),
301
306
  segments: withConditionDefaultAlias(
302
307
  addFieldType(
303
308
  ruleImplementationProps,
@@ -330,7 +335,7 @@ export const NewRuleImplementation = ({
330
335
  dataset: [{}],
331
336
  population: [],
332
337
  populations: [],
333
- validations: [{}],
338
+ validations: [[{}]],
334
339
  segments: [{}],
335
340
  rawContent: {
336
341
  database: "",
@@ -393,36 +398,36 @@ export const NewRuleImplementation = ({
393
398
  _.isNil(_.path("value[0].id")(val)) ||
394
399
  belongsToDataset(_.path("value[0].id")(val));
395
400
 
396
- const validations_within_dataset = _.flow(
397
- _.prop("validations"),
398
- _.filter((val) => belongsToDataset(_.path("structure.id")(val))),
399
- _.filter((val) => valueInDataset(val))
401
+ const withinDataset = (val) =>
402
+ belongsToDataset(_.path("structure.id")(val)) && valueInDataset(val);
403
+
404
+ const populationsWithinDataset = _.flow(
405
+ _.prop("populations"),
406
+ _.map((population) => _.filter(withinDataset)(population)),
407
+ _.reject(_.isEmpty)
400
408
  )(ruleImplementation);
401
409
 
402
- const segments_within_dataset = _.flow(
403
- _.prop("segments"),
404
- _.filter((val) => belongsToDataset(_.path("structure.id")(val))),
405
- _.filter((val) => valueInDataset(val))
410
+ const validationsWithinDataset = _.flow(
411
+ _.prop("validations"),
412
+ _.map((validation) => _.filter(withinDataset)(validation)),
413
+ _.reject(_.isEmpty)
406
414
  )(ruleImplementation);
407
415
 
408
- const population_within_dataset = _.flow(
409
- _.prop("population"),
410
- _.filter((val) => belongsToDataset(_.path("structure.id")(val))),
411
- _.filter((val) => valueInDataset(val))
416
+ const segmentsWithinDataset = _.flow(
417
+ _.prop("segments"),
418
+ _.filter(withinDataset)
412
419
  )(ruleImplementation);
413
420
 
414
421
  setRuleImplementation({
415
422
  ...ruleImplementation,
416
423
  dataset: cleanDataset,
417
- population: _.isEmpty(population_within_dataset)
424
+ populations: _.isEmpty(populationsWithinDataset)
418
425
  ? []
419
- : population_within_dataset,
420
- validations: _.isEmpty(validations_within_dataset)
421
- ? [{}]
422
- : validations_within_dataset,
423
- segments: _.isEmpty(segments_within_dataset)
424
- ? []
425
- : segments_within_dataset,
426
+ : populationsWithinDataset,
427
+ validations: _.isEmpty(validationsWithinDataset)
428
+ ? [[{}]]
429
+ : validationsWithinDataset,
430
+ segments: _.isEmpty(segmentsWithinDataset) ? [] : segmentsWithinDataset,
426
431
  });
427
432
  };
428
433
 
@@ -446,11 +451,27 @@ export const NewRuleImplementation = ({
446
451
  setRuleImplementation({ ...ruleImplementation, populations: populations });
447
452
  };
448
453
 
449
- const setValidations = (validations) => {
450
- setRuleImplementation({ ...ruleImplementation, validations });
454
+ const addValidation = () => {
455
+ const validations = _.concat(
456
+ _.pathOr([[{}]], "validations")(ruleImplementation)
457
+ )([[{}]]);
458
+ setRuleImplementation({ ...ruleImplementation, validations: validations });
459
+ };
460
+
461
+ const setValidations = (validation, index) => {
462
+ const validations = _.flow(
463
+ _.pathOr([], "validations"),
464
+ _.update(`[${index}]`, (_previousValidation) => validation),
465
+ _.reject(_.isEmpty)
466
+ )(ruleImplementation);
467
+
468
+ setRuleImplementation({
469
+ ...ruleImplementation,
470
+ validations: _.isEmpty(validations) ? [[{}]] : validations,
471
+ });
451
472
  };
452
473
 
453
- const addSegments = () => {
474
+ const addSegment = () => {
454
475
  const segments = _.concat(_.pathOr([], "segments")(ruleImplementation))([
455
476
  {},
456
477
  ]);
@@ -495,8 +516,8 @@ export const NewRuleImplementation = ({
495
516
  : {
496
517
  executable: ruleImplementation.executable,
497
518
  dataset: datasetAttributes(ruleImplementation.dataset),
498
- populations: populationsAttributes(populations),
499
- validations: conditionAttributes(validations),
519
+ populations: conditionsAttributes(populations),
520
+ validation: conditionsAttributes(validations),
500
521
  segments,
501
522
  implementation_key: ruleImplementation.implementationKey,
502
523
  implementation_type: ruleImplementation.implementationType,
@@ -555,7 +576,8 @@ export const NewRuleImplementation = ({
555
576
  ) : (
556
577
  <RuleImplementationForm
557
578
  addPopulation={addPopulation}
558
- addSegments={addSegments}
579
+ addValidation={addValidation}
580
+ addSegment={addSegment}
559
581
  onSubmit={doSubmit}
560
582
  onChange={onChange}
561
583
  operators={operators}
@@ -6,6 +6,7 @@ import {
6
6
  EXECUTION_GROUP,
7
7
  EXECUTION_GROUPS,
8
8
  IMPLEMENTATIONS,
9
+ IMPLEMENTATIONS_DEPRECATED,
9
10
  IMPLEMENTATIONS_PENDING,
10
11
  RULES,
11
12
  } from "@truedat/core/routes";
@@ -55,6 +56,12 @@ const QualityRoutes = () => {
55
56
  authorized ? <ImplementationsRoutes /> : <Unauthorized />
56
57
  }
57
58
  />
59
+ <Route
60
+ path={IMPLEMENTATIONS_DEPRECATED}
61
+ render={() =>
62
+ authorized ? <ImplementationsRoutes /> : <Unauthorized />
63
+ }
64
+ />
58
65
  </>
59
66
  );
60
67
  };
@@ -27,15 +27,7 @@ export const RuleImplementation = ({ children, ruleImplementation }) => {
27
27
  </Grid.Column>
28
28
  <Grid.Column width={8} textAlign="right">
29
29
  <>
30
- {deletedAt ? (
31
- <Label
32
- className="alert warning"
33
- content={formatMessage({
34
- id: "ruleImplementation.props.status.deprecated",
35
- })}
36
- icon={{ name: "warning circle", color: "red" }}
37
- />
38
- ) : (
30
+ {deletedAt ? null : (
39
31
  <Subscription
40
32
  resource={ruleImplementation}
41
33
  resourceType="implementation"
@@ -12,7 +12,7 @@ const renderOpts = {
12
12
  "quality.threshold": "threshold",
13
13
  "quality.goal": "goal",
14
14
  "ruleImplementations.props.result_type.percentage": "percentage",
15
- "ruleImplementations.summary.headers.populations": "populations",
15
+ "ruleImplementations.summary.headers.population.plural": "populations",
16
16
  "ruleImplementation.summary.field": "Field",
17
17
  "ruleImplementation.summary.operator": "Operator",
18
18
  "ruleImplementation.summary.structure": "Structure",
@@ -149,20 +149,22 @@ describe("<NewRuleImplementation> NewRuleImplementation doSubmit", () => {
149
149
  it("doSubmit: is empty operator", async () => {
150
150
  const expectedRuleImplementation = {
151
151
  ...expectedRuleImplementationBase,
152
- validations: [
153
- {
154
- modifier: null,
155
- operator: { name: "empty" },
156
- population: [],
157
- structure: {
158
- id: 11127109,
159
- parent_index: 4,
160
- name: "EMAIL",
161
- type: "column",
152
+ validation: [
153
+ [
154
+ {
155
+ modifier: null,
156
+ operator: { name: "empty" },
157
+ population: [],
158
+ structure: {
159
+ id: 11127109,
160
+ parent_index: 4,
161
+ name: "EMAIL",
162
+ type: "column",
163
+ },
164
+ value: [],
165
+ value_modifier: [],
162
166
  },
163
- value: [],
164
- value_modifier: [],
165
- },
167
+ ],
166
168
  ],
167
169
  };
168
170
 
@@ -245,39 +247,41 @@ describe("<NewRuleImplementation> NewRuleImplementation doSubmit", () => {
245
247
  it("doSubmit: unique across fields operator", async () => {
246
248
  const expectedRuleImplementation = {
247
249
  ...expectedRuleImplementationBase,
248
- validations: [
249
- {
250
- modifier: null,
251
- operator: { name: "unique", value_type: "field_list" },
252
- population: [],
253
- structure: {
254
- id: 11127109,
255
- parent_index: 4,
256
- name: "EMAIL",
257
- type: "column",
258
- },
259
- value: [
260
- {
261
- fields: [
262
- {
263
- id: 11127109,
264
- name: "EMAIL",
265
- parent_index: 4,
266
- path: undefined,
267
- type: "column",
268
- },
269
- {
270
- id: 11127116,
271
- name: "PHONE_NUMBER",
272
- parent_index: 4,
273
- path: undefined,
274
- type: "column",
275
- },
276
- ],
250
+ validation: [
251
+ [
252
+ {
253
+ modifier: null,
254
+ operator: { name: "unique", value_type: "field_list" },
255
+ population: [],
256
+ structure: {
257
+ id: 11127109,
258
+ parent_index: 4,
259
+ name: "EMAIL",
260
+ type: "column",
277
261
  },
278
- ],
279
- value_modifier: [],
280
- },
262
+ value: [
263
+ {
264
+ fields: [
265
+ {
266
+ id: 11127109,
267
+ name: "EMAIL",
268
+ parent_index: 4,
269
+ path: undefined,
270
+ type: "column",
271
+ },
272
+ {
273
+ id: 11127116,
274
+ name: "PHONE_NUMBER",
275
+ parent_index: 4,
276
+ path: undefined,
277
+ type: "column",
278
+ },
279
+ ],
280
+ },
281
+ ],
282
+ value_modifier: [],
283
+ },
284
+ ],
281
285
  ],
282
286
  };
283
287