@truedat/df 8.8.3 → 8.8.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@truedat/df",
3
- "version": "8.8.3",
3
+ "version": "8.8.4",
4
4
  "description": "Truedat Web Data Quality Module",
5
5
  "sideEffects": false,
6
6
  "module": "src/index.js",
@@ -51,14 +51,14 @@
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.8.3",
54
+ "@truedat/test": "8.8.4",
55
55
  "identity-obj-proxy": "^3.0.0",
56
56
  "jest": "^29.7.0",
57
57
  "redux-saga-test-plan": "^4.0.6"
58
58
  },
59
59
  "dependencies": {
60
60
  "@apollo/client": "^3.13.8",
61
- "@truedat/core": "8.8.3",
61
+ "@truedat/core": "8.8.4",
62
62
  "axios": "^1.15.0",
63
63
  "graphql": "^16.11.0",
64
64
  "is-hotkey": "^0.2.0",
@@ -87,5 +87,5 @@
87
87
  "semantic-ui-react": "^3.0.0-beta.2",
88
88
  "swr": "^2.3.3"
89
89
  },
90
- "gitHead": "db057d418d0612dbf385d40c48d5fa6a8258e9ab"
90
+ "gitHead": "eebd748d118e628959e9d935e9ba9baaebe0a8e1"
91
91
  }
@@ -0,0 +1,4 @@
1
+ .template-question-popup {
2
+ width: max-content;
3
+ max-width: 80vw !important;
4
+ }
@@ -58,6 +58,11 @@ exports[`<NewTemplate /> matches the latest snapshot 1`] = `
58
58
  >
59
59
  <label>
60
60
  template.form.name
61
+ <i
62
+ aria-hidden="true"
63
+ class="question circle outline icon"
64
+ style="cursor: pointer; margin-left: 5px;"
65
+ />
61
66
  <div
62
67
  class="ui left pointing label"
63
68
  >
@@ -68,6 +73,7 @@ exports[`<NewTemplate /> matches the latest snapshot 1`] = `
68
73
  class="ui input"
69
74
  >
70
75
  <input
76
+ maxlength="31"
71
77
  name="name"
72
78
  required=""
73
79
  type="text"
@@ -80,6 +86,11 @@ exports[`<NewTemplate /> matches the latest snapshot 1`] = `
80
86
  >
81
87
  <label>
82
88
  template.form.label
89
+ <i
90
+ aria-hidden="true"
91
+ class="question circle outline icon"
92
+ style="cursor: pointer; margin-left: 5px;"
93
+ />
83
94
  <div
84
95
  class="ui left pointing label"
85
96
  >
@@ -90,6 +101,7 @@ exports[`<NewTemplate /> matches the latest snapshot 1`] = `
90
101
  class="ui input"
91
102
  >
92
103
  <input
104
+ maxlength="31"
93
105
  name="label"
94
106
  required=""
95
107
  type="text"
@@ -73,6 +73,11 @@ exports[`<Template /> matches the latest snapshot for empty data 1`] = `
73
73
  >
74
74
  <label>
75
75
  template.form.name
76
+ <i
77
+ aria-hidden="true"
78
+ class="question circle outline icon"
79
+ style="cursor: pointer; margin-left: 5px;"
80
+ />
76
81
  <div
77
82
  class="ui left pointing label"
78
83
  >
@@ -83,6 +88,7 @@ exports[`<Template /> matches the latest snapshot for empty data 1`] = `
83
88
  class="ui input"
84
89
  >
85
90
  <input
91
+ maxlength="31"
86
92
  name="name"
87
93
  readonly=""
88
94
  required=""
@@ -96,6 +102,11 @@ exports[`<Template /> matches the latest snapshot for empty data 1`] = `
96
102
  >
97
103
  <label>
98
104
  template.form.label
105
+ <i
106
+ aria-hidden="true"
107
+ class="question circle outline icon"
108
+ style="cursor: pointer; margin-left: 5px;"
109
+ />
99
110
  <div
100
111
  class="ui left pointing label"
101
112
  >
@@ -106,6 +117,7 @@ exports[`<Template /> matches the latest snapshot for empty data 1`] = `
106
117
  class="ui input"
