update: data source

This commit is contained in:
tao.chen
2026-08-14 11:59:06 +08:00
parent 225a585499
commit 480e1cc638
15 changed files with 432 additions and 559 deletions
+98 -7
View File
@@ -3,6 +3,7 @@ import { type FormEvent, useEffect, useMemo, useRef } from "react";
import { useAuth } from "../../context/AuthContext";
import { CreateFolderModal } from "../../components/platform/CreateFolderModal";
import { CreateScriptModal } from "../../components/platform/CreateScriptModal";
import { DataResourceUploadModal } from "../../components/platform/DataResourceUploadModal";
import Icon from "../../components/common/Icon";
import { PublishModal } from "../../components/platform/PublishModal";
import { ScriptExplorer } from "../../components/platform/ScriptExplorer";
@@ -32,6 +33,9 @@ export default function ScriptsPage() {
const latestVersion = useScriptWorkspaceStore((s) => s.latestVersion);
const latestVersionLoading = useScriptWorkspaceStore((s) => s.latestVersionLoading);
const dataResources = useScriptWorkspaceStore((s) => s.dataResources);
const loadDataResources = useScriptWorkspaceStore((s) => s.loadDataResources);
const pythonEditorBuffers = useScriptWorkspaceStore((s) => s.pythonEditorBuffers);
// store actions
@@ -51,6 +55,7 @@ export default function ScriptsPage() {
const loadLatestVersion = useScriptWorkspaceStore((s) => s.loadLatestVersion);
const createScript = useScriptWorkspaceStore((s) => s.createScript);
const uploadScripts = useScriptWorkspaceStore((s) => s.uploadScripts);
const uploadDataResource = useScriptWorkspaceStore((s) => s.uploadDataResource);
const createFolder = useScriptWorkspaceStore((s) => s.createFolder);
const deleteScript = useScriptWorkspaceStore((s) => s.deleteScript);
const deleteDirectory = useScriptWorkspaceStore((s) => s.deleteDirectory);
@@ -74,6 +79,13 @@ export default function ScriptsPage() {
const openCreateDialog = useUiStore((s) => s.openCreateDialog);
const openFolderDialog = useUiStore((s) => s.openFolderDialog);
const chooseUpload = useUiStore((s) => s.chooseUpload);
const dataResourceDialog = useUiStore((s) => s.dataResourceDialog);
const openDataResourceDialog = useUiStore((s) => s.openDataResourceDialog);
const closeDataResourceDialog = useUiStore((s) => s.closeDataResourceDialog);
const setDataResourceName = useUiStore((s) => s.setDataResourceName);
const setDataResourceVisibility = useUiStore((s) => s.setDataResourceVisibility);
const setDataResourceDescription = useUiStore((s) => s.setDataResourceDescription);
const setDataResourceTargetPath = useUiStore((s) => s.setDataResourceTargetPath);
const publish = useUiStore((s) => s.publish);
const setReleaseNote = useUiStore((s) => s.setReleaseNote);
const setPublishVisibility = useUiStore((s) => s.setPublishVisibility);
@@ -87,6 +99,10 @@ export default function ScriptsPage() {
void load();
}, [load]);
useEffect(() => {
void loadDataResources();
}, [loadDataResources, workspaceId]);
useEffect(() => {
reset();
// 刷新前递增版本号,触发已打开标签页的只读内容刷新
@@ -189,12 +205,68 @@ export default function ScriptsPage() {
void closeTab(scriptId);
};
// 5) handlers
// 5) handlers
const SCRIPT_EXTS = [".py", ".ipynb"];
const DATA_EXTS = [".csv", ".xlsx", ".xls", ".tsv", ".json", ".parquet", ".txt"];
const matchesExt = (name: string, exts: string[]) =>
exts.some((ext) => name.toLowerCase().endsWith(ext));
const handleUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
const files = Array.from(event.target.files ?? []);
event.target.value = "";
if (files.length === 0) return;
void uploadScripts(files, upload.parentPath);
const scriptFiles = files.filter((f) => matchesExt(f.name, SCRIPT_EXTS));
const dataFiles = files.filter((f) => matchesExt(f.name, DATA_EXTS));
const rejected = files.filter(
(f) => !matchesExt(f.name, SCRIPT_EXTS) && !matchesExt(f.name, DATA_EXTS),
);
if (rejected.length) {
pushToast({
tone: "error",
message: `不支持的文件类型: ${rejected.map((f) => f.name).join(", ")}`,
});
}
if (scriptFiles.length) {
void uploadScripts(scriptFiles, upload.parentPath);
}
if (dataFiles.length === 1) {
openDataResourceDialog(dataFiles[0], upload.parentPath);
} else if (dataFiles.length > 1) {
pushToast({
tone: "info",
message: "数据资源一次只支持上传一个文件,请分别上传",
});
}
};
const handleDataResourceSubmit = (event: FormEvent) => {
event.preventDefault();
const { file, resourceName, visibility, description, targetPath } = dataResourceDialog;
if (!file || !resourceName.trim()) return;
void uploadDataResource(file, {
resourceName: resourceName.trim(),
visibility,
description: description.trim(),
targetPath: targetPath.trim(),
}).then((resource) => {
if (resource) void loadDataResources();
});
};
const handleCopyResourcePath = async (jupyterPath: string) => {
if (!jupyterPath) return;
const fullPrefix = `${workspaceId ?? ""}/${user?.user_id ?? ""}/`;
let stripped = jupyterPath;
if (fullPrefix !== "/" && stripped.startsWith(fullPrefix)) {
stripped = stripped.slice(fullPrefix.length);
}
try {
await navigator.clipboard.writeText(stripped);
pushToast({ tone: "success", message: `已复制:${stripped}` });
} catch {
pushToast({ tone: "error", message: "复制失败" });
}
};
const handleCreateSubmit = (event: FormEvent) => {
@@ -223,6 +295,7 @@ export default function ScriptsPage() {
scripts={scripts}
filteredScripts={filteredScripts}
directories={directories}
dataResources={dataResources}
user={user}
selectedId={selectedId}
loading={loading}
@@ -238,6 +311,7 @@ export default function ScriptsPage() {
onChooseUpload={(parentPath) => triggerUpload(parentPath)}
onContextMenu={showContextMenu}
onSelect={openTab}
onCopyResourcePath={(p) => void handleCopyResourcePath(p)}
uploadInputRef={uploadInputRef}
onHandleUpload={handleUpload}
/>
@@ -344,8 +418,9 @@ export default function ScriptsPage() {
onOpenCreateDialog={(parentPath, scriptType) =>
openCreateDialog(parentPath, scriptType)}
onOpenFolderDialog={(parentPath) => openFolderDialog(parentPath)}
onChooseUpload={(parentPath) => chooseUpload(parentPath)}
onChooseUpload={(parentPath) => triggerUpload(parentPath ?? "")}
onRemoveDirectory={(p) => void deleteDirectory(p)}
onCopyResourcePath={(p) => void handleCopyResourcePath(p)}
onClose={closeContextMenu}
/>
@@ -360,10 +435,26 @@ export default function ScriptsPage() {
onClose={closePublishDialog}
/>
<VersionReceiptModal
publishedVersion={publish.publishedVersion}
onClose={clearPublishedVersion}
onCopy={(message) => pushToast({ tone: "success", message })}
<VersionReceiptModal
publishedVersion={publish.publishedVersion}
onClose={clearPublishedVersion}
onCopy={(message) => pushToast({ tone: "success", message })}
/>
<DataResourceUploadModal
open={dataResourceDialog.open}
file={dataResourceDialog.file}
resourceName={dataResourceDialog.resourceName}
visibility={dataResourceDialog.visibility}
description={dataResourceDialog.description}
uploading={dataResourceDialog.uploading}
parentPath={dataResourceDialog.parentPath}
targetPath={dataResourceDialog.targetPath}
onNameChange={setDataResourceName}
onVisibilityChange={setDataResourceVisibility}
onDescriptionChange={setDataResourceDescription}
onTargetPathChange={setDataResourceTargetPath}
onSubmit={handleDataResourceSubmit}
onClose={closeDataResourceDialog}
/>
</section>
);