feat: unify workspace creation component with branch dropdown

- Rewrite WorkspaceCreateForm as unified component used in both pages
- Standalone mode (WorkspacesPage): shows project/repo/branch selectors
- Contextual mode (ProjectsPage): accepts defaultProjectId/defaultRepoId,
  skips project/repo selectors, shows only name + branch dropdown
- Branch dropdown fetched from repo via listRepositoryBranches API
- Auto-selects first/only option for project, repo, and branch
- '+ Create new branch...' option reveals text input for custom branch
- Falls back to free-text branch input if branch API fails
- Removes duplicated inline creation logic from WorkspacesPage
- TypeScript + eslint clean
This commit is contained in:
2026-06-01 18:18:00 +02:00
parent b8fc4e6642
commit e956d7c30d
3 changed files with 281 additions and 359 deletions
+10 -28
View File
@@ -11,7 +11,6 @@ import {
type ProjectUpdateInput,
} from "../api/projects";
import {
createWorkspace,
deleteWorkspace,
syncWorkspace,
} from "../api/workspaces";
@@ -112,22 +111,7 @@ export const ProjectsPage = () => {
}
};
const handleCreateWorkspace = async (
projectId: string,
repoId: string,
data: { name: string; branch: string },
) => {
setWorkspaceLoading(repoId);
try {
await createWorkspace(projectId, repoId, data);
setCreatingWorkspace(null);
reload();
} catch (err) {
alert(err instanceof Error ? err.message : "Failed to create workspace");
} finally {
setWorkspaceLoading(null);
}
};
const handleSyncWorkspace = async (
projectId: string,
@@ -218,9 +202,10 @@ export const ProjectsPage = () => {
: null
}
onCancelCreate={() => setCreatingWorkspace(null)}
onSubmitCreate={async (repoId, data) =>
await handleCreateWorkspace(project.id, repoId, data)
}
onCreated={() => {
setCreatingWorkspace(null);
reload();
}}
/>
))}
</div>
@@ -299,7 +284,7 @@ function ProjectCard({
workspaceLoading,
showCreateForm,
onCancelCreate,
onSubmitCreate,
onCreated,
}: {
project: ProjectWithRepos;
expanded: boolean;
@@ -318,10 +303,7 @@ function ProjectCard({
workspaceLoading: string | null;
onCancelCreate: () => void;
showCreateForm: string | null;
onSubmitCreate: (
repoId: string,
data: { name: string; branch: string },
) => Promise<void>;
onCreated: () => void;
}) {
return (
<article className="card project-card">
@@ -399,9 +381,9 @@ function ProjectCard({
</div>
{showCreateForm === repo.id && (
<WorkspaceCreateForm
projectId={project.id}
repoId={repo.id}
onSubmit={(data) => onSubmitCreate(repo.id, data)}
defaultProjectId={project.id}
defaultRepoId={repo.id}
onSubmit={onCreated}
onCancel={onCancelCreate}
/>
)}