@vuu-ui/vuu-table-extras 4.0.0-alpha.9 → 4.0.0-beta.2

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 (158) hide show
  1. package/package.json +18 -18
  2. package/src/cell-renderers/pct-progress-cell/PctProgressCell.css.js +2 -2
  3. package/src/cell-renderers/progress-cell/ProgressCell.css.js +2 -2
  4. package/src/column-expression-input/ColumnExpressionInput.css.js +5 -5
  5. package/src/column-expression-input/column-language-parser/column-expression-parse-utils.js +1 -1
  6. package/src/column-expression-input/theme.js +1 -1
  7. package/src/column-expression-input/useColumnExpressionEditor.js +1 -0
  8. package/src/column-expression-input/useColumnExpressionSuggestionProvider.js +2 -2
  9. package/src/column-formatting-settings/ColumnFormattingPanel.js +12 -9
  10. package/src/column-formatting-settings/DateTimeFormattingSettings.js +107 -3
  11. package/src/column-formatting-settings/LongTypeFormattingSettings.js +8 -3
  12. package/src/column-picker/ColumnModel.js +3 -2
  13. package/src/column-picker/ColumnPicker.js +1 -3
  14. package/src/column-settings-panel/ColumnNameLabel.css.js +1 -1
  15. package/src/csv-export/export-utils.js +76 -20
  16. package/src/csv-export/index.js +1 -1
  17. package/src/csv-export/useCsvExport.js +9 -1
  18. package/src/csv-upload/CsvUpload.css.js +36 -2
  19. package/src/csv-upload/CsvUpload.js +107 -63
  20. package/src/csv-upload/data-upload-preview/DataUploadPreview.js +1 -1
  21. package/src/csv-upload/parse/csv-errors.js +1 -1
  22. package/src/csv-upload/parse/csv-parse.js +1 -1
  23. package/src/csv-upload/parse/csv-schema-validation.js +46 -7
  24. package/src/csv-upload/parse/csv-upload-utils.js +47 -2
  25. package/src/csv-upload/session/index.js +2 -0
  26. package/src/csv-upload/session/useImportSchema.js +44 -0
  27. package/src/csv-upload/session/useImportSession.js +204 -0
  28. package/src/csv-upload/useCsvUpload.js +54 -199
  29. package/src/freeze-control/FreezeControl.css.js +4 -4
  30. package/src/freeze-control/FrozenBanner.css.js +2 -2
  31. package/src/table-footer/TableFooter.js +3 -3
  32. package/types/calculated-column/CalculatedColumnPanel.d.ts +1 -1
  33. package/types/cell-renderers/background-cell/BackgroundCell.d.ts +1 -1
  34. package/types/cell-renderers/background-cell/BackgroundCellConfigurationEditor.d.ts +1 -1
  35. package/types/cell-renderers/button-cell/IconButtonCell.d.ts +1 -1
  36. package/types/cell-renderers/dropdown-cell/DropdownCell.d.ts +1 -1
  37. package/types/cell-renderers/lookup-cell/LookupCell.d.ts +1 -1
  38. package/types/cell-renderers/pct-progress-cell/PctProgressCell.d.ts +1 -1
  39. package/types/column-expression-input/ColumnExpressionInput.d.ts +1 -1
  40. package/types/column-expression-input/column-language-parser/column-expression-parse-utils.d.ts +1 -1
  41. package/types/column-expression-input/column-language-parser/test.d.mts +1 -1
  42. package/types/column-expression-input/useColumnExpressionEditor.d.ts +4 -4
  43. package/types/column-formatting-settings/BaseNumericFormattingSettings.d.ts +1 -1
  44. package/types/column-formatting-settings/ColumnFormattingPanel.d.ts +1 -1
  45. package/types/column-formatting-settings/DateTimeFormattingSettings.d.ts +1 -1
  46. package/types/column-formatting-settings/LongTypeFormattingSettings.d.ts +1 -2
  47. package/types/column-menu/ColumnMenu.d.ts +1 -1
  48. package/types/column-picker/ColumnPicker.d.ts +4 -4
  49. package/types/column-picker/ColumnPickerAction.d.ts +1 -1
  50. package/types/column-settings-panel/ColumnNameLabel.d.ts +1 -1
  51. package/types/column-settings-panel/ColumnSettingsPanel.d.ts +1 -1
  52. package/types/csv-export/export-utils.d.ts +22 -9
  53. package/types/csv-export/index.d.ts +1 -1
  54. package/types/csv-export/useCsvExport.d.ts +5 -2
  55. package/types/csv-upload/CsvUpload.d.ts +2 -6
  56. package/types/csv-upload/data-upload-preview/DataUploadPreview.d.ts +1 -1
  57. package/types/csv-upload/parse/csv-errors.d.ts +1 -1
  58. package/types/csv-upload/parse/csv-schema-validation.d.ts +8 -2
  59. package/types/csv-upload/parse/csv-upload-utils.d.ts +9 -0
  60. package/types/csv-upload/session/index.d.ts +2 -0
  61. package/types/csv-upload/session/useImportSchema.d.ts +13 -0
  62. package/types/csv-upload/session/useImportSession.d.ts +26 -0
  63. package/types/csv-upload/useCsvUpload.d.ts +3 -3
  64. package/types/datasource-stats/DatasourceStats.d.ts +1 -1
  65. package/types/freeze-control/FreezeControl.d.ts +1 -1
  66. package/types/freeze-control/FrozenBanner.d.ts +1 -1
  67. package/types/inline-add-row/InlineAddRow.d.ts +1 -1
  68. package/types/inline-add-row/useInlineAddRow.d.ts +2 -1
  69. package/types/tabbed-table-config-panel/TabbedTableConfigPanel.d.ts +5 -5
  70. package/types/tabbed-table-config-panel/TabbedTableSettingsAction.d.ts +1 -1
  71. package/types/table-footer/TableFooter.d.ts +4 -4
  72. package/types/table-provider/TableProvider.d.ts +1 -1
  73. package/types/table-settings-panel/TableSettingsPanel.d.ts +1 -1
  74. package/types/src/calculated-column/CalculatedColumnPanel.d.ts +0 -12
  75. package/types/src/calculated-column/useCalculatedColumnPanel.d.ts +0 -10
  76. package/types/src/calculated-column/useEditCalculatedColumn.d.ts +0 -13
  77. package/types/src/cell-edit-validators/CaseValidator.d.ts +0 -2
  78. package/types/src/cell-edit-validators/PatternValidator.d.ts +0 -2
  79. package/types/src/cell-edit-validators/index.d.ts +0 -2
  80. package/types/src/cell-renderers/background-cell/BackgroundCell.d.ts +0 -2
  81. package/types/src/cell-renderers/background-cell/BackgroundCellConfigurationEditor.d.ts +0 -2
  82. package/types/src/cell-renderers/background-cell/index.d.ts +0 -2
  83. package/types/src/cell-renderers/background-cell/useDirection.d.ts +0 -3
  84. package/types/src/cell-renderers/button-cell/IconButtonCell.d.ts +0 -6
  85. package/types/src/cell-renderers/dropdown-cell/DropdownCell.d.ts +0 -2
  86. package/types/src/cell-renderers/dropdown-cell/index.d.ts +0 -1
  87. package/types/src/cell-renderers/index.d.ts +0 -6
  88. package/types/src/cell-renderers/lookup-cell/LookupCell.d.ts +0 -2
  89. package/types/src/cell-renderers/lookup-cell/index.d.ts +0 -1
  90. package/types/src/cell-renderers/pct-progress-cell/PctProgressCell.d.ts +0 -2
  91. package/types/src/cell-renderers/pct-progress-cell/index.d.ts +0 -1
  92. package/types/src/cell-renderers/progress-cell/ProgressCell.d.ts +0 -1
  93. package/types/src/cell-renderers/progress-cell/index.d.ts +0 -1
  94. package/types/src/column-expression-input/ColumnExpressionInput.d.ts +0 -10
  95. package/types/src/column-expression-input/column-function-descriptors.d.ts +0 -15
  96. package/types/src/column-expression-input/column-language-parser/ColumnExpressionLanguage.d.ts +0 -2
  97. package/types/src/column-expression-input/column-language-parser/ColumnExpressionTreeWalker.d.ts +0 -57
  98. package/types/src/column-expression-input/column-language-parser/column-expression-parse-utils.d.ts +0 -5
  99. package/types/src/column-expression-input/column-language-parser/generated/column-parser.d.ts +0 -2
  100. package/types/src/column-expression-input/column-language-parser/generated/column-parser.terms.d.ts +0 -1
  101. package/types/src/column-expression-input/column-language-parser/index.d.ts +0 -3
  102. package/types/src/column-expression-input/column-language-parser/test.d.mts +0 -1
  103. package/types/src/column-expression-input/functionDocInfo.d.ts +0 -2
  104. package/types/src/column-expression-input/highlighting.d.ts +0 -1
  105. package/types/src/column-expression-input/index.d.ts +0 -4
  106. package/types/src/column-expression-input/theme.d.ts +0 -1
  107. package/types/src/column-expression-input/useColumnAutoComplete.d.ts +0 -6
  108. package/types/src/column-expression-input/useColumnExpressionEditor.d.ts +0 -25
  109. package/types/src/column-expression-input/useColumnExpressionSuggestionProvider.d.ts +0 -8
  110. package/types/src/column-formatting-settings/BaseNumericFormattingSettings.d.ts +0 -2
  111. package/types/src/column-formatting-settings/ColumnFormattingPanel.d.ts +0 -9
  112. package/types/src/column-formatting-settings/DateTimeFormattingSettings.d.ts +0 -3
  113. package/types/src/column-formatting-settings/LongTypeFormattingSettings.d.ts +0 -3
  114. package/types/src/column-formatting-settings/index.d.ts +0 -3
  115. package/types/src/column-menu/ColumnMenu.d.ts +0 -10
  116. package/types/src/column-menu/column-action-types.d.ts +0 -11
  117. package/types/src/column-menu/column-menu-utils.d.ts +0 -19
  118. package/types/src/column-menu/useColumnActions.d.ts +0 -16
  119. package/types/src/column-picker/ColumnModel.d.ts +0 -81
  120. package/types/src/column-picker/ColumnPicker.d.ts +0 -10
  121. package/types/src/column-picker/ColumnPickerAction.d.ts +0 -5
  122. package/types/src/column-picker/useColumnPicker.d.ts +0 -16
  123. package/types/src/column-picker/useTableColumnPicker.d.ts +0 -7
  124. package/types/src/column-picker/useTableColumnPickerDeprecated.d.ts +0 -14
  125. package/types/src/column-settings-panel/ColumnNameLabel.d.ts +0 -7
  126. package/types/src/column-settings-panel/ColumnSettingsPanel.d.ts +0 -5
  127. package/types/src/column-settings-panel/useColumnSettings.d.ts +0 -30
  128. package/types/src/csv-export/export-utils.d.ts +0 -42
  129. package/types/src/csv-export/index.d.ts +0 -2
  130. package/types/src/csv-export/useCsvExport.d.ts +0 -14
  131. package/types/src/csv-upload/CsvUpload.d.ts +0 -69
  132. package/types/src/csv-upload/data-upload-preview/DataUploadPreview.d.ts +0 -10
  133. package/types/src/csv-upload/data-upload-preview/useDataUploadPreview.d.ts +0 -17
  134. package/types/src/csv-upload/index.d.ts +0 -7
  135. package/types/src/csv-upload/parse/csv-constants.d.ts +0 -3
  136. package/types/src/csv-upload/parse/csv-errors.d.ts +0 -47
  137. package/types/src/csv-upload/parse/csv-parse.d.ts +0 -11
  138. package/types/src/csv-upload/parse/csv-schema-validation.d.ts +0 -18
  139. package/types/src/csv-upload/parse/csv-upload-utils.d.ts +0 -21
  140. package/types/src/csv-upload/parse/index.d.ts +0 -5
  141. package/types/src/csv-upload/useCsvUpload.d.ts +0 -43
  142. package/types/src/datasource-stats/DatasourceStats.d.ts +0 -17
  143. package/types/src/datasource-stats/useDatasourceStats.d.ts +0 -15
  144. package/types/src/freeze-control/FreezeControl.d.ts +0 -15
  145. package/types/src/freeze-control/FrozenBanner.d.ts +0 -6
  146. package/types/src/freeze-control/freezeControlBadge.d.ts +0 -11
  147. package/types/src/freeze-control/useFreezeControl.d.ts +0 -10
  148. package/types/src/index.d.ts +0 -26
  149. package/types/src/inline-add-row/InlineAddRow.d.ts +0 -3
  150. package/types/src/inline-add-row/index.d.ts +0 -2
  151. package/types/src/inline-add-row/useInlineAddRow.d.ts +0 -59
  152. package/types/src/tabbed-table-config-panel/TabbedTableConfigPanel.d.ts +0 -17
  153. package/types/src/tabbed-table-config-panel/TabbedTableSettingsAction.d.ts +0 -7
  154. package/types/src/tabbed-table-config-panel/useTabbedTableConfigPanel.d.ts +0 -13
  155. package/types/src/table-footer/TableFooter.d.ts +0 -10
  156. package/types/src/table-provider/TableProvider.d.ts +0 -18
  157. package/types/src/table-settings-panel/TableSettingsPanel.d.ts +0 -22
  158. package/types/src/table-settings-panel/useTableSettings.d.ts +0 -14
