Files
headquarter/apps/web/src/components/features/workspace/workspace-tools-panel.tsx
T
Developer 415aecc0dd fix: constrain dialog content to the viewport
- Add dynamic viewport bounds and scrollable body regions to dialogs and modals\n- Make tool-launch popups use the shared scrollable body pattern\n- Keep mobile sheets, action sheets, and notification popups scroll-contained\n- Restore the ProjectsPage test setup required for the frontend suite\n\nOpenSpec: fix-dialog-scroll-containment\nQuality gates: npm run typecheck, npm run lint, npm test (88 passed), npm run build
2026-07-15 10:20:20 +00:00

86 lines
2.2 KiB
TypeScript

/** Tools tab for the workspace detail page. */
import { useState } from "react";
import { Icon } from "../../icon";
import { ToolStarter } from "../tool/tool-starter";
import { useWorkspaceInstances } from "../../../hooks/use-workspace-instances";
import type { Workspace } from "../../../types/workspace";
interface WorkspaceToolsPanelProps {
workspace: Workspace;
}
export function WorkspaceToolsPanel({ workspace }: WorkspaceToolsPanelProps) {
const { instances, loading, refresh } = useWorkspaceInstances(workspace.id);
const [showModal, setShowModal] = useState(false);
return (
<div className="tools-tab">
{loading && <p className="muted">Loading instances...</p>}
{instances.length === 0 ? (
<div className="card card-lg empty-state-card">
<Icon name="terminal" size="lg" />
<h3>No tools running</h3>
<p>Start a tool to begin coding in this workspace</p>
<button
className="btn btn-primary"
onClick={() => setShowModal(true)}
type="button"
>
Start Tool
</button>
</div>
) : (
<>
<div className="instances-grid">
{instances.map((instance) => (
<div
key={instance.id}
className={`instance-card ${instance.status}`}
>
<h4>{instance.display_name}</h4>
<span className="status-badge">{instance.status}</span>
{instance.url && (
<a
href={instance.url}
target={`instance-${instance.id}`}
rel="noreferrer"
>
Open
</a>
)}
</div>
))}
</div>
<button
className="btn btn-primary"
onClick={() => setShowModal(true)}
type="button"
>
Start Another Tool
</button>
</>
)}
{showModal && (
<div className="dialog-overlay" onClick={() => setShowModal(false)}>
<div className="dialog" onClick={(e) => e.stopPropagation()}>
<div className="dialog-header">
<h3>Start Tool</h3>
</div>
<div className="dialog-body">
<ToolStarter
workspace={workspace}
onStarted={() => {
setShowModal(false);
void refresh();
}}
onCancel={() => setShowModal(false)}
/>
</div>
</div>
</div>
)}
</div>
);
}