@truedat/dq 4.36.0 → 4.36.4

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,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [4.36.4] 2022-01-19
4
+
5
+ ### Added
6
+
7
+ - [TD-4293] Add rule implementations `events`
8
+
9
+ ## [4.36.2] 2022-01-17
10
+
11
+ ### Added
12
+
13
+ - [TD-3178] Show join details in implementation summary
14
+
3
15
  ## [4.35.8] 2022-01-07
4
16
 
5
17
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dq",
3
- "version": "4.36.0",
3
+ "version": "4.36.4",
4
4
  "description": "Truedat Web Data Quality Module",
5
5
  "sideEffects": false,
6
6
  "jsnext:main": "src/index.js",
@@ -82,8 +82,8 @@
82
82
  },
83
83
  "dependencies": {
84
84
  "@apollo/client": "^3.4.10",
85
- "@truedat/core": "4.36.0",
86
- "@truedat/df": "4.36.0",
85
+ "@truedat/core": "4.36.4",
86
+ "@truedat/df": "4.36.4",
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": "6bf7c33362c73f97c8e5ff61f19c694ef28a0c3d"
106
+ "gitHead": "4dbf4f9e5188b82b17d053b65e76506e60aa6722"
107
107
  }
@@ -74,7 +74,12 @@ OperatorMessage.propTypes = {
74
74
  operator: PropTypes.object,
75
75
  };
76
76
 
