fuse-importer 0.23.4 → 0.23.7

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 (45) hide show
  1. package/lib/esm/Importer/FuseApi.js +1 -1
  2. package/lib/esm/Importer/ImporterContextProvider.d.ts +2 -0
  3. package/lib/esm/Importer/ImporterContextProvider.js +4 -1
  4. package/lib/esm/Importer/Review/index.js +1 -1
  5. package/lib/esm/Importer/SpreadsheetReviewContextProvider.d.ts +2 -1
  6. package/lib/esm/Importer/SpreadsheetReviewContextProvider.js +20 -9
  7. package/lib/esm/Importer/Stepper.js +4 -2
  8. package/lib/esm/Importer/Uploader/DragAndDropImporter/ImporterDropzone.js +1 -1
  9. package/lib/esm/Importer/Uploader/HeadersPreview.js +1 -1
  10. package/lib/esm/Importer/common/Spreadsheet/SpreadsheetContextProvider.d.ts +1 -0
  11. package/lib/esm/Importer/common/Spreadsheet/SpreadsheetContextProvider.js +81 -61
  12. package/lib/esm/Importer/common/Spreadsheet/SpreadsheetRowNumbers.d.ts +3 -3
  13. package/lib/esm/Importer/common/Spreadsheet/SpreadsheetRowNumbers.js +10 -10
  14. package/lib/esm/Importer/common/Spreadsheet/common/fields/index.d.ts +2 -2
  15. package/lib/esm/Importer/common/Spreadsheet/common/fields/index.js +32 -47
  16. package/lib/esm/Importer/common/Spreadsheet/common/index.js +11 -3
  17. package/lib/esm/Importer/common/Spreadsheet/index.js +18 -57
  18. package/lib/esm/Importer/index.js +2 -2
  19. package/lib/esm/api/index.d.ts +1 -0
  20. package/lib/esm/api/index.js +3 -3
  21. package/lib/esm/common/Modal.d.ts +7 -4
  22. package/lib/esm/common/Modal.js +2 -2
  23. package/lib/esm/common/Table/TableDataProvider.js +24 -23
  24. package/lib/esm/common/Table/TableView/TableHeaders.d.ts +3 -2
  25. package/lib/esm/common/Table/TableView/TableHeaders.js +1 -5
  26. package/lib/esm/common/Table/TableView/TableRow.d.ts +2 -2
  27. package/lib/esm/common/Table/TableView/TableRow.js +7 -10
  28. package/lib/esm/common/Table/TableView/index.d.ts +1 -2
  29. package/lib/esm/common/Table/TableView/index.js +52 -45
  30. package/lib/esm/common/TooltipProvider.d.ts +1 -0
  31. package/lib/esm/common/TooltipProvider.js +7 -7
  32. package/lib/esm/common/buttons.js +2 -2
  33. package/lib/esm/common/index.d.ts +1 -1
  34. package/lib/esm/common/index.js +2 -2
  35. package/lib/esm/common/inputs/Autocomplete.js +8 -4
  36. package/lib/esm/common/inputs/TextInput.d.ts +2 -1
  37. package/lib/esm/common/inputs/TextInput.js +3 -2
  38. package/lib/esm/styled/utils.d.ts +3 -0
  39. package/lib/esm/styled/utils.js +4 -2
  40. package/lib/esm/types.d.ts +11 -7
  41. package/lib/esm/utils/index.d.ts +1 -0
  42. package/lib/esm/utils/index.js +3 -0
  43. package/lib/main.js +1 -1
  44. package/lib/main.js.LICENSE.txt +9 -0
  45. package/package.json +18 -14
