@truedat/audit 8.5.3 → 8.5.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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/audit",
|
|
3
|
-
"version": "8.5.
|
|
3
|
+
"version": "8.5.5",
|
|
4
4
|
"description": "Truedat Web Audit Module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"module": "src/index.js",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"@testing-library/jest-dom": "^6.6.3",
|
|
52
52
|
"@testing-library/react": "^16.3.0",
|
|
53
53
|
"@testing-library/user-event": "^14.6.1",
|
|
54
|
-
"@truedat/test": "8.5.
|
|
54
|
+
"@truedat/test": "8.5.4",
|
|
55
55
|
"identity-obj-proxy": "^3.0.0",
|
|
56
56
|
"jest": "^29.7.0",
|
|
57
57
|
"redux-saga-test-plan": "^4.0.6"
|
|
@@ -83,5 +83,5 @@
|
|
|
83
83
|
"semantic-ui-react": "^3.0.0-beta.2",
|
|
84
84
|
"swr": "^2.3.3"
|
|
85
85
|
},
|
|
86
|
-
"gitHead": "
|
|
86
|
+
"gitHead": "8fb280f11b1f8ce7b1081e0654621de191ad8f80"
|
|
87
87
|
}
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from "semantic-ui-react";
|
|
12
12
|
import { FormattedMessage, useIntl } from "react-intl";
|
|
13
13
|
import { connect } from "react-redux";
|
|
14
|
+
import { visibleEvents } from "../subscriptionConstants";
|
|
14
15
|
import SubscriptionCrumbs from "./SubscriptionCrumbs";
|
|
15
16
|
import SubscriptionActions from "./SubscriptionActions";
|
|
16
17
|
|
|
@@ -75,7 +76,7 @@ export const Subscription = ({
|
|
|
75
76
|
: identifier;
|
|
76
77
|
const resourceName = subscription.resource?.name;
|
|
77
78
|
const periodicity = subscription.periodicity;
|
|
78
|
-
const events = subscription.scope?.events;
|
|
79
|
+
const events = visibleEvents(subscription.scope?.events);
|
|
79
80
|
const status = subscription.scope?.status;
|
|
80
81
|
const filters = subscription.scope?.filters;
|
|
81
82
|
const template = _.find({ id: filters?.template?.id })(templates);
|
|
@@ -9,11 +9,14 @@ import {
|
|
|
9
9
|
CONCEPT_EVENTS,
|
|
10
10
|
DEFAULT_ICON,
|
|
11
11
|
EVENTS_BY_TYPE,
|
|
12
|
+
expandPairedEvents,
|
|
13
|
+
isHiddenPairedEvent,
|
|
12
14
|
isQualityControlSubscriptionsEnabled,
|
|
13
15
|
RESOURCE_TYPES,
|
|
14
16
|
RESOURCE_TYPE_ICONS,
|
|
15
17
|
STATUSES_BY_EVENT,
|
|
16
18
|
SUBSCRIBER_TYPE_ICONS,
|
|
19
|
+
visibleEvents,
|
|
17
20
|
isSubset,
|
|
18
21
|
} from "../subscriptionConstants";
|
|
19
22
|
import ContentFilters from "./ContentFilters";
|
|
@@ -483,18 +486,20 @@ export const SubscriptionForm = ({
|
|
|
483
486
|
disabled={_.isEmpty(eventsForType)}
|
|
484
487
|
label={formatMessage({ id: "subscriptions.events" })}
|
|
485
488
|
onBlur={onBlur}
|
|
486
|
-
onChange={(_e, { value }) => onChange(value)}
|
|
489
|
+
onChange={(_e, { value }) => onChange(expandPairedEvents(value))}
|
|
487
490
|
placeholder={formatMessage({ id: "subscriptions.events" })}
|
|
488
|
-
value={value}
|
|
491
|
+
value={visibleEvents(value)}
|
|
489
492
|
required
|
|
490
|
-
options={eventsForType
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
493
|
+
options={eventsForType
|
|
494
|
+
.filter((event) => !isHiddenPairedEvent(event))
|
|
495
|
+
.map((event, key) => ({
|
|
496
|
+
key,
|
|
497
|
+
value: event,
|
|
498
|
+
text: formatMessage({
|
|
499
|
+
id: `subscriptions.events.${event}`,
|
|
500
|
+
defaultMessage: event,
|
|
501
|
+
}),
|
|
502
|
+
}))}
|
|
498
503
|
/>
|
|
499
504
|
)}
|
|
500
505
|
/>
|
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import userEvent from "@testing-library/user-event";
|
|
2
|
+
import { waitFor, within } from "@testing-library/react";
|
|
3
|
+
import { render, waitForLoad } from "@truedat/test/render";
|
|
4
|
+
import { domainsMock } from "@truedat/test/mocks";
|
|
5
|
+
import SubscriptionForm from "../SubscriptionForm";
|
|
6
|
+
|
|
7
|
+
jest.mock("@truedat/bg/concepts/relations/components/ConceptSelector", () => ({
|
|
8
|
+
__esModule: true,
|
|
9
|
+
default: ({ handleConceptSelected }) => (
|
|
10
|
+
<button
|
|
11
|
+
data-testid="mock-concept-selector"
|
|
12
|
+
onClick={() =>
|
|
13
|
+
handleConceptSelected({
|
|
14
|
+
business_concept_id: "42",
|
|
15
|
+
type: "foo",
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
type="button"
|
|
19
|
+
>
|
|
20
|
+
MockConceptSelector
|
|
21
|
+
</button>
|
|
22
|
+
),
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
jest.mock("@truedat/dd/components/StructureSelector", () => ({
|
|
26
|
+
__esModule: true,
|
|
27
|
+
default: ({ onSelect }) => (
|
|
28
|
+
<button
|
|
29
|
+
data-testid="mock-structure-selector"
|
|
30
|
+
onClick={() =>
|
|
31
|
+
onSelect({ id: "7", name: "MyStructure", domain_id: "99" })
|
|
32
|
+
}
|
|
33
|
+
type="button"
|
|
34
|
+
>
|
|
35
|
+
MockStructureSelector
|
|
36
|
+
</button>
|
|
37
|
+
),
|
|
38
|
+
}));
|
|
39
|
+
|
|
40
|
+
jest.mock("@truedat/cx/sources/components/SourceSelector", () => ({
|
|
41
|
+
__esModule: true,
|
|
42
|
+
default: ({ onChange }) => (
|
|
43
|
+
<button
|
|
44
|
+
data-testid="mock-source-selector"
|
|
45
|
+
onClick={() =>
|
|
46
|
+
onChange(null, {
|
|
47
|
+
value: "5",
|
|
48
|
+
options: [{ key: "5", text: "MySource" }],
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
type="button"
|
|
52
|
+
>
|
|
53
|
+
MockSourceSelector
|
|
54
|
+
</button>
|
|
55
|
+
),
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
jest.mock(
|
|
59
|
+
"@truedat/qx/components/qualityControls/QualityControlSelector",
|
|
60
|
+
() => ({
|
|
61
|
+
__esModule: true,
|
|
62
|
+
default: ({ onSelect }) => (
|
|
63
|
+
<button
|
|
64
|
+
data-testid="mock-qc-selector"
|
|
65
|
+
onClick={() => onSelect({ quality_control_id: "11", name: "MyQC" })}
|
|
66
|
+
type="button"
|
|
67
|
+
>
|
|
68
|
+
MockQCSelector
|
|
69
|
+
</button>
|
|
70
|
+
),
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
jest.mock("@truedat/auth/users/components/UserSelector", () => ({
|
|
75
|
+
__esModule: true,
|
|
76
|
+
default: ({ onChange, value }) => (
|
|
77
|
+
<button
|
|
78
|
+
data-testid="mock-user-selector"
|
|
79
|
+
onClick={() => onChange(null, { value: "2" })}
|
|
80
|
+
type="button"
|
|
81
|
+
>
|
|
82
|
+
MockUserSelector:{value}
|
|
83
|
+
</button>
|
|
84
|
+
),
|
|
85
|
+
}));
|
|
86
|
+
|
|
87
|
+
jest.mock("@truedat/core/hooks/useUserFilters");
|
|
88
|
+
|
|
89
|
+
const variables = { action: "manageSubscriptions" };
|
|
90
|
+
const mocks = [domainsMock(variables)];
|
|
91
|
+
const state = {
|
|
92
|
+
roles: [{ name: "role1" }, { name: "role2" }],
|
|
93
|
+
templates: [],
|
|
94
|
+
users: [
|
|
95
|
+
{ full_name: "user1", id: 1 },
|
|
96
|
+
{ full_name: "user2", id: 2 },
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
const renderOpts = { state, mocks };
|
|
100
|
+
|
|
101
|
+
describe("<SubscriptionForm /> lazy selectors and email", () => {
|
|
102
|
+
it("submits with concept resource selected via ConceptSelector", async () => {
|
|
103
|
+
const onSubmit = jest.fn();
|
|
104
|
+
const user = userEvent.setup({ delay: null });
|
|
105
|
+
|
|
106
|
+
const rendered = render(
|
|
107
|
+
<SubscriptionForm onSubmit={onSubmit} />,
|
|
108
|
+
renderOpts
|
|
109
|
+
);
|
|
110
|
+
await waitForLoad(rendered);
|
|
111
|
+
|
|
112
|
+
await user.click(rendered.getByText(/^user$/i));
|
|
113
|
+
await user.click(await rendered.findByTestId("mock-user-selector"));
|
|
114
|
+
|
|
115
|
+
await user.click(rendered.getByText("concept"));
|
|
116
|
+
await user.click(await rendered.findByTestId("mock-concept-selector"));
|
|
117
|
+
|
|
118
|
+
await user.click(rendered.getByText(/daily/i));
|
|
119
|
+
await user.click(await rendered.findByText(/concept_published/i));
|
|
120
|
+
|
|
121
|
+
const saveButton = rendered.getByRole("button", { name: "actions.save" });
|
|
122
|
+
await waitFor(() => expect(saveButton).toBeEnabled());
|
|
123
|
+
|
|
124
|
+
await user.click(saveButton);
|
|
125
|
+
|
|
126
|
+
await waitFor(() => {
|
|
127
|
+
expect(onSubmit).toHaveBeenCalledWith(
|
|
128
|
+
expect.objectContaining({
|
|
129
|
+
subscriber: { type: "user", identifier: "2" },
|
|
130
|
+
scope: expect.objectContaining({
|
|
131
|
+
resource_type: "concept",
|
|
132
|
+
resource_id: "42",
|
|
133
|
+
}),
|
|
134
|
+
periodicity: "daily",
|
|
135
|
+
})
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("submits with data_structure resource selected via StructureSelector", async () => {
|
|
141
|
+
const onSubmit = jest.fn();
|
|
142
|
+
const user = userEvent.setup({ delay: null });
|
|
143
|
+
|
|
144
|
+
const rendered = render(
|
|
145
|
+
<SubscriptionForm onSubmit={onSubmit} />,
|
|
146
|
+
renderOpts
|
|
147
|
+
);
|
|
148
|
+
await waitForLoad(rendered);
|
|
149
|
+
|
|
150
|
+
await user.click(rendered.getByText(/^user$/i));
|
|
151
|
+
await user.click(await rendered.findByTestId("mock-user-selector"));
|
|
152
|
+
|
|
153
|
+
await user.click(rendered.getByText(/data_structure/i));
|
|
154
|
+
await user.click(await rendered.findByTestId("mock-structure-selector"));
|
|
155
|
+
|
|
156
|
+
await user.click(rendered.getByText(/daily/i));
|
|
157
|
+
await user.click(await rendered.findByText(/structure_note_published/i));
|
|
158
|
+
|
|
159
|
+
const saveButton = rendered.getByRole("button", { name: "actions.save" });
|
|
160
|
+
await waitFor(() => expect(saveButton).toBeEnabled());
|
|
161
|
+
|
|
162
|
+
await user.click(saveButton);
|
|
163
|
+
|
|
164
|
+
await waitFor(() => {
|
|
165
|
+
expect(onSubmit).toHaveBeenCalledWith(
|
|
166
|
+
expect.objectContaining({
|
|
167
|
+
subscriber: { type: "user", identifier: "2" },
|
|
168
|
+
scope: expect.objectContaining({
|
|
169
|
+
resource_type: "data_structure",
|
|
170
|
+
resource_id: "7",
|
|
171
|
+
resource_name: "MyStructure",
|
|
172
|
+
domain_id: "99",
|
|
173
|
+
}),
|
|
174
|
+
periodicity: "daily",
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
it("submits with source resource selected via SourceSelector", async () => {
|
|
181
|
+
const onSubmit = jest.fn();
|
|
182
|
+
const user = userEvent.setup({ delay: null });
|
|
183
|
+
|
|
184
|
+
const rendered = render(
|
|
185
|
+
<SubscriptionForm onSubmit={onSubmit} />,
|
|
186
|
+
renderOpts
|
|
187
|
+
);
|
|
188
|
+
await waitForLoad(rendered);
|
|
189
|
+
|
|
190
|
+
await user.click(rendered.getByText(/^user$/i));
|
|
191
|
+
await user.click(await rendered.findByTestId("mock-user-selector"));
|
|
192
|
+
|
|
193
|
+
await user.click(rendered.getByText(/^source$/i));
|
|
194
|
+
await user.click(await rendered.findByTestId("mock-source-selector"));
|
|
195
|
+
|
|
196
|
+
await user.click(rendered.getByText(/daily/i));
|
|
197
|
+
await user.click(await rendered.findByText(/status_changed/i));
|
|
198
|
+
await user.click(await rendered.findByText(/job_status_started/i));
|
|
199
|
+
|
|
200
|
+
const saveButton = rendered.getByRole("button", { name: "actions.save" });
|
|
201
|
+
await waitFor(() => expect(saveButton).toBeEnabled());
|
|
202
|
+
|
|
203
|
+
await user.click(saveButton);
|
|
204
|
+
|
|
205
|
+
await waitFor(() => {
|
|
206
|
+
expect(onSubmit).toHaveBeenCalledWith(
|
|
207
|
+
expect.objectContaining({
|
|
208
|
+
subscriber: { type: "user", identifier: "2" },
|
|
209
|
+
scope: expect.objectContaining({
|
|
210
|
+
resource_type: "source",
|
|
211
|
+
resource_id: "5",
|
|
212
|
+
resource_name: "MySource",
|
|
213
|
+
}),
|
|
214
|
+
periodicity: "daily",
|
|
215
|
+
})
|
|
216
|
+
);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it("submits with quality_control resource selected via QualityControlSelector", async () => {
|
|
221
|
+
const onSubmit = jest.fn();
|
|
222
|
+
const user = userEvent.setup({ delay: null });
|
|
223
|
+
|
|
224
|
+
const rendered = render(
|
|
225
|
+
<SubscriptionForm onSubmit={onSubmit} />,
|
|
226
|
+
renderOpts
|
|
227
|
+
);
|
|
228
|
+
await waitForLoad(rendered);
|
|
229
|
+
|
|
230
|
+
await user.click(rendered.getByText(/^user$/i));
|
|
231
|
+
await user.click(await rendered.findByTestId("mock-user-selector"));
|
|
232
|
+
|
|
233
|
+
await user.click(rendered.getByText(/quality_control/i));
|
|
234
|
+
await user.click(await rendered.findByTestId("mock-qc-selector"));
|
|
235
|
+
|
|
236
|
+
await user.click(rendered.getByText(/daily/i));
|
|
237
|
+
await user.click(
|
|
238
|
+
await rendered.findByText(/quality_control_version_draft_created/i)
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
const saveButton = rendered.getByRole("button", { name: "actions.save" });
|
|
242
|
+
await waitFor(() => expect(saveButton).toBeEnabled());
|
|
243
|
+
|
|
244
|
+
await user.click(saveButton);
|
|
245
|
+
|
|
246
|
+
await waitFor(() => {
|
|
247
|
+
expect(onSubmit).toHaveBeenCalledWith(
|
|
248
|
+
expect.objectContaining({
|
|
249
|
+
subscriber: { type: "user", identifier: "2" },
|
|
250
|
+
scope: expect.objectContaining({
|
|
251
|
+
resource_type: "quality_control",
|
|
252
|
+
resource_id: "11",
|
|
253
|
+
resource_name: "MyQC",
|
|
254
|
+
}),
|
|
255
|
+
periodicity: "daily",
|
|
256
|
+
})
|
|
257
|
+
);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
it("updates email subscriber identifier when typing into email input", async () => {
|
|
262
|
+
const onSubmit = jest.fn();
|
|
263
|
+
const user = userEvent.setup({ delay: null });
|
|
264
|
+
|
|
265
|
+
const rendered = render(
|
|
266
|
+
<SubscriptionForm onSubmit={onSubmit} />,
|
|
267
|
+
renderOpts
|
|
268
|
+
);
|
|
269
|
+
await waitForLoad(rendered);
|
|
270
|
+
|
|
271
|
+
await user.click(rendered.getByText(/email/i));
|
|
272
|
+
|
|
273
|
+
await waitFor(() =>
|
|
274
|
+
expect(rendered.getByTestId("email-input")).toBeInTheDocument()
|
|
275
|
+
);
|
|
276
|
+
|
|
277
|
+
const emailInput = within(rendered.getByTestId("email-input")).getByRole(
|
|
278
|
+
"textbox"
|
|
279
|
+
);
|
|
280
|
+
await user.type(emailInput, "test@example.com");
|
|
281
|
+
|
|
282
|
+
expect(emailInput).toHaveValue("test@example.com");
|
|
283
|
+
|
|
284
|
+
await user.click(rendered.getByText(/data_structure/i));
|
|
285
|
+
await user.click(await rendered.findByTestId("mock-structure-selector"));
|
|
286
|
+
|
|
287
|
+
await user.click(rendered.getByText(/daily/i));
|
|
288
|
+
await user.click(await rendered.findByText(/structure_note_published/i));
|
|
289
|
+
|
|
290
|
+
const saveButton = rendered.getByRole("button", { name: "actions.save" });
|
|
291
|
+
await waitFor(() => expect(saveButton).toBeEnabled());
|
|
292
|
+
|
|
293
|
+
await user.click(saveButton);
|
|
294
|
+
|
|
295
|
+
await waitFor(() => {
|
|
296
|
+
expect(onSubmit).toHaveBeenCalledWith(
|
|
297
|
+
expect.objectContaining({
|
|
298
|
+
subscriber: { type: "email", identifier: "test@example.com" },
|
|
299
|
+
})
|
|
300
|
+
);
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
});
|
|
@@ -33,7 +33,9 @@ export const CONCEPT_EVENTS = [
|
|
|
33
33
|
"concept_rejected",
|
|
34
34
|
"concept_rejection_canceled",
|
|
35
35
|
"new_concept_draft",
|
|
36
|
+
"create_concept_draft",
|
|
36
37
|
"update_concept_draft",
|
|
38
|
+
"update_concept",
|
|
37
39
|
"delete_concept_draft",
|
|
38
40
|
"comment_created",
|
|
39
41
|
"relation_created",
|
|
@@ -41,6 +43,26 @@ export const CONCEPT_EVENTS = [
|
|
|
41
43
|
"relation_deleted",
|
|
42
44
|
];
|
|
43
45
|
|
|
46
|
+
export const PAIRED_EVENTS = {
|
|
47
|
+
new_concept_draft: "create_concept_draft",
|
|
48
|
+
update_concept_draft: "update_concept",
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const HIDDEN_PAIRED_EVENTS = _.values(PAIRED_EVENTS);
|
|
52
|
+
|
|
53
|
+
export const isHiddenPairedEvent = (event) =>
|
|
54
|
+
_.includes(event)(HIDDEN_PAIRED_EVENTS);
|
|
55
|
+
|
|
56
|
+
export const expandPairedEvents = (events = []) =>
|
|
57
|
+
_.uniq(
|
|
58
|
+
_.flatMap((event) =>
|
|
59
|
+
PAIRED_EVENTS[event] ? [event, PAIRED_EVENTS[event]] : [event]
|
|
60
|
+
)(events)
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
export const visibleEvents = (events = []) =>
|
|
64
|
+
_.filter((event) => !isHiddenPairedEvent(event))(events);
|
|
65
|
+
|
|
44
66
|
export const STRUCTURE_EVENTS = [
|
|
45
67
|
"structure_note_published",
|
|
46
68
|
"structure_note_pending_approval",
|