diff --git a/ui/src/components/IssueProperties.tsx b/ui/src/components/IssueProperties.tsx index d864b3ad..f6ddcfbe 100644 --- a/ui/src/components/IssueProperties.tsx +++ b/ui/src/components/IssueProperties.tsx @@ -26,8 +26,6 @@ const EXECUTION_WORKSPACE_OPTIONS = [ { value: "shared_workspace", label: "Project default" }, { value: "isolated_workspace", label: "New isolated workspace" }, { value: "reuse_existing", label: "Reuse existing workspace" }, - { value: "operator_branch", label: "Operator branch" }, - { value: "agent_default", label: "Agent default" }, ] as const; function defaultProjectWorkspaceIdForProject(project: { @@ -237,7 +235,19 @@ export function IssueProperties({ issue, onUpdate, inline }: IssuePropertiesProp }), enabled: Boolean(companyId) && Boolean(issue.projectId), }); - const selectedReusableExecutionWorkspace = (reusableExecutionWorkspaces ?? []).find( + const deduplicatedReusableWorkspaces = useMemo(() => { + const workspaces = reusableExecutionWorkspaces ?? []; + const seen = new Map(); + for (const ws of workspaces) { + const key = ws.cwd ?? ws.id; + const existing = seen.get(key); + if (!existing || new Date(ws.lastUsedAt) > new Date(existing.lastUsedAt)) { + seen.set(key, ws); + } + } + return Array.from(seen.values()); + }, [reusableExecutionWorkspaces]); + const selectedReusableExecutionWorkspace = deduplicatedReusableWorkspaces.find( (workspace) => workspace.id === issue.executionWorkspaceId, ); const projectLink = (id: string | null) => { @@ -630,7 +640,7 @@ export function IssueProperties({ issue, onUpdate, inline }: IssuePropertiesProp value={issue.executionWorkspaceId ?? ""} onChange={(e) => { const nextExecutionWorkspaceId = e.target.value || null; - const nextExecutionWorkspace = (reusableExecutionWorkspaces ?? []).find( + const nextExecutionWorkspace = deduplicatedReusableWorkspaces.find( (workspace) => workspace.id === nextExecutionWorkspaceId, ); onUpdate({ @@ -643,7 +653,7 @@ export function IssueProperties({ issue, onUpdate, inline }: IssuePropertiesProp }} > - {(reusableExecutionWorkspaces ?? []).map((workspace) => ( + {deduplicatedReusableWorkspaces.map((workspace) => ( diff --git a/ui/src/components/NewIssueDialog.tsx b/ui/src/components/NewIssueDialog.tsx index 9efb96fc..74e5bcf1 100644 --- a/ui/src/components/NewIssueDialog.tsx +++ b/ui/src/components/NewIssueDialog.tsx @@ -242,8 +242,6 @@ const EXECUTION_WORKSPACE_MODES = [ { value: "shared_workspace", label: "Project default" }, { value: "isolated_workspace", label: "New isolated workspace" }, { value: "reuse_existing", label: "Reuse existing workspace" }, - { value: "operator_branch", label: "Operator branch" }, - { value: "agent_default", label: "Agent default" }, ] as const; function defaultProjectWorkspaceIdForProject(project: { workspaces?: Array<{ id: string; isPrimary: boolean }>; executionWorkspacePolicy?: { defaultProjectWorkspaceId?: string | null } | null } | null | undefined) { @@ -638,7 +636,7 @@ export function NewIssueDialog() { }); const selectedProject = orderedProjects.find((project) => project.id === projectId); const executionWorkspacePolicy = selectedProject?.executionWorkspacePolicy ?? null; - const selectedReusableExecutionWorkspace = (reusableExecutionWorkspaces ?? []).find( + const selectedReusableExecutionWorkspace = deduplicatedReusableWorkspaces.find( (workspace) => workspace.id === selectedExecutionWorkspaceId, ); const requestedExecutionWorkspaceMode = @@ -747,7 +745,19 @@ export function NewIssueDialog() { const currentProject = orderedProjects.find((project) => project.id === projectId); const currentProjectExecutionWorkspacePolicy = currentProject?.executionWorkspacePolicy ?? null; const currentProjectSupportsExecutionWorkspace = Boolean(currentProjectExecutionWorkspacePolicy?.enabled); - const selectedReusableExecutionWorkspace = (reusableExecutionWorkspaces ?? []).find( + const deduplicatedReusableWorkspaces = useMemo(() => { + const workspaces = reusableExecutionWorkspaces ?? []; + const seen = new Map(); + for (const ws of workspaces) { + const key = ws.cwd ?? ws.id; + const existing = seen.get(key); + if (!existing || new Date(ws.lastUsedAt) > new Date(existing.lastUsedAt)) { + seen.set(key, ws); + } + } + return Array.from(seen.values()); + }, [reusableExecutionWorkspaces]); + const selectedReusableExecutionWorkspace = deduplicatedReusableWorkspaces.find( (workspace) => workspace.id === selectedExecutionWorkspaceId, ); const assigneeOptionsTitle = @@ -1126,7 +1136,7 @@ export function NewIssueDialog() { onChange={(e) => setSelectedExecutionWorkspaceId(e.target.value)} > - {(reusableExecutionWorkspaces ?? []).map((workspace) => ( + {deduplicatedReusableWorkspaces.map((workspace) => (