@vuu-ui/vuu-table-extras 3.3.7 → 3.3.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.3.7",
2
+ "version": "3.3.9",
3
3
  "author": "heswell",
4
4
  "main": "./src/index.js",
5
5
  "license": "Apache-2.0",
@@ -11,19 +11,19 @@
11
11
  "lezer-generate:column": "lezer-generator --output ./src/column-expression-input/column-language-parser/generated/column-parser.js ./src/column-expression-input/column-language-parser/grammar/column.grammar"
12
12
  },
13
13
  "devDependencies": {
14
- "@vuu-ui/vuu-filter-types": "3.3.7",
15
- "@vuu-ui/vuu-protocol-types": "3.3.7"
14
+ "@vuu-ui/vuu-filter-types": "3.3.9",
15
+ "@vuu-ui/vuu-protocol-types": "3.3.9"
16
16
  },
17
17
  "dependencies": {
18
- "@vuu-ui/vuu-codemirror": "3.3.7",
19
- "@vuu-ui/vuu-data-editing": "3.3.7",
20
- "@vuu-ui/vuu-data-react": "3.3.7",
21
- "@vuu-ui/vuu-data-types": "3.3.7",
22
- "@vuu-ui/vuu-table-types": "3.3.7",
23
- "@vuu-ui/vuu-popups": "3.3.7",
24
- "@vuu-ui/vuu-table": "3.3.7",
25
- "@vuu-ui/vuu-utils": "3.3.7",
26
- "@vuu-ui/vuu-ui-controls": "3.3.7",
18
+ "@vuu-ui/vuu-codemirror": "3.3.9",
19
+ "@vuu-ui/vuu-data-editing": "3.3.9",
20
+ "@vuu-ui/vuu-data-react": "3.3.9",
21
+ "@vuu-ui/vuu-data-types": "3.3.9",
22
+ "@vuu-ui/vuu-table-types": "3.3.9",
23
+ "@vuu-ui/vuu-popups": "3.3.9",
24
+ "@vuu-ui/vuu-table": "3.3.9",
25
+ "@vuu-ui/vuu-utils": "3.3.9",
26
+ "@vuu-ui/vuu-ui-controls": "3.3.9",
27
27
  "@lezer/lr": "1.4.2",
28
28
  "@salt-ds/core": "1.54.1",
29
29
  "@salt-ds/lab": "1.0.0-alpha.83",
@@ -7,7 +7,7 @@ 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 } = props;
10
+ const { children, dialogTitle = "Import CSV", embedded = false, onCancel, onClose, open, renderError } = props;
11
11
  const isControlledOpen = void 0 !== open;
12
12
  const [internalOpen, setInternalOpen] = useState(open ?? true);
13
13
  const dialogOpen = isControlledOpen ? open : internalOpen;
@@ -17,7 +17,7 @@ const CsvUpload_CsvUpload = (props)=>{
17
17
  css: CsvUpload,
18
18
  window: targetWindow
19
19
  });
20
- const { canImport, cancelImport, isProcessingFile, isImporting, importData, onDrop, onTriggerChange, schema, validation } = useCsvUpload(props);
20
+ const { canImport, cancelImport, isProcessingFile, isImporting, importData, onDrop, onTriggerChange, schema, validation, error } = useCsvUpload(props);
21
21
  const handleCancel = useCallback(async ()=>{
22
22
  await cancelImport();
23
23
  if (!isControlledOpen) setInternalOpen(false);
@@ -40,7 +40,7 @@ const CsvUpload_CsvUpload = (props)=>{
40
40
  className: `${classBase}-dropZone`,
41
41
  disabled: void 0 === schema || isProcessingFile || isImporting,
42
42
  onDrop: onDrop,
43
- status: validation && validation.errors.length > 0 ? "error" : void 0,
43
+ status: validation && validation.errors.length > 0 || error ? "error" : void 0,
44
44
  children: [
45
45
  /*#__PURE__*/ jsx(FileDropZoneIcon, {}),
46
46
  validation && validation.errors.length > 0 ? /*#__PURE__*/ jsxs(Fragment, {
@@ -53,7 +53,7 @@ const CsvUpload_CsvUpload = (props)=>{
53
53
  children: validation.errors.filter((e)=>e.column in validation.errorMap.fileErrors).map((error, i)=>/*#__PURE__*/ jsx("li", {
54
54
  className: `${classBase}-errorItem`,
55
55
  children: error.message
56
- }, i))
56
+ }, `${error.column}-${error.message}-${i}`))
57
57
  }),
58
58
  /*#__PURE__*/ jsx("div", {
59
59
  children: "Please rectify and reupload"
@@ -69,6 +69,19 @@ const CsvUpload_CsvUpload = (props)=>{
69
69
  })
70
70
  ]
71
71
  }),
