Conversation
) Click the branch name in a workspace hover card to open a modal that renames the local git branch via the host service. The GitHub external- link icon is split out as a separate affordance so the branch name itself is always the rename trigger. In the v2 dashboard sidebar, the rename also writes the new branch through the v2Workspaces optimistic action so the hover card reflects the new name immediately without waiting for a manual refresh.
* Update sidebar main workspace icons * Preserve remote sidebar workspace icons * Separate sidebar remove and close actions * Stop sidebar action key events bubbling
* Add shared overflow fade utilities * Simplify overflow-fade components and drop tab scrollbar Remove duplicate barrel shims, inline forwardRef via React 19 ref-as-prop, drop redundant layout effect and SSR guards in use-overflow-fade, and collapse the on-hover tab scrollbar back to hide-scrollbar. * Stabilize OverflowFadeContainer onOverflowChange firing Stash the callback in a ref so the effect only fires when measured overflow flags change, not on every consumer render with an unmemoized callback.
- Pin `bunx turbo@2.8.7` in the prune stage. Previously unpinned, so Docker fetched whatever was latest on npm (2.9.6) — that version produces a pruned bun.lock inconsistent with its own pruned package.jsons, causing `bun install --frozen-lockfile` to fail. Pinning to the project's turbo version eliminates the drift. - Drop dead `COPY patches patches` left over from superset-sh#3509 (durable-streams patch removal). The directory hasn't existed since March, so any redeploy from a clean cache failed at this line. - Bump VM memory from 2gb to 4gb. Fly's `cpu_kind = "performance"` now requires ≥4096 MiB; the existing machine was grandfathered but new deploys are rejected.
* feat(desktop): persistent v2 sidebar hover card Replace the per-row Radix HoverCard wrappers with a single sidebar-level Popover anchored via virtualRef to whichever workspace row is hovered. Moving between rows now slides the panel rather than unmounting and remounting, and the content updates in place. The slide is gated by a data-positioned flag so the initial open doesn't animate from Radix's off-screen measuring transform. - Introduces DashboardSidebarHoverProvider (open/close timers, anchor + payload state, context-menu suppression, live workspace sync via syncIfHovered). - Introduces DashboardSidebarHoverCardOverlay with the single Popover + PopoverAnchor and lifts useDiffStats(hoveredId) up so the row's per- item hook can stay focused on its own rendering. - Strips the HoverCard layer out of DashboardSidebarWorkspaceContextMenu and lets the context menu report its open state through the provider. - Cloud workspaces get hover cards too; only the PR-refresh callback remains gated to local-device hosts. * refactor(desktop): co-locate hover card transition CSS Move the popover-wrapper transition rule out of globals.css into a sibling CSS file imported by DashboardSidebarHoverCardOverlay so the style stays scoped to the component that needs it.
📝 Walkthroughウォークスルーホバーカードオーバーレイプロバイダーの導入、ブランチ名変更機能の実装、オーバーフローフェードコンポーネントの新規作成、パネルドラッグアンドドロップ機能の追加により、ダッシュボードサイドバーとワークスペースUIの相互作用を大幅に強化しました。CSS utility削除とDocker/Fly設定の軽微な更新も含まれます。 変更内容
シーケンス図sequenceDiagram
participant User as ユーザー
participant Dashboard as ダッシュボード<br/>サイドバー
participant Provider as ホバー<br/>プロバイダー
participant Overlay as ホバーカード<br/>オーバーレイ
participant Dialog as ブランチ<br/>編集ダイアログ
participant API as API
User->>Dashboard: ワークスペース項目にマウスオーバー
Dashboard->>Provider: requestOpen(id, element, payload)
Provider->>Provider: 遅延タイマースケジュール (200ms)
Provider->>Overlay: ホバー状態を更新
Overlay->>Overlay: アニメーション遅延 (2フレーム)
Overlay->>User: ホバーカード表示
User->>Overlay: ブランチ編集ボタンクリック
Overlay->>Dialog: onEditBranchClick(branchName)
Dialog->>User: ダイアログ表示
User->>Dialog: 新しいブランチ名入力 + 送信
Dialog->>API: git.renameBranch.mutate()
API->>API: ブランチ名変更実行
API-->>Dialog: 成功
Dialog->>Dialog: キャッシュ無効化<br/>(worktree/workspace)
Dialog->>User: ダイアログクローズ
Dashboard->>User: UI 更新表示
sequenceDiagram
participant User as ユーザー
participant TabBar as TabBar
participant DnD as ドラッグ<br/>アンドドロップ
participant Store as Zustand<br/>ストア
participant UI as UI更新
User->>DnD: パネルをタブストリップにドラッグ
DnD->>DnD: drop イベント検出
DnD->>DnD: ドロップ item 型判別
alt パネル型
DnD->>TabBar: onMovePaneToNewTab(paneId, toIndex)
TabBar->>Store: movePaneToNewTab({paneId, toIndex})
else タブ型
DnD->>Store: 既存タブ順序変更ロジック
end
Store->>Store: 新タブ作成、パネル移動
Store->>UI: state 更新
UI->>User: TabBar と Pane レイアウト再レンダリング
推定コードレビュー労力🎯 4 (複雑) | ⏱️ ~60 分 ポエム
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
🧹 Preview Cleanup CompleteThe following preview resources have been cleaned up:
Thank you for your contribution! 🎉 |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (10)
apps/desktop/src/renderer/lib/dev-chat.ts (1)
26-30: モデル定義の二重管理は将来的にドリフトしやすいです今回の追加自体は正しいですが、
apps/desktop/src/renderer/lib/dev-chat.tsとpackages/trpc/src/router/chat/chat.tsで同じモデル一覧を別管理しているため、将来の更新漏れリスクがあります。共有定数(またはサーバー定義を参照する仕組み)への集約を検討してください。🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/lib/dev-chat.ts` around lines 26 - 30, The model list defined inline in apps/desktop/src/renderer/lib/dev-chat.ts (e.g., the entry with id "openai/gpt-5.5") is duplicated in packages/trpc/src/router/chat/chat.ts; extract the canonical model list into a shared constant/module (for example a new exported array like SUPPORTED_MODELS in a shared package or utils module) and replace the inline arrays in both dev-chat.ts and chat.ts with imports from that single source, or alternatively expose the server-side list via the chat router and have dev-chat consume it; update imports and types so both files reference the same identifier (e.g., SUPPORTED_MODELS) to prevent future drift.apps/relay/fly.toml (1)
31-31: 変更内容を承認します。メモリ割り当てを4GBに増やす変更は、リレーのデプロイ問題に対処するための適切な調整です。
デプロイ後は、メモリ使用状況を監視して、この増加が問題を解決していることを確認することをお勧めします。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/relay/fly.toml` at line 31, Change is approved: the deployment memory setting was increased to memory = "4gb"; merge the change (keep the memory key set to "4gb") and deploy, then monitor runtime memory metrics and logs post-deploy to confirm the increase resolves the relay OOM/deployment issues and be prepared to adjust or roll back the memory value if abnormal behavior or cost concerns arise.apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceHoverCardContent/DashboardSidebarWorkspaceHoverCardContent.tsx (1)
71-79:cn()を使用したクラス名の一貫性向上を検討テンプレートリテラルでの条件付きクラス名構築は機能しますが、他の箇所と同様に
cn()ユーティリティを使用することで、より一貫性のあるスタイルになります。♻️ 提案する変更
<button type="button" onClick={() => onEditBranchClick(branch)} - className={`group/branch flex min-w-0 flex-1 items-center gap-1 font-mono break-all text-left hover:text-foreground hover:underline ${hasCustomAlias ? "text-xs" : "text-sm"}`} + className={cn( + "group/branch flex min-w-0 flex-1 items-center gap-1 font-mono break-all text-left hover:text-foreground hover:underline", + hasCustomAlias ? "text-xs" : "text-sm" + )} title="Rename branch" >🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceHoverCardContent/DashboardSidebarWorkspaceHoverCardContent.tsx` around lines 71 - 79, Replace the template-literal className on the button in DashboardSidebarWorkspaceHoverCardContent with the project's cn() utility to match other components; update the button element that calls onEditBranchClick(branch) to build classes via cn("group/branch flex min-w-0 flex-1 items-center gap-1 font-mono break-all text-left hover:text-foreground hover:underline", hasCustomAlias ? "text-xs" : "text-sm", "group-hover/branch:opacity-100 transition-opacity") so conditional classes are handled consistently with the rest of the codebase.apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/DashboardSidebarExpandedWorkspaceRow.tsx (1)
291-299: 「Spacebar」キー値について
event.key === "Spacebar"は古いIE/Edgeでの名前で、モダンブラウザでは" "が使用されます。現在のターゲットブラウザを考慮すると、"Spacebar"のチェックは不要かもしれませんが、後方互換性のために残すことも合理的です。♻️ モダンブラウザのみをターゲットにする場合の簡略化
onKeyDown={(event) => { if ( event.key === "Enter" || - event.key === " " || - event.key === "Spacebar" + event.key === " " ) { event.stopPropagation(); } }}Also applies to: 319-327
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/DashboardSidebarExpandedWorkspaceRow.tsx` around lines 291 - 299, In DashboardSidebarExpandedWorkspaceRow update the onKeyDown handler(s) to use the modern space key value: replace the legacy check event.key === "Spacebar" with the single-space string (" ") — or, if you want to keep backward compatibility, keep both checks but prefer the " " check first; locate the onKeyDown prop in the DashboardSidebarExpandedWorkspaceRow component (also adjust the other similar onKeyDown occurrence in the same component) and ensure the handler still calls event.stopPropagation() for Enter and Space.apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx (3)
100-103: useMemo の依存配列にsetRenameBranchTargetが含まれていない点について
setRenameBranchTargetはuseStateのセッター関数であり、React によって安定した参照が保証されているため、依存配列に含めなくても動作上は問題ありません。ただし、明示的に含めることでコードの意図がより明確になります。♻️ より明示的な依存配列
const hoverPayload = useMemo( () => ({ workspace, onEditBranchClick: setRenameBranchTarget }), - [workspace], + [workspace, setRenameBranchTarget], );🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx` around lines 100 - 103, The useMemo that computes hoverPayload currently lists only workspace in its dependency array; update the dependency array for the useMemo call that creates hoverPayload to also include the state setter setRenameBranchTarget so the intent is explicit (hoverPayload -> useMemo(() => ({ workspace, onEditBranchClick: setRenameBranchTarget }), [workspace, setRenameBranchTarget])) while keeping the same returned object shape referencing workspace and setRenameBranchTarget.
275-285: 冗長なopenプロップ条件(expanded view)expanded view でも同様のパターンがあります。collapsed view と同じ修正を適用できます。
♻️ 提案する修正
{renameBranchTarget && ( <RenameBranchDialog workspaceId={id} currentBranchName={renameBranchTarget} - open={renameBranchTarget !== null} + open onOpenChange={(open) => { if (!open) setRenameBranchTarget(null); }} onAfterRename={handleAfterBranchRename} /> )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx` around lines 275 - 285, 現在のコード renders <RenameBranchDialog> only when renameBranchTarget is truthy but also passes open={renameBranchTarget !== null}, which is redundant; change the usage to either always render the dialog and control visibility via the open prop (e.g., open={renameBranchTarget !== null}) or, simpler, keep conditional rendering and set open to true (or omit the open prop) so the dialog doesn't receive a duplicate condition; apply the same fix to the expanded view variant—update occurrences around RenameBranchDialog, renameBranchTarget, setRenameBranchTarget, and handleAfterBranchRename to remove the redundant open={renameBranchTarget !== null} check.
195-205: 冗長なopenプロップ条件(collapsed view)他のファイルと同様に、
renameBranchTarget &&ブロック内でのopen={renameBranchTarget !== null}は常にtrueとなります。♻️ 提案する修正
{renameBranchTarget && ( <RenameBranchDialog workspaceId={id} currentBranchName={renameBranchTarget} - open={renameBranchTarget !== null} + open onOpenChange={(open) => { if (!open) setRenameBranchTarget(null); }} onAfterRename={handleAfterBranchRename} /> )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx` around lines 195 - 205, The conditional render uses both "renameBranchTarget &&" and "open={renameBranchTarget !== null}", which is redundant because the component is only rendered when renameBranchTarget is truthy; simplify by removing the redundant runtime check in the prop: keep the conditional render "renameBranchTarget && <RenameBranchDialog ... />" and change the open prop to a constant true (e.g., open={true} or simply open) while keeping workspaceId={id}, currentBranchName={renameBranchTarget}, onOpenChange that calls setRenameBranchTarget(null), and onAfterRename={handleAfterBranchRename}.apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceContextMenu.tsx (1)
258-267: 冗長なopenプロップ条件
renameBranchTarget &&の条件ブロック内では、renameBranchTargetは常に truthy なので、open={renameBranchTarget !== null}は常にtrueとなります。シンプルにopen={true}またはopenプロップをrenameBranchTargetの条件で制御する方が明確です。♻️ 提案する修正
{renameBranchTarget && ( <RenameBranchDialog workspaceId={id} currentBranchName={renameBranchTarget} - open={renameBranchTarget !== null} + open onOpenChange={(open) => { if (!open) setRenameBranchTarget(null); }} /> )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceContextMenu.tsx` around lines 258 - 267, 現在のコードでは外側の条件レンダリングと open={renameBranchTarget !== null} が重複しているので、冗長さを解消してください:Remove the surrounding conditional render (the "renameBranchTarget && (...)" check) and instead render RenameBranchDialog unconditionally but control visibility via the open prop set to renameBranchTarget !== null; keep workspaceId={id}, currentBranchName={renameBranchTarget} and the onOpenChange handler as-is so closing clears renameBranchTarget. Use the RenameBranchDialog component and the renameBranchTarget/open/onOpenChange symbols to locate and update the code.apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/CollapsedWorkspaceItem.tsx (1)
184-193: 冗長なopenプロップ条件(WorkspaceContextMenu.tsx と同様)
renameBranchTarget &&ブロック内でのopen={renameBranchTarget !== null}は常にtrueになります。♻️ 提案する修正
{renameBranchTarget && ( <RenameBranchDialog workspaceId={id} currentBranchName={renameBranchTarget} - open={renameBranchTarget !== null} + open onOpenChange={(open) => { if (!open) setRenameBranchTarget(null); }} /> )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/CollapsedWorkspaceItem.tsx` around lines 184 - 193, 表示ブロックが既に renameBranchTarget && でガードされているため RenameBranchDialog の open に渡している open={renameBranchTarget !== null} は冗長です;RenameBranchDialog を表示するブロック内で open を常に true にする(例: open={true} または 単に open を渡す)か open プロップ自体を削除してコンポーネント側の表示制御に委ね、現在の onOpenChange={(open) => { if (!open) setRenameBranchTarget(null); }} は維持して renameBranchTarget と setRenameBranchTarget によるクローズ時のリセット挙動を保ってください。apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx (1)
27-27: 深い相対 import ではなく alias import に寄せてください。このファイルはすでに
renderer/...を使っているので、ここも同じ形にしておくと移動・分割時に壊れにくくなります。As per coding guidelines,apps/desktop/**/*.{ts,tsx}: Use aliases as defined in tsconfig.json when possible.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx` at line 27, The import in DashboardSidebarWorkspaceContextMenu.tsx uses a deep relative path; replace the relative import of useDashboardSidebarHover with the project alias path (use the existing renderer/... style used elsewhere in this file) so it reads the aliased module import instead of "../../../../providers/DashboardSidebarHoverProvider"; update the import statement that brings in useDashboardSidebarHover to use the tsconfig-defined alias to keep moves/splits safe and consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/RenameBranchDialog.tsx`:
- Around line 46-80: The submit flow in handleSubmit creates the renameBranch
mutation before setting the isSubmitting guard, allowing race conditions; fix by
placing a synchronous guard and setting setIsSubmitting(true) immediately after
verifying !isSubmitting and before calling client.git.renameBranch.mutate so
further clicks are blocked, then proceed to create renamePromise, call
toast.promise, await it, call onAfterRename and invalidate caches, and finally
clear setIsSubmitting(false) in the existing finally block; reference
handleSubmit, isSubmitting, setIsSubmitting, client.git.renameBranch.mutate and
toast.promise when making the change.
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx`:
- Around line 107-120: ブランチ名を URL エンコードしていないため "#" や "/" などを含む有効な ref が GitHub
リンクを壊す問題があります。WorkspaceHoverCard の該当箇所で href を組み立てている部分(参照シンボル: repoUrl,
branchName, branchExistsOnRemote)を修正し、パス部分に branchName を埋め込む際は必ず
encodeURIComponent(branchName) を使ってエンコードしてから `${repoUrl}/tree/...`
を生成するようにしてください(onClick の stopPropagation など既存の挙動は維持)。
---
Nitpick comments:
In `@apps/desktop/src/renderer/lib/dev-chat.ts`:
- Around line 26-30: The model list defined inline in
apps/desktop/src/renderer/lib/dev-chat.ts (e.g., the entry with id
"openai/gpt-5.5") is duplicated in packages/trpc/src/router/chat/chat.ts;
extract the canonical model list into a shared constant/module (for example a
new exported array like SUPPORTED_MODELS in a shared package or utils module)
and replace the inline arrays in both dev-chat.ts and chat.ts with imports from
that single source, or alternatively expose the server-side list via the chat
router and have dev-chat consume it; update imports and types so both files
reference the same identifier (e.g., SUPPORTED_MODELS) to prevent future drift.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/DashboardSidebarExpandedWorkspaceRow.tsx`:
- Around line 291-299: In DashboardSidebarExpandedWorkspaceRow update the
onKeyDown handler(s) to use the modern space key value: replace the legacy check
event.key === "Spacebar" with the single-space string (" ") — or, if you want to
keep backward compatibility, keep both checks but prefer the " " check first;
locate the onKeyDown prop in the DashboardSidebarExpandedWorkspaceRow component
(also adjust the other similar onKeyDown occurrence in the same component) and
ensure the handler still calls event.stopPropagation() for Enter and Space.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx`:
- Line 27: The import in DashboardSidebarWorkspaceContextMenu.tsx uses a deep
relative path; replace the relative import of useDashboardSidebarHover with the
project alias path (use the existing renderer/... style used elsewhere in this
file) so it reads the aliased module import instead of
"../../../../providers/DashboardSidebarHoverProvider"; update the import
statement that brings in useDashboardSidebarHover to use the tsconfig-defined
alias to keep moves/splits safe and consistent.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceHoverCardContent/DashboardSidebarWorkspaceHoverCardContent.tsx`:
- Around line 71-79: Replace the template-literal className on the button in
DashboardSidebarWorkspaceHoverCardContent with the project's cn() utility to
match other components; update the button element that calls
onEditBranchClick(branch) to build classes via cn("group/branch flex min-w-0
flex-1 items-center gap-1 font-mono break-all text-left hover:text-foreground
hover:underline", hasCustomAlias ? "text-xs" : "text-sm",
"group-hover/branch:opacity-100 transition-opacity") so conditional classes are
handled consistently with the rest of the codebase.
In
`@apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx`:
- Around line 100-103: The useMemo that computes hoverPayload currently lists
only workspace in its dependency array; update the dependency array for the
useMemo call that creates hoverPayload to also include the state setter
setRenameBranchTarget so the intent is explicit (hoverPayload -> useMemo(() =>
({ workspace, onEditBranchClick: setRenameBranchTarget }), [workspace,
setRenameBranchTarget])) while keeping the same returned object shape
referencing workspace and setRenameBranchTarget.
- Around line 275-285: 現在のコード renders <RenameBranchDialog> only when
renameBranchTarget is truthy but also passes open={renameBranchTarget !== null},
which is redundant; change the usage to either always render the dialog and
control visibility via the open prop (e.g., open={renameBranchTarget !== null})
or, simpler, keep conditional rendering and set open to true (or omit the open
prop) so the dialog doesn't receive a duplicate condition; apply the same fix to
the expanded view variant—update occurrences around RenameBranchDialog,
renameBranchTarget, setRenameBranchTarget, and handleAfterBranchRename to remove
the redundant open={renameBranchTarget !== null} check.
- Around line 195-205: The conditional render uses both "renameBranchTarget &&"
and "open={renameBranchTarget !== null}", which is redundant because the
component is only rendered when renameBranchTarget is truthy; simplify by
removing the redundant runtime check in the prop: keep the conditional render
"renameBranchTarget && <RenameBranchDialog ... />" and change the open prop to a
constant true (e.g., open={true} or simply open) while keeping workspaceId={id},
currentBranchName={renameBranchTarget}, onOpenChange that calls
setRenameBranchTarget(null), and onAfterRename={handleAfterBranchRename}.
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/CollapsedWorkspaceItem.tsx`:
- Around line 184-193: 表示ブロックが既に renameBranchTarget && でガードされているため
RenameBranchDialog の open に渡している open={renameBranchTarget !== null}
は冗長です;RenameBranchDialog を表示するブロック内で open を常に true にする(例: open={true} または 単に
open を渡す)か open プロップ自体を削除してコンポーネント側の表示制御に委ね、現在の onOpenChange={(open) => { if
(!open) setRenameBranchTarget(null); }} は維持して renameBranchTarget と
setRenameBranchTarget によるクローズ時のリセット挙動を保ってください。
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceContextMenu.tsx`:
- Around line 258-267: 現在のコードでは外側の条件レンダリングと open={renameBranchTarget !== null}
が重複しているので、冗長さを解消してください:Remove the surrounding conditional render (the
"renameBranchTarget && (...)" check) and instead render RenameBranchDialog
unconditionally but control visibility via the open prop set to
renameBranchTarget !== null; keep workspaceId={id},
currentBranchName={renameBranchTarget} and the onOpenChange handler as-is so
closing clears renameBranchTarget. Use the RenameBranchDialog component and the
renameBranchTarget/open/onOpenChange symbols to locate and update the code.
In `@apps/relay/fly.toml`:
- Line 31: Change is approved: the deployment memory setting was increased to
memory = "4gb"; merge the change (keep the memory key set to "4gb") and deploy,
then monitor runtime memory metrics and logs post-deploy to confirm the increase
resolves the relay OOM/deployment issues and be prepared to adjust or roll back
the memory value if abnormal behavior or cost concerns arise.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 86491507-d326-4147-905d-f3ad8009c56c
📒 Files selected for processing (36)
apps/desktop/src/renderer/globals.cssapps/desktop/src/renderer/lib/dev-chat.tsapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/DashboardSidebar.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarHoverCardOverlay/DashboardSidebarHoverCardOverlay.cssapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarHoverCardOverlay/DashboardSidebarHoverCardOverlay.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarHoverCardOverlay/index.tsapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarPortsList/components/DashboardSidebarPortGroup/DashboardSidebarPortGroup.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarCollapsedWorkspaceButton/DashboardSidebarCollapsedWorkspaceButton.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarExpandedWorkspaceRow/DashboardSidebarExpandedWorkspaceRow.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceHoverCardContent/DashboardSidebarWorkspaceHoverCardContent.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceIcon/DashboardSidebarWorkspaceIcon.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/providers/DashboardSidebarHoverProvider/DashboardSidebarHoverProvider.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/providers/DashboardSidebarHoverProvider/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/CollapsedWorkspaceItem.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/WorkspaceContextMenu.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/RenameBranchDialog.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/index.tsapps/relay/Dockerfileapps/relay/fly.tomlpackages/panes/src/core/store/store.test.tspackages/panes/src/core/store/store.tspackages/panes/src/react/components/Workspace/Workspace.tsxpackages/panes/src/react/components/Workspace/components/TabBar/TabBar.tsxpackages/panes/src/react/components/Workspace/components/TabBar/components/TabItem/TabItem.tsxpackages/trpc/src/router/chat/chat.tspackages/ui/package.jsonpackages/ui/src/components/overflow-fade/OverflowFadeContainer/OverflowFadeContainer.tsxpackages/ui/src/components/overflow-fade/OverflowFadeContainer/index.tspackages/ui/src/components/overflow-fade/OverflowFadeText/OverflowFadeText.tsxpackages/ui/src/components/overflow-fade/OverflowFadeText/index.tspackages/ui/src/components/overflow-fade/fade-edge.csspackages/ui/src/hooks/use-overflow-fade.ts
💤 Files with no reviewable changes (2)
- packages/ui/src/components/overflow-fade/fade-edge.css
- apps/desktop/src/renderer/globals.css
| const handleSubmit = async () => { | ||
| if (isInvalid || isSubmitting) return; | ||
| if (!activeHostUrl) { | ||
| toast.error("Host service is not available"); | ||
| return; | ||
| } | ||
|
|
||
| const client = getHostServiceClientByUrl(activeHostUrl); | ||
| const renamePromise = client.git.renameBranch.mutate({ | ||
| workspaceId, | ||
| oldName: currentBranchName, | ||
| newName: trimmed, | ||
| }); | ||
|
|
||
| toast.promise(renamePromise, { | ||
| loading: `Renaming branch to ${trimmed}...`, | ||
| success: `Branch renamed to ${trimmed}`, | ||
| error: (err) => | ||
| err instanceof Error ? err.message : "Failed to rename branch", | ||
| }); | ||
|
|
||
| setIsSubmitting(true); | ||
| try { | ||
| await renamePromise; | ||
| onAfterRename?.(trimmed); | ||
| void electronUtils.workspaces.getWorktreeInfo.invalidate({ | ||
| workspaceId, | ||
| }); | ||
| void electronUtils.workspaces.get.invalidate({ id: workspaceId }); | ||
| void electronUtils.workspaces.getAllGrouped.invalidate(); | ||
| onOpenChange(false); | ||
| } catch { | ||
| // toast.promise surfaced the error to the user | ||
| } finally { | ||
| setIsSubmitting(false); |
There was a problem hiding this comment.
重複送信を防ぐ同期ガードが不足しています。
Line [67] で isSubmitting を立てる前に mutation を生成しているため、素早い連打で renameBranch が二重送信される余地があります。非冪等操作なので送信前に同期的なガードを置いてください。
修正案(同期ガード追加)
-import { useEffect, useState } from "react";
+import { useEffect, useRef, useState } from "react";
@@
const [value, setValue] = useState(currentBranchName);
const [isSubmitting, setIsSubmitting] = useState(false);
+ const isSubmittingRef = useRef(false);
@@
const handleSubmit = async () => {
- if (isInvalid || isSubmitting) return;
+ if (isInvalid || isSubmittingRef.current) return;
if (!activeHostUrl) {
toast.error("Host service is not available");
return;
}
+ isSubmittingRef.current = true;
+ setIsSubmitting(true);
const client = getHostServiceClientByUrl(activeHostUrl);
const renamePromise = client.git.renameBranch.mutate({
workspaceId,
oldName: currentBranchName,
newName: trimmed,
});
@@
- setIsSubmitting(true);
try {
await renamePromise;
@@
} finally {
+ isSubmittingRef.current = false;
setIsSubmitting(false);
}
};🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/RenameBranchDialog/RenameBranchDialog.tsx`
around lines 46 - 80, The submit flow in handleSubmit creates the renameBranch
mutation before setting the isSubmitting guard, allowing race conditions; fix by
placing a synchronous guard and setting setIsSubmitting(true) immediately after
verifying !isSubmitting and before calling client.git.renameBranch.mutate so
further clicks are blocked, then proceed to create renamePromise, call
toast.promise, await it, call onAfterRename and invalidate caches, and finally
clear setIsSubmitting(false) in the existing finally block; reference
handleSubmit, isSubmitting, setIsSubmitting, client.git.renameBranch.mutate and
toast.promise when making the change.
| {repoUrl && branchExistsOnRemote && ( | ||
| <a | ||
| href={`${repoUrl}/tree/${branchName}`} | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| className="shrink-0 text-muted-foreground hover:text-foreground" | ||
| title="Open branch on GitHub" | ||
| onClick={(e) => e.stopPropagation()} | ||
| > | ||
| <LuExternalLink | ||
| className="size-3" | ||
| strokeWidth={STROKE_WIDTH} | ||
| /> | ||
| </a> |
There was a problem hiding this comment.
ブランチ名は URL エンコードしてから href を組み立ててください。
いまの文字列結合だと、# などの予約文字を含む有効な ref 名で GitHub リンクが途中で壊れます。
修正例
- href={`${repoUrl}/tree/${branchName}`}
+ href={`${repoUrl}/tree/${encodeURIComponent(branchName)}`}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {repoUrl && branchExistsOnRemote && ( | |
| <a | |
| href={`${repoUrl}/tree/${branchName}`} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="shrink-0 text-muted-foreground hover:text-foreground" | |
| title="Open branch on GitHub" | |
| onClick={(e) => e.stopPropagation()} | |
| > | |
| <LuExternalLink | |
| className="size-3" | |
| strokeWidth={STROKE_WIDTH} | |
| /> | |
| </a> | |
| {repoUrl && branchExistsOnRemote && ( | |
| <a | |
| href={`${repoUrl}/tree/${encodeURIComponent(branchName)}`} | |
| target="_blank" | |
| rel="noopener noreferrer" | |
| className="shrink-0 text-muted-foreground hover:text-foreground" | |
| title="Open branch on GitHub" | |
| onClick={(e) => e.stopPropagation()} | |
| > | |
| <LuExternalLink | |
| className="size-3" | |
| strokeWidth={STROKE_WIDTH} | |
| /> | |
| </a> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceSidebar/WorkspaceListItem/components/WorkspaceHoverCard/WorkspaceHoverCard.tsx`
around lines 107 - 120, ブランチ名を URL エンコードしていないため "#" や "/" などを含む有効な ref が GitHub
リンクを壊す問題があります。WorkspaceHoverCard の該当箇所で href を組み立てている部分(参照シンボル: repoUrl,
branchName, branchExistsOnRemote)を修正し、パス部分に branchName を埋め込む際は必ず
encodeURIComponent(branchName) を使ってエンコードしてから `${repoUrl}/tree/...`
を生成するようにしてください(onClick の stopPropagation など既存の挙動は維持)。
Summary
upstream (superset-sh/superset) から fork (MocA-Love/superset) への 2026-04-27 後半バッチ取り込み 第1弾。新規 13 commits を 5 PR に分割した中の PR-D1: safe batch (sidebar / fade / panes / relay / model) (7 commits)。
base は main (#445/#446/#447 マージ後の最新)。conflict は依存順守れば全て clean apply。
取り込み内容 (chronological)
0eedb03a410a1f1579c1a3e3...packages/uiに hook + components 追加、旧 fade-edge.css 削除)c3a9f088abec589c79cb...556a0368a依存順序
Codex 事前調査で確認した依存:
5cceee0cc(pane drops) は01af7dc8c(overflow fade) の TabBar 移行に依存 → 同 PR 内で順序保持f19cb6ac4(persistent hover card) は2183bcf09(rename branch from hover card) と180425a5e(icon update) に依存 → 同 PR 内で順序保持chronological 順で cherry-pick した結果、全 7 件 conflict なし (clean apply)。
Fork 固有機能ヘルスチェック
baseline (
/tmp/pr-late-baseline.txt) と比較し全項目健在を確認:ansi_up,@vscode/ripgrep,@xyflow/reactelectron-builder.tsのdmg.size = "4g"維持packages/db/drizzle/最大 idx 0039 /packages/local-db/drizzle/最大 idx 0072 維持Test plan
bun install整合性 OKbun run typecheck全 28 task greenbun run lintbiome greenbun run --filter @superset/desktop build成功確認後続 PR (このバッチ残り)
2473996a6) — conflict 1ファイル790cbbc6a) — fork 流に書き換え298d773ee,95cff6b36,50eb12532)864a81c03) — 39 files / +2522 行の大物単独 PRSummary by CodeRabbit
リリースノート
新機能
改善