@truedat/dd 8.12.1 → 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 (82) 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/GrantRequestTemplateForm.js +76 -0
  8. package/src/components/GrantsDownloadButton.js +9 -1
  9. package/src/components/GrantsTable.js +4 -1
  10. package/src/components/StructureFields.js +7 -4
  11. package/src/components/StructureGrantCartCheckout.js +122 -59
  12. package/src/components/StructureGrantCartInformation.js +38 -9
  13. package/src/components/StructureGrantCartUserSelector.js +29 -4
  14. package/src/components/StructureGrantDropdown.js +7 -1
  15. package/src/components/StructureGrants.js +4 -1
  16. package/src/components/StructuresUpdateOption.js +2 -2
  17. package/src/components/SystemStructures.js +3 -3
  18. package/src/components/__tests__/CatalogViewConfigForm.spec.js +2 -0
  19. package/src/components/__tests__/EditDomainForm.spec.js +3 -1
  20. package/src/components/__tests__/Grant.spec.js +171 -0
  21. package/src/components/__tests__/GrantApprovalRuleForm.spec.js +2 -0
  22. package/src/components/__tests__/GrantApprovalRuleNew.spec.js +8 -0
  23. package/src/components/__tests__/GrantApprovalRules.spec.js +4 -0
  24. package/src/components/__tests__/GrantRequest.spec.js +4 -4
  25. package/src/components/__tests__/GrantRequestBulkActions.spec.js +1 -4
  26. package/src/components/__tests__/GrantRequestsSearchResults.spec.js +2 -0
  27. package/src/components/__tests__/GrantsDownloadButton.spec.js +58 -2
  28. package/src/components/__tests__/GrantsTable.spec.js +22 -2
  29. package/src/components/__tests__/LineageDefs.spec.js +6 -1
  30. package/src/components/__tests__/LineageForm.spec.js +1 -0
  31. package/src/components/__tests__/LineageGraphToolbar.spec.js +19 -17
  32. package/src/components/__tests__/LineageInspectorPanel.spec.js +17 -9
  33. package/src/components/__tests__/ProfileGroup.spec.js +7 -1
  34. package/src/components/__tests__/ReferenceDatasetForm.spec.js +2 -0
  35. package/src/components/__tests__/ReferenceDatasetRoutes.spec.js +9 -0
  36. package/src/components/__tests__/StructureGrantCartCheckout.grouping.spec.js +95 -0
  37. package/src/components/__tests__/StructureGrantCartCheckout.selection.spec.js +416 -0
  38. package/src/components/__tests__/StructureGrantCartCheckout.spec.js +216 -4
  39. package/src/components/__tests__/StructureGrantCartInformation.spec.js +5 -2
  40. package/src/components/__tests__/StructureGrantCartUserSelector.spec.js +128 -0
  41. package/src/components/__tests__/StructureGrantDropdown.spec.js +92 -0
  42. package/src/components/__tests__/StructureGrantListButton.spec.js +70 -0
  43. package/src/components/__tests__/StructureGrantSummaryButton.spec.js +36 -1
  44. package/src/components/__tests__/StructureGrants.spec.js +12 -0
  45. package/src/components/__tests__/StructureRelationRow.spec.js +72 -4
  46. package/src/components/__tests__/StructureRelations.spec.js +18 -0
  47. package/src/components/__tests__/StructureRoles.spec.js +9 -0
  48. package/src/components/__tests__/StructureRow.spec.js +13 -4
  49. package/src/components/__tests__/StructureSelector.spec.js +2 -0
  50. package/src/components/__tests__/StructureTag.spec.js +2 -0
  51. package/src/components/__tests__/StructureTagForm.spec.js +2 -0
  52. package/src/components/__tests__/StructureType.spec.js +3 -1
  53. package/src/components/__tests__/StructureTypeForm.spec.js +3 -1
  54. package/src/components/__tests__/StructureView.spec.js +17 -1
  55. package/src/components/__tests__/StructuresGrantRequestView.spec.js +2 -0
  56. package/src/components/__tests__/StructuresView.spec.js +2 -1
  57. package/src/components/__tests__/Tag.spec.js +4 -1
  58. package/src/components/__tests__/Tags.spec.js +7 -1
  59. package/src/components/__tests__/__snapshots__/GrantsTable.spec.js.snap +34 -2
  60. package/src/components/__tests__/__snapshots__/LineageDefs.spec.js.snap +32 -30
  61. package/src/components/__tests__/__snapshots__/StructureFields.spec.js.snap +1 -16
  62. package/src/components/__tests__/__snapshots__/StructureGrantCartCheckout.spec.js.snap +217 -1
  63. package/src/components/__tests__/__snapshots__/StructureGrantCartInformation.spec.js.snap +54 -0
  64. package/src/components/__tests__/__snapshots__/StructureRelationRow.spec.js.snap +23 -19
  65. package/src/components/__tests__/__snapshots__/StructureRow.spec.js.snap +28 -24
  66. package/src/components/__tests__/__snapshots__/StructuresUpdateOption.spec.js.snap +7 -3
  67. package/src/messages/en.js +2 -2
  68. package/src/messages/es.js +2 -2
  69. package/src/reducers/__tests__/grantRequestsCart.spec.js +86 -0
  70. package/src/reducers/__tests__/structureRelations.spec.js +28 -0
  71. package/src/reducers/grantRequestsCart.js +20 -2
  72. package/src/selectors/__tests__/__snapshots__/getGrantsColumns.spec.js.snap +1 -9
  73. package/src/selectors/__tests__/getGrantRequestsSearchColumns.spec.js +11 -4
  74. package/src/selectors/__tests__/getGrantsColumns.spec.js +295 -0
  75. package/src/selectors/getBusinessConceptsLinksToStructuresColumnsSelector.js +3 -5
  76. package/src/selectors/getGrantRequestsSearchColumns.js +3 -5
  77. package/src/selectors/getGrantsColumns.js +85 -11
  78. package/src/selectors/getLinkedImplementationsToStructuresColumns.js +3 -7
  79. package/src/selectors/getStructureFieldColumns.js +7 -6
  80. package/src/selectors/getStructureProperties.js +2 -5
  81. package/src/selectors/getStructuresUploadEventColumns.js +2 -7
  82. package/src/selectors/structureColumnsSelector.js +13 -16
