fuse-importer 0.24.4 → 0.25.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.
Files changed (24) hide show
  1. package/README.md +14 -5
  2. package/lib/esm/Importer/ImporterWithContext.js +1 -1
  3. package/lib/esm/Importer/common/Spreadsheet/SpreadsheetContextProvider.d.ts +2 -0
  4. package/lib/esm/Importer/common/Spreadsheet/SpreadsheetContextProvider.js +17 -7
  5. package/lib/esm/Importer/common/Spreadsheet/components/FieldHeader.d.ts +1 -0
  6. package/lib/esm/Importer/common/Spreadsheet/components/FieldHeader.js +9 -3
  7. package/lib/esm/Importer/common/Spreadsheet/components/SpreadsheetData.js +7 -2
  8. package/lib/esm/Importer/common/Spreadsheet/components/fields/SpeadsheetAutocomplete.js +10 -6
  9. package/lib/esm/Importer/common/Spreadsheet/components/fields/SpreadsheetInput.d.ts +1 -0
  10. package/lib/esm/Importer/common/Spreadsheet/components/fields/SpreadsheetInput.js +7 -5
  11. package/lib/esm/Importer/common/Spreadsheet/components/fields/index.d.ts +4 -2
  12. package/lib/esm/Importer/common/Spreadsheet/components/fields/index.js +12 -9
  13. package/lib/esm/Importer/common/Spreadsheet/hooks.d.ts +5 -0
  14. package/lib/esm/Importer/common/Spreadsheet/hooks.js +53 -20
  15. package/lib/esm/Importer/common/Spreadsheet/validation/index.d.ts +4 -1
  16. package/lib/esm/Importer/common/Spreadsheet/validation/index.js +39 -15
  17. package/lib/esm/Importer/common/theme.d.ts +2 -0
  18. package/lib/esm/Importer/data/index.js +0 -1
  19. package/lib/esm/styled/theme/colorPalette.d.ts +4 -0
  20. package/lib/esm/styled/theme/colorPalette.js +2 -0
  21. package/lib/esm/styled/theme/index.d.ts +2 -0
  22. package/lib/esm/types.d.ts +6 -2
  23. package/lib/main.js +5 -5
  24. package/package.json +1 -1
package/README.md CHANGED
@@ -80,7 +80,7 @@ If you don't have an account yet, you can go over the [Registration](https://fus
80
80
 
81
81
  ## Create Your First Importer
82
82
 
