59b125d8e2
- Add all_workspaces_router with GET /workspaces/ (no project/repo required) - Include project_id in workspace responses - Frontend: useWorkspaces() calls listAllWorkspaces when no args - Frontend: WorkspacesPage uses top-level list, derives project/repo from workspace for mutations - Fixes 422 from invalid UUID path params
46 lines
1.1 KiB
TypeScript
46 lines
1.1 KiB
TypeScript
/** Hook for fetching workspaces. */
|
|
|
|
import { useCallback, useEffect, useState } from "react";
|
|
import { listAllWorkspaces, listWorkspaces } from "../api/workspaces";
|
|
import type { Workspace } from "../types/workspace";
|
|
|
|
export interface UseWorkspacesResult {
|
|
workspaces: Workspace[];
|
|
loading: boolean;
|
|
error: string | null;
|
|
refresh: () => Promise<void>;
|
|
}
|
|
|
|
export function useWorkspaces(
|
|
projectId?: string,
|
|
repoId?: string,
|
|
): UseWorkspacesResult {
|
|
const [workspaces, setWorkspaces] = useState<Workspace[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const refresh = useCallback(async () => {
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
const data =
|
|
projectId && repoId
|
|
? await listWorkspaces(projectId, repoId)
|
|
: await listAllWorkspaces();
|
|
setWorkspaces(data);
|
|
} catch (err) {
|
|
setError(
|
|
err instanceof Error ? err.message : "Failed to load workspaces",
|
|
);
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
}, [projectId, repoId]);
|
|
|
|
useEffect(() => {
|
|
refresh();
|
|
}, [refresh]);
|
|
|
|
return { workspaces, loading, error, refresh };
|
|
}
|