Skip to content

Commit f928fb0

Browse files
committed
feat(webapp): agent status for the standard toast; wake toast uses it
Third ToastUI variant: success's layout with the agent glyph and the Ask Trigger border. The wake toast drops its Callout composition for it.
1 parent 39e9ed3 commit f928fb0

3 files changed

Lines changed: 50 additions & 37 deletions

File tree

apps/webapp/app/components/dashboard-agent/WatchWakeToast.tsx

Lines changed: 22 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,9 @@
1212
* toasts use — so a wake looks like everything else the dashboard says, not like
1313
* a one-off panel.
1414
*/
15-
import { XMarkIcon } from "@heroicons/react/20/solid";
1615
import { toast } from "sonner";
1716
import { Button } from "~/components/primitives/Buttons";
18-
import { Callout } from "~/components/primitives/Callout";
19-
import { Header2 } from "~/components/primitives/Headers";
20-
import { Paragraph } from "~/components/primitives/Paragraph";
17+
import { ToastUI } from "~/components/primitives/Toast";
2118
import type { WatchObservedOutcome, WatchResolution } from "@internal/dashboard-agent-contracts";
2219
import { wakeResolution } from "./WakeBanner";
2320
import { presentResolvedWatch, WATCH_PRESENTATION_FALLBACK } from "./watch-presentation";
@@ -74,38 +71,28 @@ function WakeToastUI({
7471
message: string;
7572
onOpenChat: () => void;
7673
}) {
74+
// The standard toast, in its agent status: success's layout, the agent's
75+
// glyph and the Ask Trigger border.
7776
return (
78-
// Opaque base under the callout: a callout is translucent by design, and a
79-
// toast has to read over whatever page is behind it.
80-
<div className="self-end rounded-md bg-background-dimmed" style={{ width: TOAST_WIDTH }}>
81-
<Callout
82-
variant="agent"
83-
cta={
84-
<button
85-
className="-mr-1 -mt-1 rounded p-1 text-text-dimmed transition hover:text-text-bright"
86-
aria-label="Dismiss"
87-
onClick={() => toast.dismiss(t)}
88-
>
89-
<XMarkIcon className="size-4" />
90-
</button>
91-
}
92-
>
93-
<div className="flex flex-col items-start gap-1">
94-
<Header2 className="pt-0">{title}</Header2>
95-
<Paragraph variant="small/dimmed">{message}</Paragraph>
96-
<Button
97-
variant="secondary/small"
98-
className="mt-1"
99-
onClick={() => {
100-
onOpenChat();
101-
toast.dismiss(t);
102-
}}
103-
>
104-
Open chat
105-
</Button>
106-
</div>
107-
</Callout>
108-
</div>
77+
<ToastUI
78+
variant="agent"
79+
t={t}
80+
title={title}
81+
message={message}
82+
toastWidth={TOAST_WIDTH}
83+
actionNode={
84+
<Button
85+
variant="secondary/small"
86+
className="my-2 self-start"
87+
onClick={() => {
88+
onOpenChat();
89+
toast.dismiss(t);
90+
}}
91+
>
92+
Open chat
93+
</Button>
94+
}
95+
/>
10996
);
11097
}
11198

apps/webapp/app/components/primitives/Toast.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { EnvelopeIcon, ExclamationCircleIcon, XMarkIcon } from "@heroicons/react/20/solid";
22
import { CheckCircleIcon } from "@heroicons/react/24/solid";
3+
import { AgentMonoLogo } from "./AgentDotMatrix";
34
import { useSearchParams } from "@remix-run/react";
45
import { useEffect, useMemo } from "react";
56
import { useTypedLoaderData } from "remix-typedjson";
@@ -76,20 +77,28 @@ export function ToastUI({
7677
toastWidth = 356, // Default width, matches what sonner provides by default
7778
title,
7879
action,
80+
actionNode,
7981
}: {
80-
variant: "error" | "success";
82+
variant: "error" | "success" | "agent";
8183
message: string;
8284
t: string;
8385
toastWidth?: string | number;
8486
title?: string;
8587
action?: ToastMessageAction;
88+
/**
89+
* A caller-rendered action (a button with an onClick) for toasts shown from
90+
* client code — `action` stays the serializable server-message shape.
91+
*/
92+
actionNode?: React.ReactNode;
8693
}) {
8794
return (
8895
<div
8996
className={cn(
9097
"self-end rounded-md border border-grid-bright bg-background-dimmed",
9198
variant === "success" && "border-success",
92-
variant === "error" && "border-error"
99+
variant === "error" && "border-error",
100+
// The agent's toast wears the Ask Trigger button's border.
101+
variant === "agent" && "border-[#41FF54]/25 light:border-success/60"
93102
)}
94103
style={{
95104
width: toastWidth,
@@ -100,6 +109,10 @@ export function ToastUI({
100109
>
101110
{variant === "success" ? (
102111
<CheckCircleIcon className={cn("size-4 min-w-4 text-success", title && "mt-1")} />
112+
) : variant === "agent" ? (
113+
<span className={cn("flex size-4 min-w-4 items-center", title && "mt-1")}>
114+
<AgentMonoLogo size={16} decorative />
115+
</span>
103116
) : (
104117
<ExclamationCircleIcon className={cn("size-4 min-w-4 text-error", title && "mt-1")} />
105118
)}
@@ -112,6 +125,7 @@ export function ToastUI({
112125
{message}
113126
</Paragraph>
114127
<Action action={action} toastId={t} className="my-2" />
128+
{actionNode}
115129
</div>
116130
<button
117131
className={cn(

apps/webapp/app/routes/storybook.toast/route.tsx

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,18 @@ export default function Story() {
1717
message="This is a long error message that wraps over multiple lines so we can test the UI."
1818
t="-"
1919
/>
20+
<ToastUI variant="agent" message="Agent info UI" t="-" />
21+
<ToastUI
22+
variant="agent"
23+
title="Watch update"
24+
message="Error error_c4b4a797 happened again — 1 new occurrence since the watch started."
25+
t="-"
26+
actionNode={
27+
<Button variant="secondary/small" className="my-2 self-start">
28+
Open chat
29+
</Button>
30+
}
31+
/>
2032
<br />
2133
<Button
2234
variant="primary/medium"

0 commit comments

Comments
 (0)