feat: complete reorganize-long-files cleanup
- Extract tool instance lifecycle endpoints (start/stop/restart/delete) from api/tool/tool_instances.py into new api/tool/tool_lifecycle.py. - Register tool_lifecycle_router in main.py and api/tool/__init__.py. - Extract inline WorkspaceDetailPage components into components/features/workspace/: detail header, tab bars, file/git/tools/settings panels. Slim page from ~446 to ~62 lines. - Update OpenSpec reorganize-long-files tasks to reflect completed work and current source state; mark change completed. - Regenerate project maps. Quality gates: python3 -m py_compile (backend clean), npm run typecheck, npm run lint, npm test -- --run (87 passed), pytest workspace integration and unit tests (27 passed, 1 skipped).
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
/** 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="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="modal-overlay" onClick={() => setShowModal(false)}>
|
||||
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
|
||||
<h3>Start Tool</h3>
|
||||
<ToolStarter
|
||||
workspace={workspace}
|
||||
onStarted={() => {
|
||||
setShowModal(false);
|
||||
void refresh();
|
||||
}}
|
||||
onCancel={() => setShowModal(false)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user