mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
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:
+10
-21
@@ -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
@@ -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".
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,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) },
|
||||
];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user