@truedat/dq 6.8.9 → 6.9.1
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/package.json +2 -2
- package/src/components/ImplementationStructureLinksActions.js +36 -0
- package/src/components/ImplementationStructures.js +17 -151
- package/src/components/__tests__/ImplementationStructures.spec.js +94 -65
- package/src/components/__tests__/__snapshots__/ImplementationStructures.spec.js.snap +101 -185
- package/src/selectors/__tests__/getImplementationStructureLinksColumns.spec.js +56 -0
- package/src/selectors/getImplementationStructureLinksColumns.js +184 -0
- package/src/selectors/index.js +4 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/dq",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.9.1",
|
|
4
4
|
"description": "Truedat Web Data Quality Module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"jsnext:main": "src/index.js",
|
|
@@ -118,5 +118,5 @@
|
|
|
118
118
|
"react-dom": ">= 16.8.6 < 17",
|
|
119
119
|
"semantic-ui-react": ">= 2.0.3 < 2.2"
|
|
120
120
|
},
|
|
121
|
-
"gitHead": "
|
|
121
|
+
"gitHead": "e17809019e0759416fb21959bd45ebe4c10c32b4"
|
|
122
122
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { connect } from "react-redux";
|
|
5
|
+
import { Button } from "semantic-ui-react";
|
|
6
|
+
import { Link } from "react-router-dom";
|
|
7
|
+
import { FormattedMessage } from "react-intl";
|
|
8
|
+
import { linkTo } from "@truedat/core/routes";
|
|
9
|
+
|
|
10
|
+
export const ImplementationStructureLinksActions = ({
|
|
11
|
+
implementation_id,
|
|
12
|
+
canCreateLink,
|
|
13
|
+
}) =>
|
|
14
|
+
implementation_id && canCreateLink ? (
|
|
15
|
+
<Button
|
|
16
|
+
floated="right"
|
|
17
|
+
primary
|
|
18
|
+
as={Link}
|
|
19
|
+
to={linkTo.IMPLEMENTATION_STRUCTURES_NEW({
|
|
20
|
+
implementation_id,
|
|
21
|
+
})}
|
|
22
|
+
content={<FormattedMessage id="links.actions.create" />}
|
|
23
|
+
/>
|
|
24
|
+
) : null;
|
|
25
|
+
|
|
26
|
+
ImplementationStructureLinksActions.propTypes = {
|
|
27
|
+
implementation_id: PropTypes.number,
|
|
28
|
+
canCreateLink: PropTypes.bool,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const mapStateToProps = (state) => ({
|
|
32
|
+
implementation_id: _.prop("id")(state.ruleImplementation),
|
|
33
|
+
canCreateLink: _.propOr(false, "link_structure")(state.implementationActions),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
export default connect(mapStateToProps)(ImplementationStructureLinksActions);
|
|
@@ -1,163 +1,29 @@
|
|
|
1
|
-
import _ from "lodash/fp";
|
|
2
1
|
import React from "react";
|
|
3
2
|
import PropTypes from "prop-types";
|
|
4
3
|
import { connect } from "react-redux";
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
import ImplementationStructureDelete from "./ImplementationStructureDelete";
|
|
19
|
-
import ImplementationStructureLink from "./ImplementationStructureLink";
|
|
20
|
-
|
|
21
|
-
const ImplementationStructureDeleteDecorator = ({ id, implementation_id }) => (
|
|
22
|
-
<ImplementationStructureDelete id={id} implementationId={implementation_id} />
|
|
23
|
-
);
|
|
24
|
-
ImplementationStructureDeleteDecorator.propTypes = {
|
|
25
|
-
id: PropTypes.number,
|
|
26
|
-
implementation_id: PropTypes.number,
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const DomainDecorator = (domains) => (
|
|
30
|
-
<List>
|
|
31
|
-
{domains.map(({ name, parents }, i) => (
|
|
32
|
-
<List.Item key={i}>
|
|
33
|
-
{_.flow(_.map("name"), _.union([name]), _.join(" > "))(parents)}
|
|
34
|
-
</List.Item>
|
|
35
|
-
))}
|
|
36
|
-
</List>
|
|
37
|
-
);
|
|
38
|
-
|
|
39
|
-
DomainDecorator.propTypes = {
|
|
40
|
-
domains: PropTypes.array,
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
const PathDecorator = (path) => (
|
|
44
|
-
<span title={_.join(" › ")(path)}>
|
|
45
|
-
{_.flow(_.join(" › "), _.truncate({ length: 90 }))(path)}
|
|
46
|
-
</span>
|
|
47
|
-
);
|
|
48
|
-
PathDecorator.propTypes = {
|
|
49
|
-
path: PropTypes.string,
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const ImplementationStructureTypeDecorator = (type) => (
|
|
53
|
-
<FormattedMessage id={`implementationsStructures.type.${type}`} />
|
|
54
|
-
);
|
|
55
|
-
ImplementationStructureTypeDecorator.propTypes = {
|
|
56
|
-
type: PropTypes.string,
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
export const ImplementationStructures = ({ implementation, canCreateLink }) => {
|
|
60
|
-
const deleteColumn = canCreateLink
|
|
61
|
-
? [
|
|
62
|
-
{
|
|
63
|
-
fieldSelector: _.identity,
|
|
64
|
-
fieldDecorator: ImplementationStructureDeleteDecorator,
|
|
65
|
-
},
|
|
66
|
-
]
|
|
67
|
-
: [];
|
|
68
|
-
|
|
69
|
-
const columns = [
|
|
70
|
-
{
|
|
71
|
-
header: "structure.name",
|
|
72
|
-
fieldSelector: _.path("data_structure"),
|
|
73
|
-
fieldDecorator: ImplementationStructureLink,
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
header: "structure.domain",
|
|
77
|
-
fieldSelector: _.path("data_structure.domains"),
|
|
78
|
-
fieldDecorator: DomainDecorator,
|
|
79
|
-
},
|
|
80
|
-
{
|
|
81
|
-
header: "structure.system",
|
|
82
|
-
fieldSelector: _.path("data_structure.system.name"),
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
header: "structure.path",
|
|
86
|
-
fieldSelector: _.path("data_structure.current_version.path"),
|
|
87
|
-
fieldDecorator: PathDecorator,
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
header: "implementationsStructures.type",
|
|
91
|
-
fieldSelector: _.path("type"),
|
|
92
|
-
fieldDecorator: ImplementationStructureTypeDecorator,
|
|
93
|
-
},
|
|
94
|
-
...deleteColumn,
|
|
95
|
-
];
|
|
96
|
-
|
|
97
|
-
const headerRow = columns.map(({ header }, key) => (
|
|
98
|
-
<Table.HeaderCell
|
|
99
|
-
key={key}
|
|
100
|
-
content={header ? <FormattedMessage id={header} /> : null}
|
|
4
|
+
import { Segment } from "semantic-ui-react";
|
|
5
|
+
import { getImplementationStructureLinksColumns } from "../selectors";
|
|
6
|
+
import ImplementationStructureLinksActions from "./ImplementationStructureLinksActions";
|
|
7
|
+
|
|
8
|
+
const LinksPane = React.lazy(() => import("@truedat/lm/components/LinksPane"));
|
|
9
|
+
|
|
10
|
+
export const ImplementationStructures = ({ groups }) => (
|
|
11
|
+
<Segment attached="bottom">
|
|
12
|
+
<LinksPane
|
|
13
|
+
groups={groups}
|
|
14
|
+
sourceType="implementations"
|
|
15
|
+
targetType="structure"
|
|
16
|
+
linksActions={<ImplementationStructureLinksActions />}
|
|
101
17
|
/>
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const implementation_id = _.prop("id")(implementation);
|
|
105
|
-
|
|
106
|
-
return (
|
|
107
|
-
<Segment attached="bottom">
|
|
108
|
-
<Grid>
|
|
109
|
-
{implementation_id && canCreateLink && (
|
|
110
|
-
<Grid.Column width={16}>
|
|
111
|
-
<Button
|
|
112
|
-
floated="right"
|
|
113
|
-
primary
|
|
114
|
-
as={Link}
|
|
115
|
-
to={linkTo.IMPLEMENTATION_STRUCTURES_NEW({
|
|
116
|
-
implementation_id,
|
|
117
|
-
})}
|
|
118
|
-
content={<FormattedMessage id="links.actions.create" />}
|
|
119
|
-
/>
|
|
120
|
-
</Grid.Column>
|
|
121
|
-
)}
|
|
122
|
-
{!_.isEmpty(implementation?.data_structures) ? (
|
|
123
|
-
<Grid.Column width={16}>
|
|
124
|
-
<Table
|
|
125
|
-
headerRow={headerRow}
|
|
126
|
-
renderBodyRow={(link, i) => (
|
|
127
|
-
<Table.Row key={i}>
|
|
128
|
-
{columns.map((column, ci) => (
|
|
129
|
-
<Table.Cell
|
|
130
|
-
key={ci}
|
|
131
|
-
textAlign={_.prop("textAlign")(column)}
|
|
132
|
-
content={columnDecorator(column)(link)}
|
|
133
|
-
/>
|
|
134
|
-
))}
|
|
135
|
-
</Table.Row>
|
|
136
|
-
)}
|
|
137
|
-
tableData={implementation?.data_structures}
|
|
138
|
-
/>
|
|
139
|
-
</Grid.Column>
|
|
140
|
-
) : (
|
|
141
|
-
<Header as="h4">
|
|
142
|
-
<Icon name="search" />
|
|
143
|
-
<Header.Content>
|
|
144
|
-
<FormattedMessage id="implementationStructures.empty" />
|
|
145
|
-
</Header.Content>
|
|
146
|
-
</Header>
|
|
147
|
-
)}
|
|
148
|
-
</Grid>
|
|
149
|
-
</Segment>
|
|
150
|
-
);
|
|
151
|
-
};
|
|
18
|
+
</Segment>
|
|
19
|
+
);
|
|
152
20
|
|
|
153
21
|
ImplementationStructures.propTypes = {
|
|
154
|
-
|
|
155
|
-
canCreateLink: PropTypes.bool,
|
|
22
|
+
groups: PropTypes.array,
|
|
156
23
|
};
|
|
157
24
|
|
|
158
25
|
const mapStateToProps = (state) => ({
|
|
159
|
-
|
|
160
|
-
canCreateLink: _.propOr(false, "link_structure")(state.implementationActions),
|
|
26
|
+
groups: getImplementationStructureLinksColumns(state),
|
|
161
27
|
});
|
|
162
28
|
|
|
163
29
|
export default connect(mapStateToProps)(ImplementationStructures);
|
|
@@ -1,91 +1,120 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { Suspense } from "react";
|
|
2
|
+
import { waitFor } from "@testing-library/react";
|
|
2
3
|
import { render } from "@truedat/test/render";
|
|
3
4
|
import { ImplementationStructures } from "../ImplementationStructures";
|
|
5
|
+
import { defaultImplementationStructureLinksColumns } from "../../selectors";
|
|
6
|
+
|
|
7
|
+
const columns = defaultImplementationStructureLinksColumns;
|
|
8
|
+
|
|
9
|
+
const groups = [
|
|
10
|
+
[
|
|
11
|
+
columns,
|
|
12
|
+
[
|
|
13
|
+
"undefined",
|
|
14
|
+
[
|
|
15
|
+
{
|
|
16
|
+
data_structure: {
|
|
17
|
+
current_version: {
|
|
18
|
+
deleted_at: null,
|
|
19
|
+
name: "AGENCIA RECIBO",
|
|
20
|
+
},
|
|
21
|
+
id: 10397859,
|
|
22
|
+
},
|
|
23
|
+
data_structure_id: 10397859,
|
|
24
|
+
id: 21844,
|
|
25
|
+
implementation_id: 11932,
|
|
26
|
+
type: "population",
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
],
|
|
30
|
+
],
|
|
31
|
+
[
|
|
32
|
+
columns,
|
|
33
|
+
[
|
|
34
|
+
"deleted",
|
|
35
|
+
[
|
|
36
|
+
{
|
|
37
|
+
data_structure: {
|
|
38
|
+
current_version: {
|
|
39
|
+
deleted_at: "2023-07-12T08:11:23.000000Z",
|
|
40
|
+
name: "/BEV1/RBKP",
|
|
41
|
+
},
|
|
42
|
+
id: 12579384,
|
|
43
|
+
},
|
|
44
|
+
data_structure_id: 12579384,
|
|
45
|
+
id: 21800,
|
|
46
|
+
implementation_id: 11932,
|
|
47
|
+
type: "dataset",
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
],
|
|
51
|
+
],
|
|
52
|
+
];
|
|
4
53
|
|
|
5
54
|
describe("<ImplementationStructures />", () => {
|
|
6
55
|
const renderOpts = {
|
|
56
|
+
fallback: "lazy",
|
|
7
57
|
messages: {
|
|
8
58
|
en: {
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"structure.path": "path",
|
|
13
|
-
"implementationsStructures.type": "type",
|
|
14
|
-
"links.actions.create": "create",
|
|
15
|
-
"implementationStructures.empty": "empty",
|
|
59
|
+
"implementationsRelation.master.table.title": "Links to Structures",
|
|
60
|
+
"implementationsDeletedRelation.table.title": "Deleted Structures",
|
|
61
|
+
"links.actions.create": "Create",
|
|
16
62
|
"implementationsStructures.type.dataset": "dataset",
|
|
63
|
+
"implementationsStructures.type.population": "population",
|
|
17
64
|
},
|
|
18
65
|
},
|
|
19
66
|
};
|
|
20
67
|
|
|
21
|
-
it("matches the latest snapshot", () => {
|
|
22
|
-
const props = {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
id: 1,
|
|
28
|
-
name: "foo",
|
|
29
|
-
system: { name: "bar" },
|
|
30
|
-
domains: [{ name: "foo_domain", parents: [{ name: "bar" }] }],
|
|
31
|
-
current_version: {
|
|
32
|
-
name: "qux",
|
|
33
|
-
path: ["baz"],
|
|
34
|
-
},
|
|
35
|
-
},
|
|
36
|
-
type: "dataset",
|
|
37
|
-
},
|
|
38
|
-
],
|
|
39
|
-
},
|
|
40
|
-
canCreateLink: true,
|
|
41
|
-
};
|
|
42
|
-
const { container } = render(
|
|
43
|
-
<ImplementationStructures {...props} />,
|
|
68
|
+
it("matches the latest snapshot", async () => {
|
|
69
|
+
const props = { groups };
|
|
70
|
+
const { container, queryByText } = render(
|
|
71
|
+
<Suspense fallback={null}>
|
|
72
|
+
<ImplementationStructures {...props} />
|
|
73
|
+
</Suspense>,
|
|
44
74
|
renderOpts
|
|
45
75
|
);
|
|
76
|
+
|
|
77
|
+
await waitFor(() =>
|
|
78
|
+
expect(queryByText(/AGENCIA RECIBO/i)).toBeInTheDocument()
|
|
79
|
+
);
|
|
80
|
+
|
|
46
81
|
expect(container).toMatchSnapshot();
|
|
47
82
|
});
|
|
48
83
|
|
|
49
|
-
it("matches the latest snapshot without create permission", () => {
|
|
50
|
-
const props = {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
data_structure: {
|
|
55
|
-
id: 1,
|
|
56
|
-
name: "foo",
|
|
57
|
-
domains: [{ name: "foo_domain", parents: [{ name: "bar" }] }],
|
|
58
|
-
system: { name: "bar" },
|
|
59
|
-
path: ["baz"],
|
|
60
|
-
current_version: {
|
|
61
|
-
name: "qux",
|
|
62
|
-
path: ["baz"],
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
type: "dataset",
|
|
66
|
-
},
|
|
67
|
-
],
|
|
68
|
-
},
|
|
69
|
-
canCreateLink: false,
|
|
84
|
+
it("matches the latest snapshot without create permission", async () => {
|
|
85
|
+
const props = { groups };
|
|
86
|
+
const state = {
|
|
87
|
+
ruleImplementation: { id: 1 },
|
|
88
|
+
implementationActions: { link_structure: {} },
|
|
70
89
|
};
|
|
71
|
-
const {
|
|
72
|
-
<
|
|
73
|
-
|
|
90
|
+
const { getByRole } = render(
|
|
91
|
+
<Suspense fallback={null}>
|
|
92
|
+
<ImplementationStructures {...props} />
|
|
93
|
+
</Suspense>,
|
|
94
|
+
{ ...renderOpts, state }
|
|
95
|
+
);
|
|
96
|
+
await waitFor(() =>
|
|
97
|
+
expect(getByRole("button", { name: /create/i })).toBeEnabled()
|
|
74
98
|
);
|
|
75
|
-
expect(container).toMatchSnapshot();
|
|
76
99
|
});
|
|
77
100
|
|
|
78
|
-
it("matches the latest snapshot without data_structures", () => {
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
},
|
|
83
|
-
canCreateLink: true,
|
|
101
|
+
it("matches the latest snapshot without data_structures", async () => {
|
|
102
|
+
const state = {
|
|
103
|
+
ruleImplementation: { id: 1 },
|
|
104
|
+
implementationActions: { link_structure: {} },
|
|
84
105
|
};
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
106
|
+
const props = [];
|
|
107
|
+
const { container, getByRole } = render(
|
|
108
|
+
<Suspense fallback={null}>
|
|
109
|
+
<ImplementationStructures {...props} />
|
|
110
|
+
</Suspense>,
|
|
111
|
+
{ ...renderOpts, state }
|
|
88
112
|
);
|
|
113
|
+
|
|
114
|
+
await waitFor(() =>
|
|
115
|
+
expect(getByRole("button", { name: /create/i })).toBeEnabled()
|
|
116
|
+
);
|
|
117
|
+
|
|
89
118
|
expect(container).toMatchSnapshot();
|
|
90
119
|
});
|
|
91
120
|
});
|
|
@@ -4,217 +4,131 @@ exports[`<ImplementationStructures /> matches the latest snapshot 1`] = `
|
|
|
4
4
|
<div>
|
|
5
5
|
<div
|
|
6
6
|
class="ui bottom attached segment"
|
|
7
|
+
style=""
|
|
7
8
|
>
|
|
8
9
|
<div
|
|
9
10
|
class="ui grid"
|
|
10
11
|
>
|
|
11
12
|
<div
|
|
12
|
-
class="
|
|
13
|
+
class="row"
|
|
13
14
|
>
|
|
14
|
-
<
|
|
15
|
-
class="
|
|
15
|
+
<div
|
|
16
|
+
class="column"
|
|
17
|
+
/>
|
|
18
|
+
</div>
|
|
19
|
+
<div
|
|
20
|
+
class="row"
|
|
21
|
+
>
|
|
22
|
+
<div
|
|
23
|
+
class="column"
|
|
16
24
|
>
|
|
17
|
-
<
|
|
18
|
-
class=""
|
|
25
|
+
<h3
|
|
26
|
+
class="ui header"
|
|
19
27
|
>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class=""
|
|
25
|
-
>
|
|
26
|
-
name
|
|
27
|
-
</th>
|
|
28
|
-
<th
|
|
29
|
-
class=""
|
|
30
|
-
>
|
|
31
|
-
domain
|
|
32
|
-
</th>
|
|
33
|
-
<th
|
|
34
|
-
class=""
|
|
35
|
-
>
|
|
36
|
-
system
|
|
37
|
-
</th>
|
|
38
|
-
<th
|
|
39
|
-
class=""
|
|
40
|
-
>
|
|
41
|
-
path
|
|
42
|
-
</th>
|
|
43
|
-
<th
|
|
44
|
-
class=""
|
|
45
|
-
>
|
|
46
|
-
type
|
|
47
|
-
</th>
|
|
48
|
-
<th
|
|
49
|
-
class=""
|
|
50
|
-
/>
|
|
51
|
-
</tr>
|
|
52
|
-
</thead>
|
|
53
|
-
<tbody
|
|
54
|
-
class=""
|
|
28
|
+
Links to Structures
|
|
29
|
+
</h3>
|
|
30
|
+
<table
|
|
31
|
+
class="ui table"
|
|
55
32
|
>
|
|
56
|
-
<
|
|
33
|
+
<thead
|
|
57
34
|
class=""
|
|
58
35
|
>
|
|
59
|
-
<
|
|
36
|
+
<tr
|
|
60
37
|
class=""
|
|
61
38
|
>
|
|
62
|
-
<
|
|
63
|
-
|
|
39
|
+
<th
|
|
40
|
+
class=""
|
|
41
|
+
>
|
|
42
|
+
name
|
|
43
|
+
</th>
|
|
44
|
+
<th
|
|
45
|
+
class=""
|
|
64
46
|
>
|
|
65
|
-
|
|
66
|
-
</
|
|
67
|
-
</
|
|
68
|
-
|
|
47
|
+
type
|
|
48
|
+
</th>
|
|
49
|
+
</tr>
|
|
50
|
+
</thead>
|
|
51
|
+
<tbody
|
|
52
|
+
class=""
|
|
53
|
+
>
|
|
54
|
+
<tr
|
|
69
55
|
class=""
|
|
70
56
|
>
|
|
71
|
-
<
|
|
72
|
-
class="
|
|
73
|
-
role="list"
|
|
57
|
+
<td
|
|
58
|
+
class=""
|
|
74
59
|
>
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
role="listitem"
|
|
60
|
+
<a
|
|
61
|
+
href="/structures/10397859"
|
|
78
62
|
>
|
|
79
|
-
|
|
80
|
-
</
|
|
81
|
-
</
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
class=""
|
|
85
|
-
>
|
|
86
|
-
bar
|
|
87
|
-
</td>
|
|
88
|
-
<td
|
|
89
|
-
class=""
|
|
90
|
-
>
|
|
91
|
-
<span
|
|
92
|
-
title="baz"
|
|
63
|
+
AGENCIA RECIBO
|
|
64
|
+
</a>
|
|
65
|
+
</td>
|
|
66
|
+
<td
|
|
67
|
+
class=""
|
|
93
68
|
>
|
|
94
|
-
|
|
95
|
-
</
|
|
96
|
-
</
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
dataset
|
|
101
|
-
</td>
|
|
102
|
-
<td
|
|
103
|
-
class=""
|
|
104
|
-
>
|
|
105
|
-
<i
|
|
106
|
-
aria-hidden="true"
|
|
107
|
-
class="red trash alternate outline icon"
|
|
108
|
-
/>
|
|
109
|
-
</td>
|
|
110
|
-
</tr>
|
|
111
|
-
</tbody>
|
|
112
|
-
</table>
|
|
69
|
+
population
|
|
70
|
+
</td>
|
|
71
|
+
</tr>
|
|
72
|
+
</tbody>
|
|
73
|
+
</table>
|
|
74
|
+
</div>
|
|
113
75
|
</div>
|
|
114
|
-
</div>
|
|
115
|
-
</div>
|
|
116
|
-
</div>
|
|
117
|
-
`;
|
|
118
|
-
|
|
119
|
-
exports[`<ImplementationStructures /> matches the latest snapshot without create permission 1`] = `
|
|
120
|
-
<div>
|
|
121
|
-
<div
|
|
122
|
-
class="ui bottom attached segment"
|
|
123
|
-
>
|
|
124
|
-
<div
|
|
125
|
-
class="ui grid"
|
|
126
|
-
>
|
|
127
76
|
<div
|
|
128
|
-
class="
|
|
77
|
+
class="row"
|
|
129
78
|
>
|
|
130
|
-
<
|
|
131
|
-
class="
|
|
79
|
+
<div
|
|
80
|
+
class="column"
|
|
132
81
|
>
|
|
133
|
-
<
|
|
134
|
-
class=""
|
|
82
|
+
<h3
|
|
83
|
+
class="ui header"
|
|
135
84
|
>
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
class=""
|
|
141
|
-
>
|
|
142
|
-
name
|
|
143
|
-
</th>
|
|
144
|
-
<th
|
|
145
|
-
class=""
|
|
146
|
-
>
|
|
147
|
-
domain
|
|
148
|
-
</th>
|
|
149
|
-
<th
|
|
150
|
-
class=""
|
|
151
|
-
>
|
|
152
|
-
system
|
|
153
|
-
</th>
|
|
154
|
-
<th
|
|
155
|
-
class=""
|
|
156
|
-
>
|
|
157
|
-
path
|
|
158
|
-
</th>
|
|
159
|
-
<th
|
|
160
|
-
class=""
|
|
161
|
-
>
|
|
162
|
-
type
|
|
163
|
-
</th>
|
|
164
|
-
</tr>
|
|
165
|
-
</thead>
|
|
166
|
-
<tbody
|
|
167
|
-
class=""
|
|
85
|
+
Deleted Structures
|
|
86
|
+
</h3>
|
|
87
|
+
<table
|
|
88
|
+
class="ui table"
|
|
168
89
|
>
|
|
169
|
-
<
|
|
90
|
+
<thead
|
|
170
91
|
class=""
|
|
171
92
|
>
|
|
172
|
-
<
|
|
93
|
+
<tr
|
|
173
94
|
class=""
|
|
174
95
|
>
|
|
175
|
-
<
|
|
176
|
-
|
|
96
|
+
<th
|
|
97
|
+
class=""
|
|
177
98
|
>
|
|
178
|
-
|
|
179
|
-
</
|
|
180
|
-
|
|
181
|
-
|
|
99
|
+
name
|
|
100
|
+
</th>
|
|
101
|
+
<th
|
|
102
|
+
class=""
|
|
103
|
+
>
|
|
104
|
+
type
|
|
105
|
+
</th>
|
|
106
|
+
</tr>
|
|
107
|
+
</thead>
|
|
108
|
+
<tbody
|
|
109
|
+
class=""
|
|
110
|
+
>
|
|
111
|
+
<tr
|
|
182
112
|
class=""
|
|
183
113
|
>
|
|
184
|
-
<
|
|
185
|
-
class="
|
|
186
|
-
role="list"
|
|
114
|
+
<td
|
|
115
|
+
class=""
|
|
187
116
|
>
|
|
188
|
-
<
|
|
189
|
-
|
|
190
|
-
role="listitem"
|
|
117
|
+
<a
|
|
118
|
+
href="/structures/12579384"
|
|
191
119
|
>
|
|
192
|
-
|
|
193
|
-
</
|
|
194
|
-
</
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
class=""
|
|
198
|
-
>
|
|
199
|
-
bar
|
|
200
|
-
</td>
|
|
201
|
-
<td
|
|
202
|
-
class=""
|
|
203
|
-
>
|
|
204
|
-
<span
|
|
205
|
-
title="baz"
|
|
120
|
+
/BEV1/RBKP
|
|
121
|
+
</a>
|
|
122
|
+
</td>
|
|
123
|
+
<td
|
|
124
|
+
class=""
|
|
206
125
|
>
|
|
207
|
-
|
|
208
|
-
</
|
|
209
|
-
</
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
dataset
|
|
214
|
-
</td>
|
|
215
|
-
</tr>
|
|
216
|
-
</tbody>
|
|
217
|
-
</table>
|
|
126
|
+
dataset
|
|
127
|
+
</td>
|
|
128
|
+
</tr>
|
|
129
|
+
</tbody>
|
|
130
|
+
</table>
|
|
131
|
+
</div>
|
|
218
132
|
</div>
|
|
219
133
|
</div>
|
|
220
134
|
</div>
|
|
@@ -229,19 +143,21 @@ exports[`<ImplementationStructures /> matches the latest snapshot without data_s
|
|
|
229
143
|
<div
|
|
230
144
|
class="ui grid"
|
|
231
145
|
>
|
|
232
|
-
<
|
|
233
|
-
class="
|
|
146
|
+
<div
|
|
147
|
+
class="row"
|
|
234
148
|
>
|
|
235
|
-
<i
|
|
236
|
-
aria-hidden="true"
|
|
237
|
-
class="search icon"
|
|
238
|
-
/>
|
|
239
149
|
<div
|
|
240
|
-
class="
|
|
150
|
+
class="column"
|
|
241
151
|
>
|
|
242
|
-
|
|
152
|
+
<a
|
|
153
|
+
class="ui primary right floated button"
|
|
154
|
+
href="/implementations/1/structures/new"
|
|
155
|
+
role="button"
|
|
156
|
+
>
|
|
157
|
+
Create
|
|
158
|
+
</a>
|
|
243
159
|
</div>
|
|
244
|
-
</
|
|
160
|
+
</div>
|
|
245
161
|
</div>
|
|
246
162
|
</div>
|
|
247
163
|
</div>
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import { getImplementationStructureLinksColumns } from "..";
|
|
3
|
+
// import { defaultImplementationStructureLinksColumns } from "../../selectors";
|
|
4
|
+
|
|
5
|
+
const foo = {
|
|
6
|
+
data_structure: {
|
|
7
|
+
current_version: {
|
|
8
|
+
deleted_at: "2023-07-12T08:11:23.000000Z",
|
|
9
|
+
name: "/BEV1/RBKP",
|
|
10
|
+
},
|
|
11
|
+
id: 12579384,
|
|
12
|
+
},
|
|
13
|
+
data_structure_id: 12579384,
|
|
14
|
+
id: 21800,
|
|
15
|
+
implementation_id: 11932,
|
|
16
|
+
type: "dataset",
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const bar = {
|
|
20
|
+
data_structure: {
|
|
21
|
+
current_version: {
|
|
22
|
+
deleted_at: null,
|
|
23
|
+
name: "AGENCIA RECIBO",
|
|
24
|
+
},
|
|
25
|
+
id: 10397859,
|
|
26
|
+
},
|
|
27
|
+
data_structure_id: 10397859,
|
|
28
|
+
id: 21844,
|
|
29
|
+
implementation_id: 11932,
|
|
30
|
+
type: "population",
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const data_structures = [foo, bar];
|
|
34
|
+
|
|
35
|
+
// const columns = defaultImplementationStructureLinksColumns
|
|
36
|
+
|
|
37
|
+
describe("selectors: getImplementationStructureLinksColumns", () => {
|
|
38
|
+
const state = {
|
|
39
|
+
ruleImplementation: {
|
|
40
|
+
id: 1,
|
|
41
|
+
data_structures,
|
|
42
|
+
},
|
|
43
|
+
implementationActions: { link_structure: {} },
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
it("should return all links", () => {
|
|
47
|
+
const links = _.flow(
|
|
48
|
+
getImplementationStructureLinksColumns,
|
|
49
|
+
_.map(_.last)
|
|
50
|
+
)(state);
|
|
51
|
+
expect(links).toEqual([
|
|
52
|
+
["undefined", [bar]],
|
|
53
|
+
["deleted", [foo]],
|
|
54
|
+
]);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { Icon, Label, List } from "semantic-ui-react";
|
|
5
|
+
import { createSelector } from "reselect";
|
|
6
|
+
import { FormattedMessage } from "react-intl";
|
|
7
|
+
import Moment from "react-moment";
|
|
8
|
+
import { accentInsensitivePathOrder } from "@truedat/core/services/sort";
|
|
9
|
+
import ImplementationStructureDelete from "../components/ImplementationStructureDelete";
|
|
10
|
+
import ImplementationStructureLink from "../components/ImplementationStructureLink";
|
|
11
|
+
|
|
12
|
+
const ImplementationStructureDeleteDecorator = ({ id, implementation_id }) => (
|
|
13
|
+
<ImplementationStructureDelete id={id} implementationId={implementation_id} />
|
|
14
|
+
);
|
|
15
|
+
ImplementationStructureDeleteDecorator.propTypes = {
|
|
16
|
+
id: PropTypes.number,
|
|
17
|
+
implementation_id: PropTypes.number,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const deletedDateDecorator = (date) => (
|
|
21
|
+
<Label className="alert warning">
|
|
22
|
+
<Icon name="warning circle" color="red" />
|
|
23
|
+
<Moment locale="es" date={date} format="YYYY-MM-DD HH:mm" />
|
|
24
|
+
</Label>
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const dateDecorator = (date) => (
|
|
28
|
+
<Moment locale="es" date={date} format="YYYY-MM-DD HH:mm" />
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const DomainDecorator = (domains) => (
|
|
32
|
+
<List>
|
|
33
|
+
{domains.map(({ name, parents }, i) => (
|
|
34
|
+
<List.Item key={i}>
|
|
35
|
+
{_.flow(_.map("name"), _.union([name]), _.join(" > "))(parents)}
|
|
36
|
+
</List.Item>
|
|
37
|
+
))}
|
|
38
|
+
</List>
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
DomainDecorator.propTypes = {
|
|
42
|
+
domains: PropTypes.array,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const PathDecorator = (path) => (
|
|
46
|
+
<span title={_.join(" › ")(path)}>
|
|
47
|
+
{_.flow(_.join(" › "), _.truncate({ length: 90 }))(path)}
|
|
48
|
+
</span>
|
|
49
|
+
);
|
|
50
|
+
PathDecorator.propTypes = {
|
|
51
|
+
path: PropTypes.string,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const ImplementationStructureTypeDecorator = (type) => (
|
|
55
|
+
<FormattedMessage id={`implementationsStructures.type.${type}`} />
|
|
56
|
+
);
|
|
57
|
+
ImplementationStructureTypeDecorator.propTypes = {
|
|
58
|
+
type: PropTypes.string,
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export const defaultImplementationStructureLinksColumns = [
|
|
62
|
+
{
|
|
63
|
+
name: "name",
|
|
64
|
+
fieldSelector: _.path("data_structure"),
|
|
65
|
+
fieldDecorator: ImplementationStructureLink,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "domain",
|
|
69
|
+
fieldSelector: _.path("data_structure.domains"),
|
|
70
|
+
fieldDecorator: DomainDecorator,
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
name: "system",
|
|
74
|
+
fieldSelector: _.path("data_structure.system.name"),
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "path",
|
|
78
|
+
fieldSelector: _.path("data_structure.current_version.path"),
|
|
79
|
+
fieldDecorator: PathDecorator,
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
name: "updated_at",
|
|
83
|
+
fieldSelector: _.path("data_structure.updated_at"),
|
|
84
|
+
fieldDecorator: dateDecorator,
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: "type",
|
|
88
|
+
fieldSelector: _.path("type"),
|
|
89
|
+
fieldDecorator: ImplementationStructureTypeDecorator,
|
|
90
|
+
},
|
|
91
|
+
];
|
|
92
|
+
|
|
93
|
+
const getStructureLinks = ({ ruleImplementation }) =>
|
|
94
|
+
ruleImplementation?.data_structures;
|
|
95
|
+
|
|
96
|
+
const getAction = (state) =>
|
|
97
|
+
!!_.prop("link_structure")(state.implementationActions);
|
|
98
|
+
|
|
99
|
+
const getColumns = (state) =>
|
|
100
|
+
_.defaultTo(defaultImplementationStructureLinksColumns)(
|
|
101
|
+
state.implementationStructureLinksColumns
|
|
102
|
+
);
|
|
103
|
+
const orderedLinks = (links) =>
|
|
104
|
+
_.sortBy(accentInsensitivePathOrder("current_version.name"))(links);
|
|
105
|
+
|
|
106
|
+
const withActions = (columns, canCreateLink) => {
|
|
107
|
+
const deleteColumn = canCreateLink
|
|
108
|
+
? [
|
|
109
|
+
{
|
|
110
|
+
name: "_actions",
|
|
111
|
+
fieldSelector: _.identity,
|
|
112
|
+
fieldDecorator: ImplementationStructureDeleteDecorator,
|
|
113
|
+
},
|
|
114
|
+
]
|
|
115
|
+
: [];
|
|
116
|
+
const result = [...columns, ...deleteColumn];
|
|
117
|
+
|
|
118
|
+
return result;
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const withDeletedAttribute = (columns, tag) =>
|
|
122
|
+
tag == "deleted"
|
|
123
|
+
? _.map((c) =>
|
|
124
|
+
_.propEq("name", "updated_at")(c)
|
|
125
|
+
? {
|
|
126
|
+
name: "deleted_at",
|
|
127
|
+
fieldSelector: _.path(
|
|
128
|
+
"data_structure.current_version.deleted_at"
|
|
129
|
+
),
|
|
130
|
+
fieldDecorator: deletedDateDecorator,
|
|
131
|
+
}
|
|
132
|
+
: c
|
|
133
|
+
)(columns)
|
|
134
|
+
: columns;
|
|
135
|
+
|
|
136
|
+
const mapColumns = (tag, columns, canCreateLink) =>
|
|
137
|
+
_.flow(
|
|
138
|
+
(cols) => withActions(cols, canCreateLink),
|
|
139
|
+
(cols) => withDeletedAttribute(cols, tag)
|
|
140
|
+
)(columns);
|
|
141
|
+
|
|
142
|
+
const withHeaders = (pair, columns, canCreateLink) => [
|
|
143
|
+
mapColumns(_.first(pair), columns, canCreateLink),
|
|
144
|
+
pair,
|
|
145
|
+
];
|
|
146
|
+
|
|
147
|
+
const implementationStructureDeletedLinks = (links, columns, canCreateLink) => {
|
|
148
|
+
const deleted = _.flow(
|
|
149
|
+
orderedLinks,
|
|
150
|
+
_.filter(
|
|
151
|
+
({ data_structure }) =>
|
|
152
|
+
!_.isEmpty(_.get("current_version.deleted_at", data_structure))
|
|
153
|
+
)
|
|
154
|
+
)(links);
|
|
155
|
+
return _.isEmpty(deleted)
|
|
156
|
+
? []
|
|
157
|
+
: [withHeaders(["deleted", deleted], columns, canCreateLink)];
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
const implementationStructureLinks = (links, columns, canCreateLink) =>
|
|
161
|
+
_.flow(
|
|
162
|
+
orderedLinks,
|
|
163
|
+
_.filter(({ data_structure }) =>
|
|
164
|
+
_.isEmpty(_.get("current_version.deleted_at", data_structure))
|
|
165
|
+
),
|
|
166
|
+
_.groupBy("\uffee"),
|
|
167
|
+
_.toPairs,
|
|
168
|
+
_.sortBy(([k]) => k),
|
|
169
|
+
_.map((pair) => withHeaders(pair, columns, canCreateLink))
|
|
170
|
+
)(links);
|
|
171
|
+
|
|
172
|
+
export const getImplementationStructureLinksColumns = createSelector(
|
|
173
|
+
[getStructureLinks, getColumns, getAction],
|
|
174
|
+
(structureLinks, columns, canCreateLink) => {
|
|
175
|
+
return [
|
|
176
|
+
...implementationStructureLinks(structureLinks, columns, canCreateLink),
|
|
177
|
+
...implementationStructureDeletedLinks(
|
|
178
|
+
structureLinks,
|
|
179
|
+
columns,
|
|
180
|
+
canCreateLink
|
|
181
|
+
),
|
|
182
|
+
];
|
|
183
|
+
}
|
|
184
|
+
);
|
package/src/selectors/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
export { datasetDefaultFiltersSelector } from "./datasetDefaultFiltersSelector";
|
|
2
2
|
export { getImplementationsExecution } from "./getImplementationsExecution";
|
|
3
|
+
export {
|
|
4
|
+
getImplementationStructureLinksColumns,
|
|
5
|
+
defaultImplementationStructureLinksColumns,
|
|
6
|
+
} from "./getImplementationStructureLinksColumns";
|
|
3
7
|
export { getRuleAvailableFilters } from "./getRuleAvailableFilters";
|
|
4
8
|
export { getRuleFilterTypes } from "./getRuleFilterTypes";
|
|
5
9
|
export { getRuleSelectedFilters } from "./getRuleSelectedFilters";
|