File size: 2,566 Bytes
8fc8501 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | import { useCallback, useEffect, useState } from "react";
import type {
EmbedDataFile,
EmbedDataFileMeta,
EmbedDataStore,
} from "../editor/embeds/embed-data-store";
import {
MAX_DATA_FILE_SIZE,
extFromName,
inferDataShape,
isAcceptedExt,
} from "../utils/data-files";
interface UseEmbedDataOptions {
dataStore: EmbedDataStore | null;
userId: string;
}
export interface UploadResult {
ok: boolean;
name?: string;
error?: string;
}
export function useEmbedData({ dataStore, userId }: UseEmbedDataOptions) {
const [files, setFiles] = useState<EmbedDataFileMeta[]>(() =>
dataStore ? dataStore.list() : [],
);
useEffect(() => {
if (!dataStore) {
setFiles([]);
return;
}
setFiles(dataStore.list());
return dataStore.observe(() => {
setFiles(dataStore.list());
});
}, [dataStore]);
const uploadFile = useCallback(
async (file: File): Promise<UploadResult> => {
if (!dataStore) return { ok: false, error: "Data store not ready" };
if (file.size > MAX_DATA_FILE_SIZE) {
return {
ok: false,
error: `File too large (max ${(MAX_DATA_FILE_SIZE / (1024 * 1024)).toFixed(0)} MB)`,
};
}
const ext = extFromName(file.name);
if (!isAcceptedExt(ext)) {
return {
ok: false,
error: `Unsupported file type ".${ext}". Use CSV, TSV, JSON, NDJSON or TXT.`,
};
}
const content = await file.text();
const shape = inferDataShape(ext, content);
const record: EmbedDataFile = {
meta: {
name: file.name,
ext,
size: new Blob([content]).size,
uploader: userId,
addedAt: Date.now(),
rowCount: shape.rowCount,
columns: shape.columns,
},
content,
};
dataStore.set(record);
return { ok: true, name: file.name };
},
[dataStore, userId],
);
const uploadFiles = useCallback(
async (fileList: FileList | File[]): Promise<UploadResult[]> => {
const arr = Array.from(fileList);
const results: UploadResult[] = [];
for (const f of arr) {
results.push(await uploadFile(f));
}
return results;
},
[uploadFile],
);
const removeFile = useCallback(
(name: string) => {
dataStore?.remove(name);
},
[dataStore],
);
const getFile = useCallback(
(name: string) => dataStore?.get(name),
[dataStore],
);
return {
files,
uploadFile,
uploadFiles,
removeFile,
getFile,
};
}
|