@truedat/dd 5.18.3 → 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.
- package/package.json +5 -5
- package/src/api/queries.js +19 -1
- package/src/components/Grant.js +9 -27
- package/src/components/GrantRemoval.js +26 -34
- package/src/components/GrantRemovalDirectButton.js +89 -0
- package/src/components/GrantRemovalWorkflow.js +107 -0
- package/src/components/GrantRemovalWorkflowDropdown.js +144 -0
- package/src/components/GrantRequest.js +2 -1
- package/src/components/GrantRequestCancel.js +5 -2
- package/src/components/GrantRequestHeader.js +13 -7
- package/src/components/GrantRequestRow.js +8 -1
- package/src/components/GrantRequests.js +8 -3
- package/src/components/GrantRequestsTable.js +1 -1
- package/src/components/StructureGrantDropdown.js +7 -40
- package/src/components/StructureGrantSummaryButton.js +2 -2
- package/src/components/StructureGrants.js +21 -17
- package/src/components/StructureNoteActions.js +1 -0
- package/src/components/StructureNoteSuggestions.js +179 -0
- package/src/components/StructureNotesEdit.js +19 -2
- package/src/components/__tests__/Grant.spec.js +11 -7
- package/src/components/__tests__/GrantRemoval.spec.js +19 -54
- package/src/components/__tests__/GrantRemovalDirectButton.spec.js +66 -0
- package/src/components/__tests__/GrantRemovalWorkflow.spec.js +157 -0
- package/src/components/__tests__/GrantRequest.spec.js +2 -0
- package/src/components/__tests__/GrantRequestHeader.spec.js +2 -5
- package/src/components/__tests__/StructureGrantDropdown.spec.js +1 -16
- package/src/components/__tests__/StructureGrantSummaryButton.spec.js +3 -2
- package/src/components/__tests__/StructureGrants.spec.js +5 -1
- package/src/components/__tests__/StructureNoteSuggestions.spec.js +151 -0
- package/src/components/__tests__/StructureNotesEdit.spec.js +34 -0
- package/src/components/__tests__/__snapshots__/Grant.spec.js.snap +5 -4
- package/src/components/__tests__/__snapshots__/GrantRequest.spec.js.snap +3 -3
- package/src/components/__tests__/__snapshots__/GrantRequestHeader.spec.js.snap +4 -4
- package/src/components/__tests__/__snapshots__/GrantRequestsSearchResults.spec.js.snap +1 -1
- package/src/components/__tests__/__snapshots__/StructureGrantDropdown.spec.js.snap +0 -52
- package/src/components/__tests__/__snapshots__/StructureGrantListButton.spec.js.snap +0 -14
- package/src/components/__tests__/__snapshots__/StructureGrantSummaryButton.spec.js.snap +0 -14
- package/src/components/__tests__/__snapshots__/StructureGrants.spec.js.snap +4 -5
- package/src/components/__tests__/__snapshots__/StructureNoteSuggestions.spec.js.snap +316 -0
- package/src/components/__tests__/__snapshots__/StructureNotesEdit.spec.js.snap +49 -0
- package/src/hooks/useGrantRequest.js +10 -1
- package/src/messages/en.js +23 -8
- package/src/messages/es.js +26 -9
- package/src/reducers/structure.js +1 -0
- package/src/sagas/__tests__/createGrantRequestStatus.spec.js +1 -1
- package/src/sagas/createGrantRequestStatus.js +24 -8
- package/src/selectors/getGrantRequestsColumns.js +32 -5
- package/src/selectors/getGrantRequestsSearchColumns.js +20 -14
- package/src/selectors/utils/decorators.js +68 -0
- 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.
|
|
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"]
|
|
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
|
-
|
|
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
|
|
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 {
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
-
<
|
|
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);
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import _ from "lodash/fp";
|
|
2
|
+
import React, { useState } from "react";
|
|
3
|
+
import PropTypes from "prop-types";
|
|
4
|
+
import {
|
|
5
|
+
Button,
|
|
6
|
+
Checkbox,
|
|
7
|
+
Container,
|
|
8
|
+
Divider,
|
|
9
|
+
Icon,
|
|
10
|
+
List,
|
|
11
|
+
Message,
|
|
12
|
+
Segment,
|
|
13
|
+
} from "semantic-ui-react";
|
|
14
|
+
import { FormattedMessage, useIntl } from "react-intl";
|
|
15
|
+
import { apiJson } from "@truedat/core/services/api";
|
|
16
|
+
|
|
17
|
+
export default function StructureNoteSuggestions({
|
|
18
|
+
aiSuggestionsAction,
|
|
19
|
+
applySuggestions,
|
|
20
|
+
template,
|
|
21
|
+
isModification,
|
|
22
|
+
}) {
|
|
23
|
+
const [loadingSuggestion, setLoadingSuggestion] = useState();
|
|
24
|
+
const [suggestions, setSuggestions] = useState();
|
|
25
|
+
const [suggestionsError, setSuggestionsError] = useState();
|
|
26
|
+
const [selectedSuggestions, setSelectedSuggestions] = useState([]);
|
|
27
|
+
|
|
28
|
+
const { locale } = useIntl();
|
|
29
|
+
|
|
30
|
+
const suggestionKeys = _.keys(suggestions);
|
|
31
|
+
const fieldInSuggestions = ({ name }) => _.includes(name)(suggestionKeys);
|
|
32
|
+
const templateFields = _.flow(
|
|
33
|
+
_.prop("content"),
|
|
34
|
+
_.filter(({ fields }) => _.any(fieldInSuggestions)(fields)),
|
|
35
|
+
_.map(({ name, fields }) => ({
|
|
36
|
+
name,
|
|
37
|
+
fields: _.filter(fieldInSuggestions)(fields),
|
|
38
|
+
}))
|
|
39
|
+
)(template);
|
|
40
|
+
const validFields = _.flow(
|
|
41
|
+
_.prop("content"),
|
|
42
|
+
_.flatMap(({ fields }) =>
|
|
43
|
+
_.flow(
|
|
44
|
+
_.filter(({ editable }) => editable || !isModification),
|
|
45
|
+
_.map(({ name }) => name)
|
|
46
|
+
)(fields)
|
|
47
|
+
)
|
|
48
|
+
)(template);
|
|
49
|
+
|
|
50
|
+
const handleRequestSuggestions = () => {
|
|
51
|
+
setLoadingSuggestion(true);
|
|
52
|
+
setSuggestionsError(null);
|
|
53
|
+
setSelectedSuggestions([]);
|
|
54
|
+
setSuggestions(null);
|
|
55
|
+
const url = `${aiSuggestionsAction.href}?language=${locale}`;
|
|
56
|
+
apiJson(url).then(({ data: { data: suggestions } }) => {
|
|
57
|
+
if (_.prop("[0]")(suggestions) === "error") {
|
|
58
|
+
setSuggestionsError(
|
|
59
|
+
_.prop("[1].error.message")(suggestions) || _.prop("[1]")(suggestions)
|
|
60
|
+
);
|
|
61
|
+
} else {
|
|
62
|
+
setSuggestions(suggestions);
|
|
63
|
+
const selectedFields = _.flow(
|
|
64
|
+
_.keys,
|
|
65
|
+
_.filter(
|
|
66
|
+
(key) =>
|
|
67
|
+
_.includes(key)(validFields) && !_.isEmpty(suggestions[key])
|
|
68
|
+
)
|
|
69
|
+
)(suggestions);
|
|
70
|
+
setSelectedSuggestions(selectedFields);
|
|
71
|
+
}
|
|
72
|
+
setLoadingSuggestion(false);
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
const handleApplySuggestions = () => {
|
|
76
|
+
applySuggestions(_.pick(selectedSuggestions)(suggestions));
|
|
77
|
+
setSelectedSuggestions([]);
|
|
78
|
+
setSuggestions(null);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const toggleSelectedSuggestion = (name) => {
|
|
82
|
+
setSelectedSuggestions(
|
|
83
|
+
_.includes(name)(selectedSuggestions)
|
|
84
|
+
? _.reject((v) => v == name)(selectedSuggestions)
|
|
85
|
+
: [...selectedSuggestions, name]
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
return (
|
|
90
|
+
<Segment loading={loadingSuggestion}>
|
|
91
|
+
<Container style={{ display: "flex", justifyContent: "space-between" }}>
|
|
92
|
+
<h4>
|
|
93
|
+
{suggestions ? (
|
|
94
|
+
<Icon name="lightbulb outline" />
|
|
95
|
+
) : (
|
|
96
|
+
<Icon name="lightbulb" />
|
|
97
|
+
)}
|
|
98
|
+
<FormattedMessage id="structure_note.ai_suggestion.header" />
|
|
99
|
+
</h4>
|
|
100
|
+
<Divider hidden />
|
|
101
|
+
{suggestions ? null : (
|
|
102
|
+
<Button onClick={handleRequestSuggestions}>
|
|
103
|
+
<FormattedMessage id="actions.ai_suggestion" />
|
|
104
|
+
</Button>
|
|
105
|
+
)}
|
|
106
|
+
</Container>
|
|
107
|
+
{suggestionsError ? (
|
|
108
|
+
<Message negative>
|
|
109
|
+
<Message.Header>
|
|
110
|
+
<FormattedMessage id="structure_note.ai_suggestion.error" />
|
|
111
|
+
</Message.Header>
|
|
112
|
+
<p>{suggestionsError}</p>
|
|
113
|
+
</Message>
|
|
114
|
+
) : null}
|
|
115
|
+
{suggestions ? (
|
|
116
|
+
<>
|
|
117
|
+
{_.map(({ name: groupName, fields }) => (
|
|
118
|
+
<Container key={`group-${groupName}`}>
|
|
119
|
+
<>
|
|
120
|
+
<h5>{groupName ? groupName : ""}</h5>
|
|
121
|
+
<List>
|
|
122
|
+
{_.map(({ name, label, editable }) => (
|
|
123
|
+
<List.Item
|
|
124
|
+
key={name}
|
|
125
|
+
style={{
|
|
126
|
+
display: "flex",
|
|
127
|
+
alignItems: "center",
|
|
128
|
+
gap: "12px",
|
|
129
|
+
}}
|
|
130
|
+
>
|
|
131
|
+
<Checkbox
|
|
132
|
+
id={name}
|
|
133
|
+
disabled={
|
|
134
|
+
(isModification && !editable) ||
|
|
135
|
+
_.isEmpty(suggestions[name])
|
|
136
|
+
}
|
|
137
|
+
checked={_.includes(name)(selectedSuggestions)}
|
|
138
|
+
onChange={() => toggleSelectedSuggestion(name)}
|
|
139
|
+
/>
|
|
140
|
+
<label
|
|
141
|
+
htmlFor={name}
|
|
142
|
+
style={{ cursor: "pointer" }}
|
|
143
|
+
disabled
|
|
144
|
+
>
|
|
145
|
+
<List.Header>{label}</List.Header>
|
|
146
|
+
<List.Description>
|
|
147
|
+
{_.isEmpty(suggestions[name])
|
|
148
|
+
? "-"
|
|
149
|
+
: suggestions[name]}
|
|
150
|
+
</List.Description>
|
|
151
|
+
</label>
|
|
152
|
+
</List.Item>
|
|
153
|
+
))(fields)}
|
|
154
|
+
</List>
|
|
155
|
+
<Divider hidden />
|
|
156
|
+
</>
|
|
157
|
+
</Container>
|
|
158
|
+
))(templateFields)}
|
|
159
|
+
<Container textAlign="right">
|
|
160
|
+
<Button
|
|
161
|
+
primary
|
|
162
|
+
onClick={handleApplySuggestions}
|
|
163
|
+
disabled={_.isEmpty(selectedSuggestions)}
|
|
164
|
+
>
|
|
165
|
+
<FormattedMessage id="actions.apply_ai_suggestion" />
|
|
166
|
+
</Button>
|
|
167
|
+
</Container>
|
|
168
|
+
</>
|
|
169
|
+
) : null}
|
|
170
|
+
</Segment>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
StructureNoteSuggestions.propTypes = {
|
|
175
|
+
aiSuggestionsAction: PropTypes.object,
|
|
176
|
+
applySuggestions: PropTypes.func,
|
|
177
|
+
template: PropTypes.object,
|
|
178
|
+
isModification: PropTypes.bool,
|
|
179
|
+
};
|
|
@@ -9,6 +9,7 @@ import { selectTemplate, selectDomains } from "@truedat/df/routines";
|
|
|
9
9
|
import { applyTemplate, validateContent } from "@truedat/df/utils";
|
|
10
10
|
import { doStructureNoteAction } from "../routines";
|
|
11
11
|
import { getLatestDfContent } from "../selectors/getSortedStructureNotes";
|
|
12
|
+
import StructureNoteSuggestions from "./StructureNoteSuggestions";
|
|
12
13
|
|
|
13
14
|
const DynamicForm = React.lazy(() =>
|
|
14
15
|
import("@truedat/df/components/DynamicForm")
|
|
@@ -29,6 +30,9 @@ export const StructureNotesEdit = ({
|
|
|
29
30
|
latestDfContent,
|
|
30
31
|
}) => {
|
|
31
32
|
const [content, setContent] = useState(latestDfContent);
|
|
33
|
+
const aiSuggestionsAction = _.prop("_actions.ai_suggestions")(structureNotes);
|
|
34
|
+
|
|
35
|
+
const isModification = !_.isEmpty(latestDfContent);
|
|
32
36
|
|
|
33
37
|
useEffect(() => {
|
|
34
38
|
selectDomains(structure.domain_ids);
|
|
@@ -41,7 +45,7 @@ export const StructureNotesEdit = ({
|
|
|
41
45
|
}
|
|
42
46
|
}, [applyTemplate, template, latestDfContent, structure.domain_id]);
|
|
43
47
|
|
|
44
|
-
const { formatMessage } = useIntl();
|
|
48
|
+
const { formatMessage, locale } = useIntl();
|
|
45
49
|
|
|
46
50
|
const submitDisabled =
|
|
47
51
|
!template || _.size(validateContent(template)(content)) > 0;
|
|
@@ -67,14 +71,27 @@ export const StructureNotesEdit = ({
|
|
|
67
71
|
doStructureNoteAction(payload);
|
|
68
72
|
};
|
|
69
73
|
|
|
74
|
+
const applySuggestions = (suggestions) => {
|
|
75
|
+
setContent({ ...content, ...suggestions });
|
|
76
|
+
};
|
|
77
|
+
|
|
70
78
|
return (
|
|
71
79
|
<Segment attached="bottom">
|
|
72
80
|
<TemplateLoader />
|
|
81
|
+
|
|
82
|
+
{aiSuggestionsAction ? (
|
|
83
|
+
<StructureNoteSuggestions
|
|
84
|
+
aiSuggestionsAction={aiSuggestionsAction}
|
|
85
|
+
template={template}
|
|
86
|
+
applySuggestions={applySuggestions}
|
|
87
|
+
isModification={isModification}
|
|
88
|
+
/>
|
|
89
|
+
) : null}
|
|
73
90
|
<Form>
|
|
74
91
|
<DynamicForm
|
|
75
92
|
onChange={setContent}
|
|
76
93
|
content={content}
|
|
77
|
-
isModification={
|
|
94
|
+
isModification={isModification}
|
|
78
95
|
/>
|
|
79
96
|
<Button
|
|
80
97
|
primary
|
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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: "
|
|
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:
|
|
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
|
-
|
|
10
|
+
const actions_with_request_cancel = {
|
|
11
|
+
manage_grant_removal: {},
|
|
12
|
+
};
|
|
36
13
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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("
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
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
|
+
});
|