@wix/bex-core 2.322.0 → 2.324.0
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/cjs/assets/locale/messages_ar.json +5 -0
- package/dist/cjs/assets/locale/messages_bg.json +5 -0
- package/dist/cjs/assets/locale/messages_ca.json +5 -0
- package/dist/cjs/assets/locale/messages_cs.json +5 -0
- package/dist/cjs/assets/locale/messages_da.json +5 -0
- package/dist/cjs/assets/locale/messages_de.json +5 -0
- package/dist/cjs/assets/locale/messages_el.json +5 -0
- package/dist/cjs/assets/locale/messages_en.json +5 -0
- package/dist/cjs/assets/locale/messages_es.json +5 -0
- package/dist/cjs/assets/locale/messages_fi.json +5 -0
- package/dist/cjs/assets/locale/messages_fr.json +5 -0
- package/dist/cjs/assets/locale/messages_he.json +5 -0
- package/dist/cjs/assets/locale/messages_hi.json +5 -0
- package/dist/cjs/assets/locale/messages_hu.json +5 -0
- package/dist/cjs/assets/locale/messages_id.json +5 -0
- package/dist/cjs/assets/locale/messages_it.json +5 -0
- package/dist/cjs/assets/locale/messages_ja.json +5 -0
- package/dist/cjs/assets/locale/messages_ko.json +5 -0
- package/dist/cjs/assets/locale/messages_lt.json +5 -0
- package/dist/cjs/assets/locale/messages_ms.json +5 -0
- package/dist/cjs/assets/locale/messages_nl.json +5 -0
- package/dist/cjs/assets/locale/messages_no.json +5 -0
- package/dist/cjs/assets/locale/messages_pl.json +5 -0
- package/dist/cjs/assets/locale/messages_pt.json +5 -0
- package/dist/cjs/assets/locale/messages_ro.json +5 -0
- package/dist/cjs/assets/locale/messages_ru.json +5 -0
- package/dist/cjs/assets/locale/messages_sk.json +5 -0
- package/dist/cjs/assets/locale/messages_sl.json +5 -0
- package/dist/cjs/assets/locale/messages_sv.json +5 -0
- package/dist/cjs/assets/locale/messages_th.json +5 -0
- package/dist/cjs/assets/locale/messages_tl.json +5 -0
- package/dist/cjs/assets/locale/messages_tr.json +5 -0
- package/dist/cjs/assets/locale/messages_uk.json +5 -0
- package/dist/cjs/assets/locale/messages_vi.json +5 -0
- package/dist/cjs/assets/locale/messages_zh.json +5 -0
- package/dist/cjs/assets/locale/version_file +1 -1
- package/dist/cjs/assets/visual-e2e-locale/messages_visuale2e.json +7 -2
- package/dist/cjs/hooks/useImport.js +6 -2
- package/dist/cjs/hooks/useImport.js.map +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/services/translations.js.map +1 -1
- package/dist/cjs/state/ImportState/ImportState.js +123 -13
- package/dist/cjs/state/ImportState/ImportState.js.map +1 -1
- package/dist/cjs/state/ImportState/parseCsv.js +4 -0
- package/dist/cjs/state/ImportState/parseCsv.js.map +1 -1
- package/dist/cjs/state/SetupWidgetState.js +15 -0
- package/dist/cjs/state/SetupWidgetState.js.map +1 -1
- package/dist/cjs/types/Field.js.map +1 -1
- package/dist/cjs/types/Schema.js +4 -0
- package/dist/cjs/types/Schema.js.map +1 -0
- package/dist/esm/assets/locale/messages_ar.json +5 -0
- package/dist/esm/assets/locale/messages_bg.json +5 -0
- package/dist/esm/assets/locale/messages_ca.json +5 -0
- package/dist/esm/assets/locale/messages_cs.json +5 -0
- package/dist/esm/assets/locale/messages_da.json +5 -0
- package/dist/esm/assets/locale/messages_de.json +5 -0
- package/dist/esm/assets/locale/messages_el.json +5 -0
- package/dist/esm/assets/locale/messages_en.json +5 -0
- package/dist/esm/assets/locale/messages_es.json +5 -0
- package/dist/esm/assets/locale/messages_fi.json +5 -0
- package/dist/esm/assets/locale/messages_fr.json +5 -0
- package/dist/esm/assets/locale/messages_he.json +5 -0
- package/dist/esm/assets/locale/messages_hi.json +5 -0
- package/dist/esm/assets/locale/messages_hu.json +5 -0
- package/dist/esm/assets/locale/messages_id.json +5 -0
- package/dist/esm/assets/locale/messages_it.json +5 -0
- package/dist/esm/assets/locale/messages_ja.json +5 -0
- package/dist/esm/assets/locale/messages_ko.json +5 -0
- package/dist/esm/assets/locale/messages_lt.json +5 -0
- package/dist/esm/assets/locale/messages_ms.json +5 -0
- package/dist/esm/assets/locale/messages_nl.json +5 -0
- package/dist/esm/assets/locale/messages_no.json +5 -0
- package/dist/esm/assets/locale/messages_pl.json +5 -0
- package/dist/esm/assets/locale/messages_pt.json +5 -0
- package/dist/esm/assets/locale/messages_ro.json +5 -0
- package/dist/esm/assets/locale/messages_ru.json +5 -0
- package/dist/esm/assets/locale/messages_sk.json +5 -0
- package/dist/esm/assets/locale/messages_sl.json +5 -0
- package/dist/esm/assets/locale/messages_sv.json +5 -0
- package/dist/esm/assets/locale/messages_th.json +5 -0
- package/dist/esm/assets/locale/messages_tl.json +5 -0
- package/dist/esm/assets/locale/messages_tr.json +5 -0
- package/dist/esm/assets/locale/messages_uk.json +5 -0
- package/dist/esm/assets/locale/messages_vi.json +5 -0
- package/dist/esm/assets/locale/messages_zh.json +5 -0
- package/dist/esm/assets/locale/version_file +1 -1
- package/dist/esm/assets/visual-e2e-locale/messages_visuale2e.json +7 -2
- package/dist/esm/hooks/useImport.js +4 -1
- package/dist/esm/hooks/useImport.js.map +1 -1
- package/dist/esm/state/ImportState/ImportState.js +110 -12
- package/dist/esm/state/ImportState/ImportState.js.map +1 -1
- package/dist/esm/state/ImportState/parseCsv.js +3 -0
- package/dist/esm/state/ImportState/parseCsv.js.map +1 -1
- package/dist/esm/state/SetupWidgetState.js +14 -0
- package/dist/esm/state/SetupWidgetState.js.map +1 -1
- package/dist/esm/types/Schema.js +2 -0
- package/dist/esm/types/Schema.js.map +1 -0
- package/dist/types/hooks/useImport.d.ts.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/services/translations.d.ts +11 -1
- package/dist/types/services/translations.d.ts.map +1 -1
- package/dist/types/state/ImportState/ImportState.d.ts +15 -0
- package/dist/types/state/ImportState/ImportState.d.ts.map +1 -1
- package/dist/types/state/ImportState/parseCsv.d.ts +1 -0
- package/dist/types/state/ImportState/parseCsv.d.ts.map +1 -1
- package/dist/types/state/SetupWidgetState.d.ts +11 -0
- package/dist/types/state/SetupWidgetState.d.ts.map +1 -1
- package/dist/types/types/Field.d.ts +4 -0
- package/dist/types/types/Field.d.ts.map +1 -1
- package/dist/types/types/Schema.d.ts +103 -0
- package/dist/types/types/Schema.d.ts.map +1 -0
- package/package.json +4 -4
|
@@ -10,6 +10,12 @@ var _ConditionalModalState = require("../ConditionalModalState");
|
|
|
10
10
|
var _parseCsv = require("./parseCsv");
|
|
11
11
|
var _set = _interopRequireDefault(require("lodash/set"));
|
|
12
12
|
const DEFAULT_BATCH_SIZE = 100;
|
|
13
|
+
|
|
14
|
+
// How long to keep the completed progress bar (100%) on screen before closing
|
|
15
|
+
// the modal on a clean import. Without it, an import of very few rows finishes
|
|
16
|
+
// near-instantly and the modal appears to vanish without ever showing the bar
|
|
17
|
+
// reaching completion.
|
|
18
|
+
const COMPLETION_LINGER_MS = 600;
|
|
13
19
|
function normalize(value) {
|
|
14
20
|
return value.trim().toLowerCase();
|
|
15
21
|
}
|
|
@@ -36,6 +42,7 @@ class ImportState {
|
|
|
36
42
|
(0, _defineProperty2.default)(this, "translate", void 0);
|
|
37
43
|
(0, _defineProperty2.default)(this, "errorHandler", void 0);
|
|
38
44
|
(0, _defineProperty2.default)(this, "showToast", void 0);
|
|
45
|
+
(0, _defineProperty2.default)(this, "downloadCsv", void 0);
|
|
39
46
|
(0, _defineProperty2.default)(this, "batchSize", void 0);
|
|
40
47
|
(0, _defineProperty2.default)(this, "discardChangesModal", new _ConditionalModalState.ConditionalModalState());
|
|
41
48
|
(0, _defineProperty2.default)(this, "currentStep", 'upload');
|
|
@@ -58,6 +65,11 @@ class ImportState {
|
|
|
58
65
|
(0, _defineProperty2.default)(this, "restoreFn", null);
|
|
59
66
|
(0, _defineProperty2.default)(this, "_cancelled", false);
|
|
60
67
|
(0, _defineProperty2.default)(this, "_abortController", null);
|
|
68
|
+
// Global indices (into `csvRows`) of every row that was not imported: rows
|
|
69
|
+
// the server rejected via a batch's returned `errors`, plus — when a batch
|
|
70
|
+
// throws after some rows succeeded — the throwing batch and all un-attempted
|
|
71
|
+
// rows. Offered to the user as a downloadable CSV via the partial toast.
|
|
72
|
+
(0, _defineProperty2.default)(this, "_failedRowIndices", []);
|
|
61
73
|
this.fields = props.fields ?? [];
|
|
62
74
|
this.bulkUploadItems = props.bulkUploadItems;
|
|
63
75
|
this.backup = props.backup;
|
|
@@ -66,6 +78,7 @@ class ImportState {
|
|
|
66
78
|
this.translate = props.translate;
|
|
67
79
|
this.errorHandler = props.errorHandler;
|
|
68
80
|
this.showToast = props.showToast;
|
|
81
|
+
this.downloadCsv = props.downloadCsv;
|
|
69
82
|
this.batchSize = props.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
70
83
|
(0, _mobx.makeObservable)(this, {
|
|
71
84
|
currentStep: _mobx.observable.ref,
|
|
@@ -81,6 +94,7 @@ class ImportState {
|
|
|
81
94
|
isRestoring: _mobx.observable.ref,
|
|
82
95
|
hasParsedRows: _mobx.computed,
|
|
83
96
|
hasMappings: _mobx.computed,
|
|
97
|
+
hasNoMappedData: _mobx.computed,
|
|
84
98
|
selectedFieldIds: _mobx.computed,
|
|
85
99
|
mappedRows: _mobx.computed,
|
|
86
100
|
onUploadContinue: _mobx.action.bound,
|
|
@@ -101,6 +115,26 @@ class ImportState {
|
|
|
101
115
|
get hasMappings() {
|
|
102
116
|
return Object.values(this.mappingByHeader).some(value => value != null);
|
|
103
117
|
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* True when there are mappings but none of the mapped columns contain any
|
|
121
|
+
* data in any row (including the case of zero data rows). Drives the
|
|
122
|
+
* non-blocking "no rows found" warning in the configuration step. Returns
|
|
123
|
+
* false when nothing is mapped yet — that case is handled by the disabled
|
|
124
|
+
* import button instead.
|
|
125
|
+
*/
|
|
126
|
+
get hasNoMappedData() {
|
|
127
|
+
if (!this.hasMappings) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
const mappedIndices = this.csvHeaders.reduce((indices, header, index) => {
|
|
131
|
+
if (this.mappingByHeader[header] != null) {
|
|
132
|
+
indices.push(index);
|
|
133
|
+
}
|
|
134
|
+
return indices;
|
|
135
|
+
}, []);
|
|
136
|
+
return !this.csvRows.some(row => mappedIndices.some(index => (row[index] ?? '').trim() !== ''));
|
|
137
|
+
}
|
|
104
138
|
get selectedFieldIds() {
|
|
105
139
|
return new Set(Object.values(this.mappingByHeader).filter(v => v != null));
|
|
106
140
|
}
|
|
@@ -130,6 +164,7 @@ class ImportState {
|
|
|
130
164
|
this.isRestoring = false;
|
|
131
165
|
this.restoreFn = null;
|
|
132
166
|
this._cancelled = false;
|
|
167
|
+
this._failedRowIndices = [];
|
|
133
168
|
}
|
|
134
169
|
async close() {
|
|
135
170
|
if (this.currentStep === 'progress') {
|
|
@@ -279,6 +314,28 @@ class ImportState {
|
|
|
279
314
|
}
|
|
280
315
|
});
|
|
281
316
|
}
|
|
317
|
+
_showPartialSuccessToast() {
|
|
318
|
+
var _this$showToast3;
|
|
319
|
+
const failed = this._failedRowIndices.length;
|
|
320
|
+
(_this$showToast3 = this.showToast) == null || _this$showToast3.call(this, {
|
|
321
|
+
type: 'WARNING',
|
|
322
|
+
message: this.translate('cairo.import.partialSuccessToast', {
|
|
323
|
+
failed: String(failed),
|
|
324
|
+
imported: String(this.totalCount - failed)
|
|
325
|
+
}),
|
|
326
|
+
action: {
|
|
327
|
+
text: this.translate('cairo.import.downloadFailedRows'),
|
|
328
|
+
onClick: () => this._downloadFailedRows(),
|
|
329
|
+
removeToastOnClick: true
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
_downloadFailedRows() {
|
|
334
|
+
var _this$downloadCsv;
|
|
335
|
+
const failedRows = this._failedRowIndices.map(index => this.csvRows[index]);
|
|
336
|
+
const content = (0, _parseCsv.unparseCsv)(this.csvHeaders, failedRows);
|
|
337
|
+
(_this$downloadCsv = this.downloadCsv) == null || _this$downloadCsv.call(this, content, `failed-${this.fileName || 'import.csv'}`);
|
|
338
|
+
}
|
|
282
339
|
setMapping(header, fieldId) {
|
|
283
340
|
this.mappingByHeader = {
|
|
284
341
|
...this.mappingByHeader,
|
|
@@ -287,23 +344,44 @@ class ImportState {
|
|
|
287
344
|
}
|
|
288
345
|
async _uploadBatches(batches) {
|
|
289
346
|
let processedRows = 0;
|
|
347
|
+
let receivedOkResponse = false;
|
|
348
|
+
const failedRowIndices = [];
|
|
290
349
|
for (const batch of batches) {
|
|
291
350
|
if (this._cancelled) {
|
|
292
351
|
break;
|
|
293
352
|
}
|
|
353
|
+
const batchStart = processedRows;
|
|
294
354
|
try {
|
|
295
355
|
const batchResult = await this.bulkUploadItems(batch);
|
|
356
|
+
receivedOkResponse = true;
|
|
296
357
|
this.result = {
|
|
297
358
|
succeeded: this.result.succeeded + batchResult.succeeded,
|
|
298
359
|
failed: this.result.failed + batchResult.failed,
|
|
299
360
|
errors: [...this.result.errors, ...batchResult.errors]
|
|
300
361
|
};
|
|
362
|
+
|
|
363
|
+
// Rows the server rejected within an otherwise-OK response. `rowIndex`
|
|
364
|
+
// is relative to the batch, so offset it to a global `csvRows` index.
|
|
365
|
+
for (const {
|
|
366
|
+
rowIndex
|
|
367
|
+
} of batchResult.errors) {
|
|
368
|
+
failedRowIndices.push(batchStart + rowIndex);
|
|
369
|
+
}
|
|
301
370
|
} catch (error) {
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
371
|
+
// Full batch failure: a batch threw before any OK response came back.
|
|
372
|
+
// Surface it as an error state with a "Try again" action by rejecting
|
|
373
|
+
// up to `startImport`, instead of reporting a partial success.
|
|
374
|
+
if (!receivedOkResponse) {
|
|
375
|
+
throw error;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// A batch threw after some rows were already imported. Every row from
|
|
379
|
+
// the throwing batch onward (including the batches we won't attempt)
|
|
380
|
+
// counts as failed, on top of any rows already rejected via returned
|
|
381
|
+
// errors in earlier batches.
|
|
382
|
+
for (let index = batchStart; index < this.totalCount; index++) {
|
|
383
|
+
failedRowIndices.push(index);
|
|
384
|
+
}
|
|
307
385
|
break;
|
|
308
386
|
}
|
|
309
387
|
processedRows += batch.length;
|
|
@@ -311,6 +389,7 @@ class ImportState {
|
|
|
311
389
|
this.processedCount = Math.min(processedRows, this.totalCount);
|
|
312
390
|
});
|
|
313
391
|
}
|
|
392
|
+
this._failedRowIndices = failedRowIndices;
|
|
314
393
|
return this.result;
|
|
315
394
|
}
|
|
316
395
|
async _runBackup() {
|
|
@@ -344,6 +423,9 @@ class ImportState {
|
|
|
344
423
|
});
|
|
345
424
|
return false;
|
|
346
425
|
}
|
|
426
|
+
_lingerOnCompletion() {
|
|
427
|
+
return new Promise(resolve => setTimeout(resolve, COMPLETION_LINGER_MS));
|
|
428
|
+
}
|
|
347
429
|
_createRowsBatches(rows) {
|
|
348
430
|
return rows.reduce((acc, row, index) => {
|
|
349
431
|
if (index % this.batchSize === 0) {
|
|
@@ -367,6 +449,17 @@ class ImportState {
|
|
|
367
449
|
this.totalCount = totalCount;
|
|
368
450
|
this.processedCount = 0;
|
|
369
451
|
this.isBackingUp = !!this.backup;
|
|
452
|
+
// Clear any error/result from a previous attempt so "Try again" starts
|
|
453
|
+
// from a clean slate (e.g. after a backup failure).
|
|
454
|
+
this.importStatus = {
|
|
455
|
+
..._model.queryStatus.idle
|
|
456
|
+
};
|
|
457
|
+
this.result = {
|
|
458
|
+
succeeded: 0,
|
|
459
|
+
failed: 0,
|
|
460
|
+
errors: []
|
|
461
|
+
};
|
|
462
|
+
this._failedRowIndices = [];
|
|
370
463
|
});
|
|
371
464
|
const backupFailed = await this._runBackup();
|
|
372
465
|
if (backupFailed) {
|
|
@@ -379,20 +472,37 @@ class ImportState {
|
|
|
379
472
|
};
|
|
380
473
|
try {
|
|
381
474
|
await promise;
|
|
475
|
+
if (this._cancelled) {
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
382
478
|
(0, _mobx.runInAction)(() => {
|
|
383
|
-
if (this._cancelled) {
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
479
|
this.importStatus = {
|
|
387
480
|
..._model.queryStatus.success,
|
|
388
481
|
data: this.result
|
|
389
482
|
};
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
// On a clean import, hold the completed (100%) progress bar on screen
|
|
486
|
+
// briefly so the completion is perceptible even for very few rows. Skip
|
|
487
|
+
// the wait when there are failed rows — that path closes and surfaces a
|
|
488
|
+
// toast instead.
|
|
489
|
+
if (this._failedRowIndices.length === 0) {
|
|
490
|
+
await this._lingerOnCompletion();
|
|
491
|
+
if (this._cancelled) {
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
(0, _mobx.runInAction)(() => {
|
|
496
|
+
// Any rows that didn't make it in — whether rejected via a batch's
|
|
497
|
+
// returned `errors` or left unimported when a batch threw — are
|
|
498
|
+
// reported via a toast that offers them as a downloadable CSV.
|
|
499
|
+
if (this._failedRowIndices.length > 0) {
|
|
500
|
+
this._showPartialSuccessToast();
|
|
395
501
|
}
|
|
502
|
+
this.importModalState.close();
|
|
503
|
+
this.collection.clearResultAndMoveToStart({
|
|
504
|
+
force: true
|
|
505
|
+
});
|
|
396
506
|
});
|
|
397
507
|
} catch (error) {
|
|
398
508
|
(0, _mobx.runInAction)(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_mobx","require","_model","_ConditionalModalState","_parseCsv","_set","_interopRequireDefault","DEFAULT_BATCH_SIZE","normalize","value","trim","toLowerCase","toMappedRows","rows","headers","mappingByHeader","map","row","mapped","forEach","header","index","mappedField","set","ImportState","constructor","props","_defineProperty2","default","ConditionalModalState","queryStatus","idle","succeeded","failed","errors","fields","bulkUploadItems","backup","collection","importModalState","translate","errorHandler","showToast","batchSize","makeObservable","currentStep","observable","ref","importStatus","fileName","csvHeaders","csvRows","processedCount","totalCount","result","isBackingUp","isRestoring","hasParsedRows","computed","hasMappings","selectedFieldIds","mappedRows","onUploadContinue","action","bound","goToUpload","setMapping","close","onFileSelected","startImport","reset","init","undefined","length","Object","values","some","Set","filter","v","_this$_abortControlle","_abortController","abort","restoreFn","_cancelled","_this$_abortControlle2","_restoreBackup","clearResultAndMoveToStart","force","restoreController","AbortController","signal","error","console","runInAction","discardAndGoBack","discardChangesModal","open","modal","promise","discardAndClose","getDefaultMapping","mapping","field","id","normalizedHeader","matched","find","applyParsedCsv","parsedCsv","file","bytes","_readFileBytes","_showFileReadErrorToast","content","_decodeUtf8","_rejectFile","parseCsv","name","arrayBuffer","e","TextDecoder","fatal","decode","messageKey","_this$showToast","call","type","message","_this$showToast2","text","onClick","removeToastOnClick","fieldId","_uploadBatches","batches","processedRows","batch","batchResult","Math","min","_runBackup","restore","_createRowsBatches","reduce","acc","push","backupFailed","loading","success","data","exports"],"sources":["../../../../src/state/ImportState/ImportState.ts"],"sourcesContent":["import {\n action,\n computed,\n makeObservable,\n observable,\n runInAction,\n} from 'mobx';\nimport {\n queryStatus,\n ShowToast,\n TaskStatus,\n PatternsErrorHandler,\n} from '../../model';\nimport { Translate, TranslationsKeys } from '../../services';\nimport { ModalState } from '../ModalState';\nimport { ConditionalModalState } from '../ConditionalModalState';\nimport { CreateExportAsyncJobRequest } from '@wix/bex-utils/@wix/ambassador-fedinfra-exportservice-v1-export-async-job/types';\nimport { ParseCsvResult, parseCsv } from './parseCsv';\nimport set from 'lodash/set';\n\nexport interface ImportCollection {\n clearResultAndMoveToStart(params?: { force?: boolean }): void;\n}\n\nexport interface BulkUploadError {\n rowIndex: number;\n message?: string;\n code?: string;\n}\n\nexport interface BulkUploadResults {\n succeeded: number;\n failed: number;\n errors: BulkUploadError[];\n insertedIds?: string[];\n}\n\nexport type BulkUploadItemsFn = (\n items: Record<string, unknown>[],\n) => Promise<BulkUploadResults>;\n\nexport interface BackupResult {\n restore(signal: AbortSignal): Promise<void>;\n}\n\nexport type BackupFn = (signal: AbortSignal) => Promise<BackupResult | void>;\n\nexport type ImportField = NonNullable<\n CreateExportAsyncJobRequest['fields']\n>[number];\n\nexport interface ImportStateProps {\n fields: CreateExportAsyncJobRequest['fields'];\n bulkUploadItems: BulkUploadItemsFn;\n backup?: BackupFn;\n collection: ImportCollection;\n importModalState: ModalState;\n translate: Translate;\n errorHandler: PatternsErrorHandler;\n showToast?: ShowToast;\n batchSize?: number;\n}\n\nexport type ImportStep = 'upload' | 'configuration' | 'progress';\n\nconst DEFAULT_BATCH_SIZE = 100;\n\nfunction normalize(value: string) {\n return value.trim().toLowerCase();\n}\n\nfunction toMappedRows(\n rows: string[][],\n headers: string[],\n mappingByHeader: Record<string, string | null | undefined>,\n) {\n return rows.map((row) => {\n const mapped: Record<string, unknown> = {};\n\n headers.forEach((header, index) => {\n const mappedField = mappingByHeader[header];\n if (mappedField == null) {\n return;\n }\n\n set(mapped, mappedField, row[index] ?? '');\n });\n\n return mapped;\n });\n}\n\nexport class ImportState {\n readonly fields: ImportField[];\n readonly bulkUploadItems: BulkUploadItemsFn;\n readonly backup?: BackupFn;\n readonly collection: ImportCollection;\n readonly importModalState: ModalState;\n readonly translate: Translate;\n readonly errorHandler: PatternsErrorHandler;\n readonly showToast?: ShowToast;\n readonly batchSize: number;\n readonly discardChangesModal = new ConditionalModalState<'goBack' | 'close'>();\n\n currentStep: ImportStep = 'upload';\n importStatus: TaskStatus<BulkUploadResults, unknown> = {\n ...queryStatus.idle,\n };\n fileName = '';\n csvHeaders: string[] = [];\n csvRows: string[][] = [];\n mappingByHeader: Record<string, string | null> = {};\n processedCount = 0;\n totalCount = 0;\n result: BulkUploadResults = {\n succeeded: 0,\n failed: 0,\n errors: [],\n };\n isBackingUp = false;\n isRestoring = false;\n private restoreFn: ((signal: AbortSignal) => Promise<void>) | null = null;\n private _cancelled = false;\n private _abortController: AbortController | null = null;\n\n constructor(props: ImportStateProps) {\n this.fields = (props.fields ?? []) as ImportField[];\n this.bulkUploadItems = props.bulkUploadItems;\n this.backup = props.backup;\n this.collection = props.collection;\n this.importModalState = props.importModalState;\n this.translate = props.translate;\n this.errorHandler = props.errorHandler;\n this.showToast = props.showToast;\n this.batchSize = props.batchSize ?? DEFAULT_BATCH_SIZE;\n\n makeObservable(this, {\n currentStep: observable.ref,\n importStatus: observable.ref,\n fileName: observable.ref,\n csvHeaders: observable.ref,\n csvRows: observable.ref,\n mappingByHeader: observable.ref,\n processedCount: observable.ref,\n totalCount: observable.ref,\n result: observable.ref,\n isBackingUp: observable.ref,\n isRestoring: observable.ref,\n hasParsedRows: computed,\n hasMappings: computed,\n selectedFieldIds: computed,\n mappedRows: computed,\n onUploadContinue: action.bound,\n goToUpload: action.bound,\n setMapping: action.bound,\n close: action.bound,\n onFileSelected: action.bound,\n startImport: action.bound,\n reset: action.bound,\n });\n }\n\n init() {\n return () => undefined;\n }\n\n get hasParsedRows() {\n return this.csvHeaders.length > 0 && this.csvRows.length > 0;\n }\n\n get hasMappings() {\n return Object.values(this.mappingByHeader).some((value) => value != null);\n }\n\n get selectedFieldIds(): Set<string> {\n return new Set(\n Object.values(this.mappingByHeader).filter(\n (v): v is string => v != null,\n ),\n );\n }\n\n get mappedRows() {\n return toMappedRows(this.csvRows, this.csvHeaders, this.mappingByHeader);\n }\n\n reset() {\n this._abortController?.abort();\n this._abortController = null;\n this.currentStep = 'upload';\n this.importStatus = {\n ...queryStatus.idle,\n };\n this.fileName = '';\n this.csvHeaders = [];\n this.csvRows = [];\n this.mappingByHeader = {};\n this.processedCount = 0;\n this.totalCount = 0;\n this.result = {\n succeeded: 0,\n failed: 0,\n errors: [],\n };\n this.isBackingUp = false;\n this.isRestoring = false;\n this.restoreFn = null;\n this._cancelled = false;\n }\n\n async close() {\n if (this.currentStep === 'progress') {\n this._cancelled = true;\n this._abortController?.abort();\n\n if (!this.isBackingUp) {\n await this._restoreBackup();\n }\n\n this.collection.clearResultAndMoveToStart({\n force: true,\n });\n }\n\n this.importModalState.close();\n }\n\n private async _restoreBackup() {\n const restoreFn = this.restoreFn;\n if (!restoreFn) {\n return;\n }\n\n const restoreController = new AbortController();\n this._abortController = restoreController;\n\n this.isRestoring = true;\n try {\n await restoreFn(restoreController.signal);\n } catch (error) {\n console.error('Restore failed', error);\n }\n runInAction(() => {\n this.isRestoring = false;\n this.restoreFn = null;\n });\n }\n\n goToUpload() {\n this.currentStep = 'upload';\n }\n\n async discardAndGoBack() {\n this.discardChangesModal.open('goBack');\n const { result } = await this.discardChangesModal.modal.promise();\n if (result === 'confirmed') {\n this.goToUpload();\n }\n }\n\n async discardAndClose() {\n this.discardChangesModal.open('close');\n const { result } = await this.discardChangesModal.modal.promise();\n if (result === 'confirmed') {\n this.close();\n }\n }\n\n onUploadContinue() {\n if (this.hasParsedRows) {\n this.currentStep = 'configuration';\n }\n }\n\n private getDefaultMapping(headers: string[]) {\n const mapping: Record<string, string | null> = {};\n const fields = this.fields.map((field) => ({\n id: field.id ?? '',\n header: field.header ?? '',\n }));\n\n headers.forEach((header) => {\n const normalizedHeader = normalize(header);\n const matched = fields.find(\n (field) =>\n normalize(field.id) === normalizedHeader ||\n normalize(field.header) === normalizedHeader,\n );\n\n mapping[header] = matched?.id || null;\n });\n\n return mapping;\n }\n\n private applyParsedCsv(fileName: string, parsedCsv: ParseCsvResult) {\n this.fileName = fileName;\n this.csvHeaders = parsedCsv.headers;\n this.csvRows = parsedCsv.rows;\n this.mappingByHeader = this.getDefaultMapping(parsedCsv.headers);\n this.currentStep = 'configuration';\n }\n\n async onFileSelected(file: File | null) {\n if (file == null) {\n return;\n }\n\n const bytes = await this._readFileBytes(file);\n if (bytes == null) {\n this._showFileReadErrorToast(file);\n return;\n }\n\n const content = this._decodeUtf8(bytes);\n if (content == null) {\n this._rejectFile(file, 'cairo.import.encodingFailed');\n return;\n }\n\n const parsedCsv = parseCsv(content);\n if ('code' in parsedCsv) {\n this._rejectFile(file, 'cairo.import.processFailed');\n return;\n }\n\n runInAction(() => {\n this.applyParsedCsv(file.name, parsedCsv);\n });\n }\n\n private async _readFileBytes(file: File): Promise<ArrayBuffer | null> {\n try {\n return await file.arrayBuffer();\n } catch (e) {\n console.error(e);\n return null;\n }\n }\n\n private _decodeUtf8(bytes: ArrayBuffer): string | null {\n try {\n // `fatal: true` throws on any byte sequence that isn't valid UTF-8,\n // so encoding is validated against the raw bytes before decoding —\n // unlike `File.text()`, which silently substitutes U+FFFD.\n return new TextDecoder('utf-8', { fatal: true }).decode(bytes);\n } catch (e) {\n console.error(e);\n return null;\n }\n }\n\n private _rejectFile(file: File, messageKey: TranslationsKeys) {\n runInAction(() => {\n this.fileName = file.name;\n this.csvHeaders = [];\n this.csvRows = [];\n this.mappingByHeader = {};\n this.currentStep = 'upload';\n });\n this.showToast?.({\n type: 'ERROR',\n message: this.translate(messageKey),\n });\n }\n\n private _showFileReadErrorToast(file: File) {\n this.showToast?.({\n type: 'ERROR',\n message: this.translate('cairo.import.fileReadFailed'),\n action: {\n text: this.translate('cairo.import.tryAgain'),\n onClick: () => this.onFileSelected(file),\n removeToastOnClick: true,\n },\n });\n }\n\n setMapping(header: string, fieldId: string | null) {\n this.mappingByHeader = {\n ...this.mappingByHeader,\n [header]: fieldId,\n };\n }\n\n private async _uploadBatches(batches: Record<string, unknown>[][]) {\n let processedRows = 0;\n\n for (const batch of batches) {\n if (this._cancelled) {\n break;\n }\n\n try {\n const batchResult = await this.bulkUploadItems(batch);\n\n this.result = {\n succeeded: this.result.succeeded + batchResult.succeeded,\n failed: this.result.failed + batchResult.failed,\n errors: [...this.result.errors, ...batchResult.errors],\n };\n } catch (error) {\n this.result = {\n succeeded: this.result.succeeded,\n failed: this.result.failed + batch.length,\n errors: this.result.errors,\n };\n\n break;\n }\n\n processedRows += batch.length;\n\n runInAction(() => {\n this.processedCount = Math.min(processedRows, this.totalCount);\n });\n }\n\n return this.result;\n }\n\n private async _runBackup(): Promise<boolean> {\n const backup = this.backup;\n if (!backup) {\n return false;\n }\n\n try {\n const result = await backup(this._abortController!.signal);\n if (this._cancelled) {\n return true;\n }\n if (result?.restore) {\n this.restoreFn = result.restore;\n }\n } catch (error) {\n if (this._cancelled) {\n return true;\n }\n runInAction(() => {\n this.isBackingUp = false;\n this.importStatus = {\n ...queryStatus.error,\n error,\n };\n });\n return true;\n }\n\n runInAction(() => {\n this.isBackingUp = false;\n });\n return false;\n }\n\n private _createRowsBatches(rows: Record<string, unknown>[]) {\n return rows.reduce<Record<string, unknown>[][]>((acc, row, index) => {\n if (index % this.batchSize === 0) {\n acc.push([]);\n }\n acc[acc.length - 1].push(row);\n return acc;\n }, []);\n }\n\n async startImport() {\n if (!this.hasMappings) {\n return;\n }\n\n this._cancelled = false;\n this._abortController = new AbortController();\n\n const rows = this.mappedRows;\n const totalCount = rows.length;\n const batches = this._createRowsBatches(rows);\n\n runInAction(() => {\n this.currentStep = 'progress';\n this.totalCount = totalCount;\n this.processedCount = 0;\n this.isBackingUp = !!this.backup;\n });\n\n const backupFailed = await this._runBackup();\n if (backupFailed) {\n return;\n }\n\n const promise = this._uploadBatches(batches);\n\n this.importStatus = {\n ...queryStatus.loading,\n promise,\n };\n\n try {\n await promise;\n runInAction(() => {\n if (this._cancelled) {\n return;\n }\n\n this.importStatus = {\n ...queryStatus.success,\n data: this.result,\n };\n\n if (this.result.failed === 0) {\n this.importModalState.close();\n this.collection.clearResultAndMoveToStart({ force: true });\n }\n });\n } catch (error) {\n runInAction(() => {\n this.importStatus = {\n ...queryStatus.error,\n error,\n };\n });\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["_mobx","require","_model","_ConditionalModalState","_parseCsv","_set","_interopRequireDefault","DEFAULT_BATCH_SIZE","COMPLETION_LINGER_MS","normalize","value","trim","toLowerCase","toMappedRows","rows","headers","mappingByHeader","map","row","mapped","forEach","header","index","mappedField","set","ImportState","constructor","props","_defineProperty2","default","ConditionalModalState","queryStatus","idle","succeeded","failed","errors","fields","bulkUploadItems","backup","collection","importModalState","translate","errorHandler","showToast","downloadCsv","batchSize","makeObservable","currentStep","observable","ref","importStatus","fileName","csvHeaders","csvRows","processedCount","totalCount","result","isBackingUp","isRestoring","hasParsedRows","computed","hasMappings","hasNoMappedData","selectedFieldIds","mappedRows","onUploadContinue","action","bound","goToUpload","setMapping","close","onFileSelected","startImport","reset","init","undefined","length","Object","values","some","mappedIndices","reduce","indices","push","Set","filter","v","_this$_abortControlle","_abortController","abort","restoreFn","_cancelled","_failedRowIndices","_this$_abortControlle2","_restoreBackup","clearResultAndMoveToStart","force","restoreController","AbortController","signal","error","console","runInAction","discardAndGoBack","discardChangesModal","open","modal","promise","discardAndClose","getDefaultMapping","mapping","field","id","normalizedHeader","matched","find","applyParsedCsv","parsedCsv","file","bytes","_readFileBytes","_showFileReadErrorToast","content","_decodeUtf8","_rejectFile","parseCsv","name","arrayBuffer","e","TextDecoder","fatal","decode","messageKey","_this$showToast","call","type","message","_this$showToast2","text","onClick","removeToastOnClick","_showPartialSuccessToast","_this$showToast3","String","imported","_downloadFailedRows","_this$downloadCsv","failedRows","unparseCsv","fieldId","_uploadBatches","batches","processedRows","receivedOkResponse","failedRowIndices","batch","batchStart","batchResult","rowIndex","Math","min","_runBackup","restore","_lingerOnCompletion","Promise","resolve","setTimeout","_createRowsBatches","acc","backupFailed","loading","success","data","exports"],"sources":["../../../../src/state/ImportState/ImportState.ts"],"sourcesContent":["import {\n action,\n computed,\n makeObservable,\n observable,\n runInAction,\n} from 'mobx';\nimport {\n queryStatus,\n ShowToast,\n TaskStatus,\n PatternsErrorHandler,\n} from '../../model';\nimport { Translate, TranslationsKeys } from '../../services';\nimport { ModalState } from '../ModalState';\nimport { ConditionalModalState } from '../ConditionalModalState';\nimport { CreateExportAsyncJobRequest } from '@wix/bex-utils/@wix/ambassador-fedinfra-exportservice-v1-export-async-job/types';\nimport { ParseCsvResult, parseCsv, unparseCsv } from './parseCsv';\nimport set from 'lodash/set';\n\nexport interface ImportCollection {\n clearResultAndMoveToStart(params?: { force?: boolean }): void;\n}\n\nexport interface BulkUploadError {\n rowIndex: number;\n message?: string;\n code?: string;\n}\n\nexport interface BulkUploadResults {\n succeeded: number;\n failed: number;\n errors: BulkUploadError[];\n insertedIds?: string[];\n}\n\nexport type BulkUploadItemsFn = (\n items: Record<string, unknown>[],\n) => Promise<BulkUploadResults>;\n\nexport interface BackupResult {\n restore(signal: AbortSignal): Promise<void>;\n}\n\nexport type BackupFn = (signal: AbortSignal) => Promise<BackupResult | void>;\n\nexport type DownloadCsvFn = (content: string, fileName: string) => void;\n\nexport type ImportField = NonNullable<\n CreateExportAsyncJobRequest['fields']\n>[number];\n\nexport interface ImportStateProps {\n fields: CreateExportAsyncJobRequest['fields'];\n bulkUploadItems: BulkUploadItemsFn;\n backup?: BackupFn;\n collection: ImportCollection;\n importModalState: ModalState;\n translate: Translate;\n errorHandler: PatternsErrorHandler;\n showToast?: ShowToast;\n downloadCsv?: DownloadCsvFn;\n batchSize?: number;\n}\n\nexport type ImportStep = 'upload' | 'configuration' | 'progress';\n\nconst DEFAULT_BATCH_SIZE = 100;\n\n// How long to keep the completed progress bar (100%) on screen before closing\n// the modal on a clean import. Without it, an import of very few rows finishes\n// near-instantly and the modal appears to vanish without ever showing the bar\n// reaching completion.\nconst COMPLETION_LINGER_MS = 600;\n\nfunction normalize(value: string) {\n return value.trim().toLowerCase();\n}\n\nfunction toMappedRows(\n rows: string[][],\n headers: string[],\n mappingByHeader: Record<string, string | null | undefined>,\n) {\n return rows.map((row) => {\n const mapped: Record<string, unknown> = {};\n\n headers.forEach((header, index) => {\n const mappedField = mappingByHeader[header];\n if (mappedField == null) {\n return;\n }\n\n set(mapped, mappedField, row[index] ?? '');\n });\n\n return mapped;\n });\n}\n\nexport class ImportState {\n readonly fields: ImportField[];\n readonly bulkUploadItems: BulkUploadItemsFn;\n readonly backup?: BackupFn;\n readonly collection: ImportCollection;\n readonly importModalState: ModalState;\n readonly translate: Translate;\n readonly errorHandler: PatternsErrorHandler;\n readonly showToast?: ShowToast;\n readonly downloadCsv?: DownloadCsvFn;\n readonly batchSize: number;\n readonly discardChangesModal = new ConditionalModalState<\n 'goBack' | 'close'\n >();\n\n currentStep: ImportStep = 'upload';\n importStatus: TaskStatus<BulkUploadResults, unknown> = {\n ...queryStatus.idle,\n };\n fileName = '';\n csvHeaders: string[] = [];\n csvRows: string[][] = [];\n mappingByHeader: Record<string, string | null> = {};\n processedCount = 0;\n totalCount = 0;\n result: BulkUploadResults = {\n succeeded: 0,\n failed: 0,\n errors: [],\n };\n isBackingUp = false;\n isRestoring = false;\n private restoreFn: ((signal: AbortSignal) => Promise<void>) | null = null;\n private _cancelled = false;\n private _abortController: AbortController | null = null;\n // Global indices (into `csvRows`) of every row that was not imported: rows\n // the server rejected via a batch's returned `errors`, plus — when a batch\n // throws after some rows succeeded — the throwing batch and all un-attempted\n // rows. Offered to the user as a downloadable CSV via the partial toast.\n private _failedRowIndices: number[] = [];\n\n constructor(props: ImportStateProps) {\n this.fields = (props.fields ?? []) as ImportField[];\n this.bulkUploadItems = props.bulkUploadItems;\n this.backup = props.backup;\n this.collection = props.collection;\n this.importModalState = props.importModalState;\n this.translate = props.translate;\n this.errorHandler = props.errorHandler;\n this.showToast = props.showToast;\n this.downloadCsv = props.downloadCsv;\n this.batchSize = props.batchSize ?? DEFAULT_BATCH_SIZE;\n\n makeObservable(this, {\n currentStep: observable.ref,\n importStatus: observable.ref,\n fileName: observable.ref,\n csvHeaders: observable.ref,\n csvRows: observable.ref,\n mappingByHeader: observable.ref,\n processedCount: observable.ref,\n totalCount: observable.ref,\n result: observable.ref,\n isBackingUp: observable.ref,\n isRestoring: observable.ref,\n hasParsedRows: computed,\n hasMappings: computed,\n hasNoMappedData: computed,\n selectedFieldIds: computed,\n mappedRows: computed,\n onUploadContinue: action.bound,\n goToUpload: action.bound,\n setMapping: action.bound,\n close: action.bound,\n onFileSelected: action.bound,\n startImport: action.bound,\n reset: action.bound,\n });\n }\n\n init() {\n return () => undefined;\n }\n\n get hasParsedRows() {\n return this.csvHeaders.length > 0 && this.csvRows.length > 0;\n }\n\n get hasMappings() {\n return Object.values(this.mappingByHeader).some((value) => value != null);\n }\n\n /**\n * True when there are mappings but none of the mapped columns contain any\n * data in any row (including the case of zero data rows). Drives the\n * non-blocking \"no rows found\" warning in the configuration step. Returns\n * false when nothing is mapped yet — that case is handled by the disabled\n * import button instead.\n */\n get hasNoMappedData(): boolean {\n if (!this.hasMappings) {\n return false;\n }\n\n const mappedIndices = this.csvHeaders.reduce<number[]>(\n (indices, header, index) => {\n if (this.mappingByHeader[header] != null) {\n indices.push(index);\n }\n return indices;\n },\n [],\n );\n\n return !this.csvRows.some((row) =>\n mappedIndices.some((index) => (row[index] ?? '').trim() !== ''),\n );\n }\n\n get selectedFieldIds(): Set<string> {\n return new Set(\n Object.values(this.mappingByHeader).filter((v): v is string => v != null),\n );\n }\n\n get mappedRows() {\n return toMappedRows(this.csvRows, this.csvHeaders, this.mappingByHeader);\n }\n\n reset() {\n this._abortController?.abort();\n this._abortController = null;\n this.currentStep = 'upload';\n this.importStatus = {\n ...queryStatus.idle,\n };\n this.fileName = '';\n this.csvHeaders = [];\n this.csvRows = [];\n this.mappingByHeader = {};\n this.processedCount = 0;\n this.totalCount = 0;\n this.result = {\n succeeded: 0,\n failed: 0,\n errors: [],\n };\n this.isBackingUp = false;\n this.isRestoring = false;\n this.restoreFn = null;\n this._cancelled = false;\n this._failedRowIndices = [];\n }\n\n async close() {\n if (this.currentStep === 'progress') {\n this._cancelled = true;\n this._abortController?.abort();\n\n if (!this.isBackingUp) {\n await this._restoreBackup();\n }\n\n this.collection.clearResultAndMoveToStart({\n force: true,\n });\n }\n\n this.importModalState.close();\n }\n\n private async _restoreBackup() {\n const restoreFn = this.restoreFn;\n if (!restoreFn) {\n return;\n }\n\n const restoreController = new AbortController();\n this._abortController = restoreController;\n\n this.isRestoring = true;\n try {\n await restoreFn(restoreController.signal);\n } catch (error) {\n console.error('Restore failed', error);\n }\n runInAction(() => {\n this.isRestoring = false;\n this.restoreFn = null;\n });\n }\n\n goToUpload() {\n this.currentStep = 'upload';\n }\n\n async discardAndGoBack() {\n this.discardChangesModal.open('goBack');\n const { result } = await this.discardChangesModal.modal.promise();\n if (result === 'confirmed') {\n this.goToUpload();\n }\n }\n\n async discardAndClose() {\n this.discardChangesModal.open('close');\n const { result } = await this.discardChangesModal.modal.promise();\n if (result === 'confirmed') {\n this.close();\n }\n }\n\n onUploadContinue() {\n if (this.hasParsedRows) {\n this.currentStep = 'configuration';\n }\n }\n\n private getDefaultMapping(headers: string[]) {\n const mapping: Record<string, string | null> = {};\n const fields = this.fields.map((field) => ({\n id: field.id ?? '',\n header: field.header ?? '',\n }));\n\n headers.forEach((header) => {\n const normalizedHeader = normalize(header);\n const matched = fields.find(\n (field) =>\n normalize(field.id) === normalizedHeader ||\n normalize(field.header) === normalizedHeader,\n );\n\n mapping[header] = matched?.id || null;\n });\n\n return mapping;\n }\n\n private applyParsedCsv(fileName: string, parsedCsv: ParseCsvResult) {\n this.fileName = fileName;\n this.csvHeaders = parsedCsv.headers;\n this.csvRows = parsedCsv.rows;\n this.mappingByHeader = this.getDefaultMapping(parsedCsv.headers);\n this.currentStep = 'configuration';\n }\n\n async onFileSelected(file: File | null) {\n if (file == null) {\n return;\n }\n\n const bytes = await this._readFileBytes(file);\n if (bytes == null) {\n this._showFileReadErrorToast(file);\n return;\n }\n\n const content = this._decodeUtf8(bytes);\n if (content == null) {\n this._rejectFile(file, 'cairo.import.encodingFailed');\n return;\n }\n\n const parsedCsv = parseCsv(content);\n if ('code' in parsedCsv) {\n this._rejectFile(file, 'cairo.import.processFailed');\n return;\n }\n\n runInAction(() => {\n this.applyParsedCsv(file.name, parsedCsv);\n });\n }\n\n private async _readFileBytes(file: File): Promise<ArrayBuffer | null> {\n try {\n return await file.arrayBuffer();\n } catch (e) {\n console.error(e);\n return null;\n }\n }\n\n private _decodeUtf8(bytes: ArrayBuffer): string | null {\n try {\n // `fatal: true` throws on any byte sequence that isn't valid UTF-8,\n // so encoding is validated against the raw bytes before decoding —\n // unlike `File.text()`, which silently substitutes U+FFFD.\n return new TextDecoder('utf-8', { fatal: true }).decode(bytes);\n } catch (e) {\n console.error(e);\n return null;\n }\n }\n\n private _rejectFile(file: File, messageKey: TranslationsKeys) {\n runInAction(() => {\n this.fileName = file.name;\n this.csvHeaders = [];\n this.csvRows = [];\n this.mappingByHeader = {};\n this.currentStep = 'upload';\n });\n this.showToast?.({\n type: 'ERROR',\n message: this.translate(messageKey),\n });\n }\n\n private _showFileReadErrorToast(file: File) {\n this.showToast?.({\n type: 'ERROR',\n message: this.translate('cairo.import.fileReadFailed'),\n action: {\n text: this.translate('cairo.import.tryAgain'),\n onClick: () => this.onFileSelected(file),\n removeToastOnClick: true,\n },\n });\n }\n\n private _showPartialSuccessToast() {\n const failed = this._failedRowIndices.length;\n this.showToast?.({\n type: 'WARNING',\n message: this.translate('cairo.import.partialSuccessToast', {\n failed: String(failed),\n imported: String(this.totalCount - failed),\n }),\n action: {\n text: this.translate('cairo.import.downloadFailedRows'),\n onClick: () => this._downloadFailedRows(),\n removeToastOnClick: true,\n },\n });\n }\n\n private _downloadFailedRows() {\n const failedRows = this._failedRowIndices.map(\n (index) => this.csvRows[index],\n );\n const content = unparseCsv(this.csvHeaders, failedRows);\n this.downloadCsv?.(content, `failed-${this.fileName || 'import.csv'}`);\n }\n\n setMapping(header: string, fieldId: string | null) {\n this.mappingByHeader = {\n ...this.mappingByHeader,\n [header]: fieldId,\n };\n }\n\n private async _uploadBatches(batches: Record<string, unknown>[][]) {\n let processedRows = 0;\n let receivedOkResponse = false;\n const failedRowIndices: number[] = [];\n\n for (const batch of batches) {\n if (this._cancelled) {\n break;\n }\n\n const batchStart = processedRows;\n\n try {\n const batchResult = await this.bulkUploadItems(batch);\n receivedOkResponse = true;\n\n this.result = {\n succeeded: this.result.succeeded + batchResult.succeeded,\n failed: this.result.failed + batchResult.failed,\n errors: [...this.result.errors, ...batchResult.errors],\n };\n\n // Rows the server rejected within an otherwise-OK response. `rowIndex`\n // is relative to the batch, so offset it to a global `csvRows` index.\n for (const { rowIndex } of batchResult.errors) {\n failedRowIndices.push(batchStart + rowIndex);\n }\n } catch (error) {\n // Full batch failure: a batch threw before any OK response came back.\n // Surface it as an error state with a \"Try again\" action by rejecting\n // up to `startImport`, instead of reporting a partial success.\n if (!receivedOkResponse) {\n throw error;\n }\n\n // A batch threw after some rows were already imported. Every row from\n // the throwing batch onward (including the batches we won't attempt)\n // counts as failed, on top of any rows already rejected via returned\n // errors in earlier batches.\n for (let index = batchStart; index < this.totalCount; index++) {\n failedRowIndices.push(index);\n }\n\n break;\n }\n\n processedRows += batch.length;\n\n runInAction(() => {\n this.processedCount = Math.min(processedRows, this.totalCount);\n });\n }\n\n this._failedRowIndices = failedRowIndices;\n\n return this.result;\n }\n\n private async _runBackup(): Promise<boolean> {\n const backup = this.backup;\n if (!backup) {\n return false;\n }\n\n try {\n const result = await backup(this._abortController!.signal);\n if (this._cancelled) {\n return true;\n }\n if (result?.restore) {\n this.restoreFn = result.restore;\n }\n } catch (error) {\n if (this._cancelled) {\n return true;\n }\n runInAction(() => {\n this.isBackingUp = false;\n this.importStatus = {\n ...queryStatus.error,\n error,\n };\n });\n return true;\n }\n\n runInAction(() => {\n this.isBackingUp = false;\n });\n return false;\n }\n\n private _lingerOnCompletion() {\n return new Promise<void>((resolve) =>\n setTimeout(resolve, COMPLETION_LINGER_MS),\n );\n }\n\n private _createRowsBatches(rows: Record<string, unknown>[]) {\n return rows.reduce<Record<string, unknown>[][]>((acc, row, index) => {\n if (index % this.batchSize === 0) {\n acc.push([]);\n }\n acc[acc.length - 1].push(row);\n return acc;\n }, []);\n }\n\n async startImport() {\n if (!this.hasMappings) {\n return;\n }\n\n this._cancelled = false;\n this._abortController = new AbortController();\n\n const rows = this.mappedRows;\n const totalCount = rows.length;\n const batches = this._createRowsBatches(rows);\n\n runInAction(() => {\n this.currentStep = 'progress';\n this.totalCount = totalCount;\n this.processedCount = 0;\n this.isBackingUp = !!this.backup;\n // Clear any error/result from a previous attempt so \"Try again\" starts\n // from a clean slate (e.g. after a backup failure).\n this.importStatus = { ...queryStatus.idle };\n this.result = {\n succeeded: 0,\n failed: 0,\n errors: [],\n };\n this._failedRowIndices = [];\n });\n\n const backupFailed = await this._runBackup();\n if (backupFailed) {\n return;\n }\n\n const promise = this._uploadBatches(batches);\n\n this.importStatus = {\n ...queryStatus.loading,\n promise,\n };\n\n try {\n await promise;\n if (this._cancelled) {\n return;\n }\n\n runInAction(() => {\n this.importStatus = {\n ...queryStatus.success,\n data: this.result,\n };\n });\n\n // On a clean import, hold the completed (100%) progress bar on screen\n // briefly so the completion is perceptible even for very few rows. Skip\n // the wait when there are failed rows — that path closes and surfaces a\n // toast instead.\n if (this._failedRowIndices.length === 0) {\n await this._lingerOnCompletion();\n if (this._cancelled) {\n return;\n }\n }\n\n runInAction(() => {\n // Any rows that didn't make it in — whether rejected via a batch's\n // returned `errors` or left unimported when a batch threw — are\n // reported via a toast that offers them as a downloadable CSV.\n if (this._failedRowIndices.length > 0) {\n this._showPartialSuccessToast();\n }\n\n this.importModalState.close();\n this.collection.clearResultAndMoveToStart({ force: true });\n });\n } catch (error) {\n runInAction(() => {\n this.importStatus = {\n ...queryStatus.error,\n error,\n };\n });\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
4
|
exports.__esModule = true;
|
|
5
5
|
exports.parseCsv = parseCsv;
|
|
6
|
+
exports.unparseCsv = unparseCsv;
|
|
6
7
|
var _papaparse = _interopRequireDefault(require("papaparse"));
|
|
7
8
|
function parseCsv(content) {
|
|
8
9
|
const result = _papaparse.default.parse(content, {
|
|
@@ -27,4 +28,7 @@ function parseCsv(content) {
|
|
|
27
28
|
rows
|
|
28
29
|
};
|
|
29
30
|
}
|
|
31
|
+
function unparseCsv(headers, rows) {
|
|
32
|
+
return _papaparse.default.unparse([headers, ...rows]);
|
|
33
|
+
}
|
|
30
34
|
//# sourceMappingURL=parseCsv.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_papaparse","_interopRequireDefault","require","parseCsv","content","result","Papa","parse","skipEmptyLines","errors","length","code","data","headers","rows","slice","filter","row","some","cell","String","trim"],"sources":["../../../../src/state/ImportState/parseCsv.ts"],"sourcesContent":["import Papa from 'papaparse';\n\nexport interface ParseCsvResult {\n headers: string[];\n rows: string[][];\n}\n\nexport interface ParseCsvError {\n code: 'PARSE_ERROR';\n}\n\nexport function parseCsv(content: string): ParseCsvResult | ParseCsvError {\n const result = Papa.parse<string[]>(content, {\n skipEmptyLines: true,\n });\n\n if (result.errors.length > 0) {\n return {\n code: 'PARSE_ERROR',\n };\n }\n\n const data = result.data;\n if (!data || data.length === 0) {\n return { headers: [], rows: [] };\n }\n\n const headers = data[0];\n const rows = data\n .slice(1)\n .filter((row) => row.some((cell) => String(cell).trim() !== ''));\n\n return { headers, rows };\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"names":["_papaparse","_interopRequireDefault","require","parseCsv","content","result","Papa","parse","skipEmptyLines","errors","length","code","data","headers","rows","slice","filter","row","some","cell","String","trim","unparseCsv","unparse"],"sources":["../../../../src/state/ImportState/parseCsv.ts"],"sourcesContent":["import Papa from 'papaparse';\n\nexport interface ParseCsvResult {\n headers: string[];\n rows: string[][];\n}\n\nexport interface ParseCsvError {\n code: 'PARSE_ERROR';\n}\n\nexport function parseCsv(content: string): ParseCsvResult | ParseCsvError {\n const result = Papa.parse<string[]>(content, {\n skipEmptyLines: true,\n });\n\n if (result.errors.length > 0) {\n return {\n code: 'PARSE_ERROR',\n };\n }\n\n const data = result.data;\n if (!data || data.length === 0) {\n return { headers: [], rows: [] };\n }\n\n const headers = data[0];\n const rows = data\n .slice(1)\n .filter((row) => row.some((cell) => String(cell).trim() !== ''));\n\n return { headers, rows };\n}\n\nexport function unparseCsv(headers: string[], rows: string[][]): string {\n return Papa.unparse([headers, ...rows]);\n}\n"],"mappings":";;;;;;AAAA,IAAAA,UAAA,GAAAC,sBAAA,CAAAC,OAAA;AAWO,SAASC,QAAQA,CAACC,OAAe,EAAkC;EACxE,MAAMC,MAAM,GAAGC,kBAAI,CAACC,KAAK,CAAWH,OAAO,EAAE;IAC3CI,cAAc,EAAE;EAClB,CAAC,CAAC;EAEF,IAAIH,MAAM,CAACI,MAAM,CAACC,MAAM,GAAG,CAAC,EAAE;IAC5B,OAAO;MACLC,IAAI,EAAE;IACR,CAAC;EACH;EAEA,MAAMC,IAAI,GAAGP,MAAM,CAACO,IAAI;EACxB,IAAI,CAACA,IAAI,IAAIA,IAAI,CAACF,MAAM,KAAK,CAAC,EAAE;IAC9B,OAAO;MAAEG,OAAO,EAAE,EAAE;MAAEC,IAAI,EAAE;IAAG,CAAC;EAClC;EAEA,MAAMD,OAAO,GAAGD,IAAI,CAAC,CAAC,CAAC;EACvB,MAAME,IAAI,GAAGF,IAAI,CACdG,KAAK,CAAC,CAAC,CAAC,CACRC,MAAM,CAAEC,GAAG,IAAKA,GAAG,CAACC,IAAI,CAAEC,IAAI,IAAKC,MAAM,CAACD,IAAI,CAAC,CAACE,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;EAElE,OAAO;IAAER,OAAO;IAAEC;EAAK,CAAC;AAC1B;AAEO,SAASQ,UAAUA,CAACT,OAAiB,EAAEC,IAAgB,EAAU;EACtE,OAAOR,kBAAI,CAACiB,OAAO,CAAC,CAACV,OAAO,EAAE,GAAGC,IAAI,CAAC,CAAC;AACzC","ignoreList":[]}
|
|
@@ -59,6 +59,7 @@ class SetupWidgetState {
|
|
|
59
59
|
_isAllComplete: _mobx.computed,
|
|
60
60
|
_primaryStepId: _mobx.computed,
|
|
61
61
|
_expandedStepId: _mobx.computed,
|
|
62
|
+
_focusedStepId: _mobx.computed,
|
|
62
63
|
seedFromData: _mobx.action.bound,
|
|
63
64
|
setStepStatus: _mobx.action.bound,
|
|
64
65
|
_toggleStep: _mobx.action.bound,
|
|
@@ -248,6 +249,20 @@ class SetupWidgetState {
|
|
|
248
249
|
return (primary == null ? void 0 : primary.expansionMode) === 'inline' ? primary.id : null;
|
|
249
250
|
}
|
|
250
251
|
|
|
252
|
+
/**
|
|
253
|
+
* @internal The single focused (highlighted) step. Production keeps focus and
|
|
254
|
+
* inline-expansion unified in one `focusedStepId`, so only ever one step is
|
|
255
|
+
* highlighted; here `_primaryStepId` (recommended next) and `_expandedStepId`
|
|
256
|
+
* (what the user toggled open) are separate, and can diverge once the user
|
|
257
|
+
* opens a non-primary inline step. Collapsing them to a single id — the
|
|
258
|
+
* expanded step when one is open, otherwise the primary — preserves the
|
|
259
|
+
* single-focus invariant (avoids highlighting both the primary and the
|
|
260
|
+
* expanded row).
|
|
261
|
+
*/
|
|
262
|
+
get _focusedStepId() {
|
|
263
|
+
return this._expandedStepId ?? this._primaryStepId;
|
|
264
|
+
}
|
|
265
|
+
|
|
251
266
|
// ---- Public write API ----
|
|
252
267
|
|
|
253
268
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_mobx","require","_TaskState","SetupWidgetState","constructor","params","_defineProperty2","default","TaskState","container","fetchData","makeObservable","seededSteps","observable","ref","seededTitle","focusedStepId","userToggled","isRefreshing","steps","computed","_title","_isLoading","_isError","_leafSteps","_completedCount","_totalCount","_progressPercentage","_isAllComplete","_primaryStepId","_expandedStepId","seedFromData","action","bound","setStepStatus","_toggleStep","_retry","refresh","init","load","disposeSeed","reaction","_loadTask","status","data","fireImmediately","runOnce","Promise","all","initTask","promise","error","onError","reset","latestRefresh","runInAction","internalMonitor","reportError","title","getStep","id","find","step","inChild","undefined","isIdle","isLoading","isError","flatMap","_step$steps","length","filter","Math","round","_this$seededSteps$fin","_this$seededSteps$fin2","primary","expansionMode","wasExpanded","update","map","currentlyExpanded","exports"],"sources":["../../../src/state/SetupWidgetState.ts"],"sourcesContent":["import {\n action,\n computed,\n makeObservable,\n observable,\n reaction,\n runInAction,\n} from 'mobx';\nimport { WixPatternsContainer } from './WixPatternsContainer';\nimport { TaskState } from './TaskState';\nimport {\n SetupWidgetData,\n SetupWidgetStep,\n SetupWidgetStepStatus,\n} from '../model/setupWidget';\n\nexport interface SetupWidgetStateParams {\n readonly container: WixPatternsContainer;\n /** Consumer-supplied data resolver. The widget owns loading / error state. */\n readonly fetchData: () => Promise<SetupWidgetData>;\n}\n\n/**\n * State for the Setup widget, created via the `useSetupWidget` hook and passed\n * to the `SetupWidget` component (the same shape as `useCollection` →\n * `CollectionState`).\n *\n * Owns the async lifecycle via {@link TaskState}, seeds an observable copy of\n * the steps from the resolved {@link SetupWidgetData}, and exposes a public API to\n * read the steps and change a step's status.\n *\n * The consumer API is `steps`, `getStep`, `setStepStatus`, `refresh` and\n * `isRefreshing`. Underscore-prefixed members are internal to the\n * `@wix/patterns` rendering layer — not consumer API.\n *\n * Render-time concerns (how inline content is supplied, navigation handling)\n * stay in the cairo component — this class never imports from `@wix/patterns`,\n * preserving the upward dependency direction.\n */\nexport class SetupWidgetState {\n private readonly container: WixPatternsContainer;\n private readonly fetchData: () => Promise<SetupWidgetData>;\n /** @internal Read by the `SetupWidget` component for the page status mapping. */\n readonly _loadTask = new TaskState<SetupWidgetData>();\n\n /** Mutable copy of the steps, seeded from `fetchData` and editable via the public API. */\n private seededSteps: SetupWidgetStep[] = [];\n private seededTitle?: string | null = null;\n\n /** The step the user explicitly expanded; `null` once explicitly collapsed. */\n private focusedStepId: string | null = null;\n /** Whether the user has interacted with inline expansion yet. */\n private userToggled = false;\n /** True while a `refresh()` is in flight (for an optional consumer indicator). */\n isRefreshing = false;\n /** The most recently issued `refresh()` fetch, for last-write-wins. */\n private latestRefresh?: Promise<SetupWidgetData>;\n\n constructor(params: SetupWidgetStateParams) {\n this.container = params.container;\n this.fetchData = params.fetchData;\n\n makeObservable<\n SetupWidgetState,\n | 'seededSteps'\n | 'seededTitle'\n | 'focusedStepId'\n | 'userToggled'\n | 'seedFromData'\n >(this, {\n seededSteps: observable.ref,\n seededTitle: observable.ref,\n focusedStepId: observable.ref,\n userToggled: observable.ref,\n isRefreshing: observable.ref,\n steps: computed,\n _title: computed,\n _isLoading: computed,\n _isError: computed,\n _leafSteps: computed,\n _completedCount: computed,\n _totalCount: computed,\n _progressPercentage: computed,\n _isAllComplete: computed,\n _primaryStepId: computed,\n _expandedStepId: computed,\n seedFromData: action.bound,\n setStepStatus: action.bound,\n _toggleStep: action.bound,\n _retry: action.bound,\n refresh: action.bound,\n });\n }\n\n init(): () => void {\n this.load();\n\n // Seed the editable step list whenever fresh data resolves through the load\n // task (initial load + `_retry`). Consumer edits via `setStepStatus` survive\n // until the next successful fetch reseeds.\n const disposeSeed = reaction(\n () => this._loadTask.status.data,\n (data) => this.seedFromData(data),\n { fireImmediately: true },\n );\n\n return () => disposeSeed();\n }\n\n private load() {\n this._loadTask.runOnce(\n async () => {\n // Wait for the container init (i18n, experiments) alongside the data,\n // so the widget's translated chrome is ready when it leaves the\n // loading state — same as CollectionState / EntityPageState.\n const [data] = await Promise.all([\n this.fetchData(),\n this.container.initTask.status.promise,\n ]);\n return data;\n },\n (error) => this.onError(error),\n );\n }\n\n /**\n * @internal Re-run the initial load after an error (shows the loading\n * skeleton again). Consumers receive this as the `retry` param of\n * `renderError`.\n */\n _retry() {\n this._loadTask.reset();\n this.load();\n }\n\n /**\n * Re-fetch the data on demand and swap in the result — without flipping back\n * to the loading skeleton, so the current steps stay visible during the\n * refetch (mirrors `onDashboardWidgetDataChange` in dashboard-setup). Use this\n * to reflect status changes that happen outside the widget (a `navigate` step\n * finishing elsewhere, a real-time/server push). Discards local\n * `setStepStatus` edits in favour of the freshly fetched server truth. A\n * failed refresh keeps the current data (the error is reported, not surfaced).\n *\n * `refresh()` is not error recovery: it never touches the load task, so a\n * refresh after a failed initial load seeds data but leaves the error state\n * (and the component's error UI) up. Error recovery is {@link _retry} —\n * surfaced to consumers as the `retry` param of `renderError`.\n */\n async refresh() {\n const promise = this.fetchData();\n this.latestRefresh = promise;\n this.isRefreshing = true;\n try {\n const data = await promise;\n // Last-write-wins: a stale fetch that resolves after a newer refresh was\n // issued must not clobber it (mirrors TaskState.run's promise guard).\n if (promise === this.latestRefresh) {\n this.seedFromData(data);\n }\n } catch (error) {\n this.onError(error);\n } finally {\n if (promise === this.latestRefresh) {\n runInAction(() => {\n this.isRefreshing = false;\n });\n }\n }\n }\n\n private onError(error: unknown) {\n this.container.internalMonitor.reportError({ error: error as Error });\n }\n\n private seedFromData(data: SetupWidgetData | undefined) {\n if (!data) {\n return;\n }\n this.seededSteps = data.steps;\n this.seededTitle = data.title;\n // Fresh data → drop any explicit expansion so focus recomputes from the new\n // steps (matches the focus reset on refetch in dashboard-setup).\n this.userToggled = false;\n this.focusedStepId = null;\n }\n\n // ---- Public read API ----\n\n get steps() {\n return this.seededSteps;\n }\n\n getStep(id: string): SetupWidgetStep | undefined {\n const find = (steps: SetupWidgetStep[]): SetupWidgetStep | undefined => {\n for (const step of steps) {\n if (step.id === id) {\n return step;\n }\n const inChild = step.steps && find(step.steps);\n if (inChild) {\n return inChild;\n }\n }\n return undefined;\n };\n return find(this.seededSteps);\n }\n\n // ---- Internal read API (consumed by the SetupWidget component) ----\n\n /** @internal */\n get _title() {\n return this.seededTitle;\n }\n\n /** @internal */\n get _isLoading(): boolean {\n const { status } = this._loadTask;\n return status.isIdle || status.isLoading;\n }\n\n /** @internal */\n get _isError(): boolean {\n return this._loadTask.status.isError;\n }\n\n /**\n * @internal Steps flattened to their leaves — an aggregated step (with\n * `steps`) is replaced by its sub-steps. Progress is measured over the\n * leaves so a group counts as its child steps, not as one row (matches\n * dashboard-setup).\n */\n get _leafSteps(): SetupWidgetStep[] {\n return this.seededSteps.flatMap((step) =>\n step.steps?.length ? step.steps : [step],\n );\n }\n\n /** @internal */\n get _completedCount(): number {\n return this._leafSteps.filter((step) => step.status === 'completed').length;\n }\n\n /** @internal */\n get _totalCount(): number {\n return this._leafSteps.length;\n }\n\n /** @internal */\n get _progressPercentage(): number {\n return this._totalCount === 0\n ? 0\n : Math.round((this._completedCount / this._totalCount) * 100);\n }\n\n /** @internal */\n get _isAllComplete(): boolean {\n return this._totalCount > 0 && this._completedCount === this._totalCount;\n }\n\n /**\n * @internal The recommended next step — highlighted as \"focused\" and given\n * the primary CTA. Derived, never pinned by the data (matches\n * dashboard-setup's client-side focus): the first upcoming step, then the\n * first step that isn't already done or disabled.\n */\n get _primaryStepId(): string | null {\n return (\n this.seededSteps.find((step) => step.status === 'upcoming')?.id ??\n this.seededSteps.find(\n (step) => step.status !== 'completed' && step.status !== 'disabled',\n )?.id ??\n null\n );\n }\n\n /**\n * @internal The step whose inline content is currently expanded\n * (single-open). Until the user interacts, defaults to the primary step when\n * its content is inline — mirroring `isFocused && isExtensionStep` in\n * dashboard-setup.\n */\n get _expandedStepId(): string | null {\n if (this.userToggled) {\n return this.focusedStepId;\n }\n const primary = this.seededSteps.find(\n (step) => step.id === this._primaryStepId,\n );\n return primary?.expansionMode === 'inline' ? primary.id : null;\n }\n\n // ---- Public write API ----\n\n /**\n * Change a step's status (e.g. mark it completed after the consumer flow\n * finishes). Works for top-level steps and for sub-steps of an aggregated\n * group, so a group's counter + the leaf progress stay in sync.\n */\n setStepStatus(id: string, status: SetupWidgetStepStatus) {\n const wasExpanded = this._expandedStepId === id;\n\n const update = (steps: SetupWidgetStep[]): SetupWidgetStep[] =>\n steps.map((step) => {\n if (step.id === id) {\n return { ...step, status };\n }\n if (step.steps) {\n return { ...step, steps: update(step.steps) };\n }\n return step;\n });\n\n this.seededSteps = update(this.seededSteps);\n\n // When the expanded step gets completed, drop the explicit focus so the\n // now-completed row collapses and focus recomputes to the next step —\n // mirroring `setStepCompleted` in dashboard-setup's widget context.\n if (status === 'completed' && wasExpanded) {\n this.userToggled = false;\n this.focusedStepId = null;\n }\n }\n\n /** @internal Toggle a step's inline expansion (single-open). */\n _toggleStep(id: string) {\n // Read the effective expanded step *before* flipping `userToggled`, since\n // doing so changes which branch `_expandedStepId` returns.\n const currentlyExpanded = this._expandedStepId;\n this.userToggled = true;\n this.focusedStepId = currentlyExpanded === id ? null : id;\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":["_mobx","require","_TaskState","SetupWidgetState","constructor","params","_defineProperty2","default","TaskState","container","fetchData","makeObservable","seededSteps","observable","ref","seededTitle","focusedStepId","userToggled","isRefreshing","steps","computed","_title","_isLoading","_isError","_leafSteps","_completedCount","_totalCount","_progressPercentage","_isAllComplete","_primaryStepId","_expandedStepId","_focusedStepId","seedFromData","action","bound","setStepStatus","_toggleStep","_retry","refresh","init","load","disposeSeed","reaction","_loadTask","status","data","fireImmediately","runOnce","Promise","all","initTask","promise","error","onError","reset","latestRefresh","runInAction","internalMonitor","reportError","title","getStep","id","find","step","inChild","undefined","isIdle","isLoading","isError","flatMap","_step$steps","length","filter","Math","round","_this$seededSteps$fin","_this$seededSteps$fin2","primary","expansionMode","wasExpanded","update","map","currentlyExpanded","exports"],"sources":["../../../src/state/SetupWidgetState.ts"],"sourcesContent":["import {\n action,\n computed,\n makeObservable,\n observable,\n reaction,\n runInAction,\n} from 'mobx';\nimport { WixPatternsContainer } from './WixPatternsContainer';\nimport { TaskState } from './TaskState';\nimport {\n SetupWidgetData,\n SetupWidgetStep,\n SetupWidgetStepStatus,\n} from '../model/setupWidget';\n\nexport interface SetupWidgetStateParams {\n readonly container: WixPatternsContainer;\n /** Consumer-supplied data resolver. The widget owns loading / error state. */\n readonly fetchData: () => Promise<SetupWidgetData>;\n}\n\n/**\n * State for the Setup widget, created via the `useSetupWidget` hook and passed\n * to the `SetupWidget` component (the same shape as `useCollection` →\n * `CollectionState`).\n *\n * Owns the async lifecycle via {@link TaskState}, seeds an observable copy of\n * the steps from the resolved {@link SetupWidgetData}, and exposes a public API to\n * read the steps and change a step's status.\n *\n * The consumer API is `steps`, `getStep`, `setStepStatus`, `refresh` and\n * `isRefreshing`. Underscore-prefixed members are internal to the\n * `@wix/patterns` rendering layer — not consumer API.\n *\n * Render-time concerns (how inline content is supplied, navigation handling)\n * stay in the cairo component — this class never imports from `@wix/patterns`,\n * preserving the upward dependency direction.\n */\nexport class SetupWidgetState {\n private readonly container: WixPatternsContainer;\n private readonly fetchData: () => Promise<SetupWidgetData>;\n /** @internal Read by the `SetupWidget` component for the page status mapping. */\n readonly _loadTask = new TaskState<SetupWidgetData>();\n\n /** Mutable copy of the steps, seeded from `fetchData` and editable via the public API. */\n private seededSteps: SetupWidgetStep[] = [];\n private seededTitle?: string | null = null;\n\n /** The step the user explicitly expanded; `null` once explicitly collapsed. */\n private focusedStepId: string | null = null;\n /** Whether the user has interacted with inline expansion yet. */\n private userToggled = false;\n /** True while a `refresh()` is in flight (for an optional consumer indicator). */\n isRefreshing = false;\n /** The most recently issued `refresh()` fetch, for last-write-wins. */\n private latestRefresh?: Promise<SetupWidgetData>;\n\n constructor(params: SetupWidgetStateParams) {\n this.container = params.container;\n this.fetchData = params.fetchData;\n\n makeObservable<\n SetupWidgetState,\n | 'seededSteps'\n | 'seededTitle'\n | 'focusedStepId'\n | 'userToggled'\n | 'seedFromData'\n >(this, {\n seededSteps: observable.ref,\n seededTitle: observable.ref,\n focusedStepId: observable.ref,\n userToggled: observable.ref,\n isRefreshing: observable.ref,\n steps: computed,\n _title: computed,\n _isLoading: computed,\n _isError: computed,\n _leafSteps: computed,\n _completedCount: computed,\n _totalCount: computed,\n _progressPercentage: computed,\n _isAllComplete: computed,\n _primaryStepId: computed,\n _expandedStepId: computed,\n _focusedStepId: computed,\n seedFromData: action.bound,\n setStepStatus: action.bound,\n _toggleStep: action.bound,\n _retry: action.bound,\n refresh: action.bound,\n });\n }\n\n init(): () => void {\n this.load();\n\n // Seed the editable step list whenever fresh data resolves through the load\n // task (initial load + `_retry`). Consumer edits via `setStepStatus` survive\n // until the next successful fetch reseeds.\n const disposeSeed = reaction(\n () => this._loadTask.status.data,\n (data) => this.seedFromData(data),\n { fireImmediately: true },\n );\n\n return () => disposeSeed();\n }\n\n private load() {\n this._loadTask.runOnce(\n async () => {\n // Wait for the container init (i18n, experiments) alongside the data,\n // so the widget's translated chrome is ready when it leaves the\n // loading state — same as CollectionState / EntityPageState.\n const [data] = await Promise.all([\n this.fetchData(),\n this.container.initTask.status.promise,\n ]);\n return data;\n },\n (error) => this.onError(error),\n );\n }\n\n /**\n * @internal Re-run the initial load after an error (shows the loading\n * skeleton again). Consumers receive this as the `retry` param of\n * `renderError`.\n */\n _retry() {\n this._loadTask.reset();\n this.load();\n }\n\n /**\n * Re-fetch the data on demand and swap in the result — without flipping back\n * to the loading skeleton, so the current steps stay visible during the\n * refetch (mirrors `onDashboardWidgetDataChange` in dashboard-setup). Use this\n * to reflect status changes that happen outside the widget (a `navigate` step\n * finishing elsewhere, a real-time/server push). Discards local\n * `setStepStatus` edits in favour of the freshly fetched server truth. A\n * failed refresh keeps the current data (the error is reported, not surfaced).\n *\n * `refresh()` is not error recovery: it never touches the load task, so a\n * refresh after a failed initial load seeds data but leaves the error state\n * (and the component's error UI) up. Error recovery is {@link _retry} —\n * surfaced to consumers as the `retry` param of `renderError`.\n */\n async refresh() {\n const promise = this.fetchData();\n this.latestRefresh = promise;\n this.isRefreshing = true;\n try {\n const data = await promise;\n // Last-write-wins: a stale fetch that resolves after a newer refresh was\n // issued must not clobber it (mirrors TaskState.run's promise guard).\n if (promise === this.latestRefresh) {\n this.seedFromData(data);\n }\n } catch (error) {\n this.onError(error);\n } finally {\n if (promise === this.latestRefresh) {\n runInAction(() => {\n this.isRefreshing = false;\n });\n }\n }\n }\n\n private onError(error: unknown) {\n this.container.internalMonitor.reportError({ error: error as Error });\n }\n\n private seedFromData(data: SetupWidgetData | undefined) {\n if (!data) {\n return;\n }\n this.seededSteps = data.steps;\n this.seededTitle = data.title;\n // Fresh data → drop any explicit expansion so focus recomputes from the new\n // steps (matches the focus reset on refetch in dashboard-setup).\n this.userToggled = false;\n this.focusedStepId = null;\n }\n\n // ---- Public read API ----\n\n get steps() {\n return this.seededSteps;\n }\n\n getStep(id: string): SetupWidgetStep | undefined {\n const find = (steps: SetupWidgetStep[]): SetupWidgetStep | undefined => {\n for (const step of steps) {\n if (step.id === id) {\n return step;\n }\n const inChild = step.steps && find(step.steps);\n if (inChild) {\n return inChild;\n }\n }\n return undefined;\n };\n return find(this.seededSteps);\n }\n\n // ---- Internal read API (consumed by the SetupWidget component) ----\n\n /** @internal */\n get _title() {\n return this.seededTitle;\n }\n\n /** @internal */\n get _isLoading(): boolean {\n const { status } = this._loadTask;\n return status.isIdle || status.isLoading;\n }\n\n /** @internal */\n get _isError(): boolean {\n return this._loadTask.status.isError;\n }\n\n /**\n * @internal Steps flattened to their leaves — an aggregated step (with\n * `steps`) is replaced by its sub-steps. Progress is measured over the\n * leaves so a group counts as its child steps, not as one row (matches\n * dashboard-setup).\n */\n get _leafSteps(): SetupWidgetStep[] {\n return this.seededSteps.flatMap((step) =>\n step.steps?.length ? step.steps : [step],\n );\n }\n\n /** @internal */\n get _completedCount(): number {\n return this._leafSteps.filter((step) => step.status === 'completed').length;\n }\n\n /** @internal */\n get _totalCount(): number {\n return this._leafSteps.length;\n }\n\n /** @internal */\n get _progressPercentage(): number {\n return this._totalCount === 0\n ? 0\n : Math.round((this._completedCount / this._totalCount) * 100);\n }\n\n /** @internal */\n get _isAllComplete(): boolean {\n return this._totalCount > 0 && this._completedCount === this._totalCount;\n }\n\n /**\n * @internal The recommended next step — highlighted as \"focused\" and given\n * the primary CTA. Derived, never pinned by the data (matches\n * dashboard-setup's client-side focus): the first upcoming step, then the\n * first step that isn't already done or disabled.\n */\n get _primaryStepId(): string | null {\n return (\n this.seededSteps.find((step) => step.status === 'upcoming')?.id ??\n this.seededSteps.find(\n (step) => step.status !== 'completed' && step.status !== 'disabled',\n )?.id ??\n null\n );\n }\n\n /**\n * @internal The step whose inline content is currently expanded\n * (single-open). Until the user interacts, defaults to the primary step when\n * its content is inline — mirroring `isFocused && isExtensionStep` in\n * dashboard-setup.\n */\n get _expandedStepId(): string | null {\n if (this.userToggled) {\n return this.focusedStepId;\n }\n const primary = this.seededSteps.find(\n (step) => step.id === this._primaryStepId,\n );\n return primary?.expansionMode === 'inline' ? primary.id : null;\n }\n\n /**\n * @internal The single focused (highlighted) step. Production keeps focus and\n * inline-expansion unified in one `focusedStepId`, so only ever one step is\n * highlighted; here `_primaryStepId` (recommended next) and `_expandedStepId`\n * (what the user toggled open) are separate, and can diverge once the user\n * opens a non-primary inline step. Collapsing them to a single id — the\n * expanded step when one is open, otherwise the primary — preserves the\n * single-focus invariant (avoids highlighting both the primary and the\n * expanded row).\n */\n get _focusedStepId(): string | null {\n return this._expandedStepId ?? this._primaryStepId;\n }\n\n // ---- Public write API ----\n\n /**\n * Change a step's status (e.g. mark it completed after the consumer flow\n * finishes). Works for top-level steps and for sub-steps of an aggregated\n * group, so a group's counter + the leaf progress stay in sync.\n */\n setStepStatus(id: string, status: SetupWidgetStepStatus) {\n const wasExpanded = this._expandedStepId === id;\n\n const update = (steps: SetupWidgetStep[]): SetupWidgetStep[] =>\n steps.map((step) => {\n if (step.id === id) {\n return { ...step, status };\n }\n if (step.steps) {\n return { ...step, steps: update(step.steps) };\n }\n return step;\n });\n\n this.seededSteps = update(this.seededSteps);\n\n // When the expanded step gets completed, drop the explicit focus so the\n // now-completed row collapses and focus recomputes to the next step —\n // mirroring `setStepCompleted` in dashboard-setup's widget context.\n if (status === 'completed' && wasExpanded) {\n this.userToggled = false;\n this.focusedStepId = null;\n }\n }\n\n /** @internal Toggle a step's inline expansion (single-open). */\n _toggleStep(id: string) {\n // Read the effective expanded step *before* flipping `userToggled`, since\n // doing so changes which branch `_expandedStepId` returns.\n const currentlyExpanded = this._expandedStepId;\n this.userToggled = true;\n this.focusedStepId = currentlyExpanded === id ? null : id;\n }\n}\n"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":[],"sources":["../../../src/types/Field.ts"],"sourcesContent":["export type PatternsFieldType =\n | 'SHORT_TEXT'\n | 'LONG_TEXT'\n | 'NUMBER'\n | 'BOOLEAN'\n | 'DATE'\n | 'DATETIME'\n | 'TIME'\n | 'URL'\n | 'ARRAY'\n | 'REFERENCE'\n | 'MULTI_REFERENCE'\n | 'OBJECT'\n | 'IMAGE'\n | 'VIDEO'\n | 'MEDIA_GALLERY'\n | 'ADDRESS'\n | 'RICH_TEXT'\n | 'DOCUMENT'\n | 'RICH_CONTENT'\n | 'MULTI_DOCUMENT'\n | 'EMAIL'\n | 'AUDIO'\n | 'COLOR'\n | 'UNKNOWN';\n\nexport type QueryOperator =\n | 'CONTAINS'\n | 'ENDS_WITH'\n | 'EQ'\n | 'EXISTS'\n | 'GT'\n | 'GTE'\n | 'HAS_ALL'\n | 'HAS_SOME'\n | 'LT'\n | 'LTE'\n | 'NE'\n | 'STARTS_WITH'\n | 'URLIZED';\n\nexport interface NumberRange {\n min?: number;\n max?: number;\n}\n\nexport interface StringLengthRange {\n minLength?: number;\n maxLength?: number;\n}\n\ninterface BaseField {\n id: string;\n displayName: string;\n isPii?: boolean;\n helpText?: string;\n validation?: {\n numberRange?: NumberRange;\n stringLengthRange?: StringLengthRange;\n required: boolean;\n };\n capabilities?: {\n supportedQueryOperators: QueryOperator[];\n sortable: boolean;\n };\n}\n\nexport interface BaseReferenceField extends BaseField {\n referenceMetadata: {\n referencedCollectionId: string;\n };\n}\n\nexport interface ReferenceField extends BaseReferenceField {\n type: 'REFERENCE';\n}\n\nexport interface MultiReferenceField extends BaseReferenceField {\n type: 'MULTI_REFERENCE';\n}\n\nexport interface NonReferenceField extends BaseField {\n type: Exclude<PatternsFieldType, 'REFERENCE' | 'MULTI_REFERENCE'>;\n}\n\nexport type Field = ReferenceField | MultiReferenceField | NonReferenceField;\nexport type FieldSpec = Omit<Field, 'id'>;\n"],"mappings":"","ignoreList":[]}
|
|
1
|
+
{"version":3,"names":[],"sources":["../../../src/types/Field.ts"],"sourcesContent":["export type PatternsFieldType =\n | 'SHORT_TEXT'\n | 'LONG_TEXT'\n | 'NUMBER'\n | 'BOOLEAN'\n | 'DATE'\n | 'DATETIME'\n | 'TIME'\n | 'URL'\n | 'ARRAY'\n | 'REFERENCE'\n | 'MULTI_REFERENCE'\n | 'OBJECT'\n | 'IMAGE'\n | 'VIDEO'\n | 'MEDIA_GALLERY'\n | 'ADDRESS'\n | 'RICH_TEXT'\n | 'DOCUMENT'\n | 'RICH_CONTENT'\n | 'MULTI_DOCUMENT'\n | 'EMAIL'\n | 'AUDIO'\n | 'COLOR'\n | 'UNKNOWN';\n\nexport type QueryOperator =\n | 'CONTAINS'\n | 'ENDS_WITH'\n | 'EQ'\n | 'EXISTS'\n | 'GT'\n | 'GTE'\n | 'HAS_ALL'\n | 'HAS_SOME'\n | 'LT'\n | 'LTE'\n | 'NE'\n | 'STARTS_WITH'\n | 'URLIZED';\n\nexport interface NumberRange {\n min?: number;\n max?: number;\n}\n\nexport interface StringLengthRange {\n minLength?: number;\n maxLength?: number;\n}\n\ninterface BaseField {\n id: string;\n displayName: string;\n isPii?: boolean;\n helpText?: string;\n /** Whether this is a system-managed field (not user-created). */\n isSystem?: boolean;\n /** Whether this is the collection's primary display field. */\n isPrimary?: boolean;\n validation?: {\n numberRange?: NumberRange;\n stringLengthRange?: StringLengthRange;\n required: boolean;\n };\n capabilities?: {\n supportedQueryOperators: QueryOperator[];\n sortable: boolean;\n };\n}\n\nexport interface BaseReferenceField extends BaseField {\n referenceMetadata: {\n referencedCollectionId: string;\n };\n}\n\nexport interface ReferenceField extends BaseReferenceField {\n type: 'REFERENCE';\n}\n\nexport interface MultiReferenceField extends BaseReferenceField {\n type: 'MULTI_REFERENCE';\n}\n\nexport interface NonReferenceField extends BaseField {\n type: Exclude<PatternsFieldType, 'REFERENCE' | 'MULTI_REFERENCE'>;\n}\n\nexport type Field = ReferenceField | MultiReferenceField | NonReferenceField;\nexport type FieldSpec = Omit<Field, 'id'>;\n"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sources":["../../../src/types/Schema.ts"],"sourcesContent":["import type { Field } from './Field';\nimport type { FiltersMap, OptionalFiltersMap } from '../model';\nimport type {\n OffsetFetchDataFn,\n CursorFetchDataFn,\n FetchTotalFn,\n} from '../hooks/paginationModeConfig';\n\n/** Field-management permissions. Absent when the schema's fields cannot be edited. */\nexport interface SchemaPermissions {\n createField: boolean;\n updateField: boolean;\n deleteField: boolean;\n}\n\n/** Item-level CRUD permissions. */\nexport interface ItemPermissions {\n createItem: boolean;\n updateItem: boolean;\n deleteItem: boolean;\n}\n\n/**\n * A source-neutral description of a collection — data only, no behavior.\n * Item access is in `CollectionBackend`, field mutations in `FieldActions`.\n */\nexport interface Schema {\n id: string;\n fields: Record<string, Field | undefined>;\n /** The field that best represents the entity (titles/selections). */\n displayField: string;\n /** The identifier field (e.g. '_id'). */\n idField: string;\n /** Absent when the schema's fields cannot be edited. */\n schemaPermissions?: SchemaPermissions;\n itemPermissions?: ItemPermissions;\n}\n\nexport interface BackupConfig {\n create: () => Promise<{ backupId: string }>;\n waitForCompletion: (\n backupId: string,\n options?: { signal?: AbortSignal },\n ) => Promise<void>;\n cancel?: (backupId: string) => Promise<void>;\n restore?: (backupId: string) => Promise<{ restorationId: string }>;\n waitForRestoration?: (\n restorationId: string,\n options?: { signal?: AbortSignal },\n ) => Promise<void>;\n}\n\nexport interface BulkInsertError {\n rowIndex: number;\n message?: string;\n code?: string;\n}\n\nexport interface BulkInsertResult {\n succeeded?: number;\n failed?: number;\n errors?: BulkInsertError[];\n}\n\n/** Item data access shared by both pagination modes. */\nexport interface CollectionBackendBase<T = Record<string, unknown>> {\n get: (entityId: string) => Promise<T>;\n create: (entity: Partial<T>) => Promise<T>;\n update: (entity: T) => Promise<T>;\n delete: (entityId: string) => Promise<void>;\n bulkDelete: (entityIds: string[]) => Promise<void>;\n move?: (\n id: string,\n params: { moveAfterId: string | null | undefined },\n ) => Promise<void>;\n backup?: BackupConfig;\n bulkInsert?: (entities: Partial<T>[]) => Promise<BulkInsertResult>;\n}\n\n/**\n * A source's item data access. The source declares its `paginationMode`\n * (offset by default) together with the matching `find`, same as core's\n * `PaginationModeConfig`.\n */\nexport type CollectionBackend<\n T = Record<string, unknown>,\n F extends FiltersMap = OptionalFiltersMap,\n> = CollectionBackendBase<T> &\n (\n | { paginationMode?: 'offset'; find: OffsetFetchDataFn<T, F> }\n | {\n paginationMode: 'cursor';\n find: CursorFetchDataFn<T, F>;\n fetchTotal?: FetchTotalFn;\n }\n );\n\n/** Field-management actions. All optional — a read-only source provides none. */\nexport interface FieldActions {\n addField?: (field: Field) => Promise<void>;\n editField?: (fieldId: string, updates: Partial<Field>) => Promise<void>;\n deleteField?: (fieldId: string) => Promise<void>;\n renameField?: (fieldId: string, newName: string) => Promise<void>;\n makePrimary?: (fieldId: string) => Promise<void>;\n duplicateField?: (fieldId: string) => Promise<void>;\n duplicateFieldWithContent?: (fieldId: string) => Promise<void>;\n}\n\n/** Everything a source provides for a collection. */\nexport interface LoadedSchema<T = Record<string, unknown>> {\n schema: Schema;\n backend: CollectionBackend<T>;\n fieldActions?: FieldActions;\n}\n\n/**\n * Loads a collection's `LoadedSchema`. Sources that need dependencies expose a\n * factory that returns this type (e.g. `createCmsSchemaLoader(deps)`).\n */\nexport type SchemaLoader<\n T extends Record<string, unknown> = Record<string, unknown>,\n> = (collectionId: string) => Promise<LoadedSchema<T>>;\n"],"mappings":"","ignoreList":[]}
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"cairo.import.back": "Back",
|
|
46
46
|
"cairo.export.exportingDescription": "Once the export is complete, your file download will begin.",
|
|
47
47
|
"cairo.manageView.setAsDefault.CTA": "Set as default view",
|
|
48
|
+
"cairo.import.newFieldOption": "{column} (New)",
|
|
48
49
|
"cairo.customFields.addCustomField.modal.advancedSettings.siteCollaborators": "Site collaborators",
|
|
49
50
|
"cairo.passiveEmptyState.title": "No items yet",
|
|
50
51
|
"cairo.filterOperator.valuePlaceholder.tag": "select an option",
|
|
@@ -137,6 +138,7 @@
|
|
|
137
138
|
"cairo.search.Tab.noresults.text": "Look in a different tab or try a new search.",
|
|
138
139
|
"cairo.viewDropdown.unsavedView.status": "Unsaved view",
|
|
139
140
|
"cairo.technical.error.text": "There was a technical problem on our end. Refresh the page and try again in a moment.",
|
|
141
|
+
"cairo.import.downloadFailedRows": "Download failed rows",
|
|
140
142
|
"cairo.export.get-async-job.error.internal": "Unable to export due to a technical issue on our end.",
|
|
141
143
|
"cairo.table.advanced-sorting.subtitle": "Sort your items by multiple columns.",
|
|
142
144
|
"cairo.customFields.updateDataExtension.removing-fields-not-allowed.error": "This item can't be deleted.",
|
|
@@ -146,6 +148,7 @@
|
|
|
146
148
|
"cairo.customFields.addCustomField.modal.subtitle.note": "Note that this field will be added to all of your items.",
|
|
147
149
|
"cairo.entityPage.widgetError.TPAconnectionFail.CTA": "Reload Section",
|
|
148
150
|
"cairo.dragAndDrop.error.toast": "Due to a technical issue, changes you made to the order of your items weren’t saved.",
|
|
151
|
+
"cairo.import.partialSuccessToast": "{failed} rows failed, {imported} rows imported.",
|
|
149
152
|
"cairo.table.custom-columns.subtitle": "Choose which columns to show.",
|
|
150
153
|
"cairo.customFields.addCustomField.modal.advancedSettings.read": "Read",
|
|
151
154
|
"cairo.filterOperator.equals": "Equals",
|
|
@@ -470,6 +473,7 @@
|
|
|
470
473
|
"cairo.manageView.Rename.modal.title": "Rename view",
|
|
471
474
|
"cairo.tags.collectionPage.tagsColumn.title.asLabels": "Labels",
|
|
472
475
|
"cairo.table.summaryBar.loadError": "Couldn't load summary bar.",
|
|
476
|
+
"cairo.import.newFieldHelper": "This will be a new {typeName} field.",
|
|
473
477
|
"cairo.tags.tagsWidget.title": "Tags",
|
|
474
478
|
"cairo.customFields.entityPage.emptyState.subtitle": "User fields appear here if they are filled in by users.",
|
|
475
479
|
"cairo.archivedFields.title": "Archived fields",
|
|
@@ -541,6 +545,7 @@
|
|
|
541
545
|
"cairo.customFields.editCustomField.success.toast": "Your changes were saved.",
|
|
542
546
|
"matvey.test": "testing",
|
|
543
547
|
"cairo.export.cancelTheExport": "Cancel the export?",
|
|
548
|
+
"cairo.import.newFieldSuffix": "(New)",
|
|
544
549
|
"cairo.customFields.addCustomField.modal.PII.learnMore": "Learn more",
|
|
545
550
|
"cairo.import.uploadButtonLabel": "Upload File",
|
|
546
551
|
"cairo.tags.manageTags.modal.list.input.cancel.CTA": "Cancel",
|