update: dir tree

This commit is contained in:
tao.chen
2026-08-14 15:02:55 +08:00
parent 4530811441
commit 65d14b8610
6 changed files with 73 additions and 21 deletions
@@ -19,6 +19,7 @@ type TreeContextMenuProps = {
onChooseUpload: (parentPath: string) => void;
onRemoveDirectory: (path: string) => void;
onCopyResourcePath?: (jupyterPath: string) => void;
onRemoveResource?: (resourceId: string) => void;
onClose: () => void;
};
@@ -32,6 +33,7 @@ export function TreeContextMenu({
onChooseUpload,
onRemoveDirectory,
onCopyResourcePath,
onRemoveResource,
onClose,
}: TreeContextMenuProps) {
if (!contextMenu) return null;
@@ -55,19 +57,36 @@ export function TreeContextMenu({
{contextMenu.kind === "file" && contextMenu.script ? (
<>
{isDataResource ? (
<button
type="button"
role="menuitem"
onClick={() => {
if (onCopyResourcePath) {
onCopyResourcePath(contextMenu.script!.relative_path);
}
onClose();
}}
>
<Icon name="database" size={16} />
Jupyter
</button>
<>
<button
type="button"
role="menuitem"
onClick={() => {
if (onCopyResourcePath) {
onCopyResourcePath(contextMenu.script!.relative_path);
}
onClose();
}}
>
<Icon name="database" size={16} />
Jupyter
</button>
{onRemoveResource && (
<button
className="is-danger"
type="button"
role="menuitem"
onClick={() => {
const id = contextMenu.script!.script_id.replace(/^data:/, "");
onRemoveResource(id);
onClose();
}}
>
<Icon name="close" size={16} />
</button>
)}
</>
) : (
<>
<button
+2
View File
@@ -232,6 +232,8 @@ export function useApi(): WorkspaceBoundApi {
rawApi.uploadResourceBytes(workspaceId, uploadId, fileBytes, contentType),
bindResourceUpload: (uploadId, body) =>
rawApi.bindResourceUpload(workspaceId, uploadId, body),
deleteResource: (resourceId) =>
rawApi.deleteResource(workspaceId, resourceId),
updateScript: (scriptId, input) =>
rawApi.updateScript(workspaceId, scriptId, input),
deleteScript: (scriptId) => rawApi.deleteScript(workspaceId, scriptId),
@@ -58,6 +58,7 @@ export default function ScriptsPage() {
const uploadDataResource = useScriptWorkspaceStore((s) => s.uploadDataResource);
const createFolder = useScriptWorkspaceStore((s) => s.createFolder);
const deleteScript = useScriptWorkspaceStore((s) => s.deleteScript);
const deleteDataResource = useScriptWorkspaceStore((s) => s.deleteDataResource);
const deleteDirectory = useScriptWorkspaceStore((s) => s.deleteDirectory);
const toggleScriptLock = useScriptWorkspaceStore((s) => s.toggleScriptLock);
const openPublishDialog = useScriptWorkspaceStore((s) => s.openPublishDialog);
@@ -421,6 +422,7 @@ export default function ScriptsPage() {
onChooseUpload={(parentPath) => triggerUpload(parentPath ?? "")}
onRemoveDirectory={(p) => void deleteDirectory(p)}
onCopyResourcePath={(p) => void handleCopyResourcePath(p)}
onRemoveResource={(id) => void deleteDataResource(id)}
onClose={closeContextMenu}
/>
@@ -1,7 +1,6 @@
import { useEffect } from "react";
import {
bindScriptWorkspaceApi,
editSessionHandle,
useScriptWorkspaceStore,
} from "../state/scriptWorkspaceStore";
@@ -61,11 +60,4 @@ export function useEditSessionLifecycle({
window.addEventListener("beforeunload", handleUnload);
return () => window.removeEventListener("beforeunload", handleUnload);
}, []);
// 4) layout 卸载时解绑 api
useEffect(() => {
return () => {
bindScriptWorkspaceApi(null);
};
}, []);
}
@@ -118,6 +118,7 @@ type State = {
}) => Promise<ResourceItem | null>;
createFolder: (name: string, parentPath: string) => Promise<void>;
deleteScript: (script: ScriptItem) => Promise<void>;
deleteDataResource: (resourceId: string) => Promise<void>;
deleteDirectory: (path: string) => Promise<void>;
toggleExpanded: (path: string, loadPath?: string) => Promise<void>;
loadChildren: (parentPath: string) => Promise<void>;
@@ -856,6 +857,28 @@ export const useScriptWorkspaceStore = create<State>((set, get) => {
}
},
deleteDataResource: async (resourceId) => {
const api = requireApi();
useUiStore.getState().closeContextMenu();
if (!window.confirm(`确定删除数据资源吗?稳定版本会保留。`)) {
return;
}
try {
await api.deleteResource(resourceId);
set((state) => ({
dataResources: state.dataResources.filter(
(r) => r.resource_id !== resourceId,
),
}));
pushToast("success", "数据资源已删除");
} catch (error) {
pushToast(
"error",
error instanceof Error ? error.message : "数据资源删除失败",
);
}
},
createFolder: async (name, parentPath) => {
const api = requireApi();
const trimmed = name.trim();
+14
View File
@@ -428,6 +428,17 @@ export async function listResources(
);
}
export async function deleteResource(
workspaceId: string,
resourceId: string,
): Promise<{ resource_id: string; status: string }> {
return apiRequest<{ resource_id: string; status: string }>(
`/api/v1/data-resources/${encodeURIComponent(resourceId)}`,
{ method: "DELETE" },
workspaceId,
);
}
export async function createResourceUpload(
workspaceId: string,
body: {
@@ -1462,6 +1473,9 @@ export type WorkspaceBoundApi = {
uploadId: string,
body: Parameters<typeof bindResourceUpload>[2],
) => Promise<ResourceItem>;
deleteResource: (
resourceId: string,
) => Promise<{ resource_id: string; status: string }>;
updateScript: (
scriptId: string,
input: Parameters<typeof updateScript>[2],