fix: script not found

This commit is contained in:
tao.chen
2026-08-04 14:24:55 +08:00
parent 1cf2eecbc9
commit 94a1aef7c7
4 changed files with 37 additions and 49 deletions
+37 -13
View File
@@ -21,6 +21,7 @@ from fastapi import (
from sqlalchemy import func, select from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.ext.asyncio import AsyncSession
from common.config import settings
from common.db.models import ( from common.db.models import (
Scripts, Scripts,
StorageObjects, StorageObjects,
@@ -356,19 +357,40 @@ async def create_script_record(
detail=exc.detail, detail=exc.detail,
) from exc ) from exc
# Synthesise a storage_data-shaped dict from the Jupyter response # Build a real StorageObjects row so the file participates in
# so the existing script_payload + response shape keep working. # workspace-tree / list / get queries that JOIN this table. The
# The storage_object_id is a fresh ULID — there is no real # bytes live in the Jupyter mount; rclone replicates them to
# StorageObject row for this file; downstream list/get operations # RustFS asynchronously. We mark the row "available" because the
# that JOIN StorageObjects will skip jupyter-only scripts. # file is queryable as a workspace file from the user's POV; the
# storage_uri points at where the replicated bytes will land.
object_id = new_ulid() object_id = new_ulid()
storage_data = { object_key = f"{workspace_id}/{jupyter_name}"
"storage_object_id": object_id, bucket_name = settings.rustfs_workspace_bucket
"relative_path": jupyter_name, relative_path = user_relative_path(context, jupyter_name)
"object_key": f"{workspace_id}/{jupyter_name}", mime_type = mimetypes.guess_type(jupyter_name)[0]
"content_hash": content_hash, storage_object = StorageObjects(
"size_bytes": size_bytes, storage_object_id=object_id,
} workspace_id=context.workspace.workspace_id,
owner_user_id=context.user.user_id,
object_type="file",
usage_type="working_copy",
storage_backend="rustfs",
bucket_name=bucket_name,
object_key=object_key,
object_key_hash=hashlib.sha256(object_key.encode("utf-8")).digest(),
storage_uri=f"s3://{bucket_name}/{object_key}",
file_name=name,
file_extension=PurePosixPath(jupyter_name).suffix.lower() or None,
mime_type=mime_type,
size_bytes=size_bytes,
content_hash=content_hash,
visibility=visibility,
is_immutable=0,
object_status="available",
created_by=context.user.user_id,
relative_path=relative_path,
path_hash=hashlib.sha256(relative_path.encode("utf-8")).digest(),
)
script = Scripts( script = Scripts(
script_id=script_id, script_id=script_id,
workspace_id=context.workspace.workspace_id, workspace_id=context.workspace.workspace_id,
@@ -379,10 +401,12 @@ async def create_script_record(
visibility=visibility, visibility=visibility,
status="active", status="active",
) )
session.add(storage_object)
session.add(script) session.add(script)
await session.flush() await session.flush()
await session.refresh(storage_object)
await session.refresh(script) await session.refresh(script)
return script, storage_data return script, storage_object
@router.post("/api/v1/scripts", status_code=status.HTTP_201_CREATED) @router.post("/api/v1/scripts", status_code=status.HTTP_201_CREATED)
-1
View File
@@ -222,7 +222,6 @@ export function useApi(): WorkspaceBoundApi {
rawApi.createJupyterAccessTicket(workspaceId, session), rawApi.createJupyterAccessTicket(workspaceId, session),
getLatestScriptVersion: (scriptId) => getLatestScriptVersion: (scriptId) =>
rawApi.getLatestScriptVersion(workspaceId, scriptId), rawApi.getLatestScriptVersion(workspaceId, scriptId),
listScriptVersions: (scriptId) => rawApi.listScriptVersions(workspaceId, scriptId),
publishScriptVersion: (input) => rawApi.publishScriptVersion(workspaceId, input), publishScriptVersion: (input) => rawApi.publishScriptVersion(workspaceId, input),
listSchedules: () => rawApi.listSchedules(workspaceId), listSchedules: () => rawApi.listSchedules(workspaceId),
getSchedule: (scheduleId) => rawApi.getSchedule(workspaceId, scheduleId), getSchedule: (scheduleId) => rawApi.getSchedule(workspaceId, scheduleId),
@@ -162,8 +162,6 @@ function AuthenticatedModelPlatformApp() {
scriptId: string; scriptId: string;
message: string; message: string;
} | null>(null); } | null>(null);
const [versions, setVersions] = useState<StableVersion[]>([]);
const [versionsLoading, setVersionsLoading] = useState(false);
const [latestVersion, setLatestVersion] = useState<LatestVersion | null>( const [latestVersion, setLatestVersion] = useState<LatestVersion | null>(
null, null,
); );
@@ -248,12 +246,10 @@ function AuthenticatedModelPlatformApp() {
useEffect(() => { useEffect(() => {
if (!selectedId) { if (!selectedId) {
setVersions([]);
setLatestVersion(null); setLatestVersion(null);
return; return;
} }
let ignore = false; let ignore = false;
setVersionsLoading(true);
setLatestVersionLoading(true); setLatestVersionLoading(true);
void api.getLatestScriptVersion(selectedId) void api.getLatestScriptVersion(selectedId)
.then((item) => { .then((item) => {
@@ -273,21 +269,6 @@ function AuthenticatedModelPlatformApp() {
.finally(() => { .finally(() => {
if (!ignore) setLatestVersionLoading(false); if (!ignore) setLatestVersionLoading(false);
}); });
void api.listScriptVersions(selectedId)
.then((items) => {
if (!ignore) setVersions(items);
})
.catch((error) => {
if (!ignore) {
setToast({
tone: "error",
message: error instanceof Error ? error.message : "版本列表加载失败",
});
}
})
.finally(() => {
if (!ignore) setVersionsLoading(false);
});
return () => { return () => {
ignore = true; ignore = true;
}; };
@@ -595,10 +576,6 @@ function AuthenticatedModelPlatformApp() {
releaseNote, releaseNote,
visibility: publishVisibility, visibility: publishVisibility,
}); });
setVersions((items) => [
version,
...items.filter((item) => item.versions_id !== version.versions_id),
]);
setPublishTarget(null); setPublishTarget(null);
setPublishedVersion(version); setPublishedVersion(version);
setToast({ setToast({
-12
View File
@@ -574,17 +574,6 @@ export async function getLatestScriptVersion(
); );
} }
export async function listScriptVersions(
workspaceId: string,
scriptId: string,
): Promise<StableVersion[]> {
return apiRequest<StableVersion[]>(
`/api/v1/scripts/${scriptId}/versions`,
{},
workspaceId,
);
}
export async function publishScriptVersion( export async function publishScriptVersion(
workspaceId: string, workspaceId: string,
input: { input: {
@@ -1119,7 +1108,6 @@ export type WorkspaceBoundApi = {
session: ActiveEditSession, session: ActiveEditSession,
) => Promise<JupyterAccessTicket>; ) => Promise<JupyterAccessTicket>;
getLatestScriptVersion: (scriptId: string) => Promise<LatestVersion | null>; getLatestScriptVersion: (scriptId: string) => Promise<LatestVersion | null>;
listScriptVersions: (scriptId: string) => Promise<StableVersion[]>;
publishScriptVersion: ( publishScriptVersion: (
input: Parameters<typeof publishScriptVersion>[1], input: Parameters<typeof publishScriptVersion>[1],
) => Promise<StableVersion>; ) => Promise<StableVersion>;