@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.
Files changed (91) 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/StructureNoteActions.js +10 -1
  14. package/src/components/StructureNotes.js +42 -6
  15. package/src/components/StructureNotesEdit.js +38 -8
  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.spec.js +39 -1
  37. package/src/components/__tests__/StructureGrantCartInformation.spec.js +5 -2
  38. package/src/components/__tests__/StructureGrantCartUserSelector.spec.js +128 -0
  39. package/src/components/__tests__/StructureGrantDropdown.spec.js +92 -0
  40. package/src/components/__tests__/StructureGrantListButton.spec.js +70 -0
  41. package/src/components/__tests__/StructureGrantSummaryButton.spec.js +36 -1
  42. package/src/components/__tests__/StructureGrants.spec.js +12 -0
  43. package/src/components/__tests__/StructureNoteActions.spec.js +96 -0
  44. package/src/components/__tests__/StructureNotes.spec.js +170 -1
  45. package/src/components/__tests__/StructureNotesEdit.spec.js +185 -1
  46. package/src/components/__tests__/StructureRelationRow.spec.js +72 -4
  47. package/src/components/__tests__/StructureRelations.spec.js +18 -0
  48. package/src/components/__tests__/StructureRoles.spec.js +9 -0
  49. package/src/components/__tests__/StructureRow.spec.js +13 -4
  50. package/src/components/__tests__/StructureSelector.spec.js +2 -0
  51. package/src/components/__tests__/StructureTag.spec.js +2 -0
  52. package/src/components/__tests__/StructureTagForm.spec.js +2 -0
  53. package/src/components/__tests__/StructureType.spec.js +3 -1
  54. package/src/components/__tests__/StructureTypeForm.spec.js +3 -1
  55. package/src/components/__tests__/StructureView.spec.js +17 -1
  56. package/src/components/__tests__/StructuresGrantRequestView.spec.js +2 -0
  57. package/src/components/__tests__/StructuresView.spec.js +2 -1
  58. package/src/components/__tests__/Tag.spec.js +4 -1
  59. package/src/components/__tests__/Tags.spec.js +7 -1
  60. package/src/components/__tests__/__snapshots__/GrantsTable.spec.js.snap +34 -2
  61. package/src/components/__tests__/__snapshots__/LineageDefs.spec.js.snap +32 -30
  62. package/src/components/__tests__/__snapshots__/StructureFields.spec.js.snap +1 -16
  63. package/src/components/__tests__/__snapshots__/StructureNoteActions.spec.js.snap +2 -1
  64. package/src/components/__tests__/__snapshots__/StructureNotesEdit.spec.js.snap +3 -0
  65. package/src/components/__tests__/__snapshots__/StructureRelationRow.spec.js.snap +23 -19
  66. package/src/components/__tests__/__snapshots__/StructureRow.spec.js.snap +28 -24
  67. package/src/components/__tests__/__snapshots__/StructuresUpdateOption.spec.js.snap +7 -3
  68. package/src/messages/en.js +2 -2
  69. package/src/messages/es.js +2 -2
  70. package/src/reducers/__tests__/ddMessage.spec.js +48 -0
  71. package/src/reducers/__tests__/grantRequestsCart.spec.js +17 -0
  72. package/src/reducers/__tests__/structureRedirect.spec.js +22 -0
  73. package/src/reducers/__tests__/structureRelations.spec.js +28 -0
  74. package/src/reducers/ddMessage.js +32 -0
  75. package/src/reducers/grantRequestsCart.js +3 -0
  76. package/src/reducers/structureRedirect.js +7 -2
  77. package/src/selectors/__tests__/__snapshots__/getGrantsColumns.spec.js.snap +1 -9
  78. package/src/selectors/__tests__/getGrantRequestsSearchColumns.spec.js +11 -4
  79. package/src/selectors/__tests__/getGrantsColumns.spec.js +295 -0
  80. package/src/selectors/__tests__/messages.spec.js +14 -0
  81. package/src/selectors/getBusinessConceptsLinksToStructuresColumnsSelector.js +3 -5
  82. package/src/selectors/getGrantRequestsSearchColumns.js +3 -5
  83. package/src/selectors/getGrantsColumns.js +85 -11
  84. package/src/selectors/getLinkedImplementationsToStructuresColumns.js +3 -7
  85. package/src/selectors/getStructureFieldColumns.js +7 -6
  86. package/src/selectors/getStructureProperties.js +2 -5
  87. package/src/selectors/getStructuresUploadEventColumns.js +2 -7
  88. package/src/selectors/messages.js +30 -0
  89. package/src/selectors/structureColumnsSelector.js +13 -16
  90. package/src/utils/__tests__/structureNoteActions.spec.js +196 -0
  91. package/src/utils/structureNoteActions.js +22 -0
