@truedat/dd 5.19.0 → 5.20.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.
Files changed (43) hide show
  1. package/package.json +5 -5
  2. package/src/api/queries.js +19 -1
  3. package/src/components/Grant.js +9 -27
  4. package/src/components/GrantRemoval.js +26 -34
  5. package/src/components/GrantRemovalDirectButton.js +89 -0
  6. package/src/components/GrantRemovalWorkflow.js +107 -0
  7. package/src/components/GrantRemovalWorkflowDropdown.js +144 -0
  8. package/src/components/GrantRequest.js +2 -1
  9. package/src/components/GrantRequestCancel.js +5 -2
  10. package/src/components/GrantRequestHeader.js +13 -7
  11. package/src/components/GrantRequestRow.js +8 -1
  12. package/src/components/GrantRequests.js +8 -3
  13. package/src/components/GrantRequestsTable.js +1 -1
  14. package/src/components/StructureGrantDropdown.js +7 -40
  15. package/src/components/StructureGrantSummaryButton.js +2 -2
  16. package/src/components/StructureGrants.js +21 -17
  17. package/src/components/__tests__/Grant.spec.js +11 -7
  18. package/src/components/__tests__/GrantRemoval.spec.js +19 -54
  19. package/src/components/__tests__/GrantRemovalDirectButton.spec.js +66 -0
  20. package/src/components/__tests__/GrantRemovalWorkflow.spec.js +157 -0
  21. package/src/components/__tests__/GrantRequest.spec.js +2 -0
  22. package/src/components/__tests__/GrantRequestHeader.spec.js +2 -5
  23. package/src/components/__tests__/StructureGrantDropdown.spec.js +1 -16
  24. package/src/components/__tests__/StructureGrantSummaryButton.spec.js +3 -2
  25. package/src/components/__tests__/StructureGrants.spec.js +5 -1
  26. package/src/components/__tests__/__snapshots__/Grant.spec.js.snap +5 -4
  27. package/src/components/__tests__/__snapshots__/GrantRequest.spec.js.snap +3 -3
  28. package/src/components/__tests__/__snapshots__/GrantRequestHeader.spec.js.snap +4 -4
  29. package/src/components/__tests__/__snapshots__/GrantRequestsSearchResults.spec.js.snap +1 -1
  30. package/src/components/__tests__/__snapshots__/StructureGrantDropdown.spec.js.snap +0 -52
  31. package/src/components/__tests__/__snapshots__/StructureGrantListButton.spec.js.snap +0 -14
  32. package/src/components/__tests__/__snapshots__/StructureGrantSummaryButton.spec.js.snap +0 -14
  33. package/src/components/__tests__/__snapshots__/StructureGrants.spec.js.snap +4 -5
  34. package/src/hooks/useGrantRequest.js +10 -1
  35. package/src/messages/en.js +23 -8
  36. package/src/messages/es.js +26 -9
  37. package/src/reducers/structure.js +1 -0
  38. package/src/sagas/__tests__/createGrantRequestStatus.spec.js +1 -1
  39. package/src/sagas/createGrantRequestStatus.js +24 -8
  40. package/src/selectors/getGrantRequestsColumns.js +32 -5
  41. package/src/selectors/getGrantRequestsSearchColumns.js +20 -14
  42. package/src/selectors/utils/decorators.js +68 -0
  43. package/src/components/__tests__/__snapshots__/GrantRemoval.spec.js.snap +0 -9
@@ -8,11 +8,11 @@ import { linkTo } from "@truedat/core/routes";
8
8
  import { Date } from "@truedat/core/components";
9
9
 
10
10
  import GrantChangeRequest from "./GrantChangeRequest";
11
- import GrantRemoval from "./GrantRemoval";
12
11
  import GrantRequestCancel from "./GrantRequestCancel";
13
12
  import StructureGrantRequestAddCart from "./StructureGrantRequestAddCart";
14
13
 
15
14
  const isNilOrEmpty = (value) => _.isEmpty(value) || _.isNil(value);