72
+ error && (renderError ? renderError(error) : /*#__PURE__*/ jsxs("div", {
73
+ className: `${classBase}-errors`,
74
+ children: [
75
+ /*#__PURE__*/ jsx("div", {
76
+ children: /*#__PURE__*/ jsx("strong", {
77
+ children: "Import Error:"
78
+ })
79
+ }),
80
+ /*#__PURE__*/ jsx("div", {
81
+ children: error.errors.importError?.message || error.errors.schemaError?.message || error.errors.validationError?.message || "An unexpected error occurred during import."
82
+ })
83
+ ]
84
+ })),
72
85
  children
73
86
  ]
74
87
  });
@@ -12,6 +12,13 @@ const useCsvUpload = ({ dataSource, importMode = "direct", importSchema, importT
12
12
  const [isProcessingFile, setIsProcessingFile] = useState(false);
13
13
  const [isImporting, setIsImporting] = useState(false);
14
14
  const [fetchedImportSchema, setFetchedImportSchema] = useState();
15
+ const [error, setError] = useState();
16
+ const handleError = useCallback((errResult)=>{
17
+ setError(errResult);
18
+ onError?.(errResult);
19
+ }, [
20
+ onError
21
+ ]);
15
22
  useEffect(()=>{
16
23
  if (importSchema || void 0 === importTable) return void setFetchedImportSchema(void 0);
17
24
  let cancelled = false;
@@ -195,21 +202,23 @@ const useCsvUpload = ({ dataSource, importMode = "direct", importSchema, importT
195
202
  ]);
196
203
  const cancelImport = useCallback(async ()=>{
197
204
  operationIdRef.current++;
198
- try {
199
- await processingPromiseRef.current;
200
- } catch {}
205
+ processingPromiseRef.current = void 0;
206
+ setIsProcessingFile(false);
207
+ setIsImporting(false);
208
+ handleError(void 0);
201
209
  await closePendingEditSession(false);
202
210
  }, [
203
- closePendingEditSession
211
+ closePendingEditSession,
212
+ handleError
204
213
  ]);
205
214
  const processFile = useCallback(async (file, operationId)=>{
206
215
  setValidation(void 0);
207
- onError?.(void 0);
216
+ handleError(void 0);
208
217
  await closePendingEditSession(false);
209
218
  if (operationId !== operationIdRef.current) return;
210
219
  if (!isSessionTable(dataSource.table) && ("initialising" === dataSource.status || "unsubscribed" === dataSource.status)) {
211
220
  const errorMessage = `CsvUpload requires dataSource to be subscribed before uploading (current status: "${dataSource.status}").`;
212
- onError?.({
221
+ handleError({
213
222
  errors: {
214
223
  validationError: createUploadError("validation", errorMessage)
215
224
  }
@@ -223,7 +232,7 @@ const useCsvUpload = ({ dataSource, importMode = "direct", importSchema, importT
223
232
  const parsedCsv = parseCsv(fileContents, parseOptions);
224
233
  if (parsedCsv.error && hasFileParseErrors(parsedCsv.error)) {
225
234
  setValidation(void 0);
226
- onError?.({
235
+ handleError({
227
236
  errors: {
228
237
  validationError: createUploadError("validation", `Validation failed: ${parsedCsv.error.message}`, parsedCsv.error)
229
238
  }
@@ -235,7 +244,7 @@ const useCsvUpload = ({ dataSource, importMode = "direct", importSchema, importT
235
244
  });
236
245
  if (Object.keys(schemaValidation.errorMap.fileErrors).length > 0) {
237
246
  setValidation(schemaValidation);
238
- onError?.({
247
+ handleError({
239
248
  errors: {
240
249
  schemaError: createUploadError("schema", "CSV validation failed.", parsedCsv.error, {
241
250
  errorMap: schemaValidation.errorMap,
@@ -248,24 +257,28 @@ const useCsvUpload = ({ dataSource, importMode = "direct", importSchema, importT
248
257
  }
249
258
  const mergedValidation = mergeValidationWithParseErrors(schemaValidation, parsedCsv.error);
250
259
  setValidation(mergedValidation);
251
- if (mergedValidation.rows.length > 0) {
260
+ if (mergedValidation.rows.length > 0) try {
252
261
  await beginEditSession();
253
262
  if (operationId !== operationIdRef.current) return;
254
- try {
255
- const rowsAdded = await addAllRows(mergedValidation, operationId);
256
- if (!rowsAdded) return;
257
- } catch (error) {
258
- await endEditSessionAndNotify(false, "failed");
259
- setValidation(void 0);
260
- onError?.({
261
- errors: {
262
- importError: createUploadError("import", `RPC import failed: ${toErrorMessage(error)}`)
263
- }
264
- });
263
+ const rowsAdded = await addAllRows(mergedValidation, operationId);
264
+ if (!rowsAdded) return;
265
+ } catch (error) {
266
+ if (void 0 !== sessionDataSourceRef.current) await endEditSessionAndNotify(false, "failed");
267
+ else try {
268
+ await editSession.end(false);
269
+ } catch (err) {
270
+ console.error("[useCsvUpload] failed to end clean session", err);
265
271
  }
272
+ setValidation(void 0);
273
+ handleError({
274
+ errors: {
275
+ importError: createUploadError("import", `RPC import failed: ${toErrorMessage(error)}`)
276
+ }
277
+ });
266
278
  }
267
279
  }, [
268
- onError,
280
+ handleError,
281
+ editSession,
269
282
  addAllRows,
270
283
  maxRows,
271
284
  parseOptions,
@@ -297,13 +310,13 @@ const useCsvUpload = ({ dataSource, importMode = "direct", importSchema, importT
297
310
  validationError: createUploadError("validation", errorMessage, parseError)
298
311
  }
299
312
  };
300
- onError?.(errors);
313
+ handleError(errors);
301
314
  } finally{
302
315
  if (processingPromiseRef.current === processingPromise) processingPromiseRef.current = void 0;
303
316
  setIsProcessingFile(false);
304
317
  }
305
318
  }, [
306
- onError,
319
+ handleError,
307
320
  onProcessingStarted,
308
321
  processFile,
309
322
  setActiveSessionDataSource
@@ -326,7 +339,7 @@ const useCsvUpload = ({ dataSource, importMode = "direct", importSchema, importT
326
339
  const importData = useCallback(async ()=>{
327
340
  if (!canImport || void 0 === validation) return false;
328
341
  setIsImporting(true);
329
- onError?.(void 0);
342
+ handleError(void 0);
330
343
  try {
331
344
  const fallbackTableData = {
332
345
  columns: validation.columns,
@@ -357,7 +370,7 @@ const useCsvUpload = ({ dataSource, importMode = "direct", importSchema, importT
357
370
  importError: createUploadError("import", errorMessage)
358
371
  }
359
372
  };
360
- onError?.(errors);
373
+ handleError(errors);
361
374
  return false;
362
375
  } finally{
363
376
  setIsImporting(false);
@@ -366,7 +379,7 @@ const useCsvUpload = ({ dataSource, importMode = "direct", importSchema, importT
366
379
  canImport,
367
380
  editSession,
368
381
  endEditSessionAndNotify,
369
- onError,
382
+ handleError,
370
383
  onImported,
371
384
  onPreview,
372
385
  importMode,
@@ -382,7 +395,8 @@ const useCsvUpload = ({ dataSource, importMode = "direct", importSchema, importT
382
395
  onTriggerChange,
383
396
  sessionTable,
384
397
  schema,
385
- validation
398
+ validation,
399
+ error
386
400
  };
387
401
  };
388
402
  export { useCsvUpload };
@@ -60,5 +60,9 @@ export interface CsvUploadProps {
60
60
  parseOptions?: CsvParseOptions;
61
61
  importMode?: "direct" | "preview";
62
62
  rowDefaults?: RowDefaultDataItemValues;
63
+ /**
64
+ * Custom renderer for the error panel.
65
+ */
66
+ renderError?: (error: CsvUploadErrorResult) => ReactNode;
63
67
  }
64
68
  export declare const CsvUpload: (props: CsvUploadProps) => import("react/jsx-runtime").JSX.Element;
@@ -11,7 +11,7 @@ export declare const useDataUploadPreview: ({ dataSource, editSession, onClose,
11
11
  canSave: boolean;
12
12
  hasSelection: boolean;
13
13
  onCancel: () => Promise<void>;
14
- onDelete: () => Promise<void>;
14
+ onDelete: () => Promise<import("@vuu-ui/vuu-protocol-types").RpcResult>;
15
15
  onSave: (force?: boolean) => Promise<void>;
16
16
  sessionError: string | undefined;
17
17
  };
@@ -37,5 +37,6 @@ export type UseCsvUploadReturn = {
37
37
  sessionTable: CsvUploadSessionTable | undefined;
38
38
  schema: TableSchema | undefined;
39
39
  validation: CsvValidationResult | undefined;
40
+ error: CsvUploadErrorResult | undefined;
40
41
  };
41
42
  export declare const useCsvUpload: ({ dataSource, importMode, importSchema, importTable, onImportSessionEnded, onImportSessionStarted, onError, onImported, onPreview, onProcessingStarted, maxRows, parseOptions, rowDefaults, }: CsvUploadHookProps) => UseCsvUploadReturn;