@webitel/ui-sdk 26.8.56 → 26.8.57
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/dist/clients-B8MJJx6E.js +39958 -0
- package/dist/{components-CWSUHV29.js → components-BWyW5EEY.js} +3 -3
- package/dist/{engineCallFileType.zod-C-t93kQg.js → engineCallFileType-D7QVFOac.js} +1 -1
- package/dist/{generateInstance-C9d7J_TX.js → genClient-HHiOUj56.js} +969 -755
- package/dist/ui-sdk.js +2 -2
- package/dist/ui-sdk.umd.cjs +2056 -2056
- package/dist/{wt-call-media-action-Bn2bGCWs.js → wt-call-media-action-Bkyppnsm.js} +1 -1
- package/dist/{wt-chat-emoji-DRK_E-lD.js → wt-chat-emoji-Cj3B8oR5.js} +1 -1
- package/dist/{wt-display-chip-items-C5z7aCDZ.js → wt-display-chip-items-Cvm5rOYr.js} +1 -1
- package/dist/{wt-screen-recordings-action-Dj6ITuhE.js → wt-screen-recordings-action-DI1qlUi1.js} +1 -1
- package/dist/{wt-send-message-popup-G26F9NPH.js → wt-send-message-popup-OYvzhdyL.js} +2 -2
- package/dist/{wt-type-extension-value-input--Vc1cs5d.js → wt-type-extension-value-input-BfUPxO-s.js} +2 -2
- package/dist/{wt-vidstack-player-FD4gfDSE.js → wt-vidstack-player-DjQEPOTu.js} +1 -1
- package/package.json +6 -2
- package/src/modules/UploadCsvPopup/components/__tests__/wt-upload-csv-popup.spec.js +32 -0
- package/src/modules/UploadCsvPopup/components/wt-upload-csv-popup.vue +15 -26
- package/src/modules/UploadCsvPopup/composable/__tests__/useUploadCsv.spec.js +393 -0
- package/src/modules/UploadCsvPopup/composable/useUploadCsv.ts +36 -19
- package/src/modules/UploadCsvPopup/index.ts +11 -0
- package/src/modules/UploadCsvPopup/scripts/__tests__/normalizeCSVData.spec.js +125 -0
- package/src/modules/UploadCsvPopup/scripts/__tests__/parseCSV.spec.js +63 -0
- package/src/modules/UploadCsvPopup/scripts/normalizeCSVData.ts +2 -0
- package/src/modules/UploadCsvPopup/scripts/parseCSV.ts +0 -23
- package/types/.tsbuildinfo +1 -1
- package/types/api/defaults/getDefaultInstance/getDefaultInstance.d.ts +1 -1
- package/types/modules/UploadCsvPopup/components/__tests__/wt-upload-csv-popup.spec.d.ts +1 -0
- package/types/modules/UploadCsvPopup/components/wt-upload-csv-popup.vue.d.ts +5 -5
- package/types/modules/UploadCsvPopup/composable/__tests__/useUploadCsv.spec.d.ts +1 -0
- package/types/modules/UploadCsvPopup/composable/useUploadCsv.d.ts +7 -3
- package/types/modules/UploadCsvPopup/index.d.ts +5 -0
- package/types/modules/UploadCsvPopup/scripts/__tests__/normalizeCSVData.spec.d.ts +1 -0
- package/types/modules/UploadCsvPopup/scripts/__tests__/parseCSV.spec.d.ts +1 -0
- package/types/modules/UploadCsvPopup/scripts/normalizeCSVData.d.ts +2 -0
- package/dist/clients-CWSXQd89.js +0 -40124
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { computed, type Ref, ref, watch } from 'vue';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useEventBus } from '../../../composables';
|
|
4
|
+
import {
|
|
5
|
+
debounce,
|
|
6
|
+
eventBus as defaultEventBus,
|
|
7
|
+
isEmpty,
|
|
8
|
+
} from '../../../scripts';
|
|
4
9
|
import normalizeCSVData, {
|
|
5
10
|
type CsvDataRow,
|
|
6
11
|
type CsvMappingField,
|
|
@@ -17,12 +22,20 @@ import HandlingCSVMode from '../types/WtUploadCSVHandlingMode.enum';
|
|
|
17
22
|
* @param {import('vue').Ref<boolean>} params.skipHeaders
|
|
18
23
|
* @param {import('vue').Ref<string>} params.separator
|
|
19
24
|
*/
|
|
25
|
+
|
|
26
|
+
export interface UploadCsvParseSettings {
|
|
27
|
+
separator: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
20
30
|
export interface UseUploadCsvProps {
|
|
21
31
|
file?: File | null;
|
|
22
32
|
mappingFields?: CsvMappingField[];
|
|
23
33
|
addBulkItems?: (items: unknown[]) => unknown | Promise<unknown>;
|
|
24
|
-
handlingMode?:
|
|
25
|
-
fileUploadHandler?: (
|
|
34
|
+
handlingMode?: HandlingCSVMode;
|
|
35
|
+
fileUploadHandler?: (
|
|
36
|
+
settings: UploadCsvParseSettings,
|
|
37
|
+
) => unknown | Promise<unknown>;
|
|
38
|
+
charset?: string;
|
|
26
39
|
}
|
|
27
40
|
|
|
28
41
|
interface UseUploadCsvParams {
|
|
@@ -39,11 +52,12 @@ const useUploadCsv = ({
|
|
|
39
52
|
skipHeaders,
|
|
40
53
|
separator,
|
|
41
54
|
}: UseUploadCsvParams) => {
|
|
55
|
+
const eventBus = useEventBus() ?? defaultEventBus;
|
|
56
|
+
|
|
42
57
|
const isReadingFile = ref(false);
|
|
43
58
|
const isParsingCSV = ref(false);
|
|
44
59
|
const parsedFile = ref<unknown>(null);
|
|
45
60
|
const isParsingPreview = ref(false);
|
|
46
|
-
const parseErrorStackTrace = ref<unknown>('');
|
|
47
61
|
const csvPreview = ref<unknown[]>([
|
|
48
62
|
[],
|
|
49
63
|
]);
|
|
@@ -101,15 +115,21 @@ const useUploadCsv = ({
|
|
|
101
115
|
),
|
|
102
116
|
);
|
|
103
117
|
|
|
118
|
+
function notifyError(err: unknown) {
|
|
119
|
+
eventBus.$emit('notification', {
|
|
120
|
+
type: 'error',
|
|
121
|
+
text: err instanceof Error ? err.message : String(err),
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
104
125
|
async function createCSVPreview(file = parsedFile.value) {
|
|
105
126
|
try {
|
|
106
|
-
parseErrorStackTrace.value = '';
|
|
107
127
|
csvPreview.value = await parseCSV(file as string, {
|
|
108
128
|
...parseCSVOptions.value,
|
|
109
129
|
toLine: 4,
|
|
110
130
|
});
|
|
111
131
|
} catch (err) {
|
|
112
|
-
|
|
132
|
+
notifyError(err);
|
|
113
133
|
csvPreview.value = [
|
|
114
134
|
[],
|
|
115
135
|
];
|
|
@@ -138,7 +158,9 @@ const useUploadCsv = ({
|
|
|
138
158
|
|
|
139
159
|
isReadingFile.value = true;
|
|
140
160
|
|
|
141
|
-
parsedFile.value = await processFile(props.file as File, {
|
|
161
|
+
parsedFile.value = await processFile(props.file as File, {
|
|
162
|
+
charset: props.charset,
|
|
163
|
+
});
|
|
142
164
|
await createCSVPreview(parsedFile.value);
|
|
143
165
|
|
|
144
166
|
isReadingFile.value = false;
|
|
@@ -165,20 +187,17 @@ const useUploadCsv = ({
|
|
|
165
187
|
isParsingCSV.value = true;
|
|
166
188
|
|
|
167
189
|
try {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
props.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if (handler) {
|
|
176
|
-
await handler();
|
|
190
|
+
if (props.handlingMode === HandlingCSVMode.PROCESS) {
|
|
191
|
+
await handleCSVProcessing();
|
|
192
|
+
} else {
|
|
193
|
+
await props.fileUploadHandler?.({
|
|
194
|
+
separator: separator.value,
|
|
195
|
+
});
|
|
177
196
|
}
|
|
178
197
|
|
|
179
198
|
close();
|
|
180
199
|
} catch (err) {
|
|
181
|
-
|
|
200
|
+
notifyError(err);
|
|
182
201
|
throw err;
|
|
183
202
|
} finally {
|
|
184
203
|
isParsingCSV.value = false;
|
|
@@ -194,7 +213,6 @@ const useUploadCsv = ({
|
|
|
194
213
|
emit('close');
|
|
195
214
|
}
|
|
196
215
|
|
|
197
|
-
// watchers (те, що були в mixin.watch)
|
|
198
216
|
watch(skipHeaders, async () => {
|
|
199
217
|
await handleParseOptionsChange();
|
|
200
218
|
});
|
|
@@ -214,7 +232,6 @@ const useUploadCsv = ({
|
|
|
214
232
|
isReadingFile,
|
|
215
233
|
isParsingCSV,
|
|
216
234
|
isParsingPreview,
|
|
217
|
-
parseErrorStackTrace,
|
|
218
235
|
csvPreviewTableData,
|
|
219
236
|
csvPreviewTableHeaders,
|
|
220
237
|
filteredCsvPreviewTableHeaders,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { default as WtUploadCsvPopup } from './components/wt-upload-csv-popup.vue';
|
|
2
|
+
export type {
|
|
3
|
+
UploadCsvParseSettings,
|
|
4
|
+
UseUploadCsvProps,
|
|
5
|
+
} from './composable/useUploadCsv';
|
|
6
|
+
export { default as useUploadCsv } from './composable/useUploadCsv';
|
|
7
|
+
export type {
|
|
8
|
+
CsvDataRow,
|
|
9
|
+
CsvMappingField,
|
|
10
|
+
} from './scripts/normalizeCSVData';
|
|
11
|
+
export { HandlingCSVMode } from './types/WtUploadCSVHandlingMode.enum';
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import normalizeCSVData from '../normalizeCSVData';
|
|
2
|
+
|
|
3
|
+
describe('normalizeCSVData', () => {
|
|
4
|
+
const mappings = [
|
|
5
|
+
{
|
|
6
|
+
// webitel field name
|
|
7
|
+
name: 'name',
|
|
8
|
+
// csv column name
|
|
9
|
+
csv: 'col1',
|
|
10
|
+
// is this webitel field required?
|
|
11
|
+
required: true,
|
|
12
|
+
// ui
|
|
13
|
+
locale: '',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'phone',
|
|
17
|
+
csv: [
|
|
18
|
+
'col2',
|
|
19
|
+
'col3',
|
|
20
|
+
],
|
|
21
|
+
required: true,
|
|
22
|
+
},
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
it('normalizes simple data', () => {
|
|
26
|
+
const input = [
|
|
27
|
+
{
|
|
28
|
+
col1: 'John',
|
|
29
|
+
col2: '123',
|
|
30
|
+
col3: '456',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
col1: 'Jane',
|
|
34
|
+
col2: '789',
|
|
35
|
+
col3: '012',
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
const result = normalizeCSVData({
|
|
39
|
+
data: input,
|
|
40
|
+
mappings,
|
|
41
|
+
});
|
|
42
|
+
const output = [
|
|
43
|
+
{
|
|
44
|
+
name: 'John',
|
|
45
|
+
phone: [
|
|
46
|
+
'123',
|
|
47
|
+
'456',
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: 'Jane',
|
|
52
|
+
phone: [
|
|
53
|
+
'789',
|
|
54
|
+
'012',
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
expect(result).toEqual(output);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('throws an error at normalizing data with required (!) empty value', () => {
|
|
62
|
+
const input = [
|
|
63
|
+
{
|
|
64
|
+
col1: '',
|
|
65
|
+
col2: '123',
|
|
66
|
+
col3: '3424',
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
col1: 'name',
|
|
70
|
+
col2: '131312',
|
|
71
|
+
col3: '012',
|
|
72
|
+
},
|
|
73
|
+
];
|
|
74
|
+
try {
|
|
75
|
+
normalizeCSVData({
|
|
76
|
+
data: input,
|
|
77
|
+
mappings,
|
|
78
|
+
});
|
|
79
|
+
} catch (err) {
|
|
80
|
+
expect(err).toBeTruthy();
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
expect(false).toBe(true); // reject test if no error
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it(`returns correct fields for mapping, including empty fields,
|
|
87
|
+
if one of them is empty`, () => {
|
|
88
|
+
const input = [
|
|
89
|
+
{
|
|
90
|
+
col1: 'name',
|
|
91
|
+
col2: '123',
|
|
92
|
+
col3: '',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
col1: 'name',
|
|
96
|
+
col2: '123',
|
|
97
|
+
col3: '012',
|
|
98
|
+
},
|
|
99
|
+
];
|
|
100
|
+
|
|
101
|
+
const result = normalizeCSVData({
|
|
102
|
+
data: input,
|
|
103
|
+
mappings,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const output = [
|
|
107
|
+
{
|
|
108
|
+
name: 'name',
|
|
109
|
+
phone: [
|
|
110
|
+
'123',
|
|
111
|
+
'',
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
name: 'name',
|
|
116
|
+
phone: [
|
|
117
|
+
'123',
|
|
118
|
+
'012',
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
expect(result).toEqual(output);
|
|
124
|
+
});
|
|
125
|
+
});
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import parseCSV from '../parseCSV';
|
|
2
|
+
|
|
3
|
+
describe('parseCSV', () => {
|
|
4
|
+
it('parses a csv into rows keyed by the header', async () => {
|
|
5
|
+
const csv = 'col1,col2\nJohn,30';
|
|
6
|
+
|
|
7
|
+
const result = await parseCSV(csv, {
|
|
8
|
+
columns: true,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
expect(result).toEqual([
|
|
12
|
+
{
|
|
13
|
+
col1: 'John',
|
|
14
|
+
col2: '30',
|
|
15
|
+
},
|
|
16
|
+
]);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/*
|
|
20
|
+
WTEL-10058: the parser used to coerce 'true'/'false' and JSON-looking cells
|
|
21
|
+
for every consumer. Type casting belongs to whoever knows the field types —
|
|
22
|
+
CRM does it in prepareCsvLookupRows. Everything here stays a string.
|
|
23
|
+
*/
|
|
24
|
+
it.each([
|
|
25
|
+
'true',
|
|
26
|
+
'false',
|
|
27
|
+
'[1,2]',
|
|
28
|
+
'{"a":1}',
|
|
29
|
+
'42',
|
|
30
|
+
])('keeps %s as a string', async (value) => {
|
|
31
|
+
const csv = `col1\n"${value.replaceAll('"', '""')}"`;
|
|
32
|
+
|
|
33
|
+
const result = await parseCSV(csv, {
|
|
34
|
+
columns: true,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
expect(result[0].col1).toBe(value);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('respects a custom delimiter', async () => {
|
|
41
|
+
const csv = 'col1;col2\nJohn;30';
|
|
42
|
+
|
|
43
|
+
const result = await parseCSV(csv, {
|
|
44
|
+
columns: true,
|
|
45
|
+
delimiter: ';',
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect(result[0]).toEqual({
|
|
49
|
+
col1: 'John',
|
|
50
|
+
col2: '30',
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('rejects on a malformed csv', async () => {
|
|
55
|
+
const csv = 'col1,col2\n"unterminated,30\nJane,25';
|
|
56
|
+
|
|
57
|
+
await expect(
|
|
58
|
+
parseCSV(csv, {
|
|
59
|
+
columns: true,
|
|
60
|
+
}),
|
|
61
|
+
).rejects.toBeTruthy();
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -6,29 +6,6 @@ const parseCSV = (csvStr: string, options: Options = {}): Promise<unknown[]> =>
|
|
|
6
6
|
csvStr,
|
|
7
7
|
{
|
|
8
8
|
columns: true,
|
|
9
|
-
cast: (value /* context */) => {
|
|
10
|
-
if (typeof value !== 'string') return value;
|
|
11
|
-
|
|
12
|
-
const trimmed = value.trim();
|
|
13
|
-
|
|
14
|
-
// boolean
|
|
15
|
-
if (trimmed === 'true') return true;
|
|
16
|
-
if (trimmed === 'false') return false;
|
|
17
|
-
|
|
18
|
-
// array / object (JSON)
|
|
19
|
-
if (
|
|
20
|
-
(trimmed.startsWith('[') && trimmed.endsWith(']')) ||
|
|
21
|
-
(trimmed.startsWith('{') && trimmed.endsWith('}'))
|
|
22
|
-
) {
|
|
23
|
-
try {
|
|
24
|
-
return JSON.parse(trimmed);
|
|
25
|
-
} catch {
|
|
26
|
-
return value;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return value;
|
|
31
|
-
},
|
|
32
9
|
...options,
|
|
33
10
|
},
|
|
34
11
|
(err, output) => {
|