@@ -1,12 +1,11 @@
1
1
  import _ from "lodash/fp";
2
2
  import PropTypes from "prop-types";
3
- import { useEffect, useMemo, Suspense } from "react";
3
+ import { useEffect, useMemo, Suspense, lazy } from "react";
4
4
  import { Header, Segment, Grid, Button, GridColumn } from "semantic-ui-react";
5
5
  import { bindActionCreators } from "redux";
6
6
  import { connect, useDispatch } from "react-redux";
7
7
  import { HistoryBackButton } from "@truedat/core/components";
8
8
  import { useIntl, FormattedMessage } from "react-intl";
9
- import { lazy } from "react";
10
9
  import { useWebContext } from "@truedat/core/webContext";
11
10
  import { useTemplateRelations } from "@truedat/df/hooks/useTemplateRelations";
12
11
  import {
@@ -21,9 +20,8 @@ import { useTemplatesByIds } from "../hooks/useTemplatesByIds";
21
20
  import StructureGrantCart from "./StructureGrantCart";
22
21
  import StructureGrantCartInformation from "./StructureGrantCartInformation";
23
22
  import StructureGrantCartUserSelector from "./StructureGrantCartUserSelector";
24
-
25
- const SelectableDynamicForm = lazy(
26
- () => import("@truedat/df/components/SelectableDynamicForm"),
23
+ const GrantRequestTemplateForm = lazy(
24
+ () => import("./GrantRequestTemplateForm"),
27
25
  );
28
26
 
29
27
  const getUniqueDomainIds = (structures) =>
@@ -32,7 +30,7 @@ const getUniqueDomainIds = (structures) =>
32
30
  const getUniqueSystemName = (structures) =>
33
31
  _.flow(_.map("system.name"), _.flatten, _.compact, _.uniq)(structures ?? []);
34
32
 
35
- const getGroupedStructuresByDomainAndTemplate = (
33
+ export const getGroupedStructuresByDomainAndTemplate = (
36
34
  structures,
37
35
  templateResourceRelations,
38
36
  defaultTemplateId,
@@ -115,11 +113,14 @@ export const StructureGrantCartCheckout = ({
115
113
  }) => {
116
114
  const dispatch = useDispatch();
117
115
  const { trigger, isMutating } = useCheckoutGrantRequest();
118
- const { resource: templateResourceRelations, default: defaultRelation } =
119
- useTemplateRelations({
120
- resourceType: "system",
121
- listAll: true,
122
- });
116
+ const {
117
+ resource: templateResourceRelations,
118
+ default: defaultRelation,
119
+ loading: relationsLoading,
120
+ } = useTemplateRelations({
121
+ resourceType: "system",
122
+ listAll: true,
123
+ });
123
124
  const defaultTemplateId =
124
125
  defaultRelation?.template_id != null
125
126
  ? Number(defaultRelation.template_id) || defaultRelation.template_id
@@ -157,8 +158,12 @@ export const StructureGrantCartCheckout = ({
157
158
  enableGrouping,
158
159
  ],
159
160
  );
160
- const groupKeys = _.keys(groupedStructures);
161
+ const groupKeys = useMemo(
162
+ () => _.keys(groupedStructures),
163
+ [groupedStructures],
164
+ );
161
165
  const isMultiGroup = enableGrouping && groupKeys.length > 1;
166
+ const useGroupDrafts = enableGrouping && groupKeys.length > 0;
162
167
 
163
168
  const getTemplateIdFromKey = (key) => {
164
169
  const parts = key.split("_");
@@ -180,7 +185,7 @@ export const StructureGrantCartCheckout = ({
180
185
 
181
186
  const effectiveTemplateIdByKey = useMemo(
182
187
  () => _.fromPairs(groupKeys.map((k) => [k, getTemplateIdFromKey(k)])),
183
- [groupKeys.join(","), defaultTemplateId],
188
+ [groupKeys],
184
189
  );
185
190
 
186
191
  const uniqueTemplateIds = useMemo(
@@ -196,16 +201,25 @@ export const StructureGrantCartCheckout = ({
196
201
  ? getTemplateIdFromKey(singleGroupKey)
197
202
  : null;
198
203
 
199
- const templateIdsToFetch = isMultiGroup
200
- ? uniqueTemplateIds
201
- : singleTemplateId != null
202
- ? [singleTemplateId]
203
- : [];
204
+ const templateIdsToFetch = useMemo(
205
+ () =>
206
+ _.uniq(
207
+ _.compact([
208
+ ...(isMultiGroup
209
+ ? uniqueTemplateIds
210
+ : singleTemplateId != null
211
+ ? [singleTemplateId]
212
+ : []),
213
+ defaultTemplateId,
214
+ ]),
215
+ ),
216
+ [isMultiGroup, uniqueTemplateIds, singleTemplateId, defaultTemplateId],
217
+ );
204
218
 
205
219
  const templatesById = useTemplatesByIds(templateIdsToFetch);
206
220
 
207
221
  const systemTemplates = useMemo(() => {
208
- if (!isMultiGroup) return {};
222
+ if (!useGroupDrafts) return {};
209
223
  const next = {};
210
224
  groupKeys.forEach((k) => {
211
225
  const tid = effectiveTemplateIdByKey[k];
@@ -215,12 +229,7 @@ export const StructureGrantCartCheckout = ({
215
229
  if (t) next[k] = t;
216
230
  });
217
231
  return next;
218
- }, [
219
- isMultiGroup,
220
- groupKeys.join(","),
221
- effectiveTemplateIdByKey,
222
- templatesById,
223
- ]);
232
+ }, [useGroupDrafts, groupKeys, effectiveTemplateIdByKey, templatesById]);
224
233
 
225
234
  const singleSystemTemplate = useMemo(
226
235
  () =>
@@ -232,12 +241,30 @@ export const StructureGrantCartCheckout = ({
232
241
  [singleTemplateId, templatesById],
233
242
  );
234
243
 
244
+ const defaultTemplate = useMemo(
245
+ () =>
246
+ defaultTemplateId != null
247
+ ? (templatesById[String(defaultTemplateId)] ??
248
+ templatesById[defaultTemplateId] ??
249
+ null)
250
+ : null,
251
+ [defaultTemplateId, templatesById],
252
+ );
253
+
235
254
  useEffect(() => {
236
- if (!isMultiGroup) return;
237
- if (_.isEmpty(uniqueTemplateIds)) {
238
- initGroupTemplates(
239
- _.fromPairs(
240
- groupKeys.map((k) => [
255
+ if (!useGroupDrafts || relationsLoading) return;
256
+ if (singleGroupKey && !groupTemplates[singleGroupKey] && template) {
257
+ initGroupTemplates({
258
+ ...groupTemplates,
259
+ [singleGroupKey]: { template, templateContent, valid: validCart },
260
+ });
261
+ return;
262
+ }
263
+ if (_.isEmpty(templateIdsToFetch)) {
264
+ const missingGroupTemplates = _.fromPairs(
265
+ groupKeys
266
+ .filter((k) => groupTemplates[k] == null)
267
+ .map((k) => [
241
268
  k,
242
269
  {
243
270
  template: undefined,
@@ -245,54 +272,76 @@ export const StructureGrantCartCheckout = ({
245
272
  valid: false,
246
273
  },
247
274
  ]),
248
- ),
249
275
  );
276
+ if (!_.isEmpty(missingGroupTemplates)) {
277
+ initGroupTemplates({ ...groupTemplates, ...missingGroupTemplates });
278
+ }
250
279
  return;
251
280
  }
252
- const allLoaded = uniqueTemplateIds.every(
281
+ const allLoaded = templateIdsToFetch.every(
253
282
  (id) =>
254
283
  templatesById[String(id)] !== undefined ||
255
284
  templatesById[id] !== undefined,
256
285
  );
257
286
  if (!allLoaded) return;
258
- const getTemplateById = (tid) =>
259
- tid != null ? (templatesById[String(tid)] ?? templatesById[tid]) : null;
260
287
  groupKeys.forEach((k) => {
261
- const templateObj = getTemplateById(effectiveTemplateIdByKey[k]);
288
+ const tid = effectiveTemplateIdByKey[k];
289
+ const existingTemplateName = groupTemplates[k]?.template;
290
+ const templateObj =
291
+ tid != null
292
+ ? (templatesById[String(tid)] ?? templatesById[tid])
293
+ : existingTemplateName
294
+ ? null
295
+ : defaultTemplate;
262
296
  const t = templateObj?.name;
263
- if (t) {
297
+ if (t && t !== existingTemplateName) {
264
298
  selectGrantRequestTemplateForGroup({ key: k, template: t });
265
299
  }
266
300
  });
267
301
  }, [
268
- isMultiGroup,
269
- groupKeys.join(","),
270
- uniqueTemplateIds.join(","),
271
- defaultTemplateId,
302
+ useGroupDrafts,
303
+ relationsLoading,
304
+ groupTemplates,
305
+ initGroupTemplates,
306
+ singleGroupKey,
307
+ template,
308
+ templateContent,
309
+ validCart,
310
+ groupKeys,
311
+ templateIdsToFetch,
312
+ defaultTemplate,
272
313
  templatesById,
273
314
  effectiveTemplateIdByKey,
274
315
  selectGrantRequestTemplateForGroup,
275
316
  ]);
276
317
 
277
318
  useEffect(() => {
278
- if (isMultiGroup || singleTemplateId == null || !singleSystemTemplate?.name)
279
- return;
280
- selectGrantRequestTemplate(singleSystemTemplate.name);
319
+ if (useGroupDrafts || relationsLoading) return;
320
+ const templateName =
321
+ singleSystemTemplate?.name ?? (!template ? defaultTemplate?.name : null);
322
+ if (templateName && templateName !== template) {
323
+ selectGrantRequestTemplate(templateName);
324
+ }
281
325
  }, [
282
- isMultiGroup,
283
- singleTemplateId,
326
+ useGroupDrafts,
327
+ relationsLoading,
284
328
  singleSystemTemplate?.name,
329
+ defaultTemplate?.name,
330
+ template,
285
331
  selectGrantRequestTemplate,
286
332
  ]);
287
333
 
288
- const validCartMulti =
289
- isMultiGroup &&
334
+ const validCartGrouped =
335
+ useGroupDrafts &&
290
336
  user?.valid &&
291
337
  groupKeys.every(
292
338
  (k) => groupTemplates[k]?.template && groupTemplates[k]?.valid,
293
339
  );
294
340
 
295
- const canSubmit = isMultiGroup ? validCartMulti : validCart && user?.valid;
341
+ const canSubmit =
342
+ !relationsLoading &&
343
+ templateIdsToFetch.every((id) => templatesById[id] != null) &&
344
+ (useGroupDrafts ? validCartGrouped : validCart && user?.valid);
296
345
 
297
346
  const grantRequestGroupIds = _.omitBy(_.isNil)({
298
347
  user_id: _.isNil(user_group_id) ? user?.id : null,
@@ -331,7 +380,7 @@ export const StructureGrantCartCheckout = ({
331
380
  return [key, domainNames];
332
381
  }),
333
382
  );
334
- }, [groupKeys.join(","), structures, groupedStructures]);
383
+ }, [groupKeys, structures]);
335
384
 
336
385
  const checkout = () => {
337
386
  // eslint-disable-next-line fp/no-let
@@ -357,16 +406,19 @@ export const StructureGrantCartCheckout = ({
357
406
  // eslint-disable-next-line fp/no-mutation
358
407
  payload = { grant_request_groups };
359
408
  } else {
409
+ const singleDraft = useGroupDrafts
410
+ ? groupTemplates[singleGroupKey]
411
+ : { template, templateContent };
360
412
  const requests = _.map((structure) => ({
361
413
  data_structure_id: structure.id,
362
414
  filters: { rows: structure.filters },
363
- metadata: templateContent,
415
+ metadata: singleDraft?.templateContent ?? {},
364
416
  }))(structures);
365
417
  // eslint-disable-next-line fp/no-mutation
366
418
  payload = {
367
419
  grant_request_group: _.omitBy(_.isNil)({
368
420
  requests,
369
- type: template,
421
+ type: singleDraft?.template,
370
422
  modification_grant_id: modificationGrant?.id ?? null,
371
423
  ...grantRequestGroupIds,
372
424
  }),
@@ -412,7 +464,7 @@ export const StructureGrantCartCheckout = ({
412
464
  />
413
465
  </GridColumn>
414
466
  </Grid.Row>
415
- {groupKeys.length > 1 ? (
467
+ {relationsLoading ? null : isMultiGroup ? (
416
468
  <>
417
469
  <Grid.Row>
418
470
  <Grid.Column width={16}>
@@ -428,7 +480,6 @@ export const StructureGrantCartCheckout = ({
428
480
  const groupDomainIds = getUniqueDomainIds(groupStructures);
429
481
  const groupData = groupTemplates[key] ?? {};
430
482
  const selectedTemplate = systemTemplates[key];
431
- const autoTemplateName = selectedTemplate?.name;
432
483
  const domainName = domainNamesByKey[key];
433
484
  const systemNames = getUniqueSystemName(groupStructures);
434
485
 
@@ -491,14 +542,16 @@ export const StructureGrantCartCheckout = ({
491
542
  </Header.Subheader>
492
543
  </Header>
493
544
  <Suspense fallback={null}>
494
- <SelectableDynamicForm
495
- scope="gr"
545
+ <GrantRequestTemplateForm
496
546
  content={groupData.templateContent ?? null}
497
547
  domainIds={groupDomainIds}
498
548
  hideLabel
499
549
  isModification={!!modificationGrant}
500
- name={autoTemplateName}
501
- disableSelector={!!selectedTemplate}
550
+ name={groupData.template}
551
+ disableSelector={
552
+ effectiveTemplateIdByKey[key] != null
553
+ }
554
+ selectedTemplate={selectedTemplate ?? defaultTemplate}
502
555
  onChange={({ content, valid }) =>
503
556
  updateGrantRequestTemplateContentForGroup({
504
557
  key,
@@ -534,9 +587,19 @@ export const StructureGrantCartCheckout = ({
534
587
  <Grid.Row>
535
588
  <Grid.Column width={5}>
536
589
  <StructureGrantCartInformation
590
+ groupKey={useGroupDrafts ? singleGroupKey : undefined}
537
591
  isModification={!!modificationGrant}
538
- name={singleSystemTemplate?.name}
539
- disableSelector={!!singleSystemTemplate}
592
+ name={
593
+ useGroupDrafts
594
+ ? groupTemplates[singleGroupKey]?.template
595
+ : template
596
+ }
597
+ disableSelector={
598
+ useGroupDrafts
599
+ ? singleTemplateId != null
600
+ : !!singleSystemTemplate
601
+ }
602
+ selectedTemplate={singleSystemTemplate ?? defaultTemplate}
540
603
  />
541
604
  </Grid.Column>
542
605
  <Grid.Column width={11}>
@@ -8,12 +8,13 @@ import { useIntl } from "react-intl";
8
8
  import { DOMAINS_QUERY } from "@truedat/core/api/queries";
9
9
  import {
10
10
  selectGrantRequestTemplate,
11
+ selectGrantRequestTemplateForGroup,
11
12
  updateGrantRequestTemplateContent,
13
+ updateGrantRequestTemplateContentForGroup,
12
14
  } from "../routines";
13
15
  import StructureGrantCartUserSelector from "./StructureGrantCartUserSelector";
14
-
15
- const SelectableDynamicForm = lazy(
16
- () => import("@truedat/df/components/SelectableDynamicForm"),
16
+ const GrantRequestTemplateForm = lazy(
17
+ () => import("./GrantRequestTemplateForm"),
17
18
  );
18
19
 
19
20
  const getUniqueDomainIds = (structures) =>
@@ -21,15 +22,21 @@ const getUniqueDomainIds = (structures) =>
21
22
 
22
23
  export const StructureGrantCartInformation = ({
23
24
  grantRequestsCart,
25
+ groupKey,
24
26
  isModification,
25
27
  selectGrantRequestTemplate,
28
+ selectGrantRequestTemplateForGroup,
26
29
  updateGrantRequestTemplateContent,
30
+ updateGrantRequestTemplateContentForGroup,
27
31
  selectedTemplate,
28
32
  disableSelector,
29
33
  name: autoTemplateName,
30
34
  }) => {
31
35
  const { formatMessage } = useIntl();
32
- const templateContent = _.pathOr({}, "templateContent")(grantRequestsCart);
36
+ const draft = groupKey
37
+ ? grantRequestsCart?.groupTemplates?.[groupKey]
38
+ : grantRequestsCart;
39
+ const templateContent = draft?.templateContent ?? {};
33
40
  const structures = _.pathOr([], "structures")(grantRequestsCart);
34
41
  const domainIds = getUniqueDomainIds(structures);
35
42
 
@@ -58,20 +65,37 @@ export const StructureGrantCartInformation = ({
58
65
  >
59
66
  {formatMessage({ id: `structure.grant.cart.template` })}
60
67
  </Header>
61
- <SelectableDynamicForm
62
- scope="gr"
68
+ <GrantRequestTemplateForm
63
69
  content={templateContent}
64
70
  domainIds={domainIds}
65
71
  hideLabel
66
72
  isModification={isModification}
67
- onChange={updateGrantRequestTemplateContent}
68
- onNameChange={selectGrantRequestTemplate}
73
+ onChange={
74
+ groupKey
75
+ ? ({ content, valid }) =>
76
+ updateGrantRequestTemplateContentForGroup({
77
+ key: groupKey,
78
+ content,
79
+ valid,
80
+ })
81
+ : updateGrantRequestTemplateContent
82
+ }
83
+ onNameChange={
84
+ groupKey
85
+ ? (template) =>
86
+ selectGrantRequestTemplateForGroup({
87
+ key: groupKey,
88
+ template,
89
+ })
90
+ : selectGrantRequestTemplate
91
+ }
69
92
  placeholder={formatMessage({
70
93
  id: `structure.grant.cart.template.placeholder`,
71
94
  })}
72
95
  required
73
- name={autoTemplateName}
96
+ name={autoTemplateName ?? draft?.template}
74
97
  disableSelector={disableSelector}
98
+ selectedTemplate={selectedTemplate}
75
99
  />
76
100
  </Form>
77
101
  </Segment>
@@ -80,8 +104,11 @@ export const StructureGrantCartInformation = ({
80
104
 
81
105
  StructureGrantCartInformation.propTypes = {
82
106
  grantRequestsCart: PropTypes.object,
107
+ groupKey: PropTypes.string,
83
108
  selectGrantRequestTemplate: PropTypes.func,
109
+ selectGrantRequestTemplateForGroup: PropTypes.func,
84
110
  updateGrantRequestTemplateContent: PropTypes.func,
111
+ updateGrantRequestTemplateContentForGroup: PropTypes.func,
85
112
  isModification: PropTypes.bool,
86
113
  selectedTemplate: PropTypes.object,
87
114
  disableSelector: PropTypes.bool,
@@ -92,5 +119,7 @@ const mapStateToProps = ({ grantRequestsCart }) => ({ grantRequestsCart });
92
119
 
93
120
  export default connect(mapStateToProps, {
94
121
  selectGrantRequestTemplate,
122
+ selectGrantRequestTemplateForGroup,
95
123
  updateGrantRequestTemplateContent,
124
+ updateGrantRequestTemplateContentForGroup,
96
125
  })(StructureGrantCartInformation);
@@ -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();