refactor: unify StartToolModal — remove inline duplicate from workspace detail

- Delete inline hardcoded StartToolModal from workspace-detail.tsx
- Import shared StartToolModal that fetches real tool types from API
- Pass workspace object to ToolsTab so shared modal gets proper context
- onStart handler passes optional configProfileId through to useWorkspaceInstances.create()

Quality gates: tsc --noEmit clean
This commit is contained in:
2026-06-01 20:45:19 +02:00
parent 06a4a27880
commit 398436ecb5
2 changed files with 10 additions and 68 deletions
+9 -65
View File
@@ -8,7 +8,9 @@ import { useWorkspaceFiles } from "../hooks/use-workspace-files";
import { useWorkspaceGit } from "../hooks/use-workspace-git";
import { useWorkspaceInstances } from "../hooks/use-workspace-instances";
import { useMobileViewport } from "../hooks/use-mobile-viewport";
import { StartToolModal } from "../components/start-tool-modal";
import type { FileEntry } from "../api/workspace-files";
import type { Workspace } from "../types/workspace";
type Tab = "files" | "git" | "tools" | "settings";
@@ -40,7 +42,7 @@ export function WorkspaceDetailPage() {
<div className="workspace-content">
{activeTab === "files" && <FilesTab workspaceId={workspace.id} />}
{activeTab === "git" && <GitTab workspaceId={workspace.id} />}
{activeTab === "tools" && <ToolsTab workspaceId={workspace.id} />}
{activeTab === "tools" && <ToolsTab workspace={workspace} />}
{activeTab === "settings" && <SettingsTab workspace={workspace} />}
</div>
{isMobile && <MobileTabBar active={activeTab} onChange={setActiveTab} />}
@@ -309,8 +311,8 @@ function GitTab({ workspaceId }: { workspaceId: string }) {
/* ─── Tools Tab ─── */
function ToolsTab({ workspaceId }: { workspaceId: string }) {
const { instances, loading, create } = useWorkspaceInstances(workspaceId);
function ToolsTab({ workspace }: { workspace: Workspace }) {
const { instances, loading, create } = useWorkspaceInstances(workspace.id);
const [showModal, setShowModal] = useState(false);
return (
@@ -360,9 +362,10 @@ function ToolsTab({ workspaceId }: { workspaceId: string }) {
)}
{showModal && (
<StartToolModal
workspace={workspace}
onClose={() => setShowModal(false)}
onStart={async (toolTypeId: string) => {
await create(toolTypeId);
onStart={async (toolTypeId, configProfileId) => {
await create(toolTypeId, undefined, configProfileId);
setShowModal(false);
}}
/>
@@ -376,14 +379,7 @@ function ToolsTab({ workspaceId }: { workspaceId: string }) {
function SettingsTab({
workspace,
}: {
workspace: {
id: string;
name: string;
branch: string;
path: string;
status: string;
created_at: string;
};
workspace: Workspace;
}) {
return (
<div className="settings-tab">
@@ -416,56 +412,4 @@ function SettingsTab({
);
}
/* ─── Start Tool Modal ─── */
function StartToolModal({
onClose,
onStart,
}: {
onClose: () => void;
onStart: (toolTypeId: string) => Promise<void>;
}) {
const [toolTypeId, setToolTypeId] = useState("");
const [submitting, setSubmitting] = useState(false);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!toolTypeId) return;
setSubmitting(true);
try {
await onStart(toolTypeId);
} finally {
setSubmitting(false);
}
};
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
<h3>Start Tool</h3>
<form onSubmit={handleSubmit}>
<div className="form-group">
<label>Tool Type</label>
<select
value={toolTypeId}
onChange={(e) => setToolTypeId(e.target.value)}
>
<option value="">Select...</option>
<option value="code-server">Code Server</option>
<option value="jupyter-notebook">Jupyter Notebook</option>
<option value="terminal">Terminal</option>
</select>
</div>
<div className="form-actions">
<button type="button" onClick={onClose} disabled={submitting}>
Cancel
</button>
<button type="submit" disabled={!toolTypeId || submitting}>
{submitting ? "Starting..." : "Start"}
</button>
</div>
</form>
</div>
</div>
);
}