feat: new ToolStarter component — unified workspace-first tool starting

- New ToolStarter component: workspace context, fetches real tool types,
  auto-fetches config profiles per tool type, shows SSH key status
- Backend: add repo_ssh_key_id to workspace list responses
- WorkspacesPage: uses ToolStarter in modal instead of StartToolModal
- WorkspaceDetailPage ToolsTab: uses ToolStarter in modal
- Removed old inline StartToolModal from workspace-detail.tsx
- Styles: .tool-starter-context, .context-row, .ssh-key-status

Quality gates: ruff clean, tsc --noEmit clean, pytest workspaces API (9 passed, 1 skipped)
This commit is contained in:
2026-06-01 21:27:21 +02:00
parent ff8aa2a4f5
commit c1445976d7
6 changed files with 351 additions and 50 deletions
+4 -1
View File
@@ -38,6 +38,7 @@ async def list_all_workspaces(
Workspace,
GitRepository.name.label("repo_name"),
GitRepository.project_id,
GitRepository.ssh_key_id.label("repo_ssh_key_id"),
instance_count.label("instance_count"),
)
.join(GitRepository, Workspace.repo_id == GitRepository.id)
@@ -52,6 +53,7 @@ async def list_all_workspaces(
"name": ws.name,
"repo_id": str(ws.repo_id),
"repo_name": repo_name or "",
"repo_ssh_key_id": str(ssh_key_id) if ssh_key_id else None,
"project_id": str(project_id) if project_id else "",
"project_name": "",
"user_id": str(ws.user_id),
@@ -63,7 +65,7 @@ async def list_all_workspaces(
"updated_at": ws.updated_at.isoformat() if ws.updated_at else None,
"instance_count": count or 0,
}
for ws, repo_name, project_id, count in rows
for ws, repo_name, project_id, ssh_key_id, count in rows
]
@@ -190,6 +192,7 @@ async def list_workspaces(
"name": ws.name,
"repo_id": str(ws.repo_id),
"repo_name": repo.name,
"repo_ssh_key_id": str(repo.ssh_key_id) if repo.ssh_key_id else None,
"project_id": str(repo.project_id) if repo.project_id else "",
"project_name": repo.project.name if repo.project else "",
"user_id": str(ws.user_id),