@truedat/dd 8.12.2 → 8.12.4

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 (75) hide show
  1. package/package.json +3 -3
  2. package/src/api/__tests__/queries.spec.js +55 -0
  3. package/src/api/queries.js +31 -0
  4. package/src/components/Grant.js +106 -16
  5. package/src/components/GrantRequest.js +2 -2
  6. package/src/components/GrantRequestBulkApprovalPopup.js +0 -1
  7. package/src/components/GrantsDownloadButton.js +9 -1
  8. package/src/components/GrantsTable.js +4 -1
  9. package/src/components/StructureFields.js +7 -4
  10. package/src/components/StructureGrantCartUserSelector.js +29 -4
  11. package/src/components/StructureGrantDropdown.js +7 -1
  12. package/src/components/StructureGrants.js +4 -1
  13. package/src/components/StructuresUpdateOption.js +2 -2
  14. package/src/components/SystemStructures.js +3 -3
  15. package/src/components/__tests__/CatalogViewConfigForm.spec.js +2 -0
  16. package/src/components/__tests__/EditDomainForm.spec.js +3 -1
  17. package/src/components/__tests__/Grant.spec.js +171 -0
  18. package/src/components/__tests__/GrantApprovalRuleForm.spec.js +2 -0
  19. package/src/components/__tests__/GrantApprovalRuleNew.spec.js +8 -0
  20. package/src/components/__tests__/GrantApprovalRules.spec.js +4 -0
  21. package/src/components/__tests__/GrantRequest.spec.js +4 -4
  22. package/src/components/__tests__/GrantRequestBulkActions.spec.js +1 -4
  23. package/src/components/__tests__/GrantRequestsSearchResults.spec.js +2 -0
  24. package/src/components/__tests__/GrantsDownloadButton.spec.js +58 -2
  25. package/src/components/__tests__/GrantsTable.spec.js +22 -2
  26. package/src/components/__tests__/LineageDefs.spec.js +6 -1
  27. package/src/components/__tests__/LineageForm.spec.js +1 -0
  28. package/src/components/__tests__/LineageGraphToolbar.spec.js +19 -17
  29. package/src/components/__tests__/LineageInspectorPanel.spec.js +17 -9
  30. package/src/components/__tests__/ProfileGroup.spec.js +7 -1
  31. package/src/components/__tests__/ReferenceDatasetForm.spec.js +2 -0
  32. package/src/components/__tests__/ReferenceDatasetRoutes.spec.js +9 -0
  33. package/src/components/__tests__/StructureGrantCartCheckout.spec.js +39 -1
  34. package/src/components/__tests__/StructureGrantCartInformation.spec.js +5 -2
  35. package/src/components/__tests__/StructureGrantCartUserSelector.spec.js +128 -0
  36. package/src/components/__tests__/StructureGrantDropdown.spec.js +92 -0
  37. package/src/components/__tests__/StructureGrantListButton.spec.js +70 -0
  38. package/src/components/__tests__/StructureGrantSummaryButton.spec.js +36 -1
  39. package/src/components/__tests__/StructureGrants.spec.js +12 -0
  40. package/src/components/__tests__/StructureRelationRow.spec.js +72 -4
  41. package/src/components/__tests__/StructureRelations.spec.js +18 -0
  42. package/src/components/__tests__/StructureRoles.spec.js +9 -0
  43. package/src/components/__tests__/StructureRow.spec.js +13 -4
  44. package/src/components/__tests__/StructureSelector.spec.js +2 -0
  45. package/src/components/__tests__/StructureTag.spec.js +2 -0
  46. package/src/components/__tests__/StructureTagForm.spec.js +2 -0
  47. package/src/components/__tests__/StructureType.spec.js +3 -1
  48. package/src/components/__tests__/StructureTypeForm.spec.js +3 -1
  49. package/src/components/__tests__/StructureView.spec.js +17 -1
  50. package/src/components/__tests__/StructuresGrantRequestView.spec.js +2 -0
  51. package/src/components/__tests__/StructuresView.spec.js +2 -1
  52. package/src/components/__tests__/Tag.spec.js +4 -1
  53. package/src/components/__tests__/Tags.spec.js +7 -1
  54. package/src/components/__tests__/__snapshots__/GrantsTable.spec.js.snap +34 -2
  55. package/src/components/__tests__/__snapshots__/LineageDefs.spec.js.snap +32 -30
  56. package/src/components/__tests__/__snapshots__/StructureFields.spec.js.snap +1 -16
  57. package/src/components/__tests__/__snapshots__/StructureRelationRow.spec.js.snap +23 -19
  58. package/src/components/__tests__/__snapshots__/StructureRow.spec.js.snap +28 -24
  59. package/src/components/__tests__/__snapshots__/StructuresUpdateOption.spec.js.snap +7 -3
  60. package/src/messages/en.js +2 -2
  61. package/src/messages/es.js +2 -2
  62. package/src/reducers/__tests__/grantRequestsCart.spec.js +17 -0
  63. package/src/reducers/__tests__/structureRelations.spec.js +28 -0
  64. package/src/reducers/grantRequestsCart.js +3 -0
  65. package/src/selectors/__tests__/__snapshots__/getGrantsColumns.spec.js.snap +1 -9
  66. package/src/selectors/__tests__/getGrantRequestsSearchColumns.spec.js +11 -4
  67. package/src/selectors/__tests__/getGrantsColumns.spec.js +295 -0
  68. package/src/selectors/getBusinessConceptsLinksToStructuresColumnsSelector.js +3 -5
  69. package/src/selectors/getGrantRequestsSearchColumns.js +3 -5
  70. package/src/selectors/getGrantsColumns.js +85 -11
  71. package/src/selectors/getLinkedImplementationsToStructuresColumns.js +3 -7
  72. package/src/selectors/getStructureFieldColumns.js +7 -6
  73. package/src/selectors/getStructureProperties.js +2 -5
  74. package/src/selectors/getStructuresUploadEventColumns.js +2 -7
  75. package/src/selectors/structureColumnsSelector.js +13 -16
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/dd",
3
- "version": "8.12.2",
3
+ "version": "8.12.4",
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.2",
57
+ "@truedat/test": "8.12.4",
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": "b0000f1b2727cad43ce3c3eb2fa29681488dd2ec"
93
+ "gitHead": "d5bc1af84c4d828bdec676b0da58385cf0d6015f"
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
+ });
@@ -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
  }
