Show error when remote branch status is unavailable (Vibe Kanban) (#1825)
* I've completed the implementation. Here's a summary of the changes:
## Summary
### Changes Made
1. **`frontend/src/hooks/useBranchStatus.ts`**
- Modified to return `{ data, error, isError, isLoading, refetch }` instead of just the query result
- This exposes the error state to consuming components
2. **`frontend/src/components/tasks/Toolbar/GitOperations.tsx`**
- Added `branchStatusError` prop to interface
- Removed `hasConflictsCalculated` from the "Change target branch" button's disabled condition - now it stays enabled even during errors, allowing users to recover
- Changed the actions section from hiding completely when `selectedRepoStatus` is null to showing an error message when there's a `branchStatusError`
3. **`frontend/src/components/dialogs/tasks/GitActionsDialog.tsx`**
- Extracted `error` from `useBranchStatus` and passes it to `GitOperations` as `branchStatusError`
4. **`frontend/src/pages/ProjectTasks.tsx`**
- Updated `DiffsPanelContainer` to accept and pass `branchStatusError`
- Extracted `branchStatusError` from `useBranchStatus` hook
- Passes the error through to `DiffsPanelContainer`
5. **i18n translation files** (all 6 locales: en, es, ja, ko, zh-Hans, zh-Hant)
- Added `git.errors.branchStatusUnavailable` translation string
### Behavior Changes
- **Before**: When branch status API failed, git operations (Merge, PR/Push, Rebase buttons) were completely hidden
- **After**:
- An error message is shown: "Unable to fetch branch status. You can still change the target branch."
- The "Change target branch" button remains enabled, allowing users to recover from deadlock situations
- Users can see something went wrong instead of the UI silently failing
* Cleanup script changes for workspace cdcbb9c6-fc9f-45bf-9c30-0e432d06cccf
* Simplify useBranchStatus hook return
Return useQuery result directly instead of manually constructing an object.
The useQuery hook already returns all needed properties (data, error, isError, isLoading, refetch).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Restore hasConflictsCalculated check for change target branch button
The conflict check wasn't needed for the branch status error fix.
Keeping it prevents changing target branch during active git conflicts.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -35,7 +35,9 @@ function GitActionsDialogContent({
|
||||
task,
|
||||
}: GitActionsDialogContentProps) {
|
||||
const { t } = useTranslation('tasks');
|
||||
const { data: branchStatus } = useBranchStatus(attempt.id);
|
||||
const { data: branchStatus, error: branchStatusError } = useBranchStatus(
|
||||
attempt.id
|
||||
);
|
||||
const { isAttemptRunning } = useAttemptExecution(attempt.id);
|
||||
const { error: gitError } = useGitOperationsError();
|
||||
const { repos, selectedRepoId } = useAttemptRepo(attempt.id);
|
||||
@@ -83,6 +85,7 @@ function GitActionsDialogContent({
|
||||
selectedAttempt={attempt}
|
||||
task={task}
|
||||
branchStatus={branchStatus ?? null}
|
||||
branchStatusError={branchStatusError}
|
||||
isAttemptRunning={isAttemptRunning}
|
||||
selectedBranch={getSelectedRepoStatus()?.target_branch_name ?? null}
|
||||
layout="vertical"
|
||||
|
||||
@@ -35,6 +35,7 @@ interface GitOperationsProps {
|
||||
selectedAttempt: Workspace;
|
||||
task: TaskWithAttemptStatus;
|
||||
branchStatus: RepoBranchStatus[] | null;
|
||||
branchStatusError?: Error | null;
|
||||
isAttemptRunning: boolean;
|
||||
selectedBranch: string | null;
|
||||
layout?: 'horizontal' | 'vertical';
|
||||
@@ -46,6 +47,7 @@ function GitOperations({
|
||||
selectedAttempt,
|
||||
task,
|
||||
branchStatus,
|
||||
branchStatusError,
|
||||
isAttemptRunning,
|
||||
selectedBranch,
|
||||
layout = 'horizontal',
|
||||
@@ -463,7 +465,12 @@ function GitOperations({
|
||||
)}
|
||||
|
||||
{/* Right: Actions */}
|
||||
{selectedRepoStatus && (
|
||||
{branchStatusError && !selectedRepoStatus ? (
|
||||
<div className="flex items-center gap-2 text-xs text-destructive">
|
||||
<AlertTriangle className="h-3.5 w-3.5" />
|
||||
<span>{t('git.errors.branchStatusUnavailable')}</span>
|
||||
</div>
|
||||
) : selectedRepoStatus ? (
|
||||
<div className={actionsClasses}>
|
||||
<Button
|
||||
onClick={handleMergeClick}
|
||||
@@ -523,7 +530,7 @@ function GitOperations({
|
||||
<span className="truncate max-w-[10ch]">{rebaseButtonLabel}</span>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -257,7 +257,8 @@
|
||||
"changeTargetBranch": "Failed to change target branch",
|
||||
"pushChanges": "Failed to push changes",
|
||||
"mergeChanges": "Failed to merge changes",
|
||||
"rebaseBranch": "Failed to rebase branch"
|
||||
"rebaseBranch": "Failed to rebase branch",
|
||||
"branchStatusUnavailable": "Unable to fetch branch status. You can still change the target branch."
|
||||
},
|
||||
"pr": {
|
||||
"open": "Open PR #{{number}}",
|
||||
|
||||
@@ -235,7 +235,8 @@
|
||||
"changeTargetBranch": "Error al cambiar rama de destino",
|
||||
"mergeChanges": "Error al fusionar cambios",
|
||||
"pushChanges": "Error al enviar cambios",
|
||||
"rebaseBranch": "Error al hacer rebase de la rama"
|
||||
"rebaseBranch": "Error al hacer rebase de la rama",
|
||||
"branchStatusUnavailable": "No se puede obtener el estado de la rama. Aún puedes cambiar la rama de destino."
|
||||
},
|
||||
"labels": {
|
||||
"taskBranch": "Rama de tarea"
|
||||
|
||||
@@ -235,7 +235,8 @@
|
||||
"changeTargetBranch": "ターゲットブランチの変更に失敗しました",
|
||||
"mergeChanges": "変更のマージに失敗しました",
|
||||
"pushChanges": "変更のプッシュに失敗しました",
|
||||
"rebaseBranch": "ブランチのリベースに失敗しました"
|
||||
"rebaseBranch": "ブランチのリベースに失敗しました",
|
||||
"branchStatusUnavailable": "ブランチのステータスを取得できません。ターゲットブランチの変更は引き続き可能です。"
|
||||
},
|
||||
"labels": {
|
||||
"taskBranch": "タスクブランチ"
|
||||
|
||||
@@ -235,7 +235,8 @@
|
||||
"changeTargetBranch": "대상 브랜치를 변경하지 못했습니다",
|
||||
"mergeChanges": "변경사항을 병합하지 못했습니다",
|
||||
"pushChanges": "변경사항을 푸시하지 못했습니다",
|
||||
"rebaseBranch": "브랜치를 리베이스하지 못했습니다"
|
||||
"rebaseBranch": "브랜치를 리베이스하지 못했습니다",
|
||||
"branchStatusUnavailable": "브랜치 상태를 가져올 수 없습니다. 대상 브랜치는 여전히 변경할 수 있습니다."
|
||||
},
|
||||
"labels": {
|
||||
"taskBranch": "작업 브랜치"
|
||||
|
||||
@@ -270,7 +270,8 @@
|
||||
"changeTargetBranch": "更改目标分支失败",
|
||||
"pushChanges": "推送更改失败",
|
||||
"mergeChanges": "合并更改失败",
|
||||
"rebaseBranch": "变基分支失败"
|
||||
"rebaseBranch": "变基分支失败",
|
||||
"branchStatusUnavailable": "无法获取分支状态。您仍然可以更改目标分支。"
|
||||
},
|
||||
"pr": {
|
||||
"open": "打开 PR #{{number}}",
|
||||
|
||||
@@ -270,7 +270,8 @@
|
||||
"changeTargetBranch": "變更目標分支失敗",
|
||||
"pushChanges": "推送變更失敗",
|
||||
"mergeChanges": "合併變更失敗",
|
||||
"rebaseBranch": "重基底分支失敗"
|
||||
"rebaseBranch": "重基底分支失敗",
|
||||
"branchStatusUnavailable": "無法取得分支狀態。您仍然可以變更目標分支。"
|
||||
},
|
||||
"pr": {
|
||||
"open": "開啟 PR #{{number}}",
|
||||
|
||||
@@ -102,10 +102,12 @@ function DiffsPanelContainer({
|
||||
attempt,
|
||||
selectedTask,
|
||||
branchStatus,
|
||||
branchStatusError,
|
||||
}: {
|
||||
attempt: Workspace | null;
|
||||
selectedTask: TaskWithAttemptStatus | null;
|
||||
branchStatus: RepoBranchStatus[] | null;
|
||||
branchStatusError?: Error | null;
|
||||
}) {
|
||||
const { isAttemptRunning } = useAttemptExecution(attempt?.id);
|
||||
|
||||
@@ -118,6 +120,7 @@ function DiffsPanelContainer({
|
||||
? {
|
||||
task: selectedTask,
|
||||
branchStatus: branchStatus ?? null,
|
||||
branchStatusError,
|
||||
isAttemptRunning,
|
||||
selectedBranch: branchStatus?.[0]?.target_branch_name ?? null,
|
||||
}
|
||||
@@ -284,7 +287,9 @@ export function ProjectTasks() {
|
||||
const isTaskView = !!taskId && !effectiveAttemptId;
|
||||
const { data: attempt } = useTaskAttemptWithSession(effectiveAttemptId);
|
||||
|
||||
const { data: branchStatus } = useBranchStatus(attempt?.id);
|
||||
const { data: branchStatus, error: branchStatusError } = useBranchStatus(
|
||||
attempt?.id
|
||||
);
|
||||
|
||||
const rawMode = searchParams.get('view') as LayoutMode;
|
||||
const mode: LayoutMode =
|
||||
@@ -1000,6 +1005,7 @@ export function ProjectTasks() {
|
||||
attempt={attempt}
|
||||
selectedTask={selectedTask}
|
||||
branchStatus={branchStatus ?? null}
|
||||
branchStatusError={branchStatusError}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user