@@ -48,6 +48,32 @@ const uploadAccepted = () => {
48
48
  };
49
49
  };
50
50
 
51
+ const uploadFailed = (data) => ({
52
+ error: true,
53
+ header: "structures.bulkUpdateStructures.failed.header",
54
+ icon: "attention",
55
+ color: "red",
56
+ text: "",
57
+ messages: _.has("errors")(data)
58
+ ? _.flow(
59
+ _.propOr([], "errors"),
60
+ _.map((error) => ({
61
+ id: `structures.bulkUpdateStructures.failed.note.${error.message}`,
62
+ fields: {
63
+ row: error.row,
64
+ id: error.id,
65
+ field: error.field,
66
+ externalId: error.external_id,
67
+ message: error.message,
68
+ },
69
+ defaultMessage: "structures.bulkUploadStructures.success.errors",
70
+ })),
71
+ )(data)
72
+ : [],
73
+ fields: data?.errors ? { count_errors: data.errors.length } : {},
74
+ initialMaxListItems: 5,
75
+ });
76
+
51
77
  export const getUploadAlertMessage = ({ status, data }) => {
52
78
  if (status === 202) {
53
79
  return uploadAccepted();
@@ -55,4 +81,8 @@ export const getUploadAlertMessage = ({ status, data }) => {
55
81
  if (status === 200) {
56
82
  return uploadWithErrors(data);
57
83
  }
84
+ if (status >= 400) {
85
+ return uploadFailed(data || {});
86
+ }
87
+ return uploadAccepted();
58
88
  };
@@ -64,23 +64,20 @@ export const defaultStructureColumns = [
64
64
  },
65
65
  ];
66
66
 
67
- // If default filters include "system.name.raw", exclude the "system" column
68
- const filterExcludes = { "system.name.raw": "system" };
69
-
70
- const columnsToExclude = (defaultFilters) =>
71
- _.flow(_.pick(_.keys(defaultFilters)), _.values)(filterExcludes);
67
+ const filteredStructureColumns = createSelector(
68
+ (state) => state.structuresColumns ?? defaultStructureColumns,
69
+ _.reject(({ name }) => name === "system"),
70
+ );
72
71
 
73
- export const structureColumnsSelector = (state, defaultFilters, ownColumns) =>
74
- createSelector(_.prop("structuresColumns"), (columns) => {
75
- const excludes = columnsToExclude(defaultFilters);
76
- const res = ownColumns
77
- ? ownColumns
78
- : _.flow(
79
- _.defaultTo(defaultStructureColumns),
80
- _.reject(({ name }) => _.includes(name)(excludes)),
81
- )(columns);
82
- return res;
83
- })(state);
72
+ export const structureColumnsSelector = (state, defaultFilters, ownColumns) => {
73
+ if (ownColumns) return ownColumns;
74
+ return Object.prototype.hasOwnProperty.call(
75
+ defaultFilters || {},
76
+ "system.name.raw",
77
+ )
78
+ ? filteredStructureColumns(state)
79
+ : (state.structuresColumns ?? defaultStructureColumns);
80
+ };
84
81
 
85
82
  const rawName = {
86
83
  name: "name",
@@ -0,0 +1,196 @@
1
+ import {
2
+ hasMandatoryErrors,
3
+ canPerformAction,
4
+ getMissingMandatoryFields,
5
+ } from "../structureNoteActions";
6
+
7
+ describe("hasMandatoryErrors", () => {
8
+ const template = {
9
+ content: [
10
+ {
11
+ name: "group",
12
+ fields: [
13
+ {
14
+ name: "required_field",
15
+ type: "string",
16
+ cardinality: "1",
17
+ },
18
+ {
19
+ name: "optional_field",
20
+ type: "string",
21
+ cardinality: "?",
22
+ },
23
+ ],
24
+ },
25
+ ],
26
+ };
27
+
28
+ it("returns false when content is null/undefined", () => {
29
+ expect(hasMandatoryErrors(null, template)).toBe(false);
30
+ expect(hasMandatoryErrors(undefined, template)).toBe(false);
31
+ });
32
+
33
+ it("returns false when template is null/undefined", () => {
34
+ expect(hasMandatoryErrors({}, null)).toBe(false);
35
+ expect(hasMandatoryErrors({}, undefined)).toBe(false);
36
+ });
37
+
38
+ it("returns true when a mandatory field is missing", () => {
39
+ const content = { optional_field: { value: "x", origin: "user" } };
40
+ expect(hasMandatoryErrors(content, template)).toBe(true);
41
+ });
42
+
43
+ it("returns false when all mandatory fields are populated", () => {
44
+ const content = {
45
+ required_field: { value: "ok", origin: "user" },
46
+ optional_field: { value: "x", origin: "user" },
47
+ };
48
+ expect(hasMandatoryErrors(content, template)).toBe(false);
49
+ });
50
+
51
+ it("returns true when a mandatory field is present but empty", () => {
52
+ const content = {
53
+ required_field: { value: "", origin: "user" },
54
+ };
55
+ expect(hasMandatoryErrors(content, template)).toBe(true);
56
+ });
57
+
58
+ it("returns true when a mandatory field is null", () => {
59
+ const content = {
60
+ required_field: { value: null, origin: "user" },
61
+ };
62
+ expect(hasMandatoryErrors(content, template)).toBe(true);
63
+ });
64
+ });
65
+
66
+ describe("getMissingMandatoryFields", () => {
67
+ const template = {
68
+ content: [
69
+ {
70
+ name: "group",
71
+ fields: [
72
+ {
73
+ name: "required_field",
74
+ type: "string",
75
+ cardinality: "1",
76
+ },
77
+ {
78
+ name: "another_required",
79
+ type: "string",
80
+ cardinality: "+",
81
+ },
82
+ {
83
+ name: "optional_field",
84
+ type: "string",
85
+ cardinality: "?",
86
+ },
87
+ ],
88
+ },
89
+ ],
90
+ };
91
+
92
+ it("returns empty array when content is null/undefined", () => {
93
+ expect(getMissingMandatoryFields(null, template)).toEqual([]);
94
+ expect(getMissingMandatoryFields(undefined, template)).toEqual([]);
95
+ });
96
+
97
+ it("returns empty array when template is null/undefined", () => {
98
+ expect(getMissingMandatoryFields({}, null)).toEqual([]);
99
+ expect(getMissingMandatoryFields({}, undefined)).toEqual([]);
100
+ });
101
+
102
+ it("returns list of missing field names", () => {
103
+ const content = { optional_field: { value: "x", origin: "user" } };
104
+ const missing = getMissingMandatoryFields(content, template);
105
+ expect(missing).toContain("required_field");
106
+ expect(missing).toContain("another_required");
107
+ expect(missing).toHaveLength(2);
108
+ });
109
+
110
+ it("returns empty array when all mandatory fields are populated", () => {
111
+ const content = {
112
+ required_field: { value: "ok", origin: "user" },
113
+ another_required: { value: ["a"], origin: "user" },
114
+ optional_field: { value: "x", origin: "user" },
115
+ };
116
+ expect(getMissingMandatoryFields(content, template)).toEqual([]);
117
+ });
118
+ });
119
+
120
+ describe("canPerformAction (TD-7093)", () => {
121
+ const template = {
122
+ content: [
123
+ {
124
+ name: "group",
125
+ fields: [
126
+ {
127
+ name: "required_field",
128
+ type: "string",
129
+ cardinality: "1",
130
+ },
131
+ ],
132
+ },
133
+ ],
134
+ };
135
+
136
+ const fullContent = { required_field: { value: "ok", origin: "user" } };
137
+ const partialContent = { optional_field: { value: "x", origin: "user" } };
138
+
139
+ describe("publishing actions", () => {
140
+ it("returns false for 'published' when mandatory fields are missing", () => {
141
+ expect(canPerformAction("published", partialContent, template)).toBe(
142
+ false,
143
+ );
144
+ });
145
+
146
+ it("returns true for 'published' when all mandatory fields are populated", () => {
147
+ expect(canPerformAction("published", fullContent, template)).toBe(true);
148
+ });
149
+
150
+ it("returns false for 'pending_approval' when mandatory fields are missing", () => {
151
+ expect(
152
+ canPerformAction("pending_approval", partialContent, template),
153
+ ).toBe(false);
154
+ });
155
+
156
+ it("returns true for 'pending_approval' when all mandatory fields are populated", () => {
157
+ expect(canPerformAction("pending_approval", fullContent, template)).toBe(
158
+ true,
159
+ );
160
+ });
161
+ });
162
+
163
+ describe("draft actions", () => {
164
+ it("always allows 'edited' even with partial content", () => {
165
+ expect(canPerformAction("edited", partialContent, template)).toBe(true);
166
+ });
167
+
168
+ it("always allows 'draft' even with partial content", () => {
169
+ expect(canPerformAction("draft", partialContent, template)).toBe(true);
170
+ });
171
+
172
+ it("always allows 'deleted' even with partial content", () => {
173
+ expect(canPerformAction("deleted", partialContent, template)).toBe(true);
174
+ });
175
+
176
+ it("always allows 'rejected' even with partial content", () => {
177
+ expect(canPerformAction("rejected", partialContent, template)).toBe(true);
178
+ });
179
+
180
+ it("always allows 'deprecated' even with partial content", () => {
181
+ expect(canPerformAction("deprecated", partialContent, template)).toBe(
182
+ true,
183
+ );
184
+ });
185
+ });
186
+
187
+ describe("edge cases", () => {
188
+ it("returns true for publishing actions when template is missing (no validation possible)", () => {
189
+ expect(canPerformAction("published", partialContent, null)).toBe(true);
190
+ });
191
+
192
+ it("returns true for publishing actions when content is missing (no validation possible)", () => {
193
+ expect(canPerformAction("published", null, template)).toBe(true);
194
+ });
195
+ });
196
+ });
@@ -0,0 +1,22 @@
1
+ import { validateContent } from "@truedat/df/utils";
2
+
3
+ export const getMissingMandatoryFields = (content, template) => {
4
+ if (!template || !content) return [];
5
+ const errors = validateContent(template)(content);
6
+ return Array.isArray(errors)
7
+ ? errors
8
+ .filter((err) => err && err.error === "missing required" && err.field)
9
+ .map((err) => err.field)
10
+ : [];
11
+ };
12
+
13
+ export const hasMandatoryErrors = (content, template) => {
14
+ return getMissingMandatoryFields(content, template).length > 0;
15
+ };
16
+
17
+ export const canPerformAction = (action, content, template) => {
18
+ if (action === "pending_approval" || action === "published") {
19
+ return !hasMandatoryErrors(content, template);
20
+ }
21
+ return true;
22
+ };