@@ -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 { Grid, Segment, Header, Icon, List, Button } from "semantic-ui-react";
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 getTitle = ({ user, data_structure_version } = grant) => {
123
- return `${user?.user_name ? `(${user?.user_name})` : ""} -> ${
124
- data_structure_version?.name
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
- {grant?.user && (
209
+ {grantFor && (
165
210
  <List.Item>
166
211
  <List.Header>
167
- {formatMessage({ id: "grant.header.user" })}
212
+ {formatMessage({
213
+ id: isGroup
214
+ ? "grant.header.group"
215
+ : "grant.header.user",
216
+ })}
168
217
  </List.Header>
169
218
  <List.Description>
170
- <Header as="h4">
171
- <Header.Content>
172
- {grant?.user?.full_name}
173
- <Header.Subheader>
174
- {grant?.user?.email}
175
- </Header.Subheader>
176
- </Header.Content>
177
- </Header>
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: "grantRequest.deleted.group" })
54
+ ? formatMessage({ id: "deleted.group" })
55
55
  : group
56
- ? formatMessage({ id: "grantRequest.deleted.user" })
56
+ ? formatMessage({ id: "deleted.user" })
57
57
  : undefined);
58
58
  const members = _.isArray(userGroup?.users) ? userGroup.users : [];
59
59
  const createdBy =
@@ -21,7 +21,6 @@ export const GrantRequestBulkApprovalPopup = ({
21
21
  return (
22
22
  <Popup
23
23
  on="click"
24
- modal
25
24
  onClose={() => setOpen(false)}
26
25
  onOpen={() => setOpen(true)}
27
26
  open={open}
@@ -40,7 +40,15 @@ export const GrantsDownloadButton = ({
40
40
  const grants = searchData?.data;
41
41
 
42
42
  const headerLabels = _.flow(
43
- _.map((l) => [l, formatMessage({ id: `grants.props.${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: `grant.header.${column.name}`,
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 columns = useSelector((state) =>
160
- getColumns(getStructureFieldColumns(state), fields),
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
- }, [grantRequestsCart?.user?.id, modificationGrant?.user_id, options]);
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.user?.full_name
183
- }`}</Header.Content>
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: `grant.header.${column.name}`,
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
  />
@@ -84,7 +84,7 @@ export const StructuresUpdateOption = ({
84
84
  onClick={navigateToBulkUpdate}
85
85
  disabled={disabled}
86
86
  content={
87
- <>
87
+ <div>
88
88
  <span>
89
89
  {formatMessage({ id: "structures.actions.bulk_update" })}
90
90
  </span>
@@ -93,7 +93,7 @@ export const StructuresUpdateOption = ({
93
93
  {formatMessage({ id: "structures.actions.bulk_update.popup" })}
94
94
  </p>
95
95
  )}
96
- </>
96
+ </div>
97
97
  }
98
98
  />
99
99
  )
@@ -1,4 +1,3 @@
1
- import _ from "lodash/fp";
2
1
  import { useEffect } from "react";
3
2
  import { useSelector, useDispatch } from "react-redux";
4
3
  import { Grid, Segment } from "semantic-ui-react";
@@ -13,8 +12,9 @@ export default function SystemStructures() {
13
12
  const { id: systemId } = useParams();
14
13
  const dispatch = useDispatch();
15
14
 
16
- const { navFilter, systemStructuresLoading } = useSelector(
17
- _.pick(["navFilter", "systemStructuresLoading"]),
15
+ const navFilter = useSelector((state) => state.navFilter);
16
+ const systemStructuresLoading = useSelector(
17
+ (state) => state.systemStructuresLoading,
18
18
  );
19
19
  const system = useSelector((state) => getSystem(state, systemId));
20
20
 
@@ -29,6 +29,8 @@ jest.mock("react-router", () => ({
29
29
  }));
30
30
 
31
31
  describe("<CatalogViewConfigFormLoader />", () => {
32
+ beforeEach(() => jest.useRealTimers());
33
+
32
34
  it("Saves the configuration", async () => {
33
35
  const dispatch = jest.fn();
34
36
  const rendered = render(<CatalogViewConfigFormLoader />, {
@@ -4,7 +4,9 @@ import { render, waitForLoad } from "@truedat/test/render";
4
4
  import { domainsMock } from "@truedat/test/mocks";
5
5
  import { EditDomainForm } from "../EditDomainForm";
6
6
 
7
- const mocks = [domainsMock({ action: "manageStructuresDomain" })];
7
+ const mocks = Array.from({ length: 3 }, () =>
8
+ domainsMock({ action: "manageStructuresDomain" }),
9
+ );
8
10
 
9
11
  describe("<EditDomainForm />", () => {
10
12
  const updateStructure = jest.fn();