@truedat/dd 5.3.0 → 5.3.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/CHANGELOG.md +6 -0
- package/package.json +6 -6
- package/src/api/queries.js +11 -0
- package/src/api.js +5 -0
- package/src/components/LinkLabelsSelector.js +74 -0
- package/src/components/StructureStructureForm.js +95 -0
- package/src/components/StructureStructureLinks.js +89 -3
- package/src/components/StructureTabPane.js +11 -1
- package/src/components/StructureTabPaneRoutes.js +2 -2
- package/src/components/StructureTabRoutes.js +2 -2
- package/src/components/StructureTabs.js +1 -1
- package/src/components/__tests__/StructureStructureForm.spec.js +138 -0
- package/src/components/__tests__/StructureStructureLinks.spec.js +109 -35
- package/src/messages/en.js +2 -0
- package/src/messages/es.js +3 -0
- package/src/reducers/structureRedirect.js +6 -0
- package/src/routines.js +3 -1
- package/src/sagas/__tests__/deleteStructureStructureLink.spec.js +101 -0
- package/src/sagas/deleteStructureStructureLink.js +45 -0
- package/src/sagas/index.js +6 -0
- package/src/sagas/linkStructureToStructure.js +46 -0
- package/src/selectors/__tests__/getStructuresFields.spec.js +2 -2
- package/src/selectors/getActiveTab.js +2 -2
- package/src/selectors/getTabVisibility.js +1 -0
- package/src/components/__tests__/__snapshots__/StructureStructureLinks.spec.js.snap +0 -287
|
@@ -1,22 +1,27 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { render } from "@truedat/test/render";
|
|
3
3
|
import { waitFor } from "@testing-library/react";
|
|
4
|
-
import
|
|
4
|
+
import userEvent from "@testing-library/user-event";
|
|
5
5
|
import { STRUCTURE_STRUCTURE_LINKS_QUERY } from "../../api/queries";
|
|
6
|
+
import { deleteStructureStructureLink } from "../../routines";
|
|
6
7
|
import StructureStructureLinks from "../StructureStructureLinks";
|
|
7
8
|
|
|
8
9
|
jest.mock("react-router-dom", () => ({
|
|
9
10
|
...jest.requireActual("react-router-dom"),
|
|
10
|
-
useParams:
|
|
11
|
+
useParams: () => ({ id: 60217 }),
|
|
11
12
|
}));
|
|
12
13
|
|
|
13
14
|
const dataStructureWithLinks = {
|
|
14
15
|
currentVersion: {
|
|
15
16
|
id: "212416",
|
|
16
|
-
name: "
|
|
17
|
+
name: "STRUCTURE_1",
|
|
17
18
|
},
|
|
18
19
|
dataStructureLinks: [
|
|
19
20
|
{
|
|
21
|
+
_actions: {
|
|
22
|
+
delete_struct_to_struct_link: true,
|
|
23
|
+
},
|
|
24
|
+
id: "1",
|
|
20
25
|
labels: [
|
|
21
26
|
{
|
|
22
27
|
name: "copy",
|
|
@@ -24,54 +29,58 @@ const dataStructureWithLinks = {
|
|
|
24
29
|
],
|
|
25
30
|
source: {
|
|
26
31
|
currentVersion: {
|
|
27
|
-
name: "
|
|
32
|
+
name: "STRUCTURE_1",
|
|
28
33
|
pathWithIds: [
|
|
29
34
|
{
|
|
30
35
|
data_structure_id: "114207",
|
|
31
|
-
name: "
|
|
36
|
+
name: "UNO",
|
|
32
37
|
},
|
|
33
38
|
{
|
|
34
39
|
data_structure_id: "58050",
|
|
35
|
-
name: "
|
|
40
|
+
name: "DOS",
|
|
36
41
|
},
|
|
37
42
|
{
|
|
38
43
|
data_structure_id: "58045",
|
|
39
|
-
name: "
|
|
44
|
+
name: "TRES",
|
|
40
45
|
},
|
|
41
46
|
],
|
|
42
47
|
},
|
|
43
48
|
id: "60217",
|
|
44
49
|
system: {
|
|
45
50
|
id: "2",
|
|
46
|
-
name: "
|
|
51
|
+
name: "SYSTEM_1",
|
|
47
52
|
},
|
|
48
53
|
},
|
|
49
54
|
target: {
|
|
50
55
|
currentVersion: {
|
|
51
|
-
name: "
|
|
56
|
+
name: "STRUCTURE_2",
|
|
52
57
|
pathWithIds: [
|
|
53
58
|
{
|
|
54
59
|
data_structure_id: "114207",
|
|
55
|
-
name: "
|
|
60
|
+
name: "UNO",
|
|
56
61
|
},
|
|
57
62
|
{
|
|
58
63
|
data_structure_id: "58050",
|
|
59
|
-
name: "
|
|
64
|
+
name: "DOS",
|
|
60
65
|
},
|
|
61
66
|
{
|
|
62
67
|
data_structure_id: "58045",
|
|
63
|
-
name: "
|
|
68
|
+
name: "TRES",
|
|
64
69
|
},
|
|
65
70
|
],
|
|
66
71
|
},
|
|
67
72
|
id: "60218",
|
|
68
73
|
system: {
|
|
69
74
|
id: "2",
|
|
70
|
-
name: "
|
|
75
|
+
name: "SYSTEM_1",
|
|
71
76
|
},
|
|
72
77
|
},
|
|
73
78
|
},
|
|
74
79
|
{
|
|
80
|
+
_actions: {
|
|
81
|
+
delete_struct_to_struct_link: true,
|
|
82
|
+
},
|
|
83
|
+
id: "2",
|
|
75
84
|
labels: [
|
|
76
85
|
{
|
|
77
86
|
name: "label_1_1",
|
|
@@ -82,46 +91,46 @@ const dataStructureWithLinks = {
|
|
|
82
91
|
],
|
|
83
92
|
source: {
|
|
84
93
|
currentVersion: {
|
|
85
|
-
name: "
|
|
94
|
+
name: "STRUCTURE_3",
|
|
86
95
|
pathWithIds: [
|
|
87
96
|
{
|
|
88
97
|
data_structure_id: "147587",
|
|
89
|
-
name: "
|
|
98
|
+
name: "UNO",
|
|
90
99
|
},
|
|
91
100
|
{
|
|
92
101
|
data_structure_id: "151648",
|
|
93
|
-
name: "
|
|
102
|
+
name: "DOS",
|
|
94
103
|
},
|
|
95
104
|
],
|
|
96
105
|
},
|
|
97
106
|
id: "151674",
|
|
98
107
|
system: {
|
|
99
108
|
id: "11",
|
|
100
|
-
name: "
|
|
109
|
+
name: "SYSTEM_2",
|
|
101
110
|
},
|
|
102
111
|
},
|
|
103
112
|
target: {
|
|
104
113
|
currentVersion: {
|
|
105
|
-
name: "
|
|
114
|
+
name: "STRUCTURE_1",
|
|
106
115
|
pathWithIds: [
|
|
107
116
|
{
|
|
108
117
|
data_structure_id: "114207",
|
|
109
|
-
name: "
|
|
118
|
+
name: "UNO",
|
|
110
119
|
},
|
|
111
120
|
{
|
|
112
121
|
data_structure_id: "58050",
|
|
113
|
-
name: "
|
|
122
|
+
name: "DOS",
|
|
114
123
|
},
|
|
115
124
|
{
|
|
116
125
|
data_structure_id: "58045",
|
|
117
|
-
name: "
|
|
126
|
+
name: "TRES",
|
|
118
127
|
},
|
|
119
128
|
],
|
|
120
129
|
},
|
|
121
130
|
id: "60217",
|
|
122
131
|
system: {
|
|
123
132
|
id: "2",
|
|
124
|
-
name: "
|
|
133
|
+
name: "SYSTEM_1",
|
|
125
134
|
},
|
|
126
135
|
},
|
|
127
136
|
},
|
|
@@ -138,24 +147,89 @@ const linksMock = {
|
|
|
138
147
|
};
|
|
139
148
|
|
|
140
149
|
describe("<StructureStructureLinks />", () => {
|
|
141
|
-
const props = {
|
|
150
|
+
const props = {
|
|
151
|
+
dataStructureWithLinks,
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const structureActions = {
|
|
155
|
+
create_struct_to_struct_link: {
|
|
156
|
+
href: "/some/url",
|
|
157
|
+
method: "POST",
|
|
158
|
+
},
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const renderOpts = {
|
|
162
|
+
routes: ["/structures/60217/structureLinks"],
|
|
163
|
+
mocks: [linksMock],
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
it("shows structure to structure links", async () => {
|
|
167
|
+
const { getByRole } = render(<StructureStructureLinks {...props} />, {
|
|
168
|
+
...renderOpts,
|
|
169
|
+
state: { structureActions },
|
|
170
|
+
});
|
|
171
|
+
await waitFor(() => {
|
|
172
|
+
expect(getByRole("link", { name: /STRUCTURE_2/i })).toBeInTheDocument();
|
|
173
|
+
expect(getByRole("link", { name: /STRUCTURE_3/i })).toBeInTheDocument();
|
|
174
|
+
});
|
|
175
|
+
await waitFor(() => {
|
|
176
|
+
expect(getByRole("button", { name: /Add link/i })).toBeInTheDocument();
|
|
177
|
+
});
|
|
178
|
+
expect(
|
|
179
|
+
document.getElementById("delete-link-60217-60218")
|
|
180
|
+
).toBeInTheDocument();
|
|
181
|
+
expect(
|
|
182
|
+
document.getElementById("delete-link-151674-60217")
|
|
183
|
+
).toBeInTheDocument();
|
|
184
|
+
});
|
|
142
185
|
|
|
143
|
-
it("
|
|
144
|
-
const
|
|
145
|
-
routes: ["/structures/60217/structureLinks"],
|
|
146
|
-
mocks: [linksMock],
|
|
147
|
-
};
|
|
148
|
-
useParams.mockImplementation(() => ({
|
|
149
|
-
id: 60217,
|
|
150
|
-
}));
|
|
151
|
-
const { container, findByText, getByRole, queryByText, debug } = render(
|
|
186
|
+
it("hides the 'add link' and delete link buttons if there are no permissions", async () => {
|
|
187
|
+
const { getByRole, queryByRole } = render(
|
|
152
188
|
<StructureStructureLinks {...props} />,
|
|
153
189
|
renderOpts
|
|
154
190
|
);
|
|
155
191
|
await waitFor(() => {
|
|
156
|
-
expect(getByRole("link", { name: /
|
|
157
|
-
expect(getByRole("link", { name: /
|
|
192
|
+
expect(getByRole("link", { name: /STRUCTURE_2/i })).toBeInTheDocument();
|
|
193
|
+
expect(getByRole("link", { name: /STRUCTURE_3/i })).toBeInTheDocument();
|
|
194
|
+
});
|
|
195
|
+
expect(
|
|
196
|
+
queryByRole("button", { name: /Add link/i })
|
|
197
|
+
).not.toBeInTheDocument();
|
|
198
|
+
expect(document.getElementById("delete-link-60217-60218")).toBeNull();
|
|
199
|
+
expect(document.getElementById("delete-link-151674-60217")).toBeNull();
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("deletes link", async () => {
|
|
203
|
+
const dispatch = jest.fn();
|
|
204
|
+
const { getByText, getByRole } = render(
|
|
205
|
+
<StructureStructureLinks {...props} />,
|
|
206
|
+
{
|
|
207
|
+
...renderOpts,
|
|
208
|
+
state: { structureActions },
|
|
209
|
+
dispatch,
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
await waitFor(() => {
|
|
213
|
+
expect(getByRole("link", { name: /STRUCTURE_2/i })).toBeInTheDocument();
|
|
214
|
+
expect(getByRole("link", { name: /STRUCTURE_3/i })).toBeInTheDocument();
|
|
215
|
+
});
|
|
216
|
+
await waitFor(() => {
|
|
217
|
+
expect(getByRole("button", { name: /Add link/i })).toBeInTheDocument();
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
const deleteButton = document.getElementById("delete-link-60217-60218");
|
|
221
|
+
userEvent.click(deleteButton);
|
|
222
|
+
expect(getByText("Delete link")).toBeInTheDocument();
|
|
223
|
+
const yesButton = getByRole("button", { name: /Yes/i });
|
|
224
|
+
userEvent.click(yesButton);
|
|
225
|
+
|
|
226
|
+
expect(dispatch).toHaveBeenCalledWith({
|
|
227
|
+
...deleteStructureStructureLink(),
|
|
228
|
+
payload: {
|
|
229
|
+
dataStructureLinkId: "1",
|
|
230
|
+
sourceStructureId: "60217",
|
|
231
|
+
targetStructureId: "60218",
|
|
232
|
+
},
|
|
158
233
|
});
|
|
159
|
-
expect(container).toMatchSnapshot();
|
|
160
234
|
});
|
|
161
235
|
});
|
package/src/messages/en.js
CHANGED
|
@@ -424,6 +424,8 @@ export default {
|
|
|
424
424
|
"structureLink.currentStructure": "Current structure",
|
|
425
425
|
"structureLink.label": "Relation label",
|
|
426
426
|
"structureLink.relatedStructure": "Related structure",
|
|
427
|
+
"structureLink.selector.label": "Relation label",
|
|
428
|
+
"structureLink.selector.placeholder": "Select a relation label...",
|
|
427
429
|
"structureSelector.union.criteria": "Union criteria",
|
|
428
430
|
"structureSelector.union.type": "Union type",
|
|
429
431
|
"structureTag.comment": "Comments",
|
package/src/messages/es.js
CHANGED
|
@@ -433,6 +433,9 @@ export default {
|
|
|
433
433
|
"structureLink.currentStructure": "Estructura actual",
|
|
434
434
|
"structureLink.label": "Etiqueta de relación",
|
|
435
435
|
"structureLink.relatedStructure": "Estructura relacionada",
|
|
436
|
+
"structureLink.selector.label": "Etiqueta de relación",
|
|
437
|
+
"structureLink.selector.placeholder":
|
|
438
|
+
"Seleccione una etiqueta de relación...",
|
|
436
439
|
"structureSelector.union.criteria": "Criterio de unión",
|
|
437
440
|
"structureSelector.union.type": "Tipo de unión",
|
|
438
441
|
"structureTag.comment": "Comentario",
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
STRUCTURE_TAGS,
|
|
9
9
|
STRUCTURE_TYPES,
|
|
10
10
|
STRUCTURES,
|
|
11
|
+
STRUCTURE_STRUCTURE_LINKS,
|
|
11
12
|
linkTo,
|
|
12
13
|
} from "@truedat/core/routes";
|
|
13
14
|
import {
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
deleteStructure,
|
|
25
26
|
deleteTag,
|
|
26
27
|
doStructureNoteAction,
|
|
28
|
+
linkStructureToStructure,
|
|
27
29
|
updateGrantApprovalRule,
|
|
28
30
|
updateReferenceDataset,
|
|
29
31
|
updateStructure,
|
|
@@ -50,6 +52,10 @@ export const structureRedirect = (
|
|
|
50
52
|
const id = _.path("data.id")(payload);
|
|
51
53
|
return linkTo.SYSTEM_STRUCTURES({ id });
|
|
52
54
|
}
|
|
55
|
+
case linkStructureToStructure.SUCCESS:
|
|
56
|
+
return linkTo.STRUCTURE_STRUCTURE_LINKS({
|
|
57
|
+
id: payload.sourceStructureId,
|
|
58
|
+
});
|
|
53
59
|
case updateSystem.SUCCESS: {
|
|
54
60
|
const id = _.path("data.id")(payload);
|
|
55
61
|
return linkTo.SYSTEM_STRUCTURES({ id });
|
package/src/routines.js
CHANGED
|
@@ -51,6 +51,7 @@ export const deleteGrantApprovalRule = createRoutine("DELETE_GRANT_APPROVAL_RULE
|
|
|
51
51
|
export const deleteReferenceDataset = createRoutine("DELETE_REFERENCE_DATASET");
|
|
52
52
|
export const deleteStructureTag = createRoutine("DELETE_STRUCTURE_TAG");
|
|
53
53
|
export const deleteStructure = createRoutine("DELETE_STRUCTURE");
|
|
54
|
+
export const deleteStructureStructureLink = createRoutine("DELETE_STRUCTURE_STRUCTURE_LINK");
|
|
54
55
|
export const deleteTag = createRoutine("DELETE_TAG");
|
|
55
56
|
export const deleteUserSearchFilter = createRoutine("DELETE_USER_SEARCH_FILTER");
|
|
56
57
|
export const doStructureNoteAction = createRoutine("DO_STRUCTURE_NOTE_ACTION");
|
|
@@ -86,7 +87,7 @@ export const fetchUserSearchFilters = createRoutine("FETCH_USER_SEARCH_FILTERS")
|
|
|
86
87
|
export const filterStructures = createRoutine("FILTER_STRUCTURES");
|
|
87
88
|
export const hoverNode = createRoutine("HOVER_NODE");
|
|
88
89
|
export const initSvg = createRoutine("INIT_SVG");
|
|
89
|
-
export const
|
|
90
|
+
export const linkStructureToStructure = createRoutine("LINK_STRUCTURE_TO_STRUCTURE");
|
|
90
91
|
export const loadLineageEvents = createRoutine("LOAD_LINEAGE_EVENTS");
|
|
91
92
|
export const openGrantFilter = createRoutine("OPEN_GRANT_FILTER");
|
|
92
93
|
export const openStructureFilter = createRoutine("OPEN_STRUCTURE_FILTER");
|
|
@@ -113,6 +114,7 @@ export const setGrantChangeRequestCart = createRoutine("SET_GRANT_CHANGE_REQUEST
|
|
|
113
114
|
export const setGrantRequestsQuery = createRoutine("SET_GRANT_REQUESTS_QUERY");
|
|
114
115
|
export const sortGrants = createRoutine("SORT_GRANTS");
|
|
115
116
|
export const sortStructures = createRoutine("SORT_STRUCTURES");
|
|
117
|
+
export const tagStructure = createRoutine("TAG_STRUCTURE");
|
|
116
118
|
export const toggleGrantDateFilter = createRoutine("TOGGLE_GRANT_DATE_FILTER");
|
|
117
119
|
export const toggleGrantFilterValue = createRoutine("TOGGLE_GRANT_FILTER_VALUE");
|
|
118
120
|
export const toggleStructureDateFilter = createRoutine("TOGGLE_STRUCTURE_DATE_FILTER");
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import { compile } from "path-to-regexp";
|
|
3
|
+
import { testSaga } from "redux-saga-test-plan";
|
|
4
|
+
import { apiJsonDelete, JSON_OPTS } from "@truedat/core/services/api";
|
|
5
|
+
import {
|
|
6
|
+
deleteStructureStructureLinkSaga,
|
|
7
|
+
deleteStructureStructureLinkRequestSaga,
|
|
8
|
+
} from "../deleteStructureStructureLink";
|
|
9
|
+
import { deleteStructureStructureLink } from "../../routines";
|
|
10
|
+
import { API_STRUCTURE_TO_STRUCTURE_LINK } from "../../api";
|
|
11
|
+
|
|
12
|
+
describe("sagas: deleteStructureStructureRequestSaga", () => {
|
|
13
|
+
it("should invoke deleteStructureStructureSaga on deleteStructureStructureLink.TRIGGER", () => {
|
|
14
|
+
expect(() => {
|
|
15
|
+
testSaga(deleteStructureStructureLinkRequestSaga)
|
|
16
|
+
.next()
|
|
17
|
+
.takeLatest(
|
|
18
|
+
deleteStructureStructureLink.TRIGGER,
|
|
19
|
+
deleteStructureStructureLinkSaga
|
|
20
|
+
)
|
|
21
|
+
.finish()
|
|
22
|
+
.isDone();
|
|
23
|
+
}).not.toThrow();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("should throw exception if an unhandled action is received", () => {
|
|
27
|
+
expect(() => {
|
|
28
|
+
testSaga(deleteStructureStructureLinkRequestSaga)
|
|
29
|
+
.next()
|
|
30
|
+
.takeLatest("FOO", deleteStructureStructureLinkSaga);
|
|
31
|
+
}).toThrow();
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe("sagas: deleteStructureStructureLinkSaga", () => {
|
|
36
|
+
const sourceStructureId = 1;
|
|
37
|
+
const targetStructureId = 2;
|
|
38
|
+
const dataStructureLinkId = 1;
|
|
39
|
+
const receivedPayload = {
|
|
40
|
+
sourceStructureId,
|
|
41
|
+
targetStructureId,
|
|
42
|
+
dataStructureLinkId,
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const deletePayload = {
|
|
46
|
+
sourceStructureId,
|
|
47
|
+
targetStructureId,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const url = compile(API_STRUCTURE_TO_STRUCTURE_LINK)({
|
|
51
|
+
sourceStructureId,
|
|
52
|
+
targetStructureId,
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
const client = {
|
|
56
|
+
cache: {
|
|
57
|
+
identify: jest.fn(),
|
|
58
|
+
evict: jest.fn(),
|
|
59
|
+
gc: jest.fn(),
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
it("should put a success action when a response is returned", () => {
|
|
64
|
+
expect(() => {
|
|
65
|
+
testSaga(deleteStructureStructureLinkSaga, { payload: receivedPayload })
|
|
66
|
+
.next()
|
|
67
|
+
.getContext("client")
|
|
68
|
+
.next(client)
|
|
69
|
+
.put(deleteStructureStructureLink.request(deletePayload))
|
|
70
|
+
.next(client)
|
|
71
|
+
.call(apiJsonDelete, url, JSON_OPTS)
|
|
72
|
+
.next({ data: deletePayload })
|
|
73
|
+
.put(deleteStructureStructureLink.success(deletePayload))
|
|
74
|
+
.next()
|
|
75
|
+
.put(deleteStructureStructureLink.fulfill())
|
|
76
|
+
.next()
|
|
77
|
+
.isDone();
|
|
78
|
+
}).not.toThrow();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("should put a failure action when a call returns an error", () => {
|
|
82
|
+
const message = "Request failed";
|
|
83
|
+
const error = { message };
|
|
84
|
+
|
|
85
|
+
expect(() => {
|
|
86
|
+
testSaga(deleteStructureStructureLinkSaga, { payload: receivedPayload })
|
|
87
|
+
.next()
|
|
88
|
+
.getContext("client")
|
|
89
|
+
.next(client)
|
|
90
|
+
.put(deleteStructureStructureLink.request(deletePayload))
|
|
91
|
+
.next(client)
|
|
92
|
+
.call(apiJsonDelete, url, JSON_OPTS)
|
|
93
|
+
.throw(error)
|
|
94
|
+
.put(deleteStructureStructureLink.failure(message))
|
|
95
|
+
.next()
|
|
96
|
+
.put(deleteStructureStructureLink.fulfill())
|
|
97
|
+
.next()
|
|
98
|
+
.isDone();
|
|
99
|
+
}).not.toThrow();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { compile } from "path-to-regexp";
|
|
2
|
+
import { call, put, takeLatest, getContext } from "redux-saga/effects";
|
|
3
|
+
import { apiJsonDelete, JSON_OPTS } from "@truedat/core/services/api";
|
|
4
|
+
import { API_STRUCTURE_TO_STRUCTURE_LINK } from "../api";
|
|
5
|
+
import { deleteStructureStructureLink } from "../routines";
|
|
6
|
+
|
|
7
|
+
export const evictDataStructureLink = (cache, dataStructureLinkId) => {
|
|
8
|
+
const cachedDataStructureLink = cache.identify({
|
|
9
|
+
__typename: "DataStructureLink",
|
|
10
|
+
id: dataStructureLinkId,
|
|
11
|
+
});
|
|
12
|
+
cache.evict(cachedDataStructureLink);
|
|
13
|
+
cache.gc();
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function* deleteStructureStructureLinkSaga({
|
|
17
|
+
payload: { sourceStructureId, targetStructureId, dataStructureLinkId },
|
|
18
|
+
}) {
|
|
19
|
+
const client = yield getContext("client");
|
|
20
|
+
const cache = client.cache;
|
|
21
|
+
try {
|
|
22
|
+
const payload = { sourceStructureId, targetStructureId };
|
|
23
|
+
const url = compile(API_STRUCTURE_TO_STRUCTURE_LINK)(payload);
|
|
24
|
+
yield put(deleteStructureStructureLink.request(payload));
|
|
25
|
+
yield call(apiJsonDelete, url, JSON_OPTS);
|
|
26
|
+
evictDataStructureLink(cache, dataStructureLinkId);
|
|
27
|
+
yield put(deleteStructureStructureLink.success(payload));
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if (error.response) {
|
|
30
|
+
const { status, data } = error.response;
|
|
31
|
+
yield put(deleteStructureStructureLink.failure({ status, data }));
|
|
32
|
+
} else {
|
|
33
|
+
yield put(deleteStructureStructureLink.failure(error.message));
|
|
34
|
+
}
|
|
35
|
+
} finally {
|
|
36
|
+
yield put(deleteStructureStructureLink.fulfill());
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function* deleteStructureStructureLinkRequestSaga() {
|
|
41
|
+
yield takeLatest(
|
|
42
|
+
deleteStructureStructureLink.TRIGGER,
|
|
43
|
+
deleteStructureStructureLinkSaga
|
|
44
|
+
);
|
|
45
|
+
}
|
package/src/sagas/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import { deleteGrantApprovalRuleRequestSaga } from "./deleteGrantApprovalRule";
|
|
|
12
12
|
import { deleteStructureTagRequestSaga } from "./deleteStructureTag";
|
|
13
13
|
import { deleteReferenceDatasetRequestSaga } from "./deleteReferenceDataset";
|
|
14
14
|
import { deleteStructureRequestSaga } from "./deleteStructure";
|
|
15
|
+
import { deleteStructureStructureLinkRequestSaga } from "./deleteStructureStructureLink";
|
|
15
16
|
import { deleteTagRequestSaga } from "./deleteTag";
|
|
16
17
|
import { deleteUserSearchFilterRequestSaga } from "./deleteUserSearchFilter";
|
|
17
18
|
import { doStructureNoteActionRequestSaga } from "./doStructureNoteAction";
|
|
@@ -41,6 +42,7 @@ import { fetchSystemRequestSaga } from "./fetchSystem";
|
|
|
41
42
|
import { fetchSystemStructuresRequestSaga } from "./fetchSystemStructures";
|
|
42
43
|
import { fetchSystemsRequestSaga } from "./fetchSystems";
|
|
43
44
|
import { fetchUserSearchFiltersRequestSaga } from "./fetchUserSearchFilters";
|
|
45
|
+
import { linkStructureToStructureRequestSaga } from "./linkStructureToStructure";
|
|
44
46
|
import { tagStructureRequestSaga } from "./tagStructure";
|
|
45
47
|
import { operateGrantRequestToCartRequestSaga } from "./operateGrantRequestCart";
|
|
46
48
|
import { requestGrantRemovalRequestSaga } from "./requestGrantRemoval";
|
|
@@ -69,6 +71,7 @@ export {
|
|
|
69
71
|
deleteStructureTagRequestSaga,
|
|
70
72
|
deleteReferenceDatasetRequestSaga,
|
|
71
73
|
deleteStructureRequestSaga,
|
|
74
|
+
deleteStructureStructureLinkRequestSaga,
|
|
72
75
|
deleteTagRequestSaga,
|
|
73
76
|
deleteUserSearchFilterRequestSaga,
|
|
74
77
|
doStructureNoteActionRequestSaga,
|
|
@@ -98,6 +101,7 @@ export {
|
|
|
98
101
|
fetchSystemStructuresRequestSaga,
|
|
99
102
|
fetchSystemsRequestSaga,
|
|
100
103
|
fetchUserSearchFiltersRequestSaga,
|
|
104
|
+
linkStructureToStructureRequestSaga,
|
|
101
105
|
tagStructureRequestSaga,
|
|
102
106
|
operateGrantRequestToCartRequestSaga,
|
|
103
107
|
requestGrantRemovalRequestSaga,
|
|
@@ -127,6 +131,7 @@ export default [
|
|
|
127
131
|
deleteStructureTagRequestSaga(),
|
|
128
132
|
deleteReferenceDatasetRequestSaga(),
|
|
129
133
|
deleteStructureRequestSaga(),
|
|
134
|
+
deleteStructureStructureLinkRequestSaga(),
|
|
130
135
|
deleteTagRequestSaga(),
|
|
131
136
|
deleteUserSearchFilterRequestSaga(),
|
|
132
137
|
doStructureNoteActionRequestSaga(),
|
|
@@ -156,6 +161,7 @@ export default [
|
|
|
156
161
|
fetchSystemStructuresRequestSaga(),
|
|
157
162
|
fetchSystemsRequestSaga(),
|
|
158
163
|
fetchUserSearchFiltersRequestSaga(),
|
|
164
|
+
linkStructureToStructureRequestSaga(),
|
|
159
165
|
tagStructureRequestSaga(),
|
|
160
166
|
operateGrantRequestToCartRequestSaga(),
|
|
161
167
|
requestGrantRemovalRequestSaga(),
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import { call, put, takeLatest } from "redux-saga/effects";
|
|
3
|
+
import { apiJsonPost, JSON_OPTS } from "@truedat/core/services/api";
|
|
4
|
+
import { linkStructureToStructure } from "../routines";
|
|
5
|
+
import { API_STRUCTURE_TO_STRUCTURE_LINKS } from "../api";
|
|
6
|
+
|
|
7
|
+
export function* linkStructureToStructureSaga({ payload }) {
|
|
8
|
+
try {
|
|
9
|
+
const {
|
|
10
|
+
sourceStructureId: source_id,
|
|
11
|
+
targetStructureId: target_id,
|
|
12
|
+
labelIds: label_ids,
|
|
13
|
+
} = payload;
|
|
14
|
+
|
|
15
|
+
const payloadSnakeCase = {
|
|
16
|
+
source_id,
|
|
17
|
+
target_id,
|
|
18
|
+
label_ids,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
yield put(linkStructureToStructure.request(payloadSnakeCase));
|
|
22
|
+
const { data } = yield call(
|
|
23
|
+
apiJsonPost,
|
|
24
|
+
API_STRUCTURE_TO_STRUCTURE_LINKS,
|
|
25
|
+
{ data_structure_link: payloadSnakeCase },
|
|
26
|
+
JSON_OPTS
|
|
27
|
+
);
|
|
28
|
+
yield put(linkStructureToStructure.success({ ...data, ...payload }));
|
|
29
|
+
} catch (error) {
|
|
30
|
+
if (error.response) {
|
|
31
|
+
const { status, data } = error.response;
|
|
32
|
+
yield put(linkStructureToStructure.failure({ status, data }));
|
|
33
|
+
} else {
|
|
34
|
+
yield put(linkStructureToStructure.failure(error.message));
|
|
35
|
+
}
|
|
36
|
+
} finally {
|
|
37
|
+
yield put(linkStructureToStructure.fulfill());
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function* linkStructureToStructureRequestSaga() {
|
|
42
|
+
yield takeLatest(
|
|
43
|
+
linkStructureToStructure.TRIGGER,
|
|
44
|
+
linkStructureToStructureSaga
|
|
45
|
+
);
|
|
46
|
+
}
|
|
@@ -12,7 +12,7 @@ describe("selectors: getStructuresFields", () => {
|
|
|
12
12
|
external_id: null,
|
|
13
13
|
inserted_at: "2019-10-22T10:37:54Z",
|
|
14
14
|
links: [],
|
|
15
|
-
name: "
|
|
15
|
+
name: "STRUCTURE_1",
|
|
16
16
|
nullable: true,
|
|
17
17
|
precision: "8.0",
|
|
18
18
|
type: "num",
|
|
@@ -73,7 +73,7 @@ describe("selectors: getStructuresFields", () => {
|
|
|
73
73
|
external_id: null,
|
|
74
74
|
inserted_at: "2019-10-22T10:37:54Z",
|
|
75
75
|
links: [],
|
|
76
|
-
name: "
|
|
76
|
+
name: "STRUCTURE_1",
|
|
77
77
|
nullable: true,
|
|
78
78
|
precision: "8.0",
|
|
79
79
|
type: "num",
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
STRUCTURE_NOTES_EDIT,
|
|
9
9
|
STRUCTURE_PARENTS,
|
|
10
10
|
STRUCTURE_PROFILE,
|
|
11
|
-
|
|
11
|
+
STRUCTURE_STRUCTURE_LINKS,
|
|
12
12
|
STRUCTURE_RULES,
|
|
13
13
|
STRUCTURE_LINKS,
|
|
14
14
|
STRUCTURE_LINKS_NEW,
|
|
@@ -44,7 +44,7 @@ export const getActiveTab = (tabVisibility, path) => {
|
|
|
44
44
|
[_.eq(STRUCTURE_METADATA), _.constant("metadata")],
|
|
45
45
|
[_.eq(STRUCTURE_PARENTS), _.constant("parents")],
|
|
46
46
|
[_.eq(STRUCTURE_PROFILE), _.constant("profile")],
|
|
47
|
-
[_.eq(
|
|
47
|
+
[_.eq(STRUCTURE_STRUCTURE_LINKS), _.constant("structureLinks")],
|
|
48
48
|
[_.eq(STRUCTURE_RULES), _.constant("rules")],
|
|
49
49
|
[_.eq(STRUCTURE_LINKS), _.constant("links")],
|
|
50
50
|
[_.eq(STRUCTURE_LINKS_NEW), _.constant("links")],
|
|
@@ -37,6 +37,7 @@ const notesTabVisible = ({ templatesLoading, templates, structure }) =>
|
|
|
37
37
|
|
|
38
38
|
const versionsTabVisible = notEmptyPath("structureVersions");
|
|
39
39
|
const structureLinksTabVisible = (state) =>
|
|
40
|
+
_.has("manage_structure_to_structure_link", state?.structureActions) ||
|
|
40
41
|
state?.structure?.data_structure_link_count > 0;
|
|
41
42
|
const rulesTabVisible = (state) => state?.structure?.implementation_count > 0;
|
|
42
43
|
const lineageTabVisible = _.anyPass([_.path("structure.degree.in")]);
|