fuse-importer 0.25.9 → 0.26.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/lib/esm/Importer/Matcher/EnumFieldsMatchers/EnumFieldMatcher/index.js +11 -1
  2. package/lib/esm/Importer/Review/ReviewWithContext.js +4 -8
  3. package/lib/esm/Importer/Uploader/HeadersPreview.js +5 -9
  4. package/lib/esm/Importer/common/Spreadsheet/SpreadsheetContextProvider.d.ts +3 -3
  5. package/lib/esm/Importer/common/Spreadsheet/SpreadsheetContextProvider.js +35 -12
  6. package/lib/esm/Importer/common/Spreadsheet/components/SpreadsheetData.js +28 -2
  7. package/lib/esm/Importer/common/Spreadsheet/components/SpreadsheetRowCheckboxes.d.ts +1 -2
  8. package/lib/esm/Importer/common/Spreadsheet/components/SpreadsheetRowCheckboxes.js +21 -10
  9. package/lib/esm/Importer/common/Spreadsheet/hooks.d.ts +4 -2
  10. package/lib/esm/Importer/common/Spreadsheet/hooks.js +5 -68
  11. package/lib/esm/Importer/common/Spreadsheet/index.d.ts +1 -2
  12. package/lib/esm/Importer/common/Spreadsheet/index.js +2 -2
  13. package/lib/esm/Importer/common/Spreadsheet/styles.d.ts +1 -1
  14. package/lib/esm/Importer/common/Spreadsheet/styles.js +2 -2
  15. package/lib/esm/Importer/common/index.js +1 -1
  16. package/lib/esm/Importer/common/utils.d.ts +4 -1
  17. package/lib/esm/Importer/common/utils.js +15 -4
  18. package/lib/esm/Importer/contexts/ImporterContextProvider.d.ts +2 -1
  19. package/lib/esm/Importer/contexts/ImporterContextProvider.js +27 -7
  20. package/lib/esm/Importer/data/index.d.ts +7 -2
  21. package/lib/esm/Importer/data/index.js +18 -10
  22. package/lib/esm/Importer/index.d.ts +3 -2
  23. package/lib/esm/Importer/index.js +2 -4
  24. package/lib/esm/common/Table/TableActions/DeleteSelectedRows.js +10 -25
  25. package/lib/esm/common/Table/TableActions/ExportData.js +3 -1
  26. package/lib/esm/common/Table/TableActions/FilterByErrors/FilterByErrors.d.ts +1 -0
  27. package/lib/esm/common/Table/TableActions/FilterByErrors/FilterByErrors.js +37 -0
  28. package/lib/esm/common/Table/TableActions/FilterByErrors/FilterByErrors.styles.d.ts +6 -0
  29. package/lib/esm/common/Table/TableActions/FilterByErrors/FilterByErrors.styles.js +24 -0
  30. package/lib/esm/common/Table/TableActions/FilterByErrors/functions.d.ts +11 -0
  31. package/lib/esm/common/Table/TableActions/FilterByErrors/functions.js +35 -0
  32. package/lib/esm/common/Table/TableActions/FilterByErrors/index.d.ts +1 -0
  33. package/lib/esm/common/Table/TableActions/FilterByErrors/index.js +1 -0
  34. package/lib/esm/common/Table/TableActions/SearchRows.js +3 -1
  35. package/lib/esm/common/Table/TableActions/TableActions.js +2 -1
  36. package/lib/esm/common/Table/TableActions/TableActions.styles.js +1 -1
  37. package/lib/esm/common/Table/TableActions/hooks.d.ts +20 -0
  38. package/lib/esm/common/Table/TableActions/hooks.js +96 -0
  39. package/lib/esm/common/Table/TableView/TableHeaders.d.ts +6 -8
  40. package/lib/esm/common/Table/TableView/TableHeaders.js +15 -14
  41. package/lib/esm/common/Table/TableView/{TableRow.d.ts → TableRows/TableRow.d.ts} +5 -5
  42. package/lib/esm/common/Table/TableView/{TableRow.js → TableRows/TableRow.js} +9 -6
  43. package/lib/esm/common/Table/TableView/TableRows/index.d.ts +4 -0
  44. package/lib/esm/common/Table/TableView/{TableCells.js → TableRows/index.js} +13 -11
  45. package/lib/esm/common/Table/TableView/common/index.d.ts +5 -0
  46. package/lib/esm/common/Table/TableView/{common.js → common/index.js} +18 -5
  47. package/lib/esm/common/Table/TableView/index.d.ts +4 -39
  48. package/lib/esm/common/Table/TableView/index.js +48 -65
  49. package/lib/esm/common/Table/TableView/types.d.ts +37 -0
  50. package/lib/esm/common/Table/TableView/types.js +1 -0
  51. package/lib/esm/common/Table/index.d.ts +2 -2
  52. package/lib/esm/common/Table/index.js +20 -16
  53. package/lib/esm/common/columnsValidations.d.ts +45 -0
  54. package/lib/esm/common/columnsValidations.js +351 -0
  55. package/lib/esm/common/index.d.ts +1 -0
  56. package/lib/esm/common/index.js +1 -0
  57. package/lib/esm/common/inputs/Autocomplete.d.ts +2 -1
  58. package/lib/esm/common/inputs/Autocomplete.js +2 -2
  59. package/lib/esm/common/inputs/SelectMenu.d.ts +1 -1
  60. package/lib/esm/common/inputs/SelectMenu.js +17 -9
  61. package/lib/esm/index.d.ts +4 -1
  62. package/lib/esm/index.js +56 -10
  63. package/lib/esm/locales/de.d.ts +20 -0
  64. package/lib/esm/locales/de.js +20 -0
  65. package/lib/esm/locales/en.d.ts +20 -0
  66. package/lib/esm/locales/en.js +20 -0
  67. package/lib/esm/locales/es.d.ts +20 -0
  68. package/lib/esm/locales/es.js +20 -0
  69. package/lib/esm/locales/fr.d.ts +20 -0
  70. package/lib/esm/locales/fr.js +20 -0
  71. package/lib/esm/types.d.ts +53 -1
  72. package/lib/esm/types.js +31 -0
  73. package/lib/esm/utils/index.d.ts +10 -0
  74. package/lib/esm/utils/index.js +31 -0
  75. package/lib/main.js +23 -23
  76. package/package.json +3 -2
  77. package/lib/esm/Importer/useFullscreenOverlay.d.ts +0 -1
  78. package/lib/esm/Importer/useFullscreenOverlay.js +0 -14
  79. package/lib/esm/common/Table/TableView/TableCells.d.ts +0 -4
  80. package/lib/esm/common/Table/TableView/common.d.ts +0 -9