15
+
16
16
  export const StructureGrantDropdown = ({
17
17
  grantRequest,
18
18
  grantRequestStatus,
@@ -54,38 +54,10 @@ export const StructureGrantDropdown = ({
54
54
  }
55
55
  icon="info"
56
56
  text={formatMessage({
57
- id: `grant.actions.view_request.confirmation.header`,
57
+ id: `grant.actions.viewRequest.confirmation.header`,
58
58
  })}
59
59
  />
60
60
  ),
61
- requestRemoval: (
62
- <GrantRemoval
63
- grant={grant}
64
- previousStructureQuery={previousStructureQuery}
65
- key="requestRemoval"
66
- >
67
- <Dropdown.Item
68
- icon="delete"
69
- text={formatMessage({
70
- id: `grant.actions.request_removal.confirmation.header`,
71
- })}
72
- />
73
- </GrantRemoval>
74
- ),
75
- cancelRemoval: (
76
- <GrantRemoval
77
- grant={grant}
78
- previousStructureQuery={previousStructureQuery}
79
- key="cancelRemoval"
80
- >
81
- <Dropdown.Item
82
- icon="delete"
83
- text={formatMessage({
84
- id: `grant.actions.cancel_removal.confirmation.header`,
85
- })}
86
- />
87
- </GrantRemoval>
88
- ),
89
61
  requestChange: (
90
62
  <GrantChangeRequest
91
63
  structure={structure}
@@ -133,14 +105,9 @@ export const StructureGrantDropdown = ({
133
105
  ? "structure.grant.modification.attended"
134
106
  : "structure.grant.access.attended",
135
107
  },
136
- pendingRemovalGrant: {
137
- color: "red",
138
- options: [actions["cancelRemoval"]],
139
- header: "structure.grant.has_grant_pending_removal",
140
- },
141
108
  activeGrant: {
142
109
  color: "green",
143
- options: [actions["requestChange"], actions["requestRemoval"]],
110
+ options: [actions["requestChange"]],
144
111
  header: "structure.grant.has_grant",
145
112
  },
146
113
  };
@@ -149,8 +116,6 @@ export const StructureGrantDropdown = ({
149
116
  ? "pendingRequest"
150
117
  : hasProcessingGrantRequest
151
118
  ? "processingRequest"
152
- : grant?.pending_removal
153
- ? "pendingRemovalGrant"
154
119
  : "activeGrant";
155
120
 
156
121
  const stateProps = dropdownStates[currentState];
@@ -173,7 +138,9 @@ export const StructureGrantDropdown = ({
173
138
 
174
139
  const popupContent = (
175
140
  <>
176
- <Header as="h6">{formatMessage({ id: stateProps.header })}</Header>
141
+ {stateProps?.header ? (
142
+ <Header as="h6">{formatMessage({ id: stateProps.header })}</Header>
143
+ ) : null}
177
144
  {grantRequest ? grantRequestDetails : grantDetails}
178
145
  </>
179
146
  );
@@ -181,7 +148,7 @@ export const StructureGrantDropdown = ({
181
148
  const optionsWithCart =
182
149
  authorized && !requested
183
150
  ? [actions["addToCart"], ...stateProps.options]
184
- : stateProps.options;
151
+ : stateProps?.options;
185
152
 
186
153
  const trigger = (
187
154
  <Dropdown
@@ -4,7 +4,7 @@ import PropTypes from "prop-types";
4
4
  import { useQuery } from "@apollo/client";
5
5
  import { connect } from "react-redux";
6
6
  import { Loading } from "@truedat/core/components";
7
- import { LATEST_GRANT_REQUEST_QUERY } from "../api/queries";
7
+ import { LATEST_GRANT_REQUEST_BY_DS_QUERY } from "../api/queries";
8
8
  import StructureGrantRequestButton from "./StructureGrantRequestButton";
9
9
  import StructureGrantDropdown from "./StructureGrantDropdown";
10
10
 
@@ -17,7 +17,7 @@ export const StructureGrantSummaryButton = ({
17
17
  }) => {
18
18
  const { grant, id } = structure;
19
19
 
20
- const { loading, error, data } = useQuery(LATEST_GRANT_REQUEST_QUERY, {
20
+ const { loading, error, data } = useQuery(LATEST_GRANT_REQUEST_BY_DS_QUERY, {
21
21
  fetchPolicy: "cache-and-network",
22
22
  variables: { id },
23
23
  });
@@ -2,35 +2,25 @@ import _ from "lodash/fp";
2
2
  import React from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { useIntl } from "react-intl";
5
- import { Table, Button } from "semantic-ui-react";
5
+ import { Table } from "semantic-ui-react";
6
6
  import { connect } from "react-redux";
7
+ import { useHistory } from "react-router-dom";
7
8
  import { columnDecorator } from "@truedat/core/services";
9
+ import { linkTo } from "@truedat/core/routes";
8
10
  import { getGrantsColumns } from "../selectors";
9
11
  import GrantRemoval from "./GrantRemoval";
10
12
 
11
- export const RemovalButton = ({ grant }) => (
12
- <GrantRemoval grant={grant}>
13
- {grant.pending_removal ? (
14
- <Button size="mini" color="olive" icon="undo" />
15
- ) : (
16
- <Button size="mini" color="red" icon="delete" />
17
- )}
18
- </GrantRemoval>
19
- );
20
-
21
- RemovalButton.propTypes = {
22
- grant: PropTypes.object,
23
- };
24
-
25
13
  const matchesStructure = ({ id }) => _.pathEq("data_structure.id", id);
26
14
 
27
15
  export const StructureGrants = ({
28
16
  columns,
29
17
  grants,
18
+ grantsActions,
30
19
  structure,
31
20
  userPermissions,
32
21
  }) => {
33
22
  const { formatMessage } = useIntl();
23
+ const history = useHistory();
34
24
  const canUpdateRemoval =
35
25
  userPermissions?.update_grant_removal &&
36
26
  _.any(matchesStructure(structure))(grants);
@@ -54,19 +44,31 @@ export const StructureGrants = ({
54
44
  </Table.Header>
55
45
  <Table.Body>
56
46
  {grants.map((grant, i) => (
57
- <Table.Row key={i}>
47
+ // Move style to file after task to create "CSS entrypoint" is done
48
+ <Table.Row key={i} style={{ cursor: "pointer" }}>
58
49
  {columns.map((column, key) => (
59
50
  <Table.Cell
60
51
  key={key}
61
52
  textAlign={column.textAlign}
62
53
  content={columnDecorator(column)(grant)}
54
+ onClick={(ev) => {
55
+ /* Only do history.push if the table cell but not
56
+ * some possibly contained anchor (or an element
57
+ * inside an anchor, such as an icon) is clicked
58
+ */
59
+ !ev.target.closest("a") && history.push(linkTo.GRANT(grant));
60
+ }}
63
61
  />
64
62
  ))}
65
63
  {canUpdateRemoval ? (
66
64
  <Table.Cell
67
65
  content={
68
66
  matchesStructure(structure)(grant) ? (
69
- <RemovalButton grant={grant} />
67
+ <GrantRemoval
68
+ grant={grant}
69
+ actions={grantsActions}
70
+ userPermissions={userPermissions}
71
+ />
70
72
  ) : null
71
73
  }
72
74
  />
@@ -80,6 +82,7 @@ export const StructureGrants = ({
80
82
 
81
83
  StructureGrants.propTypes = {
82
84
  grants: PropTypes.array,
85
+ grantsActions: PropTypes.object,
83
86
  columns: PropTypes.array,
84
87
  structure: PropTypes.object,
85
88
  userPermissions: PropTypes.object,
@@ -90,6 +93,7 @@ const mapStateToProps = (state) => ({
90
93
  structure: state.structure,
91
94
  columns: getGrantsColumns(state),
92
95
  userPermissions: state.userPermissions,
96
+ grantsActions: state?.structure?._actions?._grants,
93
97
  });
94
98
 
95
99
  export default connect(mapStateToProps)(StructureGrants);
@@ -1,6 +1,7 @@
1
1
  import React from "react";
2
2
  import userEvent from "@testing-library/user-event";
3
3
  import { render } from "@truedat/test/render";
4
+ import { waitFor } from "@testing-library/react";
4
5
  import { Grant } from "../Grant";
5
6
  import en from "../../messages/en";
6
7
 
@@ -45,7 +46,7 @@ describe("<Grant />", () => {
45
46
  },
46
47
  };
47
48
  const actions = {
48
- request_removal: {},
49
+ manage_grant_removal: {},
49
50
  };
50
51
 
51
52
  const defaultProps = {
@@ -71,25 +72,28 @@ describe("<Grant />", () => {
71
72
  expect(container).toMatchSnapshot();
72
73
  });
73
74
 
74
- it("matches the latest snapshot with cancel_removal action", () => {
75
+ it("matches the latest snapshot with manage_grant_removal action", async () => {
75
76
  const props = {
76
77
  ...defaultProps,
78
+ grant: { ...grant, pending_removal: true },
77
79
  actions: {
78
- cancel_removal: {},
80
+ manage_grant_removal: {},
79
81
  },
80
82
  };
81
- const { container } = render(<Grant {...props} />, renderOpts);
83
+ const { container, queryByText } = render(<Grant {...props} />, renderOpts);
84
+ await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
82
85
  expect(container).toMatchSnapshot();
83
86
  });
84
87
 
85
- it("matches the latest snapshot with update action", () => {
88
+ it("matches the latest snapshot with update action", async () => {
86
89
  const props = {
87
90
  ...defaultProps,
88
91
  actions: {
89
92
  update: {},
90
93
  },
91
94
  };
92
- const { container } = render(<Grant {...props} />, renderOpts);
95
+ const { container, queryByText } = render(<Grant {...props} />, renderOpts);
96
+ await waitFor(() => expect(queryByText(/lazy/i)).not.toBeInTheDocument());
93
97
  expect(container).toMatchSnapshot();
94
98
  });
95
99
 
@@ -102,7 +106,7 @@ describe("<Grant />", () => {
102
106
  userEvent.click(await findByText("yes"));
103
107
 
104
108
  expect(defaultProps.onStatusChange).toHaveBeenLastCalledWith({
105
- action: "request_removal",
109
+ action: "mark_pending_removal",
106
110
  data_structure_id: 2,
107
111
  id: 1,
108
112
  });
@@ -1,68 +1,33 @@
1
1
  import React from "react";
2
- import userEvent from "@testing-library/user-event";
3
2
  import { render } from "@truedat/test/render";
4
- import { requestGrantRemoval } from "../../routines";
5
3
  import GrantRemoval from "../GrantRemoval";
6
4
 
7
5
  describe("<GrantRemoval />", () => {
8
6
  const grant = {
9
- id: 1,
10
- detail: { foo: "bar" },
11
- data_structure: { id: 2 },
12
- data_structure_version: { id: 3 },
7
+ id: 17,
13
8
  };
14
- it("matches the latest snapshot", () => {
15
- const { container } = render(
16
- <GrantRemoval grant={grant}>
17
- <p>child</p>
18
- </GrantRemoval>
19
- );
20
- expect(container).toMatchSnapshot();
21
- });
22
-
23
- it("on click calls requestGrantRemoval routine if onConfirm si undefined", async () => {
24
- const dispatch = jest.fn();
25
- const { findByText } = render(
26
- <GrantRemoval grant={grant}>
27
- <p>child</p>
28
- </GrantRemoval>,
29
- { dispatch }
30
- );
31
-
32
- userEvent.click(await findByText("child"));
33
- expect(await findByText("Request grant removal")).toBeInTheDocument();
34
9
 
35
- userEvent.click(await findByText("Yes"));
10
+ const actions_with_request_cancel = {
11
+ manage_grant_removal: {},
12
+ };
36
13
 
37
- expect(dispatch).toHaveBeenLastCalledWith({
38
- ...requestGrantRemoval(),
39
- payload: {
40
- action: "request_removal",
41
- data_structure_id: 2,
42
- id: 1,
43
- version: 3,
44
- },
45
- });
14
+ it("Mounts grant removal/reactivation button if user has permissions, remove", () => {
15
+ const { queryByText } = render(
16
+ <GrantRemoval
17
+ grant={{ ...grant, pending_removal: false }}
18
+ actions={actions_with_request_cancel}
19
+ />
20
+ );
21
+ expect(queryByText(/Remove/)).toBeInTheDocument();
46
22
  });
47
23
 
48
- it("on click calls onConfirm prop", async () => {
49
- const onConfirm = jest.fn();
50
- const { findByText } = render(
51
- <GrantRemoval grant={grant} onConfirm={onConfirm}>
52
- <p>child</p>
53
- </GrantRemoval>
24
+ it("Mounts grant removal/reactivation button if user has permissions, reactivate", () => {
25
+ const { queryByText } = render(
26
+ <GrantRemoval
27
+ grant={{ ...grant, pending_removal: true }}
28
+ actions={actions_with_request_cancel}
29
+ />
54
30
  );
55
-
56
- userEvent.click(await findByText("child"));
57
- expect(await findByText("Request grant removal")).toBeInTheDocument();
58
-
59
- userEvent.click(await findByText("Yes"));
60
-
61
- expect(onConfirm).toHaveBeenLastCalledWith({
62
- action: "request_removal",
63
- data_structure_id: 2,
64
- id: 1,
65
- version: 3,
66
- });
31
+ expect(queryByText(/Reactivate/)).toBeInTheDocument();
67
32
  });
68
33
  });
@@ -0,0 +1,66 @@
1
+ import React from "react";
2
+ import userEvent from "@testing-library/user-event";
3
+ import { render } from "@truedat/test/render";
4
+
5
+ import GrantRemovalDirectButton from "../GrantRemovalDirectButton";
6
+
7
+ describe("<GrantRemovalDirectButton />", () => {
8
+ const grant = {
9
+ id: 1,
10
+ detail: { foo: "bar" },
11
+ data_structure: { id: 2 },
12
+ data_structure_version: { id: 3 },
13
+ };
14
+
15
+ it("on click calls requestGrantRemoval routine if onConfirm is undefined", async () => {
16
+ const requestGrantRemoval = jest.fn();
17
+ const { findByText } = render(
18
+ <GrantRemovalDirectButton
19
+ grant={grant}
20
+ operation="markPendingRemoval"
21
+ actions={{ manage_grant_removal: {} }}
22
+ requestGrantRemoval={requestGrantRemoval}
23
+ previousStructureQuery={{}}
24
+ />
25
+ );
26
+
27
+ userEvent.click(await findByText("Remove"));
28
+ expect(await findByText("Request grant removal")).toBeInTheDocument();
29
+
30
+ userEvent.click(await findByText("Yes"));
31
+
32
+ expect(requestGrantRemoval).toHaveBeenCalledWith({
33
+ action: "mark_pending_removal",
34
+ data_structure_id: 2,
35
+ id: 1,
36
+ version: 3,
37
+ previousStructureQuery: {},
38
+ });
39
+ });
40
+
41
+ it("on click calls onConfirm prop", async () => {
42
+ const onConfirm = jest.fn();
43
+ const { findByText } = render(
44
+ <GrantRemovalDirectButton
45
+ grant={grant}
46
+ operation="markPendingRemoval"
47
+ actions={{ manage_grant_removal: {} }}
48
+ onConfirm={onConfirm}
49
+ previousStructureQuery={{}}
50
+ />
51
+ );
52
+
53
+ userEvent.click(await findByText("Remove"));
54
+ expect(await findByText("Request grant removal")).toBeInTheDocument();
55
+
56
+ userEvent.click(await findByText("Yes"));
57
+
58
+ expect(onConfirm).toHaveBeenLastCalledWith({
59
+ action: "mark_pending_removal",
60
+ data_structure_id: 2,
61
+ id: 1,
62
+ version: 3,
63
+ previousStructureQuery: {},
64
+ });
65
+ });
66
+ });
@@ -0,0 +1,157 @@
1
+ import React from "react";
2
+ import { render } from "@truedat/test/render";
3
+ import { LATEST_GRANT_REQUEST_BY_GRANT_QUERY } from "@truedat/dd/api/queries";
4
+ import GrantRemovalWorkflow from "../GrantRemovalWorkflow";
5
+
6
+ describe("<GrantRemovalWorkflow />", () => {
7
+ const latestGrantRequestByGrantMock = (variables, grantRequestStatus) => {
8
+ const latestGrantRequest = !grantRequestStatus
9
+ ? null
10
+ : {
11
+ __typename: "GrantRequest",
12
+ id: 17,
13
+ group: {
14
+ __typename: "GrantRequestGroup",
15
+ grant: null,
16
+ },
17
+ requestType: "GRANT_REMOVAL",
18
+ status: {
19
+ __typename: "GrantRequestStatus",
20
+ status: grantRequestStatus,
21
+ },
22
+ };
23
+
24
+ return {
25
+ request: {
26
+ query: LATEST_GRANT_REQUEST_BY_GRANT_QUERY,
27
+ variables,
28
+ },
29
+ result: {
30
+ data: {
31
+ latestGrantRequest,
32
+ },
33
+ },
34
+ };
35
+ };
36
+
37
+ const grant = {
38
+ id: 17,
39
+ };
40
+
41
+ const latestRequestVars = { id: grant.id, requestType: "GRANT_REMOVAL" };
42
+
43
+ it("Shows workflow button at start state", async () => {
44
+ const renderOpts = {
45
+ mocks: [latestGrantRequestByGrantMock(latestRequestVars, null)],
46
+ };
47
+ const { findByRole } = render(
48
+ <GrantRemovalWorkflow
49
+ grant={{ ...grant, pending_removal: false }}
50
+ actions={{}}
51
+ />,
52
+ renderOpts
53
+ );
54
+ expect(await findByRole("button")).toHaveClass("orange");
55
+ });
56
+
57
+ it("Shows workflow button at pending state", async () => {
58
+ const renderOpts = {
59
+ mocks: [latestGrantRequestByGrantMock(latestRequestVars, "pending")],
60
+ };
61
+ const { findByRole, queryByText } = render(
62
+ <GrantRemovalWorkflow
63
+ grant={{ ...grant, pending_removal: false }}
64
+ actions={{}}
65
+ />,
66
+ renderOpts
67
+ );
68
+ const button = await findByRole("button");
69
+ expect(button).toHaveClass("yellow");
70
+ const cancelRequestOption = queryByText(/Cancel request/);
71
+ expect(cancelRequestOption).toBeInTheDocument();
72
+ });
73
+
74
+ it("Shows workflow button at rejected state", async () => {
75
+ const renderOpts = {
76
+ mocks: [latestGrantRequestByGrantMock(latestRequestVars, "rejected")],
77
+ };
78
+ const { findByRole } = render(
79
+ <GrantRemovalWorkflow
80
+ grant={{ ...grant, pending_removal: false }}
81
+ actions={{}}
82
+ />,
83
+ renderOpts
84
+ );
85
+ expect(await findByRole("button")).toHaveClass("red");
86
+ });
87
+
88
+ it("Shows workflow button at approved state", async () => {
89
+ const renderOpts = {
90
+ mocks: [latestGrantRequestByGrantMock(latestRequestVars, "approved")],
91
+ };
92
+ const { findByRole } = render(
93
+ <GrantRemovalWorkflow
94
+ grant={{ ...grant, pending_removal: true }}
95
+ actions={{}}
96
+ />,
97
+ renderOpts
98
+ );
99
+ expect(await findByRole("button")).toHaveClass("brown");
100
+ });
101
+
102
+ it("Workflow bypass: request approved, initially pending_removal true but someone with permissions set pending_removal to false", async () => {
103
+ const renderOpts = {
104
+ mocks: [latestGrantRequestByGrantMock(latestRequestVars, "approved")],
105
+ };
106
+ const { findByRole } = render(
107
+ <GrantRemovalWorkflow
108
+ grant={{ ...grant, pending_removal: false }}
109
+ actions={{}}
110
+ />,
111
+ renderOpts
112
+ );
113
+ expect(await findByRole("button")).toHaveClass("grey");
114
+ });
115
+
116
+ it("Workflow bypass: request pending, initially pending_removal to false but someone with permissions set pending_removal to true", async () => {
117
+ const renderOpts = {
118
+ mocks: [latestGrantRequestByGrantMock(latestRequestVars, "pending")],
119
+ };
120
+ const { findByRole } = render(
121
+ <GrantRemovalWorkflow
122
+ grant={{ ...grant, pending_removal: true }}
123
+ actions={{}}
124
+ />,
125
+ renderOpts
126
+ );
127
+ expect(await findByRole("button")).toHaveClass("grey");
128
+ });
129
+
130
+ it("Workflow bypass: request rejected, initially pending_removal to false but someone with permissions set pending_removal to true", async () => {
131
+ const renderOpts = {
132
+ mocks: [latestGrantRequestByGrantMock(latestRequestVars, "rejected")],
133
+ };
134
+ const { findByRole } = render(
135
+ <GrantRemovalWorkflow
136
+ grant={{ ...grant, pending_removal: true }}
137
+ actions={{}}
138
+ />,
139
+ renderOpts
140
+ );
141
+ expect(await findByRole("button")).toHaveClass("grey");
142
+ });
143
+
144
+ it("Workflow bypass: request processing, initially pending_removal to false but someone with permissions set pending_removal to true", async () => {
145
+ const renderOpts = {
146
+ mocks: [latestGrantRequestByGrantMock(latestRequestVars, "processing")],
147
+ };
148
+ const { findByRole } = render(
149
+ <GrantRemovalWorkflow
150
+ grant={{ ...grant, pending_removal: true }}
151
+ actions={{}}
152
+ />,
153
+ renderOpts
154
+ );
155
+ expect(await findByRole("button")).toHaveClass("grey");
156
+ });
157
+ });
@@ -1,6 +1,7 @@
1
1
  import React, { Suspense } from "react";
2
2
  import { render } from "@truedat/test/render";
3
3
  import { GrantRequest } from "../GrantRequest";
4
+ import en from "../../messages/en";
4
5
 
5
6
  describe("<GrantRequest />", () => {
6
7
  const grantRequest = {
@@ -67,6 +68,7 @@ describe("<GrantRequest />", () => {
67
68
  "grantRequest.summary.emptyApprovals": "empty",
68
69
  "grantRequestApproval.header": "approval header",
69
70
  "grantRequests.header": "grant requests",
71
+ "request.grantAccess": "Structure access",
70
72
  "ruleImplementation.summary.field": "field",
71
73
  "ruleImplementation.summary.operator": "operator",
72
74
  "ruleImplementation.summary.values": "values",
@@ -1,15 +1,12 @@
1
1
  import React, { Suspense } from "react";
2
2
  import { render } from "@truedat/test/render";
3
3
  import { GrantRequestHeader } from "../GrantRequestHeader";
4
+ import en from "../../messages/en";
4
5
 
5
6
  describe("<GrantRequestHeader />", () => {
6
7
  const renderOpts = {
7
8
  messages: {
8
- en: {
9
- "grantRequest.header": "header",
10
- "grantRequest.actions.approve": "approve",
11
- "grantRequest.actions.reject": "reject",
12
- },
9
+ en,
13
10
  },
14
11
  };
15
12
 
@@ -98,21 +98,6 @@ describe("<StructureGrantDropdown />", () => {
98
98
  expect(container).toMatchSnapshot();
99
99
  });
100
100
 
101
- it("matches the latest snapshot for pendingRemovalGrant state", () => {
102
- const grantRequest = null;
103
- const props = {
104
- ...propsBuilder({ pending_removal: true }),
105
- grantRequest,
106
- grantRequestStatus: null,
107
- };
108
- const { container } = render(
109
- <StructureGrantDropdown {...props} />,
110
- renderOpts
111
- );
112
-
113
- expect(container).toMatchSnapshot();
114
- });
115
-
116
101
  it("matches the latest snapshot for activeGrant state", () => {
117
102
  const grantRequest = null;
118
103
  const props = {
@@ -177,7 +162,7 @@ describe("<StructureGrantDropdown />", () => {
177
162
  );
178
163
 
179
164
  userEvent.click(
180
- await findByText(en["grant.actions.view_request.confirmation.header"])
165
+ await findByText(en["grant.actions.viewRequest.confirmation.header"])
181
166
  );
182
167
 
183
168
  expect(mockHistory.push).toHaveBeenCalledWith("/grantRequests/8");
@@ -1,17 +1,18 @@
1
1
  import React from "react";
2
2
  import { waitFor } from "@testing-library/react";
3
3
  import { render } from "@truedat/test/render";
4
- import { LATEST_GRANT_REQUEST_QUERY } from "../../api/queries";
4
+ import { LATEST_GRANT_REQUEST_BY_DS_QUERY } from "../../api/queries";
5
5
  import StructureGrantSummaryButton from "../StructureGrantSummaryButton";
6
6
  import en from "../../messages/en";
7
7
 
8
8
  const latestGrantMockBuilder = (status) => ({
9
- request: { query: LATEST_GRANT_REQUEST_QUERY },
9
+ request: { query: LATEST_GRANT_REQUEST_BY_DS_QUERY },
10
10
  result: {
11
11
  data: {
12
12
  latestGrantRequest: status
13
13
  ? {
14
14
  id: 1,
15
+ requestType: "ACCESS",
15
16
  group: {
16
17
  grant: {
17
18
  id: 1,