mirror of
https://github.com/getpaseo/paseo.git
synced 2026-10-23 09:42:53 +00:00
* fix(app): keep Changes comparison and diff in sync Own the working comparison at the workspace checkout so the Changes tree and adjacent working diff share it. Immutable commit diffs remain scoped to their commit SHA. * docs(app): align working diff ownership notes
151 lines
3.9 KiB
TypeScript
151 lines
3.9 KiB
TypeScript
import { useCallback, useEffect, useMemo } from "react";
|
|
import {
|
|
buildWorkspaceAttachmentScopeKey,
|
|
useWorkspaceAttachmentsStore,
|
|
} from "@/attachments/workspace-attachments-store";
|
|
import {
|
|
buildReviewDraftKey,
|
|
useInlineReviewController,
|
|
useReviewAttachmentSnapshot,
|
|
} from "@/review";
|
|
import { useCheckoutDiffQuery } from "@/git/use-diff-query";
|
|
import { useCheckoutStatusQuery } from "@/git/use-status-query";
|
|
import { useWorkingDiffComparison } from "@/git/working-diff-comparison";
|
|
|
|
interface UseWorkingDiffOptions {
|
|
serverId: string;
|
|
workspaceId?: string;
|
|
cwd: string;
|
|
ignoreWhitespace: boolean;
|
|
enabled: boolean;
|
|
queryScope?: string;
|
|
}
|
|
|
|
export function useWorkingDiff({
|
|
serverId,
|
|
workspaceId,
|
|
cwd,
|
|
ignoreWhitespace,
|
|
enabled,
|
|
queryScope,
|
|
}: UseWorkingDiffOptions) {
|
|
const {
|
|
status,
|
|
isLoading: isStatusLoading,
|
|
isError: isStatusError,
|
|
error: statusError,
|
|
} = useCheckoutStatusQuery({ serverId, cwd });
|
|
const gitStatus = status && status.isGit ? status : null;
|
|
const isGit = Boolean(gitStatus);
|
|
const notGit = status !== null && !status.isGit && !status.error;
|
|
const statusErrorMessage =
|
|
status?.error?.message ??
|
|
(isStatusError && statusError instanceof Error ? statusError.message : null);
|
|
const baseRef = gitStatus?.baseRef ?? undefined;
|
|
const hasUncommittedChanges = Boolean(gitStatus?.isDirty);
|
|
const currentBranchName =
|
|
gitStatus?.currentBranch && gitStatus.currentBranch !== "HEAD" ? gitStatus.currentBranch : null;
|
|
|
|
const { comparison: diffMode, selectComparison } = useWorkingDiffComparison({
|
|
serverId,
|
|
workspaceId,
|
|
cwd,
|
|
isDirty: hasUncommittedChanges,
|
|
});
|
|
const selectUncommitted = useCallback(() => selectComparison("uncommitted"), [selectComparison]);
|
|
const selectBase = useCallback(() => selectComparison("base"), [selectComparison]);
|
|
|
|
const {
|
|
files,
|
|
payloadError: diffPayloadError,
|
|
diffTooLarge,
|
|
isLoading: isDiffLoading,
|
|
} = useCheckoutDiffQuery({
|
|
serverId,
|
|
cwd,
|
|
mode: diffMode,
|
|
baseRef,
|
|
ignoreWhitespace,
|
|
enabled: enabled && isGit,
|
|
queryScope,
|
|
});
|
|
const reviewDraftKey = useMemo(
|
|
() =>
|
|
buildReviewDraftKey({
|
|
serverId,
|
|
workspaceId,
|
|
cwd,
|
|
mode: diffMode,
|
|
baseRef,
|
|
ignoreWhitespace,
|
|
}),
|
|
[baseRef, cwd, diffMode, ignoreWhitespace, serverId, workspaceId],
|
|
);
|
|
const reviewActions = useInlineReviewController({ reviewDraftKey });
|
|
const reviewAttachment = useReviewAttachmentSnapshot({
|
|
key: reviewDraftKey,
|
|
diffFiles: files,
|
|
cwd,
|
|
mode: diffMode,
|
|
baseRef,
|
|
});
|
|
|
|
return {
|
|
status,
|
|
isStatusLoading,
|
|
isGit,
|
|
notGit,
|
|
statusErrorMessage,
|
|
baseRef,
|
|
currentBranchName,
|
|
diffMode,
|
|
selectUncommitted,
|
|
selectBase,
|
|
files,
|
|
diffPayloadError,
|
|
diffTooLarge,
|
|
isDiffLoading,
|
|
reviewActions,
|
|
reviewAttachment,
|
|
};
|
|
}
|
|
|
|
export function usePublishWorkingDiffAttachment({
|
|
serverId,
|
|
workspaceId,
|
|
cwd,
|
|
attachment,
|
|
enabled,
|
|
}: {
|
|
serverId: string;
|
|
workspaceId?: string;
|
|
cwd: string;
|
|
attachment: ReturnType<typeof useWorkingDiff>["reviewAttachment"];
|
|
enabled: boolean;
|
|
}) {
|
|
const scopeKey = useMemo(
|
|
() => buildWorkspaceAttachmentScopeKey({ serverId, workspaceId, cwd }),
|
|
[cwd, serverId, workspaceId],
|
|
);
|
|
const setWorkspaceAttachments = useWorkspaceAttachmentsStore(
|
|
(state) => state.setWorkspaceAttachments,
|
|
);
|
|
const clearWorkspaceAttachments = useWorkspaceAttachmentsStore(
|
|
(state) => state.clearWorkspaceAttachments,
|
|
);
|
|
|
|
useEffect(() => {
|
|
if (!enabled) {
|
|
return;
|
|
}
|
|
const attachments = attachment ? [attachment] : [];
|
|
setWorkspaceAttachments({ scopeKey, attachments });
|
|
return () => {
|
|
const current = useWorkspaceAttachmentsStore.getState().attachmentsByScope[scopeKey];
|
|
if (current === attachments) {
|
|
clearWorkspaceAttachments({ scopeKey });
|
|
}
|
|
};
|
|
}, [attachment, clearWorkspaceAttachments, enabled, scopeKey, setWorkspaceAttachments]);
|
|
}
|