@truedat/df 8.8.2 → 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 +4 -4
- package/src/styles/templateForm.less +4 -0
- package/src/templates/components/__tests__/__snapshots__/NewTemplate.spec.js.snap +12 -0
- package/src/templates/components/__tests__/__snapshots__/Template.spec.js.snap +24 -0
- package/src/templates/components/templateForm/TemplateForm.js +46 -4
- package/src/templates/components/templateForm/__tests__/TemplateForm.spec.js +105 -1
- package/src/templates/components/templateForm/__tests__/__snapshots__/TemplateForm.spec.js.snap +24 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@truedat/df",
|
|
3
|
-
"version": "8.8.
|
|
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.
|
|
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.
|
|
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": "
|
|
90
|
+
"gitHead": "eebd748d118e628959e9d935e9ba9baaebe0a8e1"
|
|
91
91
|
}
|
|
@@ -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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
{
|
|
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
|
});
|
package/src/templates/components/templateForm/__tests__/__snapshots__/TemplateForm.spec.js.snap
CHANGED
|
@@ -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"
|