fix(app): dismiss review feedback confirmation with a toast

The sent phase kept its confirmation over the diff indefinitely. Use the shared success toast and return the feedback workflow to idle after sending.
This commit is contained in:
Mohamed Boudra
2026-10-16 17:09:44 +02:00
parent 64693f21cf
commit d298141867
5 changed files with 29 additions and 26 deletions
@@ -310,7 +310,7 @@ async function sendFeedback(page: Page, count: number) {
}
async function expectFeedbackSent(page: Page, recipient: string) {
await expect(page.getByText(`Feedback sent to ${recipient}`, { exact: true })).toBeVisible();
await expect(page.getByTestId("app-toast")).toHaveText(`Feedback sent to ${recipient}`);
await expect(page.getByTestId("working-diff-panel")).toBeVisible();
}
@@ -340,6 +340,9 @@ test.describe("send review feedback", () => {
await expectFeedbackSent(page, "Composer diff stat");
await expectReviewAbsent(page, "Please simplify this.");
await captureFeedback(page, "single");
await expect(
page.getByText("Feedback sent to Composer diff stat", { exact: true }),
).toHaveCount(0);
});
await test.step("Return to the untouched composer draft", async () => {
await showWideLayout(page);
@@ -375,11 +378,7 @@ test.describe("send review feedback", () => {
).toBeDisabled();
expect(gate.requestCount()).toBe(1);
gate.accept();
await expect(
compactReviewSurface(page).getByText("Feedback sent to Composer diff stat", {
exact: true,
}),
).toBeVisible();
await expectFeedbackSent(page, "Composer diff stat");
});
} finally {
await workspace.cleanup();
@@ -172,8 +172,7 @@ describe("review feedback", () => {
makeComment("added"),
]);
expect(feedback.model.getState().phase).toEqual({
kind: "sent",
recipient: makeRecipient("one"),
kind: "idle",
});
});
it("clears unchanged sent comments while preserving additions", async () => {
+2 -3
View File
@@ -23,8 +23,7 @@ export type FeedbackPhase =
| { kind: "idle" }
| { kind: "choosing" }
| { kind: "sending"; recipient: FeedbackRecipient; commentCount: number }
| { kind: "failed"; message: string }
| { kind: "sent"; recipient: FeedbackRecipient };
| { kind: "failed"; message: string };
export interface ReviewFeedbackState {
phase: FeedbackPhase;
commentCount: number;
@@ -115,7 +114,7 @@ function createFeedbackView(
try {
await ports.send(recipient, attachment);
ports.clearSent(sentComments);
workflow.changePhase({ kind: "sent", recipient });
workflow.changePhase({ kind: "idle" });
} catch (error) {
workflow.changePhase({
kind: "failed",
+6 -13
View File
@@ -80,17 +80,6 @@ function OpenReviewFeedbackAction({
let notice: ReactNode = unavailableNotice;
if (state.phase.kind === "failed")
notice = <Text style={styles.error}>{state.phase.message}</Text>;
else if (state.phase.kind === "sent")
notice = (
<>
<SentNotice
recipient={state.phase.recipient}
serverId={serverId}
workspaceId={workspaceId}
/>
{unavailableNotice}
</>
);
return (
<>
{state.commentCount > 0 ? (
@@ -229,7 +218,7 @@ function RecipientRow({
);
}
function SentNotice({
export function FeedbackSentMessage({
recipient,
serverId,
workspaceId,
@@ -241,7 +230,7 @@ function SentNotice({
const { t } = useTranslation();
const render = useCallback(
(presentation: WorkspaceTabPresentation) => (
<Text style={styles.text}>
<Text style={styles.sentMessage}>
{t("review.feedback.sent", { recipient: presentation.label })}
</Text>
),
@@ -267,6 +256,10 @@ const styles = StyleSheet.create((theme) => ({
left: theme.spacing[4],
alignItems: "flex-end",
},
sentMessage: {
color: theme.colors.foreground,
fontSize: theme.fontSize.sm,
},
text: {
color: theme.colors.foreground,
fontSize: theme.fontSize.sm,
@@ -1,4 +1,4 @@
import { useEffect, useMemo, useRef, useSyncExternalStore } from "react";
import { createElement, useEffect, useMemo, useRef, useSyncExternalStore } from "react";
import {
useReviewDraftComments,
getReviewDraftComments,
@@ -22,6 +22,8 @@ import {
type FeedbackAttachment,
type FeedbackRecipient,
} from "./index";
import { useToast } from "@/contexts/toast-context";
import { FeedbackSentMessage } from "./surface";
const feedbackScope = createReviewFeedbackScope();
@@ -32,6 +34,7 @@ export function useReviewFeedback(input: {
attachment: FeedbackAttachment | null;
}) {
const { serverId, reviewDraftKey, workspaceId } = input;
const toast = useToast();
const isCompact = useIsCompactFormFactor();
const workspaceKey = workspaceId
? buildWorkspaceTabPersistenceKey({ serverId, workspaceId })
@@ -49,12 +52,14 @@ export function useReviewFeedback(input: {
connected,
attachment: input.attachment,
sendBehavior: settings.sendBehavior,
toast,
});
live.current = {
client,
connected,
attachment: input.attachment,
sendBehavior: settings.sendBehavior,
toast,
};
const model = useMemo(
() =>
@@ -85,12 +90,20 @@ export function useReviewFeedback(input: {
).turnId ?? undefined)
: undefined,
});
live.current.toast.show(
createElement(FeedbackSentMessage, {
recipient,
serverId,
workspaceId: workspaceId ?? "",
}),
{ variant: "success" },
);
},
clearSent: (sentComments) =>
clearSentReviewDraftComments({ key: reviewDraftKey, comments: sentComments }),
failedMessage: () => i18n.t("review.feedback.failed"),
}),
[reviewDraftKey, serverId, workspaceKey],
[reviewDraftKey, serverId, workspaceKey, workspaceId],
);
useEffect(() => {
model.refresh();