Simplify the workspace base picker

Co-authored-by: Tianyu Yang <yangtianyu.cl@bytedance.com>
This commit is contained in:
Mohamed Boudra
2026-11-03 07:53:14 +01:00
co-authored by Tianyu Yang
parent fbcfa86ee0
commit c34de7c1f6
12 changed files with 39 additions and 75 deletions
@@ -367,6 +367,7 @@ test("Changes lets a compact workspace change its base in a sheet", async ({ pag
await page.screenshot({ path: testInfo.outputPath("compact-base-picker.png") });
await release.click();
await expect(picker).toContainText("release");
await page.screenshot({ path: testInfo.outputPath("compact-base-selected.png") });
});
test("Changes shows a failed base selection and lets the user retry", async ({ page }) => {
@@ -392,7 +393,9 @@ test("Changes shows a failed base selection and lets the user retry", async ({ p
await expect(picker).toContainText("release");
});
test("Changes asks to update a host without the base-branch capability", async ({ page }) => {
test("Changes shows the base as text on a host without the base-branch capability", async ({
page,
}) => {
let baseRequests = 0;
await page.routeWebSocket(daemonWsRoutePattern(), (browser) => {
const server = browser.connectToServer();
+22 -15
View File
@@ -19,6 +19,7 @@ import type { Theme } from "@/styles/theme";
import { useIsCompactFormFactor } from "@/constants/layout";
import {
AlignJustify,
ArrowRight,
ChevronDown,
Columns2,
ExternalLink,
@@ -202,6 +203,7 @@ const foregroundMutedIconColorMapping = (theme: Theme) => ({ color: theme.colors
const ThemedLoadingSpinner = withUnistyles(LoadingSpinner);
const ThemedAlignJustify = withUnistyles(AlignJustify);
const ThemedArrowRight = withUnistyles(ArrowRight);
const ThemedColumns2 = withUnistyles(Columns2);
const ThemedPilcrow = withUnistyles(Pilcrow);
const ThemedWrapText = withUnistyles(WrapText);
@@ -471,7 +473,8 @@ interface ChangesPullRequestLinkModel extends Pick<PrHint, "forge" | "number" |
}
interface ChangesRepositoryToolbarModel {
baseBranchPicker: ReactNode;
baseRef: string | null;
isWorktree: boolean;
branchName: string | null;
cwd: string;
gitActions: GitActions | null;
@@ -498,7 +501,8 @@ interface ChangesHeaderProps {
}
interface BuildChangesHeaderModelInput {
baseBranchPicker: ReactNode;
baseRef: string | null;
isWorktree: boolean;
branchName: string | null;
committedDescription?: string;
compact: boolean;
@@ -522,7 +526,8 @@ function buildChangesHeaderModel(input: BuildChangesHeaderModelInput): {
} {
return {
repository: {
baseBranchPicker: input.baseBranchPicker,
baseRef: input.baseRef,
isWorktree: input.isWorktree,
branchName: input.branchName,
cwd: input.cwd,
gitActions: input.compact ? input.gitActions : null,
@@ -662,8 +667,18 @@ function ChangesRepositoryToolbar({
isGitCheckout
testID="changes-branch-switcher"
/>
<Text style={styles.baseArrow}>→</Text>
{model.baseBranchPicker}
{model.baseRef ? (
<>
<ThemedArrowRight size={14} uniProps={foregroundMutedIconColorMapping} />
<WorkspaceBaseBranchPicker
serverId={model.serverId}
workspaceId={model.workspaceId}
cwd={model.cwd}
baseRef={model.baseRef}
isWorktree={model.isWorktree}
/>
</>
) : null}
</ChangesToolbarLeading>
<ChangesToolbarTrailing>
{model.pullRequest ? (
@@ -1914,15 +1929,8 @@ export function ChangesSurface({
const changesHeaderModel = useMemo(
() =>
buildChangesHeaderModel({
baseBranchPicker: (
<WorkspaceBaseBranchPicker
serverId={serverId}
workspaceId={workspaceId}
cwd={cwd}
baseRef={baseRef ?? null}
isWorktree={isManagedWorktree(status)}
/>
),
baseRef: baseRef ?? null,
isWorktree: isManagedWorktree(status),
branchName: currentBranchName,
committedDescription: committedDiffDescription,
compact: isMobile,
@@ -2012,7 +2020,6 @@ export function ChangesSurface({
}
const styles = StyleSheet.create((theme) => ({
baseArrow: { color: theme.colors.foregroundMuted },
container: {
flex: 1,
minHeight: 0,
@@ -8,12 +8,10 @@ import { StyleSheet, withUnistyles } from "react-native-unistyles";
import type { Theme } from "@/styles/theme";
import { Combobox, ComboboxItem, type ComboboxProps } from "@/components/ui/combobox";
import { ToolbarLabelSelectTrigger } from "@/components/ui/toolbar-label-trigger";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { LoadingSpinner } from "@/components/ui/loading-spinner";
import { Button } from "@/components/ui/button";
import { useHostRuntimeClient, useHostRuntimeIsConnected } from "@/runtime/host-runtime";
import { useSessionStore } from "@/stores/session-store";
import { useToast } from "@/contexts/toast-context";
import { useDebouncedValue } from "@/hooks/use-debounced-value";
import { invalidateCheckoutGitQueriesForClient } from "./query-keys";
@@ -21,7 +19,7 @@ interface Props {
serverId: string;
workspaceId?: string | null;
cwd: string;
baseRef: string | null;
baseRef: string;
isWorktree: boolean;
}
@@ -48,7 +46,6 @@ export function WorkspaceBaseBranchPicker({
(state) => state.sessions[serverId]?.serverInfo?.features?.workspaceBaseBranch === true,
);
const queryClient = useQueryClient();
const toast = useToast();
const anchorRef = useRef<View>(null);
const [open, setOpen] = useState(false);
const [search, setSearch] = useState("");
@@ -78,7 +75,6 @@ export function WorkspaceBaseBranchPicker({
},
onSuccess: async () => {
setOpen(false);
toast.show(t("workspace.git.diff.baseBranch.saved"));
await invalidateCheckoutGitQueriesForClient(queryClient, { serverId, cwd });
},
});
@@ -88,22 +84,15 @@ export function WorkspaceBaseBranchPicker({
);
const error = mutation.error ?? branches.error;
const title = t("workspace.git.diff.baseBranch.title");
const label = baseRef ? refLabel(baseRef).replace(/^origin\//, "") : title;
const hint = supported
? t("workspace.git.diff.baseBranch.hint")
: t("workspace.git.diff.baseBranch.updateHost");
const label = refLabel(baseRef).replace(/^origin\//, "");
const { reset, mutate, isPending } = mutation;
const { refetch, isError } = branches;
const handleOpen = useCallback(() => {
if (!supported) {
toast.error(t("workspace.git.diff.baseBranch.updateHost"));
return;
}
reset();
setSearch("");
setOpen(true);
}, [reset, supported, toast, t]);
}, [reset]);
const handleSelect = useCallback(
(ref: string) => {
if (!isPending) mutate(ref);
@@ -150,26 +139,18 @@ export function WorkspaceBaseBranchPicker({
return (
<View ref={anchorRef} collapsable={false} style={styles.anchor}>
<Tooltip delayDuration={300} enabledOnDesktop enabledOnMobile={false}>
<TooltipTrigger asChild>
<ToolbarLabelSelectTrigger
testID="workspace-base-branch-trigger"
label={label}
open={open}
disabled={!connected || mutation.isPending}
accessibilityRole="button"
accessibilityLabel={title}
accessibilityHint={hint}
onPress={handleOpen}
/>
</TooltipTrigger>
<TooltipContent side="bottom">
<Text style={styles.text}>{hint}</Text>
</TooltipContent>
</Tooltip>
<ToolbarLabelSelectTrigger
testID="workspace-base-branch-trigger"
label={label}
open={open}
disabled={!connected || mutation.isPending}
accessibilityRole="button"
accessibilityLabel={title}
onPress={handleOpen}
/>
<Combobox
options={options}
value={baseRef ?? ""}
value={baseRef}
onSelect={handleSelect}
keepOpenOnSelect
searchable
-3
View File
@@ -932,9 +932,6 @@ export const ar: TranslationResources = {
diff: {
baseBranch: {
title: "الفرع الأساسي",
hint: "يُستخدم للتغييرات المثبتة والالتزامات وتحديثات Git وطلبات السحب الجديدة. مشترك بين مساحات العمل التي تستخدم نسخة العمل هذه.",
updateHost: "حدّث المضيف لتغيير الفرع الأساسي.",
saved: "تم تحديث الفرع الأساسي",
},
openChangesTab: "فتح علامة تبويب التغييرات",
openDiffTab: "فتح علامة تبويب الفرق",
-3
View File
@@ -940,9 +940,6 @@ export const en = {
diff: {
baseBranch: {
title: "Change base",
hint: "Used for committed changes, commits, Git updates and new pull requests. Shared by workspaces using this checkout.",
updateHost: "Update the host to change the base branch.",
saved: "Base branch updated",
},
openChangesTab: "Open Changes tab",
openDiffTab: "Open Diff tab",
-3
View File
@@ -965,9 +965,6 @@ export const es: TranslationResources = {
diff: {
baseBranch: {
title: "Rama base",
hint: "Se usa para cambios confirmados, commits, actualizaciones de Git y nuevas solicitudes de cambios. Se comparte entre los espacios de trabajo de este checkout.",
updateHost: "Actualiza el host para cambiar la rama base.",
saved: "Rama base actualizada",
},
openChangesTab: "Abrir la pestaña Cambios",
openDiffTab: "Abrir la pestaña Diferencia",
-3
View File
@@ -958,9 +958,6 @@ export const fr: TranslationResources = {
diff: {
baseBranch: {
title: "Branche de base",
hint: "Utilisée pour les changements validés, les commits, les mises à jour Git et les nouvelles pull requests. Partagée par les espaces de travail de ce checkout.",
updateHost: "Mettez à jour l’hôte pour changer la branche de base.",
saved: "Branche de base mise à jour",
},
openChangesTab: "Ouvrir l’onglet Modifications",
openDiffTab: "Ouvrir l’onglet Diff",
-3
View File
@@ -945,9 +945,6 @@ export const ja: TranslationResources = {
diff: {
baseBranch: {
title: "ベースブランチ",
hint: "コミット済みの変更、コミット一覧、Git の更新、新規プルリクエストに使用します。同じチェックアウトのワークスペースで共有されます。",
updateHost: "ベースブランチを変更するにはホストを更新してください。",
saved: "ベースブランチを更新しました",
},
openChangesTab: "変更タブを開く",
openDiffTab: "差分タブを開く",
-3
View File
@@ -939,9 +939,6 @@ export const ko: TranslationResources = {
diff: {
baseBranch: {
title: "기준 브랜치",
hint: "커밋된 변경, 커밋 목록, Git 업데이트 및 새 풀 리퀘스트에 사용됩니다. 같은 체크아웃을 사용하는 워크스페이스가 공유합니다.",
updateHost: "기준 브랜치를 변경하려면 호스트를 업데이트하세요.",
saved: "기준 브랜치가 업데이트되었습니다",
},
openChangesTab: "변경사항 탭 열기",
openDiffTab: "Diff 탭 열기",
-3
View File
@@ -955,9 +955,6 @@ export const ptBR: TranslationResources = {
diff: {
baseBranch: {
title: "Branch base",
hint: "Usada para alterações commitadas, commits, atualizações do Git e novos pull requests. Compartilhada pelos espaços de trabalho deste checkout.",
updateHost: "Atualize o host para alterar a branch base.",
saved: "Branch base atualizada",
},
openChangesTab: "Abrir a aba Alterações",
openDiffTab: "Abrir a aba Diff",
-3
View File
@@ -949,9 +949,6 @@ export const ru: TranslationResources = {
diff: {
baseBranch: {
title: "Базовая ветка",
hint: "Используется для закоммиченных изменений, коммитов, обновлений Git и новых pull request. Общая для рабочих пространств с этой рабочей копией.",
updateHost: "Обновите хост, чтобы изменить базовую ветку.",
saved: "Базовая ветка обновлена",
},
openChangesTab: "Открыть вкладку «Изменения»",
openDiffTab: "Открыть вкладку «Дифф»",
-3
View File
@@ -924,9 +924,6 @@ export const zhCN: TranslationResources = {
diff: {
baseBranch: {
title: "基准分支",
hint: "用于已提交改动、提交列表、Git 更新和新建 PR。同一 checkout 的工作区共享此设置。",
updateHost: "更新 Host 后即可修改基准分支。",
saved: "基准分支已更新",
},
openChangesTab: "打开“更改”标签页",
openDiffTab: "打开 Diff 标签页",