@truedat/dd 8.12.2 → 8.12.5
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 +3 -3
- package/src/api/__tests__/queries.spec.js +55 -0
- package/src/api/queries.js +31 -0
- package/src/components/Grant.js +106 -16
- package/src/components/GrantRequest.js +2 -2
- package/src/components/GrantRequestBulkApprovalPopup.js +0 -1
- package/src/components/GrantsDownloadButton.js +9 -1
- package/src/components/GrantsTable.js +4 -1
- package/src/components/StructureFields.js +7 -4
- package/src/components/StructureGrantCartUserSelector.js +29 -4
- package/src/components/StructureGrantDropdown.js +7 -1
- package/src/components/StructureGrants.js +4 -1
- package/src/components/StructureNoteActions.js +10 -1
- package/src/components/StructureNotes.js +42 -6
- package/src/components/StructureNotesEdit.js +38 -8
- package/src/components/StructuresUpdateOption.js +2 -2
- package/src/components/SystemStructures.js +3 -3
- package/src/components/__tests__/CatalogViewConfigForm.spec.js +2 -0
- package/src/components/__tests__/EditDomainForm.spec.js +3 -1
- package/src/components/__tests__/Grant.spec.js +171 -0
- package/src/components/__tests__/GrantApprovalRuleForm.spec.js +2 -0
- package/src/components/__tests__/GrantApprovalRuleNew.spec.js +8 -0
- package/src/components/__tests__/GrantApprovalRules.spec.js +4 -0
- package/src/components/__tests__/GrantRequest.spec.js +4 -4
- package/src/components/__tests__/GrantRequestBulkActions.spec.js +1 -4
- package/src/components/__tests__/GrantRequestsSearchResults.spec.js +2 -0
- package/src/components/__tests__/GrantsDownloadButton.spec.js +58 -2
- package/src/components/__tests__/GrantsTable.spec.js +22 -2
- package/src/components/__tests__/LineageDefs.spec.js +6 -1
- package/src/components/__tests__/LineageForm.spec.js +1 -0
- package/src/components/__tests__/LineageGraphToolbar.spec.js +19 -17
- package/src/components/__tests__/LineageInspectorPanel.spec.js +17 -9
- package/src/components/__tests__/ProfileGroup.spec.js +7 -1
- package/src/components/__tests__/ReferenceDatasetForm.spec.js +2 -0
- package/src/components/__tests__/ReferenceDatasetRoutes.spec.js +9 -0
- package/src/components/__tests__/StructureGrantCartCheckout.spec.js +39 -1
- package/src/components/__tests__/StructureGrantCartInformation.spec.js +5 -2
- package/src/components/__tests__/StructureGrantCartUserSelector.spec.js +128 -0
- package/src/components/__tests__/StructureGrantDropdown.spec.js +92 -0
- package/src/components/__tests__/StructureGrantListButton.spec.js +70 -0
- package/src/components/__tests__/StructureGrantSummaryButton.spec.js +36 -1
- package/src/components/__tests__/StructureGrants.spec.js +12 -0
- package/src/components/__tests__/StructureNoteActions.spec.js +96 -0
- package/src/components/__tests__/StructureNotes.spec.js +170 -1
- package/src/components/__tests__/StructureNotesEdit.spec.js +185 -1
- package/src/components/__tests__/StructureRelationRow.spec.js +72 -4
- package/src/components/__tests__/StructureRelations.spec.js +18 -0
- package/src/components/__tests__/StructureRoles.spec.js +9 -0
- package/src/components/__tests__/StructureRow.spec.js +13 -4
- package/src/components/__tests__/StructureSelector.spec.js +2 -0
- package/src/components/__tests__/StructureTag.spec.js +2 -0
- package/src/components/__tests__/StructureTagForm.spec.js +2 -0
- package/src/components/__tests__/StructureType.spec.js +3 -1
- package/src/components/__tests__/StructureTypeForm.spec.js +3 -1
- package/src/components/__tests__/StructureView.spec.js +17 -1
- package/src/components/__tests__/StructuresGrantRequestView.spec.js +2 -0
- package/src/components/__tests__/StructuresView.spec.js +2 -1
- package/src/components/__tests__/Tag.spec.js +4 -1
- package/src/components/__tests__/Tags.spec.js +7 -1
- package/src/components/__tests__/__snapshots__/GrantsTable.spec.js.snap +34 -2
- package/src/components/__tests__/__snapshots__/LineageDefs.spec.js.snap +32 -30
- package/src/components/__tests__/__snapshots__/StructureFields.spec.js.snap +1 -16
- package/src/components/__tests__/__snapshots__/StructureNoteActions.spec.js.snap +2 -1
- package/src/components/__tests__/__snapshots__/StructureNotesEdit.spec.js.snap +3 -0
- package/src/components/__tests__/__snapshots__/StructureRelationRow.spec.js.snap +23 -19
- package/src/components/__tests__/__snapshots__/StructureRow.spec.js.snap +28 -24
- package/src/components/__tests__/__snapshots__/StructuresUpdateOption.spec.js.snap +7 -3
- package/src/messages/en.js +2 -2
- package/src/messages/es.js +2 -2
- package/src/reducers/__tests__/ddMessage.spec.js +48 -0
- package/src/reducers/__tests__/grantRequestsCart.spec.js +17 -0
- package/src/reducers/__tests__/structureRedirect.spec.js +22 -0
- package/src/reducers/__tests__/structureRelations.spec.js +28 -0
- package/src/reducers/ddMessage.js +32 -0
- package/src/reducers/grantRequestsCart.js +3 -0
- package/src/reducers/structureRedirect.js +7 -2
- package/src/selectors/__tests__/__snapshots__/getGrantsColumns.spec.js.snap +1 -9
- package/src/selectors/__tests__/getGrantRequestsSearchColumns.spec.js +11 -4
- package/src/selectors/__tests__/getGrantsColumns.spec.js +295 -0
- package/src/selectors/__tests__/messages.spec.js +14 -0
- package/src/selectors/getBusinessConceptsLinksToStructuresColumnsSelector.js +3 -5
- package/src/selectors/getGrantRequestsSearchColumns.js +3 -5
- package/src/selectors/getGrantsColumns.js +85 -11
- package/src/selectors/getLinkedImplementationsToStructuresColumns.js +3 -7
- package/src/selectors/getStructureFieldColumns.js +7 -6
- package/src/selectors/getStructureProperties.js +2 -5
- package/src/selectors/getStructuresUploadEventColumns.js +2 -7
- package/src/selectors/messages.js +30 -0
- package/src/selectors/structureColumnsSelector.js +13 -16
- package/src/utils/__tests__/structureNoteActions.spec.js +196 -0
- package/src/utils/structureNoteActions.js +22 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/dd",
|
|
3
|
-
"version": "8.12.
|
|
3
|
+
"version": "8.12.5",
|
|
4
4
|
"description": "Truedat Web Data Dictionary",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"@testing-library/jest-dom": "^6.6.3",
|
|
55
55
|
"@testing-library/react": "^16.3.0",
|
|
56
56
|
"@testing-library/user-event": "^14.6.1",
|
|
57
|
-
"@truedat/test": "8.12.
|
|
57
|
+
"@truedat/test": "8.12.5",
|
|
58
58
|
"identity-obj-proxy": "^3.0.0",
|
|
59
59
|
"jest": "^29.7.0",
|
|
60
60
|
"redux-saga-test-plan": "^4.0.6"
|
|
@@ -90,5 +90,5 @@
|
|
|
90
90
|
"svg-pan-zoom": "^3.6.2",
|
|
91
91
|
"swr": "^2.3.3"
|
|
92
92
|
},
|
|
93
|
-
"gitHead": "
|
|
93
|
+
"gitHead": "71dd08262e6c26dd25466154c49fadb7b3449bd7"
|
|
94
94
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { LEGACY_DATA_STRUCTURE_VERSION_QUERY, buildDSVQuery } from "../queries";
|
|
2
|
+
|
|
3
|
+
const PARENT_PATH = ["dataStructureVersion", "relations", "parents"];
|
|
4
|
+
const CHILD_PATH = ["dataStructureVersion", "relations", "children"];
|
|
5
|
+
|
|
6
|
+
const fieldAtPath = (document, path) =>
|
|
7
|
+
path.reduce((node, name) => {
|
|
8
|
+
const selection = node.selectionSet?.selections.find(
|
|
9
|
+
(s) => s.kind === "Field" && s.name.value === name,
|
|
10
|
+
);
|
|
11
|
+
if (!selection) {
|
|
12
|
+
throw new Error(`Missing field ${path.join(".")}`);
|
|
13
|
+
}
|
|
14
|
+
return selection;
|
|
15
|
+
}, document.definitions[0]);
|
|
16
|
+
|
|
17
|
+
const selectionNames = (field) =>
|
|
18
|
+
field.selectionSet.selections
|
|
19
|
+
.filter((s) => s.kind === "Field")
|
|
20
|
+
.map((s) => s.name.value);
|
|
21
|
+
|
|
22
|
+
const linksField = (field) =>
|
|
23
|
+
field.selectionSet.selections.find(
|
|
24
|
+
(s) => s.kind === "Field" && s.name.value === "links",
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
const expectRelationLinks = (document) => {
|
|
28
|
+
const parents = fieldAtPath(document, PARENT_PATH);
|
|
29
|
+
const children = fieldAtPath(document, CHILD_PATH);
|
|
30
|
+
|
|
31
|
+
expect(selectionNames(parents)).toEqual(expect.arrayContaining(["links"]));
|
|
32
|
+
expect(selectionNames(children)).toEqual(expect.arrayContaining(["links"]));
|
|
33
|
+
|
|
34
|
+
const resourceType = linksField(parents).arguments.find(
|
|
35
|
+
(argument) => argument.name.value === "resource_type",
|
|
36
|
+
);
|
|
37
|
+
expect(resourceType.value.value).toBe("business_concept");
|
|
38
|
+
expect(linksField(children).arguments).toEqual([]);
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
describe("LEGACY_DATA_STRUCTURE_VERSION_QUERY", () => {
|
|
42
|
+
it("requests concept links on parent and child structure relations", () => {
|
|
43
|
+
expectRelationLinks(LEGACY_DATA_STRUCTURE_VERSION_QUERY);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("buildDSVQuery", () => {
|
|
48
|
+
it("requests concept links on parent and child structure relations", () => {
|
|
49
|
+
expectRelationLinks(buildDSVQuery(false));
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it("requests concept links on parent and child structure relations when loading metadata", () => {
|
|
53
|
+
expectRelationLinks(buildDSVQuery(true));
|
|
54
|
+
});
|
|
55
|
+
});
|
package/src/api/queries.js
CHANGED
|
@@ -360,6 +360,13 @@ export const LEGACY_DATA_STRUCTURE_VERSION_QUERY = gql`
|
|
|
360
360
|
user_name
|
|
361
361
|
}
|
|
362
362
|
user_id
|
|
363
|
+
user_group_id
|
|
364
|
+
source_group_name
|
|
365
|
+
user_group {
|
|
366
|
+
id
|
|
367
|
+
name
|
|
368
|
+
alias
|
|
369
|
+
}
|
|
363
370
|
}
|
|
364
371
|
grant @skip(if: $withoutGrants) {
|
|
365
372
|
data_structure {
|
|
@@ -391,6 +398,13 @@ export const LEGACY_DATA_STRUCTURE_VERSION_QUERY = gql`
|
|
|
391
398
|
user_name
|
|
392
399
|
}
|
|
393
400
|
user_id
|
|
401
|
+
user_group_id
|
|
402
|
+
source_group_name
|
|
403
|
+
user_group {
|
|
404
|
+
id
|
|
405
|
+
name
|
|
406
|
+
alias
|
|
407
|
+
}
|
|
394
408
|
}
|
|
395
409
|
|
|
396
410
|
classes
|
|
@@ -467,6 +481,7 @@ export const LEGACY_DATA_STRUCTURE_VERSION_QUERY = gql`
|
|
|
467
481
|
name
|
|
468
482
|
description
|
|
469
483
|
}
|
|
484
|
+
links(resource_type: "business_concept")
|
|
470
485
|
}
|
|
471
486
|
children {
|
|
472
487
|
id
|
|
@@ -599,6 +614,13 @@ export const buildDSVQuery = (loadStructureMetadata) => gql`
|
|
|
599
614
|
user_name
|
|
600
615
|
}
|
|
601
616
|
user_id
|
|
617
|
+
user_group_id
|
|
618
|
+
source_group_name
|
|
619
|
+
user_group {
|
|
620
|
+
id
|
|
621
|
+
name
|
|
622
|
+
alias
|
|
623
|
+
}
|
|
602
624
|
}
|
|
603
625
|
|
|
604
626
|
classes
|
|
@@ -651,6 +673,7 @@ export const buildDSVQuery = (loadStructureMetadata) => gql`
|
|
|
651
673
|
name
|
|
652
674
|
description
|
|
653
675
|
}
|
|
676
|
+
links(resource_type: "business_concept")
|
|
654
677
|
}
|
|
655
678
|
children {
|
|
656
679
|
id
|
|
@@ -736,6 +759,14 @@ export const DATA_STRUCTURE_VERSION_GRANTS_QUERY = gql`
|
|
|
736
759
|
user_name
|
|
737
760
|
}
|
|
738
761
|
user_id
|
|
762
|
+
user_group_id
|
|
763
|
+
current_user_group_member
|
|
764
|
+
source_group_name
|
|
765
|
+
user_group {
|
|
766
|
+
id
|
|
767
|
+
name
|
|
768
|
+
alias
|
|
769
|
+
}
|
|
739
770
|
}
|
|
740
771
|
}
|
|
741
772
|
}
|
package/src/components/Grant.js
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
|
-
import { lazy } from "react";
|
|
2
|
+
import { lazy, useState } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import Moment from "react-moment";
|
|
5
5
|
import { useIntl } from "react-intl";
|
|
6
6
|
import { Link } from "react-router";
|
|
7
7
|
import { useParams } from "react-router";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
Accordion,
|
|
10
|
+
Grid,
|
|
11
|
+
Segment,
|
|
12
|
+
Header,
|
|
13
|
+
Icon,
|
|
14
|
+
Label,
|
|
15
|
+
List,
|
|
16
|
+
Button,
|
|
17
|
+
Table,
|
|
18
|
+
} from "semantic-ui-react";
|
|
9
19
|
import { linkTo } from "@truedat/core/routes";
|
|
10
20
|
import { useGrant, useGrantRemoval, useStructure } from "../hooks/useGrant";
|
|
11
21
|
import GrantCrumbs from "./GrantCrumbs";
|
|
@@ -110,8 +120,16 @@ GrantHeader.propTypes = {
|
|
|
110
120
|
onStatusChange: PropTypes.func,
|
|
111
121
|
};
|
|
112
122
|
|
|
123
|
+
const groupDisplayName = (userGroup) =>
|
|
124
|
+
userGroup
|
|
125
|
+
? _.isEmpty(userGroup.alias)
|
|
126
|
+
? userGroup.name
|
|
127
|
+
: userGroup.alias
|
|
128
|
+
: undefined;
|
|
129
|
+
|
|
113
130
|
export const Grant = ({ grant, actions, loading, onStatusChange }) => {
|
|
114
131
|
const { formatMessage } = useIntl();
|
|
132
|
+
const [membersOpen, setMembersOpen] = useState(false);
|
|
115
133
|
|
|
116
134
|
const data_structure_version = _.pathOr(
|
|
117
135
|
undefined,
|
|
@@ -119,10 +137,37 @@ export const Grant = ({ grant, actions, loading, onStatusChange }) => {
|
|
|
119
137
|
)(grant);
|
|
120
138
|
const data_structure = _.pathOr(undefined, "data_structure")(grant);
|
|
121
139
|
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
140
|
+
const userGroup = grant?.user_group;
|
|
141
|
+
const userGroupId = grant?.user_group_id;
|
|
142
|
+
const user = grant?.user;
|
|
143
|
+
const userId = grant?.user_id;
|
|
144
|
+
const sourceGroupName = grant?.source_group_name;
|
|
145
|
+
const userGroupText = groupDisplayName(userGroup);
|
|
146
|
+
const hasUsableUser = user && !_.isEmpty(user.full_name);
|
|
147
|
+
const isGroup = Boolean(userGroup || userGroupId || sourceGroupName);
|
|
148
|
+
const grantFor = isGroup
|
|
149
|
+
? userGroupText ||
|
|
150
|
+
(userGroupId ? formatMessage({ id: "deleted.group" }) : sourceGroupName)
|
|
151
|
+
: hasUsableUser
|
|
152
|
+
? user.full_name
|
|
153
|
+
: userId
|
|
154
|
+
? formatMessage({ id: "deleted.user" })
|
|
155
|
+
: undefined;
|
|
156
|
+
const members = _.isArray(userGroup?.users) ? userGroup.users : [];
|
|
157
|
+
|
|
158
|
+
const getTitle = ({
|
|
159
|
+
user,
|
|
160
|
+
user_group,
|
|
161
|
+
source_group_name,
|
|
162
|
+
data_structure_version,
|
|
163
|
+
} = grant) => {
|
|
164
|
+
const groupText = groupDisplayName(user_group) || source_group_name;
|
|
165
|
+
const who = user?.user_name
|
|
166
|
+
? `(${user.user_name})`
|
|
167
|
+
: groupText
|
|
168
|
+
? `(${groupText})`
|
|
169
|
+
: "";
|
|
170
|
+
return `${who} -> ${data_structure_version?.name}`;
|
|
126
171
|
};
|
|
127
172
|
const path = _.flow(
|
|
128
173
|
_.map("name"),
|
|
@@ -161,20 +206,65 @@ export const Grant = ({ grant, actions, loading, onStatusChange }) => {
|
|
|
161
206
|
</List.Content>
|
|
162
207
|
</List.Item>
|
|
163
208
|
)}
|
|
164
|
-
{
|
|
209
|
+
{grantFor && (
|
|
165
210
|
<List.Item>
|
|
166
211
|
<List.Header>
|
|
167
|
-
{formatMessage({
|
|
212
|
+
{formatMessage({
|
|
213
|
+
id: isGroup
|
|
214
|
+
? "grant.header.group"
|
|
215
|
+
: "grant.header.user",
|
|
216
|
+
})}
|
|
168
217
|
</List.Header>
|
|
169
218
|
<List.Description>
|
|
170
|
-
|
|
171
|
-
<
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
{
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
219
|
+
{userGroup ? (
|
|
220
|
+
<Accordion>
|
|
221
|
+
<Accordion.Title
|
|
222
|
+
active={membersOpen}
|
|
223
|
+
icon={false}
|
|
224
|
+
onClick={() => setMembersOpen(!membersOpen)}
|
|
225
|
+
>
|
|
226
|
+
<Label>{grantFor}</Label>
|
|
227
|
+
<Icon
|
|
228
|
+
name={
|
|
229
|
+
membersOpen ? "angle down" : "angle right"
|
|
230
|
+
}
|
|
231
|
+
/>
|
|
232
|
+
</Accordion.Title>
|
|
233
|
+
<Accordion.Content active={membersOpen}>
|
|
234
|
+
<Table compact collapsing size="small">
|
|
235
|
+
<Table.Header>
|
|
236
|
+
<Table.Row>
|
|
237
|
+
<Table.HeaderCell>
|
|
238
|
+
{formatMessage({
|
|
239
|
+
id: "grantRequests.props.user_full_name",
|
|
240
|
+
})}
|
|
241
|
+
</Table.HeaderCell>
|
|
242
|
+
</Table.Row>
|
|
243
|
+
</Table.Header>
|
|
244
|
+
<Table.Body>
|
|
245
|
+
{members.map((member) => (
|
|
246
|
+
<Table.Row
|
|
247
|
+
key={member.id ?? member.user_name}
|
|
248
|
+
>
|
|
249
|
+
<Table.Cell>
|
|
250
|
+
{member.full_name}
|
|
251
|
+
</Table.Cell>
|
|
252
|
+
</Table.Row>
|
|
253
|
+
))}
|
|
254
|
+
</Table.Body>
|
|
255
|
+
</Table>
|
|
256
|
+
</Accordion.Content>
|
|
257
|
+
</Accordion>
|
|
258
|
+
) : hasUsableUser ? (
|
|
259
|
+
<Header as="h4">
|
|
260
|
+
<Header.Content>
|
|
261
|
+
{user.full_name}
|
|
262
|
+
<Header.Subheader>{user.email}</Header.Subheader>
|
|
263
|
+
</Header.Content>
|
|
264
|
+
</Header>
|
|
265
|
+
) : (
|
|
266
|
+
<Label>{grantFor}</Label>
|
|
267
|
+
)}
|
|
178
268
|
</List.Description>
|
|
179
269
|
</List.Item>
|
|
180
270
|
)}
|
|
@@ -51,9 +51,9 @@ export const GrantRequest = ({ grantRequest, template }) => {
|
|
|
51
51
|
user ||
|
|
52
52
|
userGroupText ||
|
|
53
53
|
(userGroupId
|
|
54
|
-
? formatMessage({ id: "
|
|
54
|
+
? formatMessage({ id: "deleted.group" })
|
|
55
55
|
: group
|
|
56
|
-
? formatMessage({ id: "
|
|
56
|
+
? formatMessage({ id: "deleted.user" })
|
|
57
57
|
: undefined);
|
|
58
58
|
const members = _.isArray(userGroup?.users) ? userGroup.users : [];
|
|
59
59
|
const createdBy =
|
|
@@ -40,7 +40,15 @@ export const GrantsDownloadButton = ({
|
|
|
40
40
|
const grants = searchData?.data;
|
|
41
41
|
|
|
42
42
|
const headerLabels = _.flow(
|
|
43
|
-
_.map((l) => [
|
|
43
|
+
_.map((l) => [
|
|
44
|
+
l,
|
|
45
|
+
formatMessage({
|
|
46
|
+
id:
|
|
47
|
+
l === "user_name"
|
|
48
|
+
? "grants.props.user_or_group"
|
|
49
|
+
: `grants.props.${l}`,
|
|
50
|
+
}),
|
|
51
|
+
]),
|
|
44
52
|
_.fromPairs,
|
|
45
53
|
)(staticLabels);
|
|
46
54
|
|
|
@@ -48,7 +48,10 @@ export const GrantsTable = ({ columns, setDownloading }) => {
|
|
|
48
48
|
key={i}
|
|
49
49
|
width={column.width}
|
|
50
50
|
content={formatMessage({
|
|
51
|
-
id:
|
|
51
|
+
id:
|
|
52
|
+
column.name === "user"
|
|
53
|
+
? "grants.props.user_or_group"
|
|
54
|
+
: `grant.header.${column.name}`,
|
|
52
55
|
defaultMessage: column.name,
|
|
53
56
|
})}
|
|
54
57
|
sorted={
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
|
-
import { useState } from "react";
|
|
2
|
+
import { useMemo, useState } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import queryString from "query-string";
|
|
5
5
|
import { useLocation } from "react-router";
|
|
@@ -32,6 +32,7 @@ const getColumns = (columns, fields) =>
|
|
|
32
32
|
_.filter((c) => _.any(columnPred(c))(fields))(columns);
|
|
33
33
|
|
|
34
34
|
const PAGE_SIZE = 50;
|
|
35
|
+
const EMPTY_FIELDS = [];
|
|
35
36
|
|
|
36
37
|
const ProfileActions = ({
|
|
37
38
|
emptyFields,
|
|
@@ -151,13 +152,15 @@ export const StructureFields = ({
|
|
|
151
152
|
: { after, before, first: PAGE_SIZE, search: q };
|
|
152
153
|
const variables = { ...structureVariables, ...searchVariables };
|
|
153
154
|
const { data, loading } = useQuery(DATA_FIELDS_QUERY, { variables });
|
|
154
|
-
const fields = data?.dataFields?.page ||
|
|
155
|
+
const fields = data?.dataFields?.page || EMPTY_FIELDS;
|
|
155
156
|
const pageInfo = data?.dataFields?.pageInfo || {};
|
|
156
157
|
const pageStructureIds = _.map("data_structure_id")(fields);
|
|
157
158
|
const emptyFields = _.isEmpty(fields);
|
|
158
159
|
|
|
159
|
-
const
|
|
160
|
-
|
|
160
|
+
const structureFieldColumns = useSelector(getStructureFieldColumns);
|
|
161
|
+
const columns = useMemo(
|
|
162
|
+
() => getColumns(structureFieldColumns, fields),
|
|
163
|
+
[structureFieldColumns, fields],
|
|
161
164
|
);
|
|
162
165
|
|
|
163
166
|
const allCheckedInPage = _.every((structureId) =>
|
|
@@ -11,6 +11,23 @@ import { useRoles } from "@truedat/auth/hooks/useRoles";
|
|
|
11
11
|
import { useGrantRequestableUsers } from "@truedat/auth/hooks/useUsers";
|
|
12
12
|
import { updateGrantRequestUser } from "../routines";
|
|
13
13
|
|
|
14
|
+
const groupDisplayName = (userGroup) =>
|
|
15
|
+
userGroup
|
|
16
|
+
? _.isEmpty(userGroup.alias)
|
|
17
|
+
? userGroup.name
|
|
18
|
+
: userGroup.alias
|
|
19
|
+
: undefined;
|
|
20
|
+
|
|
21
|
+
const modificationBeneficiary = (grant, formatMessage) => {
|
|
22
|
+
const groupName = groupDisplayName(grant?.user_group);
|
|
23
|
+
if (!_.isEmpty(groupName)) return groupName;
|
|
24
|
+
if (!_.isNil(grant?.user_group_id)) {
|
|
25
|
+
return formatMessage({ id: "deleted.group" });
|
|
26
|
+
}
|
|
27
|
+
if (grant?.source_group_name) return grant.source_group_name;
|
|
28
|
+
return grant?.user?.full_name ?? "";
|
|
29
|
+
};
|
|
30
|
+
|
|
14
31
|
export const StructureGrantCartUserSelector = ({
|
|
15
32
|
grantRequestsCart,
|
|
16
33
|
updateGrantRequestUser,
|
|
@@ -59,6 +76,8 @@ export const StructureGrantCartUserSelector = ({
|
|
|
59
76
|
useEffect(() => {
|
|
60
77
|
if (!_.isNil(modificationGrant?.user_id)) {
|
|
61
78
|
selectUser(modificationGrant?.user_id);
|
|
79
|
+
} else if (!_.isNil(modificationGrant?.user_group_id)) {
|
|
80
|
+
selectUser(`group:${modificationGrant.user_group_id}`);
|
|
62
81
|
} else if (!_.isNil(grantRequestsCart?.user?.id) && !_.isEmpty(options)) {
|
|
63
82
|
_.flow(
|
|
64
83
|
_.find({ value: userId }),
|
|
@@ -66,7 +85,12 @@ export const StructureGrantCartUserSelector = ({
|
|
|
66
85
|
selectUser,
|
|
67
86
|
)(options);
|
|
68
87
|
}
|
|
69
|
-
}, [
|
|
88
|
+
}, [
|
|
89
|
+
grantRequestsCart?.user?.id,
|
|
90
|
+
modificationGrant?.user_id,
|
|
91
|
+
modificationGrant?.user_group_id,
|
|
92
|
+
options,
|
|
93
|
+
]);
|
|
70
94
|
|
|
71
95
|
useEffect(() => {
|
|
72
96
|
const valid =
|
|
@@ -178,9 +202,10 @@ export const StructureGrantCartUserSelector = ({
|
|
|
178
202
|
|
|
179
203
|
return updateGrant ? (
|
|
180
204
|
<Header as="h4">
|
|
181
|
-
<Header.Content>{`${formatMessage({ id: "grantRequestCart.user.label" })} ${
|
|
182
|
-
modificationGrant
|
|
183
|
-
|
|
205
|
+
<Header.Content>{`${formatMessage({ id: "grantRequestCart.user.label" })} ${modificationBeneficiary(
|
|
206
|
+
modificationGrant,
|
|
207
|
+
formatMessage,
|
|
208
|
+
)}`}</Header.Content>
|
|
184
209
|
</Header>
|
|
185
210
|
) : (
|
|
186
211
|
<>
|
|
@@ -37,6 +37,12 @@ export const StructureGrantDropdown = ({
|
|
|
37
37
|
grantRequest?._embedded?.group?.userGroupId ??
|
|
38
38
|
grantRequest?._embedded?.group?._embedded?.user_group,
|
|
39
39
|
);
|
|
40
|
+
const isGroupGrant = !_.isNil(
|
|
41
|
+
grant?.user_group_id ??
|
|
42
|
+
grant?.userGroupId ??
|
|
43
|
+
grant?.user_group ??
|
|
44
|
+
grant?.userGroup,
|
|
45
|
+
);
|
|
40
46
|
const createdBy =
|
|
41
47
|
grantRequest?.group?._embedded?.created_by?.user_name ??
|
|
42
48
|
grantRequest?.group?.createdBy?.userName ??
|
|
@@ -167,11 +173,11 @@ export const StructureGrantDropdown = ({
|
|
|
167
173
|
{stateProps?.header ? (
|
|
168
174
|
<Header as="h6">
|
|
169
175
|
<Header.Content>
|
|
176
|
+
{isGroupRequest || isGroupGrant ? <Icon name="users" /> : null}
|
|
170
177
|
{formatMessage({ id: stateProps.header })}
|
|
171
178
|
</Header.Content>
|
|
172
179
|
</Header>
|
|
173
180
|
) : null}
|
|
174
|
-
{isGroupRequest ? <Icon name="users" /> : null}
|
|
175
181
|
{grantRequest ? grantRequestDetails : grantDetails}
|
|
176
182
|
</>
|
|
177
183
|
);
|
|
@@ -33,7 +33,10 @@ const StructureGrantsContent = ({
|
|
|
33
33
|
key={i}
|
|
34
34
|
textAlign={column.textAlign}
|
|
35
35
|
content={formatMessage({
|
|
36
|
-
id:
|
|
36
|
+
id:
|
|
37
|
+
column.name === "user"
|
|
38
|
+
? "grants.props.user_or_group"
|
|
39
|
+
: `grant.header.${column.name}`,
|
|
37
40
|
defaultMessage: column.name,
|
|
38
41
|
})}
|
|
39
42
|
/>
|
|
@@ -7,6 +7,7 @@ import { FormattedMessage } from "react-intl";
|
|
|
7
7
|
import { ConfirmModal, GroupActions } from "@truedat/core/components";
|
|
8
8
|
import { linkTo } from "@truedat/core/routes";
|
|
9
9
|
import { doStructureNoteAction } from "../routines";
|
|
10
|
+
import { canPerformAction } from "../utils/structureNoteActions";
|
|
10
11
|
|
|
11
12
|
const ModalDelete = ({
|
|
12
13
|
className,
|
|
@@ -67,6 +68,8 @@ export const StructureNoteActions = ({
|
|
|
67
68
|
doStructureNoteAction,
|
|
68
69
|
actions,
|
|
69
70
|
structure,
|
|
71
|
+
template,
|
|
72
|
+
content,
|
|
70
73
|
}) => {
|
|
71
74
|
const actionToIcon = {
|
|
72
75
|
deleted: "trash alternate outline",
|
|
@@ -88,6 +91,7 @@ export const StructureNoteActions = ({
|
|
|
88
91
|
_.toPairs,
|
|
89
92
|
_.reject(([action, _data]) => !_.get(action)(actionToIcon)),
|
|
90
93
|
_.map(([action, data]) => {
|
|
94
|
+
const allowed = canPerformAction(action, content, template);
|
|
91
95
|
const baseAction = {
|
|
92
96
|
key: action,
|
|
93
97
|
icon: _.get(action)(actionToIcon),
|
|
@@ -100,8 +104,11 @@ export const StructureNoteActions = ({
|
|
|
100
104
|
),
|
|
101
105
|
as: actionToAs(action),
|
|
102
106
|
to: actionToTo(action),
|
|
107
|
+
className: "td-structure-note-action",
|
|
108
|
+
disabled: !allowed,
|
|
109
|
+
...(!allowed ? { style: { opacity: 0.45 } } : {}),
|
|
103
110
|
onClick:
|
|
104
|
-
action === "edited" || withModal(action)
|
|
111
|
+
action === "edited" || withModal(action) || !allowed
|
|
105
112
|
? undefined
|
|
106
113
|
: () =>
|
|
107
114
|
doStructureNoteAction({
|
|
@@ -135,6 +142,8 @@ StructureNoteActions.propTypes = {
|
|
|
135
142
|
doStructureNoteAction: PropTypes.func,
|
|
136
143
|
actions: PropTypes.object.isRequired,
|
|
137
144
|
structure: PropTypes.object.isRequired,
|
|
145
|
+
template: PropTypes.object,
|
|
146
|
+
content: PropTypes.object,
|
|
138
147
|
};
|
|
139
148
|
|
|
140
149
|
export default connect(null, { doStructureNoteAction })(StructureNoteActions);
|
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import _ from "lodash/fp";
|
|
2
2
|
import { lazy, useState } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
|
-
import {
|
|
4
|
+
import { FormattedMessage, useIntl } from "react-intl";
|
|
5
5
|
import Moment from "react-moment";
|
|
6
6
|
import { connect } from "react-redux";
|
|
7
7
|
import { Link } from "react-router";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
Button,
|
|
10
|
+
Segment,
|
|
11
|
+
Message,
|
|
12
|
+
Loader,
|
|
13
|
+
Label,
|
|
14
|
+
Icon,
|
|
15
|
+
} from "semantic-ui-react";
|
|
9
16
|
import { linkTo } from "@truedat/core/routes";
|
|
10
17
|
import {
|
|
11
18
|
getActiveStructureNotes,
|
|
12
19
|
getVersionedStructureNotes,
|
|
13
20
|
} from "../selectors/getSortedStructureNotes";
|
|
21
|
+
import { getMissingMandatoryFields } from "../utils/structureNoteActions";
|
|
14
22
|
|
|
15
23
|
import StructureNoteActions from "./StructureNoteActions";
|
|
16
24
|
|
|
@@ -27,6 +35,10 @@ const StructureNote = ({ structureNote, template, structure, notesSize }) => {
|
|
|
27
35
|
structureNote?.status !== "published" ||
|
|
28
36
|
!_.isEmpty(actions) ||
|
|
29
37
|
notesSize > 1;
|
|
38
|
+
const noteContent =
|
|
39
|
+
structureNote?.dynamic_content || structureNote?.df_content || {};
|
|
40
|
+
const missingFields = getMissingMandatoryFields(noteContent, template);
|
|
41
|
+
const showMissingLabel = !_.isEmpty(missingFields);
|
|
30
42
|
return (
|
|
31
43
|
<Segment>
|
|
32
44
|
<div
|
|
@@ -59,6 +71,21 @@ const StructureNote = ({ structureNote, template, structure, notesSize }) => {
|
|
|
59
71
|
/>
|
|
60
72
|
</Label>
|
|
61
73
|
)}
|
|
74
|
+
{showMissingLabel && (
|
|
75
|
+
<Label
|
|
76
|
+
basic
|
|
77
|
+
color="orange"
|
|
78
|
+
size="tiny"
|
|
79
|
+
className="td-missing-mandatory-label"
|
|
80
|
+
>
|
|
81
|
+
<Icon name="warning sign" />
|
|
82
|
+
<FormattedMessage
|
|
83
|
+
id="structure.notes.actions.missing_mandatory"
|
|
84
|
+
defaultMessage="Missing required fields: {fields}"
|
|
85
|
+
values={{ fields: missingFields.join(", ") }}
|
|
86
|
+
/>
|
|
87
|
+
</Label>
|
|
88
|
+
)}
|
|
62
89
|
</>
|
|
63
90
|
)}
|
|
64
91
|
</div>
|
|
@@ -70,7 +97,12 @@ const StructureNote = ({ structureNote, template, structure, notesSize }) => {
|
|
|
70
97
|
/>
|
|
71
98
|
</Button>
|
|
72
99
|
)}
|
|
73
|
-
<StructureNoteActions
|
|
100
|
+
<StructureNoteActions
|
|
101
|
+
actions={actions}
|
|
102
|
+
structure={structure}
|
|
103
|
+
template={template}
|
|
104
|
+
content={noteContent}
|
|
105
|
+
/>
|
|
74
106
|
</div>
|
|
75
107
|
</div>
|
|
76
108
|
{!collapsed && (
|
|
@@ -99,6 +131,7 @@ export const StructureNotes = ({
|
|
|
99
131
|
template,
|
|
100
132
|
}) => {
|
|
101
133
|
const { formatMessage } = useIntl();
|
|
134
|
+
|
|
102
135
|
const [isShowingVersioned, setShowingVersioned] = useState(false);
|
|
103
136
|
const notesSize = _.size(activeStructureNotes);
|
|
104
137
|
|
|
@@ -163,6 +196,11 @@ StructureNotes.propTypes = {
|
|
|
163
196
|
template: PropTypes.object,
|
|
164
197
|
};
|
|
165
198
|
|
|
199
|
+
export const findTemplate = ({
|
|
200
|
+
templates,
|
|
201
|
+
structure: { structure_type } = {},
|
|
202
|
+
}) => _.find(_.propEq("id", _.prop("template_id")(structure_type)))(templates);
|
|
203
|
+
|
|
166
204
|
const mapStateToProps = (state) => {
|
|
167
205
|
const { templates, structure, structureNotes } = state;
|
|
168
206
|
return {
|
|
@@ -170,9 +208,7 @@ const mapStateToProps = (state) => {
|
|
|
170
208
|
versionedStructureNotes: getVersionedStructureNotes(state),
|
|
171
209
|
structureNotes,
|
|
172
210
|
structure,
|
|
173
|
-
template:
|
|
174
|
-
_.propEq("id", _.path("structure_type.template_id")(structure)),
|
|
175
|
-
)(templates),
|
|
211
|
+
template: findTemplate({ templates, structure }),
|
|
176
212
|
};
|
|
177
213
|
};
|
|
178
214
|
|