@@ -45,20 +45,29 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
45
45
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
46
46
  }
47
47
  };
48
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
49
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
50
+ if (ar || !(i in from)) {
51
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
52
+ ar[i] = from[i];
53
+ }
54
+ }
55
+ return to.concat(ar || Array.prototype.slice.call(from));
56
+ };
48
57
  import { jsx as _jsx } from "react/jsx-runtime";
49
58
  import Fuse from "fuse.js";
50
59
  import { createContext, useContext, useEffect, useMemo, useRef, useState, } from "react";
51
60
  import { FieldTypes, } from "../../types";
52
61
  import { FuseApi } from "../common/FuseApi";
53
62
  import { getCustomTheme, theme } from "../common/theme";
54
- import { getColumnType } from "../common/utils";
63
+ import { getColumnType, verifyDuplicateValue } from "../common/utils";
55
64
  export var fusejsOptions = {
56
65
  includeScore: true,
57
66
  threshold: 0.35,
58
67
  };
59
68
  var ImporterContext = createContext({});
60
69
  export var ImporterContextProvider = function (_a) {
61
- var templateSlug = _a.templateSlug, apiToken = _a.apiToken, children = _a.children, options = _a.options, onSubmit = _a.onSubmit, onClose = _a.onClose, formatRecord = _a.formatRecord, onValidateRecord = _a.onValidateRecord;
70
+ var templateSlug = _a.templateSlug, apiToken = _a.apiToken, children = _a.children, options = _a.options, onSubmit = _a.onSubmit, onClose = _a.onClose, formatRecord = _a.formatRecord, onValidateRecord = _a.onValidateRecord, dynamicColumns = _a.dynamicColumns;
62
71
  var _b = useState(0), currentStepIndex = _b[0], setCurrentStepIndex = _b[1];
63
72
  var _c = useState(0), matcherSubstep = _c[0], setMatcherSubstep = _c[1];
64
73
  var _d = useState(null), templateError = _d[0], setTemplateError = _d[1];
@@ -125,7 +134,7 @@ export var ImporterContextProvider = function (_a) {
125
134
  }, [uploadedData]);
126
135
  useEffect(function () {
127
136
  (function () { return __awaiter(void 0, void 0, void 0, function () {
128
- var _a, organization_1, columns, importer_style_preferences, integrations_1, preview_first_time, columnsOrderedByPosition, error_1, errorMsg;
137
+ var _a, organization_1, columns_1, importer_style_preferences, integrations_1, preview_first_time, error_1, errorMsg;
129
138
  var _b, _c;
130
139
  return __generator(this, function (_d) {
131
140
  switch (_d.label) {
@@ -133,10 +142,21 @@ export var ImporterContextProvider = function (_a) {
133
142
  _d.trys.push([0, 2, , 3]);
134
143
  return [4 /*yield*/, fuseApi.get("/api/v1/importer/templates/".concat(templateSlug))];
135
144
  case 1:
136
- _a = (_d.sent()).data, organization_1 = _a.organization, columns = _a.columns, importer_style_preferences = _a.importer_style_preferences, integrations_1 = _a.integrations, preview_first_time = _a.preview_first_time;
137
- columnsOrderedByPosition = columns.sort(function (a, b) { return a.position - b.position; });
145
+ _a = (_d.sent()).data, organization_1 = _a.organization, columns_1 = _a.columns, importer_style_preferences = _a.importer_style_preferences, integrations_1 = _a.integrations, preview_first_time = _a.preview_first_time;
138
146
  setOrganization(organization_1);
139
- setTemplateHeaders(columnsOrderedByPosition);
147
+ setTemplateHeaders(function () {
148
+ // user has created dynamic columns
149
+ if (dynamicColumns && (dynamicColumns === null || dynamicColumns === void 0 ? void 0 : dynamicColumns.length) >= 0) {
150
+ var allColumns = __spreadArray(__spreadArray([], columns_1, true), dynamicColumns, true);
151
+ var columnsOrderedByPosition_1 = allColumns.sort(function (a, b) { return (a === null || a === void 0 ? void 0 : a.position) - (b === null || b === void 0 ? void 0 : b.position); });
152
+ verifyDuplicateValue(columnsOrderedByPosition_1, "internal_key", true, "There is a duplicated 'internal_key' between your columns.");
153
+ verifyDuplicateValue(columnsOrderedByPosition_1, "label", true, "There is a duplicated 'label' between your columns.");
154
+ return columnsOrderedByPosition_1;
155
+ }
156
+ // user has not created dynamic columns
157
+ var columnsOrderedByPosition = columns_1.sort(function (a, b) { return a.position - b.position; });
158
+ return columnsOrderedByPosition;
159
+ });
140
160
  setIntegrations(integrations_1);
141
161
  setPreviewFirstTime(preview_first_time);
142
162
  if (organization_1.plan && organization_1.plan.allow_style_customization) {
@@ -153,7 +173,7 @@ export var ImporterContextProvider = function (_a) {
153
173
  }
154
174
  });
155
175
  }); })();
156
- }, []);
176
+ }, [dynamicColumns]);
157
177
  var resetImport = function () {
158
178
  setUploadedData(null);
159
179
  setTemplateHeaderMatchings(null);
@@ -1,7 +1,12 @@
1
1
  import { Field, FieldTypes, FormatRecord, Record, RecordDataSet, TemplateHeader } from "../../types";
2
2
  import { EnumFieldValueMatchings, HeaderMatchings } from "../contexts/ImporterContextProvider";
3
- export declare const addEmptyRows: (data: Record[], fields: Field[]) => Record[];
4
- export declare const addMeta: (record: any, index: number) => Record;
3
+ export declare const addEmptyRows: (data: Record[], fields: Field[]) => {
4
+ _meta: {
5
+ id: string;
6
+ rowIndex: number;
7
+ };
8
+ }[];
9
+ export declare const addMeta: (record: any, index: number, uploadedRow?: any) => Record;
5
10
  export declare const recordListToDataSet: (data: Record[], fields: Field[]) => RecordDataSet;
6
11
  type transformToRecordsArgs = {
7
12
  templateHeaderMatchings: HeaderMatchings;
@@ -9,6 +9,15 @@ var __assign = (this && this.__assign) || function () {
9
9
  };
10
10
  return __assign.apply(this, arguments);
11
11
  };
12
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
13
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
14
+ if (ar || !(i in from)) {
15
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
16
+ ar[i] = from[i];
17
+ }
18
+ }
19
+ return to.concat(ar || Array.prototype.slice.call(from));
20
+ };
12
21
  import { FieldTypes, } from "../../types";
