415aecc0dd
- 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
86 lines
2.2 KiB
TypeScript
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>
|
|
);
|
|
}
|