@truedat/dd 4.33.3 → 4.33.8
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 +18 -0
- package/package.json +6 -6
- package/src/api.js +4 -0
- package/src/components/GraphLoader.js +21 -6
- package/src/components/LineageEvents.js +23 -0
- package/src/components/LineageEventsTable.js +94 -0
- package/src/components/LineageForm.js +2 -1
- package/src/components/LineageGraph.js +62 -11
- package/src/components/LineageRoutes.js +9 -7
- package/src/components/StructuresBulkUpdate.js +23 -9
- package/src/components/StructuresRoutes.js +7 -0
- package/src/components/__tests__/LineageEventsTable.spec.js +39 -0
- package/src/components/__tests__/StructuresBulkUpdate.spec.js +2 -0
- package/src/components/__tests__/__snapshots__/LineageEventsTable.spec.js.snap +90 -0
- package/src/components/__tests__/__snapshots__/LineageRoutes.spec.js.snap +4 -0
- package/src/messages/en.js +18 -0
- package/src/messages/es.js +19 -0
- package/src/reducers/__tests__/graphLoading.spec.js +2 -2
- package/src/reducers/__tests__/lineageEventsLoading.spec.js +26 -0
- package/src/reducers/graph.js +4 -1
- package/src/reducers/graphLoading.js +8 -4
- package/src/reducers/graphRedirect.js +1 -2
- package/src/reducers/index.js +4 -0
- package/src/reducers/lineageEvents.js +13 -0
- package/src/reducers/lineageEventsLoading.js +14 -0
- package/src/routines.js +3 -0
- package/src/sagas/__tests__/createGraph.spec.js +162 -13
- package/src/sagas/createGraph.js +100 -7
- package/src/sagas/fetchGraph.js +1 -0
- package/src/sagas/fetchLineageEvents.js +26 -0
- package/src/sagas/index.js +6 -0
- package/src/selectors/getLineageEventColumns.js +48 -0
- package/src/styles/lineageGraph.less +3 -0
- package/src/components/StructuresUpdateButton.js +0 -45
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [4.33.8] 2021-11-29
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- [TD-4353] Fix Bulk update
|
|
8
|
+
|
|
9
|
+
## [4.33.5] 2021-11-28
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- [TD-4262] Timeout messages
|
|
14
|
+
|
|
15
|
+
## [4.33.4] 2021-11-26
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- [TD-4262] Lineage graph polling
|
|
20
|
+
|
|
3
21
|
## [4.33.3] 2021-11-25
|
|
4
22
|
|
|
5
23
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/dd",
|
|
3
|
-
"version": "4.33.
|
|
3
|
+
"version": "4.33.8",
|
|
4
4
|
"description": "Truedat Web Data Dictionary",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"jsnext:main": "src/index.js",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"@testing-library/jest-dom": "^5.14.1",
|
|
35
35
|
"@testing-library/react": "^12.0.0",
|
|
36
36
|
"@testing-library/user-event": "^13.2.1",
|
|
37
|
-
"@truedat/test": "4.33.
|
|
37
|
+
"@truedat/test": "4.33.8",
|
|
38
38
|
"babel-jest": "^27.0.6",
|
|
39
39
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
|
40
40
|
"babel-plugin-lodash": "^3.3.4",
|
|
@@ -84,9 +84,9 @@
|
|
|
84
84
|
]
|
|
85
85
|
},
|
|
86
86
|
"dependencies": {
|
|
87
|
-
"@truedat/auth": "4.33.
|
|
88
|
-
"@truedat/core": "4.33.
|
|
89
|
-
"@truedat/df": "4.33.
|
|
87
|
+
"@truedat/auth": "4.33.8",
|
|
88
|
+
"@truedat/core": "4.33.8",
|
|
89
|
+
"@truedat/df": "4.33.8",
|
|
90
90
|
"lodash": "^4.17.21",
|
|
91
91
|
"path-to-regexp": "^1.7.0",
|
|
92
92
|
"prop-types": "^15.7.2",
|
|
@@ -107,5 +107,5 @@
|
|
|
107
107
|
"react-dom": ">= 16.8.6 < 17",
|
|
108
108
|
"semantic-ui-react": ">= 0.88.2 < 2.1"
|
|
109
109
|
},
|
|
110
|
-
"gitHead": "
|
|
110
|
+
"gitHead": "14e8164b15d17c5d25ebd0296b6a9899b32dff1d"
|
|
111
111
|
}
|
package/src/api.js
CHANGED
|
@@ -14,8 +14,10 @@ const API_GRANT_REQUESTS = "/api/grant_requests";
|
|
|
14
14
|
const API_GRANTS_CSV = "/api/grants/csv";
|
|
15
15
|
const API_GRANTS_SEARCH = "/api/grants/search";
|
|
16
16
|
const API_GRAPH = "/api/graphs/:id";
|
|
17
|
+
const API_GRAPH_HASH = "/api/graphs/hash/:hash";
|
|
17
18
|
const API_GRAPHS = "/api/graphs";
|
|
18
19
|
const API_GRAPH_CSV = "/api/graphs/csv";
|
|
20
|
+
const API_LINEAGE_EVENTS = "/api/lineage_events";
|
|
19
21
|
const API_MY_GRANT_FILTERS_SEARCH = "/api/grant_filters/search/mine";
|
|
20
22
|
const API_MY_GRANTS_SEARCH = "/api/grants/search/mine";
|
|
21
23
|
const API_NODE = "/api/nodes/:id";
|
|
@@ -58,9 +60,11 @@ export {
|
|
|
58
60
|
API_GRANT_REQUESTS,
|
|
59
61
|
API_GRANTS_SEARCH,
|
|
60
62
|
API_GRAPH,
|
|
63
|
+
API_GRAPH_HASH,
|
|
61
64
|
API_GRAPHS,
|
|
62
65
|
API_GRAPH_CSV,
|
|
63
66
|
API_GRANTS_CSV,
|
|
67
|
+
API_LINEAGE_EVENTS,
|
|
64
68
|
API_MY_GRANTS_SEARCH,
|
|
65
69
|
API_MY_GRANT_FILTERS_SEARCH,
|
|
66
70
|
API_NODE,
|
|
@@ -2,27 +2,41 @@ import _ from "lodash/fp";
|
|
|
2
2
|
import { useEffect } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import { connect } from "react-redux";
|
|
5
|
-
import { useRouteMatch } from "react-router-dom";
|
|
5
|
+
import { useRouteMatch, useHistory } from "react-router-dom";
|
|
6
6
|
import { GRAPH } from "@truedat/core/routes";
|
|
7
|
-
import { fetchGraph, clearGraph } from "../routines";
|
|
7
|
+
import { fetchGraph, clearGraph, cancelPoll } from "../routines";
|
|
8
8
|
|
|
9
|
-
export const GraphLoader = ({ clearGraph, fetchGraph, graph }) => {
|
|
9
|
+
export const GraphLoader = ({ clearGraph, fetchGraph, graph, cancelPoll }) => {
|
|
10
10
|
const match = useRouteMatch(GRAPH);
|
|
11
11
|
const id = _.path("params.id")(match);
|
|
12
|
+
|
|
13
|
+
const history = useHistory();
|
|
14
|
+
|
|
12
15
|
useEffect(() => {
|
|
13
16
|
return () => {
|
|
14
17
|
clearGraph();
|
|
15
18
|
};
|
|
16
19
|
}, [clearGraph]);
|
|
20
|
+
|
|
17
21
|
useEffect(() => {
|
|
18
22
|
if (id) {
|
|
19
23
|
if (_.isEmpty(graph)) {
|
|
20
24
|
fetchGraph({ id });
|
|
21
|
-
} else if (
|
|
25
|
+
} else if (id != graph.id) {
|
|
22
26
|
fetchGraph({ id });
|
|
23
27
|
}
|
|
24
28
|
}
|
|
25
|
-
}, [graph, fetchGraph
|
|
29
|
+
}, [/*graph, */ /*fetchGraph,*/ id]);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
return () => {
|
|
33
|
+
// && history.location.pathname === "any specific path")
|
|
34
|
+
if (history.action === "POP") {
|
|
35
|
+
cancelPoll();
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}, [history]);
|
|
39
|
+
|
|
26
40
|
return null;
|
|
27
41
|
};
|
|
28
42
|
|
|
@@ -30,10 +44,11 @@ GraphLoader.propTypes = {
|
|
|
30
44
|
clearGraph: PropTypes.func.isRequired,
|
|
31
45
|
fetchGraph: PropTypes.func.isRequired,
|
|
32
46
|
graph: PropTypes.object,
|
|
47
|
+
cancelPoll: PropTypes.func,
|
|
33
48
|
};
|
|
34
49
|
|
|
35
50
|
const mapStateToProps = ({ graph }) => ({ graph });
|
|
36
51
|
|
|
37
|
-
export default connect(mapStateToProps, { clearGraph, fetchGraph })(
|
|
52
|
+
export default connect(mapStateToProps, { clearGraph, fetchGraph, cancelPoll })(
|
|
38
53
|
GraphLoader
|
|
39
54
|
);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Header, Icon, Segment, Dimmer, Loader } from "semantic-ui-react";
|
|
3
|
+
import { FormattedMessage } from "react-intl";
|
|
4
|
+
import LineageEventsTable from "./LineageEventsTable";
|
|
5
|
+
|
|
6
|
+
export const LineageEvents = () => (
|
|
7
|
+
<Segment>
|
|
8
|
+
<Header as="h2">
|
|
9
|
+
<Icon circular name="cogs" />
|
|
10
|
+
<Header.Content>
|
|
11
|
+
<FormattedMessage id="lineage.events.header" />
|
|
12
|
+
<Header.Subheader>
|
|
13
|
+
<FormattedMessage id="lineage.events.subheader" />
|
|
14
|
+
</Header.Subheader>
|
|
15
|
+
</Header.Content>
|
|
16
|
+
</Header>
|
|
17
|
+
<Segment attached="bottom">
|
|
18
|
+
<LineageEventsTable />
|
|
19
|
+
</Segment>
|
|
20
|
+
</Segment>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
export default LineageEvents;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React, { useEffect } from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import { FormattedMessage } from "react-intl";
|
|
5
|
+
import { Header, Icon, Table } from "semantic-ui-react";
|
|
6
|
+
import { useHistory } from "react-router-dom";
|
|
7
|
+
import { connect } from "react-redux";
|
|
8
|
+
import { useIntl } from "react-intl";
|
|
9
|
+
import { columnDecorator } from "@truedat/core/services";
|
|
10
|
+
import { linkTo } from "@truedat/core/routes";
|
|
11
|
+
import { lineageEventColumns as columns } from "../selectors/getLineageEventColumns";
|
|
12
|
+
import { fetchLineageEvents } from "../routines";
|
|
13
|
+
|
|
14
|
+
export const LineageEventsTable = ({
|
|
15
|
+
fetchLineageEvents,
|
|
16
|
+
lineageEvents,
|
|
17
|
+
lineageEventsLoading,
|
|
18
|
+
}) => {
|
|
19
|
+
const { formatMessage } = useIntl();
|
|
20
|
+
const history = useHistory();
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
fetchLineageEvents();
|
|
24
|
+
}, [fetchLineageEvents]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<>
|
|
28
|
+
{!_.isEmpty(lineageEvents) && (
|
|
29
|
+
<Table sortable selectable>
|
|
30
|
+
<Table.Header>
|
|
31
|
+
<Table.Row>
|
|
32
|
+
{columns.map((column, i) => {
|
|
33
|
+
return (
|
|
34
|
+
<Table.HeaderCell
|
|
35
|
+
key={i}
|
|
36
|
+
width={column.width}
|
|
37
|
+
content={formatMessage({
|
|
38
|
+
id: `lineage.events.props.${column.name}`,
|
|
39
|
+
defaultMessage: column.name,
|
|
40
|
+
})}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
})}
|
|
44
|
+
</Table.Row>
|
|
45
|
+
</Table.Header>
|
|
46
|
+
<Table.Body>
|
|
47
|
+
{lineageEvents.map((event, i) => (
|
|
48
|
+
<Table.Row
|
|
49
|
+
key={i}
|
|
50
|
+
onClick={
|
|
51
|
+
event.graph_id
|
|
52
|
+
? () => history.push(linkTo.GRAPH({ id: event?.graph_id }))
|
|
53
|
+
: null
|
|
54
|
+
}
|
|
55
|
+
>
|
|
56
|
+
{columns &&
|
|
57
|
+
columns.map((column, key) => (
|
|
58
|
+
<Table.Cell
|
|
59
|
+
key={key}
|
|
60
|
+
textAlign={column.textAlign}
|
|
61
|
+
content={columnDecorator(column)(event)}
|
|
62
|
+
/>
|
|
63
|
+
))}
|
|
64
|
+
</Table.Row>
|
|
65
|
+
))}
|
|
66
|
+
</Table.Body>
|
|
67
|
+
</Table>
|
|
68
|
+
)}
|
|
69
|
+
{_.isEmpty(lineageEvents) && !lineageEventsLoading && (
|
|
70
|
+
<Header as="h4">
|
|
71
|
+
<Icon name="search" />
|
|
72
|
+
<Header.Content>
|
|
73
|
+
<FormattedMessage id="lineage.events.search.results.empty" />
|
|
74
|
+
</Header.Content>
|
|
75
|
+
</Header>
|
|
76
|
+
)}
|
|
77
|
+
</>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
LineageEventsTable.propTypes = {
|
|
82
|
+
lineageEvents: PropTypes.array,
|
|
83
|
+
fetchLineageEvents: PropTypes.func,
|
|
84
|
+
lineageEventsLoading: PropTypes.bool,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const mapStateToProps = (state) => ({
|
|
88
|
+
lineageEvents: state.lineageEvents,
|
|
89
|
+
lineageEventsLoading: state.lineageEventsLoading,
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export default connect(mapStateToProps, { fetchLineageEvents })(
|
|
93
|
+
LineageEventsTable
|
|
94
|
+
);
|
|
@@ -54,10 +54,11 @@ export const LineageForm = ({
|
|
|
54
54
|
const [open, setOpen] = useState(true);
|
|
55
55
|
const [selectLevels, setSelectLevels] = useState(levelsSelection);
|
|
56
56
|
const [levels, setLevels] = useState(lineageLevels);
|
|
57
|
-
const handleSubmit = (type) => () =>
|
|
57
|
+
const handleSubmit = (type) => () => {
|
|
58
58
|
_.isNil(levels)
|
|
59
59
|
? createGraph({ ids: selectedResources, type })
|
|
60
60
|
: createGraph({ ids: selectedResources, type, levels });
|
|
61
|
+
};
|
|
61
62
|
const disabled = _.isEmpty(selectedResources);
|
|
62
63
|
useEffect(() => {
|
|
63
64
|
setOpen(!graphLoading && _.isEmpty(graph));
|
|
@@ -4,12 +4,19 @@ import PropTypes from "prop-types";
|
|
|
4
4
|
import { connect } from "react-redux";
|
|
5
5
|
import { Dimmer, Loader } from "semantic-ui-react";
|
|
6
6
|
import svgPanZoom from "svg-pan-zoom";
|
|
7
|
-
import { FormattedMessage } from "react-intl";
|
|
8
|
-
import {
|
|
7
|
+
import { FormattedMessage, useIntl } from "react-intl";
|
|
8
|
+
import {
|
|
9
|
+
clearNode,
|
|
10
|
+
selectNode,
|
|
11
|
+
hoverNode,
|
|
12
|
+
initSvg,
|
|
13
|
+
cancelPoll,
|
|
14
|
+
} from "../routines";
|
|
9
15
|
import LineageLink from "./LineageLink";
|
|
10
16
|
import LineageDefs from "./LineageDefs";
|
|
11
17
|
import LineageGroup from "./LineageGroup";
|
|
12
18
|
import LineageResource from "./LineageResource";
|
|
19
|
+
import "../styles/lineageGraph.less";
|
|
13
20
|
|
|
14
21
|
const svgOptions = { minZoom: 0.2, maxZoom: 2.0, fit: false, center: false };
|
|
15
22
|
const disablePanZoom = (svg) => {
|
|
@@ -50,11 +57,18 @@ export const LineageGraph = ({
|
|
|
50
57
|
groups = [],
|
|
51
58
|
resources = [],
|
|
52
59
|
loading,
|
|
60
|
+
loadingInfo,
|
|
61
|
+
cancelPoll,
|
|
53
62
|
}) => {
|
|
54
63
|
const ref = useRef(null);
|
|
55
64
|
const [state, dispatch] = useReducer(reducer, initialState);
|
|
56
65
|
const { selectedNode, hover, svg } = state;
|
|
57
66
|
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
// Anything in here is fired on component mount.
|
|
69
|
+
return () => cancelPoll();
|
|
70
|
+
}, []);
|
|
71
|
+
|
|
58
72
|
useEffect(() => {
|
|
59
73
|
if (!_.isEmpty(resources)) {
|
|
60
74
|
const svg = svgPanZoom(ref.current, svgOptions);
|
|
@@ -67,6 +81,8 @@ export const LineageGraph = ({
|
|
|
67
81
|
const onSelect = (g) => () => dispatch(selectNode.trigger(g));
|
|
68
82
|
const onHover = (g) =>
|
|
69
83
|
selectedNode ? undefined : () => dispatch(hoverNode.trigger(g));
|
|
84
|
+
const { formatMessage } = useIntl();
|
|
85
|
+
|
|
70
86
|
return (
|
|
71
87
|
<>
|
|
72
88
|
<Dimmer.Dimmable dimmed={loading} className="dl">
|
|
@@ -74,8 +90,35 @@ export const LineageGraph = ({
|
|
|
74
90
|
<Loader size="large">
|
|
75
91
|
<FormattedMessage
|
|
76
92
|
id="lineage.graph.loading"
|
|
77
|
-
defaultMessage="Analyzing..."
|
|
93
|
+
defaultMessage={"Analyzing..."}
|
|
78
94
|
/>
|
|
95
|
+
{loadingInfo?.data?.graph_hash && loadingInfo?.data?.status && (
|
|
96
|
+
<p>
|
|
97
|
+
{formatMessage({
|
|
98
|
+
id:
|
|
99
|
+
_.toLower(loadingInfo?.data?.status) === "already_started"
|
|
100
|
+
? "lineage.graph.loading.background.existing"
|
|
101
|
+
: _.toLower(loadingInfo?.data?.status) ===
|
|
102
|
+
"just_started" &&
|
|
103
|
+
"lineage.graph.loading.background.launched",
|
|
104
|
+
})}
|
|
105
|
+
</p>
|
|
106
|
+
)}
|
|
107
|
+
{loadingInfo?.data?.graph_hash && (
|
|
108
|
+
<p>
|
|
109
|
+
Graph hash:{" "}
|
|
110
|
+
<span className="graph-hash">
|
|
111
|
+
{loadingInfo?.data?.graph_hash}
|
|
112
|
+
</span>
|
|
113
|
+
</p>
|
|
114
|
+
)}
|
|
115
|
+
<p>
|
|
116
|
+
{loadingInfo?.data?.retry &&
|
|
117
|
+
formatMessage(
|
|
118
|
+
{ id: "lineage.graph.loading.polling" },
|
|
119
|
+
{ retry: loadingInfo?.data?.retry }
|
|
120
|
+
)}
|
|
121
|
+
</p>
|
|
79
122
|
</Loader>
|
|
80
123
|
</Dimmer>
|
|
81
124
|
<svg
|
|
@@ -121,17 +164,25 @@ LineageGraph.propTypes = {
|
|
|
121
164
|
paths: PropTypes.array,
|
|
122
165
|
resources: PropTypes.array,
|
|
123
166
|
height: PropTypes.string,
|
|
167
|
+
loading: PropTypes.bool,
|
|
168
|
+
loadingInfo: PropTypes.object,
|
|
169
|
+
cancelPoll: PropTypes.func,
|
|
124
170
|
};
|
|
125
171
|
|
|
126
172
|
const mapStateToProps = (
|
|
127
173
|
{ graph = {}, graphLoading, selectedNode },
|
|
128
174
|
ownProps
|
|
129
|
-
) =>
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
175
|
+
) => {
|
|
176
|
+
return {
|
|
177
|
+
paths: _.prop("paths")(_.propOr(graph, "graph")(ownProps)),
|
|
178
|
+
groups: _.prop("groups")(_.propOr(graph, "graph")(ownProps)),
|
|
179
|
+
resources: _.prop("resources")(_.propOr(graph, "graph")(ownProps)),
|
|
180
|
+
loading: graphLoading !== false,
|
|
181
|
+
loadingInfo: graphLoading,
|
|
182
|
+
selectedNode,
|
|
183
|
+
};
|
|
184
|
+
};
|
|
136
185
|
|
|
137
|
-
export default connect(mapStateToProps, { clearNode })(
|
|
186
|
+
export default connect(mapStateToProps, { clearNode, cancelPoll })(
|
|
187
|
+
LineageGraph
|
|
188
|
+
);
|
|
@@ -2,7 +2,8 @@ import React from "react";
|
|
|
2
2
|
import { Route } from "react-router-dom";
|
|
3
3
|
import { Unauthorized } from "@truedat/core/components";
|
|
4
4
|
import { useAuthorized } from "@truedat/core/hooks";
|
|
5
|
-
import { GRAPH, GRAPHS, SAMPLE } from "@truedat/core/routes";
|
|
5
|
+
import { GRAPH, GRAPHS, LINEAGE_EVENTS, SAMPLE } from "@truedat/core/routes";
|
|
6
|
+
import LineageEvents from "./LineageEvents";
|
|
6
7
|
import LineageGraph from "./LineageGraph";
|
|
7
8
|
import LineageSample from "./LineageSample";
|
|
8
9
|
import LineageForm from "./LineageForm";
|
|
@@ -13,16 +14,13 @@ const Graphs = () => (
|
|
|
13
14
|
<>
|
|
14
15
|
<LineageForm />
|
|
15
16
|
<GraphRedirector />
|
|
16
|
-
|
|
17
|
-
);
|
|
18
|
-
|
|
19
|
-
const Graph = () => (
|
|
20
|
-
<>
|
|
21
|
-
<GraphLoader />
|
|
17
|
+
{/* Load LineageGraph here so that its <Loader> is already available when clicking the LinageForm */}
|
|
22
18
|
<LineageGraph />
|
|
23
19
|
</>
|
|
24
20
|
);
|
|
25
21
|
|
|
22
|
+
const Graph = () => <GraphLoader />;
|
|
23
|
+
|
|
26
24
|
export const LineageRoutes = () => {
|
|
27
25
|
const authorized = useAuthorized("lineage");
|
|
28
26
|
return (
|
|
@@ -35,6 +33,10 @@ export const LineageRoutes = () => {
|
|
|
35
33
|
path={GRAPH}
|
|
36
34
|
render={() => (authorized ? <Graph /> : <Unauthorized />)}
|
|
37
35
|
/>
|
|
36
|
+
<Route
|
|
37
|
+
path={LINEAGE_EVENTS}
|
|
38
|
+
render={() => (authorized ? <LineageEvents /> : <Unauthorized />)}
|
|
39
|
+
/>
|
|
38
40
|
<Route
|
|
39
41
|
path={SAMPLE}
|
|
40
42
|
render={() => (authorized ? <LineageSample /> : <Unauthorized />)}
|
|
@@ -15,7 +15,6 @@ import { FormattedMessage } from "react-intl";
|
|
|
15
15
|
import { ConfirmModal, HistoryBackButton } from "@truedat/core/components";
|
|
16
16
|
import { selectTemplate } from "@truedat/df/routines";
|
|
17
17
|
import { applyTemplateWithoutDefaults } from "@truedat/df/utils";
|
|
18
|
-
import { composeProviders } from "redux-saga-test-plan/providers";
|
|
19
18
|
import { compose } from "redux";
|
|
20
19
|
import { withRouter } from "react-router-dom";
|
|
21
20
|
import { bulkUpdateStructures } from "../routines";
|
|
@@ -82,7 +81,7 @@ export class StructuresBulkUpdate extends React.Component {
|
|
|
82
81
|
template: PropTypes.object,
|
|
83
82
|
templateId: PropTypes.number,
|
|
84
83
|
templatesLoaded: PropTypes.bool,
|
|
85
|
-
|
|
84
|
+
canAutoPublish: PropTypes.bool,
|
|
86
85
|
};
|
|
87
86
|
|
|
88
87
|
state = initialState;
|
|
@@ -123,15 +122,24 @@ export class StructuresBulkUpdate extends React.Component {
|
|
|
123
122
|
};
|
|
124
123
|
|
|
125
124
|
render() {
|
|
126
|
-
const {
|
|
127
|
-
|
|
125
|
+
const {
|
|
126
|
+
loading,
|
|
127
|
+
template,
|
|
128
|
+
templateId,
|
|
129
|
+
structureCount,
|
|
130
|
+
templatesLoaded,
|
|
131
|
+
canAutoPublish,
|
|
132
|
+
structureActiveFilters,
|
|
133
|
+
} = this.props;
|
|
128
134
|
const { content } = this.state;
|
|
129
135
|
const disableAction = !template || _.isEmpty(template);
|
|
130
136
|
|
|
131
137
|
return templatesLoaded ? (
|
|
132
138
|
<Container as={Segment} text>
|
|
133
139
|
<TemplateLoader />
|
|
134
|
-
{!_.isEmpty(template) &&
|
|
140
|
+
{!_.isEmpty(template) &&
|
|
141
|
+
structureCount != 0 &&
|
|
142
|
+
_.has("type.raw")(structureActiveFilters) ? (
|
|
135
143
|
<>
|
|
136
144
|
<Header as="h2">
|
|
137
145
|
<Icon name="book" />
|
|
@@ -161,10 +169,7 @@ export class StructuresBulkUpdate extends React.Component {
|
|
|
161
169
|
/>
|
|
162
170
|
)}
|
|
163
171
|
<ConfirmModal
|
|
164
|
-
actions={actions(
|
|
165
|
-
this.handleSubmit,
|
|
166
|
-
this.props.location?.state.canAutoPublish
|
|
167
|
-
)}
|
|
172
|
+
actions={actions(this.handleSubmit, canAutoPublish)}
|
|
168
173
|
trigger={
|
|
169
174
|
<Button
|
|
170
175
|
primary
|
|
@@ -231,6 +236,8 @@ const mapStateToProps = ({
|
|
|
231
236
|
structures,
|
|
232
237
|
structureTypes,
|
|
233
238
|
structureTypesLoading,
|
|
239
|
+
userDomains,
|
|
240
|
+
structureActiveFilters,
|
|
234
241
|
}) => {
|
|
235
242
|
const structure = _.head(structures);
|
|
236
243
|
const templateId = findTemplate(structureTypes, templates, structure);
|
|
@@ -242,6 +249,13 @@ const mapStateToProps = ({
|
|
|
242
249
|
structureCount,
|
|
243
250
|
structureTypesLoaded: !structureTypesLoading,
|
|
244
251
|
templatesLoaded: !templatesLoading && !_.isEmpty(templates),
|
|
252
|
+
userDomains,
|
|
253
|
+
canAutoPublish: _.any(
|
|
254
|
+
({ domains, permission }) =>
|
|
255
|
+
!_.isEmpty(domains) &&
|
|
256
|
+
["publish_structure_note_from_draft"].includes(permission)
|
|
257
|
+
)(userDomains),
|
|
258
|
+
structureActiveFilters,
|
|
245
259
|
};
|
|
246
260
|
};
|
|
247
261
|
|
|
@@ -88,6 +88,13 @@ const AuthorizedRoutes = () => {
|
|
|
88
88
|
path={STRUCTURES_BULK_UPDATE}
|
|
89
89
|
render={() => (
|
|
90
90
|
<>
|
|
91
|
+
<UserDomainsLoader
|
|
92
|
+
permissions={[
|
|
93
|
+
"publish_structure_note_from_draft",
|
|
94
|
+
"edit_structure_note",
|
|
95
|
+
"create_structure_note",
|
|
96
|
+
]}
|
|
97
|
+
/>
|
|
91
98
|
<StructureCrumbs
|
|
92
99
|
name={formatMessage({ id: "structures.bulkUpdate.crumbs.top" })}
|
|
93
100
|
/>
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { render } from "@truedat/test/render";
|
|
3
|
+
import { LineageEventsTable } from "../LineageEventsTable";
|
|
4
|
+
import en from "../../messages/en";
|
|
5
|
+
|
|
6
|
+
describe("<LineageEventsTable />", () => {
|
|
7
|
+
const lineageEvents = [
|
|
8
|
+
{
|
|
9
|
+
graph_id: 1234,
|
|
10
|
+
graph_data: "graph_data",
|
|
11
|
+
status: "COMPLETED",
|
|
12
|
+
message: "message",
|
|
13
|
+
inserted_at: "2021-11-26T10:09:27.168999Z",
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
const lineageEventsLoading = false;
|
|
18
|
+
const fetchLineageEvents = jest.fn();
|
|
19
|
+
|
|
20
|
+
it("matches the latest snapshot", () => {
|
|
21
|
+
const props = { fetchLineageEvents, lineageEvents, lineageEventsLoading };
|
|
22
|
+
const { container } = render(<LineageEventsTable {...props} />, {
|
|
23
|
+
messages: { en },
|
|
24
|
+
});
|
|
25
|
+
expect(container).toMatchSnapshot();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("matches the latest snapshot (no jobs)", () => {
|
|
29
|
+
const props = {
|
|
30
|
+
fetchLineageEvents,
|
|
31
|
+
lineageEvents: [],
|
|
32
|
+
lineageEventsLoading,
|
|
33
|
+
};
|
|
34
|
+
const { container } = render(<LineageEventsTable {...props} />, {
|
|
35
|
+
messages: { en },
|
|
36
|
+
});
|
|
37
|
+
expect(container).toMatchSnapshot();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -17,6 +17,7 @@ describe("<StructuresBulkUpdate />", () => {
|
|
|
17
17
|
templatesLoaded: true,
|
|
18
18
|
structureTypes: [{ name: "doc", template_id: 1 }],
|
|
19
19
|
structureTypesLoaded: true,
|
|
20
|
+
structureActiveFilters: { "type.raw": "booo" },
|
|
20
21
|
};
|
|
21
22
|
|
|
22
23
|
it("matches the latest snapshot", () => {
|
|
@@ -136,6 +137,7 @@ describe("<StructuresBulkUpdate />", () => {
|
|
|
136
137
|
selectedDomain: { id: 1 },
|
|
137
138
|
templatesLoaded: true,
|
|
138
139
|
bulkUpdateStructures: jest.fn(),
|
|
140
|
+
structureActiveFilters: { "type.raw": "booo" },
|
|
139
141
|
};
|
|
140
142
|
const wrapper = shallow(<StructuresBulkUpdate {...props} />);
|
|
141
143
|
wrapper.setState({
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`<LineageEventsTable /> matches the latest snapshot (no jobs) 1`] = `
|
|
4
|
+
<div>
|
|
5
|
+
<h4
|
|
6
|
+
class="ui header"
|
|
7
|
+
>
|
|
8
|
+
<i
|
|
9
|
+
aria-hidden="true"
|
|
10
|
+
class="search icon"
|
|
11
|
+
/>
|
|
12
|
+
<div
|
|
13
|
+
class="content"
|
|
14
|
+
>
|
|
15
|
+
No graphs found
|
|
16
|
+
</div>
|
|
17
|
+
</h4>
|
|
18
|
+
</div>
|
|
19
|
+
`;
|
|
20
|
+
|
|
21
|
+
exports[`<LineageEventsTable /> matches the latest snapshot 1`] = `
|
|
22
|
+
<div>
|
|
23
|
+
<table
|
|
24
|
+
class="ui selectable sortable table"
|
|
25
|
+
>
|
|
26
|
+
<thead
|
|
27
|
+
class=""
|
|
28
|
+
>
|
|
29
|
+
<tr
|
|
30
|
+
class=""
|
|
31
|
+
>
|
|
32
|
+
<th
|
|
33
|
+
class="two wide"
|
|
34
|
+
>
|
|
35
|
+
Graph
|
|
36
|
+
</th>
|
|
37
|
+
<th
|
|
38
|
+
class="two wide"
|
|
39
|
+
>
|
|
40
|
+
Status
|
|
41
|
+
</th>
|
|
42
|
+
<th
|
|
43
|
+
class="two wide"
|
|
44
|
+
>
|
|
45
|
+
Message
|
|
46
|
+
</th>
|
|
47
|
+
<th
|
|
48
|
+
class="two wide"
|
|
49
|
+
>
|
|
50
|
+
Date
|
|
51
|
+
</th>
|
|
52
|
+
</tr>
|
|
53
|
+
</thead>
|
|
54
|
+
<tbody
|
|
55
|
+
class=""
|
|
56
|
+
>
|
|
57
|
+
<tr
|
|
58
|
+
class=""
|
|
59
|
+
>
|
|
60
|
+
<td
|
|
61
|
+
class=""
|
|
62
|
+
>
|
|
63
|
+
<span>
|
|
64
|
+
graph_data
|
|
65
|
+
</span>
|
|
66
|
+
</td>
|
|
67
|
+
<td
|
|
68
|
+
class=""
|
|
69
|
+
>
|
|
70
|
+
Completed
|
|
71
|
+
</td>
|
|
72
|
+
<td
|
|
73
|
+
class=""
|
|
74
|
+
>
|
|
75
|
+
message
|
|
76
|
+
</td>
|
|
77
|
+
<td
|
|
78
|
+
class="center aligned"
|
|
79
|
+
>
|
|
80
|
+
<time
|
|
81
|
+
datetime="1637921367168"
|
|
82
|
+
>
|
|
83
|
+
2021-11-26 10:09
|
|
84
|
+
</time>
|
|
85
|
+
</td>
|
|
86
|
+
</tr>
|
|
87
|
+
</tbody>
|
|
88
|
+
</table>
|
|
89
|
+
</div>
|
|
90
|
+
`;
|