@truedat/dq 4.41.5 → 4.42.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,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.42.1] 2022-04-12
4
+
5
+ # Changed
6
+
7
+ - [TD-4536] Support rule implementation with multiple populations
8
+
3
9
  ## [4.41.4] 2022-04-04
4
10
 
5
11
  ### Changed
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dq",
3
- "version": "4.41.5",
3
+ "version": "4.42.2",
4
4
  "description": "Truedat Web Data Quality Module",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -31,7 +31,7 @@
31
31
  "@babel/plugin-transform-modules-commonjs": "^7.15.0",
32
32
  "@babel/preset-env": "^7.15.0",
33
33
  "@babel/preset-react": "^7.14.5",
34
- "@truedat/test": "4.41.5",
34
+ "@truedat/test": "4.42.0",
35
35
  "babel-jest": "^27.0.6",
36
36
  "babel-plugin-dynamic-import-node": "^2.3.3",
37
37
  "babel-plugin-lodash": "^3.3.4",
@@ -82,8 +82,8 @@
82
82
  },
83
83
  "dependencies": {
84
84
  "@apollo/client": "^3.4.10",
85
- "@truedat/core": "4.41.5",
86
- "@truedat/df": "4.41.5",
85
+ "@truedat/core": "4.42.2",
86
+ "@truedat/df": "4.42.2",
87
87
  "axios": "^0.19.2",
88
88
  "graphql": "^15.5.3",
89
89
  "path-to-regexp": "^1.7.0",
@@ -103,5 +103,5 @@
103
103
  "react-dom": ">= 16.8.6 < 17",
104
104
  "semantic-ui-react": ">= 0.88.2 < 2.1"
105
105
  },
106
- "gitHead": "a4436b1f8d9fcf01424b44e6a7fc26ad1159a45c"
106
+ "gitHead": "1ca6b75d5b0c80c8e2e931340d5efe4eeefb27de"
107
107
  }
@@ -163,41 +163,55 @@ ConditionCell.propTypes = {
163
163
  alias: PropTypes.array,
164
164
  };
165
165
 
