feat: workspace-first UI refresh - PR-2 workspace detail page
- Add workspace detail page (/workspaces/:id) with 4 tabs: - Files: file tree, viewer, editor, git toolbar (commit/push/pull/fetch) - Git: branch selector, commit history - Tools: instance grid, start tool modal - Settings: workspace info read-only - Add workspace API clients: workspace-files, workspace-git, workspace-instances - Add hooks: useWorkspaceFiles, useWorkspaceGit, useWorkspaceInstances - WorkspaceCard links to detail page via router Link - Add comprehensive CSS for workspace detail layout - Mobile: bottom tab bar, responsive file tree/split - TypeScript + eslint clean Quality gates: tsc --noEmit clean, eslint clean
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
/** Hook for workspace instance operations. */
|
||||
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import {
|
||||
listWorkspaceInstances,
|
||||
createWorkspaceInstance,
|
||||
} from "../api/workspace-instances";
|
||||
import type { ToolInstance } from "../api/sessions";
|
||||
|
||||
export interface UseWorkspaceInstancesResult {
|
||||
instances: ToolInstance[];
|
||||
loading: boolean;
|
||||
error: string | null;
|
||||
refresh: () => Promise<void>;
|
||||
create: (
|
||||
toolTypeId: string,
|
||||
displayName?: string,
|
||||
configProfileId?: string,
|
||||
) => Promise<ToolInstance>;
|
||||
}
|
||||
|
||||
export function useWorkspaceInstances(
|
||||
workspaceId: string,
|
||||
): UseWorkspaceInstancesResult {
|
||||
const [instances, setInstances] = useState<ToolInstance[]>([]);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const data = await listWorkspaceInstances(workspaceId);
|
||||
setInstances(data);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : "Failed to load instances");
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [workspaceId]);
|
||||
|
||||
const create = useCallback(
|
||||
async (
|
||||
toolTypeId: string,
|
||||
displayName?: string,
|
||||
configProfileId?: string,
|
||||
) => {
|
||||
const instance = await createWorkspaceInstance(
|
||||
workspaceId,
|
||||
toolTypeId,
|
||||
displayName,
|
||||
configProfileId,
|
||||
);
|
||||
await refresh();
|
||||
return instance;
|
||||
},
|
||||
[workspaceId, refresh],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
refresh();
|
||||
}, [refresh]);
|
||||
|
||||
return { instances, loading, error, refresh, create };
|
||||
}
|
||||
Reference in New Issue
Block a user