Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

Commit d07a09a

Browse files
committed
restore update banner button and revamp modal
1 parent 09e1b84 commit d07a09a

4 files changed

Lines changed: 131 additions & 62 deletions

File tree

packages/ui/src/features/sidebar/components/UpdateBanner.tsx

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import { ArrowsClockwise, Gift, Spinner } from "@phosphor-icons/react";
2+
import { useHostTRPC } from "@posthog/host-router/react";
23
import { useUpdateModalStore } from "@posthog/ui/features/updates/updateModalStore";
34
import {
45
useInstallUpdate,
56
useUpdateView,
67
} from "@posthog/ui/features/updates/updateStore";
78
import { Box } from "@radix-ui/themes";
9+
import { useMutation } from "@tanstack/react-query";
810
import { AnimatePresence, motion } from "framer-motion";
911

1012
interface UpdateBannerProps {
@@ -16,6 +18,10 @@ export function UpdateBanner({ variant = "sidebar" }: UpdateBannerProps) {
1618
useUpdateView();
1719
const installUpdate = useInstallUpdate();
1820
const openModal = useUpdateModalStore((state) => state.open);
21+
const hostTRPC = useHostTRPC();
22+
const downloadMutation = useMutation(
23+
hostTRPC.updates.download.mutationOptions(),
24+
);
1925

2026
const isVisible =
2127
isEnabled &&
@@ -96,21 +102,29 @@ export function UpdateBanner({ variant = "sidebar" }: UpdateBannerProps) {
96102
<AnimatePresence mode="wait">
97103
{status === "available" && (
98104
<BannerCard key="available">
99-
<button
100-
type="button"
101-
onClick={openModal}
102-
className="flex w-full items-center gap-3 rounded-md border border-[var(--green-a5)] bg-[var(--green-a3)] px-3 py-2.5 text-left text-[13px] text-[var(--green-11)] transition-colors hover:bg-[var(--green-a4)]"
103-
>
105+
<div className="flex w-full items-center gap-3 rounded-md border border-[var(--green-a5)] bg-[var(--green-a3)] px-3 py-2.5 text-[13px] text-[var(--green-11)]">
104106
<Gift size={20} weight="duotone" className="shrink-0" />
105-
<div className="flex min-w-0 flex-1 flex-col gap-0.5">
107+
<button
108+
type="button"
109+
onClick={openModal}
110+
className="flex min-w-0 flex-1 flex-col gap-0.5 text-left"
111+
>
106112
<span className="font-medium">Update available</span>
107113
<span className="text-[11px] text-[var(--green-a11)]">
108114
{availableVersion
109115
? `Version ${availableVersion}`
110-
: "Click to view details"}
116+
: "View details"}
111117
</span>
112-
</div>
113-
</button>
118+
</button>
119+
<button
120+
type="button"
121+
className="shrink-0 rounded-2 bg-[var(--green-a4)] px-2 py-1 font-medium text-[12px] text-[var(--green-11)] transition-colors hover:bg-[var(--green-a5)] disabled:opacity-60"
122+
onClick={() => downloadMutation.mutate(undefined)}
123+
disabled={downloadMutation.isPending}
124+
>
125+
Download
126+
</button>
127+
</div>
114128
</BannerCard>
115129
)}
116130

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import type { CategorizedNotes } from "@posthog/ui/features/updates/releaseNotes";
2+
import { Flex } from "@radix-ui/themes";
3+
4+
function ReleaseSection({ title, items }: { title: string; items: string[] }) {
5+
if (items.length === 0) return null;
6+
return (
7+
<Flex direction="column" gap="1">
8+
<span className="font-medium text-[11px] text-gray-10 uppercase tracking-wide">
9+
{title}
10+
</span>
11+
<ul className="m-0 flex list-none flex-col gap-1.5 p-0">
12+
{items.map((item) => (
13+
<li
14+
key={`${title}-${item}`}
15+
className="flex gap-2 text-[13px] text-gray-12 leading-relaxed"
16+
>
17+
<span className="mt-px select-none text-gray-9"></span>
18+
<span className="min-w-0">{item}</span>
19+
</li>
20+
))}
21+
</ul>
22+
</Flex>
23+
);
24+
}
25+
26+
export function ReleaseNotesSections({ notes }: { notes: CategorizedNotes }) {
27+
return (
28+
<Flex direction="column" gap="3">
29+
<ReleaseSection title="Improved" items={notes.improved} />
30+
<ReleaseSection title="Fixed" items={notes.fixed} />
31+
</Flex>
32+
);
33+
}

packages/ui/src/features/updates/UpdateAvailableModal.tsx

Lines changed: 73 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
import { ArrowDown, ArrowsClockwise } from "@phosphor-icons/react";
1+
import {
2+
ArrowDown,
3+
ArrowRight,
4+
ArrowsClockwise,
5+
Gift,
6+
} from "@phosphor-icons/react";
27
import { useHostTRPC } from "@posthog/host-router/react";
38
import { MarkdownRenderer } from "@posthog/ui/features/editor/components/MarkdownRenderer";
9+
import { ReleaseNotesSections } from "@posthog/ui/features/updates/ReleaseNotesSections";
10+
import { parseReleaseNotes } from "@posthog/ui/features/updates/releaseNotes";
411
import { useUpdateModalStore } from "@posthog/ui/features/updates/updateModalStore";
512
import {
613
useInstallUpdate,
@@ -41,48 +48,82 @@ export function UpdateAvailableModal() {
4148
const downloadMutation = useMutation(
4249
hostTRPC.updates.download.mutationOptions(),
4350
);
51+
const { data: releasesData } = useQuery({
52+
...hostTRPC.githubReleases.list.queryOptions(),
53+
enabled: isOpen,
54+
});
4455

4556
const targetVersion = version ?? availableVersion;
4657
const percent = Math.round(downloadPercent ?? 0);
4758
const isDownloading = status === "downloading";
4859
const isReady = status === "ready" || status === "installing";
4960

61+
const releases = releasesData?.releases ?? [];
62+
const latestRelease = releases.find((r) => !r.isPrerelease) ?? releases[0];
63+
const noteRelease =
64+
releases.find((r) => r.version === targetVersion) ?? latestRelease;
65+
const rawNotes = noteRelease?.notes?.trim()
66+
? noteRelease.notes
67+
: releaseNotes;
68+
const parsedNotes = rawNotes ? parseReleaseNotes(rawNotes) : null;
69+
const hasParsedNotes =
70+
!!parsedNotes &&
71+
(parsedNotes.improved.length > 0 || parsedNotes.fixed.length > 0);
72+
5073
return (
5174
<Dialog.Root
5275
open={isOpen}
5376
onOpenChange={(open) => {
5477
if (!open) close();
5578
}}
5679
>
57-
<Dialog.Content maxWidth="460px">
58-
<Flex direction="column" gap="3">
59-
<Flex direction="column" gap="1">
60-
<Dialog.Title className="mb-0">Update Available</Dialog.Title>
61-
<Dialog.Description>
62-
<Text color="gray" size="2">
63-
{targetVersion
64-
? `PostHog Code ${targetVersion} is ready`
65-
: "A new version is ready"}
66-
</Text>
67-
</Dialog.Description>
80+
<Dialog.Content maxWidth="440px">
81+
<Flex direction="column" gap="4">
82+
<Flex align="center" gap="3">
83+
<Flex
84+
align="center"
85+
justify="center"
86+
className="size-10 shrink-0 rounded-full bg-accent-3 text-accent-11"
87+
>
88+
<Gift size={22} weight="duotone" />
89+
</Flex>
90+
<Flex direction="column">
91+
<Dialog.Title className="mb-0" size="4">
92+
{isReady ? "Update ready" : "Update available"}
93+
</Dialog.Title>
94+
<Dialog.Description>
95+
<Text color="gray" size="2">
96+
{targetVersion
97+
? `PostHog Code ${targetVersion}`
98+
: "A new version is available"}
99+
</Text>
100+
</Dialog.Description>
101+
</Flex>
68102
</Flex>
69103

70104
{currentVersion ? (
71105
<Flex
72106
align="center"
73-
gap="2"
74-
className="rounded-3 border border-gray-5 bg-gray-2 px-3 py-2"
107+
justify="center"
108+
gap="3"
109+
className="rounded-3 border border-gray-5 bg-gray-2 px-3 py-2.5"
75110
>
76-
<Text size="2" color="gray">
77-
You're currently on version
78-
</Text>
79-
<Code variant="soft">{currentVersion}</Code>
111+
<Code variant="soft" color="gray">
112+
{currentVersion}
113+
</Code>
114+
<ArrowRight size={14} className="shrink-0 text-gray-9" />
115+
<Code variant="soft">{targetVersion ?? "latest"}</Code>
80116
</Flex>
81117
) : null}
82118

83-
{releaseNotes ? (
84-
<Flex direction="column" gap="1">
85-
<Text size="2" weight="medium" color="gray">
119+
{hasParsedNotes || rawNotes ? (
120+
<Flex direction="column" gap="2">
121+
<Text
122+
size="1"
123+
weight="medium"
124+
color="gray"
125+
className="uppercase tracking-wide"
126+
>
86127
Release notes
87128
</Text>
88129
<ScrollArea
@@ -91,7 +132,11 @@ export function UpdateAvailableModal() {
91132
style={{ maxHeight: 240 }}
92133
>
93134
<div className="pr-3">
94-
<MarkdownRenderer content={releaseNotes} />
135+
{hasParsedNotes && parsedNotes ? (
136+
<ReleaseNotesSections notes={parsedNotes} />
137+
) : rawNotes ? (
138+
<MarkdownRenderer content={rawNotes} />
139+
) : null}
95140
</div>
96141
</ScrollArea>
97142
</Flex>
@@ -111,27 +156,28 @@ export function UpdateAvailableModal() {
111156
</Flex>
112157
) : null}
113158

114-
<Flex justify="end" align="center" gap="3" mt="1">
115-
<Button variant="ghost" color="gray" onClick={close}>
159+
<Flex justify="end" align="center" gap="2" mt="1">
160+
<Button variant="soft" color="gray" size="2" onClick={close}>
116161
Later
117162
</Button>
118163
{isReady ? (
119-
<Button onClick={() => void installUpdate()}>
164+
<Button size="2" onClick={() => void installUpdate()}>
120165
<ArrowsClockwise size={16} />
121166
Restart to update
122167
</Button>
123168
) : isDownloading ? (
124-
<Button disabled>
169+
<Button size="2" disabled>
125170
<ArrowsClockwise size={16} className="animate-spin" />
126171
Downloading...
127172
</Button>
128173
) : (
129174
<Button
175+
size="2"
130176
onClick={() => downloadMutation.mutate(undefined)}
131177
disabled={downloadMutation.isPending}
132178
>
133179
<ArrowDown size={16} />
134-
Download Update
180+
Download update
135181
</Button>
136182
)}
137183
</Flex>

packages/ui/src/features/updates/WhatsNewModal.tsx

Lines changed: 2 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { X } from "@phosphor-icons/react";
22
import { useHostTRPC } from "@posthog/host-router/react";
3+
import { ReleaseNotesSections } from "@posthog/ui/features/updates/ReleaseNotesSections";
34
import {
45
groupReleases,
56
mergeReleaseNotes,
@@ -16,28 +17,6 @@ import {
1617
} from "@radix-ui/themes";
1718
import { useQuery } from "@tanstack/react-query";
1819

19-
function ReleaseSection({ title, items }: { title: string; items: string[] }) {
20-
if (items.length === 0) return null;
21-
return (
22-
<Flex direction="column" gap="1">
23-
<span className="font-medium text-[11px] text-gray-10 uppercase tracking-wide">
24-
{title}
25-
</span>
26-
<ul className="m-0 flex list-none flex-col gap-1.5 p-0">
27-
{items.map((item) => (
28-
<li
29-
key={`${title}-${item}`}
30-
className="flex gap-2 text-[13px] text-gray-12 leading-relaxed"
31-
>
32-
<span className="mt-px select-none text-gray-9"></span>
33-
<span className="min-w-0">{item}</span>
34-
</li>
35-
))}
36-
</ul>
37-
</Flex>
38-
);
39-
}
40-
4120
function ChangelogSkeleton() {
4221
return (
4322
<Flex direction="column" gap="5">
@@ -155,10 +134,7 @@ export function WhatsNewModal() {
155134
No notable changes.
156135
</Text>
157136
) : (
158-
<Flex direction="column" gap="3">
159-
<ReleaseSection title="Improved" items={improved} />
160-
<ReleaseSection title="Fixed" items={fixed} />
161-
</Flex>
137+
<ReleaseNotesSections notes={{ improved, fixed }} />
162138
)}
163139
</Flex>
164140
);

0 commit comments

Comments
 (0)