refactor: remove /diff-status endpoint, include diff_status in chat payload (#23082)

The `/chats/{chat}/diff-status` endpoint was redundant because:
- The `Chat` type already has a `DiffStatus` field
- Listing chats already resolves and returns `diff_status`
- The `getChat` endpoint was the only one not resolving it (passing
`nil`)

## Changes

**Backend:**
- `getChat` now calls `resolveChatDiffStatus` and includes the result in
the response
- Removed `getChatDiffStatus` handler, route (`GET /diff-status`), and
SDK method
- Tests updated to use `GetChat` instead of `GetChatDiffStatus`

**Frontend:**
- `AgentDetail.tsx`: uses `chatQuery.data?.diff_status` instead of
separate query
- `RemoteDiffPanel.tsx`: accepts `diffStatus` as a prop instead of
fetching internally
- `AgentsPage.tsx`: `diff_status_change` events now invalidate the chat
query
- Removed `chatDiffStatus` query, `chatDiffStatusKey`, and
`getChatDiffStatus` API method
This commit is contained in:
Kyle Carberry
2026-03-16 07:40:22 -07:00
committed by GitHub
parent 3704e930a1
commit 27cbf5474b
14 changed files with 97 additions and 182 deletions
+10 -21
View File
@@ -553,7 +553,16 @@ func (api *API) chatCostUsers(rw http.ResponseWriter, r *http.Request) {
func (api *API) getChat(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
chat := httpmw.ChatParam(r)
httpapi.Write(ctx, rw, http.StatusOK, convertChat(chat, nil))
diffStatus, err := api.resolveChatDiffStatus(ctx, chat)
if err != nil {
// Log but don't fail - diff status is supplementary.
api.Logger.Error(ctx, "failed to resolve chat diff status",
slog.F("chat_id", chat.ID),
slog.Error(err),
)
}
httpapi.Write(ctx, rw, http.StatusOK, convertChat(chat, diffStatus))
}
// EXPERIMENTAL: this endpoint is experimental and is subject to change.
@@ -1299,26 +1308,6 @@ func (api *API) interruptChat(rw http.ResponseWriter, r *http.Request) {
httpapi.Write(ctx, rw, http.StatusOK, convertChat(chat, nil))
}
// EXPERIMENTAL: this endpoint is experimental and is subject to change.
//
//nolint:revive // HTTP handler writes to ResponseWriter.
func (api *API) getChatDiffStatus(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
chat := httpmw.ChatParam(r)
chatID := chat.ID
status, err := api.resolveChatDiffStatus(ctx, chat)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Failed to get chat diff status.",
Detail: err.Error(),
})
return
}
httpapi.Write(ctx, rw, http.StatusOK, convertChatDiffStatus(chatID, status))
}
// EXPERIMENTAL: this endpoint is experimental and is subject to change.
//
//nolint:revive // HTTP handler writes to ResponseWriter.
+15 -16
View File
@@ -2752,17 +2752,10 @@ func TestGetChatDiffStatus(t *testing.T) {
})
require.NoError(t, err)
noCachedStatus, err := client.GetChatDiffStatus(ctx, noCachedStatusChat.ID)
noCachedChat, err := client.GetChat(ctx, noCachedStatusChat.ID)
require.NoError(t, err)
require.Equal(t, noCachedStatusChat.ID, noCachedStatus.ChatID)
require.Nil(t, noCachedStatus.URL)
require.Nil(t, noCachedStatus.PullRequestState)
require.False(t, noCachedStatus.ChangesRequested)
require.Zero(t, noCachedStatus.Additions)
require.Zero(t, noCachedStatus.Deletions)
require.Zero(t, noCachedStatus.ChangedFiles)
require.Nil(t, noCachedStatus.RefreshedAt)
require.Nil(t, noCachedStatus.StaleAt)
require.Equal(t, noCachedStatusChat.ID, noCachedChat.ID)
require.Nil(t, noCachedChat.DiffStatus)
cachedStatusChat, err := db.InsertChat(dbauthz.AsSystemRestricted(ctx), database.InsertChatParams{
OwnerID: user.UserID,
@@ -2804,8 +2797,11 @@ func TestGetChatDiffStatus(t *testing.T) {
)
require.NoError(t, err)
cachedStatus, err := client.GetChatDiffStatus(ctx, cachedStatusChat.ID)
cachedChat, err := client.GetChat(ctx, cachedStatusChat.ID)
require.NoError(t, err)
require.Equal(t, cachedStatusChat.ID, cachedChat.ID)
require.NotNil(t, cachedChat.DiffStatus)
cachedStatus := cachedChat.DiffStatus
require.Equal(t, cachedStatusChat.ID, cachedStatus.ChatID)
require.NotNil(t, cachedStatus.URL)
require.Equal(t, "https://github.com/coder/coder/tree/feature/diff-status", *cachedStatus.URL)
@@ -2840,11 +2836,11 @@ func TestGetChatDiffStatus(t *testing.T) {
require.NoError(t, err)
otherClient, _ := coderdtest.CreateAnotherUser(t, client, firstUser.OrganizationID)
_, err = otherClient.GetChatDiffStatus(ctx, createdChat.ID)
_, err = otherClient.GetChat(ctx, createdChat.ID)
requireSDKError(t, err, http.StatusNotFound)
})
// Integration test: exercises the full HTTP handler refresh
// Integration test: exercises the full GetChat handler refresh
// path with a real DB, dbauthz, a mock GitHub API, and an
// external-auth-linked user. Verifies that a stale chat diff
// status is refreshed end-to-end via the gitsync worker's
@@ -2943,8 +2939,9 @@ func TestGetChatDiffStatus(t *testing.T) {
)
require.NoError(t, err)
// Call the HTTP endpoint. This exercises the full code
// path: resolveChatDiffStatus -> RefreshChat (with
// Call GetChat which now resolves diff status inline.
// This exercises the full code path:
// resolveChatDiffStatus -> RefreshChat (with
// AsSystemRestricted) -> Refresher.Refresh ->
// resolveChatGitAccessToken (GetExternalAuthLink with
// AsSystemRestricted) -> FetchPullRequestStatus (mock).
@@ -2953,8 +2950,10 @@ func TestGetChatDiffStatus(t *testing.T) {
// would fail under the chatd RBAC context (missing
// ActionReadPersonal), causing ErrNoTokenAvailable and a
// refresh failure that silently returns stale data.
status, err := client.GetChatDiffStatus(ctx, chat.ID)
result, err := client.GetChat(ctx, chat.ID)
require.NoError(t, err)
require.NotNil(t, result.DiffStatus)
status := result.DiffStatus
// The mock GitHub API returned PR #42 with 25 additions,
// 7 deletions, 4 changed files, state "open".
-1
View File
@@ -1187,7 +1187,6 @@ func New(options *Options) *API {
r.Patch("/messages/{message}", api.patchChatMessage)
r.Get("/stream", api.streamChat)
r.Post("/interrupt", api.interruptChat)
r.Get("/diff-status", api.getChatDiffStatus)
r.Get("/diff", api.getChatDiffContents)
r.Route("/queue/{queuedMessage}", func(r chi.Router) {
r.Delete("/", api.deleteChatQueuedMessage)
-14
View File
@@ -1346,20 +1346,6 @@ func (c *Client) GetChatGitChanges(ctx context.Context, chatID uuid.UUID) ([]Cha
return changes, json.NewDecoder(res.Body).Decode(&changes)
}
// GetChatDiffStatus returns cached GitHub pull request diff status for a chat.
func (c *Client) GetChatDiffStatus(ctx context.Context, chatID uuid.UUID) (ChatDiffStatus, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/experimental/chats/%s/diff-status", chatID), nil)
if err != nil {
return ChatDiffStatus{}, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return ChatDiffStatus{}, ReadBodyAsError(res)
}
var status ChatDiffStatus
return status, json.NewDecoder(res.Body).Decode(&status)
}
// GetChatDiffContents returns resolved diff contents for a chat.
func (c *Client) GetChatDiffContents(ctx context.Context, chatID uuid.UUID) (ChatDiffContents, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/experimental/chats/%s/diff", chatID), nil)
-9
View File
@@ -3043,15 +3043,6 @@ class ApiMethods {
return response.data;
};
getChatDiffStatus = async (
chatId: string,
): Promise<TypesGen.ChatDiffStatus> => {
const response = await this.axios.get<TypesGen.ChatDiffStatus>(
`/api/experimental/chats/${chatId}/diff-status`,
);
return response.data;
};
getChatDiffContents = async (
chatId: string,
): Promise<TypesGen.ChatDiffContents> => {
-9
View File
@@ -9,7 +9,6 @@ import {
chatCostUsers,
chatCostUsersKey,
chatDiffContentsKey,
chatDiffStatusKey,
chatKey,
chatMessagesKey,
chatsKey,
@@ -110,7 +109,6 @@ describe("invalidateChatListQueries", () => {
// Per-chat queries that should NOT be touched.
queryClient.setQueryData(chatKey(chatId), makeChat(chatId));
queryClient.setQueryData(chatMessagesKey(chatId), []);
queryClient.setQueryData(chatDiffStatusKey(chatId), {});
queryClient.setQueryData(chatDiffContentsKey(chatId), {});
queryClient.setQueryData(
chatCostSummaryKey("me", undefined),
@@ -139,10 +137,6 @@ describe("invalidateChatListQueries", () => {
queryClient.getQueryState(chatMessagesKey(chatId))?.isInvalidated,
"chatMessagesKey should NOT be invalidated",
).not.toBe(true);
expect(
queryClient.getQueryState(chatDiffStatusKey(chatId))?.isInvalidated,
"chatDiffStatusKey should NOT be invalidated",
).not.toBe(true);
expect(
queryClient.getQueryState(chatDiffContentsKey(chatId))?.isInvalidated,
"chatDiffContentsKey should NOT be invalidated",
@@ -482,8 +476,6 @@ describe("mutation invalidation scope", () => {
queryClient.setQueryData(chatKey(chatId), makeChat(chatId));
// Messages: ["chats", chatId, "messages"]
queryClient.setQueryData(chatMessagesKey(chatId), []);
// Diff status: ["chats", chatId, "diff-status"]
queryClient.setQueryData(chatDiffStatusKey(chatId), { diffs: [] });
// Diff contents: ["chats", chatId, "diff-contents"]
queryClient.setQueryData(chatDiffContentsKey(chatId), { files: [] });
// Cost summary: ["chats", "costSummary", "me", undefined]
@@ -496,7 +488,6 @@ describe("mutation invalidation scope", () => {
/** Keys that should NEVER be invalidated by chat message mutations
* because they are completely unrelated to the message flow. */
const unrelatedKeys = (chatId: string) => [
{ label: "diff-status", key: chatDiffStatusKey(chatId) },
{ label: "diff-contents", key: chatDiffContentsKey(chatId) },
{ label: "cost-summary", key: chatCostSummaryKey("me", undefined) },
];
-9
View File
@@ -352,15 +352,6 @@ export const promoteChatQueuedMessage = (
// change in real-time.
});
export const chatDiffStatusKey = (chatId: string) =>
["chats", chatId, "diff-status"] as const;
export const chatDiffStatus = (chatId: string) => ({
queryKey: chatDiffStatusKey(chatId),
queryFn: (): Promise<TypesGen.ChatDiffStatus> =>
API.getChatDiffStatus(chatId),
});
export const chatDiffContentsKey = (chatId: string) =>
["chats", chatId, "diff-contents"] as const;
@@ -13,7 +13,6 @@ import type { Meta, StoryObj } from "@storybook/react-vite";
import { API } from "api/api";
import {
chatDiffContentsKey,
chatDiffStatusKey,
chatKey,
chatMessagesKey,
chatModelsKey,
@@ -137,37 +136,40 @@ const buildQueries = (
chat: TypesGen.Chat,
messagesData: TypesGen.ChatMessagesResponse,
opts?: { diffUrl?: string },
) => [
{ key: chatKey(CHAT_ID), data: chat },
{ key: chatMessagesKey(CHAT_ID), data: messagesData },
{ key: chatsKey, data: [chat] },
{
key: chatDiffStatusKey(CHAT_ID),
data: {
chat_id: CHAT_ID,
url: opts?.diffUrl,
pull_request_title: "",
pull_request_draft: false,
changes_requested: false,
additions: opts?.diffUrl ? 4 : 0,
deletions: opts?.diffUrl ? 1 : 0,
changed_files: opts?.diffUrl ? 2 : 0,
} satisfies TypesGen.ChatDiffStatus,
},
{
key: chatDiffContentsKey(CHAT_ID),
data: {
chat_id: CHAT_ID,
diff: opts?.diffUrl ? sampleDiff : undefined,
pull_request_url: opts?.diffUrl,
} satisfies TypesGen.ChatDiffContents,
},
{
key: workspaceByIdKey(mockWorkspace.id),
data: mockWorkspace,
},
{ key: chatModelsKey, data: mockModelCatalog },
];
) => {
const diffStatus: TypesGen.ChatDiffStatus = {
chat_id: CHAT_ID,
url: opts?.diffUrl,
pull_request_title: "",
pull_request_draft: false,
changes_requested: false,
additions: opts?.diffUrl ? 4 : 0,
deletions: opts?.diffUrl ? 1 : 0,
changed_files: opts?.diffUrl ? 2 : 0,
};
const chatWithDiffStatus: TypesGen.Chat = {
...chat,
diff_status: diffStatus,
};
return [
{ key: chatKey(CHAT_ID), data: chatWithDiffStatus },
{ key: chatMessagesKey(CHAT_ID), data: messagesData },
{ key: chatsKey, data: [chatWithDiffStatus] },
{
key: chatDiffContentsKey(CHAT_ID),
data: {
chat_id: CHAT_ID,
diff: opts?.diffUrl ? sampleDiff : undefined,
pull_request_url: opts?.diffUrl,
} satisfies TypesGen.ChatDiffContents,
},
{
key: workspaceByIdKey(mockWorkspace.id),
data: mockWorkspace,
},
{ key: chatModelsKey, data: mockModelCatalog },
];
};
/**
* Wrap a chat stream event payload in the JSON string format that
+2 -7
View File
@@ -1,7 +1,6 @@
import { API, watchWorkspace } from "api/api";
import {
chat,
chatDiffStatus,
chatMessages,
chatModelConfigs,
chatModels,
@@ -635,10 +634,6 @@ const AgentDetail: FC = () => {
});
return () => socket.close();
}, [workspaceId, queryClient]);
const diffStatusQuery = useQuery({
...chatDiffStatus(agentId ?? ""),
enabled: Boolean(agentId),
});
const chatModelsQuery = useQuery(chatModels());
const chatModelConfigsQuery = useQuery(chatModelConfigs());
const sshConfigQuery = useQuery(deploymentSSHConfig());
@@ -769,7 +764,7 @@ const AgentDetail: FC = () => {
}, []);
// Extract PR number from diff status URL.
const prMatch = diffStatusQuery.data?.url?.match(/\/pull\/(\d+)/)?.[1];
const prMatch = chatQuery.data?.diff_status?.url?.match(/\/pull\/(\d+)/)?.[1];
const prNumber = prMatch ? Number(prMatch) : undefined;
// Compute an effective selected model by validating the user's
// explicit choice against the current model options, falling
@@ -1135,7 +1130,7 @@ const AgentDetail: FC = () => {
showSidebarPanel={showSidebarPanel}
onSetShowSidebarPanel={handleSetShowSidebarPanel}
prNumber={prNumber}
diffStatusData={diffStatusQuery.data}
diffStatusData={chatQuery.data?.diff_status}
gitWatcher={gitWatcher}
canOpenEditors={canOpenEditors}
canOpenWorkspace={canOpenWorkspace}
@@ -1,10 +1,11 @@
import { MockUserOwner } from "testHelpers/entities";
import { withAuthProvider, withDashboardProvider } from "testHelpers/storybook";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { API } from "api/api";
import type * as TypesGen from "api/typesGenerated";
import type { ChatDiffStatus } from "api/typesGenerated";
import type { ModelSelectorOption } from "components/ai-elements";
import { fn } from "storybook/test";
import { fn, spyOn } from "storybook/test";
import { reactRouterParameters } from "storybook-addon-remix-react-router";
import { createChatStore } from "./AgentDetail/ChatContext";
import {
@@ -207,6 +208,21 @@ export const WithSidebarPanel: Story = {
changed_files: 5,
} satisfies ChatDiffStatus,
},
beforeEach: () => {
spyOn(API, "getChatDiffContents").mockResolvedValue({
chat_id: AGENT_ID,
diff: `diff --git a/src/main.ts b/src/main.ts
index abc1234..def5678 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,3 +1,5 @@
import { start } from "./server";
+import { logger } from "./logger";
const port = 3000;
+logger.info("Starting server...");
start(port);`,
});
},
};
/** Left sidebar is collapsed. */
+1 -3
View File
@@ -3,7 +3,6 @@ import { getErrorMessage } from "api/errors";
import {
archiveChat,
chatDiffContentsKey,
chatDiffStatusKey,
chatKey,
chatModelConfigs,
chatModels,
@@ -389,7 +388,7 @@ const AgentsPage: FC = () => {
if (chatEvent.kind === "diff_status_change") {
void Promise.all([
queryClient.invalidateQueries({
queryKey: chatDiffStatusKey(updatedChat.id),
queryKey: chatKey(updatedChat.id),
}),
queryClient.invalidateQueries({
queryKey: chatDiffContentsKey(updatedChat.id),
@@ -397,7 +396,6 @@ const AgentsPage: FC = () => {
]);
return;
}
// Scope field updates by event kind so that
// status_change events (which may carry a stale title
// snapshot from before async title generation
@@ -111,7 +111,6 @@ const meta: Meta<typeof GitPanel> = {
),
],
beforeEach: () => {
spyOn(API, "getChatDiffStatus").mockResolvedValue(defaultDiffStatus);
spyOn(API, "getChatDiffContents").mockResolvedValue(defaultDiffContents);
},
};
@@ -131,7 +130,6 @@ export const PullRequestAndWorkingChanges: Story = {
repositories: new Map([["/home/coder/coder", makeRepo()]]),
},
beforeEach: () => {
spyOn(API, "getChatDiffStatus").mockResolvedValue(makePrStatus());
spyOn(API, "getChatDiffContents").mockResolvedValue({
...defaultDiffContents,
diff: sampleDiff,
@@ -157,17 +155,6 @@ export const DraftPullRequest: Story = {
]),
},
beforeEach: () => {
spyOn(API, "getChatDiffStatus").mockResolvedValue(
makePrStatus({
url: "https://github.com/coder/coder/pull/22950",
pull_request_title: "fix: resolve race condition in workspace builds",
pull_request_draft: true,
head_branch: "fix/race-condition",
additions: 142,
deletions: 38,
changed_files: 5,
}),
);
spyOn(API, "getChatDiffContents").mockResolvedValue({
...defaultDiffContents,
diff: sampleDiff,
@@ -190,17 +177,6 @@ export const MergedPullRequest: Story = {
}),
},
beforeEach: () => {
spyOn(API, "getChatDiffStatus").mockResolvedValue(
makePrStatus({
url: "https://github.com/coder/coder/pull/23000",
pull_request_title: "chore: update dependencies to latest",
pull_request_state: "merged",
head_branch: "chore/update-deps",
additions: 89,
deletions: 45,
changed_files: 3,
}),
);
spyOn(API, "getChatDiffContents").mockResolvedValue({
...defaultDiffContents,
diff: sampleDiff,
@@ -223,17 +199,6 @@ export const ClosedPullRequest: Story = {
}),
},
beforeEach: () => {
spyOn(API, "getChatDiffStatus").mockResolvedValue(
makePrStatus({
url: "https://github.com/coder/coder/pull/22800",
pull_request_title: "feat: experimental websocket transport",
pull_request_state: "closed",
head_branch: "feat/websocket-transport",
additions: 200,
deletions: 10,
changed_files: 4,
}),
);
spyOn(API, "getChatDiffContents").mockResolvedValue({
...defaultDiffContents,
diff: sampleDiff,
@@ -286,15 +251,6 @@ export const MultipleRepos: Story = {
]),
},
beforeEach: () => {
spyOn(API, "getChatDiffStatus").mockResolvedValue(
makePrStatus({
pull_request_title: "feat: multi-repo workspace support",
head_branch: "feat/multi-repo",
additions: 500,
deletions: 120,
changed_files: 8,
}),
);
spyOn(API, "getChatDiffContents").mockResolvedValue({
...defaultDiffContents,
diff: sampleDiff,
@@ -327,7 +283,6 @@ export const InlineCommentInput: Story = {
),
],
beforeEach: () => {
spyOn(API, "getChatDiffStatus").mockResolvedValue(makePrStatus());
spyOn(API, "getChatDiffContents").mockResolvedValue({
...defaultDiffContents,
diff: sampleDiff,
+4 -2
View File
@@ -278,6 +278,7 @@ export const GitPanel: FC<GitPanelProps> = ({
isExpanded={isExpanded}
chatInputRef={chatInputRef}
diffStyle={diffStyle}
diffStatus={remoteDiffStats}
/>
) : (
<LocalRepoContent
@@ -295,7 +296,6 @@ export const GitPanel: FC<GitPanelProps> = ({
</div>
);
};
// ---------------------------------------------------------------
// Remote view (branch/PR diff)
// ---------------------------------------------------------------
@@ -305,7 +305,8 @@ const RemoteContent: FC<{
isExpanded?: boolean;
chatInputRef?: RefObject<ChatMessageInputRef | null>;
diffStyle: DiffStyle;
}> = ({ prTab, isExpanded, chatInputRef, diffStyle }) => {
diffStatus?: ChatDiffStatus;
}> = ({ prTab, isExpanded, chatInputRef, diffStyle, diffStatus }) => {
if (!prTab) {
return (
<div className="flex h-full flex-col items-center justify-center p-8 text-center">
@@ -328,6 +329,7 @@ const RemoteContent: FC<{
isExpanded={isExpanded}
chatInputRef={chatInputRef}
diffStyle={diffStyle}
diffStatus={diffStatus}
/>
);
};
+14 -13
View File
@@ -1,6 +1,7 @@
import type { DiffLineAnnotation, FileDiffMetadata } from "@pierre/diffs";
import { parsePatchFiles } from "@pierre/diffs";
import { chatDiffContents, chatDiffStatus } from "api/queries/chats";
import { chatDiffContents } from "api/queries/chats";
import type * as TypesGen from "api/typesGenerated";
import { Button } from "components/Button/Button";
import {
ArrowLeftIcon,
@@ -247,6 +248,7 @@ interface RemoteDiffPanelProps {
isExpanded?: boolean;
chatInputRef?: RefObject<ChatMessageInputRef | null>;
diffStyle: DiffStyle;
diffStatus?: TypesGen.ChatDiffStatus;
}
export const RemoteDiffPanel: FC<RemoteDiffPanelProps> = ({
@@ -254,6 +256,7 @@ export const RemoteDiffPanel: FC<RemoteDiffPanelProps> = ({
isExpanded,
chatInputRef,
diffStyle,
diffStatus,
}) => {
// ---------------------------------------------------------------
// Comment / annotation state
@@ -268,10 +271,9 @@ export const RemoteDiffPanel: FC<RemoteDiffPanelProps> = ({
// ---------------------------------------------------------------
// Data fetching
// ---------------------------------------------------------------
const diffStatusQuery = useQuery(chatDiffStatus(chatId));
const diffContentsQuery = useQuery({
...chatDiffContents(chatId),
enabled: Boolean(diffStatusQuery.data?.url),
enabled: Boolean(diffStatus?.url),
});
const parsedFiles = useMemo(() => {
@@ -426,12 +428,12 @@ export const RemoteDiffPanel: FC<RemoteDiffPanelProps> = ({
// ---------------------------------------------------------------
// Header content
// ---------------------------------------------------------------
const pullRequestUrl = diffStatusQuery.data?.url;
const pullRequestUrl = diffStatus?.url;
const parsedPr = pullRequestUrl ? parsePullRequestUrl(pullRequestUrl) : null;
const prState = diffStatusQuery.data?.pull_request_state;
const prDraft = diffStatusQuery.data?.pull_request_draft;
const baseBranch = diffStatusQuery.data?.base_branch;
const headBranch = diffStatusQuery.data?.head_branch;
const prState = diffStatus?.pull_request_state;
const prDraft = diffStatus?.pull_request_draft;
const baseBranch = diffStatus?.base_branch;
const headBranch = diffStatus?.head_branch;
// ---------------------------------------------------------------
// Render
@@ -461,11 +463,10 @@ export const RemoteDiffPanel: FC<RemoteDiffPanelProps> = ({
</div>
<div className="ml-auto flex shrink-0 items-center gap-1.5">
<PullRequestStateBadge state={prState} draft={prDraft} />
{diffStatusQuery.data?.additions ||
diffStatusQuery.data?.deletions ? (
{diffStatus?.additions || diffStatus?.deletions ? (
<DiffStatBadge
additions={diffStatusQuery.data.additions}
deletions={diffStatusQuery.data.deletions}
additions={diffStatus.additions}
deletions={diffStatus.deletions}
/>
) : null}
<a
@@ -484,7 +485,7 @@ export const RemoteDiffPanel: FC<RemoteDiffPanelProps> = ({
parsedFiles={parsedFiles}
isExpanded={isExpanded}
diffStyle={diffStyle}
isLoading={diffContentsQuery.isLoading || diffStatusQuery.isLoading}
isLoading={diffContentsQuery.isLoading}
error={diffContentsQuery.isError ? diffContentsQuery.error : undefined}
onLineNumberClick={handleLineNumberClick}
onLineSelected={handleLineSelected}