Merge branch 'main' into dev
This commit is contained in:
@@ -29,6 +29,7 @@ import {
|
||||
Archive,
|
||||
ChevronDown,
|
||||
Columns2,
|
||||
Download,
|
||||
GitBranch,
|
||||
GitCommitHorizontal,
|
||||
GitMerge,
|
||||
@@ -81,6 +82,7 @@ import { openExternalUrl } from "@/utils/open-external-url";
|
||||
import { GitActionsSplitButton } from "@/components/git-actions-split-button";
|
||||
import { usePanelStore } from "@/stores/panel-store";
|
||||
import { buildWorkspaceExplorerStateKey } from "@/hooks/use-file-explorer-actions";
|
||||
import { useToast } from "@/contexts/toast-context";
|
||||
import {
|
||||
formatDiffContentText,
|
||||
formatDiffGutterText,
|
||||
@@ -607,12 +609,12 @@ type DiffFlatItem =
|
||||
|
||||
export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDiffPaneProps) {
|
||||
const { theme } = useUnistyles();
|
||||
const toast = useToast();
|
||||
const isMobile = useIsCompactFormFactor();
|
||||
const showDesktopWebScrollbar = Platform.OS === "web" && !isMobile;
|
||||
const canUseSplitLayout = Platform.OS === "web" && !isMobile;
|
||||
const router = useRouter();
|
||||
const [diffModeOverride, setDiffModeOverride] = useState<"uncommitted" | "base" | null>(null);
|
||||
const [actionError, setActionError] = useState<string | null>(null);
|
||||
const [postShipArchiveSuggested, setPostShipArchiveSuggested] = useState(false);
|
||||
const [shipDefault, setShipDefault] = useState<"merge" | "pr">("merge");
|
||||
const { preferences: changesPreferences, updatePreferences: updateChangesPreferences } =
|
||||
@@ -896,6 +898,9 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
|
||||
const commitStatus = useCheckoutGitActionsStore((state) =>
|
||||
state.getStatus({ serverId, cwd, actionId: "commit" }),
|
||||
);
|
||||
const pullStatus = useCheckoutGitActionsStore((state) =>
|
||||
state.getStatus({ serverId, cwd, actionId: "pull" }),
|
||||
);
|
||||
const pushStatus = useCheckoutGitActionsStore((state) =>
|
||||
state.getStatus({ serverId, cwd, actionId: "push" }),
|
||||
);
|
||||
@@ -913,83 +918,123 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
|
||||
);
|
||||
|
||||
const runCommit = useCheckoutGitActionsStore((state) => state.commit);
|
||||
const runPull = useCheckoutGitActionsStore((state) => state.pull);
|
||||
const runPush = useCheckoutGitActionsStore((state) => state.push);
|
||||
const runCreatePr = useCheckoutGitActionsStore((state) => state.createPr);
|
||||
const runMergeBranch = useCheckoutGitActionsStore((state) => state.mergeBranch);
|
||||
const runMergeFromBase = useCheckoutGitActionsStore((state) => state.mergeFromBase);
|
||||
const runArchiveWorktree = useCheckoutGitActionsStore((state) => state.archiveWorktree);
|
||||
|
||||
const toastActionError = useCallback(
|
||||
(error: unknown, fallback: string) => {
|
||||
const message = error instanceof Error ? error.message : fallback;
|
||||
toast.error(message);
|
||||
},
|
||||
[toast],
|
||||
);
|
||||
|
||||
const toastActionSuccess = useCallback(
|
||||
(message: string) => {
|
||||
toast.show(message, { variant: "success" });
|
||||
},
|
||||
[toast],
|
||||
);
|
||||
|
||||
const handleCommit = useCallback(() => {
|
||||
setActionError(null);
|
||||
void runCommit({ serverId, cwd }).catch((err) => {
|
||||
const message = err instanceof Error ? err.message : "Failed to commit";
|
||||
setActionError(message);
|
||||
});
|
||||
}, [runCommit, serverId, cwd]);
|
||||
void runCommit({ serverId, cwd })
|
||||
.then(() => {
|
||||
toastActionSuccess("Committed");
|
||||
})
|
||||
.catch((err) => {
|
||||
toastActionError(err, "Failed to commit");
|
||||
});
|
||||
}, [cwd, runCommit, serverId, toastActionError, toastActionSuccess]);
|
||||
|
||||
const handlePull = useCallback(() => {
|
||||
void runPull({ serverId, cwd })
|
||||
.then(() => {
|
||||
toastActionSuccess("Pulled");
|
||||
})
|
||||
.catch((err) => {
|
||||
toastActionError(err, "Failed to pull");
|
||||
});
|
||||
}, [cwd, runPull, serverId, toastActionError, toastActionSuccess]);
|
||||
|
||||
const handlePush = useCallback(() => {
|
||||
setActionError(null);
|
||||
void runPush({ serverId, cwd }).catch((err) => {
|
||||
const message = err instanceof Error ? err.message : "Failed to push";
|
||||
setActionError(message);
|
||||
});
|
||||
}, [runPush, serverId, cwd]);
|
||||
void runPush({ serverId, cwd })
|
||||
.then(() => {
|
||||
toastActionSuccess("Pushed");
|
||||
})
|
||||
.catch((err) => {
|
||||
toastActionError(err, "Failed to push");
|
||||
});
|
||||
}, [cwd, runPush, serverId, toastActionError, toastActionSuccess]);
|
||||
|
||||
const handleCreatePr = useCallback(() => {
|
||||
void persistShipDefault("pr");
|
||||
setActionError(null);
|
||||
void runCreatePr({ serverId, cwd }).catch((err) => {
|
||||
const message = err instanceof Error ? err.message : "Failed to create PR";
|
||||
setActionError(message);
|
||||
});
|
||||
}, [persistShipDefault, runCreatePr, serverId, cwd]);
|
||||
void runCreatePr({ serverId, cwd })
|
||||
.then(() => {
|
||||
toastActionSuccess("PR created");
|
||||
})
|
||||
.catch((err) => {
|
||||
toastActionError(err, "Failed to create PR");
|
||||
});
|
||||
}, [cwd, persistShipDefault, runCreatePr, serverId, toastActionError, toastActionSuccess]);
|
||||
|
||||
const handleMergeBranch = useCallback(() => {
|
||||
if (!baseRef) {
|
||||
setActionError("Base ref unavailable");
|
||||
toast.error("Base ref unavailable");
|
||||
return;
|
||||
}
|
||||
void persistShipDefault("merge");
|
||||
setActionError(null);
|
||||
void runMergeBranch({ serverId, cwd, baseRef })
|
||||
.then(() => {
|
||||
setPostShipArchiveSuggested(true);
|
||||
toastActionSuccess("Merged");
|
||||
})
|
||||
.catch((err) => {
|
||||
const message = err instanceof Error ? err.message : "Failed to merge";
|
||||
setActionError(message);
|
||||
toastActionError(err, "Failed to merge");
|
||||
});
|
||||
}, [baseRef, persistShipDefault, runMergeBranch, serverId, cwd]);
|
||||
}, [
|
||||
baseRef,
|
||||
cwd,
|
||||
persistShipDefault,
|
||||
runMergeBranch,
|
||||
serverId,
|
||||
toast,
|
||||
toastActionError,
|
||||
toastActionSuccess,
|
||||
]);
|
||||
|
||||
const handleMergeFromBase = useCallback(() => {
|
||||
if (!baseRef) {
|
||||
setActionError("Base ref unavailable");
|
||||
toast.error("Base ref unavailable");
|
||||
return;
|
||||
}
|
||||
setActionError(null);
|
||||
void runMergeFromBase({ serverId, cwd, baseRef }).catch((err) => {
|
||||
const message = err instanceof Error ? err.message : "Failed to merge from base";
|
||||
setActionError(message);
|
||||
});
|
||||
}, [baseRef, runMergeFromBase, serverId, cwd]);
|
||||
void runMergeFromBase({ serverId, cwd, baseRef })
|
||||
.then(() => {
|
||||
toastActionSuccess("Updated");
|
||||
})
|
||||
.catch((err) => {
|
||||
toastActionError(err, "Failed to merge from base");
|
||||
});
|
||||
}, [baseRef, cwd, runMergeFromBase, serverId, toast, toastActionError, toastActionSuccess]);
|
||||
|
||||
const handleArchiveWorktree = useCallback(() => {
|
||||
const worktreePath = status?.cwd;
|
||||
if (!worktreePath) {
|
||||
setActionError("Worktree path unavailable");
|
||||
toast.error("Worktree path unavailable");
|
||||
return;
|
||||
}
|
||||
setActionError(null);
|
||||
const targetWorkingDir = resolveNewAgentWorkingDir(cwd, status ?? null);
|
||||
void runArchiveWorktree({ serverId, cwd, worktreePath })
|
||||
.then(() => {
|
||||
router.replace(buildNewAgentRoute(serverId, targetWorkingDir));
|
||||
})
|
||||
.catch((err) => {
|
||||
const message = err instanceof Error ? err.message : "Failed to archive worktree";
|
||||
setActionError(message);
|
||||
toastActionError(err, "Failed to archive worktree");
|
||||
});
|
||||
}, [runArchiveWorktree, router, serverId, cwd, status]);
|
||||
}, [cwd, router, runArchiveWorktree, serverId, status, toast, toastActionError]);
|
||||
|
||||
const renderFlatItem = useCallback(
|
||||
({ item }: { item: DiffFlatItem }) => {
|
||||
@@ -1041,6 +1086,7 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
|
||||
: "Unknown";
|
||||
const actionsDisabled = !isGit || Boolean(status?.error) || isStatusLoading;
|
||||
const aheadCount = gitStatus?.aheadBehind?.ahead ?? 0;
|
||||
const behindBaseCount = gitStatus?.aheadBehind?.behind ?? 0;
|
||||
const aheadOfOrigin = gitStatus?.aheadOfOrigin ?? 0;
|
||||
const behindOfOrigin = gitStatus?.behindOfOrigin ?? 0;
|
||||
const baseRefLabel = useMemo(() => {
|
||||
@@ -1066,6 +1112,7 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
|
||||
(postShipArchiveSuggested || isMergedPullRequest);
|
||||
|
||||
const commitDisabled = actionsDisabled || commitStatus === "pending";
|
||||
const pullDisabled = actionsDisabled || pullStatus === "pending";
|
||||
const prDisabled = actionsDisabled || prCreateStatus === "pending";
|
||||
const mergeDisabled = actionsDisabled || mergeStatus === "pending";
|
||||
const mergeFromBaseDisabled = actionsDisabled || mergeFromBaseStatus === "pending";
|
||||
@@ -1172,6 +1219,7 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
|
||||
baseRefAvailable: Boolean(baseRef),
|
||||
baseRefLabel,
|
||||
aheadCount,
|
||||
behindBaseCount,
|
||||
aheadOfOrigin,
|
||||
behindOfOrigin,
|
||||
shouldPromoteArchive,
|
||||
@@ -1183,6 +1231,12 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
|
||||
icon: <GitCommitHorizontal size={16} color={theme.colors.foregroundMuted} />,
|
||||
handler: handleCommit,
|
||||
},
|
||||
pull: {
|
||||
disabled: pullDisabled,
|
||||
status: pullStatus,
|
||||
icon: <Download size={16} color={theme.colors.foregroundMuted} />,
|
||||
handler: handlePull,
|
||||
},
|
||||
push: {
|
||||
disabled: pushDisabled,
|
||||
status: pushStatus,
|
||||
@@ -1227,6 +1281,7 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
|
||||
hasPullRequest,
|
||||
prStatus?.url,
|
||||
aheadCount,
|
||||
behindBaseCount,
|
||||
isPaseoOwnedWorktree,
|
||||
isOnBaseBranch,
|
||||
githubFeaturesEnabled,
|
||||
@@ -1237,18 +1292,21 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
|
||||
baseRefLabel,
|
||||
shouldPromoteArchive,
|
||||
commitDisabled,
|
||||
pullDisabled,
|
||||
pushDisabled,
|
||||
prDisabled,
|
||||
mergeDisabled,
|
||||
mergeFromBaseDisabled,
|
||||
archiveDisabled,
|
||||
commitStatus,
|
||||
pullStatus,
|
||||
pushStatus,
|
||||
prCreateStatus,
|
||||
mergeStatus,
|
||||
mergeFromBaseStatus,
|
||||
archiveStatus,
|
||||
handleCommit,
|
||||
handlePull,
|
||||
handlePush,
|
||||
handleCreatePr,
|
||||
handleMergeBranch,
|
||||
@@ -1458,7 +1516,6 @@ export function GitDiffPane({ serverId, workspaceId, cwd, hideHeaderRow }: GitDi
|
||||
</View>
|
||||
) : null}
|
||||
|
||||
{actionError ? <Text style={styles.actionErrorText}>{actionError}</Text> : null}
|
||||
{prErrorMessage ? <Text style={styles.actionErrorText}>{prErrorMessage}</Text> : null}
|
||||
|
||||
<View style={styles.diffContainer}>
|
||||
|
||||
Reference in New Issue
Block a user