@@ -14,10 +14,44 @@ const css = `
14
14
  display: grid;
15
15
  }
16
16
 
17
+ .vuuCsvUpload-errorContainer {
18
+ margin-top: var(--salt-spacing-100);
19
+ width: 100%;
20
+ max-width: 480px;
21
+ max-height: 120px;
22
+ padding: var(--salt-spacing-100) var(--salt-spacing-200);
23
+ background-color: var(--salt-status-error-background);
24
+ border-radius: var(--salt-palette-corner);
25
+ text-align: left;
26
+ overflow-y: auto;
27
+ }
28
+
29
+ .vuuCsvUpload-errorList {
30
+ padding-left: var(--salt-spacing-200);
31
+ margin: 0;
32
+ list-style-type: disc;
33
+ }
34
+
35
+ .vuuCsvUpload-errorItem {
36
+ font-size: var(--salt-text-label-fontSize);
37
+ color: var(--salt-status-error-foreground-informative);
38
+ line-height: var(--salt-text-label-lineHeight);
39
+ word-break: break-word;
40
+ margin-bottom: var(--salt-spacing-50);
41
+ }
42
+
43
+ .vuuCsvUpload-importErrorItem {
44
+ text-align: center;
45
+ }
46
+
47
+ .vuuCsvUpload-rectifyPrompt {
48
+ margin-top: var(--salt-spacing-100);
49
+ }
50
+
17
51
  .vuuCsvUpload-errors {
18
52
  border: solid 1px var(--salt-status-error-borderColor);
19
- border-radius: var(--salt-size-borderRadius);
20
- color: var(--salt-status-error-foreground);
53
+ border-radius: var(--salt-palette-corner);
54
+ color: var(--salt-status-error-foreground-informative);
21
55
  gap: var(--salt-spacing-100);
22
56
  padding: var(--salt-spacing-200);
23
57
  display: grid;
@@ -2,12 +2,12 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
2
  import { Button, Dialog, DialogActions, DialogContent, DialogHeader, FileDropZone, FileDropZoneIcon, FileDropZoneTrigger, Text } from "@salt-ds/core";
3
3
  import { useComponentCssInjection } from "@salt-ds/styles";
4
4
  import { useWindow } from "@salt-ds/window";
5
- import { useCallback, useState } from "react";
5
+ import { useCallback, useMemo, useState } from "react";
6
6
  import { useCsvUpload } from "./useCsvUpload.js";
7
7
  import CsvUpload from "./CsvUpload.css";
8
8
  const classBase = "vuuCsvUpload";
9
9
  const CsvUpload_CsvUpload = (props)=>{
10
- const { children, dialogTitle = "Import CSV", embedded = false, onCancel, onClose, open, renderError } = props;
10
+ const { children, dialogTitle = "Import CSV", embedded = false, onCancel, onClose, open } = props;
11
11
  const isControlledOpen = void 0 !== open;
12
12
  const [internalOpen, setInternalOpen] = useState(open ?? true);
13
13
  const dialogOpen = isControlledOpen ? open : internalOpen;
@@ -18,7 +18,23 @@ const CsvUpload_CsvUpload = (props)=>{
18
18
  window: targetWindow
19
19
  });
20
20
  const { canImport, cancelImport, isProcessingFile, isImporting, importData, onDrop, onTriggerChange, schema, validation, error } = useCsvUpload(props);
21
- const fileErrors = validation?.errors.filter((e)=>e.column in validation.errorMap.fileErrors) ?? [];
21
+ const errorsToRender = useMemo(()=>{
22
+ if (validation?.errors && validation.errors.length > 0) return validation.errors;
23
+ const parseErrors = error?.errors.schemaError?.parseError?.errors || error?.errors.validationError?.parseError?.errors;
24
+ if (parseErrors && parseErrors.length > 0) return parseErrors;
25
+ return [];
26
+ }, [
27
+ validation,
28
+ error
29
+ ]);
30
+ const parsedSchemaErrors = useMemo(()=>{
31
+ const schemaErrorMsg = error?.errors.schemaError?.message || error?.errors.validationError?.message;
32
+ if (!schemaErrorMsg) return [];
33
+ const cleanedMsg = schemaErrorMsg.replace(/^CSV validation failed:\s*/, "");
34
+ return cleanedMsg.split(";").map((item)=>item.trim()).filter((item)=>item.length > 0);
35
+ }, [
36
+ error
37
+ ]);
22
38
  const hasErrors = !!error || validation && validation.errors.length > 0;
23
39
  const isUploaded = canImport || isImporting;
24
40
  const status = hasErrors ? "error" : isUploaded ? "success" : void 0;
@@ -37,73 +53,101 @@ const CsvUpload_CsvUpload = (props)=>{
37
53
  importData,
38
54
  onClose
39
55
  ]);
40
- const content = /*#__PURE__*/ jsxs("div", {
41
- className: classBase,
42
- children: [
43
- /*#__PURE__*/ jsx(FileDropZone, {
44
- className: `${classBase}-dropZone`,
45
- disabled: void 0 === schema || isProcessingFile || isImporting,
46
- onDrop: onDrop,
47
- status: status,
48
- children: isUploaded ? /*#__PURE__*/ jsxs(Fragment, {
49
- children: [
50
- /*#__PURE__*/ jsx(FileDropZoneIcon, {
51
- status: "success"
52
- }),
53
- /*#__PURE__*/ jsx("strong", {
54
- children: "Upload completed"
55
- })
56
- ]
57
- }) : /*#__PURE__*/ jsxs(Fragment, {
58
- children: [
59
- /*#__PURE__*/ jsx(FileDropZoneIcon, {
60
- status: hasErrors ? "error" : void 0
61
- }),
62
- validation && validation.errors.length > 0 ? /*#__PURE__*/ jsxs(Fragment, {
63
- children: [
64
- /*#__PURE__*/ jsx("div", {
65
- children: "Your file contains errors"
66
- }),
67
- fileErrors.length > 0 && /*#__PURE__*/ jsx("ul", {
68
- className: `${classBase}-errorList`,
69
- children: fileErrors.map((error, i)=>/*#__PURE__*/ jsx("li", {
70
- className: `${classBase}-errorItem`,
71
- children: error.message
72
- }, `${error.column}-${error.message}-${i}`))
73
- }),
74
- /*#__PURE__*/ jsx("div", {
75
- children: "Please rectify and reupload"
76
- })
77
- ]
78
- }) : /*#__PURE__*/ jsx("div", {
79
- children: "Drop a file here or"
80
- }),
81
- /*#__PURE__*/ jsx(FileDropZoneTrigger, {
82
- accept: ".csv,text/csv",
83
- onChange: onTriggerChange,
84
- children: "BROWSE FILES"
85
- }),
86
- /*#__PURE__*/ jsx(Text, {
87
- children: "Only .csv files"
88
- }),
89
- children
90
- ]
56
+ const renderErrorsContent = useMemo(()=>{
57
+ if (error?.errors.importError) return /*#__PURE__*/ jsxs(Fragment, {
58
+ children: [
59
+ /*#__PURE__*/ jsx("strong", {
60
+ children: "Import failed"
61
+ }),
62
+ /*#__PURE__*/ jsx("div", {
63
+ className: `${classBase}-errorContainer`,
64
+ children: /*#__PURE__*/ jsx("div", {
65
+ className: `${classBase}-errorItem ${classBase}-importErrorItem`,
66
+ children: error.errors.importError.message
67
+ })
91
68
  })
92
- }),
93
- error && (renderError ? renderError(error) : /*#__PURE__*/ jsxs("div", {
94
- className: `${classBase}-errors`,
69
+ ]
70
+ });
71
+ if (hasErrors) {
72
+ const headingText = error ? "Validation failed" : "Your file contains errors";
73
+ return /*#__PURE__*/ jsxs(Fragment, {
95
74
  children: [
75
+ /*#__PURE__*/ jsx("strong", {
76
+ children: headingText
77
+ }),
96
78
  /*#__PURE__*/ jsx("div", {
97
- children: /*#__PURE__*/ jsx("strong", {
98
- children: "Import Error:"
79
+ className: `${classBase}-errorContainer`,
80
+ children: errorsToRender.length > 0 ? /*#__PURE__*/ jsx("ul", {
81
+ className: `${classBase}-errorList`,
82
+ children: errorsToRender.map((error, i)=>/*#__PURE__*/ jsxs("li", {
83
+ className: `${classBase}-errorItem`,
84
+ children: [
85
+ error.rowNum > 0 ? `Row ${error.rowNum}: ` : "",
86
+ "*" === error.column ? "" : `${error.column}: `,
87
+ error.message
88
+ ]
89
+ }, `${error.column}-${error.message}-${i}`))
90
+ }) : parsedSchemaErrors.length > 0 ? /*#__PURE__*/ jsx("ul", {
91
+ className: `${classBase}-errorList`,
92
+ children: parsedSchemaErrors.map((errMsg)=>/*#__PURE__*/ jsx("li", {
93
+ className: `${classBase}-errorItem`,
94
+ children: errMsg
95
+ }, errMsg))
96
+ }) : /*#__PURE__*/ jsx("div", {
97
+ className: `${classBase}-errorItem ${classBase}-importErrorItem`,
98
+ children: error?.errors.schemaError?.message || error?.errors.validationError?.message || "An unexpected error occurred during import"
99
99
  })
100
+ })
101
+ ]
102
+ });
103
+ }
104
+ return /*#__PURE__*/ jsx("div", {
105
+ children: "Drop a file here or"
106
+ });
107
+ }, [
108
+ error,
109
+ hasErrors,
110
+ errorsToRender,
111
+ parsedSchemaErrors
112
+ ]);
113
+ const content = /*#__PURE__*/ jsx("div", {
114
+ className: classBase,
115
+ children: /*#__PURE__*/ jsx(FileDropZone, {
116
+ className: `${classBase}-dropZone`,
117
+ disabled: void 0 === schema || isProcessingFile || isImporting,
118
+ onDrop: onDrop,
119
+ status: status,
120
+ children: isUploaded ? /*#__PURE__*/ jsxs(Fragment, {
121
+ children: [
122
+ /*#__PURE__*/ jsx(FileDropZoneIcon, {
123
+ status: "success"
100
124
  }),
101
- /*#__PURE__*/ jsx("div", {
102
- children: error.errors.importError?.message || error.errors.schemaError?.message || error.errors.validationError?.message || "An unexpected error occurred during import."
125
+ /*#__PURE__*/ jsx("strong", {
126
+ children: "Upload completed"
103
127
  })
104
128
  ]
105
- }))
106
- ]
129
+ }) : /*#__PURE__*/ jsxs(Fragment, {
130
+ children: [
131
+ /*#__PURE__*/ jsx(FileDropZoneIcon, {
132
+ status: hasErrors ? "error" : void 0
133
+ }),
134
+ renderErrorsContent,
135
+ hasErrors && /*#__PURE__*/ jsx(Text, {
136
+ className: `${classBase}-rectifyPrompt`,
137
+ children: "Please rectify and reupload"
138
+ }),
139
+ /*#__PURE__*/ jsx(FileDropZoneTrigger, {
140
+ accept: ".csv,text/csv",
141
+ onChange: onTriggerChange,
142
+ children: "BROWSE FILES"
143
+ }),
144
+ /*#__PURE__*/ jsx(Text, {
145
+ children: "Only .csv files"
146
+ }),
147
+ children
148
+ ]
149
+ })
150
+ })
107
151
  });
108
152
  const actions = /*#__PURE__*/ jsxs(DialogActions, {
109
153
  children: [
@@ -45,7 +45,7 @@ const DataUploadPreview_DataUploadPreview = ({ className, editSession, onClose,
45
45
  editable: false,
46
46
  hidden: false,
47
47
  label: "Error",
48
- width: 200
48
+ width: 300
49
49
  } : {
50
50
  ...column,
51
51
  editable: true
@@ -13,7 +13,7 @@ var csv_errors_CsvValidationErrorEnum = /*#__PURE__*/ function(CsvValidationErro
13
13
  CsvValidationErrorEnum["MISSING_KEY_COLUMN"] = "MISSING_KEY_COLUMN";
14
14
  CsvValidationErrorEnum["UNKNOWN_COLUMN"] = "UNKNOWN_COLUMN";
15
15
  CsvValidationErrorEnum["MAX_ROWS_EXCEEDED"] = "MAX_ROWS_EXCEEDED";
16
- CsvValidationErrorEnum["EMPTY_NON_STRING_VALUE"] = "EMPTY_NON_STRING_VALUE";
16
+ CsvValidationErrorEnum["REQUIRED_FIELD_MISSING"] = "REQUIRED_FIELD_MISSING";
17
17
  CsvValidationErrorEnum["TYPE_MISMATCH"] = "TYPE_MISMATCH";
18
18
  CsvValidationErrorEnum["CUSTOM_VALIDATION"] = "CUSTOM_VALIDATION";
19
19
  return CsvValidationErrorEnum;
@@ -68,7 +68,7 @@ const parseCsv = (csvText, options)=>{
68
68
  }
69
69
  const rows = records.slice(1);
70
70
  rows.forEach((row, rowIndex)=>{
71
- if (row.length !== header.length) addCsvRowError(errorState, rowIndex + CSV_FIRST_DATA_ROW_NUMBER, "*", CsvParseErrorEnum.ROW_COLUMN_COUNT_MISMATCH, "CSV rows must have the same number of columns as the header.", row.join(","));
71
+ if (row.length !== header.length) addCsvRowError(errorState, rowIndex + CSV_FIRST_DATA_ROW_NUMBER, "*", CsvParseErrorEnum.ROW_COLUMN_COUNT_MISMATCH, "This row has too many or too few columns compared to the header line. Check for extra or missing commas.", row.join(","));
72
72
  });
73
73
  if (hasCsvErrors(errorState.errorMap)) return withError("CSV rows must have the same number of columns as the header.", errorState.errorMap, errorState.errors, header, rows);
74
74
  return {
@@ -4,10 +4,44 @@ import { CSV_FIRST_DATA_ROW_NUMBER, MAX_ROWS_IN_CSV } from "./csv-constants.js";
4
4
  const INTERNAL_KEY_COLUMNS = new Set([
5
5
  "vuuRowNum"
6
6
  ]);
7
+ const getFriendlyTypeName = (type)=>{
8
+ switch(type){
9
+ case "int":
10
+ case "long":
11
+ return "whole number";
12
+ case "double":
13
+ case "number":
14
+ case "decimal":
15
+ case "scaleddecimal":
16
+ case "scaleddecimal2":
17
+ case "scaleddecimal4":
18
+ case "scaleddecimal6":
19
+ case "scaleddecimal8":
20
+ return "decimal or number";
21
+ case "time":
22
+ return "time in 'HH:MM:SS' format";
23
+ case "epochtimestamp":
24
+ case "epochtimestampnano":
25
+ case "date/time":
26
+ return "date/time";
27
+ case "char":
28
+ return "single character";
29
+ case "boolean":
30
+ return "boolean (true/false)";
31
+ case "json":
32
+ return "JSON value";
33
+ default:
34
+ return type;
35
+ }
36
+ };
37
+ const getFriendlyErrorMessage = (errMessage, rawValue, toType)=>{
38
+ if (errMessage.includes("is not a valid")) return `'${rawValue}' is not a valid ${getFriendlyTypeName(toType)}`;
39
+ return errMessage;
40
+ };
7
41
  const validateCsvAgainstSchema = (parsed, tableSchema, options)=>{
8
42
  const schemaColumns = new Map(tableSchema.columns.map((col)=>[
9
43
  col.name,
10
- col.serverDataType
44
+ col
11
45
  ]));
12
46
  const maxRows = options?.maxRows ?? MAX_ROWS_IN_CSV;
13
47
  const errorState = createCsvErrorState();
@@ -21,22 +55,27 @@ const validateCsvAgainstSchema = (parsed, tableSchema, options)=>{
21
55
  const rowNum = rowIndex + CSV_FIRST_DATA_ROW_NUMBER;
22
56
  const typedRow = {};
23
57
  const rawRow = parsed.header.reduce((acc, headerCol, idx)=>{
24
- acc[headerCol] = rowValues[idx];
58
+ acc[headerCol] = rowValues[idx] ?? "";
25
59
  return acc;
26
60
  }, {});
27
61
  parsed.header.forEach((columnName, columnIndex)=>{
28
- const rawValue = rowValues[columnIndex];
29
- const schemaType = schemaColumns.get(columnName);
30
- if (0 === rawValue.length && "string" !== schemaType) return void addCsvRowError(errorState, rowNum, columnName, CsvValidationErrorEnum.EMPTY_NON_STRING_VALUE, "Empty value is not allowed for non-string columns.", rawValue);
62
+ const rawValue = rowValues[columnIndex] ?? "";
63
+ const schemaColumn = schemaColumns.get(columnName);
64
+ const schemaType = schemaColumn?.serverDataType;
65
+ const isRequired = schemaColumn?.required === true;
66
+ if (0 === rawValue.length) {
67
+ if (isRequired) addCsvRowError(errorState, rowNum, columnName, CsvValidationErrorEnum.REQUIRED_FIELD_MISSING, "This field is required and cannot be left blank", rawValue);
68
+ return;
69
+ }
31
70
  let value;
32
71
  const toType = schemaType ?? "string";
33
72
  try {
34
73
  value = getTypedValue(rawValue, toType);
35
74
  } catch (err) {
36
- addCsvRowError(errorState, rowNum, columnName, CsvValidationErrorEnum.TYPE_MISMATCH, err instanceof Error ? err.message : String(err), rawValue);
75
+ addCsvRowError(errorState, rowNum, columnName, CsvValidationErrorEnum.TYPE_MISMATCH, getFriendlyErrorMessage(err instanceof Error ? err.message : String(err), rawValue, toType), rawValue);
37
76
  return;
38
77
  }
39
- if (void 0 === value) return void addCsvRowError(errorState, rowNum, columnName, CsvValidationErrorEnum.TYPE_MISMATCH, `Value '${rawValue}' is not a valid ${toType}`, rawValue);
78
+ if (void 0 === value) return void addCsvRowError(errorState, rowNum, columnName, CsvValidationErrorEnum.TYPE_MISMATCH, `'${rawValue}' is not a valid ${getFriendlyTypeName(toType)}`, rawValue);
40
79
  const customValidator = options?.validators?.[columnName];
41
80
  if (customValidator) {
42
81
  const validationResult = customValidator(rawValue, columnName, rawRow);
@@ -1,4 +1,4 @@
1
- import { isRpcError } from "@vuu-ui/vuu-utils";
1
+ import { isRpcError, metadataKeys } from "@vuu-ui/vuu-utils";
2
2
  import { CSV_FIRST_DATA_ROW_NUMBER } from "./csv-constants.js";
3
3
  const isRecord = (value)=>"object" == typeof value && null !== value;
4
4
  const toErrorMessage = (error)=>error instanceof Error ? error.message : String(error);
@@ -56,4 +56,49 @@ const executeBatchRpcCalls = async (items, executor, errorFormatter)=>{
56
56
  results
57
57
  };
58
58
  };
59
- export { buildRowErrorMessage, createUploadError, executeBatchRpcCalls, hasFileParseErrors, isCsvParseError, mergeValidationWithParseErrors, normalizeTableData, toErrorMessage, toValidationErrorsFromParseRowErrors };
59
+ const getInlineRowErrorMessage = (result)=>{
60
+ if (isRecord(result) && "data" in result && isRecord(result.data)) {
61
+ const data = result.data;
62
+ const msg = data.vuuMsg ?? data.msg;
63
+ if ("string" == typeof msg && "" !== msg.trim()) return msg.trim();
64
+ }
65
+ };
66
+ const getRowVuuMsgError = (row, vuuMsgDataIndex, vuuRowNumDataIndex)=>{
67
+ if (-1 === vuuMsgDataIndex) return;
68
+ const msg = Array.isArray(row) ? row[vuuMsgDataIndex] : row?.vuuMsg;
69
+ if ("string" == typeof msg && "" !== msg.trim()) {
70
+ const rowNum = -1 !== vuuRowNumDataIndex && void 0 !== row[vuuRowNumDataIndex] ? Number(row[vuuRowNumDataIndex]) : Number(row[metadataKeys.IDX]) + CSV_FIRST_DATA_ROW_NUMBER;
71
+ return {
72
+ rowNum,
73
+ message: msg.trim()
74
+ };
75
+ }
76
+ };
77
+ const waitForSessionErrors = (isRemote, sessionErrors, receivedRowKeys, expectedRowCount, listeners, timeoutMs = 500)=>{
78
+ if (sessionErrors.size > 0 || !isRemote) return Promise.resolve([
79
+ ...sessionErrors.values()
80
+ ]);
81
+ return new Promise((resolve)=>{
82
+ let timeoutId;
83
+ const onUpdate = ()=>{
84
+ if (sessionErrors.size > 0 || receivedRowKeys.size >= expectedRowCount) {
85
+ cleanup();
86
+ resolve([
87
+ ...sessionErrors.values()
88
+ ]);
89
+ }
90
+ };
91
+ const cleanup = ()=>{
92
+ clearTimeout(timeoutId);
93
+ listeners.delete(onUpdate);
94
+ };
95
+ listeners.add(onUpdate);
96
+ timeoutId = setTimeout(()=>{
97
+ cleanup();
98
+ resolve([
99
+ ...sessionErrors.values()
100
+ ]);
101
+ }, timeoutMs);
102
+ });
103
+ };
104
+ export { buildRowErrorMessage, createUploadError, executeBatchRpcCalls, getInlineRowErrorMessage, getRowVuuMsgError, hasFileParseErrors, isCsvParseError, mergeValidationWithParseErrors, normalizeTableData, toErrorMessage, toValidationErrorsFromParseRowErrors, waitForSessionErrors };
@@ -0,0 +1,2 @@
1
+ export * from "./useImportSchema.js";
2
+ export * from "./useImportSession.js";
@@ -0,0 +1,44 @@
1
+ import { useData } from "@vuu-ui/vuu-utils";
2
+ import { useEffect, useMemo, useState } from "react";
3
+ const useImportSchema = ({ dataSource, importSchema, importTable })=>{
4
+ const { getServerAPI } = useData();
5
+ const [fetchedImportSchema, setFetchedImportSchema] = useState();
6
+ useEffect(()=>{
7
+ if (importSchema || void 0 === importTable) return void setFetchedImportSchema(void 0);
8
+ let cancelled = false;
9
+ (async ()=>{
10
+ try {
11
+ const server = await getServerAPI();
12
+ const tableSchema = await server.getTableSchema(importTable);
13
+ if (!cancelled) setFetchedImportSchema(tableSchema);
14
+ } catch (error) {
15
+ console.error("[useImportSchema] failed to fetch import table schema", error);
16
+ }
17
+ })();
18
+ return ()=>{
19
+ cancelled = true;
20
+ };
21
+ }, [
22
+ getServerAPI,
23
+ importSchema,
24
+ importTable
25
+ ]);
26
+ const resolvedImportSchema = importSchema ?? fetchedImportSchema;
27
+ const sessionOverrides = useMemo(()=>{
28
+ const columns = resolvedImportSchema?.columns.map(({ name })=>name);
29
+ return columns || importTable ? {
30
+ columns,
31
+ table: importTable
32
+ } : void 0;
33
+ }, [
34
+ resolvedImportSchema,
35
+ importTable
36
+ ]);
37
+ const schema = importTable ? resolvedImportSchema : resolvedImportSchema ?? dataSource.tableSchema;
38
+ return {
39
+ resolvedImportSchema,
40
+ schema,
41
+ sessionOverrides
42
+ };
43
+ };
44
+ export { useImportSchema };