@truedat/dq 4.42.4 → 4.43.0
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 +6 -0
- package/package.json +5 -5
- package/src/api.js +6 -0
- package/src/components/ImplementationStructureDelete.js +41 -0
- package/src/components/ImplementationStructureLink.js +24 -0
- package/src/components/ImplementationStructures.js +138 -0
- package/src/components/ImplementationStructuresNew.js +125 -0
- package/src/components/RuleImplementationTabs.js +16 -1
- package/src/components/RuleImplementationsTable.js +10 -3
- package/src/components/RuleRoutes.js +37 -1
- package/src/components/__tests__/ImplementationStructureDelete.spec.js +27 -0
- package/src/components/__tests__/ImplementationStructureLink.spec.js +23 -0
- package/src/components/__tests__/ImplementationStructures.spec.js +88 -0
- package/src/components/__tests__/ImplementationStructuresNew.spec.js +34 -0
- package/src/components/__tests__/RuleImplementation.spec.js +2 -1
- package/src/components/__tests__/RuleImplementationTabs.spec.js +2 -1
- package/src/components/__tests__/__snapshots__/ImplementationStructureDelete.spec.js.snap +10 -0
- package/src/components/__tests__/__snapshots__/ImplementationStructureLink.spec.js.snap +11 -0
- package/src/components/__tests__/__snapshots__/ImplementationStructures.spec.js.snap +208 -0
- package/src/components/__tests__/__snapshots__/ImplementationStructuresNew.spec.js.snap +106 -0
- package/src/components/__tests__/__snapshots__/RuleImplementation.spec.js.snap +7 -1
- package/src/components/__tests__/__snapshots__/RuleImplementationTabs.spec.js.snap +8 -2
- package/src/messages/en.js +13 -1
- package/src/messages/es.js +14 -1
- package/src/reducers/ruleImplementation.js +1 -0
- package/src/reducers/ruleImplementationRedirect.js +4 -0
- package/src/routines.js +7 -0
- package/src/sagas/__tests__/createImplementationStructure.spec.js +86 -0
- package/src/sagas/__tests__/deleteImplementationStructure.spec.js +84 -0
- package/src/sagas/createImplementationStructure.js +32 -0
- package/src/sagas/deleteImplementationStructure.js +37 -0
- package/src/sagas/index.js +16 -10
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/dq",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.43.0",
|
|
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.
|
|
34
|
+
"@truedat/test": "4.43.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.
|
|
86
|
-
"@truedat/df": "4.
|
|
85
|
+
"@truedat/core": "4.43.0",
|
|
86
|
+
"@truedat/df": "4.43.0",
|
|
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": "ad0f63f2d98ae377883743b839858d9d671d2431"
|
|
107
107
|
}
|
package/src/api.js
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
const API_CONCEPT_RULES = "/api/rules/concept/:id";
|
|
2
2
|
const API_EXECUTION_GROUP = "/api/execution_groups/:id";
|
|
3
3
|
const API_EXECUTION_GROUPS = "/api/execution_groups";
|
|
4
|
+
const API_IMPLEMENTATIONS_STRUCTURES =
|
|
5
|
+
"/api/rule_implementations/:implementationId/data_structures";
|
|
6
|
+
const API_IMPLEMENTATIONS_STRUCTURE =
|
|
7
|
+
"/api/rule_implementations/data_structures/:id";
|
|
4
8
|
const API_RULE = "/api/rules/:id";
|
|
5
9
|
const API_REMEDIATION_PLAN = "/api/rule_results/:rule_result_id/remediation";
|
|
6
10
|
const API_RULES = "/api/rules";
|
|
@@ -26,6 +30,8 @@ export {
|
|
|
26
30
|
API_CONCEPT_RULES,
|
|
27
31
|
API_EXECUTION_GROUP,
|
|
28
32
|
API_EXECUTION_GROUPS,
|
|
33
|
+
API_IMPLEMENTATIONS_STRUCTURES,
|
|
34
|
+
API_IMPLEMENTATIONS_STRUCTURE,
|
|
29
35
|
API_REMEDIATION_PLAN,
|
|
30
36
|
API_RULE,
|
|
31
37
|
API_RULES,
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import PropTypes from "prop-types";
|
|
3
|
+
import { connect } from "react-redux";
|
|
4
|
+
import { Icon } from "semantic-ui-react";
|
|
5
|
+
import { FormattedMessage } from "react-intl";
|
|
6
|
+
import { ConfirmModal } from "@truedat/core/components";
|
|
7
|
+
import { deleteImplementationStructure } from "../routines";
|
|
8
|
+
|
|
9
|
+
export const ImplementationStructureDelete = ({
|
|
10
|
+
implementationId,
|
|
11
|
+
id,
|
|
12
|
+
deleteImplementationStructure,
|
|
13
|
+
}) => (
|
|
14
|
+
<ConfirmModal
|
|
15
|
+
icon="trash"
|
|
16
|
+
trigger={<Icon name="trash alternate outline" color="red" />}
|
|
17
|
+
header={
|
|
18
|
+
<FormattedMessage
|
|
19
|
+
id={"implementationsStructures.delete.confirmation.header"}
|
|
20
|
+
/>
|
|
21
|
+
}
|
|
22
|
+
content={
|
|
23
|
+
<FormattedMessage
|
|
24
|
+
id={"implementationsStructures.delete.confirmation.content"}
|
|
25
|
+
/>
|
|
26
|
+
}
|
|
27
|
+
onConfirm={() => deleteImplementationStructure({ implementationId, id })}
|
|
28
|
+
onOpen={(e) => e.stopPropagation()}
|
|
29
|
+
onClose={(e) => e.stopPropagation()}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
ImplementationStructureDelete.propTypes = {
|
|
34
|
+
implementationId: PropTypes.number,
|
|
35
|
+
id: PropTypes.number,
|
|
36
|
+
deleteImplementationStructure: PropTypes.func,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default connect(null, { deleteImplementationStructure })(
|
|
40
|
+
ImplementationStructureDelete
|
|
41
|
+
);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Link } from "react-router-dom";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { linkTo } from "@truedat/core/routes";
|
|
5
|
+
|
|
6
|
+
export const ImplementationStructureLink = ({
|
|
7
|
+
id,
|
|
8
|
+
current_version: { name },
|
|
9
|
+
}) => (
|
|
10
|
+
<Link
|
|
11
|
+
to={linkTo.STRUCTURE({
|
|
12
|
+
id,
|
|
13
|
+
})}
|
|
14
|
+
>
|
|
15
|
+
{name}
|
|
16
|
+
</Link>
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
ImplementationStructureLink.propTypes = {
|
|
20
|
+
id: PropTypes.number,
|
|
21
|
+
current_version: PropTypes.object,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default ImplementationStructureLink;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { connect } from "react-redux";
|
|
5
|
+
import { Table, Button, Grid, Segment, Header, Icon } from "semantic-ui-react";
|
|
6
|
+
import { FormattedMessage } from "react-intl";
|
|
7
|
+
import { Link } from "react-router-dom";
|
|
8
|
+
import { linkTo } from "@truedat/core/routes";
|
|
9
|
+
import { columnDecorator } from "@truedat/core/services";
|
|
10
|
+
import ImplementationStructureDelete from "./ImplementationStructureDelete";
|
|
11
|
+
import ImplementationStructureLink from "./ImplementationStructureLink";
|
|
12
|
+
|
|
13
|
+
const ImplementationStructureDeleteDecorator = ({ id, implementation_id }) => (
|
|
14
|
+
<ImplementationStructureDelete id={id} implementationId={implementation_id} />
|
|
15
|
+
);
|
|
16
|
+
ImplementationStructureDeleteDecorator.propTypes = {
|
|
17
|
+
id: PropTypes.number,
|
|
18
|
+
implementation_id: PropTypes.number,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const PathDecorator = (path) => (
|
|
22
|
+
<span title={_.join(" › ")(path)}>
|
|
23
|
+
{_.flow(_.join(" › "), _.truncate({ length: 90 }))(path)}
|
|
24
|
+
</span>
|
|
25
|
+
);
|
|
26
|
+
PathDecorator.propTypes = {
|
|
27
|
+
path: PropTypes.string,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const ImplementationStructureTypeDecorator = (type) => (
|
|
31
|
+
<FormattedMessage id={`implementationsStructures.type.${type}`} />
|
|
32
|
+
);
|
|
33
|
+
ImplementationStructureTypeDecorator.propTypes = {
|
|
34
|
+
type: PropTypes.string,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export const ImplementationStructures = ({ implementation, canCreateLink }) => {
|
|
38
|
+
const deleteColumn = canCreateLink
|
|
39
|
+
? [
|
|
40
|
+
{
|
|
41
|
+
fieldSelector: _.identity,
|
|
42
|
+
fieldDecorator: ImplementationStructureDeleteDecorator,
|
|
43
|
+
},
|
|
44
|
+
]
|
|
45
|
+
: [];
|
|
46
|
+
|
|
47
|
+
const columns = [
|
|
48
|
+
{
|
|
49
|
+
header: "structure.name",
|
|
50
|
+
fieldSelector: _.path("data_structure"),
|
|
51
|
+
fieldDecorator: ImplementationStructureLink,
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
header: "structure.system",
|
|
55
|
+
fieldSelector: _.path("data_structure.system.name"),
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
header: "structure.path",
|
|
59
|
+
fieldSelector: _.path("data_structure.current_version.path"),
|
|
60
|
+
fieldDecorator: PathDecorator,
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
header: "implementationsStructures.type",
|
|
64
|
+
fieldSelector: _.path("type"),
|
|
65
|
+
fieldDecorator: ImplementationStructureTypeDecorator,
|
|
66
|
+
},
|
|
67
|
+
...deleteColumn,
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
const headerRow = columns.map(({ header }, key) => (
|
|
71
|
+
<Table.HeaderCell
|
|
72
|
+
key={key}
|
|
73
|
+
content={header ? <FormattedMessage id={header} /> : null}
|
|
74
|
+
/>
|
|
75
|
+
));
|
|
76
|
+
|
|
77
|
+
const id = _.prop("rule_id")(implementation);
|
|
78
|
+
const implementation_id = _.prop("id")(implementation);
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<Segment attached="bottom">
|
|
82
|
+
<Grid>
|
|
83
|
+
{id && canCreateLink && (
|
|
84
|
+
<Grid.Column width={16}>
|
|
85
|
+
<Button
|
|
86
|
+
floated="right"
|
|
87
|
+
primary
|
|
88
|
+
as={Link}
|
|
89
|
+
to={linkTo.IMPLEMENTATION_STRUCTURES_NEW({
|
|
90
|
+
id,
|
|
91
|
+
implementation_id,
|
|
92
|
+
})}
|
|
93
|
+
content={<FormattedMessage id="links.actions.create" />}
|
|
94
|
+
/>
|
|
95
|
+
</Grid.Column>
|
|
96
|
+
)}
|
|
97
|
+
{!_.isEmpty(implementation?.data_structures) ? (
|
|
98
|
+
<Grid.Column width={16}>
|
|
99
|
+
<Table
|
|
100
|
+
headerRow={headerRow}
|
|
101
|
+
renderBodyRow={(link, i) => (
|
|
102
|
+
<Table.Row key={i}>
|
|
103
|
+
{columns.map((column, ci) => (
|
|
104
|
+
<Table.Cell
|
|
105
|
+
key={ci}
|
|
106
|
+
textAlign={_.prop("textAlign")(column)}
|
|
107
|
+
content={columnDecorator(column)(link)}
|
|
108
|
+
/>
|
|
109
|
+
))}
|
|
110
|
+
</Table.Row>
|
|
111
|
+
)}
|
|
112
|
+
tableData={implementation?.data_structures}
|
|
113
|
+
/>
|
|
114
|
+
</Grid.Column>
|
|
115
|
+
) : (
|
|
116
|
+
<Header as="h4">
|
|
117
|
+
<Icon name="search" />
|
|
118
|
+
<Header.Content>
|
|
119
|
+
<FormattedMessage id="implementationStructures.empty" />
|
|
120
|
+
</Header.Content>
|
|
121
|
+
</Header>
|
|
122
|
+
)}
|
|
123
|
+
</Grid>
|
|
124
|
+
</Segment>
|
|
125
|
+
);
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
ImplementationStructures.propTypes = {
|
|
129
|
+
implementation: PropTypes.object,
|
|
130
|
+
canCreateLink: PropTypes.bool,
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
const mapStateToProps = (state) => ({
|
|
134
|
+
implementation: state.ruleImplementation,
|
|
135
|
+
canCreateLink: _.propOr(false, "link_structure")(state.implementationActions),
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
export default connect(mapStateToProps)(ImplementationStructures);
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { connect } from "react-redux";
|
|
5
|
+
import { useIntl } from "react-intl";
|
|
6
|
+
import { Button, Dropdown, Grid, Header, Segment } from "semantic-ui-react";
|
|
7
|
+
import { HistoryBackButton } from "@truedat/core/components";
|
|
8
|
+
import { linkTo } from "@truedat/core/routes";
|
|
9
|
+
import { createImplementationStructure } from "../routines";
|
|
10
|
+
|
|
11
|
+
const StructureSelector = React.lazy(() =>
|
|
12
|
+
import("@truedat/dd/components/StructureSelector")
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
export const ImplementationStructuresNew = ({
|
|
16
|
+
creatingImplementationStructure,
|
|
17
|
+
implementation,
|
|
18
|
+
createImplementationStructure,
|
|
19
|
+
}) => {
|
|
20
|
+
const { formatMessage } = useIntl();
|
|
21
|
+
const [selectedTarget, setSelectedTarget] = useState(null);
|
|
22
|
+
const [type, setType] = useState("dataset");
|
|
23
|
+
const submitDisabled = creatingImplementationStructure || !selectedTarget;
|
|
24
|
+
|
|
25
|
+
const handleTargetSelected = (selectedTarget) =>
|
|
26
|
+
setSelectedTarget(selectedTarget);
|
|
27
|
+
|
|
28
|
+
const handleSubmit = () => {
|
|
29
|
+
const redirectUrl = linkTo.IMPLEMENTATION_STRUCTURES({
|
|
30
|
+
id: implementation.rule_id,
|
|
31
|
+
implementation_id: implementation.id,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
createImplementationStructure({
|
|
35
|
+
implementationId: implementation.id,
|
|
36
|
+
dataStructureId: selectedTarget?.id,
|
|
37
|
+
type,
|
|
38
|
+
redirectUrl,
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const handleTypeChange = (e, { value }) => {
|
|
43
|
+
if (type !== value && (value === "dataset" || type === "dataset")) {
|
|
44
|
+
// Reset selectTarget only if changing type from or to "dataset"
|
|
45
|
+
// because structure class changes
|
|
46
|
+
setSelectedTarget(null);
|
|
47
|
+
}
|
|
48
|
+
setType(value);
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const typeOptions = ["dataset", "population", "validation"].map((type) => ({
|
|
52
|
+
key: type,
|
|
53
|
+
value: type,
|
|
54
|
+
text: formatMessage({ id: `implementationsStructures.type.${type}` }),
|
|
55
|
+
}));
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<Segment attached="bottom">
|
|
59
|
+
<Grid>
|
|
60
|
+
<Grid.Column with={16}>
|
|
61
|
+
<Header
|
|
62
|
+
as="h4"
|
|
63
|
+
content={formatMessage({
|
|
64
|
+
id: "implementationsStructures.new.header",
|
|
65
|
+
})}
|
|
66
|
+
/>
|
|
67
|
+
<Dropdown
|
|
68
|
+
placeholder={formatMessage({
|
|
69
|
+
id: "implementationsStructures.type",
|
|
70
|
+
})}
|
|
71
|
+
selection
|
|
72
|
+
value={type}
|
|
73
|
+
onChange={handleTypeChange}
|
|
74
|
+
options={typeOptions}
|
|
75
|
+
/>
|
|
76
|
+
{
|
|
77
|
+
// Duplicated component and 'keys' to force Selector rerender on changing type to clean selection
|
|
78
|
+
type === "dataset" ? (
|
|
79
|
+
<StructureSelector
|
|
80
|
+
key="datasetSelector"
|
|
81
|
+
onSelect={handleTargetSelected}
|
|
82
|
+
defaultFilters={{ "class.raw": ["table"] }}
|
|
83
|
+
/>
|
|
84
|
+
) : (
|
|
85
|
+
<StructureSelector
|
|
86
|
+
key="nonDatasetSelector"
|
|
87
|
+
onSelect={handleTargetSelected}
|
|
88
|
+
defaultFilters={{ "class.raw": ["field"] }}
|
|
89
|
+
/>
|
|
90
|
+
)
|
|
91
|
+
}
|
|
92
|
+
<div className="actions">
|
|
93
|
+
<HistoryBackButton
|
|
94
|
+
content={formatMessage({ id: "actions.cancel" })}
|
|
95
|
+
disabled={creatingImplementationStructure}
|
|
96
|
+
/>
|
|
97
|
+
|
|
98
|
+
<Button
|
|
99
|
+
primary
|
|
100
|
+
content={formatMessage({ id: "actions.create" })}
|
|
101
|
+
disabled={submitDisabled}
|
|
102
|
+
loading={creatingImplementationStructure}
|
|
103
|
+
onClick={handleSubmit}
|
|
104
|
+
/>
|
|
105
|
+
</div>
|
|
106
|
+
</Grid.Column>
|
|
107
|
+
</Grid>
|
|
108
|
+
</Segment>
|
|
109
|
+
);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
ImplementationStructuresNew.propTypes = {
|
|
113
|
+
implementation: PropTypes.object,
|
|
114
|
+
creatingImplementationStructure: PropTypes.bool,
|
|
115
|
+
createImplementationStructure: PropTypes.func,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
const mapStateToProps = (state) => ({
|
|
119
|
+
creatingImplementationStructure: state.creatingImplementationStructure,
|
|
120
|
+
implementation: state.ruleImplementation,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
export default connect(mapStateToProps, { createImplementationStructure })(
|
|
124
|
+
ImplementationStructuresNew
|
|
125
|
+
);
|
|
@@ -10,6 +10,8 @@ import {
|
|
|
10
10
|
RULE_IMPLEMENTATION_EVENTS,
|
|
11
11
|
IMPLEMENTATION_CONCEPT_LINKS,
|
|
12
12
|
IMPLEMENTATION_CONCEPT_LINKS_NEW,
|
|
13
|
+
IMPLEMENTATION_STRUCTURES,
|
|
14
|
+
IMPLEMENTATION_STRUCTURES_NEW,
|
|
13
15
|
RULE_IMPLEMENTATION_MOVE,
|
|
14
16
|
RULE_IMPLEMENTATION_RESULTS_DETAILS,
|
|
15
17
|
RULE_IMPLEMENTATION_RESULTS,
|
|
@@ -57,9 +59,22 @@ export const RuleImplementationTabs = ({
|
|
|
57
59
|
implementation_id: ruleImplementation.id,
|
|
58
60
|
})}
|
|
59
61
|
>
|
|
60
|
-
<FormattedMessage id="tabs.dq.implementation.links" />
|
|
62
|
+
<FormattedMessage id="tabs.dq.implementation.links.concepts" />
|
|
61
63
|
</Menu.Item>
|
|
62
64
|
)}
|
|
65
|
+
<Menu.Item
|
|
66
|
+
active={
|
|
67
|
+
match.path === IMPLEMENTATION_STRUCTURES ||
|
|
68
|
+
match.path === IMPLEMENTATION_STRUCTURES_NEW
|
|
69
|
+
}
|
|
70
|
+
as={Link}
|
|
71
|
+
to={linkTo.IMPLEMENTATION_STRUCTURES({
|
|
72
|
+
id: rule.id,
|
|
73
|
+
implementation_id: ruleImplementation.id,
|
|
74
|
+
})}
|
|
75
|
+
>
|
|
76
|
+
<FormattedMessage id="tabs.dq.implementation.structures" />
|
|
77
|
+
</Menu.Item>
|
|
63
78
|
<Menu.Item
|
|
64
79
|
active={match.path === RULE_IMPLEMENTATION_RESULTS}
|
|
65
80
|
as={Link}
|
|
@@ -15,6 +15,7 @@ export const RuleImplementationsTable = ({
|
|
|
15
15
|
additionalColumns = [],
|
|
16
16
|
checkedAll,
|
|
17
17
|
checkRow,
|
|
18
|
+
structure,
|
|
18
19
|
executeImplementationsOn,
|
|
19
20
|
implementationsSort,
|
|
20
21
|
sortImplementations,
|
|
@@ -127,6 +128,7 @@ RuleImplementationsTable.propTypes = {
|
|
|
127
128
|
isRowChecked: PropTypes.bool,
|
|
128
129
|
ruleImplementationsLoading: PropTypes.bool,
|
|
129
130
|
sortImplementations: PropTypes.func,
|
|
131
|
+
structure: PropTypes.object,
|
|
130
132
|
ruleImplementations: PropTypes.array,
|
|
131
133
|
columns: PropTypes.array,
|
|
132
134
|
withoutColumns: PropTypes.array,
|
|
@@ -134,11 +136,16 @@ RuleImplementationsTable.propTypes = {
|
|
|
134
136
|
|
|
135
137
|
const mapStateToProps = (state, props) => ({
|
|
136
138
|
columns: getRuleImplementationColumns(state),
|
|
137
|
-
ruleImplementations:
|
|
139
|
+
ruleImplementations:
|
|
140
|
+
props.ruleImplementations ||
|
|
141
|
+
(state?.structure?.implementations &&
|
|
142
|
+
_.map(({ implementation, type }) => ({
|
|
143
|
+
...implementation,
|
|
144
|
+
implementation_structure_structure_type: type,
|
|
145
|
+
}))(state.structure.implementations)) ||
|
|
138
146
|
state.ruleImplementations,
|
|
139
|
-
"ruleImplementations"
|
|
140
|
-
)(props),
|
|
141
147
|
ruleImplementationsLoading: state.ruleImplementationsLoading,
|
|
148
|
+
structure: state.structure,
|
|
142
149
|
implementationsSort: _.path("ruleImplementationQuery.sort")(state),
|
|
143
150
|
});
|
|
144
151
|
|
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
RULE_IMPLEMENTATION_EVENTS,
|
|
16
16
|
IMPLEMENTATION_CONCEPT_LINKS,
|
|
17
17
|
IMPLEMENTATION_CONCEPT_LINKS_NEW,
|
|
18
|
+
IMPLEMENTATION_STRUCTURES,
|
|
19
|
+
IMPLEMENTATION_STRUCTURES_NEW,
|
|
18
20
|
RULE_IMPLEMENTATION_MOVE,
|
|
19
21
|
RULE_IMPLEMENTATION_NEW,
|
|
20
22
|
RULE_IMPLEMENTATION_RESULT_DETAILS,
|
|
@@ -30,18 +32,20 @@ import {
|
|
|
30
32
|
} from "../selectors";
|
|
31
33
|
import EditRule from "./EditRule";
|
|
32
34
|
import ExecutionDetails from "./ExecutionDetails";
|
|
35
|
+
import ImplementationStructures from "./ImplementationStructures";
|
|
36
|
+
import ImplementationStructuresNew from "./ImplementationStructuresNew";
|
|
33
37
|
import MoveImplementation from "./MoveImplementation";
|
|
34
38
|
import NewRule from "./NewRule";
|
|
35
39
|
import NewRuleImplementation from "./NewRuleImplementation";
|
|
36
40
|
import Rule from "./Rule";
|
|
37
41
|
import RuleCrumbs from "./RuleCrumbs";
|
|
38
42
|
import RuleEvents from "./RuleEvents";
|
|
43
|
+
import RuleFormImplementations from "./RuleFormImplementations";
|
|
39
44
|
import RuleImplementation from "./RuleImplementation";
|
|
40
45
|
import RuleImplementationEvents from "./RuleImplementationEvents";
|
|
41
46
|
import RuleImplementationLoader from "./RuleImplementationLoader";
|
|
42
47
|
import RuleImplementationProperties from "./RuleImplementationProperties";
|
|
43
48
|
import RuleImplementationResults from "./RuleImplementationResults";
|
|
44
|
-
import RuleFormImplementations from "./RuleFormImplementations";
|
|
45
49
|
import RuleImplementationsFromRuleLoader from "./RuleImplementationsFromRuleLoader";
|
|
46
50
|
import RuleLoader from "./RuleLoader";
|
|
47
51
|
import RuleProperties from "./RuleProperties";
|
|
@@ -353,6 +357,38 @@ const ImplementationRoutes = ({
|
|
|
353
357
|
</>
|
|
354
358
|
)}
|
|
355
359
|
/>
|
|
360
|
+
<Route
|
|
361
|
+
exact
|
|
362
|
+
path={IMPLEMENTATION_STRUCTURES}
|
|
363
|
+
render={() => (
|
|
364
|
+
<>
|
|
365
|
+
<RuleCrumbs />
|
|
366
|
+
<Segment>
|
|
367
|
+
{ruleLoaded && ruleImplementationLoaded && (
|
|
368
|
+
<RuleImplementation>
|
|
369
|
+
<ImplementationStructures />
|
|
370
|
+
</RuleImplementation>
|
|
371
|
+
)}
|
|
372
|
+
</Segment>
|
|
373
|
+
</>
|
|
374
|
+
)}
|
|
375
|
+
/>
|
|
376
|
+
<Route
|
|
377
|
+
exact
|
|
378
|
+
path={IMPLEMENTATION_STRUCTURES_NEW}
|
|
379
|
+
render={() => (
|
|
380
|
+
<>
|
|
381
|
+
<RuleCrumbs />
|
|
382
|
+
<Segment>
|
|
383
|
+
{ruleLoaded && ruleImplementationLoaded && (
|
|
384
|
+
<RuleImplementation>
|
|
385
|
+
<ImplementationStructuresNew />
|
|
386
|
+
</RuleImplementation>
|
|
387
|
+
)}
|
|
388
|
+
</Segment>
|
|
389
|
+
</>
|
|
390
|
+
)}
|
|
391
|
+
/>
|
|
356
392
|
<Route
|
|
357
393
|
exact
|
|
358
394
|
path={RULE_IMPLEMENTATION_RESULTS}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@truedat/test/render";
|
|
3
|
+
import { ImplementationStructureDelete } from "../ImplementationStructureDelete";
|
|
4
|
+
|
|
5
|
+
describe("<ImplementationStructureDelete />", () => {
|
|
6
|
+
const renderOpts = {
|
|
7
|
+
messages: {
|
|
8
|
+
en: {
|
|
9
|
+
"implementationsStructures.delete.confirmation.header": "header",
|
|
10
|
+
"implementationsStructures.delete.confirmation.content": "content",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
it("matches the latest snapshot", () => {
|
|
16
|
+
const props = {
|
|
17
|
+
implementationId: 1,
|
|
18
|
+
dataStructureId: 2,
|
|
19
|
+
deleteImplementationStructure: () => {},
|
|
20
|
+
};
|
|
21
|
+
const { container } = render(
|
|
22
|
+
<ImplementationStructureDelete {...props} />,
|
|
23
|
+
renderOpts
|
|
24
|
+
);
|
|
25
|
+
expect(container).toMatchSnapshot();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@truedat/test/render";
|
|
3
|
+
import { ImplementationStructureLink } from "../ImplementationStructureLink";
|
|
4
|
+
|
|
5
|
+
describe("<ImplementationStructureLink />", () => {
|
|
6
|
+
const renderOpts = {
|
|
7
|
+
messages: {
|
|
8
|
+
en: {},
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
it("matches the latest snapshot", () => {
|
|
13
|
+
const props = {
|
|
14
|
+
id: 1,
|
|
15
|
+
current_version: { name: "foo" },
|
|
16
|
+
};
|
|
17
|
+
const { container } = render(
|
|
18
|
+
<ImplementationStructureLink {...props} />,
|
|
19
|
+
renderOpts
|
|
20
|
+
);
|
|
21
|
+
expect(container).toMatchSnapshot();
|
|
22
|
+
});
|
|
23
|
+
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@truedat/test/render";
|
|
3
|
+
import { ImplementationStructures } from "../ImplementationStructures";
|
|
4
|
+
|
|
5
|
+
describe("<ImplementationStructures />", () => {
|
|
6
|
+
const renderOpts = {
|
|
7
|
+
messages: {
|
|
8
|
+
en: {
|
|
9
|
+
"structure.name": "name",
|
|
10
|
+
"structure.system": "system",
|
|
11
|
+
"structure.path": "path",
|
|
12
|
+
"implementationsStructures.type": "type",
|
|
13
|
+
"links.actions.create": "create",
|
|
14
|
+
"implementationStructures.empty": "empty",
|
|
15
|
+
"implementationsStructures.type.dataset": "dataset",
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
it("matches the latest snapshot", () => {
|
|
21
|
+
const props = {
|
|
22
|
+
implementation: {
|
|
23
|
+
data_structures: [
|
|
24
|
+
{
|
|
25
|
+
data_structure: {
|
|
26
|
+
id: 1,
|
|
27
|
+
name: "foo",
|
|
28
|
+
system: { name: "bar" },
|
|
29
|
+
current_version: {
|
|
30
|
+
name: "qux",
|
|
31
|
+
path: ["baz"],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
type: "dataset",
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
canCreateLink: true,
|
|
39
|
+
};
|
|
40
|
+
const { container } = render(
|
|
41
|
+
<ImplementationStructures {...props} />,
|
|
42
|
+
renderOpts
|
|
43
|
+
);
|
|
44
|
+
expect(container).toMatchSnapshot();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("matches the latest snapshot without create permission", () => {
|
|
48
|
+
const props = {
|
|
49
|
+
implementation: {
|
|
50
|
+
data_structures: [
|
|
51
|
+
{
|
|
52
|
+
data_structure: {
|
|
53
|
+
id: 1,
|
|
54
|
+
name: "foo",
|
|
55
|
+
system: { name: "bar" },
|
|
56
|
+
path: ["baz"],
|
|
57
|
+
current_version: {
|
|
58
|
+
name: "qux",
|
|
59
|
+
path: ["baz"],
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
type: "dataset",
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
canCreateLink: false,
|
|
67
|
+
};
|
|
68
|
+
const { container } = render(
|
|
69
|
+
<ImplementationStructures {...props} />,
|
|
70
|
+
renderOpts
|
|
71
|
+
);
|
|
72
|
+
expect(container).toMatchSnapshot();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("matches the latest snapshot without data_structures", () => {
|
|
76
|
+
const props = {
|
|
77
|
+
implementation: {
|
|
78
|
+
data_structures: [],
|
|
79
|
+
},
|
|
80
|
+
canCreateLink: true,
|
|
81
|
+
};
|
|
82
|
+
const { container } = render(
|
|
83
|
+
<ImplementationStructures {...props} />,
|
|
84
|
+
renderOpts
|
|
85
|
+
);
|
|
86
|
+
expect(container).toMatchSnapshot();
|
|
87
|
+
});
|
|
88
|
+
});
|