@truedat/dq 4.36.1 → 4.36.5
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 +9 -3
- package/package.json +4 -4
- package/src/components/ConditionSummary.js +13 -7
- package/src/components/ImplementationSummary.js +57 -7
- package/src/components/RuleImplementationEventRow.js +48 -0
- package/src/components/RuleImplementationEvents.js +29 -0
- package/src/components/RuleImplementationTabs.js +11 -0
- package/src/components/RuleRoutes.js +32 -2
- package/src/components/__tests__/ImplementationSummary.spec.js +1 -0
- package/src/components/__tests__/RuleImplementation.spec.js +1 -0
- package/src/components/__tests__/RuleImplementationEvents.spec.js +43 -0
- package/src/components/__tests__/__snapshots__/ConditionSummary.spec.js.snap +1 -0
- package/src/components/__tests__/__snapshots__/ImplementationSummary.spec.js.snap +30 -2
- package/src/components/__tests__/__snapshots__/RuleImplementation.spec.js.snap +6 -0
- package/src/components/__tests__/__snapshots__/RuleImplementationEvents.spec.js.snap +74 -0
- package/src/components/index.js +2 -0
- package/src/components/ruleImplementationForm/DatasetForm.js +4 -1
- package/src/components/ruleImplementationForm/__tests__/DataSetForm.spec.js +11 -11
- package/src/components/ruleImplementationForm/__tests__/__snapshots__/DataSetForm.spec.js.snap +6 -5
- package/src/messages/en.js +9 -0
- package/src/messages/es.js +9 -0
- package/src/selectors/getParsedEvents.js +86 -0
- package/src/selectors/index.js +1 -0
- package/src/styles/ImplementationSummary.less +3 -0
- package/src/styles/ruleImplementationForm/DatasetForm.less +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [4.36.
|
|
3
|
+
## [4.36.4] 2022-01-19
|
|
4
4
|
|
|
5
|
-
###
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- [TD-4293] Add rule implementations `events`
|
|
8
|
+
|
|
9
|
+
## [4.36.2] 2022-01-17
|
|
10
|
+
|
|
11
|
+
### Added
|
|
6
12
|
|
|
7
|
-
- [TD-
|
|
13
|
+
- [TD-3178] Show join details in implementation summary
|
|
8
14
|
|
|
9
15
|
## [4.35.8] 2022-01-07
|
|
10
16
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/dq",
|
|
3
|
-
"version": "4.36.
|
|
3
|
+
"version": "4.36.5",
|
|
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.
|
|
86
|
-
"@truedat/df": "4.36.
|
|
85
|
+
"@truedat/core": "4.36.5",
|
|
86
|
+
"@truedat/df": "4.36.5",
|
|
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": "
|
|
106
|
+
"gitHead": "dec36033435443b730ea93fa482ef1ca7dbf28a6"
|
|
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">
|
|
91
|
-
""
|
|
92
|
-
"structure.name"
|
|
93
|
-
|
|
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
|
|
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
|
|
103
|
+
<Table.Cell>
|
|
65
104
|
<Link
|
|
66
105
|
to={linkTo.STRUCTURE({
|
|
67
106
|
id: _.pathOr("", "structure.id")(row),
|
|
68
107
|
})}
|
|
69
108
|
>
|
|
70
|
-
<
|
|
109
|
+
<p className="highlighted">{`"${path(
|
|
71
110
|
_.propOr({}, "structure")(row)
|
|
72
|
-
)}"`}</
|
|
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
|
|
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 />
|
|
@@ -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
|
+
});
|
|
@@ -133,11 +133,11 @@ exports[`<ImplementationSummary /> displays correctly validations values of list
|
|
|
133
133
|
<a
|
|
134
134
|
href="/structures/1915"
|
|
135
135
|
>
|
|
136
|
-
<
|
|
136
|
+
<p
|
|
137
137
|
class="highlighted"
|
|
138
138
|
>
|
|
139
139
|
"CMC > Objetos Públicos > 0. 0 Meses"
|
|
140
|
-
</
|
|
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 [
|
|
@@ -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
|
+
`;
|
package/src/components/index.js
CHANGED
|
@@ -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")
|
|
@@ -88,7 +89,7 @@ export const DatasetForm = ({
|
|
|
88
89
|
};
|
|
89
90
|
|
|
90
91
|
const buildDefaultFilters = (i) => {
|
|
91
|
-
const defaultFilters = { "
|
|
92
|
+
const defaultFilters = { "class.raw": [""] };
|
|
92
93
|
return i == 0
|
|
93
94
|
? { defaultFilters }
|
|
94
95
|
: { defaultFilters: { ...defaultFilters, ...customFilters } };
|
|
@@ -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" } });
|
|
@@ -20,8 +20,8 @@ describe("<DatasetForm />", () => {
|
|
|
20
20
|
id: 1,
|
|
21
21
|
name: "strcuture1",
|
|
22
22
|
path: [],
|
|
23
|
-
system: { name: "system" }
|
|
24
|
-
}
|
|
23
|
+
system: { name: "system" }
|
|
24
|
+
}
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
join_type: "inner",
|
|
@@ -29,10 +29,10 @@ describe("<DatasetForm />", () => {
|
|
|
29
29
|
id: 2,
|
|
30
30
|
name: "structure2",
|
|
31
31
|
path: [],
|
|
32
|
-
system: { name: "system" }
|
|
32
|
+
system: { name: "system" }
|
|
33
33
|
},
|
|
34
|
-
clauses: [{ id: 100 }, { id: 200 }]
|
|
35
|
-
}
|
|
34
|
+
clauses: [{ id: 100 }, { id: 200 }]
|
|
35
|
+
}
|
|
36
36
|
];
|
|
37
37
|
|
|
38
38
|
const customFilters = { "foo.bar": ["baz"] };
|
|
@@ -44,7 +44,7 @@ describe("<DatasetForm />", () => {
|
|
|
44
44
|
setSelector,
|
|
45
45
|
selector,
|
|
46
46
|
setImplementationFilterValues,
|
|
47
|
-
setImplementationKey
|
|
47
|
+
setImplementationKey
|
|
48
48
|
};
|
|
49
49
|
|
|
50
50
|
it("matches the latest snapshot", () => {
|
|
@@ -63,14 +63,14 @@ describe("<DatasetForm />", () => {
|
|
|
63
63
|
const selectors = wrapper.find("lazy");
|
|
64
64
|
expect(selectors.first().prop("options")).toEqual({
|
|
65
65
|
defaultFilters: {
|
|
66
|
-
"
|
|
67
|
-
}
|
|
66
|
+
"class.raw": [""]
|
|
67
|
+
}
|
|
68
68
|
});
|
|
69
69
|
expect(selectors.last().prop("options")).toEqual({
|
|
70
70
|
defaultFilters: {
|
|
71
|
-
"
|
|
72
|
-
"foo.bar": ["baz"]
|
|
73
|
-
}
|
|
71
|
+
"class.raw": [""],
|
|
72
|
+
"foo.bar": ["baz"]
|
|
73
|
+
}
|
|
74
74
|
});
|
|
75
75
|
});
|
|
76
76
|
});
|
package/src/components/ruleImplementationForm/__tests__/__snapshots__/DataSetForm.spec.js.snap
CHANGED
|
@@ -13,8 +13,8 @@ exports[`<DatasetForm /> matches the latest snapshot 1`] = `
|
|
|
13
13
|
options={
|
|
14
14
|
Object {
|
|
15
15
|
"defaultFilters": Object {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
16
|
+
"class.raw": Array [
|
|
17
|
+
"",
|
|
18
18
|
],
|
|
19
19
|
},
|
|
20
20
|
}
|
|
@@ -77,12 +77,12 @@ exports[`<DatasetForm /> matches the latest snapshot 1`] = `
|
|
|
77
77
|
options={
|
|
78
78
|
Object {
|
|
79
79
|
"defaultFilters": Object {
|
|
80
|
+
"class.raw": Array [
|
|
81
|
+
"",
|
|
82
|
+
],
|
|
80
83
|
"foo.bar": Array [
|
|
81
84
|
"baz",
|
|
82
85
|
],
|
|
83
|
-
"has_field_child.raw": Array [
|
|
84
|
-
"true",
|
|
85
|
-
],
|
|
86
86
|
},
|
|
87
87
|
}
|
|
88
88
|
}
|
|
@@ -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
|
package/src/messages/en.js
CHANGED
|
@@ -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",
|
package/src/messages/es.js
CHANGED
|
@@ -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 };
|
package/src/selectors/index.js
CHANGED
|
@@ -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";
|