LocalVersionPopover.tsx201 lines · main
1import dayjs from 'dayjs'
2import {
3 Badge,
4 Button,
5 Dialog,
6 DialogContent,
7 DialogHeader,
8 DialogSection,
9 DialogTitle,
10 DialogTrigger,
11 Popover,
12 PopoverContent,
13 PopoverSeparator,
14 PopoverTrigger,
15 Tabs_Shadcn_,
16 TabsContent_Shadcn_,
17 TabsList_Shadcn_,
18 TabsTrigger_Shadcn_,
19} from 'ui'
20import { Admonition } from 'ui-patterns/admonition'
21import { SimpleCodeBlock } from 'ui-patterns/SimpleCodeBlock'
22
23import { getSemver, semverGte, semverLte } from './LocalVersionPopover.utils'
24import { DocsButton } from '@/components/ui/DocsButton'
25import { InlineLink } from '@/components/ui/InlineLink'
26import { useCLIReleaseVersionQuery } from '@/data/misc/cli-release-version-query'
27import { DOCS_URL } from '@/lib/constants'
28import { useTrack } from '@/lib/telemetry/track'
29
30export const LocalVersionPopover = () => {
31 const track = useTrack()
32 const { data, isSuccess } = useCLIReleaseVersionQuery()
33 const { current: currentCliVersion, latest: latestCliVersion } = data || {}
34 const hasLatestCLIVersion = isSuccess && !!latestCliVersion
35
36 const current = getSemver(currentCliVersion)
37 const latest = getSemver(latestCliVersion)
38
39 const hasUpdate =
40 !!current && !!latest
41 ? currentCliVersion !== latestCliVersion && semverLte(current, latest)
42 : false
43 const isBeta =
44 !!current && !!latest && currentCliVersion !== latestCliVersion && semverGte(current, latest)
45
46 const approximateNextRelease = !!data?.published_at
47 ? dayjs(data?.published_at).utc().add(14, 'day').format('DD MMM YYYY')
48 : undefined
49
50 if (!isSuccess || !currentCliVersion) return null
51
52 return (
53 <Popover
54 onOpenChange={(open) => {
55 if (open) track('header_local_version_popover_opened')
56 }}
57 >
58 <PopoverTrigger className="flex items-center">
59 <Badge variant={isBeta ? 'warning' : hasUpdate ? 'success' : 'default'}>
60 {isBeta ? 'Beta' : hasUpdate ? 'Update available' : 'Latest'}
61 </Badge>
62 </PopoverTrigger>
63 <PopoverContent align="end" className="w-80 px-0">
64 {hasLatestCLIVersion ? (
65 !isBeta && hasUpdate ? (
66 <div className="px-4 mb-3">
67 <p className="text-sm mb-2">A new version of Briven CLI is available:</p>
68 <Tabs_Shadcn_ defaultValue="macos">
69 <TabsList_Shadcn_ className="mt-2">
70 <TabsTrigger_Shadcn_ className="px-2 text-xs" value="macos">
71 macOS
72 </TabsTrigger_Shadcn_>
73 <TabsTrigger_Shadcn_ className="px-2 text-xs" value="windows">
74 Windows
75 </TabsTrigger_Shadcn_>
76 <TabsTrigger_Shadcn_ className="px-2 text-xs" value="linux">
77 Linux
78 </TabsTrigger_Shadcn_>
79 <TabsTrigger_Shadcn_ className="px-2 text-xs" value="npm">
80 npm / Bun
81 </TabsTrigger_Shadcn_>
82 </TabsList_Shadcn_>
83 <TabsContent_Shadcn_ className="mt-2 text-xs" value="macos">
84 <SimpleCodeBlock parentClassName="bg-selection rounded-sm px-2!">
85 brew upgrade briven
86 </SimpleCodeBlock>
87 </TabsContent_Shadcn_>
88 <TabsContent_Shadcn_ className="mt-2 text-xs" value="windows">
89 <SimpleCodeBlock parentClassName="bg-selection rounded-sm px-2!">
90 scoop update briven
91 </SimpleCodeBlock>
92 </TabsContent_Shadcn_>
93 <TabsContent_Shadcn_ className="mt-2 text-xs" value="linux">
94 <SimpleCodeBlock parentClassName="bg-selection rounded-sm px-2!">
95 brew upgrade briven
96 </SimpleCodeBlock>
97 </TabsContent_Shadcn_>
98 <TabsContent_Shadcn_ className="mt-2 text-xs" value="npm">
99 <SimpleCodeBlock parentClassName="bg-selection rounded-sm px-2!">
100 npm update briven --save-dev
101 </SimpleCodeBlock>
102 </TabsContent_Shadcn_>
103 </Tabs_Shadcn_>
104 </div>
105 ) : (
106 <div className="px-4 mb-3">
107 {isBeta ? (
108 <p className="text-sm">You're on the Beta version of Briven CLI</p>
109 ) : (
110 <p className="text-sm">You're on the latest version of Briven CLI</p>
111 )}
112 </div>
113 )
114 ) : null}
115
116 <div className="flex flex-col gap-y-2 px-4">
117 <p className="text-xs text-foreground-lighter">
118 All available release versions of the CLI can be found on our{' '}
119 <InlineLink href="https://github.com/briven/cli/releases">
120 GitHub repository
121 </InlineLink>
122 .
123 </p>
124 </div>
125
126 <div className="flex items-center gap-x-2 mt-3 px-4">
127 <Dialog>
128 <DialogTrigger asChild>
129 <Button type="default">Release schedule</Button>
130 </DialogTrigger>
131 <DialogContent>
132 <DialogHeader className="border-b">
133 <DialogTitle>Stable release schedule</DialogTitle>
134 </DialogHeader>
135 <DialogSection className="flex flex-col gap-y-3">
136 <div className="flex flex-col gap-y-2">
137 <p className="text-foreground-lighter text-xs font-mono uppercase">
138 Approximate next release: {approximateNextRelease}
139 </p>
140 <p className="text-sm">
141 Briven CLI releases follows a two-week schedule, with stable updates available
142 through the{' '}
143 <InlineLink
144 href={`${DOCS_URL}/guides/local-development/cli/getting-started?queryGroups=platform&platform=linux#updating-the-briven-cli`}
145 >
146 CLI
147 </InlineLink>
148 .
149 </p>
150 </div>
151 <Admonition
152 type="default"
153 title="Beta Releases"
154 description="Beta releases are also available between stable releases through the Beta version of the CLI, which might be helpful if you are waiting for a specific fix."
155 >
156 <p className="mt-2!">If you'd like to try, we recommend doing so via npm:</p>
157 <div className="flex items-center bg-surface-200 py-1 px-2 rounded-sm mt-2 mb-1">
158 <SimpleCodeBlock parentClassName="bg-surface-200">
159 npm i briven@beta --save-dev
160 </SimpleCodeBlock>
161 </div>
162 {
163 <p className="text-sm text-foreground-lighter">
164 Latest Beta version: <span>{data.beta}</span>
165 </p>
166 }
167 <DocsButton
168 href={`${DOCS_URL}/guides/local-development/cli/getting-started?queryGroups=platform&platform=linux#using-beta-version`}
169 className="no-underline! mt-2"
170 />
171 </Admonition>
172 </DialogSection>
173 </DialogContent>
174 </Dialog>
175 <Button type="default" asChild>
176 <a
177 target="_blank"
178 rel="noreferrer noopener"
179 href={`${DOCS_URL}/guides/local-development/cli/getting-started?queryGroups=platform&platform=linux`}
180 >
181 CLI Docs
182 </a>
183 </Button>
184 </div>
185 <PopoverSeparator className="my-4" />
186 <div className="flex items-center gap-x-4 px-4">
187 <div className="flex flex-col gap-y-1">
188 <p className="text-xs">Current version:</p>
189 <p className="text-sm font-mono">{currentCliVersion}</p>
190 </div>
191 {hasLatestCLIVersion && hasUpdate && !isBeta && (
192 <div className="flex flex-col gap-y-1">
193 <p className="text-xs">Available version:</p>
194 <p className="text-sm font-mono">{latestCliVersion}</p>
195 </div>
196 )}
197 </div>
198 </PopoverContent>
199 </Popover>
200 )
201}