13
22
  import { parseValue } from "../common/Spreadsheet/common";
14
23
  var MINIMUM_ROW_COUNT = 20;
@@ -21,19 +30,18 @@ export var addEmptyRows = function (data, fields) {
21
30
  var _a;
22
31
  return (__assign(__assign({}, obj), (_a = {}, _a[f.name] = null, _a)));
23
32
  }, {});
24
- for (var i = data.length; i < MINIMUM_ROW_COUNT; i++) {
25
- data.push(__assign(__assign({}, emptyRecord), { _meta: {
26
- id: getRowId(i),
27
- rowIndex: i,
28
- } }));
29
- }
30
- return data;
33
+ var newData = Array.from({ length: MINIMUM_ROW_COUNT - data.length }, function (_, index) { return (__assign(__assign({}, emptyRecord), { _meta: {
34
+ id: getRowId(data.length + index),
35
+ rowIndex: data.length + index,
36
+ } })); });
37
+ return __spreadArray(__spreadArray([], data, true), newData, true);
31
38
  };
32
- export var addMeta = function (record, index) {
39
+ export var addMeta = function (record, index, uploadedRow) {
33
40
  var _a;
41
+ if (uploadedRow === void 0) { uploadedRow = null; }
34
42
  var rId = getRowId(index);
35
43
  var meta = (_a = record._meta) !== null && _a !== void 0 ? _a : {};
36
- return __assign(__assign({}, record), { _meta: __assign(__assign({}, meta), { id: rId, rowIndex: index, touched: false }) });
44
+ return __assign(__assign({}, record), { _meta: __assign(__assign({}, meta), { id: rId, rowIndex: index, touched: false, uploadedRow: uploadedRow }) });
37
45
  };
38
46
  export var recordListToDataSet = function (data, fields) {
39
47
  var initialData = data;
@@ -59,7 +67,7 @@ var transformToRecords = function (_a) {
59
67
  return (__assign(__assign({}, byLabel), (_a = {}, _a[header.label] = header, _a)));
60
68
  }, {});
61
69
  var getRecord = function (row, index) {
62
- var record = addMeta({}, index);
70
+ var record = addMeta({}, index, row);
63
71
  matchedColumnsLabels.forEach(function (_a) {
64
72
  var label = _a.label, index = _a.index;
65
73
  var enumSet = enumFieldValueMatchings
@@ -1,4 +1,4 @@
1
- import { FormatRecord, ImporterOptions, OnSubmit, OnValidateRecord } from "../types";
1
+ import { FormatRecord, ImporterOptions, OnSubmit, OnValidateRecord, TemplateHeader } from "../types";
2
2
  export declare const ACCOUNT_ROUTES: {
3
3
  TEMPLATES: string;
4
4
  };
@@ -13,8 +13,9 @@ type ImporterProps = {
13
13
  onValidateRecord?: OnValidateRecord;
14
14
  onSubmit?: OnSubmit;
15
15
  onClose: () => void;
16
+ dynamicColumns: TemplateHeader[];
16
17
  };
17
- declare const Importer: ({ templateSlug, apiToken, options, formatRecord, onValidateRecord, onSubmit, onClose, }: ImporterProps) => JSX.Element;
18
+ declare const Importer: ({ templateSlug, apiToken, options, formatRecord, onValidateRecord, onSubmit, onClose, dynamicColumns, }: ImporterProps) => JSX.Element;
18
19
  export * from "./common/Spreadsheet";
19
20
  export * from "./common/utils";
20
21
  export * from "./Review/ReviewContextProvider";
@@ -12,7 +12,6 @@ var __assign = (this && this.__assign) || function () {
12
12
  import { jsx as _jsx } from "react/jsx-runtime";
13
13
  import { ImporterContextProvider } from "./contexts/ImporterContextProvider";
14
14
  import { ImporterWithContext } from "./ImporterWithContext";
15
- import { useFullscreenOverlay } from "./useFullscreenOverlay";
16
15
  export var ACCOUNT_ROUTES = {
17
16
  TEMPLATES: "/importers",
18
17
  };
@@ -20,9 +19,8 @@ export var ACCOUNT_VIEW_PATH = "/account";
20
19
  var p = function (path) { return "".concat(ACCOUNT_VIEW_PATH).concat(path); };
21
20
  export var TEMPLATES_ROUTE = p(ACCOUNT_ROUTES.TEMPLATES);
22
21
  var Importer = function (_a) {
23
- var templateSlug = _a.templateSlug, apiToken = _a.apiToken, options = _a.options, formatRecord = _a.formatRecord, onValidateRecord = _a.onValidateRecord, onSubmit = _a.onSubmit, onClose = _a.onClose;
24
- useFullscreenOverlay();
25
- return (_jsx(ImporterContextProvider, __assign({ options: options, templateSlug: templateSlug, apiToken: apiToken, formatRecord: formatRecord, onValidateRecord: onValidateRecord, onClose: onClose, onSubmit: onSubmit }, { children: _jsx(ImporterWithContext, {}) })));
22
+ var templateSlug = _a.templateSlug, apiToken = _a.apiToken, options = _a.options, formatRecord = _a.formatRecord, onValidateRecord = _a.onValidateRecord, onSubmit = _a.onSubmit, onClose = _a.onClose, dynamicColumns = _a.dynamicColumns;
23
+ return (_jsx(ImporterContextProvider, __assign({ options: options, templateSlug: templateSlug, apiToken: apiToken, formatRecord: formatRecord, onValidateRecord: onValidateRecord, onClose: onClose, onSubmit: onSubmit, dynamicColumns: dynamicColumns }, { children: _jsx(ImporterWithContext, {}) })));
26
24
  };
27
25
  export * from "./common/Spreadsheet";
28
26
  export * from "./common/utils";
@@ -19,27 +19,16 @@ import styled from "styled-components";
19
19
  import { TooltipProvider } from "../../../common/TooltipProvider";
20
20
  import { ConfirmationModal } from "../../../common/ConfirmationModal";
21
21
  import { useSpreadsheetContext } from "../../../Importer";
22
- import { useImporterContext } from "../../../Importer/contexts/ImporterContextProvider";
23
22
  import { DeleteIcon, ConfirmationDeleteIcon } from "./icons";
24
- import { addToast } from "../../../common/Toast";
25
23
  import { Div } from "../../../styled/utils";
26
24
  import { ActionButton } from "./TableActions.styles";
25
+ import { useTranslation } from "react-i18next";
27
26
  var StyledTooltipProvider = styled(TooltipProvider)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n width: fit-content;\n"], ["\n width: fit-content;\n"])));
28
- var filterByRecordsThatContainsValues = function (mainObject) {
29
- return mainObject.filter(function (obj) {
30
- for (var key in obj) {
31
- if (key !== "_meta" && obj[key] !== null && obj[key] !== undefined) {
32
- return true;
33
- }
34
- }
35
- return false;
36
- });
37
- };
38
27
  export var DeleteSelectedRows = function (_a) {
39
28
  var _b = _a.testId, testId = _b === void 0 ? "ta-delete-rows" : _b;
40
29
  var _c = useState(false), isConfirmationModalOpen = _c[0], setIsConfirmationModalOpen = _c[1];
41
- var _d = useSpreadsheetContext(), data = _d.data, filteredInputValue = _d.filteredInputValue, deleteRecords = _d.deleteRecords, selectedRows = _d.selectedRows, setSelectedRows = _d.setSelectedRows, setFilteredInputValue = _d.setFilteredInputValue;
42
- var _e = useImporterContext(), setCurrentStepIndex = _e.setCurrentStepIndex, isUsingManualImport = _e.isUsingManualImport;
30
+ var _d = useSpreadsheetContext(), deleteRecords = _d.deleteRecords, selectedRows = _d.selectedRows, setSelectedRows = _d.setSelectedRows, setFilteredInputValue = _d.setFilteredInputValue;
31
+ var t = useTranslation("review").t;
43
32
  var toggleModalVisibility = function () {
44
33
  setIsConfirmationModalOpen(function (oldValue) { return !oldValue; });
45
34
  };
@@ -47,19 +36,15 @@ export var DeleteSelectedRows = function (_a) {
47
36
  setSelectedRows([]);
48
37
  toggleModalVisibility();
49
38
  setFilteredInputValue("");
50
- var validData = filterByRecordsThatContainsValues(data);
51
- // If user is deleting every row, but not using the manual import option
52
- if (!isUsingManualImport.current &&
53
- !filteredInputValue &&
54
- selectedRows.length === validData.length) {
55
- setCurrentStepIndex(0);
56
- return addToast("You have deleted all the rows. You will be redirect to the upload step.", "success");
57
- }
58
39
  deleteRecords(selectedRows);
59
40
  };
60
- var DescriptionUI = function () { return (_jsx(_Fragment, { children: _jsxs(Div, { children: ["Are you sure you want to delete ", selectedRows.length, " row", selectedRows.length > 1 ? "s" : "", "?"] }) })); };
61
- var confirmationModalUI = (_jsx(ConfirmationModal, { isOpen: isConfirmationModalOpen, handleClose: toggleModalVisibility, title: "Delete Selected Row".concat(selectedRows.length > 1 ? "s" : ""), description: _jsx(DescriptionUI, {}), onSubmit: handleDeleteRecord, buttonText: "Yes, delete", icon: ConfirmationDeleteIcon }));
41
+ var DescriptionUI = function () { return (_jsx(_Fragment, { children: _jsxs(Div, { children: [t("table_actions.delete_rows.confirmation_modal", {
42
+ length: selectedRows.length,
43
+ }), selectedRows.length > 1 ? "s" : "", "?"] }) })); };
44
+ var confirmationModalUI = (_jsx(ConfirmationModal, { isOpen: isConfirmationModalOpen, handleClose: toggleModalVisibility, title: "".concat(t("table_actions.delete_rows.modal_title")).concat(selectedRows.length > 1 ? "s" : ""), description: _jsx(DescriptionUI, {}), onSubmit: handleDeleteRecord, buttonText: t("table_actions.delete_rows.yes_delete"), icon: ConfirmationDeleteIcon }));
62
45
  var isDeleteButtonDisabled = selectedRows.length <= 0;
63
- return (_jsxs(_Fragment, { children: [confirmationModalUI, _jsx(StyledTooltipProvider, __assign({ tooltip: isDeleteButtonDisabled ? "Select rows to delete" : "Delete Row", placement: "right", flip: false, centered: true, "data-testid": testId }, { children: _jsx(ActionButton, __assign({ onClick: toggleModalVisibility, disabled: isDeleteButtonDisabled }, { children: _jsx(DeleteIcon, {}) })) }))] }));
46
+ return (_jsxs(_Fragment, { children: [confirmationModalUI, _jsx(StyledTooltipProvider, __assign({ tooltip: isDeleteButtonDisabled
47
+ ? t("table_actions.delete_rows.select_rows")
48
+ : t("table_actions.delete_rows.delete_row"), placement: "right", flip: false, centered: true, "data-testid": testId }, { children: _jsx(ActionButton, __assign({ onClick: toggleModalVisibility, disabled: isDeleteButtonDisabled }, { children: _jsx(DeleteIcon, {}) })) }))] }));
64
49
  };
65
50
  var templateObject_1;
@@ -14,8 +14,10 @@ import { DownloadIcon } from "./icons";
14
14
  import { useReviewContext } from "../../../Importer";
15
15
  import { TooltipProvider } from "../../../common/TooltipProvider";
16
16
  import { ActionButton } from "./TableActions.styles";
17
+ import { useTranslation } from "react-i18next";
17
18
  export var ExportData = function (_a) {
18
19
  var _b = _a.testId, testId = _b === void 0 ? "ta-export-data" : _b;
19
20
  var onExport = useReviewContext().onExport;
20
- return (_jsx(TooltipProvider, __assign({ tooltip: "Export your data", placement: "right", flip: false, centered: true, "data-testid": testId }, { children: _jsx(ActionButton, __assign({ onClick: onExport }, { children: _jsx(DownloadIcon, {}) })) })));
21
+ var t = useTranslation("review").t;
22
+ return (_jsx(TooltipProvider, __assign({ tooltip: t("table_actions.export_your_data.tooltip"), placement: "right", flip: false, centered: true, "data-testid": testId }, { children: _jsx(ActionButton, __assign({ onClick: onExport }, { children: _jsx(DownloadIcon, {}) })) })));
21
23
  };
@@ -0,0 +1 @@
1
+ export declare const FilterByErrors: () => JSX.Element;
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import * as S from "./FilterByErrors.styles";
4
+ import { useSpreadsheetContext } from "../../../../Importer";
5
+ import { formatErrors, getUniqueErrors } from "./functions";
6
+ import { useTranslation } from "react-i18next";
7
+ import { addToast } from "../../../../common/Toast";
8
+ export var FilterByErrors = function () {
9
+ var _a = useSpreadsheetContext(), errors = _a.errors, fields = _a.fields, selectedErrorToFilter = _a.selectedErrorToFilter, setSelectedErrorToFilter = _a.setSelectedErrorToFilter;
10
+ var _b = useState(false), isMenuOpened = _b[0], setIsMenuOpened = _b[1];
11
+ var t = useTranslation("review").t;
12
+ var prefix = "Filter by errors: ";
13
+ var onToggle = function (isOpen) {
14
+ if (errorArray.length === 0)
15
+ return;
16
+ setIsMenuOpened(isOpen);
17
+ };
18
+ var onChange = function (selected) {
19
+ if (selected) {
20
+ var selectedField = fields.filter(function (field) { return field.name === selected; });
21
+ var label = selectedField[0].label || selected;
22
+ addToast("Showing only the rows with error on the ".concat(label, " column"), "success");
23
+ }
24
+ setSelectedErrorToFilter(selected || "");
25
+ };
26
+ var uniqueErrors = getUniqueErrors(fields, errors);
27
+ var errorArray = formatErrors(fields, uniqueErrors);
28
+ // the average size of each character in the input (in px)
29
+ var widthPerCharacter = 5.3;
30
+ var amountOfCharacters = prefix.length + (selectedErrorToFilter === null || selectedErrorToFilter === void 0 ? void 0 : selectedErrorToFilter.length) || 0;
31
+ // 24 + 24 -> padding right and left + 48px of the X icon area
32
+ var totalWidth = widthPerCharacter * amountOfCharacters + 24 + 48;
33
+ var inputWidth = selectedErrorToFilter ? "".concat(totalWidth, "px") : "fit-content";
34
+ var search_or_select = t("table_actions.filter_by_errors.search_or_select");
35
+ var filter_by_errors = t("table_actions.filter_by_errors.filter_by_errors");
36
+ return (_jsx(S.StyledAutocomplete, { placement: "bottom", placeholder: isMenuOpened ? search_or_select : filter_by_errors, onChange: onChange, value: selectedErrorToFilter, options: errorArray, isDisabled: errorArray.length === 0, isInputDisabled: errorArray.length === 0, onToggle: onToggle, inputWidth: inputWidth, "data-testid": "ta-filter-by-errors", prefix: prefix }));
37
+ };
@@ -0,0 +1,6 @@
1
+ type StyledAutocompleteProps = {
2
+ inputWidth: string;
3
+ isDisabled: boolean;
4
+ };
5
+ export declare const StyledAutocomplete: import("styled-components").StyledComponent<({ label, isDisabled, isInputDisabled, placeholder, value, icon, onChange, placement, options, onToggle, id, labelTooltip, prefix, ...props }: import("../../../../common/inputs/Autocomplete").Props) => JSX.Element, import("styled-components").DefaultTheme, StyledAutocompleteProps, never>;
6
+ export {};
@@ -0,0 +1,24 @@
1
+ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
2
+ if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
3
+ return cooked;
4
+ };
5
+ import styled, { css } from "styled-components";
6
+ import { Autocomplete } from "../../../../common/inputs/Autocomplete";
7
+ import { textStyles } from "../../../../styled/theme/textStyles";
8
+ export var StyledAutocomplete = styled(Autocomplete)(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n &,\n * {\n box-sizing: border-box !important;\n\n ", "\n }\n\n div[data-popper-placement=\"bottom\"] > div {\n display: flex;\n flex-direction: column;\n gap: 8px;\n outline: 1px solid red;\n padding: 8px;\n\n > div div {\n padding: 6px 12px;\n }\n\n ", "\n }\n\n input {\n ", ";\n background-color: ", ";\n border: 1px solid transparent;\n font-family: \"DM Sans\";\n font-size: 14px;\n font-weight: 400;\n height: 32px;\n padding: 6px 12px;\n width: ", ";\n\n ::placeholder {\n color: ", ";\n }\n\n :focus {\n border: none;\n box-shadow: none;\n }\n }\n"], ["\n &,\n * {\n box-sizing: border-box !important;\n\n ", "\n }\n\n div[data-popper-placement=\"bottom\"] > div {\n display: flex;\n flex-direction: column;\n gap: 8px;\n outline: 1px solid red;\n padding: 8px;\n\n > div div {\n padding: 6px 12px;\n }\n\n ", "\n }\n\n input {\n ", ";\n background-color: ", ";\n border: 1px solid transparent;\n font-family: \"DM Sans\";\n font-size: 14px;\n font-weight: 400;\n height: 32px;\n padding: 6px 12px;\n width: ", ";\n\n ::placeholder {\n color: ", ";\n }\n\n :focus {\n border: none;\n box-shadow: none;\n }\n }\n"])), function (_a) {
9
+ var isDisabled = _a.isDisabled;
10
+ return isDisabled && css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n cursor: not-allowed !important;\n "], ["\n cursor: not-allowed !important;\n "])));
11
+ }, function (_a) {
12
+ var isDisabled = _a.isDisabled;
13
+ return isDisabled && css(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n cursor: not-allowed;\n "], ["\n cursor: not-allowed;\n "])));
14
+ }, textStyles.body3, function (_a) {
15
+ var theme = _a.theme;
16
+ return theme.colors.orange50;
17
+ }, function (_a) {
18
+ var inputWidth = _a.inputWidth;
19
+ return inputWidth;
20
+ }, function (_a) {
21
+ var theme = _a.theme;
22
+ return theme.colors.black;
23
+ });
24
+ var templateObject_1, templateObject_2, templateObject_3;
@@ -0,0 +1,11 @@
1
+ import { Field, BatchValidationErrors } from "../../../../types";
2
+ type UniqueError = {
3
+ fieldName: string;
4
+ };
5
+ type Error = {
6
+ value: string;
7
+ label: string;
8
+ };
9
+ export declare const getUniqueErrors: (fields: Field[], errors: BatchValidationErrors) => UniqueError[];
10
+ export declare const formatErrors: (fields: Field[], uniqueErrors: any) => Error[];
11
+ export {};
@@ -0,0 +1,35 @@
1
+ export var getUniqueErrors = function (fields, errors) {
2
+ var fieldKeys = new Set(fields.map(function (field) { return field.name; }));
3
+ var uniqueErrors = [];
4
+ for (var _i = 0, _a = Object.entries(errors); _i < _a.length; _i++) {
5
+ var _b = _a[_i], _1 = _b[0], errorObj = _b[1];
6
+ for (var _c = 0, _d = Object.entries(errorObj); _c < _d.length; _c++) {
7
+ var fieldName = _d[_c][0];
8
+ if (fieldKeys.has(fieldName)) {
9
+ uniqueErrors.push({ fieldName: fieldName });
10
+ }
11
+ }
12
+ }
13
+ return uniqueErrors;
14
+ };
15
+ export var formatErrors = function (fields, uniqueErrors) {
16
+ var errorMap = new Map();
17
+ var orderedErrorArray = [];
18
+ fields.forEach(function (field) {
19
+ errorMap.set(field.name, field);
20
+ });
21
+ fields.forEach(function (field) {
22
+ var name = field.name, label = field.label;
23
+ if (uniqueErrors.some(function (_a) {
24
+ var fieldName = _a.fieldName;
25
+ return fieldName === name;
26
+ }) &&
27
+ !orderedErrorArray.some(function (error) { return error.value === name; })) {
28
+ orderedErrorArray.push({
29
+ value: name,
30
+ label: label,
31
+ });
32
+ }
33
+ });
34
+ return orderedErrorArray;
35
+ };
@@ -0,0 +1 @@
1
+ export * from "./FilterByErrors";
@@ -0,0 +1 @@
1
+ export * from "./FilterByErrors";
@@ -22,6 +22,7 @@ import { useRef, useState } from "react";
22
22
  import { colors } from "../../../styled/theme/colorPalette";
23
23
  import { textStyles } from "../../../styled/theme/textStyles";
24
24
  import { TooltipProvider } from "../../../common/TooltipProvider";
25
+ import { useTranslation } from "react-i18next";
25
26
  var Wrapper = styled.div(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n background: ", ";\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n gap: 8px;\n height: 24px;\n overflow: hidden;\n padding: 8px;\n position: relative;\n transition: width 0.25s ease-in-out;\n width: ", ";\n"], ["\n background: ", ";\n border-radius: 4px;\n cursor: pointer;\n display: flex;\n gap: 8px;\n height: 24px;\n overflow: hidden;\n padding: 8px;\n position: relative;\n transition: width 0.25s ease-in-out;\n width: ", ";\n"])), function (_a) {
26
27
  var isOpen = _a.isOpen;
27
28
  return (isOpen ? colors.orange50 : "none");
@@ -39,6 +40,7 @@ var SearchInput = function (_a) {
39
40
  var _b = useDebounce(value, onChange, 300), _value = _b._value, set_Value = _b.set_Value;
40
41
  var inputRef = useRef(null);
41
42
  var _c = useState(false), isOpen = _c[0], setIsOpen = _c[1];
43
+ var t = useTranslation("review").t;
42
44
  var handleInputChange = function (_a) {
43
45
  var target = _a.target;
44
46
  set_Value(target.value);
@@ -57,7 +59,7 @@ var SearchInput = function (_a) {
57
59
  }
58
60
  }
59
61
  };
60
- return (_jsx(TooltipProvider, __assign({ tooltip: !isOpen ? "Search something" : "", placement: "right", flip: false, centered: true, "data-testid": testId }, { children: _jsxs(Wrapper, __assign({ isOpen: isOpen, onClick: handleWrapperClick }, { children: [_jsx(IconWrapper, { children: _jsx(SearchIcon, {}) }), _jsx(Input, { isOpen: isOpen, ref: inputRef, value: _value, onChange: handleInputChange, onBlur: handleInputOnBlur, type: "text", placeholder: "Search something..." })] })) })));
62
+ return (_jsx(TooltipProvider, __assign({ tooltip: !isOpen ? t("table_actions.search_rows.tooltip") : "", placement: "right", flip: false, centered: true, w: "auto", "data-testid": testId }, { children: _jsxs(Wrapper, __assign({ isOpen: isOpen, onClick: handleWrapperClick }, { children: [_jsx(IconWrapper, { children: _jsx(SearchIcon, {}) }), _jsx(Input, { isOpen: isOpen, ref: inputRef, value: _value, onChange: handleInputChange, onBlur: handleInputOnBlur, type: "text", placeholder: t("table_actions.search_rows.placeholder") })] })) })));
61
63
  };
62
64
  export var SearchRows = function (_a) {
63
65
  var _b = _a.testId, testId = _b === void 0 ? "ta-search-rows" : _b;
@@ -26,7 +26,8 @@ import { DeleteSelectedRows } from "./DeleteSelectedRows";
26
26
  import { SearchRows } from "./SearchRows";
27
27
  import { ExportData } from "./ExportData";
28
28
  import { ButtonActionsContainer, TableActionsContainer, TableActionsContent, } from "./TableActions.styles";
29
+ import { FilterByErrors } from "./FilterByErrors/FilterByErrors";
29
30
  export var TableActions = function (_a) {
30
31
  var _b = _a.tableActionsHeight, tableActionsHeight = _b === void 0 ? defaultTableActionsHeightPx : _b, props = __rest(_a, ["tableActionsHeight"]);
31
- return (_jsx(TableActionsContainer, __assign({ height: tableActionsHeight }, props, { children: _jsxs(TableActionsContent, { children: [_jsx(SearchRows, {}), _jsxs(ButtonActionsContainer, { children: [_jsx(DeleteSelectedRows, {}), _jsx(ExportData, {})] })] }) })));
32
+ return (_jsx(TableActionsContainer, __assign({ height: tableActionsHeight }, props, { children: _jsxs(TableActionsContent, { children: [_jsx(SearchRows, {}), _jsx(FilterByErrors, {}), _jsxs(ButtonActionsContainer, { children: [_jsx(DeleteSelectedRows, {}), _jsx(ExportData, {})] })] }) })));
32
33
  };
@@ -4,7 +4,7 @@ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cook
4
4
  };
5
5
  import styled from "styled-components";
6
6
  import { Div } from "../../../styled/utils";
7
- export var TableActionsContainer = styled(Div)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n align-items: center;\n background: ", ";\n border-top: 1px solid ", ";\n display: flex;\n overflow: hidden;\n padding: 8px 32px;\n width: 100%;\n\n * {\n box-sizing: content-box;\n }\n"], ["\n align-items: center;\n background: ", ";\n border-top: 1px solid ", ";\n display: flex;\n overflow: hidden;\n padding: 8px 32px;\n width: 100%;\n\n * {\n box-sizing: content-box;\n }\n"])), function (_a) {
7
+ export var TableActionsContainer = styled(Div)(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n align-items: center;\n background: ", ";\n border-top: 1px solid ", ";\n display: flex;\n padding: 8px 32px;\n width: 100%;\n\n * {\n box-sizing: content-box;\n }\n"], ["\n align-items: center;\n background: ", ";\n border-top: 1px solid ", ";\n display: flex;\n padding: 8px 32px;\n width: 100%;\n\n * {\n box-sizing: content-box;\n }\n"])), function (_a) {
8
8
  var theme = _a.theme;
9
9
  return theme.colors.white;
10
10
  }, function (_a) {
@@ -0,0 +1,20 @@
1
+ /// <reference types="react" />
2
+ import { BatchValidationErrors, Field, RecordDataSet } from "../../../types";
3
+ interface UseTableActionsProps {
4
+ setErrors: React.Dispatch<React.SetStateAction<BatchValidationErrors>>;
5
+ setWarnings: React.Dispatch<React.SetStateAction<BatchValidationErrors>>;
6
+ }
7
+ export type DeleteRecords = (setDataSet: React.Dispatch<React.SetStateAction<RecordDataSet>>, selectedRecords: string[], errors: BatchValidationErrors, warnings: BatchValidationErrors, isDeletingAllRows: boolean) => void;
8
+ export type FilterRecordsBySearchValue = (obj: RecordDataSet, value: string, fields: Field[]) => RecordDataSet;
9
+ export type FilterRecordsByError = (obj: RecordDataSet, keyToFilter: string, errors: BatchValidationErrors, fields: Field[]) => RecordDataSet;
10
+ interface UseTableActionsProps {
11
+ setErrors: React.Dispatch<React.SetStateAction<BatchValidationErrors>>;
12
+ setWarnings: React.Dispatch<React.SetStateAction<BatchValidationErrors>>;
13
+ fields: Field[];
14
+ }
15
+ export declare const useTableActions: ({ setErrors, setWarnings, fields, }: UseTableActionsProps) => {
16
+ deleteRecords: DeleteRecords;
17
+ filterRecordsBySearchValue: (obj: RecordDataSet, value: string) => RecordDataSet;
18
+ filterRecordsByError: (obj: RecordDataSet, keyToFilter: string, errors: BatchValidationErrors, fields: Field[]) => {};
19
+ };
20
+ export {};
@@ -0,0 +1,96 @@
1
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
2
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
3
+ if (ar || !(i in from)) {
4
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
5
+ ar[i] = from[i];
6
+ }
7
+ }
8
+ return to.concat(ar || Array.prototype.slice.call(from));
9
+ };
10
+ import { useRef } from "react";
11
+ import { addEmptyRows, recordListToDataSet } from "../../../Importer/data";
12
+ var removeErrorsOrWarningsFromObject = function (obj, keysToRemove) {
13
+ var keysSet = new Set(keysToRemove);
14
+ var newObj = {};
15
+ for (var key in obj) {
16
+ if (Object.prototype.hasOwnProperty.call(obj, key) && !(keysSet === null || keysSet === void 0 ? void 0 : keysSet.has(key))) {
17
+ newObj[key] = obj[key];
18
+ }
19
+ }
20
+ return newObj;
21
+ };
22
+ var isObject = function (value) {
23
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24
+ };
25
+ var includesSearchValue = function (value, searchValue) {
26
+ if (typeof value === "string" || typeof value === "number") {
27
+ var stringValue = String(value).toLowerCase();
28
+ var searchValueLower = searchValue.toLowerCase();
29
+ return stringValue.includes(searchValueLower);
30
+ }
31
+ return false;
32
+ };
33
+ export var useTableActions = function (_a) {
34
+ var setErrors = _a.setErrors, setWarnings = _a.setWarnings, fields = _a.fields;
35
+ var allRowsDeleted = useRef([]);
36
+ // Delete records from dataSet and from validations
37
+ var deleteRecords = function (setDataSet, selectedRecords, errors, warnings, isDeletingAllRows) {
38
+ var rowsToBeAddedIntoDeletedOnes = Array.from(new Set(__spreadArray(__spreadArray([], selectedRecords, true), allRowsDeleted.current, true)));
39
+ allRowsDeleted.current = rowsToBeAddedIntoDeletedOnes;
40
+ var newErrors = removeErrorsOrWarningsFromObject(errors, rowsToBeAddedIntoDeletedOnes);
41
+ var newWarnings = removeErrorsOrWarningsFromObject(warnings, rowsToBeAddedIntoDeletedOnes);
42
+ setDataSet(function (oldValues) {
43
+ if (!rowsToBeAddedIntoDeletedOnes)
44
+ return oldValues;
45
+ if (isDeletingAllRows) {
46
+ allRowsDeleted.current = [];
47
+ return recordListToDataSet(addEmptyRows([], fields), fields);
48
+ }
49
+ var dataSetWithoutDeletedRecords = {};
50
+ for (var objKey in oldValues) {
51
+ if (!selectedRecords.includes(objKey)) {
52
+ dataSetWithoutDeletedRecords[objKey] = oldValues[objKey];
53
+ }
54
+ }
55
+ return dataSetWithoutDeletedRecords;
56
+ });
57
+ setErrors(newErrors);
58
+ setWarnings(newWarnings);
59
+ };
60
+ // Filter records by search value
61
+ var filterRecordsBySearchValue = function (obj, value) {
62
+ var filteredObj = {};
63
+ for (var _i = 0, _a = Object.entries(obj); _i < _a.length; _i++) {
64
+ var _b = _a[_i], key = _b[0], currentObj = _b[1];
65
+ if (!isObject(currentObj)) {
66
+ continue;
67
+ }
68
+ var matches = Object.values(currentObj).some(function (propertyValue) {
69
+ return includesSearchValue(propertyValue, value);
70
+ });
71
+ if (matches) {
72
+ filteredObj[key] = currentObj;
73
+ }
74
+ }
75
+ // To ensure that rows are always displayed, even when the search query is empty,
76
+ // we return an empty record list when the search yields no results.
77
+ if (Object.keys(filteredObj).length === 0) {
78
+ return recordListToDataSet(addEmptyRows([], fields), fields);
79
+ }
80
+ return filteredObj;
81
+ };
82
+ // Filter records by selected column error
83
+ var filterRecordsByError = function (obj, keyToFilter, errors, fields) {
84
+ var filteredObj = {};
85
+ var filteredKeys = Object.keys(errors).filter(function (key) { var _a, _b; return ((_b = (_a = obj[key]) === null || _a === void 0 ? void 0 : _a._meta) === null || _b === void 0 ? void 0 : _b.isInvalid) && errors[key][keyToFilter]; });
86
+ for (var i = 0; i < filteredKeys.length; i++) {
87
+ filteredObj[filteredKeys[i]] = obj[filteredKeys[i]];
88
+ }
89
+ return filteredObj;
90
+ };
91
+ return {
92
+ deleteRecords: deleteRecords,
93
+ filterRecordsBySearchValue: filterRecordsBySearchValue,
94
+ filterRecordsByError: filterRecordsByError,
95
+ };
96
+ };
@@ -1,25 +1,23 @@
1
1
  import React from "react";
2
- import { TableViewProps } from ".";
3
2
  import { DivCSSProps } from "../../../styled/utils";
4
3
  import { SortDirection } from "../TableDataProvider";
4
+ import { TableViewProps } from "./types";
5
5
  type TableViewHeaderProps = {
6
6
  isLast: boolean;
7
- shouldHaveCustomScrollbar?: boolean;
8
7
  };
9
- export declare const TableViewHeader: import("styled-components").StyledComponent<"div", import("styled-components").DefaultTheme, import("../../../styled/utils").CSSProps & {
10
- shouldHaveCustomScrollbar?: boolean;
11
- } & TableViewHeaderProps, never>;
8
+ export declare const TableViewHeader: import("styled-components").StyledComponent<"div", import("styled-components").DefaultTheme, import("../../../styled/utils").CSSProps & TableViewHeaderProps, never>;
12
9
  type SortIndicatorProps = {
13
10
  direction: SortDirection;
14
11
  };
15
12
  export declare const SortIndicator: import("styled-components").StyledComponent<"div", import("styled-components").DefaultTheme, import("../../../styled/utils").CSSProps & SortIndicatorProps, never>;
16
13
  export declare const TableHeadersContainer: import("styled-components").StyledComponent<"div", import("styled-components").DefaultTheme, import("../../../styled/utils").CSSProps, never>;
17
14
  export declare const TableHeadersContent: import("styled-components").StyledComponent<"div", import("styled-components").DefaultTheme, import("../../../styled/utils").CSSProps, never>;
18
- type TableHeadersProps = Pick<TableViewProps, "columns" | "sortBy" | "setSortBy" | "rowHeight" | "rowWidth"> & {
15
+ type TableHeadersProps = Pick<TableViewProps, "columns" | "sortBy" | "setSortBy" | "rowHeight" | "rowWidthScalingFactor"> & {
19
16
  scrollLeft: number;
20
17
  height: number;
21
18
  containerRef: React.MutableRefObject<HTMLDivElement>;
22
- shouldHaveCustomScrollbar?: boolean;
19
+ containerWidth: number;
20
+ rowWidth: number;
23
21
  } & DivCSSProps;
24
- export declare const TableHeaders: ({ scrollLeft, columns, sortBy, rowHeight, containerRef, setSortBy, rowWidth, height, shouldHaveCustomScrollbar, ...props }: TableHeadersProps) => JSX.Element;
22
+ export declare const TableHeaders: ({ scrollLeft, columns, sortBy, rowHeight, containerRef, setSortBy, height, containerWidth, rowWidth, ...props }: TableHeadersProps) => JSX.Element;
25
23
  export {};