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,45 @@
|
||||
/** Workspace file API client. */
|
||||
|
||||
import { apiClient } from "./client";
|
||||
|
||||
export interface FileEntry {
|
||||
name: string;
|
||||
path: string;
|
||||
type: "file" | "directory";
|
||||
size?: number;
|
||||
}
|
||||
|
||||
export async function listWorkspaceFiles(
|
||||
workspaceId: string,
|
||||
path: string = "",
|
||||
): Promise<FileEntry[]> {
|
||||
const response = await apiClient.get<{ entries: FileEntry[] }>(
|
||||
`/workspaces/${workspaceId}/files/`,
|
||||
{ params: { path } },
|
||||
);
|
||||
return response.data.entries;
|
||||
}
|
||||
|
||||
export async function getWorkspaceFileContent(
|
||||
workspaceId: string,
|
||||
path: string,
|
||||
): Promise<string> {
|
||||
const response = await apiClient.get<{ content: string }>(
|
||||
`/workspaces/${workspaceId}/files/content`,
|
||||
{ params: { path } },
|
||||
);
|
||||
return response.data.content;
|
||||
}
|
||||
|
||||
export async function saveWorkspaceFile(
|
||||
workspaceId: string,
|
||||
path: string,
|
||||
content: string,
|
||||
commitMessage?: string,
|
||||
): Promise<void> {
|
||||
await apiClient.post(`/workspaces/${workspaceId}/files/content`, {
|
||||
path,
|
||||
content,
|
||||
message: commitMessage,
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/** Workspace git API client. */
|
||||
|
||||
import { apiClient } from "./client";
|
||||
|
||||
export interface GitStatus {
|
||||
branch: string;
|
||||
modified: string[];
|
||||
added: string[];
|
||||
deleted: string[];
|
||||
untracked: string[];
|
||||
ahead: number;
|
||||
behind: number;
|
||||
}
|
||||
|
||||
export interface Commit {
|
||||
hash: string;
|
||||
message: string;
|
||||
author: string;
|
||||
date: string;
|
||||
}
|
||||
|
||||
export async function getGitStatus(workspaceId: string): Promise<GitStatus> {
|
||||
const response = await apiClient.get<GitStatus>(
|
||||
`/workspaces/${workspaceId}/git/status`,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function getGitBranches(
|
||||
workspaceId: string,
|
||||
): Promise<{ branches: string[]; current_branch: string }> {
|
||||
const response = await apiClient.get<{
|
||||
branches: string[];
|
||||
current_branch: string;
|
||||
}>(`/workspaces/${workspaceId}/git/branches`);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function gitCommit(
|
||||
workspaceId: string,
|
||||
message: string,
|
||||
): Promise<void> {
|
||||
await apiClient.post(`/workspaces/${workspaceId}/git/commit`, { message });
|
||||
}
|
||||
|
||||
export async function gitPush(workspaceId: string): Promise<void> {
|
||||
await apiClient.post(`/workspaces/${workspaceId}/git/push`);
|
||||
}
|
||||
|
||||
export async function gitPull(workspaceId: string): Promise<void> {
|
||||
await apiClient.post(`/workspaces/${workspaceId}/git/pull`);
|
||||
}
|
||||
|
||||
export async function gitFetch(workspaceId: string): Promise<void> {
|
||||
await apiClient.post(`/workspaces/${workspaceId}/git/fetch`);
|
||||
}
|
||||
|
||||
export async function gitCheckout(
|
||||
workspaceId: string,
|
||||
branch: string,
|
||||
): Promise<void> {
|
||||
await apiClient.post(`/workspaces/${workspaceId}/git/checkout`, { branch });
|
||||
}
|
||||
|
||||
export async function getGitHistory(
|
||||
workspaceId: string,
|
||||
path?: string,
|
||||
limit: number = 50,
|
||||
): Promise<Commit[]> {
|
||||
const response = await apiClient.get<{ commits: Commit[] }>(
|
||||
`/workspaces/${workspaceId}/git/history`,
|
||||
{ params: { path, limit } },
|
||||
);
|
||||
return response.data.commits;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/** Workspace instance API client. */
|
||||
|
||||
import { apiClient } from "./client";
|
||||
import type { ToolInstance } from "./sessions";
|
||||
|
||||
export async function listWorkspaceInstances(
|
||||
workspaceId: string,
|
||||
): Promise<ToolInstance[]> {
|
||||
const response = await apiClient.get<ToolInstance[]>(
|
||||
`/workspaces/${workspaceId}/instances/`,
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
|
||||
export async function createWorkspaceInstance(
|
||||
workspaceId: string,
|
||||
toolTypeId: string,
|
||||
displayName?: string,
|
||||
configProfileId?: string,
|
||||
): Promise<ToolInstance> {
|
||||
const response = await apiClient.post<ToolInstance>(
|
||||
`/workspaces/${workspaceId}/instances/`,
|
||||
{
|
||||
tool_type_id: toolTypeId,
|
||||
display_name: displayName,
|
||||
config_profile_id: configProfileId,
|
||||
},
|
||||
);
|
||||
return response.data;
|
||||
}
|
||||
Reference in New Issue
Block a user