166
- export const ConditionSummary = ({ rows, type, icon, alias }) =>
167
- empty(rows) ? null : (
166
+ export const ConditionSummary = ({ rows, type, icon, alias }) => {
167
+ const areMultidimensionalRows =
168
+ rows.filter(Array.isArray).length == rows.length;
169
+ const wrappedRows = areMultidimensionalRows ? rows : [rows];
170
+ return empty(rows) ? null : (
168
171
  <>
169
172
  <Header as="h3">
170
173
  <Icon name={icon} size="small" />
171
174
  <Header.Content>
172
- <FormattedMessage
173
- id={`ruleImplementations.summary.headers.${type}`}
174
- />
175
+ {areMultidimensionalRows ? (
176
+ <FormattedMessage
177
+ id={`ruleImplementations.summary.headers.${type}s`}
178
+ />
179
+ ) : (
180
+ <FormattedMessage
181
+ id={`ruleImplementations.summary.headers.${type}`}
182
+ />
183
+ )}
175
184
  </Header.Content>
176
185
  </Header>
177
- <Segment>
178
- <Table basic="very">
179
- <Table.Header>
180
- <Table.Row>
181
- <Table.HeaderCell>
182
- <FormattedMessage id={`ruleImplementation.summary.field`} />
183
- </Table.HeaderCell>
184
- <Table.HeaderCell>
185
- <FormattedMessage id={`ruleImplementation.summary.operator`} />
186
- </Table.HeaderCell>
187
- <Table.HeaderCell>
188
- <FormattedMessage id={`ruleImplementation.summary.values`} />
189
- </Table.HeaderCell>
190
- </Table.Row>
191
- </Table.Header>
192
- <Table.Body>
193
- {rows.map((row, i) => (
194
- <ConditionCell key={i} row={row} alias={alias} />
195
- ))}
196
- </Table.Body>
197
- </Table>
198
- </Segment>
186
+ {wrappedRows.map((rows, i) => (
187
+ <Segment key={i}>
188
+ <Table basic="very">
189
+ <Table.Header>
190
+ <Table.Row>
191
+ <Table.HeaderCell>
192
+ <FormattedMessage id={`ruleImplementation.summary.field`} />
193
+ </Table.HeaderCell>
194
+ <Table.HeaderCell>
195
+ <FormattedMessage
196
+ id={`ruleImplementation.summary.operator`}
197
+ />
198
+ </Table.HeaderCell>
199
+ <Table.HeaderCell>
200
+ <FormattedMessage id={`ruleImplementation.summary.values`} />
201
+ </Table.HeaderCell>
202
+ </Table.Row>
203
+ </Table.Header>
204
+ <Table.Body>
205
+ {rows.map((row, i) => (
206
+ <ConditionCell key={i} row={row} alias={alias} />
207
+ ))}
208
+ </Table.Body>
209
+ </Table>
210
+ </Segment>
211
+ ))}
199
212
  </>
200
213
  );
214
+ };
201
215
 
202
216
  ConditionSummary.propTypes = {
203
217
  icon: PropTypes.string,
@@ -13,7 +13,7 @@ const defaults = [
13
13
  "executable",
14
14
  "implementationKey",
15
15
  "dataset",
16
- "population",
16
+ "populations",
17
17
  "validations",
18
18
  ];
19
19
 
@@ -130,7 +130,7 @@ DatasetSummary.propTypes = {
130
130
 
131
131
  export const ImplementationSummary = ({ ruleImplementation, activeSteps }) => {
132
132
  const steps = _.isEmpty(activeSteps) ? defaults : activeSteps;
133
- const { dataset, population, validations } =
133
+ const { dataset, populations, validations } =
134
134
  _.pick(steps)(ruleImplementation);
135
135
  const alias = _.map(_.propOr({}, "alias"))(dataset);
136
136
  return (
@@ -142,14 +142,14 @@ export const ImplementationSummary = ({ ruleImplementation, activeSteps }) => {
142
142
  {dataset && _.includes("dataset")(steps) && (
143
143
  <DatasetSummary rows={dataset} alias={alias} />
144
144
  )}
145
- {population && _.includes("population")(steps) && (
145
+ {populations && _.includes("populations")(steps) ? (
146
146
  <ConditionSummary
147
147
  type="population"
148
148
  icon="user"
149
- rows={population}
149
+ rows={populations}
150
150
  alias={alias}
151
151
  />
152
- )}
152
+ ) : null}
153
153
  {validations && _.includes("validations")(steps) && (
154
154
  <ConditionSummary
155
155
  type="validations"
@@ -92,6 +92,9 @@ const conditionAttributes = (condition) =>
92
92
  _.map(updateConditionKey)
93
93
  )(condition);
94
94
 
95
+ const populationsAttributes = (populations) =>
96
+ _.flow(_.map(conditionAttributes))(populations);
97
+
95
98
  const fieldTypeFromStructure = (row, structures, operators, scope) => {
96
99
  const structure_id = _.path("structure.id")(row);
97
100
  const field = _.find(_.propEq("data_structure_id", structure_id))(structures);
@@ -266,17 +269,22 @@ export const NewRuleImplementation = ({
266
269
  ruleImplementationProps
267
270
  ),
268
271
  dataset: precalculatedDataset,
269
- population: withConditionDefaultAlias(
270
- addFieldType(
271
- ruleImplementationProps,
272
- structuresFields,
273
- structuresSiblings,
274
- "population",
275
- "population",
276
- operators
277
- ),
278
- precalculatedDataset
279
- ),
272
+ populations: _.flow(
273
+ _.pathOr([], "populations"),
274
+ _.map((population) =>
275
+ withConditionDefaultAlias(
276
+ addFieldType(
277
+ { population: population },
278
+ structuresFields,
279
+ structuresSiblings,
280
+ "population",
281
+ "population",
282
+ operators
283
+ ),
284
+ precalculatedDataset
285
+ )
286
+ )
287
+ )(ruleImplementationProps),
280
288
  validations: withConditionDefaultAlias(
281
289
  addFieldType(
282
290
  ruleImplementationProps,
@@ -303,6 +311,7 @@ export const NewRuleImplementation = ({
303
311
  implementationType: "default",
304
312
  dataset: [{}],
305
313
  population: [],
314
+ populations: [],
306
315
  validations: [{}],
307
316
  rawContent: {
308
317
  database: "",
@@ -396,6 +405,23 @@ export const NewRuleImplementation = ({
396
405
  setRuleImplementation({ ...ruleImplementation, population });
397
406
  };
398
407
 
408
+ const addPopulation = () => {
409
+ const populations = _.concat(
410
+ _.pathOr([], "populations")(ruleImplementation)
411
+ )([[{}]]);
412
+ setRuleImplementation({ ...ruleImplementation, populations: populations });
413
+ };
414
+
415
+ const setPopulations = (population, index) => {
416
+ const populations = _.flow(
417
+ _.pathOr([], "populations"),
418
+ _.update(`[${index}]`, (_previousPopulation) => population),
419
+ _.reject(_.isEmpty)
420
+ )(ruleImplementation);
421
+
422
+ setRuleImplementation({ ...ruleImplementation, populations: populations });
423
+ };
424
+
399
425
  const setValidations = (validations) => {
400
426
  setRuleImplementation({ ...ruleImplementation, validations });
401
427
  };
@@ -417,8 +443,8 @@ export const NewRuleImplementation = ({
417
443
  }, [template]);
418
444
 
419
445
  const doSubmit = () => {
420
- const population = _.filter(_.negate(_.isEmpty))(
421
- ruleImplementation.population
446
+ const populations = _.filter(_.negate(_.isEmpty))(
447
+ ruleImplementation.populations
422
448
  );
423
449
  const validations = _.filter(_.negate(_.isEmpty))(
424
450
  ruleImplementation.validations
@@ -453,7 +479,7 @@ export const NewRuleImplementation = ({
453
479
  : {
454
480
  executable: ruleImplementation.executable,
455
481
  dataset: datasetAttributes(_.prop("dataset")(ruleImplementation)),
456
- population: conditionAttributes(population),
482
+ populations: populationsAttributes(populations),
457
483
  validations: conditionAttributes(validations),
458
484
  implementation_key: _.prop("implementationKey")(ruleImplementation),
459
485
  implementation_type:
@@ -533,7 +559,8 @@ export const NewRuleImplementation = ({
533
559
  <RuleImplementationForm
534
560
  ruleImplementation={ruleImplementation}
535
561
  setStructures={setDataset}
536
- setPopulation={setPopulation}
562
+ addPopulation={addPopulation}
563
+ setPopulations={setPopulations}
537
564
  setValidations={setValidations}
538
565
  operators={operators}
539
566
  setImplementationKey={setImplementationKey}
@@ -12,7 +12,7 @@ const DynamicFormViewer = React.lazy(() =>
12
12
  import("@truedat/df/components/DynamicFormViewer")
13
13
  );
14
14
 
15
- const summarySteps = ["dataset", "population", "validations"];
15
+ const summarySteps = ["dataset", "populations", "validations"];
16
16
 
17
17
  export const RuleImplementationProperties = ({
18
18
  ruleImplementation,
@@ -74,6 +74,7 @@ const mapStateToProps = ({
74
74
  }) => ({
75
75
  ruleImplementation: _.pick([
76
76
  ...summarySteps,
77
+ "populations",
77
78
  "executable",
78
79
  "event_type",
79
80
  "event_message",
@@ -130,56 +130,58 @@ export const newRuleImplementationProps = {
130
130
  id: 852,
131
131
  implementation_key: "impl_example_1",
132
132
  implementation_type: "default",
133
- population: [
134
- {
135
- operator: {
136
- name: "eq",
137
- value_type: "field",
138
- },
139
- structure: {
140
- external_id:
141
- "https://glue.eu-west-1.amazonaws.com/#/576759405678/cepsa-demo-s3/02_es_provincias/descripcion",
142
- id: 4817544,
143
- metadata: {
144
- account: "576759405678",
145
- data_type_class: "string",
146
- database: "cepsa-demo-s3",
147
- order: "2.0",
148
- region: "eu-west-1",
149
- tablename: "02_es_provincias",
150
- type: "string",
151
- },
152
- name: "descripcion",
153
- path: ["cepsa-demo-s3", "02_es_provincias"],
154
- system: {
155
- external_id: "glue",
156
- id: 94,
157
- name: "Glue",
133
+ populations: [
134
+ [
135
+ {
136
+ operator: {
137
+ name: "eq",
138
+ value_type: "field",
158
139
  },
159
- type: "Column",
160
- },
161
- value: [
162
- {
140
+ structure: {
163
141
  external_id:
164
- "/home/alberto/projects/connectors/td-connector-txt-files/data/########_D_PELAYO_POLIZAS_20201202033016_I.txt[Aux. Externo]",
165
- id: 4814767,
142
+ "https://glue.eu-west-1.amazonaws.com/#/576759405678/cepsa-demo-s3/02_es_provincias/descripcion",
143
+ id: 4817544,
166
144
  metadata: {
167
- order: "8",
145
+ account: "576759405678",
146
+ data_type_class: "string",
147
+ database: "cepsa-demo-s3",
148
+ order: "2.0",
149
+ region: "eu-west-1",
150
+ tablename: "02_es_provincias",
151
+ type: "string",
168
152
  },
169
- name: "Aux. Externo",
170
- path: [
171
- "Area_Vida",
172
- "########_D_PELAYO_POLIZAS_20201202033016_I.txt",
173
- ],
153
+ name: "descripcion",
154
+ path: ["cepsa-demo-s3", "02_es_provincias"],
174
155
  system: {
175
- external_id: "file_system",
176
- id: 33,
177
- name: "File System",
156
+ external_id: "glue",
157
+ id: 94,
158
+ name: "Glue",
178
159
  },
179
160
  type: "Column",
180
161
  },
181
- ],
182
- },
162
+ value: [
163
+ {
164
+ external_id:
165
+ "/home/alberto/projects/connectors/td-connector-txt-files/data/########_D_PELAYO_POLIZAS_20201202033016_I.txt[Aux. Externo]",
166
+ id: 4814767,
167
+ metadata: {
168
+ order: "8",
169
+ },
170
+ name: "Aux. Externo",
171
+ path: [
172
+ "Area_Vida",
173
+ "########_D_PELAYO_POLIZAS_20201202033016_I.txt",
174
+ ],
175
+ system: {
176
+ external_id: "file_system",
177
+ id: 33,
178
+ name: "File System",
179
+ },
180
+ type: "Column",
181
+ },
182
+ ],
183
+ },
184
+ ],
183
185
  ],
184
186
  results: [
185
187
  {
@@ -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
-
15
+ "ruleImplementations.summary.headers.populations": "populations",
16
16
  "ruleImplementation.summary.field": "Field",
17
17
  "ruleImplementation.summary.operator": "Operator",
18
18
  "ruleImplementation.summary.structure": "Structure",
@@ -46,7 +46,7 @@ const ruleImplementation = {
46
46
  },
47
47
  },
48
48
  ],
49
- population: [{}],
49
+ populations: [[{}]],
50
50
  validations: [
51
51
  {
52
52
  structure: { field_type: "string", name: "Mes", id: 2598 },
@@ -67,7 +67,7 @@ describe("<ImplementationSummary />", () => {
67
67
  "implementationKey",
68
68
  "executable",
69
69
  "dataset",
70
- "population",
70
+ "populations",
71
71
  "validations",
72
72
  ];
73
73
  const props = {
@@ -79,7 +79,7 @@ describe("<ImplementationSummary />", () => {
79
79
  });
80
80
 
81
81
  it("displays correctly validations values of list type", () => {
82
- const steps = ["dataset", "population", "validations"];
82
+ const steps = ["dataset", "populations", "validations"];
83
83
  const props = {
84
84
  steps,
85
85
  ruleImplementation,
@@ -144,6 +144,67 @@ exports[`<ImplementationSummary /> displays correctly validations values of list
144
144
  </tbody>
145
145
  </table>
146
146
  </div>
147
+ <h3
148
+ class="ui header"
149
+ >
150
+ <i
151
+ aria-hidden="true"
152
+ class="user small icon"
153
+ />
154
+ <div
155
+ class="content"
156
+ >
157
+ populations
158
+ </div>
159
+ </h3>
160
+ <div
161
+ class="ui segment"
162
+ >
163
+ <table
164
+ class="ui very basic table"
165
+ >
166
+ <thead
167
+ class=""
168
+ >
169
+ <tr
170
+ class=""
171
+ >
172
+ <th
173
+ class=""
174
+ >
175
+ Field
176
+ </th>
177
+ <th
178
+ class=""
179
+ >
180
+ Operator
181
+ </th>
182
+ <th
183
+ class=""
184
+ >
185
+ Values
186
+ </th>
187
+ </tr>
188
+ </thead>
189
+ <tbody
190
+ class=""
191
+ >
192
+ <tr
193
+ class=""
194
+ >
195
+ <td
196
+ class="five wide"
197
+ />
198
+ <td
199
+ class="five wide"
200
+ />
201
+ <td
202
+ class="five wide"
203
+ />
204
+ </tr>
205
+ </tbody>
206
+ </table>
207
+ </div>
147
208
  <h3
148
209
  class="ui header"
149
210
  >
@@ -264,8 +325,10 @@ exports[`<ImplementationSummary /> matches the latest snapshot 1`] = `
264
325
  "implementationKey": "ImplKey",
265
326
  "implementationType": "",
266
327
  "minimum": 10,
267
- "population": Array [
268
- Object {},
328
+ "populations": Array [
329
+ Array [
330
+ Object {},
331
+ ],
269
332
  ],
270
333
  "rawContent": Object {
271
334
  "dataset": "",
@@ -340,7 +403,9 @@ exports[`<ImplementationSummary /> matches the latest snapshot 1`] = `
340
403
  icon="user"
341
404
  rows={
342
405
  Array [
343
- Object {},
406
+ Array [
407
+ Object {},
408
+ ],
344
409
  ]
345
410
  }
346
411
  type="population"
@@ -28,6 +28,7 @@ exports[`<NewRuleImplementation /> calculate aliases when not informed 1`] = `
28
28
  stretched={true}
29
29
  >
30
30
  <Connect(RuleImplementationForm)
31
+ addPopulation={[Function]}
31
32
  handleSubmit={[Function]}
32
33
  onChange={[Function]}
33
34
  operators={
@@ -799,64 +800,66 @@ exports[`<NewRuleImplementation /> calculate aliases when not informed 1`] = `
799
800
  "implementationKey": "impl_example_1",
800
801
  "implementationType": "default",
801
802
  "minimum": 2010,
802
- "population": Array [
803
- Object {
804
- "modifier": undefined,
805
- "operator": Object {
806
- "group": "eq",
807
- "id": 23,
808
- "name": "eq",
809
- "value_type": "field",
810
- },
811
- "structure": Object {
812
- "external_id": "https://glue.eu-west-1.amazonaws.com/#/576759405678/cepsa-demo-s3/02_es_provincias/descripcion",
813
- "field_type": "string",
814
- "id": 4817544,
815
- "metadata": Object {
816
- "account": "576759405678",
817
- "data_type_class": "string",
818
- "database": "cepsa-demo-s3",
819
- "order": "2.0",
820
- "region": "eu-west-1",
821
- "tablename": "02_es_provincias",
822
- "type": "string",
803
+ "populations": Array [
804
+ Array [
805
+ Object {
806
+ "modifier": undefined,
807
+ "operator": Object {
808
+ "group": "eq",
809
+ "id": 23,
810
+ "name": "eq",
811
+ "value_type": "field",
823
812
  },
824
- "name": "descripcion",
825
- "parent_index": 1,
826
- "path": Array [
827
- "cepsa-demo-s3",
828
- "02_es_provincias",
829
- ],
830
- "system": Object {
831
- "external_id": "glue",
832
- "id": 94,
833
- "name": "Glue",
834
- },
835
- "type": "Column",
836
- },
837
- "value": Array [
838
- Object {
839
- "external_id": "/home/alberto/projects/connectors/td-connector-txt-files/data/########_D_PELAYO_POLIZAS_20201202033016_I.txt[Aux. Externo]",
840
- "id": 4814767,
813
+ "structure": Object {
814
+ "external_id": "https://glue.eu-west-1.amazonaws.com/#/576759405678/cepsa-demo-s3/02_es_provincias/descripcion",
815
+ "field_type": "string",
816
+ "id": 4817544,
841
817
  "metadata": Object {
842
- "order": "8",
818
+ "account": "576759405678",
819
+ "data_type_class": "string",
820
+ "database": "cepsa-demo-s3",
821
+ "order": "2.0",
822
+ "region": "eu-west-1",
823
+ "tablename": "02_es_provincias",
824
+ "type": "string",
843
825
  },
844
- "name": "Aux. Externo",
845
- "parent_index": 0,
826
+ "name": "descripcion",
827
+ "parent_index": 1,
846
828
  "path": Array [
847
- "Area_Vida",
848
- "########_D_PELAYO_POLIZAS_20201202033016_I.txt",
829
+ "cepsa-demo-s3",
830
+ "02_es_provincias",
849
831
  ],
850
832
  "system": Object {
851
- "external_id": "file_system",
852
- "id": 33,
853
- "name": "File System",
833
+ "external_id": "glue",
834
+ "id": 94,
835
+ "name": "Glue",
854
836
  },
855
837
  "type": "Column",
856
838
  },
857
- ],
858
- "value_modifier": undefined,
859
- },
839
+ "value": Array [
840
+ Object {
841
+ "external_id": "/home/alberto/projects/connectors/td-connector-txt-files/data/########_D_PELAYO_POLIZAS_20201202033016_I.txt[Aux. Externo]",
842
+ "id": 4814767,
843
+ "metadata": Object {
844
+ "order": "8",
845
+ },
846
+ "name": "Aux. Externo",
847
+ "parent_index": 0,
848
+ "path": Array [
849
+ "Area_Vida",
850
+ "########_D_PELAYO_POLIZAS_20201202033016_I.txt",
851
+ ],
852
+ "system": Object {
853
+ "external_id": "file_system",
854
+ "id": 33,
855
+ "name": "File System",
856
+ },
857
+ "type": "Column",
858
+ },
859
+ ],
860
+ "value_modifier": undefined,
861
+ },
862
+ ],
860
863
  ],
861
864
  "rawContent": Object {},
862
865
  "result_type": "errors_number",
@@ -901,7 +904,7 @@ exports[`<NewRuleImplementation /> calculate aliases when not informed 1`] = `
901
904
  }
902
905
  }
903
906
  setImplementationKey={[Function]}
904
- setPopulation={[Function]}
907
+ setPopulations={[Function]}
905
908
  setStructures={[Function]}
906
909
  setValidations={[Function]}
907
910
  />
@@ -1022,64 +1025,66 @@ exports[`<NewRuleImplementation /> calculate aliases when not informed 1`] = `
1022
1025
  "implementationKey": "impl_example_1",
1023
1026
  "implementationType": "default",
1024
1027
  "minimum": 2010,
1025
- "population": Array [
1026
- Object {
1027
- "modifier": undefined,
1028
- "operator": Object {
1029
- "group": "eq",
1030
- "id": 23,
1031
- "name": "eq",
1032
- "value_type": "field",
1033
- },
1034
- "structure": Object {
1035
- "external_id": "https://glue.eu-west-1.amazonaws.com/#/576759405678/cepsa-demo-s3/02_es_provincias/descripcion",
1036
- "field_type": "string",
1037
- "id": 4817544,
1038
- "metadata": Object {
1039
- "account": "576759405678",
1040
- "data_type_class": "string",
1041
- "database": "cepsa-demo-s3",
1042
- "order": "2.0",
1043
- "region": "eu-west-1",
1044
- "tablename": "02_es_provincias",
1045
- "type": "string",
1046
- },
1047
- "name": "descripcion",
1048
- "parent_index": 1,
1049
- "path": Array [
1050
- "cepsa-demo-s3",
1051
- "02_es_provincias",
1052
- ],
1053
- "system": Object {
1054
- "external_id": "glue",
1055
- "id": 94,
1056
- "name": "Glue",
1028
+ "populations": Array [
1029
+ Array [
1030
+ Object {
1031
+ "modifier": undefined,
1032
+ "operator": Object {
1033
+ "group": "eq",
1034
+ "id": 23,
1035
+ "name": "eq",
1036
+ "value_type": "field",
1057
1037
  },
1058
- "type": "Column",
1059
- },
1060
- "value": Array [
1061
- Object {
1062
- "external_id": "/home/alberto/projects/connectors/td-connector-txt-files/data/########_D_PELAYO_POLIZAS_20201202033016_I.txt[Aux. Externo]",
1063
- "id": 4814767,
1038
+ "structure": Object {
1039
+ "external_id": "https://glue.eu-west-1.amazonaws.com/#/576759405678/cepsa-demo-s3/02_es_provincias/descripcion",
1040
+ "field_type": "string",
1041
+ "id": 4817544,
1064
1042
  "metadata": Object {
1065
- "order": "8",
1043
+ "account": "576759405678",
1044
+ "data_type_class": "string",
1045
+ "database": "cepsa-demo-s3",
1046
+ "order": "2.0",
1047
+ "region": "eu-west-1",
1048
+ "tablename": "02_es_provincias",
1049
+ "type": "string",
1066
1050
  },
1067
- "name": "Aux. Externo",
1068
- "parent_index": 0,
1051
+ "name": "descripcion",
1052
+ "parent_index": 1,
1069
1053
  "path": Array [
1070
- "Area_Vida",
1071
- "########_D_PELAYO_POLIZAS_20201202033016_I.txt",
1054
+ "cepsa-demo-s3",
1055
+ "02_es_provincias",
1072
1056
  ],
1073
1057
  "system": Object {
1074
- "external_id": "file_system",
1075
- "id": 33,
1076
- "name": "File System",
1058
+ "external_id": "glue",
1059
+ "id": 94,
1060
+ "name": "Glue",
1077
1061
  },
1078
1062
  "type": "Column",
1079
1063
  },
1080
- ],
1081
- "value_modifier": undefined,
1082
- },
1064
+ "value": Array [
1065
+ Object {
1066
+ "external_id": "/home/alberto/projects/connectors/td-connector-txt-files/data/########_D_PELAYO_POLIZAS_20201202033016_I.txt[Aux. Externo]",
1067
+ "id": 4814767,
1068
+ "metadata": Object {
1069
+ "order": "8",
1070
+ },
1071
+ "name": "Aux. Externo",
1072
+ "parent_index": 0,
1073
+ "path": Array [
1074
+ "Area_Vida",
1075
+ "########_D_PELAYO_POLIZAS_20201202033016_I.txt",
1076
+ ],
1077
+ "system": Object {
1078
+ "external_id": "file_system",
1079
+ "id": 33,
1080
+ "name": "File System",
1081
+ },
1082
+ "type": "Column",
1083
+ },
1084
+ ],
1085
+ "value_modifier": undefined,
1086
+ },
1087
+ ],
1083
1088
  ],
1084
1089
  "rawContent": Object {},
1085
1090
  "result_type": "errors_number",
@@ -1157,6 +1162,7 @@ exports[`<NewRuleImplementation /> matches the latest snapshot 1`] = `
1157
1162
  stretched={true}
1158
1163
  >
1159
1164
  <Connect(RuleImplementationForm)
1165
+ addPopulation={[Function]}
1160
1166
  handleSubmit={[Function]}
1161
1167
  onChange={[Function]}
1162
1168
  ruleImplementation={
@@ -1172,6 +1178,7 @@ exports[`<NewRuleImplementation /> matches the latest snapshot 1`] = `
1172
1178
  "implementationType": "default",
1173
1179
  "minimum": null,
1174
1180
  "population": Array [],
1181
+ "populations": Array [],
1175
1182
  "rawContent": Object {
1176
1183
  "database": "",
1177
1184
  "dataset": "",
@@ -1186,7 +1193,7 @@ exports[`<NewRuleImplementation /> matches the latest snapshot 1`] = `
1186
1193
  }
1187
1194
  }
1188
1195
  setImplementationKey={[Function]}
1189
- setPopulation={[Function]}
1196
+ setPopulations={[Function]}
1190
1197
  setStructures={[Function]}
1191
1198
  setValidations={[Function]}
1192
1199
  />
@@ -1209,6 +1216,7 @@ exports[`<NewRuleImplementation /> matches the latest snapshot 1`] = `
1209
1216
  "implementationType": "default",
1210
1217
  "minimum": null,
1211
1218
  "population": Array [],
1219
+ "populations": Array [],
1212
1220
  "rawContent": Object {
1213
1221
  "database": "",
1214
1222
  "dataset": "",
@@ -63,7 +63,7 @@ exports[`<RuleImplementationProperties /> matches the latest snapshot 1`] = `
63
63
  activeSteps={
64
64
  Array [
65
65
  "dataset",
66
- "population",
66
+ "populations",
67
67
  "validations",
68
68
  ]
69
69
  }
@@ -6,30 +6,6 @@ import { Grid, Icon, Segment } from "semantic-ui-react";
6
6
  import { dropAt, replaceAt } from "@truedat/core/services/arrays";
7
7
  import { FiltersGrid } from "./FiltersGrid";
8
8
 
9
- const PopulationTypeForm = ({ createFilter }) => (
10
- <Grid columns={2} textAlign="center">
11
- <Grid.Column>
12
- <Segment className={`population active`}>
13
- <FormattedMessage id="populationForm.selectAll.text" />
14
- <Icon circular name="check" color="green" />
15
- </Segment>
16
- </Grid.Column>
17
- <Grid.Column>
18
- <Segment
19
- className={`population selectable`}
20
- onClick={() => createFilter()}
21
- >
22
- <Icon name="plus circle" />
23
- <FormattedMessage id="populationForm.createFilters.text" />
24
- </Segment>
25
- </Grid.Column>
26
- </Grid>
27
- );
28
-
29
- PopulationTypeForm.propTypes = {
30
- createFilter: PropTypes.func,
31
- };
32
-
33
9
  export default function PopulationForm({
34
10
  typeOperators,
35
11
  population,
@@ -45,9 +21,7 @@ export default function PopulationForm({
45
21
  } else setPopulation(dropAt(index)(population));
46
22
  };
47
23
 
48
- return _.isEmpty(population) ? (
49
- <PopulationTypeForm createFilter={() => setPopulation([{}])} />
50
- ) : (
24
+ return _.isEmpty(population) ? null : (
51
25
  <FiltersGrid
52
26
  rows={population}
53
27
  setRowValue={setPopulationField}
@@ -4,7 +4,15 @@ import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
5
  import { useHistory } from "react-router-dom";
6
6
  import { FormattedMessage, useIntl } from "react-intl";
7
- import { Button, Divider, Form, Grid, Icon, Step } from "semantic-ui-react";
7
+ import {
8
+ Button,
9
+ Divider,
10
+ Form,
11
+ Grid,
12
+ Icon,
13
+ Step,
14
+ Segment,
15
+ } from "semantic-ui-react";
8
16
  import { validateContent } from "@truedat/df/utils";
9
17
  import PopulationForm from "./PopulationForm";
10
18
  import DatasetForm from "./DatasetForm";
@@ -32,7 +40,8 @@ RuleImplementationStep.propTypes = {
32
40
  export const RuleImplementationForm = ({
33
41
  ruleImplementation,
34
42
  setStructures,
35
- setPopulation,
43
+ addPopulation,
44
+ setPopulations,
36
45
  setImplementationKey,
37
46
  setValidations,
38
47
  isSubmitting,
@@ -46,7 +55,7 @@ export const RuleImplementationForm = ({
46
55
  const steps = [
47
56
  { name: "information", icon: "info", isValid: () => validInformation() },
48
57
  { name: "dataset", icon: "database", isValid: () => validDataSet() },
49
- { name: "population", icon: "user", isValid: () => validPopulation() },
58
+ { name: "populations", icon: "user", isValid: () => validPopulations() },
50
59
  { name: "validations", icon: "setting", isValid: () => validValidations() },
51
60
  ];
52
61
 
@@ -55,7 +64,7 @@ export const RuleImplementationForm = ({
55
64
 
56
65
  const {
57
66
  dataset: structures,
58
- population,
67
+ populations,
59
68
  validations,
60
69
  dfContent,
61
70
  } = ruleImplementation || {};
@@ -66,8 +75,8 @@ export const RuleImplementationForm = ({
66
75
  _.size(validateContent(template)(dfContent)) == 0 &&
67
76
  areLimitsValid(ruleImplementation);
68
77
 
69
- const validPopulation = () =>
70
- _.every(_.isEmpty)(population) || populationComplete();
78
+ const validPopulations = () =>
79
+ _.every((population) => populationComplete(population))(populations);
71
80
 
72
81
  const validValidations = () =>
73
82
  _.every(_.negate(_.isEmpty))(validations) && validationsComplete();
@@ -90,11 +99,9 @@ export const RuleImplementationForm = ({
90
99
  _.size(clauses) > 0 &&
91
100
  _.every((c) => itemComplete(c, ["left", "right"]))(clauses);
92
101
 
93
- const populationComplete = () =>
94
- _.flow(
95
- _.filter(_.negate(_.isEmpty)),
96
- _.every((p) => itemComplete(p, attrsFromProfile(p)))
97
- )(population);
102
+ const populationComplete = (population) =>
103
+ _.every(_.negate(_.isEmpty))(population) &&
104
+ _.every((p) => itemComplete(p, attrsFromProfile(p)))(population);
98
105
 
99
106
  const validationsComplete = () =>
100
107
  _.every((v) => itemComplete(v, attrsFromProfile(v)))(validations);
@@ -231,14 +238,31 @@ export const RuleImplementationForm = ({
231
238
  }}
232
239
  />
233
240
  )}
234
- {activeStep == "population" && (
235
- <PopulationForm
236
- population={population}
237
- setPopulation={setPopulation}
238
- structures={structures}
239
- typeOperators={operators}
240
- />
241
- )}
241
+ {activeStep == "populations" ? (
242
+ <>
243
+ {populations.map((population, i) => (
244
+ <Segment key={i}>
245
+ <PopulationForm
246
+ population={population}
247
+ setPopulation={(p) => setPopulations(p, i)}
248
+ structures={structures}
249
+ typeOperators={operators}
250
+ />
251
+ </Segment>
252
+ ))}
253
+ {_.flow(_.flatten, _.isEmpty)(populations) ? (
254
+ <PopulationTypeForm createFilter={() => addPopulation()} />
255
+ ) : validPopulations() ? (
256
+ <Button
257
+ secondary
258
+ onClick={() => addPopulation()}
259
+ content={formatMessage({
260
+ id: "ruleImplementationForm.populations.add",
261
+ })}
262
+ />
263
+ ) : null}
264
+ </>
265
+ ) : null}
242
266
  {activeStep == "validations" && (
243
267
  <ValidationsForm
244
268
  validations={validations}
@@ -291,7 +315,8 @@ RuleImplementationForm.propTypes = {
291
315
  handleSubmit: PropTypes.func.isRequired,
292
316
  isSubmitting: PropTypes.bool.isRequired,
293
317
  setStructures: PropTypes.func,
294
- setPopulation: PropTypes.func,
318
+ addPopulation: PropTypes.func,
319
+ setPopulations: PropTypes.func,
295
320
  setImplementationKey: PropTypes.func,
296
321
  setValidations: PropTypes.func,
297
322
  operators: PropTypes.object,
@@ -305,3 +330,27 @@ const mapStateToProps = (state) => ({
305
330
  });
306
331
 
307
332
  export default connect(mapStateToProps)(RuleImplementationForm);
333
+
334
+ const PopulationTypeForm = ({ createFilter }) => (
335
+ <Grid columns={2} textAlign="center">
336
+ <Grid.Column>
337
+ <Segment className={`population active`}>
338
+ <FormattedMessage id="populationForm.selectAll.text" />
339
+ <Icon circular name="check" color="green" />
340
+ </Segment>
341
+ </Grid.Column>
342
+ <Grid.Column>
343
+ <Segment
344
+ className={`population selectable`}
345
+ onClick={() => createFilter()}
346
+ >
347
+ <Icon name="plus circle" />
348
+ <FormattedMessage id="populationForm.createFilters.text" />
349
+ </Segment>
350
+ </Grid.Column>
351
+ </Grid>
352
+ );
353
+
354
+ PopulationTypeForm.propTypes = {
355
+ createFilter: PropTypes.func,
356
+ };
@@ -37,7 +37,7 @@ exports[`<RuleImplementationForm /> matches the latest snapshot 1`] = `
37
37
  }
38
38
  }
39
39
  key="2"
40
- name="population"
40
+ name="populations"
41
41
  />
42
42
  <RuleImplementationStep
43
43
  activeStep="information"
@@ -138,7 +138,7 @@ export default {
138
138
  "All rule implementations should be removed",
139
139
  "rule.error.rule_name_bc_id.unique_constraint":
140
140
  "Duplicated rule name. Edit name or associated business concept.",
141
-
141
+
142
142
  "rule.form.accordion.select": "Select",
143
143
  "rule.form.concept.label": "Concept",
144
144
  "ruleImplementation.form.tooltip.deviation.goal":
@@ -441,9 +441,10 @@ export default {
441
441
  "ruleImplementation.system.placeholder": "Select a system",
442
442
  "ruleImplementation.table": "Table",
443
443
  "ruleImplementation.table.placeholder": "Select a table",
444
+ "ruleImplementationForm.populations.add": "Add population",
444
445
  "ruleImplementationForm.step.information": "Information",
445
446
  "ruleImplementationForm.step.dataset": "Data Set",
446
- "ruleImplementationForm.step.population": "Population",
447
+ "ruleImplementationForm.step.populations": "Populations",
447
448
  "ruleImplementationForm.step.validations": "Validations",
448
449
  "ruleImplementationRawForm.props.database": "Database",
449
450
  "ruleImplementationRawForm.props.database.placeholder": "Select database",
@@ -515,6 +516,7 @@ export default {
515
516
  "ruleImplementations.summary.headers.filters": "Filters",
516
517
  "ruleImplementations.summary.headers.implementation": "Rule Implementation",
517
518
  "ruleImplementations.summary.headers.population": "Population",
519
+ "ruleImplementations.summary.headers.populations": "Populations",
518
520
  "ruleImplementations.summary.headers.validations": "Validation",
519
521
  "ruleImplementations.upload.success.errors":
520
522
  "Error in {implementation_key} attribute: {key} message: {message} ",
@@ -455,9 +455,10 @@ export default {
455
455
  "ruleImplementation.system": "Sistema",
456
456
  "ruleImplementation.table.placeholder": "Seleccionar tabla",
457
457
  "ruleImplementation.table": "Tabla",
458
+ "ruleImplementationForm.populations.add": "Añadir población",
458
459
  "ruleImplementationForm.step.dataset": "Datos",
459
460
  "ruleImplementationForm.step.information": "Información",
460
- "ruleImplementationForm.step.population": "Población",
461
+ "ruleImplementationForm.step.populations": "Poblaciones",
461
462
  "ruleImplementationForm.step.validations": "Validaciones",
462
463
  "ruleImplementationRawForm.props.database.placeholder":
463
464
  "Seleccionar base de datos",
@@ -537,6 +538,7 @@ export default {
537
538
  "ruleImplementations.summary.headers.implementation":
538
539
  "Implementación de una Regla",
539
540
  "ruleImplementations.summary.headers.population": "Población",
541
+ "ruleImplementations.summary.headers.populations": "Poblaciones",
540
542
  "ruleImplementations.summary.headers.validations": "Validaciones",
541
543
  "ruleImplementations.upload.success.errors":
542
544
  "Error en {name} atributo: {key} mensaje: {message} ",
@@ -15,7 +15,7 @@ const pickFields = _.pick([
15
15
  "id",
16
16
  "implementation_key",
17
17
  "implementation_type",
18
- "population",
18
+ "populations",
19
19
  "raw_content",
20
20
  "results",
21
21
  "rule_id",
@@ -2,7 +2,7 @@ import { testSaga } from "redux-saga-test-plan";
2
2
  import { apiJsonPost, JSON_OPTS } from "@truedat/core/services/api";
3
3
  import {
4
4
  createRuleImplementationRequestSaga,
5
- createRuleImplementationSaga
5
+ createRuleImplementationSaga,
6
6
  } from "../createRuleImplementation";
7
7
  import { API_RULE_IMPLEMENTATIONS } from "../../api";
8
8
  import { createRuleImplementation, clearStructure } from "../../routines";
@@ -35,21 +35,23 @@ describe("sagas: createRuleImplementationSaga", () => {
35
35
  const rule_implementation = {
36
36
  implementation_key: "Awesome Impl Key",
37
37
  dataset: [{ structure: { id: 1 } }],
38
- population: [
39
- {
40
- operator: { name: "eq", value_type: "number" },
41
- structure: { id: 2 },
42
- value: [{ raw: 3 }]
43
- }
38
+ populations: [
39
+ [
40
+ {
41
+ operator: { name: "eq", value_type: "number" },
42
+ structure: { id: 2 },
43
+ value: [{ raw: 3 }],
44
+ },
45
+ ],
44
46
  ],
45
47
  validations: [
46
48
  {
47
49
  operator: { name: "between", value_type: "field" },
48
50
  structure: { id: 3 },
49
- value: [{ id: 4 }, { id: 5 }]
50
- }
51
+ value: [{ id: 4 }, { id: 5 }],
52
+ },
51
53
  ],
52
- rule_id: 1
54
+ rule_id: 1,
53
55
  };
54
56
  const data = { rule_implementation };
55
57
  const url = API_RULE_IMPLEMENTATIONS;
@@ -39,12 +39,14 @@ describe("sagas: updateRuleImplementationSaga", () => {
39
39
  id: 1,
40
40
  implementation_key: "impl_key",
41
41
  dataset: [{ structure: { id: 1 } }],
42
- population: [
43
- {
44
- operator: { name: "eq", value_type: "number" },
45
- structure: { id: 2 },
46
- value: [{ raw: 3 }],
47
- },
42
+ populations: [
43
+ [
44
+ {
45
+ operator: { name: "eq", value_type: "number" },
46
+ structure: { id: 2 },
47
+ value: [{ raw: 3 }],
48
+ },
49
+ ],
48
50
  ],
49
51
  validations: [
50
52
  {