83
- If you don’t have a Importer yet, you can go over [Create Your First Importer](https://fuse-docs.flatirons.com/getting-started/create-your-first-template?utm_source=npmjs&utm_medium=Create+Your+First+Template&utm_campaign=NPM). Importer represents the fields and validations that your own system accepts, also known as your data schema.
83
+ If you don’t have an Importer yet, you can go over [Create Your First Importer](https://fuse-docs.flatirons.com/getting-started/create-your-first-template?utm_source=npmjs&utm_medium=Create+Your+First+Template&utm_campaign=NPM). Importer represents the fields and validations that your own system accepts, also known as your data schema.
84
84
 
85
85
  ## Getting started
86
86
 
@@ -180,26 +180,35 @@ importer.onClose = () => {
180
180
 
181
181
  #### `onValidateRecord`
182
182
 
183
- The `onValidationRecord` hook is called for each row (record) that a customer uploads. It allows you to specify custom frontend validations and display error messages in the importer for the user to fix. When you create a importer, each column contains an `internal key`. These internal keys represent the
183
+ The `onValidationRecord` hook is called for each row (record) that a customer uploads. It allows you to specify custom frontend validations and display error messages in the importer for the user to fix. When you create an importer, each column contains an `internal key`. These internal keys represent the
184
184
 
185
185
  Return values:
186
186
 
187
- - If the record has no errors, we expect you to return an empty object: `return {}`;
188
- - If the record has validation errors, you can specify them like so:
187
+ - If the record has no errors, we expect you to return an empty object: `return {}`.
188
+ - If the record has validation errors, you can specify them like below.
189
+ - If the record has validation warnings, you can specify them like so:
189
190
 
190
191
  ```typescript
191
192
  importer.onValidateRecord = async (record) => {
192
193
  const errors = {};
194
+ const warnings = {};
193
195
 
194
196
  // force emails to include gmail
195
197
  if (!record.email?.includes("gmail")) {
196
198
  errors["email"] = "Email must be from Gmail";
197
199
  }
198
200
 
199
- return errors;
201
+ // email should be from the domain.
202
+ if (!record.email?.includes("@example.com")) {
203
+ warnings["email"] = "Email is outside the domain";
204
+ }
205
+
206
+ return { errors: errors, warnings: warnings };
200
207
  };
201
208
  ```
202
209
 
210
+ `warnings` will still allow you to submit the spreadsheet, unlike `errors`.
211
+
203
212
  #### `formatRecord`
204
213
 
205
214
  The `formatRecord` hook can be used to format data automatically on behalf of a user. For example, if you have a field called `first_name` and you know that your system always requires `first_name` to be capitalized, you can use this callback to uppercase all `first_name` records like so:
@@ -51,7 +51,7 @@ var Content = styled(Div)(function (_a) {
51
51
  return css(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n background-color: ", ";\n padding-bottom: 70px;\n "], ["\n background-color: ", ";\n padding-bottom: 70px;\n "])), colors.backgroundInterface);
52
52
  });
53
53
  export var ImporterWithContext = function () {
54
- var _a = useImporterContext(), inTrialMode = _a.inTrialMode, currentStepIndex = _a.currentStepIndex, matcherSubstep = _a.matcherSubstep, theme = _a.theme, logoURL = _a.logoURL, previewFirstTime = _a.previewFirstTime, _b = _a.importerOptions, zIndex = _b.zIndex, loadingComponent = _b.loadingComponent, previewMode = _b.previewMode;
54
+ var _a = useImporterContext(), inTrialMode = _a.inTrialMode, currentStepIndex = _a.currentStepIndex, matcherSubstep = _a.matcherSubstep, theme = _a.theme, logoURL = _a.logoURL, previewFirstTime = _a.previewFirstTime, _b = _a.importerOptions, zIndex = _b.zIndex, previewMode = _b.previewMode;
55
55
  var layoutRef = useRef(null);
56
56
  var t = useTranslation().t;
57
57
  useEffect(function () {
@@ -13,11 +13,13 @@ type State = {
13
13
  highlightFirstRow: boolean;
14
14
  options: SpreadsheetOptions;
15
15
  sortByFieldErrors: string;
16
+ sortByFieldWarnings: string;
16
17
  updateRecord: (record: Record) => void;
17
18
  setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
18
19
  setSortByFieldErrors: React.Dispatch<React.SetStateAction<string>>;
19
20
  selectedRows: number[];
20
21
  setSelectedRows: React.Dispatch<React.SetStateAction<number[]>>;
22
+ setSortByFieldWarnings: React.Dispatch<React.SetStateAction<string>>;
21
23
  } & ValidationState;
22
24
  type Props = {
23
25
  initialDataSet: RecordDataSet;
@@ -30,8 +30,10 @@ export var SpreadsheetContextProvider = function (_a) {
30
30
  var _c = useState(initialDataSet), dataSet = _c[0], setDataSet = _c[1];
31
31
  var _d = useState(false), isLoading = _d[0], setIsLoading = _d[1];
32
32
  var _e = useState(null), sortByFieldErrors = _e[0], setSortByFieldErrors = _e[1];
33
+ var _f = useState(null), sortByFieldWarnings = _f[0], setSortByFieldWarnings = _f[1];
33
34
  var sortByCurrentErrorsRef = useRef({});
34
- var _f = useValidationState({
35
+ var sortByCurrentWarningsRef = useRef({});
36
+ var _g = useValidationState({
35
37
  dataSet: dataSet,
36
38
  initialDataSet: initialDataSet,
37
39
  fields: fields,
@@ -40,22 +42,23 @@ export var SpreadsheetContextProvider = function (_a) {
40
42
  setDataSet: setDataSet,
41
43
  setIsLoading: setIsLoading,
42
44
  onValidateRecord: onValidateRecord,
43
- }), errorsRef = _f.errorsRef, updateRecordAndRevalidate = _f.updateRecordAndRevalidate, validationState = __rest(_f, ["errorsRef", "updateRecordAndRevalidate"]);
45
+ }), errorsRef = _g.errorsRef, warningsRef = _g.warningsRef, updateRecordAndRevalidate = _g.updateRecordAndRevalidate, validationState = __rest(_g, ["errorsRef", "warningsRef", "updateRecordAndRevalidate"]);
44
46
  // sort data based on errors (errors group on top and not errors group at bottom)
45
47
  var data = useMemo(function () {
46
48
  var errors = sortByCurrentErrorsRef.current; //Sort errors snapshot
49
+ var warnings = sortByCurrentWarningsRef.current; //Sort warnings snapshot
47
50
  var dataSetValues = Object.values(dataSet);
48
- if (!sortByFieldErrors)
51
+ if (!sortByFieldErrors && !sortByFieldWarnings)
49
52
  return dataSetValues;
50
53
  return dataSetValues.sort(function (a, b) {
51
- var aHasErrors = !!get(errors, "".concat(get(a, "_meta.id"), ".").concat(sortByFieldErrors), false);
52
- var bHasErrors = !!get(errors, "".concat(get(b, "_meta.id"), ".").concat(sortByFieldErrors), false);
54
+ var aHasErrors = !!get(sortByFieldErrors ? errors : warnings, "".concat(get(a, "_meta.id"), ".").concat(sortByFieldErrors || sortByFieldWarnings), false);
55
+ var bHasErrors = !!get(sortByFieldErrors ? errors : warnings, "".concat(get(b, "_meta.id"), ".").concat(sortByFieldErrors || sortByFieldWarnings), false);
53
56
  if (aHasErrors === bHasErrors) {
54
57
  return a._meta.rowIndex > b._meta.rowIndex ? 1 : -1;
55
58
  }
56
59
  return bHasErrors ? 1 : -1;
57
60
  });
58
- }, [dataSet, sortByFieldErrors]);
61
+ }, [dataSet, sortByFieldErrors, sortByFieldWarnings]);
59
62
  useEffect(function () {
60
63
  onDataSetChanged && onDataSetChanged(dataSet);
61
64
  }, [dataSet]);
@@ -69,8 +72,15 @@ export var SpreadsheetContextProvider = function (_a) {
69
72
  //current errors snapshot for use on sort to keep data sorted without changing with each edit or revalidation.
70
73
  sortByCurrentErrorsRef.current = __assign({}, errorsRef.current);
71
74
  setSortByFieldErrors(value);
75
+ setSortByFieldWarnings(null);
72
76
  }, []);
73
- var value = __assign(__assign({ data: data, fields: fields, isLoading: isLoading }, validationState), { isReadOnly: isReadOnly, rowWidth: rowWidth, sortByFieldErrors: sortByFieldErrors, highlightFirstRow: highlightFirstRow, options: options, setIsLoading: setIsLoading, setSortByFieldErrors: handleSortByFieldErrors, onValidateRecord: onValidateRecord, updateRecord: updateRecordAndRevalidate, selectedRows: selectedRows, setSelectedRows: setSelectedRows });
77
+ var handleSortByFieldWarnings = useCallback(function (value) {
78
+ //current errors snapshot for use on sort to keep data sorted without changing with each edit or revalidation.
79
+ sortByCurrentWarningsRef.current = __assign({}, warningsRef.current);
80
+ setSortByFieldWarnings(value);
81
+ setSortByFieldErrors(null);
82
+ }, []);
83
+ var value = __assign(__assign({ data: data, fields: fields, isLoading: isLoading }, validationState), { isReadOnly: isReadOnly, rowWidth: rowWidth, sortByFieldErrors: sortByFieldErrors, sortByFieldWarnings: sortByFieldWarnings, highlightFirstRow: highlightFirstRow, options: options, setIsLoading: setIsLoading, setSortByFieldErrors: handleSortByFieldErrors, setSortByFieldWarnings: handleSortByFieldWarnings, onValidateRecord: onValidateRecord, updateRecord: updateRecordAndRevalidate, selectedRows: selectedRows, setSelectedRows: setSelectedRows });
74
84
  return (_jsx(SpreadsheetContext.Provider, __assign({ value: value }, { children: children })));
75
85
  };
76
86
  export var useSpreadsheetContext = function () { return useContext(SpreadsheetContext); };
@@ -3,5 +3,6 @@ import { Field } from "../../../../types";
3
3
  export type FieldHeaderProps = {
4
4
  field: Field;
5
5
  sortByFieldErrors: (name: string) => void;
6
+ sortByFieldWarnings: (name: string) => void;
6
7
  };
7
8
  export declare const FieldHeader: React.FC<FieldHeaderProps>;
@@ -14,6 +14,7 @@ var __assign = (this && this.__assign) || function () {
14
14
  return __assign.apply(this, arguments);
15
15
  };
16
16
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
17
+ import { colors } from "../../../../styled/theme/colorPalette";
17
18
  import styled, { css } from "styled-components";
18
19
  import { TooltipProvider } from "../../../../common";
19
20
  import { Div } from "../../../../styled/utils";
@@ -23,9 +24,14 @@ var ErrorCount = styled(Div)(function (_a) {
23
24
  return css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n color: ", ";\n background: ", ";\n border: solid 1px ", ";\n padding: 4px 7px;\n border-radius: 56px;\n min-width: 24px;\n ", ";\n "], ["\n color: ", ";\n background: ", ";\n border: solid 1px ", ";\n padding: 4px 7px;\n border-radius: 56px;\n min-width: 24px;\n ", ";\n "])), colors.error, colors.red100, colors.error, c.centered);
24
25
  });
25
26
  export var FieldHeader = function (_a) {
26
- var field = _a.field, sortByFieldErrors = _a.sortByFieldErrors;
27
- var columnErrorCounts = useSpreadsheetContext().columnErrorCounts;
27
+ var field = _a.field, sortByFieldErrors = _a.sortByFieldErrors, sortByFieldWarnings = _a.sortByFieldWarnings;
28
+ var _b = useSpreadsheetContext(), columnErrorCounts = _b.columnErrorCounts, columnWarningCounts = _b.columnWarningCounts;
28
29
  var fieldErrorCount = columnErrorCounts[field.name];
29
- return (_jsxs(Div, __assign({ "data-test-id": "column-header-".concat(field.name), p: "0 16px", spaceBetween: true, w100: true, alignCenter: true }, { children: [_jsxs(Div, __assign({ truncateText: true }, { children: [field.label, field.isRequired && "*"] })), fieldErrorCount && (_jsx(TooltipProvider, __assign({ mr: 3, w: 35, tooltip: "Sort by ".concat(field.label, " errors") }, { children: _jsx(ErrorCount, __assign({ "data-test-id": "column-errors-count-".concat(field.name), onClick: function () { return sortByFieldErrors(field.name); } }, { children: _jsx(Div, __assign({ centered: true }, { children: _jsx(Div, __assign({ w: 35, textAlignCenter: true, label3: true, truncateText: true }, { children: fieldErrorCount })) })) })) })))] })));
30
+ var fieldWarningCount = columnWarningCounts[field.name];
31
+ return (_jsxs(Div, __assign({ "data-test-id": "column-header-".concat(field.name), p: "0 16px", spaceBetween: true, w100: true, alignCenter: true }, { children: [_jsxs(Div, __assign({ truncateText: true }, { children: [field.label, field.isRequired && "*"] })), fieldErrorCount && (_jsx(TooltipProvider, __assign({ mr: 3, w: 35, tooltip: "Sort by ".concat(field.label, " errors") }, { children: _jsx(ErrorCount, __assign({ "data-test-id": "column-errors-count-".concat(field.name), onClick: function () { return sortByFieldErrors(field.name); } }, { children: _jsx(Div, __assign({ centered: true }, { children: _jsx(Div, __assign({ w: 35, textAlignCenter: true, label3: true, truncateText: true }, { children: fieldErrorCount })) })) })) }))), !fieldErrorCount && fieldWarningCount && (_jsx(TooltipProvider, __assign({ mr: 3, w: 35, tooltip: "Sort by ".concat(field.label, " errors") }, { children: _jsx(ErrorCount, __assign({ style: {
32
+ color: colors.orange1200,
33
+ background: colors.orange1100,
34
+ boxShadow: "0px 0px 0px 1px ".concat(colors.orange500, " inset"),
35
+ }, "data-test-id": "column-errors-count-".concat(field.name), onClick: function () { return sortByFieldWarnings(field.name); } }, { children: _jsx(Div, __assign({ centered: true }, { children: _jsx(Div, __assign({ w: 35, textAlignCenter: true, label3: true, truncateText: true }, { children: fieldWarningCount })) })) })) })))] })));
30
36
  };
31
37
  var templateObject_1;
@@ -36,7 +36,7 @@ import { SpreadsheetRowCheckboxes } from "./SpreadsheetRowCheckboxes";
36
36
  import ValidationProgress from "./ValidationProgress";
37
37
  var getItemKey = function (record) { return record._meta.id; };
38
38
  var SpreadsheetData = function () {
39
- var _a = useSpreadsheetContext(), fields = _a.fields, data = _a.data, isLoading = _a.isLoading, isReadOnly = _a.isReadOnly, rowWidth = _a.rowWidth, totalErrors = _a.totalErrors, validationPercentage = _a.validationPercentage, setSortByFieldErrors = _a.setSortByFieldErrors, options = _a.options;
39
+ var _a = useSpreadsheetContext(), fields = _a.fields, data = _a.data, isLoading = _a.isLoading, isReadOnly = _a.isReadOnly, rowWidth = _a.rowWidth, totalErrors = _a.totalErrors, validationPercentage = _a.validationPercentage, setSortByFieldErrors = _a.setSortByFieldErrors, options = _a.options, setSortByFieldWarnings = _a.setSortByFieldWarnings;
40
40
  var rowNumbersGridRef = useRef();
41
41
  var rowCheckboxesGridRef = useRef();
42
42
  var sortByErrors = useCallback(function (field) {
@@ -44,9 +44,14 @@ var SpreadsheetData = function () {
44
44
  return sortByFieldErrors === field ? null : field;
45
45
  });
46
46
  }, []);
47
+ var sortByWarnings = useCallback(function (field) {
48
+ return setSortByFieldWarnings(function (sortByFieldWarnings) {
49
+ return sortByFieldWarnings === field ? null : field;
50
+ });
51
+ }, []);
47
52
  var columns = useMemo(function () {
48
53
  return fields.map(function (field) { return ({
49
- Header: function () { return (_jsx(FieldHeader, { field: field, sortByFieldErrors: sortByErrors })); },
54
+ Header: function () { return (_jsx(FieldHeader, { field: field, sortByFieldErrors: sortByErrors, sortByFieldWarnings: sortByWarnings })); },
50
55
  Content: function (record) {
51
56
  var Input = inputTypes[field.type];
52
57
  var rowIndex = record.rowIndex, recordProp = __rest(record, ["rowIndex"]);
@@ -20,15 +20,19 @@ import { Autocomplete as AutocompleteBase, } from "../../../../../common/inputs/
20
20
  import { SelectMenuDiv, SelectMenuScrollArea, } from "../../../../../common/inputs/SelectMenu";
21
21
  import { HTMLInput, TextInputIcon, } from "../../../../../common/inputs/TextInput";
22
22
  import { spreadsheetRowHeightPx } from "../../common";
23
- var Autocomplete = styled(AutocompleteBase)(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n ", " {\n border: none;\n border-radius: 0;\n margin: 0;\n background: transparent;\n height: ", "px;\n padding: 0 12px;\n\n ", "\n\n ::placeholder {\n ", "\n }\n :focus {\n border: none;\n box-shadow: none;\n }\n }\n ", " {\n right: 6px;\n }\n ", " {\n border-radius: 7px;\n }\n ", " {\n padding: 4px;\n }\n"], ["\n ", " {\n border: none;\n border-radius: 0;\n margin: 0;\n background: transparent;\n height: ", "px;\n padding: 0 12px;\n\n ", "\n\n ::placeholder {\n ", "\n }\n :focus {\n border: none;\n box-shadow: none;\n }\n }\n ", " {\n right: 6px;\n }\n ", " {\n border-radius: 7px;\n }\n ", " {\n padding: 4px;\n }\n"])), HTMLInput, spreadsheetRowHeightPx - 5, function (p) {
24
- return p.hasError && css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n color: ", ";\n "], ["\n color: ", ";\n "])), function (p) { return p.theme.colors.error; });
23
+ var Autocomplete = styled(AutocompleteBase)(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n ", " {\n border: none;\n border-radius: 0;\n margin: 0;\n background: transparent;\n height: ", "px;\n padding: 0 12px;\n\n ", "\n\n ::placeholder {\n ", "\n\n ", "\n\n ::placeholder {\n ", "\n }\n }\n :focus {\n border: none;\n box-shadow: none;\n }\n }\n ", " {\n right: 6px;\n }\n ", " {\n border-radius: 7px;\n }\n ", " {\n padding: 4px;\n }\n"], ["\n ", " {\n border: none;\n border-radius: 0;\n margin: 0;\n background: transparent;\n height: ", "px;\n padding: 0 12px;\n\n ", "\n\n ::placeholder {\n ", "\n\n ", "\n\n ::placeholder {\n ", "\n }\n }\n :focus {\n border: none;\n box-shadow: none;\n }\n }\n ", " {\n right: 6px;\n }\n ", " {\n border-radius: 7px;\n }\n ", " {\n padding: 4px;\n }\n"])), HTMLInput, spreadsheetRowHeightPx - 5, function (p) {
24
+ return p.hasWarning && css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n color: ", ";\n "], ["\n color: ", ";\n "])), function (p) { return p.theme.colors.orange1200; });
25
25
  }, function (p) {
26
- return p.hasError && css(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n color: ", ";\n "], ["\n color: ", ";\n "])), function (p) { return p.theme.colors.error; });
26
+ return p.hasWarning && css(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n color: ", ";\n "], ["\n color: ", ";\n "])), function (p) { return p.theme.colors.orange1200; });
27
+ }, function (p) {
28
+ return p.hasError && css(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n color: ", ";\n "], ["\n color: ", ";\n "])), function (p) { return p.theme.colors.error; });
29
+ }, function (p) {
30
+ return p.hasError && css(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n color: ", ";\n "], ["\n color: ", ";\n "])), function (p) { return p.theme.colors.error; });
27
31
  }, TextInputIcon, SelectMenuDiv, SelectMenuScrollArea);
28
32
  export var SpreadsheetAutocomplete = function (props) {
29
33
  var name = props.name, record = props.record, options = props.options, fieldType = props.fieldType, _a = props.isInputDisabled, isInputDisabled = _a === void 0 ? false : _a, id = props.id;
30
- var _b = useSpreadsheetField(name, record, fieldType), value = _b.value, setValue = _b.setValue, validationError = _b.validationError;
31
- return (_jsx(SpreadsheetField, __assign({ validationError: validationError }, { children: _jsx(Autocomplete, { placement: "bottom", isInputDisabled: isInputDisabled, hasError: !!validationError, options: options, value: value, icon: chevronDownIcon, onChange: function (v) { return setValue(v); }, id: id }) })));
34
+ var _b = useSpreadsheetField(name, record, fieldType), value = _b.value, setValue = _b.setValue, validationError = _b.validationError, validationWarning = _b.validationWarning;
35
+ return (_jsx(SpreadsheetField, __assign({ validationError: validationError, validationWarning: validationWarning }, { children: _jsx(Autocomplete, { placement: "bottom", isInputDisabled: isInputDisabled, hasError: !!validationError, hasWarning: !!validationWarning, options: options, value: value, icon: chevronDownIcon, onChange: function (v) { return setValue(v); }, id: id }) })));
32
36
  };
33
37
  var chevronDownIcon = (_jsx("svg", __assign({ width: "10", height: "6", viewBox: "0 0 10 6", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, { children: _jsx("path", { d: "M8.46289 1L4.98131 4.48159L1.49972 1", stroke: "black", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) })));
34
- var templateObject_1, templateObject_2, templateObject_3;
38
+ var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5;
@@ -8,4 +8,5 @@ export type SpreadsheetTextInputArgs = {
8
8
  export declare const SpreadsheetInput: ({ name, record, fieldType, ...props }: SpreadsheetTextInputArgs) => JSX.Element;
9
9
  export declare const Input: import("styled-components").StyledComponent<"input", import("styled-components").DefaultTheme, {
10
10
  hasError: boolean;
11
+ hasWarning?: boolean;
11
12
  } & import("../../../../../styled/utils").HTMLInputProps & import("../../../../../styled/utils").CSSProps, never>;
@@ -29,13 +29,15 @@ import styled, { css } from "styled-components";
29
29
  import { SpreadsheetField, useSpreadsheetField } from ".";
30
30
  export var SpreadsheetInput = function (_a) {
31
31
  var name = _a.name, record = _a.record, fieldType = _a.fieldType, props = __rest(_a, ["name", "record", "fieldType"]);
32
- var _b = useSpreadsheetField(name, record, fieldType), value = _b.value, setValue = _b.setValue, validationError = _b.validationError;
33
- return (_jsx(SpreadsheetField, __assign({ validationError: validationError }, { children: _jsx(Input, __assign({ hasError: !!validationError, value: value || "", onChange: function (_a) {
32
+ var _b = useSpreadsheetField(name, record, fieldType), value = _b.value, setValue = _b.setValue, validationError = _b.validationError, validationWarning = _b.validationWarning;
33
+ return (_jsx(SpreadsheetField, __assign({ validationError: validationError, validationWarning: validationWarning }, { children: _jsx(Input, __assign({ hasError: !!validationError, hasWarning: !!validationWarning, value: value || "", onChange: function (_a) {
34
34
  var value = _a.target.value;
35
35
  return setValue(value);
36
36
  } }, props)) })));
37
37
  };
38
- export var Input = styled.input(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n outline: none;\n border: none;\n width: 100%;\n height: calc(100% - 2px);\n background: transparent;\n box-sizing: border-box;\n\n ::-webkit-outer-spin-button,\n ::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n /* Firefox */\n -moz-appearance: textfield;\n\n padding: 0 12px;\n ", ";\n color: ", ";\n ::placeholder {\n color: ", ";\n }\n\n ", "\n"], ["\n outline: none;\n border: none;\n width: 100%;\n height: calc(100% - 2px);\n background: transparent;\n box-sizing: border-box;\n\n ::-webkit-outer-spin-button,\n ::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n /* Firefox */\n -moz-appearance: textfield;\n\n padding: 0 12px;\n ", ";\n color: ", ";\n ::placeholder {\n color: ", ";\n }\n\n ", "\n"])), function (props) { return props.theme.css.body1; }, function (props) { return props.theme.colors.gray1000; }, function (props) { return props.theme.colors.placeholder; }, function (p) {
39
- return p.hasError && css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n color: ", ";\n "], ["\n color: ", ";\n "])), function (p) { return p.theme.colors.error; });
38
+ export var Input = styled.input(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n outline: none;\n border: none;\n width: 100%;\n height: calc(100% - 2px);\n background: transparent;\n box-sizing: border-box;\n\n ::-webkit-outer-spin-button,\n ::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n /* Firefox */\n -moz-appearance: textfield;\n\n padding: 0 12px;\n ", ";\n color: ", ";\n ::placeholder {\n color: ", ";\n }\n\n ", "\n\n ", "\n"], ["\n outline: none;\n border: none;\n width: 100%;\n height: calc(100% - 2px);\n background: transparent;\n box-sizing: border-box;\n\n ::-webkit-outer-spin-button,\n ::-webkit-inner-spin-button {\n -webkit-appearance: none;\n margin: 0;\n }\n /* Firefox */\n -moz-appearance: textfield;\n\n padding: 0 12px;\n ", ";\n color: ", ";\n ::placeholder {\n color: ", ";\n }\n\n ", "\n\n ", "\n"])), function (props) { return props.theme.css.body1; }, function (props) { return props.theme.colors.gray1000; }, function (props) { return props.theme.colors.placeholder; }, function (p) {
39
+ return p.hasWarning && css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n color: ", ";\n "], ["\n color: ", ";\n "])), function (p) { return p.theme.colors.orange1200; });
40
+ }, function (p) {
41
+ return p.hasError && css(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n color: ", ";\n "], ["\n color: ", ";\n "])), function (p) { return p.theme.colors.error; });
40
42
  });
41
- var templateObject_1, templateObject_2;
43
+ var templateObject_1, templateObject_2, templateObject_3;
@@ -1,10 +1,12 @@
1
1
  import { FieldTypes, Record } from "../../../../../types";
2
- export declare const useSpreadsheetField: (name: any, record: Record, fieldType: FieldTypes) => {
2
+ export declare const useSpreadsheetField: (name: string, record: Record, fieldType: FieldTypes) => {
3
3
  value: any;
4
4
  setValue: (value: any) => void;
5
5
  validationError: any;
6
+ validationWarning: any;
6
7
  };
7
- export declare const SpreadsheetField: ({ validationError, children }: {
8
+ export declare const SpreadsheetField: ({ validationError, validationWarning, children, }: {
8
9
  validationError: any;
10
+ validationWarning: any;
9
11
  children: any;
10
12
  }) => JSX.Element;
@@ -58,9 +58,10 @@ import { Div } from "../../../../../styled/utils";
58
58
  import { parseValue } from "../../common";
59
59
  import { useSpreadsheetContext } from "../../SpreadsheetContextProvider";
60
60
  export var useSpreadsheetField = function (name, record, fieldType) {
61
- var _a = useSpreadsheetContext(), updateRecord = _a.updateRecord, errors = _a.errors;
61
+ var _a = useSpreadsheetContext(), updateRecord = _a.updateRecord, errors = _a.errors, warnings = _a.warnings;
62
62
  var _b = useState(record[name]), value = _b[0], setValue = _b[1];
63
63
  var validationError = get(errors, "".concat(record._meta.id, ".").concat(name), null);
64
+ var validationWarning = get(warnings, "".concat(record._meta.id, ".").concat(name), null);
64
65
  var updateData = useCallback(debounce(function (value) { return __awaiter(void 0, void 0, void 0, function () {
65
66
  var newRecord;
66
67
  var _a;
@@ -74,20 +75,22 @@ export var useSpreadsheetField = function (name, record, fieldType) {
74
75
  setValue(value);
75
76
  updateData(value);
76
77
  }, [record, updateData]);
77
- return { value: value, setValue: updateValue, validationError: validationError };
78
+ return { value: value, setValue: updateValue, validationError: validationError, validationWarning: validationWarning };
78
79
  };
79
- 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) {
80
- 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; });
80
+ var ContentContainer = styled(Div)(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n height: calc(100% - 1px);\n width: 100%;\n ", ";\n ", "\n ", "\n ", "\n"], ["\n height: calc(100% - 1px);\n width: 100%;\n ", ";\n ", "\n ", "\n ", "\n"])), function (p) { return p.theme.css.alignCenter; }, function (p) {
81
+ return p.hasWarning && 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.orange1200; }, function (p) { return p.theme.colors.orange1100; }, function (p) { return p.theme.colors.orange500; });
81
82
  }, function (p) {
82
- return p.isReadOnly && css(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n pointer-events: none;\n "], ["\n pointer-events: none;\n "])));
83
+ return p.hasError && css(templateObject_2 || (templateObject_2 = __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; });
84
+ }, function (p) {
85
+ return p.isReadOnly && css(templateObject_3 || (templateObject_3 = __makeTemplateObject(["\n pointer-events: none;\n "], ["\n pointer-events: none;\n "])));
83
86
  });
84
87
  var Wrapper = styled(Div)(function (_a) {
85
88
  var isLoading = _a.isLoading;
86
- return css(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n ", "\n "], ["\n ", "\n "])), isLoading && css(templateObject_4 || (templateObject_4 = __makeTemplateObject(["\n pointer-events: none;\n "], ["\n pointer-events: none;\n "]))));
89
+ return css(templateObject_6 || (templateObject_6 = __makeTemplateObject(["\n ", "\n "], ["\n ", "\n "])), isLoading && css(templateObject_5 || (templateObject_5 = __makeTemplateObject(["\n pointer-events: none;\n "], ["\n pointer-events: none;\n "]))));
87
90
  });
88
91
  export var SpreadsheetField = function (_a) {
89
- var validationError = _a.validationError, children = _a.children;
92
+ var validationError = _a.validationError, validationWarning = _a.validationWarning, children = _a.children;
90
93
  var _b = useSpreadsheetContext(), isReadOnly = _b.isReadOnly, isLoading = _b.isLoading;
91
- return (_jsx(Wrapper, __assign({ dim: "100%", isLoading: isLoading }, { children: _jsx(TooltipProvider, __assign({ tooltip: validationError }, { children: _jsx(Div, __assign({ dim: "100%" }, { children: _jsx(ContentContainer, __assign({ hasError: !!validationError, isReadOnly: isReadOnly }, { children: children })) })) })) })));
94
+ return (_jsx(Wrapper, __assign({ dim: "100%", isLoading: isLoading }, { children: _jsx(TooltipProvider, __assign({ tooltip: validationError || validationWarning }, { children: _jsx(Div, __assign({ dim: "100%" }, { children: _jsx(ContentContainer, __assign({ hasError: !!validationError, hasWarning: !!validationWarning, isReadOnly: isReadOnly }, { children: children })) })) })) })));
92
95
  };
93
- var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5;
96
+ var templateObject_1, templateObject_2, templateObject_3, templateObject_4, templateObject_5, templateObject_6;
@@ -16,14 +16,19 @@ export type ValidationState = {
16
16
  isValidationCompleted: boolean;
17
17
  validationPercentage: number;
18
18
  errors: BatchValidationErrors;
19
+ warnings: BatchValidationErrors;
19
20
  totalErrors: number;
20
21
  columnErrorCounts: {
21
22
  [column: string]: number;
22
23
  };
24
+ columnWarningCounts: {
25
+ [column: string]: number;
26
+ };
23
27
  };
24
28
  type UseValidationStateReturnValue = ValidationState & {
25
29
  updateRecordAndRevalidate: (record: Record) => Promise<void>;
26
30
  errorsRef: React.MutableRefObject<BatchValidationErrors>;
31
+ warningsRef: React.MutableRefObject<BatchValidationErrors>;
27
32
  };
28
33
  export declare const useValidationState: ({ initialDataSet, dataSet, fields, options, isReadOnly, setDataSet, setIsLoading, onValidateRecord, }: UseValidationStateArgs) => UseValidationStateReturnValue;
29
34
  export {};
@@ -50,25 +50,27 @@ import { useCallback, useEffect, useMemo, useRef, useState, } from "react";
50
50
  import { sleep } from "../../..";
51
51
  import { selectValidatorsFor, validateRecord } from "./validation";
52
52
  var checkIfHasErrors = function (errors) {
53
- return Object.keys(errors).length > 0;
53
+ return errors && Object.keys(errors).length > 0;
54
54
  };
55
55
  export var useValidationState = function (_a) {
56
56
  var initialDataSet = _a.initialDataSet, //Initial Data Set, used to run the initial validation
57
57
  dataSet = _a.dataSet, //Current Updated Data Set
58
58
  fields = _a.fields, options = _a.options, isReadOnly = _a.isReadOnly, setDataSet = _a.setDataSet, setIsLoading = _a.setIsLoading, onValidateRecord = _a.onValidateRecord;
59
59
  var _b = useState({}), errors = _b[0], setErrors = _b[1];
60
- var _c = useState(0), validationPercentage = _c[0], setValidationPercentage = _c[1];
60
+ var _c = useState({}), warnings = _c[0], setWarnings = _c[1];
61
+ var _d = useState(0), validationPercentage = _d[0], setValidationPercentage = _d[1];
61
62
  var validatorsCache = useMemo(function () { return selectValidatorsFor(fields); }, [fields]);
62
63
  var errorsRef = useRef(errors);
64
+ var warningsRef = useRef(warnings);
63
65
  //Validate record and update dataSet
64
66
  var updateRecordAndRevalidate = useCallback(function (record) { return __awaiter(void 0, void 0, void 0, function () {
65
- var recordId, newDataSet, data, recordErrors, hasError;
66
- var _a;
67
- return __generator(this, function (_b) {
68
- switch (_b.label) {
67
+ var recordId, newDataSet, data, _a, recordErrors, recordWarnings, hasError, hasWarning;
68
+ var _b;
69
+ return __generator(this, function (_c) {
70
+ switch (_c.label) {
69
71
  case 0:
70
72
  recordId = record._meta.id;
71
- newDataSet = __assign(__assign({}, dataSet), (_a = {}, _a[recordId] = __assign({}, record), _a));
73
+ newDataSet = __assign(__assign({}, dataSet), (_b = {}, _b[recordId] = __assign({}, record), _b));
72
74
  data = Object.values(newDataSet);
73
75
  return [4 /*yield*/, validateRecord({
74
76
  validatorsCache: validatorsCache,
@@ -78,9 +80,11 @@ export var useValidationState = function (_a) {
78
80
  record: record,
79
81
  })];
80
82
  case 1:
81
- recordErrors = _b.sent();
83
+ _a = _c.sent(), recordErrors = _a.errors, recordWarnings = _a.warnings;
82
84
  hasError = checkIfHasErrors(recordErrors);
85
+ hasWarning = checkIfHasErrors(recordWarnings);
83
86
  newDataSet[recordId]._meta.isInvalid = hasError;
87
+ newDataSet[recordId]._meta.hasWarning = hasWarning;
84
88
  newDataSet[recordId]._meta.touched = true;
85
89
  setErrors(function (errors) {
86
90
  var newErrors = __assign({}, errors);
@@ -90,6 +94,14 @@ export var useValidationState = function (_a) {
90
94
  errorsRef.current = newState;
91
95
  return newState;
92
96
  });
97
+ setWarnings(function (warnings) {
98
+ var newWarnings = __assign({}, warnings);
99
+ var newState = hasWarning
100
+ ? set(newWarnings, recordId, recordWarnings)
101
+ : omit(newWarnings, recordId);
102
+ warningsRef.current = newState;
103
+ return newState;
104
+ });
93
105
  setDataSet(newDataSet); //Update the dataSet
94
106
  return [2 /*return*/];
95
107
  }
@@ -102,18 +114,19 @@ export var useValidationState = function (_a) {
102
114
  var isCancelled = false;
103
115
  setIsLoading(true);
104
116
  var initialValidation = function () { return __awaiter(void 0, void 0, void 0, function () {
105
- var errors, initialData, length, _a, batchValidationDelayMs, _b, batchValidationSize, batchSize, batchCount, batchIdx, idx, batch, index, record, recordId, recordErrors, hasError, validationPercentage_1, newState;
106
- return __generator(this, function (_c) {
107
- switch (_c.label) {
117
+ var errors, warnings, initialData, length, _a, batchValidationDelayMs, _b, batchValidationSize, batchSize, batchCount, batchIdx, idx, batch, index, record, recordId, _c, recordErrors, recordWarnings, hasError, hasWarning, validationPercentage_1;
118
+ return __generator(this, function (_d) {
119
+ switch (_d.label) {
108
120
  case 0:
109
121
  errors = {};
122
+ warnings = {};
110
123
  initialData = Object.values(initialDataSet);
111
124
  length = initialData.length;
112
125
  _a = options.batchValidationDelayMs, batchValidationDelayMs = _a === void 0 ? 400 : _a, _b = options.batchValidationSize, batchValidationSize = _b === void 0 ? 1000 : _b;
113
126
  batchSize = Math.min(Math.floor(batchValidationSize), length) || length;
114
127
  batchCount = Math.ceil(length / batchSize);
115
128
  batchIdx = 0;
116
- _c.label = 1;
129
+ _d.label = 1;
117
130
  case 1:
118
131
  if (!(batchIdx < batchCount)) return [3 /*break*/, 8];
119
132
  if (isCancelled)
@@ -121,7 +134,7 @@ export var useValidationState = function (_a) {
121
134
  idx = batchIdx * batchSize;
122
135
  batch = initialData.slice(idx, idx + batchSize);
123
136
  index = 0;
124
- _c.label = 2;
137
+ _d.label = 2;
125
138
  case 2:
126
139
  if (!(index < batch.length)) return [3 /*break*/, 5];
127
140
  if (isCancelled)
@@ -136,12 +149,16 @@ export var useValidationState = function (_a) {
136
149
  validatorsCache: validatorsCache,
137
150
  })];
138
151
  case 3:
139
- recordErrors = _c.sent();
152
+ _c = _d.sent(), recordErrors = _c.errors, recordWarnings = _c.warnings;
140
153
  hasError = checkIfHasErrors(recordErrors);
154
+ hasWarning = checkIfHasErrors(recordWarnings);
141
155
  record._meta.isInvalid = hasError;
156
+ record._meta.hasWarning = hasWarning;
142
157
  if (hasError)
143
158
  errors[recordId] = recordErrors;
144
- _c.label = 4;
159
+ if (hasWarning)
160
+ warnings[recordId] = recordWarnings;
161
+ _d.label = 4;
145
162
  case 4:
146
163
  index++;
147
164
  return [3 /*break*/, 2];
@@ -151,11 +168,12 @@ export var useValidationState = function (_a) {
151
168
  setValidationPercentage(Math.round((validationPercentage_1 + Number.EPSILON) * 10) / 10);
152
169
  return [4 /*yield*/, sleep(batchValidationDelayMs)];
153
170
  case 6:
154
- _c.sent();
155
- newState = __assign({}, errors);
156
- errorsRef.current = newState;
157
- setErrors(newState);
158
- _c.label = 7;
171
+ _d.sent();
172
+ errorsRef.current = errors;
173
+ setErrors(errors);
174
+ warningsRef.current = warnings;
175
+ setWarnings(warnings);
176
+ _d.label = 7;
159
177
  case 7:
160
178
  batchIdx++;
161
179
  return [3 /*break*/, 1];
@@ -183,6 +201,18 @@ export var useValidationState = function (_a) {
183
201
  }, errorsByColumns);
184
202
  }, {});
185
203
  }, [errors]);
204
+ var columnWarningCounts = useMemo(function () {
205
+ return Object.keys(warnings).reduce(function (errorsByColumns, rowId) {
206
+ var recordWarnings = warnings[rowId];
207
+ return Object.keys(recordWarnings).reduce(function (internalErrorsByColumns, fieldKey) {
208
+ var _a;
209
+ var hasError = !!recordWarnings[fieldKey];
210
+ var count = (_a = internalErrorsByColumns[fieldKey]) !== null && _a !== void 0 ? _a : 0;
211
+ internalErrorsByColumns[fieldKey] = hasError ? count + 1 : count;
212
+ return internalErrorsByColumns;
213
+ }, errorsByColumns);
214
+ }, {});
215
+ }, [warnings]);
186
216
  var totalErrors = useMemo(function () {
187
217
  return Object.keys(columnErrorCounts).reduce(function (count, column) { return count + columnErrorCounts[column]; }, 0);
188
218
  }, [columnErrorCounts]);
@@ -190,12 +220,15 @@ export var useValidationState = function (_a) {
190
220
  var isValid = isValidationCompleted && totalErrors === 0;
191
221
  return {
192
222
  errors: errors,
223
+ warnings: warnings,
193
224
  totalErrors: totalErrors,
194
225
  columnErrorCounts: columnErrorCounts,
226
+ columnWarningCounts: columnWarningCounts,
195
227
  validationPercentage: validationPercentage,
196
228
  isValidationCompleted: isValidationCompleted,
197
229
  isValid: isValid,
198
230
  errorsRef: errorsRef,
231
+ warningsRef: warningsRef,
199
232
  updateRecordAndRevalidate: updateRecordAndRevalidate,
200
233
  };
201
234
  };
@@ -16,5 +16,8 @@ type ValidateRecordArgs = {
16
16
  data: Record[];
17
17
  };
18
18
  export declare function selectValidatorsFor(fields: Field[]): SelectedFieldValidators[];
19
- export declare function validateRecord({ record, fields, data, onValidateRecord, validatorsCache, }: ValidateRecordArgs): Promise<ValidationErrors>;
19
+ export declare function validateRecord({ record, fields, data, onValidateRecord, validatorsCache, }: ValidateRecordArgs): Promise<{
20
+ errors?: ValidationErrors;
21
+ warnings?: ValidationErrors;
22
+ }>;
20
23
  export {};