@truedat/qx 8.0.0 → 8.0.1

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/qx",
3
- "version": "8.0.0",
3
+ "version": "8.0.1",
4
4
  "description": "Truedat Web Quality Experience package",
5
5
  "sideEffects": false,
6
6
  "module": "src/index.js",
@@ -53,7 +53,7 @@
53
53
  "@testing-library/jest-dom": "^6.6.3",
54
54
  "@testing-library/react": "^16.3.0",
55
55
  "@testing-library/user-event": "^14.6.1",
56
- "@truedat/test": "8.0.0",
56
+ "@truedat/test": "8.0.1",
57
57
  "identity-obj-proxy": "^3.0.0",
58
58
  "jest": "^29.7.0",
59
59
  "redux-saga-test-plan": "^4.0.6"
@@ -86,5 +86,5 @@
86
86
  "semantic-ui-react": "^3.0.0-beta.2",
87
87
  "swr": "^2.3.3"
88
88
  },
89
- "gitHead": "5a3af0f7a7833b2e02a876a08e228a5d678927ea"
89
+ "gitHead": "1d2fb016733a74a116362b4906f7141ca7b20ff0"
90
90
  }
@@ -1,3 +1,4 @@
1
+ import _ from "lodash/fp";
1
2
  import { Segment, Feed } from "semantic-ui-react";
2
3
  import { useEvents } from "@truedat/audit/hooks/useEvents";
3
4
  import PropTypes from "prop-types";
@@ -10,20 +11,48 @@ import Moment from "react-moment";
10
11
  const MESSAGE_ID = 0;
11
12
  const MESSAGE_PARAMS = 1;
12
13
 
