update: dir tree
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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],
|
||||
|
||||
Reference in New Issue
Block a user