Files
headquarter/apps/web/src/pages/workspaces.tsx
T
alex 986091ac56 feat: workspace frontend core (PR-3)
- Workspace types, API client, hooks (useWorkspaces, useWorkspaceActions)
- WorkspaceCard, WorkspaceCreateForm, StartToolModal components
- WorkspacesPage with list, create, sync, delete, start-tool flow
- Sidebar navigation: new 'Workspaces' entry
- Router: /workspaces route
- TypeScript + eslint clean
2026-05-31 23:27:10 +02:00

103 lines
3.4 KiB
TypeScript

/** Workspaces list page. */
import { useState } from "react";
import { Icon } from "../components/icon";
import { useWorkspaces } from "../hooks/use-workspaces";
import { useWorkspaceActions } from "../hooks/use-workspace-actions";
import { WorkspaceCard } from "../components/workspace-card";
import { WorkspaceCreateForm } from "../components/workspace-create-form";
import { StartToolModal } from "../components/start-tool-modal";
import type { Workspace } from "../types/workspace";
export function WorkspacesPage() {
const [showCreate, setShowCreate] = useState(false);
const [startWorkspace, setStartWorkspace] = useState<Workspace | null>(null);
// TODO: Get projectId and repoId from URL params or context
const projectId = "default-project";
const repoId = "default-repo";
const { workspaces, loading, error, refresh } = useWorkspaces(projectId, repoId);
const actions = useWorkspaceActions();
const handleCreate = async (data: { name: string; branch: string }) => {
await actions.create(projectId, repoId, data);
setShowCreate(false);
await refresh();
};
const handleDelete = async (workspace: Workspace) => {
await actions.delete(projectId, repoId, workspace, refresh);
};
const handleSync = async (workspace: Workspace) => {
await actions.sync(projectId, repoId, workspace, refresh);
};
const handleStartTool = async (toolTypeId: string, configProfileId?: string) => {
if (!startWorkspace) return;
// TODO: Call instance creation API with workspace_id
console.log("Start tool", { toolTypeId, configProfileId, workspace: startWorkspace.id });
setStartWorkspace(null);
};
return (
<div className="page workspaces-page">
<header className="page-header">
<h1>Workspaces</h1>
<div className="header-actions">
<button className="btn btn-secondary" onClick={refresh} disabled={loading}>
<Icon name="refresh" size="sm" />
</button>
<button className="btn btn-primary" onClick={() => setShowCreate(true)}>
<Icon name="add" size="sm" /> New Workspace
</button>
</div>
</header>
{error && <div className="alert alert-error">{error}</div>}
{showCreate && (
<WorkspaceCreateForm
projectId={projectId}
repoId={repoId}
onSubmit={handleCreate}
onCancel={() => setShowCreate(false)}
/>
)}
{loading && workspaces.length === 0 ? (
<div className="loading-state">Loading workspaces...</div>
) : workspaces.length === 0 ? (
<div className="empty-state">
<p>No workspaces yet.</p>
<button className="btn btn-primary" onClick={() => setShowCreate(true)}>
<Icon name="add" size="sm" /> Create your first workspace
</button>
</div>
) : (
<div className="workspaces-grid">
{workspaces.map((ws) => (
<WorkspaceCard
key={ws.id}
workspace={ws}
loading={actions.loadingId === ws.id}
onStartTool={setStartWorkspace}
onSync={handleSync}
onDelete={handleDelete}
/>
))}
</div>
)}
{startWorkspace && (
<StartToolModal
workspace={startWorkspace}
onClose={() => setStartWorkspace(null)}
onStart={handleStartTool}
/>
)}
</div>
);
}