tfrere's picture
tfrere HF Staff
feat(editor): embed studio with data files and agent-aware editing
8fc8501
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,
};
}