13
- const EventRow = ({ user, ts, payload }) => {
14
+ const EventRow = ({ user, ts, header, payload }) => {
14
15
  const { formatMessage, locale } = useIntl();
15
16
  const translateParams = (params) => {
16
- if (!params || typeof params !== "object") return params;
17
- if (params.value && typeof params.value === "object" && params.value.id) {
18
- return { ...params, value: formatMessage(params.value) };
17
+ if (!_.isObject(params)) return params;
18
+
19
+ if (_.has("value.id")(params)) {
20
+ const transformValue = params.lowercase
21
+ ? _.flow(formatMessage, _.toLower)
22
+ : formatMessage;
23
+ return {
24
+ ...params,
25
+ value: transformValue(params.value),
26
+ };
27
+ }
28
+
29
+ if (_.has("type.id")(params)) {
30
+ const formatParam = ([label, value]) =>
31
+ _.has("id")(label) && _.isString(label.id)
32
+ ? `${formatMessage(label)}: ${value}`
33
+ : `${label}: ${value}`;
34
+
35
+ return {
36
+ ...params,
37
+ type: formatMessage(params.type),
38
+ params: _.isArray(params.params)
39
+ ? _.flow(_.map(formatParam), _.join(", "))(params.params)
40
+ : params.params,
41
+ };
19
42
  }
43
+
20
44
  return params;
21
45
  };
46
+
22
47
  return (
23
48
  <Feed.Event>
24
49
  <Feed.Content>
25
50
  <Feed.Summary>
26
51
  <Feed.User>{user?.user_name}</Feed.User>{" "}
52
+ {formatMessage(
53
+ header[MESSAGE_ID],
54
+ translateParams(header[MESSAGE_PARAMS])
55
+ )}{" "}
27
56
  <Feed.Date>
28
57
  <Moment locale={locale} date={ts} format="YYYY-MM-DD HH:mm" />
29
58
  </Feed.Date>
@@ -57,7 +86,6 @@ export default function QualityControlEvents() {
57
86
  );
58
87
  const events = data?.data || [];
59
88
  const parsedEvents = useMemo(() => getParsedEvents(events), [events]);
60
-
61
89
  return (
62
90
  <Segment
63
91
  attached="bottom"
@@ -13,7 +13,8 @@ const messages = {
13
13
  ...baseMessages,
14
14
  en: {
15
15
  ...baseMessages.en,
16
- "quality_controls.events.action_created": "<b>{field}</b> created",
16
+ "quality_controls.events.action_created":
17
+ "Name: <b>{name}</b>, Version: <b>{field}</b>",
17
18
  "quality_controls.events.action_field_changed":
18
19
  "<b>{field}</b> changed to {value}",
19
20
  "quality_controls.events.action_dynamic_field_changed":
@@ -22,6 +23,8 @@ const messages = {
22
23
  "quality_controls.events.action_disabled": "Quality control disabled",
23
24
  "quality_controls.events.action_draft_version_created":
24
25
  "Draft version <b>{value}</b> created",
26
+ "quality_controls.events.quality_control_created":
27
+ "created a new draft quality control",
25
28
  },
26
29
  };
27
30
 
@@ -38,7 +41,7 @@ describe("<QualityControlEvents />", () => {
38
41
  data: [
39
42
  {
40
43
  event: "quality_control_created",
41
- payload: { name: "Sample control" },
44
+ payload: { name: "Sample control", version: "1.0" },
42
45
  ts: "2024-01-01T00:00:00Z",
43
46
  user: { user_name: "Jane Doe" },
44
47
  },
@@ -23,6 +23,8 @@ exports[`<QualityControlEvents /> renders parsed events with highlighted fields
23
23
  Jane Doe
24
24
  </a>
25
25
 
26
+ created a new draft quality control
27
+
26
28
  <div
27
29
  class="date"
28
30
  >
@@ -36,10 +38,14 @@ exports[`<QualityControlEvents /> renders parsed events with highlighted fields
36
38
  <div
37
39
  class="text extra"
38
40
  >
41
+ Name:
39
42
  <b>
40
43
  Sample control
41
44
  </b>
42
- created
45
+ , Version:
46
+ <b>
47
+ 1.0
48
+ </b>
43
49
  </div>
44
50
  </div>
45
51
  </div>
@@ -17,10 +17,11 @@ describe("getParsedEvents", () => {
17
17
  {
18
18
  ts: timestamp,
19
19
  user,
20
+ header: [{ id: "quality_controls.events.quality_control_created" }, {}],
20
21
  payload: [
21
22
  [
22
23
  { id: "quality_controls.events.action_created" },
23
- { field: "Control A", b: bold },
24
+ { name: "Control A", field: undefined, b: bold },
24
25
  ],
25
26
  ],
26
27
  },
@@ -48,16 +49,21 @@ describe("getParsedEvents", () => {
48
49
  {
49
50
  ts: timestamp,
50
51
  user,
52
+ header: [
53
+ { id: "quality_controls.events.action_disabled" },
54
+ { b: bold },
55
+ { id: "quality_controls.events.quality_control_updated" },
56
+ {},
57
+ ],
51
58
  payload: [
52
- [{ id: "quality_controls.events.action_disabled" }, { b: bold }],
53
- [
54
- { id: "quality_controls.events.action_field_changed" },
55
- { field: "name", value: "New name", b: bold },
56
- ],
57
59
  [
58
60
  { id: "quality_controls.events.action_dynamic_field_changed" },
59
61
  { field: "threshold", value: 10, b: bold },
60
62
  ],
63
+ [
64
+ { id: "quality_controls.events.action_field_changed" },
65
+ { field: "name", value: "New name", b: bold },
66
+ ],
61
67
  ],
62
68
  },
63
69
  ]);
@@ -77,14 +83,100 @@ describe("getParsedEvents", () => {
77
83
  {
78
84
  ts: timestamp,
79
85
  user,
86
+ header: [
87
+ { id: "quality_controls.events.action_approved" },
88
+ {
89
+ field: "v2",
90
+ lowercase: true,
91
+ value: { id: "quality_control.status.published" },
92
+ b: bold,
93
+ },
94
+ ],
95
+ payload: [],
96
+ },
97
+ ]);
98
+ });
99
+
100
+ it("returns payload for quality_control_updated with empty changes", () => {
101
+ const events = [
102
+ {
103
+ event: "quality_control_updated",
104
+ ts: timestamp,
105
+ user,
106
+ payload: {
107
+ version: "v1",
108
+ changes: {},
109
+ },
110
+ },
111
+ ];
112
+
113
+ expect(getParsedEvents(events)).toEqual([
114
+ {
115
+ ts: timestamp,
116
+ user,
117
+ header: [{ id: "quality_controls.events.quality_control_updated" }, {}],
80
118
  payload: [
81
119
  [
82
- { id: "quality_controls.events.action_approved" },
83
- {
84
- field: "v2",
85
- value: { id: "quality_control.status.published" },
86
- b: bold,
87
- },
120
+ { id: "quality_controls.events.action_updated" },
121
+ { field: "v1", b: bold },
122
+ ],
123
+ ],
124
+ },
125
+ ]);
126
+ });
127
+
128
+ it("returns payload for quality_control_version_draft_updated with empty changes", () => {
129
+ const events = [
130
+ {
131
+ event: "quality_control_version_draft_updated",
132
+ ts: timestamp,
133
+ user,
134
+ payload: {
135
+ version: "v2",
136
+ changes: {},
137
+ },
138
+ },
139
+ ];
140
+
141
+ expect(getParsedEvents(events)).toEqual([
142
+ {
143
+ ts: timestamp,
144
+ user,
145
+ header: [{ id: "quality_controls.events.quality_control_updated" }, {}],
146
+ payload: [
147
+ [
148
+ { id: "quality_controls.events.action_updated" },
149
+ { field: "v2", b: bold },
150
+ ],
151
+ ],
152
+ },
153
+ ]);
154
+ });
155
+
156
+ it("returns empty array for quality_control_updated with non-empty changes", () => {
157
+ const events = [
158
+ {
159
+ event: "quality_control_updated",
160
+ ts: timestamp,
161
+ user,
162
+ payload: {
163
+ version: "v1",
164
+ changes: {
165
+ name: "Updated name",
166
+ },
167
+ },
168
+ },
169
+ ];
170
+
171
+ expect(getParsedEvents(events)).toEqual([
172
+ {
173
+ ts: timestamp,
174
+ user,
175
+ header: [{ id: "quality_controls.events.quality_control_updated" }, {}],
176
+ payload: [
177
+ [
178
+ { id: "quality_controls.events.action_field_changed" },
179
+ { field: "name", value: "Updated name", b: bold },
88
180
  ],
89
181
  ],
90
182
  },
@@ -8,11 +8,18 @@ const normalizeValue = (value) => {
8
8
  return value;
9
9
  };
10
10
 
11
- const getPayloadFromActiveChange = (event) => {
11
+ const getHeaderFromActiveChange = (event) => {
12
12
  if (_.has("payload.changes.active")(event)) {
13
13
  return _.prop("payload.changes.active")(event)
14
- ? [[{ id: "quality_controls.events.action_enabled" }, { b: bold }]]
15
- : [[{ id: "quality_controls.events.action_disabled" }, { b: bold }]];
14
+ ? [{ id: "quality_controls.events.action_enabled" }, { b: bold }]
15
+ : [{ id: "quality_controls.events.action_disabled" }, { b: bold }];
16
+ }
17
+ return [];
18
+ };
19
+
20
+ const getHeaderFromRegularFields = (event) => {
21
+ if (_.has("payload.changes")(event)) {
22
+ return [{ id: "quality_controls.events.quality_control_updated" }, {}];
16
23
  }
17
24
  return [];
18
25
  };
@@ -22,7 +29,7 @@ const getDomainNames = (path) => (event) =>
22
29
 
23
30
  const getPayloadFromDomainChange = (event) => {
24
31
  if (_.has("payload.changes.domains")(event)) {
25
- const domainNames = _.join(", ")(
32
+ const changedDomainNames = _.join(", ")(
26
33
  getDomainNames("payload.changes.domains")(event)
27
34
  );
28
35
  const currentDomainNames = _.join(", ")(
@@ -31,7 +38,74 @@ const getPayloadFromDomainChange = (event) => {
31
38
  return [
32
39
  [
33
40
  { id: "quality_controls.events.action_domain_changed" },
34
- { domainNames, currentDomainNames, b: bold },
41
+ { currentDomainNames, changedDomainNames, b: bold },
42
+ ],
43
+ ];
44
+ }
45
+ return [];
46
+ };
47
+
48
+ const formatScoreCriteriaParams = (type, value) => {
49
+ if (!_.isObject(value) || !type) return [];
50
+
51
+ const paramPairs =
52
+ type === "percentage"
53
+ ? [
54
+ value.goal !== undefined && [
55
+ { id: `quality_control.score_criteria.${type}.goal` },
56
+ value.goal,
57
+ ],
58
+ value.minimum !== undefined && [
59
+ { id: `quality_control.score_criteria.${type}.minimum` },
60
+ value.minimum,
61
+ ],
62
+ ]
63
+ : [
64
+ value.goal !== undefined && [
65
+ { id: `quality_control.score_criteria.${type}.goal` },
66
+ value.goal,
67
+ ],
68
+ value.maximum !== undefined && [
69
+ { id: `quality_control.score_criteria.${type}.maximum` },
70
+ value.maximum,
71
+ ],
72
+ ];
73
+
74
+ return _.compact(paramPairs);
75
+ };
76
+
77
+ const getPayloadFromScoreCriteriaChange = (event) => {
78
+ if (_.has("payload.changes.score_criteria")(event)) {
79
+ return _.flow(
80
+ _.toPairs,
81
+ _.map(([type, value]) => {
82
+ const params = formatScoreCriteriaParams(type, value);
83
+ return [
84
+ { id: "quality_controls.events.action_score_criteria_changed" },
85
+ {
86
+ type: { id: `quality_control.control_mode.${type}` },
87
+ params,
88
+ b: bold,
89
+ },
90
+ ];
91
+ })
92
+ )(event?.payload?.changes?.score_criteria);
93
+ }
94
+ return [];
95
+ };
96
+
97
+ const getPayloadFromControlModeChange = (event) => {
98
+ if (_.has("payload.changes.control_mode")(event)) {
99
+ return [
100
+ [
101
+ { id: "quality_controls.events.action_control_mode_changed" },
102
+ {
103
+ type: {
104
+ id: `quality_control.control_mode.${event?.payload?.changes?.control_mode}`,
105
+ },
106
+ params: [],
107
+ b: bold,
108
+ },
35
109
  ],
36
110
  ];
37
111
  }
@@ -52,12 +126,26 @@ const getPayloadFromDynamicContentChange = (event) => {
52
126
  return [];
53
127
  };
54
128
 
129
+ const getPayloadFromQualityControlVersionUpdate = (event) => {
130
+ if (_.isEmpty(event?.payload?.changes)) {
131
+ return [
132
+ [
133
+ { id: "quality_controls.events.action_updated" },
134
+ { field: event?.payload?.version, b: bold },
135
+ ],
136
+ ];
137
+ }
138
+ return [];
139
+ };
140
+
55
141
  const getPayloadFromRegularFields = (event) => {
56
142
  if (_.has("payload.changes")(event)) {
57
143
  return _.flow(
58
144
  _.omit(["dynamic_content"]),
59
145
  _.omit(["domains"]),
60
146
  _.omit(["active"]),
147
+ _.omit(["score_criteria"]),
148
+ _.omit(["control_mode"]),
61
149
  _.toPairs,
62
150
  _.map(([field, value]) => [
63
151
  { id: "quality_controls.events.action_field_changed" },
@@ -68,18 +156,31 @@ const getPayloadFromRegularFields = (event) => {
68
156
  return [];
69
157
  };
70
158
 
159
+ const getHeaderFromUpdateEvent = (event) => {
160
+ const headerFromActiveChange = getHeaderFromActiveChange(event);
161
+ const headerFromRegularFields = getHeaderFromRegularFields(event);
162
+
163
+ return [...headerFromActiveChange, ...headerFromRegularFields];
164
+ };
165
+
71
166
  const getPayloadFromUpdateEvent = (event) => {
72
- const payloadFromActiveChange = getPayloadFromActiveChange(event);
73
167
  const payloadFromRegularFields = getPayloadFromRegularFields(event);
74
168
  const payloadFromDomainChange = getPayloadFromDomainChange(event);
169
+ const payloadFromScoreCriteriaChange =
170
+ getPayloadFromScoreCriteriaChange(event);
171
+ const payloadFromControlModeChange = getPayloadFromControlModeChange(event);
75
172
  const payloadFromDynamicContentChange =
76
173
  getPayloadFromDynamicContentChange(event);
174
+ const playloadFromQualityControlVersionUpdate =
175
+ getPayloadFromQualityControlVersionUpdate(event);
77
176
 
78
177
  return [
79
- ...payloadFromActiveChange,
80
- ...payloadFromRegularFields,
178
+ ...payloadFromControlModeChange,
179
+ ...payloadFromScoreCriteriaChange,
81
180
  ...payloadFromDomainChange,
82
181
  ...payloadFromDynamicContentChange,
182
+ ...payloadFromRegularFields,
183
+ ...playloadFromQualityControlVersionUpdate,
83
184
  ];
84
185
  };
85
186
 
@@ -90,30 +191,41 @@ const payloadFromEvent = (event) => {
90
191
  case "quality_control_created":
91
192
  return {
92
193
  ...eventBase,
194
+ header: [{ id: "quality_controls.events.quality_control_created" }, {}],
93
195
  payload: [
94
196
  [
95
197
  { id: "quality_controls.events.action_created" },
96
- { field: event?.payload?.name, b: bold },
198
+ {
199
+ name: event?.payload?.name,
200
+ field: event?.payload?.version,
201
+ b: bold,
202
+ },
97
203
  ],
98
204
  ],
99
205
  };
100
206
  case "quality_control_version_status_updated":
101
207
  return {
102
208
  ...eventBase,
103
- payload: [
104
- [
105
- { id: `quality_controls.events.action_${event?.payload?.action}` },
106
- {
107
- field: event?.payload?.version,
108
- value: { id: `quality_control.status.${event?.payload?.status}` },
109
- b: bold,
110
- },
111
- ],
209
+ header: [
210
+ { id: `quality_controls.events.action_${event?.payload?.action}` },
211
+ {
212
+ field: event?.payload?.version,
213
+ value: { id: `quality_control.status.${event?.payload?.status}` },
214
+ lowercase: true,
215
+ b: bold,
216
+ },
112
217
  ],
218
+ payload: [],
113
219
  };
114
220
  case "quality_control_version_draft_created":
115
221
  return {
116
222
  ...eventBase,
223
+ header: [
224
+ {
225
+ id: "quality_controls.events.quality_control_version_draft_created",
226
+ },
227
+ {},
228
+ ],
117
229
  payload: [
118
230
  [
119
231
  { id: "quality_controls.events.action_draft_version_created" },
@@ -122,9 +234,17 @@ const payloadFromEvent = (event) => {
122
234
  ],
123
235
  };
124
236
  case "quality_control_updated":
125
- return { ...eventBase, payload: getPayloadFromUpdateEvent(event) };
237
+ return {
238
+ ...eventBase,
239
+ header: getHeaderFromUpdateEvent(event),
240
+ payload: getPayloadFromUpdateEvent(event),
241
+ };
126
242
  case "quality_control_version_draft_updated":
127
- return { ...eventBase, payload: getPayloadFromUpdateEvent(event) };
243
+ return {
244
+ ...eventBase,
245
+ header: getHeaderFromUpdateEvent(event),
246
+ payload: getPayloadFromUpdateEvent(event),
247
+ };
128
248
  default:
129
249
  return null;
130
250
  }