107
118
  >
108
119
  <input
120
+ maxlength="31"
109
121
  name="label"
110
122
  required=""
111
123
  type="text"
@@ -444,11 +456,17 @@ exports[`<Template /> matches the latest snapshot with previous data 1`] = `
444
456
  >
445
457
  <label>
446
458
  template.form.name
459
+ <i
460
+ aria-hidden="true"
461
+ class="question circle outline icon"
462
+ style="cursor: pointer; margin-left: 5px;"
463
+ />
447
464
  </label>
448
465
  <div
449
466
  class="ui input"
450
467
  >
451
468
  <input
469
+ maxlength="31"
452
470
  name="name"
453
471
  readonly=""
454
472
  required=""
@@ -462,11 +480,17 @@ exports[`<Template /> matches the latest snapshot with previous data 1`] = `
462
480
  >
463
481
  <label>
464
482
  template.form.label
483
+ <i
484
+ aria-hidden="true"
485
+ class="question circle outline icon"
486
+ style="cursor: pointer; margin-left: 5px;"
487
+ />
465
488
  </label>
466
489
  <div
467
490
  class="ui input"
468
491
  >
469
492
  <input
493
+ maxlength="31"
470
494
  name="label"
471
495
  required=""
472
496
  type="text"
@@ -2,7 +2,15 @@ import _ from "lodash/fp";
2
2
  import { useState, useEffect, useCallback } from "react";
3
3
  import PropTypes from "prop-types";
4
4
  import { connect } from "react-redux";
5
- import { Header, Form, Grid, Label, Divider } from "semantic-ui-react";
5
+ import {
6
+ Header,
7
+ Form,
8
+ Grid,
9
+ Icon,
10
+ Label,
11
+ Divider,
12
+ Popup,
13
+ } from "semantic-ui-react";
6
14
  import { useIntl, FormattedMessage } from "react-intl";
7
15
  import { useWebContext } from "@truedat/core/webContext";
8
16
  import GroupsList from "./GroupsList";
@@ -31,6 +39,8 @@ const scopeOptions = (formatMessage) =>
31
39
  "qxe",
32
40
  ]);
33
41
 