@@ -12,7 +12,7 @@ var __assign = (this && this.__assign) || function () {
12
12
  import { api } from "../api";
13
13
  import { baseUrls } from "./common/index";
14
14
  // copies the axios request config from axios.AxiosInstance type and adds
15
- // baseUrl based on environment and api token
15
+ // baseUrl based on environment and api key
16
16
  var FuseApi = /** @class */ (function () {
17
17
  function FuseApi(environment, apiToken) {
18
18
  this.environment = environment;
@@ -69,6 +69,8 @@ export declare type State = {
69
69
  importerOptions: ImporterOptions;
70
70
  theme: any;
71
71
  logoURL: string;
72
+ isSpreadsheetValid: boolean;
73
+ setIsSpreadsheetValid: React.Dispatch<boolean>;
72
74
  };
73
75
  export declare type Props = {
74
76
  templateSlug: string;
@@ -72,6 +72,7 @@ export var ImporterContextProvider = function (_a) {
72
72
  var _j = useState(null), templateHeaderMatchings = _j[0], setTemplateHeaderMatchings = _j[1];
73
73
  var _k = useState(null), enumFieldValueMatchings = _k[0], setEnumFieldValueMatchings = _k[1];
74
74
  var _l = useState(null), uploadedDataEnumFieldValues = _l[0], setUploadedDataEnumFieldValues = _l[1];
75
+ var _m = useState(false), isSpreadsheetValid = _m[0], setIsSpreadsheetValid = _m[1];
75
76
  var fuseApi = useMemo(function () { return new FuseApi(options.env, apiToken); }, [
76
77
  options.env,
77
78
  apiToken,
@@ -130,7 +131,7 @@ export var ImporterContextProvider = function (_a) {
130
131
  case 2:
131
132
  error_1 = _d.sent();
132
133
  errorMsg = ((_c = (_b = error_1.response) === null || _b === void 0 ? void 0 : _b.data) === null || _c === void 0 ? void 0 : _c.message) ||
133
- "There was an error preventing the data importer from loading. Check your API Token and try again.";
134
+ "There was an error preventing the data importer from loading. Check your API Key and try again.";
134
135
  setTemplateError(errorMsg);
135
136
  return [3 /*break*/, 3];
136
137
  case 3: return [2 /*return*/];
@@ -180,6 +181,8 @@ export var ImporterContextProvider = function (_a) {
180
181
  fuseApi: fuseApi,
181
182
  theme: style.theme,
182
183
  logoURL: style.logoURL,
184
+ isSpreadsheetValid: isSpreadsheetValid,
185
+ setIsSpreadsheetValid: setIsSpreadsheetValid,
183
186
  };
184
187
  return (_jsx(ImporterContext.Provider, __assign({ value: value }, { children: children })));
185
188
  };
@@ -76,7 +76,7 @@ var Review = function () {
76
76
  }, [templateHeaders]);
77
77
  var spreadsheetUI = useMemo(function () { return (_jsx(Div, { children: _jsx(Spreadsheet, __assign({ rowWidth: getSpreadsheetRowWidth(fields, 6), options: {
78
78
  batchValidationDelayMs: batchValidationDelayMs,
79
- batchValidationSize: batchValidationSize || initialData.length,
79
+ batchValidationSize: batchValidationSize,
80
80
  } }, {
81
81
  submittedData: submittedData,
82
82
  appResponse: appResponse,
@@ -13,7 +13,8 @@ declare type State = {
13
13
  declare type Props = {
14
14
  onSubmit?: OnSubmit;
15
15
  children: JSX.Element;
16
+ loadingComponent?: () => JSX.Element;
16
17
  };
17
- export declare const SpreadsheetReviewContextProvider: ({ children, onSubmit, }: Props) => JSX.Element;
18
+ export declare const SpreadsheetReviewContextProvider: ({ children, onSubmit, loadingComponent, }: Props) => JSX.Element;
18
19
  export declare const useSpreadsheetReviewContext: () => State;
19
20
  export {};
@@ -52,7 +52,7 @@ import { getUnsubmittedData } from "./common/utils";
52
52
  import { useImporterContext } from "./ImporterContextProvider";
53
53
  var SpreadsheetReviewContext = createContext({});
54
54
  export var SpreadsheetReviewContextProvider = function (_a) {
55
- var children = _a.children, onSubmit = _a.onSubmit;
55
+ var children = _a.children, onSubmit = _a.onSubmit, loadingComponent = _a.loadingComponent;
56
56
  var _b = useState(false), isSubmitting = _b[0], setIsSubmitting = _b[1];
57
57
  var _c = useState(null), reviewedData = _c[0], setReviewedData = _c[1];
58
58
  var _d = useState(null), submittedData = _d[0], setSubmittedData = _d[1];
@@ -67,14 +67,25 @@ export var SpreadsheetReviewContextProvider = function (_a) {
67
67
  switch (_a.label) {
68
68
  case 0:
69
69
  trackImportedRowsCount = function (rowCount) { return __awaiter(void 0, void 0, void 0, function () {
70
- return __generator(this, function (_a) {
71
- switch (_a.label) {
72
- case 0: return [4 /*yield*/, fuseApi.post("/api/v1/importer/templates/".concat(templateSlug, "/imports"), {
73
- row_count: rowCount,
74
- })];
70
+ var error_1, errorMessage;
71
+ var _a, _b;
72
+ return __generator(this, function (_c) {
73
+ switch (_c.label) {
74
+ case 0:
75
+ _c.trys.push([0, 2, , 3]);
76
+ return [4 /*yield*/, fuseApi.post("/api/v1/importer/templates/".concat(templateSlug, "/imports"), {
77
+ row_count: rowCount,
78
+ })];
75
79
  case 1:
76
- _a.sent();
77
- return [2 /*return*/];
80
+ _c.sent();
81
+ return [3 /*break*/, 3];
82
+ case 2:
83
+ error_1 = _c.sent();
84
+ errorMessage = ((_b = (_a = error_1 === null || error_1 === void 0 ? void 0 : error_1.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.error) ||
85
+ "There was an error submitting your dataset";
86
+ setAppResponse({ message: errorMessage });
87
+ return [3 /*break*/, 3];
88
+ case 3: return [2 /*return*/];
78
89
  }
79
90
  });
80
91
  }); };
@@ -110,7 +121,7 @@ export var SpreadsheetReviewContextProvider = function (_a) {
110
121
  onSubmit: onSubmitData,
111
122
  setReviewedData: setReviewedData,
112
123
  };
113
- return (_jsxs(SpreadsheetReviewContext.Provider, __assign({ value: value }, { children: [isSubmitting && _jsx(AppLoading, {}), children] })));
124
+ return (_jsxs(SpreadsheetReviewContext.Provider, __assign({ value: value }, { children: [isSubmitting ? (loadingComponent ? (loadingComponent()) : (_jsx(AppLoading, {}))) : null, children] })));
114
125
  };
115
126
  export var useSpreadsheetReviewContext = function () {
116
127
  return useContext(SpreadsheetReviewContext);
@@ -66,7 +66,9 @@ var Stepper = function (_a) {
66
66
  var _b = useState(false), isUnmatchedHeadersModalOpen = _b[0], setIsUnmatchedHeadersModalOpen = _b[1];
67
67
  var _c = useSpreadsheetReviewContext(), appResponse = _c.appResponse, isSpreadsheetReviewComplete = _c.isSpreadsheetReviewComplete, onSubmit = _c.onSubmit;
68
68
  var _d = useState(false), isSubmitModalOpen = _d[0], setIsSubmitModalOpen = _d[1];
69
- var _e = useImporterContext(), currentStepIndex = _e.currentStepIndex, setEnumFieldValueMatchings = _e.setEnumFieldValueMatchings, setCurrentStepIndex = _e.setCurrentStepIndex, templateHeaderMatchings = _e.templateHeaderMatchings, matcherSubstep = _e.matcherSubstep, setMatcherSubstep = _e.setMatcherSubstep, templateHeaders = _e.templateHeaders, uploadedDataEnumFieldValues = _e.uploadedDataEnumFieldValues, onClose = _e.onClose;
69
+ var _e = useImporterContext(), currentStepIndex = _e.currentStepIndex, setEnumFieldValueMatchings = _e.setEnumFieldValueMatchings, setCurrentStepIndex = _e.setCurrentStepIndex, templateHeaderMatchings = _e.templateHeaderMatchings, matcherSubstep = _e.matcherSubstep, setMatcherSubstep = _e.setMatcherSubstep, templateHeaders = _e.templateHeaders, uploadedDataEnumFieldValues = _e.uploadedDataEnumFieldValues, onClose = _e.onClose, isSpreadsheetValid = _e.isSpreadsheetValid, disableSubmitIfInvalid = _e.importerOptions.disableSubmitIfInvalid;
70
+ var isSubmitDisabled = (disableSubmitIfInvalid && !isSpreadsheetValid) ||
71
+ !isSpreadsheetReviewComplete;
70
72
  var submitModalUI = (_jsx(Modal, __assign({ isOpen: isSubmitModalOpen, onClose: function () { return setIsSubmitModalOpen(false); } }, { children: _jsxs(Div, __assign({ centered: true, flexColumn: true, p: 60 }, { children: [_jsx(Div, { children: submitSvg }), _jsx(Div, __assign({ h5: true, mt: 20 }, { children: "Ready to submit?" })), _jsx(Div, __assign({ body1: true, mt: 12, w: 448, textAlignCenter: true }, { children: "We didn't find anything wrong with your file. You're good to go!" })), _jsxs(Div, __assign({ dflex: true, mt: 40, w100: true, centered: true }, { children: [_jsx(Button, __assign({ w: 115, variant: "secondary", mr: 10, onClick: function () { return setIsSubmitModalOpen(false); } }, { children: "Go back" })), _jsx(Button, __assign({ w: 140, ml: 10, onClick: function () {
71
73
  onSubmit();
72
74
  setIsSubmitModalOpen(false);
@@ -130,7 +132,7 @@ var Stepper = function (_a) {
130
132
  var isMatchStep = currentStepIndex === 1;
131
133
  var isReviewStep = currentStepIndex === 2;
132
134
  var leftButtonUI = (_jsx(Div, __assign({ w: 100 }, { children: currentStepIndex > 0 && !appResponse && (_jsx(Button, __assign({ variant: "secondary", onClick: goBack }, { children: "Go back" }))) })));
133
- var rightButtonUI = (_jsxs(Div, __assign({ w: 100 }, { children: [isMatchStep && (_jsx(Button, __assign({ variant: "primary", onClick: continueToNextStep }, { children: "Continue" }))), isReviewStep && (_jsx(Button, __assign({ variant: "primary", isDisabled: !isSpreadsheetReviewComplete, onClick: function () { return setIsSubmitModalOpen(true); } }, { children: "Submit" })))] })));
135
+ var rightButtonUI = (_jsxs(Div, __assign({ w: 100 }, { children: [isMatchStep && (_jsx(Button, __assign({ variant: "primary", onClick: continueToNextStep }, { children: "Continue" }))), isReviewStep && (_jsx(Button, __assign({ variant: "primary", isDisabled: isSubmitDisabled, onClick: function () { return setIsSubmitModalOpen(true); } }, { children: "Submit" })))] })));
134
136
  return (_jsxs(_Fragment, { children: [unmatchedHeadersModalUI, submitModalUI, _jsxs(StepperWrapper, __assign({ pRelative: true, alignCenter: true, w100: true, h: 96, centered: true }, { children: [logoURL && _jsx(Logo, { src: logoURL, alt: "" }), _jsxs(Content, __assign({ spaceBetween: true, w: contentWidth }, { children: [leftButtonUI, _jsx(Div, __assign({ alignCenter: true }, { children: stepsUI })), rightButtonUI] })), _jsx(CloseIcon, __assign({ centered: true, clickable: true, onClick: onClose }, { children: closeIconCondensed }))] }))] }));
135
137
  };
136
138
  var Content = styled(Div)(function (_a) {
@@ -42,7 +42,7 @@ var ImporterDropzone = function () {
42
42
  var _a = useUploaderContext(), setIsUploading = _a.setIsUploading, setFileName = _a.setFileName;
43
43
  var setUploadedData = useImporterContext().setUploadedData;
44
44
  var validHeadersCount = function (headersLength) {
45
- var headersCountLimit = 50;
45
+ var headersCountLimit = 60;
46
46
  if (headersLength > headersCountLimit) {
47
47
  addToast("File cannot contain more than ".concat(headersCountLimit, " columns"), "error");
48
48
  return false;
@@ -74,7 +74,7 @@ var HeadersPreview = function () {
74
74
  };
75
75
  });
76
76
  }, []);
77
- return (_jsx(_Fragment, { children: _jsxs(Div, __assign({ flexColumn: true, centered: true, pt: 40 }, { children: [_jsx(Div, __assign({ h2: true, mb: 16 }, { children: "Verify Your Column Headers" })), _jsx(Div, __assign({ body1: true, mb: 24, textAlignCenter: true }, { children: "File must contain column headers to proceed." })), _jsx(HeaderButtons, {}), _jsx(Div, __assign({ w100: true, centered: true, mb: 36 }, { children: _jsx(Spreadsheet, __assign({ rowWidth: getSpreadsheetRowWidth(readonlyFields, 6), isReadOnly: true, initialData: formattedData }, { fields: readonlyFields }, { highlightFirstRow: true })) }))] })) }));
77
+ return (_jsx(_Fragment, { children: _jsxs(Div, __assign({ flexColumn: true, centered: true, pt: 40 }, { children: [_jsx(Div, __assign({ h2: true, mb: 16 }, { children: "Verify Your Column Headers" })), _jsx(Div, __assign({ body1: true, mb: 24, textAlignCenter: true }, { children: "File must contain column headers to proceed." })), _jsx(HeaderButtons, {}), _jsx(Div, __assign({ w100: true, centered: true, mb: 36 }, { children: _jsx(Spreadsheet, { rowWidth: getSpreadsheetRowWidth(readonlyFields, 6), isReadOnly: true, initialData: formattedData, fields: readonlyFields, highlightFirstRow: true }) }))] })) }));
78
78
  };
79
79
  export default HeadersPreview;
80
80
  var templateObject_1;
@@ -4,6 +4,7 @@ import { BatchValidationErrors, Field, OnValidateBatch, OnValidateRecord, Record
4
4
  export declare const getBatchErrors: (records: Record[], onValidateRecord: OnValidateRecord) => Promise<BatchValidationErrors>;
5
5
  declare type State = {
6
6
  rowWidth?: number;
7
+ dataRef: React.MutableRefObject<Record[]>;
7
8
  data: Record[];
8
9
  fields: Field[];
9
10
  isLoading: boolean;
@@ -55,9 +55,11 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
55
55
  return to.concat(ar || Array.prototype.slice.call(from));
56
56
  };
57
57
  import { jsx as _jsx } from "react/jsx-runtime";
58
- import { createContext, useContext, useEffect, useState, useMemo, } from "react";
58
+ import { createContext, useContext, useEffect, useState, useMemo, useCallback, useRef, } from "react";
59
59
  import { formatBatchErrors } from "../../..";
60
60
  import { getRecordErrors, getRenderedRecordWithErrors, recordIsEmpty, } from "./common";
61
+ import { sleep } from "../../../utils";
62
+ import { useImporterContext } from "../../ImporterContextProvider";
61
63
  var MINIMUM_ROW_COUNT = 20;
62
64
  var getRowId = function (id) { return "r".concat(id); };
63
65
  export var getBatchErrors = function (records, onValidateRecord) { return __awaiter(void 0, void 0, void 0, function () {
@@ -85,10 +87,14 @@ export var getBatchErrors = function (records, onValidateRecord) { return __awai
85
87
  });
86
88
  }); };
87
89
  var SpreadsheetContext = createContext({});
88
- var sleep = function (n) { return new Promise(function (resolve) { return setTimeout(resolve, n); }); };
90
+ var addMeta = function (d, i) { return (__assign(__assign({}, d), { _meta: { id: getRowId(i), rowIndex: i } })); };
89
91
  export var SpreadsheetContextProvider = function (_a) {
90
92
  var initialData = _a.initialData, _b = _a.rowWidth, rowWidth = _b === void 0 ? 1 : _b, _c = _a.onValidateRecord, onValidateRecord = _c === void 0 ? null : _c, _d = _a.onValidateBatch, onValidateBatch = _d === void 0 ? null : _d, appResponse = _a.appResponse, fields = _a.fields, options = _a.options, isReadOnly = _a.isReadOnly, highlightFirstRow = _a.highlightFirstRow, submittedData = _a.submittedData, setReviewedData = _a.setReviewedData, children = _a.children;
91
- var _e = useState(initialData.map(function (d, i) { return (__assign(__assign({}, d), { _meta: { id: getRowId(i), rowIndex: i } })); })), data = _e[0], setData = _e[1];
93
+ var mappedInitialData = useMemo(function () { return initialData.map(addMeta); }, [
94
+ initialData,
95
+ ]);
96
+ var _e = useState(mappedInitialData), data = _e[0], setData = _e[1];
97
+ var dataRef = useRef(mappedInitialData);
92
98
  var _f = useState(false), isLoading = _f[0], setIsLoading = _f[1];
93
99
  var _g = useState(null), sortByFieldErrors = _g[0], setSortByFieldErrors = _g[1];
94
100
  var _h = useState(true), isScrollingEnabled = _h[0], setIsScrollingEnabled = _h[1];
@@ -100,74 +106,85 @@ export var SpreadsheetContextProvider = function (_a) {
100
106
  batchValidationErrors: batchValidationErrors,
101
107
  submittedData: submittedData,
102
108
  }), columnErrorCounts = _l.columnErrorCounts, totalErrors = _l.totalErrors, isValidationComplete = _l.isValidationComplete;
109
+ var updateData = useCallback(function (data) {
110
+ dataRef.current = data;
111
+ setData(data);
112
+ }, []);
103
113
  useEffect(function () {
114
+ var batchValidationDelayMs = options.batchValidationDelayMs, _a = options.batchValidationSize, batchValidationSize = _a === void 0 ? 1000 : _a;
115
+ var batchSize = Math.min(Math.floor(batchValidationSize), data.length) || data.length;
116
+ var batchCount = Math.ceil(data.length / batchSize);
117
+ var isCancelled = false;
118
+ var addEmptyRows = function () {
119
+ var newData = __spreadArray([], data, true);
120
+ var emptyRecord = fields.reduce(function (obj, f) {
121
+ var _a;
122
+ return (__assign(__assign({}, obj), (_a = {}, _a[f.name] = null, _a)));
123
+ }, {});
124
+ for (var i = newData.length; i < MINIMUM_ROW_COUNT; i++) {
125
+ newData.push(__assign(__assign({}, emptyRecord), { _meta: {
126
+ id: getRowId(i),
127
+ rowIndex: i,
128
+ } }));
129
+ }
130
+ updateData(newData);
131
+ };
132
+ var validateInBatches = function () { return __awaiter(void 0, void 0, void 0, function () {
133
+ var validationErrors, batchIdx, idx, batch, errors, validationPercentage;
134
+ return __generator(this, function (_a) {
135
+ switch (_a.label) {
136
+ case 0:
137
+ validationErrors = {};
138
+ batchIdx = 0;
139
+ _a.label = 1;
140
+ case 1:
141
+ if (!(batchIdx < batchCount)) return [3 /*break*/, 5];
142
+ if (isCancelled)
143
+ return [3 /*break*/, 5];
144
+ idx = batchIdx * batchSize;
145
+ batch = data.slice(idx, idx + batchSize);
146
+ return [4 /*yield*/, (onValidateBatch
147
+ ? onValidateBatch(batch)
148
+ : getBatchErrors(batch, onValidateRecord))];
149
+ case 2:
150
+ errors = _a.sent();
151
+ validationErrors = __assign(__assign({}, validationErrors), errors);
152
+ // unblocks main thread for rendering ui
153
+ return [4 /*yield*/, sleep(batchValidationDelayMs)];
154
+ case 3:
155
+ // unblocks main thread for rendering ui
156
+ _a.sent();
157
+ validationPercentage = (Math.min(idx + batchSize, data.length) / data.length) * 100;
158
+ setBatchValidationPercentage(Math.floor(validationPercentage));
159
+ _a.label = 4;
160
+ case 4:
161
+ batchIdx++;
162
+ return [3 /*break*/, 1];
163
+ case 5:
164
+ if (!isCancelled)
165
+ setBatchValidationErrors(validationErrors);
166
+ return [2 /*return*/];
167
+ }
168
+ });
169
+ }); };
104
170
  var init = function () { return __awaiter(void 0, void 0, void 0, function () {
105
- var batchValidationDelayMs, batchValidationSize, addEmptyRows, validateInBatches;
106
171
  return __generator(this, function (_a) {
107
- batchValidationDelayMs = options.batchValidationDelayMs, batchValidationSize = options.batchValidationSize;
108
- addEmptyRows = function () {
109
- var newData = __spreadArray([], data, true);
110
- var emptyRecord = fields.reduce(function (obj, f) {
111
- var _a;
112
- return (__assign(__assign({}, obj), (_a = {}, _a[f.name] = null, _a)));
113
- }, {});
114
- for (var i = newData.length; i < MINIMUM_ROW_COUNT; i++) {
115
- newData.push(__assign(__assign({}, emptyRecord), { _meta: {
116
- id: getRowId(i),
117
- rowIndex: i,
118
- } }));
119
- }
120
- setData(newData);
121
- };
122
172
  if (data.length < MINIMUM_ROW_COUNT)
123
173
  addEmptyRows();
124
- validateInBatches = function () { return __awaiter(void 0, void 0, void 0, function () {
125
- var validationErrors, batchSize, batchCount, batchIdx, idx, batch, errors, validationPercentage;
126
- return __generator(this, function (_a) {
127
- switch (_a.label) {
128
- case 0:
129
- validationErrors = {};
130
- batchSize = Math.min(Math.floor(batchValidationSize), data.length) || data.length;
131
- batchCount = Math.ceil(data.length / batchSize);
132
- batchIdx = 0;
133
- _a.label = 1;
134
- case 1:
135
- if (!(batchIdx < batchCount)) return [3 /*break*/, 5];
136
- idx = batchIdx * batchSize;
137
- batch = data.slice(idx, idx + batchSize);
138
- return [4 /*yield*/, (onValidateBatch
139
- ? onValidateBatch(batch)
140
- : getBatchErrors(batch, onValidateRecord))];
141
- case 2:
142
- errors = _a.sent();
143
- validationErrors = __assign(__assign({}, validationErrors), errors);
144
- // unblocks main thread for rendering ui
145
- return [4 /*yield*/, sleep(batchValidationDelayMs)];
146
- case 3:
147
- // unblocks main thread for rendering ui
148
- _a.sent();
149
- validationPercentage = (Math.min(idx + batchSize, data.length) / data.length) * 100;
150
- setBatchValidationPercentage(Math.floor(validationPercentage));
151
- setBatchValidationErrors(validationErrors);
152
- _a.label = 4;
153
- case 4:
154
- batchIdx++;
155
- return [3 /*break*/, 1];
156
- case 5: return [2 /*return*/];
157
- }
158
- });
159
- }); };
160
174
  validateInBatches();
161
175
  return [2 /*return*/];
162
176
  });
163
177
  }); };
164
178
  if (!isReadOnly)
165
179
  init();
180
+ return function () {
181
+ isCancelled = true;
182
+ };
166
183
  }, []);
167
184
  useEffect(function () {
168
185
  var appValidationErrors = appResponse === null || appResponse === void 0 ? void 0 : appResponse.errors;
169
186
  if (appValidationErrors) {
170
- setData(__spreadArray([], data, true).map(function (record) { return (__assign(__assign({}, record), { _meta: __assign(__assign({}, record._meta), { appValidationErrors: appValidationErrors[record._meta.id] }) })); }));
187
+ updateData(__spreadArray([], data, true).map(function (record) { return (__assign(__assign({}, record), { _meta: __assign(__assign({}, record._meta), { appValidationErrors: appValidationErrors[record._meta.id] }) })); }));
171
188
  }
172
189
  }, [appResponse]);
173
190
  useEffect(function () {
@@ -196,9 +213,9 @@ export var SpreadsheetContextProvider = function (_a) {
196
213
  return a._meta.rowIndex > b._meta.rowIndex ? 1 : -1;
197
214
  return bHasErrors ? 1 : -1;
198
215
  });
199
- setData(sortedByFieldErrors);
216
+ updateData(sortedByFieldErrors);
200
217
  }, [sortByFieldErrors]);
201
- var validateRenderedRecords = function (renderedData) { return __awaiter(void 0, void 0, void 0, function () {
218
+ var validateRenderedRecords = useCallback(function (renderedData) { return __awaiter(void 0, void 0, void 0, function () {
202
219
  var newData;
203
220
  return __generator(this, function (_a) {
204
221
  if (isReadOnly)
@@ -226,12 +243,13 @@ export var SpreadsheetContextProvider = function (_a) {
226
243
  });
227
244
  }); });
228
245
  setIsLoading(false);
229
- setData(newData);
246
+ updateData(newData);
230
247
  return [2 /*return*/];
231
248
  });
232
- }); };
249
+ }); }, [data]);
233
250
  var value = {
234
251
  data: data,
252
+ dataRef: dataRef,
235
253
  fields: fields,
236
254
  isLoading: isLoading,
237
255
  setIsLoading: setIsLoading,
@@ -246,7 +264,7 @@ export var SpreadsheetContextProvider = function (_a) {
246
264
  sortByFieldErrors: sortByFieldErrors,
247
265
  submittedData: submittedData,
248
266
  setSortByFieldErrors: setSortByFieldErrors,
249
- setData: setData,
267
+ setData: updateData,
250
268
  onValidateRecord: onValidateRecord,
251
269
  validateRenderedRecords: validateRenderedRecords,
252
270
  setIsScrollingEnabled: setIsScrollingEnabled,
@@ -257,6 +275,7 @@ export var SpreadsheetContextProvider = function (_a) {
257
275
  var useValidationState = function (_a) {
258
276
  var data = _a.data, fields = _a.fields, batchValidationErrors = _a.batchValidationErrors, submittedData = _a.submittedData;
259
277
  var _b = useState({}), columnErrorCounts = _b[0], setColumnErrorCounts = _b[1];
278
+ var setIsSpreadsheetValid = useImporterContext().setIsSpreadsheetValid;
260
279
  useEffect(function () {
261
280
  var updateErrorCounts = function () {
262
281
  var newColumnErrorCounts = {};
@@ -276,6 +295,7 @@ var useValidationState = function (_a) {
276
295
  });
277
296
  updateFieldErrorCount(recordErrors);
278
297
  });
298
+ setIsSpreadsheetValid(Object.keys(newColumnErrorCounts).length === 0);
279
299
  setColumnErrorCounts(newColumnErrorCounts);
280
300
  };
281
301
  updateErrorCounts();
@@ -1,9 +1,9 @@
1
- /// <reference types="react" />
1
+ import React from "react";
2
2
  import { DivCSSProps } from "../../../styled/utils";
3
3
  declare type Props = {
4
4
  height?: number;
5
- scrollTop: number;
6
5
  spreadsheetHasXScroll?: boolean;
6
+ gridRef: React.MutableRefObject<any>;
7
7
  } & DivCSSProps;
8
- export declare const SpreadsheetRowNumbers: ({ height, scrollTop, spreadsheetHasXScroll, ...props }: Props) => JSX.Element;
8
+ export declare const SpreadsheetRowNumbers: ({ height, spreadsheetHasXScroll, gridRef, ...props }: Props) => JSX.Element;
9
9
  export {};
@@ -25,27 +25,27 @@ var __rest = (this && this.__rest) || function (s, e) {
25
25
  return t;
26
26
  };
27
27
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
28
- import { Grid } from "react-virtualized";
28
+ import { FixedSizeGrid as Grid } from "react-window";
29
29
  import styled, { css } from "styled-components";
30
30
  import { Div } from "../../../styled/utils";
31
31
  import { spreadsheetRowHeightPx } from "./common";
32
32
  import { spreadsheetHeaderHeightPx } from "./common/index";
33
33
  import { useSpreadsheetContext } from "./SpreadsheetContextProvider";
34
34
  var SPREADSHEET_ROW_NUMBERS_WIDTH = 75;
35
+ var gridStyles = {
36
+ outline: "none",
37
+ willChange: "unset",
38
+ overflowY: "hidden",
39
+ overflowX: "scroll",
40
+ };
35
41
  export var SpreadsheetRowNumbers = function (_a) {
36
- var height = _a.height, scrollTop = _a.scrollTop, spreadsheetHasXScroll = _a.spreadsheetHasXScroll, props = __rest(_a, ["height", "scrollTop", "spreadsheetHasXScroll"]);
42
+ var height = _a.height, spreadsheetHasXScroll = _a.spreadsheetHasXScroll, gridRef = _a.gridRef, props = __rest(_a, ["height", "spreadsheetHasXScroll", "gridRef"]);
37
43
  var data = useSpreadsheetContext().data;
38
- var rowRenderer = function (_a) {
44
+ var Cell = function (_a) {
39
45
  var rowIndex = _a.rowIndex, style = _a.style;
40
46
  return (_jsx(RowNumber, __assign({ style: style, alignCenter: true, justifyEnd: true, isLast: rowIndex === data.length - 1 }, { children: _jsx(Div, __assign({ truncateText: true, mr: 16, textAlignRight: true }, { children: rowIndex + 1 })) }), rowIndex));
41
47
  };
42
- var gridStyles = {
43
- outline: "none",
44
- willChange: "unset",
45
- overflowY: "hidden",
46
- overflowX: "scroll",
47
- };
48
- return (_jsxs(SpreadsheetRowNumbersContainer, __assign({}, props, { h: height }, { children: [_jsx(SpreadsheetRowNumbersHeader, {}), _jsx(Grid, { scrollTop: scrollTop, style: gridStyles, width: SPREADSHEET_ROW_NUMBERS_WIDTH, columnCount: 1, columnWidth: SPREADSHEET_ROW_NUMBERS_WIDTH, height: height - spreadsheetHeaderHeightPx, rowHeight: 40, cellRenderer: rowRenderer, rowCount: data.length })] })));
48
+ return (_jsxs(SpreadsheetRowNumbersContainer, __assign({}, props, { h: height }, { children: [_jsx(SpreadsheetRowNumbersHeader, {}), _jsx(Grid, __assign({ ref: gridRef, style: gridStyles, width: SPREADSHEET_ROW_NUMBERS_WIDTH, columnCount: 1, columnWidth: SPREADSHEET_ROW_NUMBERS_WIDTH, height: height - spreadsheetHeaderHeightPx, rowHeight: 40, rowCount: data.length }, { children: Cell }))] })));
49
49
  };
50
50
  var RowNumber = styled(Div)(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n background-color: ", ";\n ", ";\n ", "\n"], ["\n background-color: ", ";\n ", ";\n ", "\n"])), function (p) { return p.theme.colors.tableHeader; }, function (p) { return p.theme.css.label3; }, function (p) {
51
51
  return !p.isLast && css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n box-shadow: inset 0 -1px 0 ", ";\n "], ["\n box-shadow: inset 0 -1px 0 ", ";\n "])), function (p) { return p.theme.colors.gray300; });
@@ -1,4 +1,4 @@
1
- import React from "react";
1
+ /// <reference types="react" />
2
2
  import { FieldTypes, Record } from "../../../../../types";
3
3
  export declare const parseValue: (fieldType: FieldTypes, value: any) => any;
4
4
  export declare const useValidationError: (fieldName: string, record: Record) => {
@@ -6,7 +6,7 @@ export declare const useValidationError: (fieldName: string, record: Record) =>
6
6
  };
7
7
  export declare const useSpreadsheetField: (name: any, record: Record, fieldType: FieldTypes) => {
8
8
  value: any;
9
- setValue: React.Dispatch<any>;
9
+ setValue: (value: any) => void;
10
10
  validationError: any;
11
11
  };
12
12
  export declare const SpreadsheetField: ({ validationError, children }: {
@@ -59,7 +59,8 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
59
59
  return to.concat(ar || Array.prototype.slice.call(from));
60
60
  };
61
61
  import { jsx as _jsx } from "react/jsx-runtime";
62
- import { useEffect, useRef, useState } from "react";
62
+ import { useState, useCallback } from "react";
63
+ import { debounce } from "lodash";
63
64
  import styled, { css } from "styled-components";
64
65
  import { getRecordErrors, getRenderedRecordWithErrors, isFloat, isInteger, } from "..";
65
66
  import { TooltipProvider } from "../../../../../common/TooltipProvider";
@@ -90,54 +91,38 @@ export var useValidationError = function (fieldName, record) {
90
91
  return { validationError: validationError };
91
92
  };
92
93
  export var useSpreadsheetField = function (name, record, fieldType) {
93
- var _a = useSpreadsheetContext(), data = _a.data, setData = _a.setData, onValidateRecord = _a.onValidateRecord;
94
+ var _a = useSpreadsheetContext(), dataRef = _a.dataRef, setData = _a.setData, onValidateRecord = _a.onValidateRecord;
94
95
  var _b = useState(record[name]), value = _b[0], setValue = _b[1];
95
96
  var validationError = useValidationError(name, record).validationError;
96
- // used for debouncing validations
97
- var timeoutIdRef = useRef(null);
98
- // used for getting updated data in setTimeout
99
- var isMountedRef = useRef(false);
100
- var dataRef = useRef(null);
101
- var recordRef = useRef(null);
102
- // set latest data on refs
103
- useEffect(function () {
104
- dataRef.current = __spreadArray([], data, true);
105
- recordRef.current = __assign({}, record);
106
- }, [data, record]);
107
- // debouncing
108
- useEffect(function () {
109
- if (!isMountedRef.current) {
110
- isMountedRef.current = true;
111
- return;
112
- }
113
- if (timeoutIdRef.current)
114
- clearTimeout(timeoutIdRef.current);
115
- timeoutIdRef.current = setTimeout(function () { return __awaiter(void 0, void 0, void 0, function () {
116
- var newData, newRecord, rowIndex, _a, _b, _c;
117
- var _d, _e;
118
- return __generator(this, function (_f) {
119
- switch (_f.label) {
120
- case 0:
121
- newData = __spreadArray([], dataRef.current, true);
122
- newRecord = __assign(__assign({}, recordRef.current), (_d = {}, _d[name] = parseValue(fieldType, value), _d));
123
- rowIndex = newData.findIndex(function (r) { return r._meta.id === record._meta.id; });
124
- _a = newData;
125
- _b = rowIndex;
126
- _c = getRenderedRecordWithErrors;
127
- _e = {
128
- record: newRecord
129
- };
130
- return [4 /*yield*/, onValidateRecord(newRecord)];
131
- case 1:
132
- _a[_b] = _c.apply(void 0, [(_e.validationErrors = _f.sent(),
133
- _e)]);
134
- setData(newData);
135
- return [2 /*return*/];
136
- }
137
- });
138
- }); }, 300);
139
- }, [value]);
140
- return { value: value, setValue: setValue, validationError: validationError };
97
+ var updateData = useCallback(debounce(function (value) { return __awaiter(void 0, void 0, void 0, function () {
98
+ var newData, newRecord, rowIndex, _a, _b, _c;
99
+ var _d, _e;
100
+ return __generator(this, function (_f) {
101
+ switch (_f.label) {
102
+ case 0:
103
+ newData = __spreadArray([], dataRef.current, true);
104
+ newRecord = __assign(__assign({}, record), (_d = {}, _d[name] = parseValue(fieldType, value), _d));
105
+ rowIndex = newData.findIndex(function (r) { return r._meta.id === record._meta.id; });
106
+ _a = newData;
107
+ _b = rowIndex;
108
+ _c = getRenderedRecordWithErrors;
109
+ _e = {
110
+ record: newRecord
111
+ };
112
+ return [4 /*yield*/, onValidateRecord(newRecord)];
113
+ case 1:
114
+ _a[_b] = _c.apply(void 0, [(_e.validationErrors = _f.sent(),
115
+ _e)]);
116
+ setData(newData);
117
+ return [2 /*return*/];
118
+ }
119
+ });
120
+ }); }, 300), [record]);
121
+ var updateValue = useCallback(function (value) {
122
+ setValue(value);
123
+ updateData(value);
124
+ }, [record, updateData]);
125
+ return { value: value, setValue: updateValue, validationError: validationError };
141
126
  };
142
127
  var ContentContainer = styled(Div)(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n height: calc(100% - 1px);\n width: 100%;\n ", ";\n ", "\n ", "\n"], ["\n height: calc(100% - 1px);\n width: 100%;\n ", ";\n ", "\n ", "\n"])), function (p) { return p.theme.css.alignCenter; }, function (p) {
143
128
  return p.hasError && css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n color: ", ";\n background: ", ";\n /* internal border */\n box-shadow: 0px 0px 0px 1px ", " inset;\n "], ["\n color: ", ";\n background: ", ";\n /* internal border */\n box-shadow: 0px 0px 0px 1px ", " inset;\n "])), function (p) { return p.theme.colors.error; }, function (p) { return p.theme.colors.red100; }, function (p) { return p.theme.colors.error; });
@@ -74,6 +74,15 @@ var validations = (_a = {},
74
74
  _a[FieldTypes.time] = validateDatePattern,
75
75
  _a[FieldTypes.datetime] = validateDatePattern,
76
76
  _a);
77
+ var ignoreNullOrUndefinedKeyValues = function (obj) {
78
+ var result = {};
79
+ Object.keys(obj || {})
80
+ .filter(function (key) { return obj[key] !== null && obj[key] !== undefined; })
81
+ .forEach(function (key) {
82
+ result[key] = obj[key];
83
+ });
84
+ return result;
85
+ };
77
86
  export var getRecordErrors = function (_a) {
78
87
  var record = _a.record, fields = _a.fields, batchValidationErrors = _a.batchValidationErrors, submittedData = _a.submittedData;
79
88
  var submittedRecord = submittedData === null || submittedData === void 0 ? void 0 : submittedData.find(function (r) { return r._meta.id === record._meta.id; });
@@ -85,7 +94,7 @@ export var getRecordErrors = function (_a) {
85
94
  if (isEmpty(fieldValue) && field.isRequired) {
86
95
  newErrors[field.name] = "".concat(field.label, " is required");
87
96
  }
88
- else if (validations[field.type]) {
97
+ else if (!isEmpty(fieldValue) && validations[field.type]) {
89
98
  newErrors[field.name] = validations[field.type](field, fieldValue);
90
99
  }
91
100
  return newErrors;
@@ -108,8 +117,7 @@ export var getRecordErrors = function (_a) {
108
117
  return newErrors;
109
118
  }, {});
110
119
  }
111
- var recordErrors = __assign(__assign(__assign({}, recordValidationErrors), recordTemplateValidationErrors), appValidationErrors);
112
- return recordErrors;
120
+ return __assign(__assign(__assign({}, ignoreNullOrUndefinedKeyValues(recordValidationErrors)), ignoreNullOrUndefinedKeyValues(recordTemplateValidationErrors)), ignoreNullOrUndefinedKeyValues(appValidationErrors));
113
121
  }
114
122
  return {};
115
123
  };