77
- const ConditionCell = ({ row }) => {
77
+ const ConditionCell = ({ row, alias }) => {
78
+ const alias_text = _.flow(
79
+ _.find({ index: row.structure?.parent_index }),
80
+ _.propOr(null, "text")
81
+ )(alias);
82
+
78
83
  const values = getValues(row);
79
84
  const operator = _.prop("operator")(row);
80
85
  return (
@@ -87,10 +92,10 @@ const ConditionCell = ({ row }) => {
87
92
  id: _.path("structure.id")(row),
88
93
  })}
89
94
  >
90
- <span className="highlighted">{`"${_.pathOr(
91
- "",
92
- "structure.name"
93
- )(row)}"`}</span>
95
+ <span className="highlighted">
96
+ {alias_text && `(${alias_text}).`}{" "}
97
+ {`"${_.pathOr("", "structure.name")(row)}"`}
98
+ </span>
94
99
  </Link>
95
100
  {row?.modifier && (
96
101
  <>
@@ -155,9 +160,10 @@ const ConditionCell = ({ row }) => {
155
160
 
156
161
  ConditionCell.propTypes = {
157
162
  row: PropTypes.object,
163
+ alias: PropTypes.array,
158
164
  };
159
165
 
160
- export const ConditionSummary = ({ rows, type, icon }) =>
166
+ export const ConditionSummary = ({ rows, type, icon, alias }) =>
161
167
  empty(rows) ? null : (
162
168
  <>
163
169
  <Header as="h3">
@@ -185,7 +191,7 @@ export const ConditionSummary = ({ rows, type, icon }) =>
185
191
  </Table.Header>
186
192
  <Table.Body>
187
193
  {rows.map((row, i) => (
188
- <ConditionCell key={i} row={row} />
194
+ <ConditionCell key={i} row={row} alias={alias} />
189
195
  ))}
190
196
  </Table.Body>
191
197
  </Table>
@@ -1,12 +1,13 @@
1
1
  import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
- import { Header, Icon, Table, Segment } from "semantic-ui-react";
4
+ import { Header, Icon, Table, Segment, List } from "semantic-ui-react";
5
5
  import { Link } from "react-router-dom";
6
6
  import { FormattedMessage } from "react-intl";
7
7
  import { linkTo } from "@truedat/core/routes";
8
8
  import ConditionSummary, { empty, path } from "./ConditionSummary";
9
9
  import InformationSummary from "./InformationSummary";
10
+ import "../styles/ImplementationSummary.less";
10
11
 
11
12
  const defaults = [
12
13
  "executable",
@@ -39,7 +40,45 @@ FormattedLink.propTypes = {
39
40
  operator: PropTypes.object,
40
41
  };
41
42
 
42
- const DatasetSummary = ({ rows }) =>
43
+ const AliasText = ({ alias, clause }) => {
44
+ const text = _.flow(
45
+ _.find({ index: clause?.parent_index }),
46
+ _.propOr(null, "text")
47
+ )(alias);
48
+ return _.isNull(text) ? clause?.name : `(${text}).${clause?.name}`;
49
+ };
50
+
51
+ AliasText.propTypes = {
52
+ alias: PropTypes.array,
53
+ clause: PropTypes.object,
54
+ };
55
+
56
+ const UnionSummary = ({ alias, row }) => {
57
+ return empty(row) || !(row?.clauses && _.size(row?.clauses) > 0) ? null : (
58
+ <List id="union-list">
59
+ <List.Item>
60
+ <List.Header>
61
+ <FormattedMessage id="structureSelector.union.criteria" />
62
+ </List.Header>
63
+ </List.Item>
64
+ {row.clauses.map((clause, k) =>
65
+ _.size(clause) > 0 ? (
66
+ <List.Item key={k}>
67
+ {clause.left && <AliasText alias={alias} clause={clause.left} />} ={" "}
68
+ {clause.right && <AliasText alias={alias} clause={clause.right} />}
69
+ </List.Item>
70
+ ) : null
71
+ )}
72
+ </List>
73
+ );
74
+ };
75
+
76
+ UnionSummary.propTypes = {
77
+ row: PropTypes.object,
78
+ alias: PropTypes.array,
79
+ };
80
+
81
+ const DatasetSummary = ({ rows, alias }) =>
43
82
  empty(rows) ? null : (
44
83
  <>
45
84
  <Header as="h3">
@@ -61,16 +100,19 @@ const DatasetSummary = ({ rows }) =>
61
100
  {rows.map((row, i) => (
62
101
  <Table.Row key={i}>
63
102
  {_.has("structure")(row) && (
64
- <Table.Cell key={i}>
103
+ <Table.Cell>
65
104
  <Link
66
105
  to={linkTo.STRUCTURE({
67
106
  id: _.pathOr("", "structure.id")(row),
68
107
  })}
69
108
  >
70
- <span key={i} className="highlighted">{`"${path(
109
+ <p className="highlighted">{`"${path(
71
110
  _.propOr({}, "structure")(row)
72
- )}"`}</span>
111
+ )}"`}</p>
73
112
  </Link>
113
+
114
+ {row.alias?.text && <span>({row.alias.text})</span>}
115
+ <UnionSummary alias={alias} row={row} />
74
116
  </Table.Cell>
75
117
  )}
76
118
  </Table.Row>
@@ -83,12 +125,14 @@ const DatasetSummary = ({ rows }) =>
83
125
 
84
126
  DatasetSummary.propTypes = {
85
127
  rows: PropTypes.array,
128
+ alias: PropTypes.array,
86
129
  };
87
130
 
88
131
  export const ImplementationSummary = ({ ruleImplementation, activeSteps }) => {
89
132
  const steps = _.isEmpty(activeSteps) ? defaults : activeSteps;
90
133
  const { dataset, population, validations } =
91
134
  _.pick(steps)(ruleImplementation);
135
+ const alias = _.map(_.propOr({}, "alias"))(dataset);
92
136
  return (
93
137
  <>
94
138
  {(_.includes("implementationKey")(steps) ||
@@ -96,16 +140,22 @@ export const ImplementationSummary = ({ ruleImplementation, activeSteps }) => {
96
140
  <InformationSummary ruleImplementation={ruleImplementation} />
97
141
  )}
98
142
  {dataset && _.includes("dataset")(steps) && (
99
- <DatasetSummary rows={dataset} />
143
+ <DatasetSummary rows={dataset} alias={alias} />
100
144
  )}
101
145
  {population && _.includes("population")(steps) && (
102
- <ConditionSummary type="population" icon="user" rows={population} />
146
+ <ConditionSummary
147
+ type="population"
148
+ icon="user"
149
+ rows={population}
150
+ alias={alias}
151
+ />
103
152
  )}
104
153
  {validations && _.includes("validations")(steps) && (
105
154
  <ConditionSummary
106
155
  type="validations"
107
156
  icon="setting"
108
157
  rows={validations}
158
+ alias={alias}
109
159
  />
110
160
  )}
111
161
  </>
@@ -0,0 +1,48 @@
1
+ import _ from "lodash/fp";
2
+ import React from "react";
3
+ import PropTypes from "prop-types";
4
+ import { Feed } from "semantic-ui-react";
5
+ import { useIntl } from "react-intl";
6
+ import Moment from "react-moment";
7
+
8
+ export const RuleImplementationEventRow = ({
9
+ user,
10
+ user_name,
11
+ ts,
12
+ payload,
13
+ }) => {
14
+ const { formatMessage, locale } = useIntl();
15
+ const userName = _.propOr(user_name, "user_name")(user);
16
+
17
+ return _.isEmpty(payload) ? null : (
18
+ <Feed.Event>
19
+ <Feed.Content>
20
+ <Feed.Summary>
21
+ <Feed.User>{userName}</Feed.User>{" "}
22
+ <Feed.Date>
23
+ <Moment locale={locale} date={ts} format="YYYY-MM-DD HH:mm" />
24
+ </Feed.Date>
25
+ </Feed.Summary>
26
+ {payload.map(({ field, action, value }, i) => (
27
+ <Feed.Extra
28
+ key={i}
29
+ text
30
+ content={formatMessage(
31
+ { id: "ruleImplementations.events.action_" + action },
32
+ [field, value]
33
+ )}
34
+ />
35
+ ))}
36
+ </Feed.Content>
37
+ </Feed.Event>
38
+ );
39
+ };
40
+
41
+ RuleImplementationEventRow.propTypes = {
42
+ user: PropTypes.object,
43
+ user_name: PropTypes.string,
44
+ ts: PropTypes.string,
45
+ payload: PropTypes.array,
46
+ };
47
+
48
+ export default RuleImplementationEventRow;
@@ -0,0 +1,29 @@
1
+ import React from "react";
2
+ import PropTypes from "prop-types";
3
+ import { Feed, Segment } from "semantic-ui-react";
4
+ import { connect } from "react-redux";
5
+ import { getParsedEvents } from "../selectors";
6
+ import { RuleImplementationEventRow } from "./RuleImplementationEventRow";
7
+
8
+ export const RuleImplementationEvents = ({ events, eventsLoading }) => {
9
+ return eventsLoading ? null : (
10
+ <Segment attached="bottom">
11
+ <Feed size="small">
12
+ {events.map((e, i) => (
13
+ <RuleImplementationEventRow key={i} {...e} />
14
+ ))}
15
+ </Feed>
16
+ </Segment>
17
+ );
18
+ };
19
+ RuleImplementationEvents.propTypes = {
20
+ events: PropTypes.array.isRequired,
21
+ eventsLoading: PropTypes.bool,
22
+ };
23
+
24
+ const mapStateToProps = (state) => ({
25
+ events: getParsedEvents(state),
26
+ eventsLoading: state.eventsLoading,
27
+ });
28
+
29
+ export default connect(mapStateToProps)(RuleImplementationEvents);
@@ -7,6 +7,7 @@ import { compose } from "redux";
7
7
  import { connect } from "react-redux";
8
8
  import { FormattedMessage } from "react-intl";
9
9
  import {
10
+ RULE_IMPLEMENTATION_EVENTS,
10
11
  RULE_IMPLEMENTATION_RESULTS_DETAILS,
11
12
  RULE_IMPLEMENTATION_MOVE,
12
13
  RULE_IMPLEMENTATION_RESULTS,
@@ -59,6 +60,16 @@ export const RuleImplementationTabs = ({ rule, ruleImplementation, match }) => {
59
60
  <FormattedMessage id="tabs.dq.ruleImplementation.details" />
60
61
  </Menu.Item>
61
62
  )}
63
+ <Menu.Item
64
+ active={match.path === RULE_IMPLEMENTATION_EVENTS}
65
+ as={Link}
66
+ to={linkTo.RULE_IMPLEMENTATION_EVENTS({
67
+ id: rule.id,
68
+ implementation_id: ruleImplementation.id,
69
+ })}
70
+ >
71
+ <FormattedMessage id="tabs.dq.ruleImplementation.audit" />
72
+ </Menu.Item>
62
73
  </Menu>
63
74
  );
64
75
  };
@@ -1,7 +1,7 @@
1
1
  import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
- import { Route, Switch } from "react-router-dom";
4
+ import { Route, Switch, useRouteMatch } from "react-router-dom";
5
5
  import { connect } from "react-redux";
6
6
  import { Segment } from "semantic-ui-react";
7
7
  import { Unauthorized } from "@truedat/core/components";
@@ -12,6 +12,7 @@ import {
12
12
  RULE_IMPLEMENTATION_RESULT_DETAILS,
13
13
  RULE_IMPLEMENTATION_RESULTS_DETAILS,
14
14
  RULE_IMPLEMENTATION,
15
+ RULE_IMPLEMENTATION_EVENTS,
15
16
  RULE_IMPLEMENTATION_NEW,
16
17
  RULE_IMPLEMENTATION_CLONE,
17
18
  RULE_IMPLEMENTATION_EDIT,
@@ -32,6 +33,7 @@ import NewRuleImplementation from "./NewRuleImplementation";
32
33
  import Rule from "./Rule";
33
34
  import RuleCrumbs from "./RuleCrumbs";
34
35
  import RuleImplementation from "./RuleImplementation";
36
+ import RuleImplementationEvents from "./RuleImplementationEvents";
35
37
  import RuleImplementationLoader from "./RuleImplementationLoader";
36
38
  import RuleImplementationProperties from "./RuleImplementationProperties";
37
39
  import RuleImplementationResults from "./RuleImplementationResults";
@@ -47,6 +49,9 @@ const DomainsLoader = React.lazy(() =>
47
49
  const DynamicFormViewer = React.lazy(() =>
48
50
  import("@truedat/df/components/DynamicFormViewer")
49
51
  );
52
+ const EventsLoader = React.lazy(() =>
53
+ import("@truedat/audit/components/EventsLoader")
54
+ );
50
55
  const TemplatesLoader = React.lazy(() =>
51
56
  import("@truedat/df/templates/components/TemplatesLoader")
52
57
  );
@@ -56,6 +61,12 @@ const ImplementationStructuresLoader = React.lazy(() =>
56
61
  const QualityTemplatesLoader = () => <TemplatesLoader scope="dq" />;
57
62
  const ImplementationTemplatesLoader = () => <TemplatesLoader scope="ri" />;
58
63
 
64
+ const ImplementationEventsLoader = () => {
65
+ const match = useRouteMatch();
66
+ const id = _.path("params.implementation_id")(match);
67
+ return <EventsLoader resource_id={id} resource_type="implementation" />;
68
+ };
69
+
59
70
  const RuleRoutes = ({
60
71
  ruleLoaded,
61
72
  ruleImplementationLoaded,
@@ -132,6 +143,7 @@ const RuleRoutes = ({
132
143
  <RuleCrumbs />
133
144
  <Segment>
134
145
  <RuleSubscriptionLoader />
146
+ <RuleImplementationLoader />
135
147
  <RuleImplementationsFromRuleLoader />
136
148
  {ruleLoaded && <Rule />}
137
149
  {ruleLoaded && <RuleFormImplementations />}
@@ -139,6 +151,25 @@ const RuleRoutes = ({
139
151
  </>
140
152
  )}
141
153
  />
154
+ <Route
155
+ exact
156
+ path={RULE_IMPLEMENTATION_EVENTS}
157
+ render={() => (
158
+ <>
159
+ <RuleCrumbs />
160
+ <Segment>
161
+ <ImplementationEventsLoader />
162
+ <RuleImplementationLoader />
163
+ {ruleLoaded && ruleImplementationLoaded && (
164
+ <RuleImplementation>
165
+ <RuleImplementationEvents />
166
+ </RuleImplementation>
167
+ )}
168
+ </Segment>
169
+ </>
170
+ )}
171
+ />
172
+
142
173
  <Route
143
174
  exact
144
175
  path={RULE_IMPLEMENTATION_NEW}
@@ -271,7 +302,6 @@ const RuleRoutes = ({
271
302
  <>
272
303
  <Segment>
273
304
  <RuleImplementationLoader />
274
-
275
305
  {ruleLoaded && ruleImplementationLoaded && (
276
306
  <>
277
307
  <RuleCrumbs />
@@ -42,6 +42,7 @@ const ruleImplementation = {
42
42
  id: 1,
43
43
  name: "Microstrategy",
44
44
  },
45
+ alias: [{ index: 0, text: "bar" }],
45
46
  },
46
47
  },
47
48
  ],
@@ -21,6 +21,7 @@ const renderOpts = {
21
21
  en: {
22
22
  "tabs.dq.ruleImplementation.results": "results",
23
23
  "tabs.dq.ruleImplementation": "implementation",
24
+ "tabs.dq.ruleImplementation.audit": "events",
24
25
  "ruleImplementation.actions.clone": "clone",
25
26
  "ruleImplementation.actions.move": "move",
26
27
  "ruleImplementation.actions.edit": "edit",
@@ -0,0 +1,43 @@
1
+ import React from "react";
2
+ import { render } from "@truedat/test/render";
3
+ import { RuleImplementationEvents } from "../RuleImplementationEvents";
4
+
5
+ describe("<RuleImplementationEvents />", () => {
6
+ const events = [
7
+ {
8
+ id: 1,
9
+ service: "service",
10
+ event: "implementation_restored",
11
+ resource_id: 100,
12
+ ts: "2019-08-12T02:00:00Z",
13
+ payload: [{ field: "foo", action: "restored" }],
14
+ },
15
+ {
16
+ id: 2,
17
+ service: "service",
18
+ event: "implementation_deprecated",
19
+ resource_id: 100,
20
+ ts: "2019-09-12T02:00:00Z",
21
+ payload: [{ field: "bar", action: "deprecated" }],
22
+ },
23
+ ];
24
+ const renderOpts = {
25
+ messages: {
26
+ en: {
27
+ "ruleImplementations.events.field_restored": "implementation restored",
28
+ "ruleImplementations.events.field_deprecated":
29
+ "implementation deprecated",
30
+ },
31
+ },
32
+ };
33
+
34
+ const props = { events };
35
+
36
+ it("matches the latest snapshot", () => {
37
+ const { container } = render(
38
+ <RuleImplementationEvents {...props} />,
39
+ renderOpts
40
+ );
41
+ expect(container).toMatchSnapshot();
42
+ });
43
+ });
@@ -59,6 +59,7 @@ exports[`<ConditionSummary /> matches the latest snapshot 1`] = `
59
59
  <span
60
60
  class="highlighted"
61
61
  >
62
+
62
63
  "Mes"
63
64
  </span>
64
65
  </a>
@@ -133,11 +133,11 @@ exports[`<ImplementationSummary /> displays correctly validations values of list
133
133
  <a
134
134
  href="/structures/1915"
135
135
  >
136
- <span
136
+ <p
137
137
  class="highlighted"
138
138
  >
139
139
  "CMC &gt; Objetos Públicos &gt; 0. 0 Meses"
140
- </span>
140
+ </p>
141
141
  </a>
142
142
  </td>
143
143
  </tr>
@@ -201,6 +201,7 @@ exports[`<ImplementationSummary /> displays correctly validations values of list
201
201
  <span
202
202
  class="highlighted"
203
203
  >
204
+
204
205
  "Mes"
205
206
  </span>
206
207
  </a>
@@ -238,6 +239,12 @@ exports[`<ImplementationSummary /> matches the latest snapshot 1`] = `
238
239
  "dataset": Array [
239
240
  Object {
240
241
  "structure": Object {
242
+ "alias": Array [
243
+ Object {
244
+ "index": 0,
245
+ "text": "bar",
246
+ },
247
+ ],
241
248
  "id": 1915,
242
249
  "name": "0. 0 Meses",
243
250
  "path": Array [
@@ -293,10 +300,21 @@ exports[`<ImplementationSummary /> matches the latest snapshot 1`] = `
293
300
  }
294
301
  />
295
302
  <DatasetSummary
303
+ alias={
304
+ Array [
305
+ Object {},
306
+ ]
307
+ }
296
308
  rows={
297
309
  Array [
298
310
  Object {
299
311
  "structure": Object {
312
+ "alias": Array [
313
+ Object {
314
+ "index": 0,
315
+ "text": "bar",
316
+ },
317
+ ],
300
318
  "id": 1915,
301
319
  "name": "0. 0 Meses",
302
320
  "path": Array [
@@ -314,6 +332,11 @@ exports[`<ImplementationSummary /> matches the latest snapshot 1`] = `
314
332
  }
315
333
  />
316
334
  <ConditionSummary
335
+ alias={
336
+ Array [
337
+ Object {},
338
+ ]
339
+ }
317
340
  icon="user"
318
341
  rows={
319
342
  Array [
@@ -323,6 +346,11 @@ exports[`<ImplementationSummary /> matches the latest snapshot 1`] = `
323
346
  type="population"
324
347
  />
325
348
  <ConditionSummary
349
+ alias={
350
+ Array [
351
+ Object {},
352
+ ]
353
+ }
326
354
  icon="setting"
327
355
  rows={
328
356
  Array [
@@ -140,6 +140,12 @@ exports[`<RuleImplementation /> matches the latest snapshot 1`] = `
140
140
  >
141
141
  results
142
142
  </a>
143
+ <a
144
+ class="item"
145
+ href="/rules/1/implementations/1/events"
146
+ >
147
+ events
148
+ </a>
143
149
  </div>
144
150
  </div>
145
151
  `;
@@ -0,0 +1,74 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`<RuleImplementationEvents /> matches the latest snapshot 1`] = `
4
+ <div>
5
+ <div
6
+ class="ui bottom attached segment"
7
+ >
8
+ <div
9
+ class="ui small feed"
10
+ >
11
+ <div
12
+ class="event"
13
+ >
14
+ <div
15
+ class="content"
16
+ >
17
+ <div
18
+ class="summary"
19
+ >
20
+ <a
21
+ class="user"
22
+ />
23
+
24
+ <div
25
+ class="date"
26
+ >
27
+ <time
28
+ datetime="1565575200000"
29
+ >
30
+ 2019-08-12 02:00
31
+ </time>
32
+ </div>
33
+ </div>
34
+ <div
35
+ class="text extra"
36
+ >
37
+ ruleImplementations.events.action_restored
38
+ </div>
39
+ </div>
40
+ </div>
41
+ <div
42
+ class="event"
43
+ >
44
+ <div
45
+ class="content"
46
+ >
47
+ <div
48
+ class="summary"
49
+ >
50
+ <a
51
+ class="user"
52
+ />
53
+
54
+ <div
55
+ class="date"
56
+ >
57
+ <time
58
+ datetime="1568253600000"
59
+ >
60
+ 2019-09-12 02:00
61
+ </time>
62
+ </div>
63
+ </div>
64
+ <div
65
+ class="text extra"
66
+ >
67
+ ruleImplementations.events.action_deprecated
68
+ </div>
69
+ </div>
70
+ </div>
71
+ </div>
72
+ </div>
73
+ </div>
74
+ `;
@@ -12,6 +12,7 @@ import QualityRoutes from "./QualityRoutes";
12
12
  import Rule from "./Rule";
13
13
  import RuleForm from "./RuleForm";
14
14
  import RuleFormImplementations from "./RuleFormImplementations";
15
+ import RuleImplementationEvents from "./RuleImplementationEvents";
15
16
  import RuleImplementationsFromRuleLoader from "./RuleImplementationsFromRuleLoader";
16
17
  import RuleImplementationsLoader from "./RuleImplementationsLoader";
17
18
  import RuleLoader from "./RuleLoader";
@@ -35,6 +36,7 @@ export {
35
36
  Rule,
36
37
  RuleForm,
37
38
  RuleFormImplementations,
39
+ RuleImplementationEvents,
38
40
  RuleImplementationsLoader,
39
41
  RuleImplementationsFromRuleLoader,
40
42
  RuleLoader,
@@ -7,6 +7,7 @@ import { dropAt, replaceAt } from "@truedat/core/services/arrays";
7
7
  import { Button } from "semantic-ui-react";
8
8
  import { setImplementationFilterValues } from "../../routines";
9
9
  import { getRuleImplementationFormFilters } from "../../selectors";
10
+ import "../../styles/ruleImplementationForm/DatasetForm.less";
10
11
 
11
12
  const StructureSelectorInputField = React.lazy(() =>
12
13
  import("@truedat/dd/components/StructureSelectorInputField")
@@ -116,7 +117,9 @@ export const DatasetForm = ({
116
117
  systemRequired={false}
117
118
  />
118
119
  ))}
120
+
119
121
  <Button
122
+ id="add-structure-button"
120
123
  onClick={(e) => {
121
124
  e.preventDefault();
122
125
  setStructure({ value: { join_type: "inner" } });
@@ -144,6 +144,7 @@ exports[`<DatasetForm /> matches the latest snapshot 1`] = `
144
144
  />
145
145
  <Button
146
146
  as="button"
147
+ id="add-structure-button"
147
148
  onClick={[Function]}
148
149
  >
149
150
  dataset.form.button.add_structure
@@ -5,6 +5,7 @@ export default {
5
5
  "actions.prev": "Previous",
6
6
  "actions.save": "Save",
7
7
  "actions.submit": "Submit",
8
+ "alert.deleteRuleImplementation.failed.header": "Error deprecating implementation",
8
9
  "alert.createExecutionGroup.success.content":
9
10
  "{count} implementations queued for execution",
10
11
  "alert.createExecutionGroup.success.header": "Executions scheduled",
@@ -464,6 +465,12 @@ export default {
464
465
  "ruleImplementations.actions.upload.tooltip": "Upload Implementations",
465
466
  "ruleImplementations.actions.upload.confirmation.header":
466
467
  "Confirm bulk upload",
468
+ "ruleImplementations.events.action_created": "Implementation created on rule: {0}",
469
+ "ruleImplementations.events.action_changed": "Field {0} changed to {1}",
470
+ "ruleImplementations.events.action_deprecated": "Implementation deprecated",
471
+ "ruleImplementations.events.action_moved": "Implementation moved to rule: {0}",
472
+ "ruleImplementations.events.action_restored": "Implementation restored",
473
+ "ruleImplementations.events.action_updated": "Implementation updated",
467
474
  "ruleImplementations.header": "Quality Implementations",
468
475
  "ruleImplementations.props.business_concept": "Concept",
469
476
  "ruleImplementations.props.status": "Status",
@@ -543,11 +550,13 @@ export default {
543
550
  "Error uploading file. No rules have been created.",
544
551
  "rules.upload.failed.misssing_required_columns":
545
552
  "Missing required columns. Expected [{expected}]. Found [{found}].",
553
+ "structureSelector.union.criteria": "Union criteria",
546
554
  "structureFields.dropdown.label": "Select Field",
547
555
  "structureFields.dropdown.placeholder": "Fields",
548
556
  "summary.link.and": "and",
549
557
  "tabs.dq.rule": "Rule",
550
558
  "tabs.dq.ruleImplementation": "Implementation",
559
+ "tabs.dq.ruleImplementation.audit": "Audit",
551
560
  "tabs.dq.ruleImplementation.details": "Details",
552
561
  "tabs.dq.ruleImplementation.results": "Results",
553
562
  "tabs.dq.ruleImplementations": "Implementations",
@@ -5,6 +5,7 @@ export default {
5
5
  "actions.prev": "Anterior",
6
6
  "actions.save": "Guardar",
7
7
  "actions.submit": "Guardar",
8
+ "alert.deleteRuleImplementation.failed.header": "Error al archivar implementación",
8
9
  "alert.createExecutionGroup.success.content":
9
10
  "Se ha solicitado la ejecución de {count} implementaciones",
10
11
  "alert.createExecutionGroup.success.header": "Ejecuciones programadas",
@@ -476,6 +477,12 @@ export default {
476
477
  "ruleImplementations.actions.create": "Crear nueva implementación",
477
478
  "ruleImplementations.actions.edit": "Editar implementación",
478
479
  "ruleImplementations.actions.popup.deprecated": "Implementaciones Archivadas",
480
+ "ruleImplementations.events.action_created": "Implementación creada en regla: {0}",
481
+ "ruleImplementations.events.action_changed": "Campo {0} actualizado a {1}",
482
+ "ruleImplementations.events.action_deprecated": "Implementación archivada",
483
+ "ruleImplementations.events.action_moved": "Implementación movida a la regla: {0}",
484
+ "ruleImplementations.events.action_restored": "Implementación restaurada",
485
+ "ruleImplementations.events.action_updated": "Implementación actualizada",
479
486
  "ruleImplementations.header": "Implementaciones de calidad",
480
487
  "ruleImplementations.props.business_concept": "Concepto",
481
488
  "ruleImplementations.props.executable.false": "Interna",
@@ -559,10 +566,12 @@ export default {
559
566
  "rules.upload.failed.misssing_required_columns":
560
567
  "Faltan columnas obligatorias en el fichero. Esperado [{expected}]. Recibido [{found}].",
561
568
  "ruleSubscription.actions.remove": "Eliminar",
569
+ "structureSelector.union.criteria": "Criterio de unión",
562
570
  "structureFields.dropdown.label": "Seleccionar Campo",
563
571
  "structureFields.dropdown.placeholder": "Campos",
564
572
  "summary.link.and": "y",
565
573
  "tabs.dq.rule": "Regla",
574
+ "tabs.dq.ruleImplementation.audit": "Auditoría",
566
575
  "tabs.dq.ruleImplementation.details": "Detalles",
567
576
  "tabs.dq.ruleImplementation.results": "Resultados",
568
577
  "tabs.dq.ruleImplementation": "Implementación",
@@ -0,0 +1,86 @@
1
+ import _ from "lodash/fp";
2
+ import { createSelector } from "reselect";
3
+
4
+ const getEvents = ({ events }) => {
5
+ return events;
6
+ };
7
+
8
+ const transformFieldFormat = (field) =>
9
+ _.isBoolean(field) ? _.toString(field) : field;
10
+
11
+ const getParsedEvents = createSelector([getEvents], (events) => {
12
+ return _.map((d) => {
13
+ switch (d.event) {
14
+ case "implementation_created":
15
+ return {
16
+ ...d,
17
+ payload: [
18
+ {
19
+ field: _.path("payload.rule_name")(d),
20
+ action: "created",
21
+ },
22
+ ],
23
+ };
24
+ case "implementation_moved":
25
+ return {
26
+ ...d,
27
+ payload: [
28
+ {
29
+ field: _.path("payload.rule_name")(d),
30
+ action: "moved",
31
+ },
32
+ ],
33
+ };
34
+ case "implementation_restored":
35
+ return {
36
+ ...d,
37
+ payload: [
38
+ {
39
+ field: _.path("payload.implementation_key")(d),
40
+ action: "restored",
41
+ },
42
+ ],
43
+ };
44
+ case "implementation_deleted":
45
+ return {};
46
+ case "implementation_deprecated":
47
+ return {
48
+ ...d,
49
+ payload: [
50
+ {
51
+ field: _.path("payload.implementation_key")(d),
52
+ action: "deprecated",
53
+ },
54
+ ],
55
+ };
56
+ case "implementation_changed":
57
+ return {
58
+ ...d,
59
+ payload: _.flow(
60
+ _.path("payload.df_content.changed"),
61
+ _.keys,
62
+ _.map((e) => ({
63
+ field: e,
64
+ action: "changed",
65
+ value: transformFieldFormat(
66
+ _.path(`payload.df_content.changed.${e}`)(d)
67
+ ),
68
+ }))
69
+ )(d),
70
+ };
71
+
72
+ default:
73
+ return {
74
+ ...d,
75
+ payload: [
76
+ {
77
+ field: _.path("payload.implementation_key")(d),
78
+ action: "updated",
79
+ },
80
+ ],
81
+ };
82
+ }
83
+ })(events);
84
+ });
85
+
86
+ export { getParsedEvents };
@@ -28,3 +28,4 @@ export { getRuleImplementationSelectedFilters } from "./getRuleImplementationSel
28
28
  export { getRuleImplementationSelectedFilterValues } from "./getRuleImplementationSelectedFilterValues";
29
29
  export { getRuleImplementationSelectedFilterActiveValues } from "./getRuleImplementationSelectedFilterActiveValues";
30
30
  export * from "./getImplementationStructures";
31
+ export { getParsedEvents } from "./getParsedEvents";
@@ -0,0 +1,3 @@
1
+ #union-list {
2
+ margin-top: 15px;
3
+ }
@@ -0,0 +1,3 @@
1
+ #add-structure-button {
2
+ margin-top: 12px;
3
+ }