42
+ const MAX_LENGTH = 31;
43
+
34
44
  export const TemplateForm = ({ loading, template, onSubmit }) => {
35
45
  const { formatMessage } = useIntl();
36
46
  const { scopesWithRelations = [] } = useWebContext();
@@ -154,10 +164,26 @@ export const TemplateForm = ({ loading, template, onSubmit }) => {
154
164
  <Form.Input
155
165
  name="name"
156
166
  width={6}
167
+ maxLength={MAX_LENGTH}
157
168
  label={
158
169
  <label>
159
170
  {formatMessage({ id: "template.form.name" })}
160
- {isNullOrEmpty(nameValue) ? (
171
+ <Popup
172
+ className="template-question-popup"
173
+ trigger={
174
+ <Icon
175
+ style={{
176
+ cursor: "pointer",
177
+ marginLeft: "5px",
178
+ }}
179
+ name="question circle outline"
180
+ />
181
+ }
182
+ content={<FormattedMessage id="template.form.name.popup" />}
183
+ on="click"
184
+ hideOnScroll
185
+ />
186
+ {isNameEmpty ? (
161
187
  <Label pointing="left">
162
188
  <FormattedMessage id="template.form.validation.empty_required" />
163
189
  </Label>
@@ -172,10 +198,26 @@ export const TemplateForm = ({ loading, template, onSubmit }) => {
172
198
  <Form.Input
173
199
  name="label"
174
200
  width={6}
201
+ maxLength={MAX_LENGTH}
175
202
  label={
176
203
  <label>
177
204
  {formatMessage({ id: "template.form.label" })}
178
- {isNullOrEmpty(labelValue) ? (
205
+ <Popup
206
+ className="template-question-popup"
207
+ trigger={
208
+ <Icon
209
+ style={{
210
+ cursor: "pointer",
211
+ marginLeft: "5px",
212
+ }}
213
+ name="question circle outline"
214
+ />
215
+ }
216
+ content={<FormattedMessage id="template.form.label.popup" />}
217
+ on="click"
218
+ hideOnScroll
219
+ />
220
+ {isLabelEmpty ? (
179
221
  <Label pointing="left">
180
222
  <FormattedMessage id="template.form.validation.empty_required" />
181
223
  </Label>
@@ -194,7 +236,7 @@ export const TemplateForm = ({ loading, template, onSubmit }) => {
194
236
  label={
195
237
  <label>
196
238
  {formatMessage({ id: "template.form.scope" })}
197
- {isNullOrEmpty(scopeValue) ? (
239
+ {isScopeEmpty ? (
198
240
  <Label pointing="left">
199
241
  <FormattedMessage id="template.form.validation.empty_required" />
200
242
  </Label>
@@ -1,6 +1,6 @@
1
1
  import React from "react";
2
2
  import userEvent from "@testing-library/user-event";
3
- import { waitFor } from "@testing-library/react";
3
+ import { fireEvent, waitFor } from "@testing-library/react";
4
4
  import { render, waitForLoad } from "@truedat/test/render";
5
5
  import TemplateForm from "../TemplateForm";
6
6
 
@@ -195,4 +195,108 @@ describe("<TemplateForm />", () => {
195
195
  const submittedPayload = onSubmit.mock.calls[0][0];
196
196
  expect(submittedPayload.template.template_resource_relations).toEqual([]);
197
197
  });
198
+
199
+ it("should limit name input to 31 characters", async () => {
200
+ const user = userEvent.setup({ delay: null });
201
+ const newTemplate = { ...validTemplate, id: undefined, name: "" };
202
+ const renderOpts = {
203
+ state: { templateDeleting: false, templateSaving: false },
204
+ };
205
+ const rendered = render(
206
+ <TemplateForm
207
+ template={newTemplate}
208
+ onSubmit={jest.fn()}
209
+ loading={false}
210
+ />,
211
+ renderOpts,
212
+ );
213
+ const nameInput = rendered
214
+ .getAllByRole("textbox")
215
+ .find((input) => input.name === "name");
216
+
217
+ expect(nameInput).toBeInTheDocument();
218
+ await user.type(nameInput, "a".repeat(40));
219
+ expect(nameInput.value.length).toBeLessThanOrEqual(31);
220
+ expect(nameInput).toHaveAttribute("maxLength", "31");
221
+ });
222
+
223
+ it("should limit label input to 31 characters", async () => {
224
+ const user = userEvent.setup({ delay: null });
225
+ const newTemplate = { ...validTemplate, id: undefined, label: "" };
226
+ const renderOpts = {
227
+ state: { templateDeleting: false, templateSaving: false },
228
+ };
229
+ const rendered = render(
230
+ <TemplateForm
231
+ template={newTemplate}
232
+ onSubmit={jest.fn()}
233
+ loading={false}
234
+ />,
235
+ renderOpts,
236
+ );
237
+ const labelInput = rendered
238
+ .getAllByRole("textbox")
239
+ .find((input) => input.name === "label");
240
+
241
+ expect(labelInput).toBeInTheDocument();
242
+ await user.type(labelInput, "b".repeat(40));
243
+ expect(labelInput.value.length).toBeLessThanOrEqual(31);
244
+ expect(labelInput).toHaveAttribute("maxLength", "31");
245
+ });
246
+
247
+ it("should truncate pasted text in name input to 31 characters", async () => {
248
+ const user = userEvent.setup({ delay: null });
249
+ const renderOpts = {
250
+ state: { templateDeleting: false, templateSaving: false },
251
+ };
252
+ const rendered = render(
253
+ <TemplateForm
254
+ template={validTemplate}
255
+ onSubmit={jest.fn()}
256
+ loading={false}
257
+ />,
258
+ renderOpts,
259
+ );
260
+ const nameInput = rendered
261
+ .getAllByRole("textbox")
262
+ .find((input) => input.name === "name");
263
+
264
+ expect(nameInput).toBeInTheDocument();
265
+ await user.click(nameInput);
266
+ fireEvent.paste(nameInput, {
267
+ clipboardData: {
268
+ getData: () => "x".repeat(50),
269
+ },
270
+ });
271
+ fireEvent.change(nameInput, { target: { value: "x".repeat(50) } });
272
+ expect(nameInput).toHaveAttribute("maxLength", "31");
273
+ });
274
+
275
+ it("should truncate pasted text in label input to 31 characters", async () => {
276
+ const user = userEvent.setup({ delay: null });
277
+ const renderOpts = {
278
+ state: { templateDeleting: false, templateSaving: false },
279
+ };
280
+ const rendered = render(
281
+ <TemplateForm
282
+ template={validTemplate}
283
+ onSubmit={jest.fn()}
284
+ loading={false}
285
+ />,
286
+ renderOpts,
287
+ );
288
+ const labelInput = rendered
289
+ .getAllByRole("textbox")
290
+ .find((input) => input.name === "label");
291
+
292
+ expect(labelInput).toBeInTheDocument();
293
+ await user.click(labelInput);
294
+ fireEvent.paste(labelInput, {
295
+ clipboardData: {
296
+ getData: () => "x".repeat(50),
297
+ },
298
+ });
299
+ fireEvent.change(labelInput, { target: { value: "x".repeat(50) } });
300
+ expect(labelInput).toHaveAttribute("maxLength", "31");
301
+ });
198
302
  });
@@ -22,11 +22,17 @@ exports[`<TemplateForm /> matches snapshot when scope has no relations 1`] = `
22
22
  >
23
23
  <label>
24
24
  template.form.name
25
+ <i
26
+ aria-hidden="true"
27
+ class="question circle outline icon"
28
+ style="cursor: pointer; margin-left: 5px;"
29
+ />
25
30
  </label>
26
31
  <div
27
32
  class="ui input"
28
33
  >
29
34
  <input
35
+ maxlength="31"
30
36
  name="name"
31
37
  readonly=""
32
38
  required=""
@@ -40,11 +46,17 @@ exports[`<TemplateForm /> matches snapshot when scope has no relations 1`] = `
40
46
  >
41
47
  <label>
42
48
  template.form.label
49
+ <i
50
+ aria-hidden="true"
51
+ class="question circle outline icon"
52
+ style="cursor: pointer; margin-left: 5px;"
53
+ />
43
54
  </label>
44
55
  <div
45
56
  class="ui input"
46
57
  >
47
58
  <input
59
+ maxlength="31"
48
60
  name="label"
49
61
  required=""
50
62
  type="text"
@@ -1122,11 +1134,17 @@ exports[`<TemplateForm /> matches snapshot when scope has relations 1`] = `
1122
1134
  >
1123
1135
  <label>
1124
1136
  template.form.name
1137
+ <i
1138
+ aria-hidden="true"
1139
+ class="question circle outline icon"
1140
+ style="cursor: pointer; margin-left: 5px;"
1141
+ />
1125
1142
  </label>
1126
1143
  <div
1127
1144
  class="ui input"
1128
1145
  >
1129
1146
  <input
1147
+ maxlength="31"
1130
1148
  name="name"
1131
1149
  readonly=""
1132
1150
  required=""
@@ -1140,11 +1158,17 @@ exports[`<TemplateForm /> matches snapshot when scope has relations 1`] = `
1140
1158
  >
1141
1159
  <label>
1142
1160
  template.form.label
1161
+ <i
1162
+ aria-hidden="true"
1163
+ class="question circle outline icon"
1164
+ style="cursor: pointer; margin-left: 5px;"
1165
+ />
1143
1166
  </label>
1144
1167
  <div
1145
1168
  class="ui input"
1146
1169
  >
1147
1170
  <input
1171
+ maxlength="31"
1148
1172
  name="label"
1149
1173
  required=""
1150
1174
  type="text"