@tscircuit/fake-snippets 0.0.106 → 0.0.108

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CLAUDE.md +92 -0
  2. package/api/generated-index.js +84 -25
  3. package/biome.json +7 -1
  4. package/bun-tests/fake-snippets-api/routes/package_builds/get.test.ts +0 -15
  5. package/bun-tests/fake-snippets-api/routes/package_builds/list.test.ts +0 -12
  6. package/dist/bundle.js +360 -434
  7. package/dist/index.d.ts +26 -15
  8. package/dist/index.js +40 -21
  9. package/dist/schema.d.ts +32 -24
  10. package/dist/schema.js +7 -5
  11. package/fake-snippets-api/lib/db/db-client.ts +19 -1
  12. package/fake-snippets-api/lib/db/schema.ts +6 -3
  13. package/fake-snippets-api/lib/db/seed.ts +23 -12
  14. package/fake-snippets-api/lib/public-mapping/public-map-package-build.ts +0 -3
  15. package/fake-snippets-api/lib/public-mapping/public-map-package-release.ts +3 -0
  16. package/fake-snippets-api/routes/api/package_builds/list.ts +0 -1
  17. package/package.json +3 -2
  18. package/src/App.tsx +27 -9
  19. package/src/components/FileSidebar.tsx +14 -159
  20. package/src/components/PackageBreadcrumb.tsx +111 -0
  21. package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +1 -1
  22. package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +18 -2
  23. package/src/components/ViewPackagePage/components/sidebar-releases-section.tsx +18 -8
  24. package/src/components/preview/BuildsList.tsx +84 -167
  25. package/src/components/preview/ConnectedPackagesList.tsx +92 -62
  26. package/src/components/preview/ConnectedRepoOverview.tsx +171 -155
  27. package/src/components/preview/{ConnectedRepoDashboard.tsx → PackageReleasesDashboard.tsx} +31 -69
  28. package/src/components/preview/index.tsx +20 -154
  29. package/src/hooks/use-package-builds.ts +0 -48
  30. package/src/hooks/use-package-release-by-id-or-version.ts +36 -0
  31. package/src/hooks/use-package-release.ts +32 -0
  32. package/src/index.css +24 -0
  33. package/src/lib/utils/isUuid.ts +5 -0
  34. package/src/lib/utils/transformFilesToTreeData.tsx +195 -0
  35. package/src/pages/404.tsx +3 -5
  36. package/src/pages/preview-release.tsx +269 -0
  37. package/src/pages/release-builds.tsx +99 -0
  38. package/src/pages/release-detail.tsx +120 -0
  39. package/src/pages/releases.tsx +55 -0
  40. package/fake-snippets-api/routes/api/package_builds/latest.ts +0 -109
  41. package/src/hooks/use-snippets-base-api-url.ts +0 -3
  42. package/src/pages/preview-build.tsx +0 -380
  43. package/src/pages/view-connected-repo.tsx +0 -49
@@ -2,15 +2,7 @@ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
2
2
  import { Badge } from "@/components/ui/badge"
3
3
  import { Button } from "@/components/ui/button"
4
4
  import { Skeleton } from "@/components/ui/skeleton"
5
- import {
6
- Clock,
7
- GitBranch,
8
- AlertCircle,
9
- CheckCircle,
10
- Loader2,
11
- MoreHorizontal,
12
- GitCommit,
13
- } from "lucide-react"
5
+ import { GitBranch, MoreHorizontal, GitCommit } from "lucide-react"
14
6
  import {
15
7
  DropdownMenu,
16
8
  DropdownMenuContent,
@@ -28,63 +20,52 @@ import {
28
20
  import { getBuildStatus, StatusIcon } from "."
29
21
  import { formatTimeAgo } from "@/lib/utils/formatTimeAgo"
30
22
  import { Package, PackageBuild } from "fake-snippets-api/lib/db/schema"
31
- import { usePackageBuilds } from "@/hooks/use-package-builds"
32
- import { usePackageReleaseById } from "@/hooks/use-package-release"
23
+ import { usePackageReleasesByPackageId } from "@/hooks/use-package-release"
33
24
  import { useQueries } from "react-query"
34
25
  import { useAxios } from "@/hooks/use-axios"
26
+ import { useLocation } from "wouter"
35
27
 
36
- export const BuildsList = ({
37
- pkg,
38
- onSelectBuild,
39
- }: {
40
- pkg: Package
41
- onSelectBuild?: (build: PackageBuild) => void
42
- }) => {
43
- const { data: builds, isLoading } = usePackageBuilds({
44
- package_id: pkg.package_id,
45
- })
28
+ export const BuildsList = ({ pkg }: { pkg: Package }) => {
29
+ const { data: releases, isLoading: isLoadingReleases } =
30
+ usePackageReleasesByPackageId(pkg.package_id)
46
31
  const axios = useAxios()
32
+ const [, setLocation] = useLocation()
33
+ // Get the latest build for each release to show status
34
+ const latestBuildQueries = useQueries(
35
+ (releases || [])
36
+ .filter((release) => release.latest_package_build_id)
37
+ .map((release) => ({
38
+ queryKey: ["packageBuild", release.latest_package_build_id],
39
+ queryFn: async () => {
40
+ if (!release.latest_package_build_id) return null
41
+ const { data } = await axios.get("/package_builds/get", {
42
+ params: { package_build_id: release.latest_package_build_id },
43
+ })
44
+ return data.package_build
45
+ },
46
+ enabled: Boolean(release.latest_package_build_id),
47
+ retry: false,
48
+ refetchOnWindowFocus: false,
49
+ })),
50
+ )
47
51
 
48
- const uniqueReleaseIds = [
49
- ...new Set(
50
- builds?.map((build) => build.package_release_id).filter(Boolean) || [],
51
- ),
52
- ]
52
+ const isLoading =
53
+ isLoadingReleases || latestBuildQueries.some((q) => q.isLoading)
53
54
 
54
- const packageReleaseQueries = useQueries(
55
- uniqueReleaseIds.map((releaseId) => ({
56
- queryKey: ["packageRelease", { package_release_id: releaseId }],
57
- queryFn: async () => {
58
- const { data } = await axios.post("/package_releases/get", {
59
- package_release_id: releaseId,
60
- })
61
- return data.package_release
62
- },
63
- enabled: Boolean(releaseId),
64
- retry: false,
65
- refetchOnWindowFocus: false,
66
- })),
67
- )
55
+ // Create a map of release ID to latest build for easy access
56
+ const latestBuildsMap = new Map<string, PackageBuild>()
68
57
 
69
- const packageReleasesMap = new Map()
70
- packageReleaseQueries.forEach((query, index) => {
71
- if (query.data) {
72
- packageReleasesMap.set(uniqueReleaseIds[index], query.data)
58
+ latestBuildQueries.forEach((query, index) => {
59
+ if (query.data && releases?.[index]) {
60
+ latestBuildsMap.set(releases[index].package_release_id, query.data)
73
61
  }
74
62
  })
75
63
  return (
76
64
  <>
77
65
  <div className="space-y-6">
78
- <div className="flex items-center justify-between">
79
- <div>
80
- <h2 className="text-2xl font-bold text-gray-900">Builds</h2>
81
- <p className="text-gray-600">Manage and monitor your builds</p>
82
- </div>
83
- </div>
84
-
85
66
  <Card>
86
67
  <CardHeader>
87
- <CardTitle>Recent Deployments</CardTitle>
68
+ <CardTitle>Recent Releases</CardTitle>
88
69
  </CardHeader>
89
70
  <CardContent>
90
71
  <div className="overflow-x-auto [&>div]:no-scrollbar">
@@ -92,10 +73,10 @@ export const BuildsList = ({
92
73
  <TableHeader>
93
74
  <TableRow>
94
75
  <TableHead>Status</TableHead>
95
- <TableHead>Build ID</TableHead>
76
+ <TableHead>Release ID</TableHead>
77
+ <TableHead>Version</TableHead>
96
78
  <TableHead>Branch/PR</TableHead>
97
- <TableHead>Commit</TableHead>
98
- <TableHead>Author</TableHead>
79
+ <TableHead>Latest Build</TableHead>
99
80
  <TableHead>Created</TableHead>
100
81
  <TableHead>Actions</TableHead>
101
82
  </TableRow>
@@ -127,16 +108,20 @@ export const BuildsList = ({
127
108
  </TableCell>
128
109
  </TableRow>
129
110
  ))
130
- : builds?.map((build) => {
131
- const { status, label } = getBuildStatus(build)
132
- const packageRelease = packageReleasesMap.get(
133
- build.package_release_id,
111
+ : releases?.map((release) => {
112
+ const latestBuild = latestBuildsMap.get(
113
+ release.package_release_id,
134
114
  )
115
+ const { status, label } = getBuildStatus(latestBuild)
135
116
  return (
136
117
  <TableRow
137
- key={build.package_build_id}
118
+ key={release.package_release_id}
138
119
  className="cursor-pointer hover:bg-gray-50 no-scrollbar"
139
- onClick={() => onSelectBuild?.(build)}
120
+ onClick={() => {
121
+ setLocation(
122
+ `/${pkg.name}/releases/${release.package_release_id}`,
123
+ )
124
+ }}
140
125
  >
141
126
  <TableCell>
142
127
  <div className="flex items-center gap-2">
@@ -157,38 +142,45 @@ export const BuildsList = ({
157
142
  </TableCell>
158
143
  <TableCell>
159
144
  <code className="text-sm bg-gray-100 px-2 py-1 rounded">
160
- {build.package_build_id.slice(-8)}
145
+ {release.package_release_id.slice(-8)}
161
146
  </code>
162
147
  </TableCell>
148
+ <TableCell>
149
+ <span className="text-sm font-medium">
150
+ {release.version ||
151
+ "v" + release.package_release_id.slice(-6)}
152
+ </span>
153
+ </TableCell>
163
154
  <TableCell>
164
155
  <div className="flex items-center gap-2">
165
- {packageRelease?.is_pr_preview ? (
156
+ {release.is_pr_preview ? (
166
157
  <GitBranch className="w-3 h-3 text-gray-500" />
167
158
  ) : (
168
159
  <GitCommit className="w-3 h-3 text-gray-500" />
169
160
  )}
170
161
  <Badge variant="outline" className="text-xs">
171
- {packageRelease?.is_pr_preview
172
- ? `#${packageRelease.github_pr_number}`
173
- : packageRelease?.branch_name || "main"}
162
+ {release.is_pr_preview
163
+ ? `#${release.github_pr_number}`
164
+ : "main"}
174
165
  </Badge>
175
166
  </div>
176
167
  </TableCell>
177
168
  <TableCell>
178
169
  <div className="max-w-xs">
179
- <p className="text-sm font-medium truncate">
180
- {build.commit_message || "No commit message"}
181
- </p>
170
+ {latestBuild ? (
171
+ <p className="text-sm text-gray-600">
172
+ {formatTimeAgo(latestBuild.created_at)}
173
+ </p>
174
+ ) : (
175
+ <p className="text-sm text-gray-400">
176
+ No builds
177
+ </p>
178
+ )}
182
179
  </div>
183
180
  </TableCell>
184
181
  <TableCell>
185
182
  <span className="text-sm text-gray-600">
186
- {build.commit_author || "Unknown"}
187
- </span>
188
- </TableCell>
189
- <TableCell>
190
- <span className="text-sm text-gray-600">
191
- {formatTimeAgo(build.created_at)}
183
+ {formatTimeAgo(release.created_at)}
192
184
  </span>
193
185
  </TableCell>
194
186
  <TableCell>
@@ -205,14 +197,27 @@ export const BuildsList = ({
205
197
  </DropdownMenuTrigger>
206
198
  <DropdownMenuContent align="end">
207
199
  <DropdownMenuItem
208
- onClick={() => onSelectBuild?.(build)}
200
+ onClick={() => {
201
+ window.location.href = `/${pkg.name}/releases/${release.package_release_id}`
202
+ }}
209
203
  >
210
- View Details
204
+ View Release
211
205
  </DropdownMenuItem>
206
+ {status !== "error" && (
207
+ <DropdownMenuItem>
208
+ <a
209
+ href={`/${pkg.name}/releases/${latestBuild?.package_release_id}/preview`}
210
+ >
211
+ Preview Release
212
+ </a>
213
+ </DropdownMenuItem>
214
+ )}
212
215
  <DropdownMenuItem
213
- onClick={() => onSelectBuild?.(build)}
216
+ onClick={() => {
217
+ window.location.href = `/${pkg.name}/releases/${release.package_release_id}/builds`
218
+ }}
214
219
  >
215
- View Logs
220
+ View All Builds
216
221
  </DropdownMenuItem>
217
222
  </DropdownMenuContent>
218
223
  </DropdownMenu>
@@ -226,94 +231,6 @@ export const BuildsList = ({
226
231
  </div>
227
232
  </CardContent>
228
233
  </Card>
229
-
230
- <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
231
- <Card>
232
- <CardContent className="p-6">
233
- <div className="flex items-center gap-3">
234
- <div className="p-2 bg-green-100 rounded-lg">
235
- <CheckCircle className="w-5 h-5 text-green-600" />
236
- </div>
237
- <div>
238
- <p className="text-sm text-gray-600">Successful</p>
239
- {isLoading ? (
240
- <Skeleton className="h-8 w-8" />
241
- ) : (
242
- <p className="text-2xl font-bold text-gray-900">
243
- {builds?.filter(
244
- (d) => getBuildStatus(d).status === "success",
245
- ).length || 0}
246
- </p>
247
- )}
248
- </div>
249
- </div>
250
- </CardContent>
251
- </Card>
252
-
253
- <Card>
254
- <CardContent className="p-6">
255
- <div className="flex items-center gap-3">
256
- <div className="p-2 bg-red-100 rounded-lg">
257
- <AlertCircle className="w-5 h-5 text-red-600" />
258
- </div>
259
- <div>
260
- <p className="text-sm text-gray-600">Failed</p>
261
- {isLoading ? (
262
- <Skeleton className="h-8 w-8" />
263
- ) : (
264
- <p className="text-2xl font-bold text-gray-900">
265
- {builds?.filter(
266
- (d) => getBuildStatus(d).status === "error",
267
- ).length || 0}
268
- </p>
269
- )}
270
- </div>
271
- </div>
272
- </CardContent>
273
- </Card>
274
-
275
- <Card>
276
- <CardContent className="p-6">
277
- <div className="flex items-center gap-3">
278
- <div className="p-2 bg-blue-100 rounded-lg">
279
- <Loader2 className="w-5 h-5 text-blue-600 animate-spin" />
280
- </div>
281
- <div>
282
- <p className="text-sm text-gray-600">Building</p>
283
- {isLoading ? (
284
- <Skeleton className="h-8 w-8" />
285
- ) : (
286
- <p className="text-2xl font-bold text-gray-900">
287
- {builds?.filter(
288
- (d) => getBuildStatus(d).status === "building",
289
- ).length || 0}
290
- </p>
291
- )}
292
- </div>
293
- </div>
294
- </CardContent>
295
- </Card>
296
-
297
- <Card>
298
- <CardContent className="p-6">
299
- <div className="flex items-center gap-3">
300
- <div className="p-2 bg-gray-100 rounded-lg">
301
- <Clock className="w-5 h-5 text-gray-600" />
302
- </div>
303
- <div>
304
- <p className="text-sm text-gray-600">Total</p>
305
- {isLoading ? (
306
- <Skeleton className="h-8 w-8" />
307
- ) : (
308
- <p className="text-2xl font-bold text-gray-900">
309
- {builds?.length || 0}
310
- </p>
311
- )}
312
- </div>
313
- </div>
314
- </CardContent>
315
- </Card>
316
- </div>
317
234
  </div>
318
235
  </>
319
236
  )
@@ -1,52 +1,83 @@
1
- import { useState } from "react"
2
- import { Card, CardContent, CardHeader } from "@/components/ui/card"
1
+ import { Card } from "@/components/ui/card"
3
2
  import { Badge } from "@/components/ui/badge"
4
3
  import { Button } from "@/components/ui/button"
5
4
  import { GitBranch, Rocket, Github } from "lucide-react"
6
5
  import { cn } from "@/lib/utils"
7
6
  import { PrefetchPageLink } from "../PrefetchPageLink"
8
7
  import { formatTimeAgo } from "@/lib/utils/formatTimeAgo"
8
+ import { getBuildStatus, StatusIcon } from "."
9
+ import { Package } from "fake-snippets-api/lib/db/schema"
10
+ import { usePackageBuild } from "@/hooks/use-package-builds"
9
11
  import {
10
- getBuildStatus,
11
- getLatestBuildForPackage,
12
- MOCK_DEPLOYMENTS,
13
- StatusIcon,
14
- } from "."
15
- import { Package, PackageBuild } from "fake-snippets-api/lib/db/schema"
16
- import { useLatestPackageBuild } from "@/hooks/use-package-builds"
12
+ useLatestPackageRelease,
13
+ usePackageReleaseById,
14
+ } from "@/hooks/use-package-release"
17
15
 
18
16
  export const ConnectedPackageCardSkeleton = () => {
19
17
  return (
20
- <Card className="animate-pulse">
21
- <CardHeader className="pb-3">
22
- <div className="flex items-start justify-between">
23
- <div className="flex items-center gap-2 flex-1">
24
- <div className="w-4 h-4 bg-gray-200 rounded" />
25
- <div className="space-y-2 flex-1">
26
- <div className="flex items-center gap-2">
27
- <div className="w-12 h-4 bg-gray-200 rounded" />
28
- <div className="w-16 h-3 bg-gray-200 rounded" />
29
- </div>
30
- <div className="w-20 h-3 bg-gray-200 rounded" />
31
- </div>
32
- </div>
18
+ <Card
19
+ className={cn(
20
+ "group relative overflow-hidden",
21
+ "border border-gray-200",
22
+ "hover:border-gray-300",
23
+ "bg-white shadow-none",
24
+ "p-6",
25
+ "flex flex-col",
26
+ "min-h-[200px]",
27
+ "animate-pulse",
28
+ )}
29
+ >
30
+ <div className="flex items-start justify-between mb-4">
31
+ <div className="flex items-center gap-3">
32
+ <div className="h-6 w-32 bg-gray-200 rounded" />
33
33
  </div>
34
- </CardHeader>
35
- <CardContent className="pt-0 space-y-3">
36
- <div className="w-full h-4 bg-gray-200 rounded" />
37
- <div className="flex gap-2">
38
- <div className="w-16 h-3 bg-gray-200 rounded" />
39
- <div className="w-20 h-3 bg-gray-200 rounded" />
34
+
35
+ <div className="flex items-center justify-center gap-2">
36
+ <div className="w-16 h-5 bg-gray-200 rounded-full" />
37
+ <div className="w-4 h-4 bg-gray-200 rounded-full" />
40
38
  </div>
41
- <div className="flex gap-2 pt-2">
42
- <div className="flex-1 h-8 bg-gray-200 rounded" />
43
- <div className="flex-1 h-8 bg-gray-200 rounded" />
39
+ </div>
40
+
41
+ <div className="flex items-center gap-2 mb-4">
42
+ <div className="w-4 h-4 bg-gray-200 rounded" />
43
+ <div className="w-48 h-5 bg-gray-200 rounded" />
44
+ </div>
45
+
46
+ <div className="mb-6 flex-1">
47
+ <div className="h-5 w-3/4 bg-gray-200 rounded mb-2" />
48
+ <div className="flex items-center gap-2">
49
+ <div className="w-32 h-4 bg-gray-200 rounded" />
50
+ <div className="flex items-center gap-1">
51
+ <div className="w-3 h-3 bg-gray-200 rounded" />
52
+ <div className="w-16 h-4 bg-gray-200 rounded-full" />
53
+ </div>
44
54
  </div>
45
- </CardContent>
55
+ </div>
56
+
57
+ <div className="flex gap-2 w-full mt-auto">
58
+ <div className="w-full h-9 bg-gray-200 rounded" />
59
+ <div className="w-full h-9 bg-gray-200 rounded" />
60
+ </div>
46
61
  </Card>
47
62
  )
48
63
  }
49
64
 
65
+ // Custom hook to get latest package build info
66
+ const useLatestPackageBuildInfo = (packageId: string) => {
67
+ const { data: latestRelease, isLoading: releaseLoading } =
68
+ useLatestPackageRelease(packageId)
69
+ const { data: latestBuild, isLoading: buildLoading } = usePackageBuild(
70
+ latestRelease?.latest_package_build_id || null,
71
+ )
72
+
73
+ return {
74
+ data: latestBuild,
75
+ isLoading:
76
+ releaseLoading ||
77
+ (latestRelease?.latest_package_build_id && buildLoading),
78
+ }
79
+ }
80
+
50
81
  export const ConnectedPackageCard = ({
51
82
  pkg,
52
83
  className,
@@ -54,9 +85,13 @@ export const ConnectedPackageCard = ({
54
85
  pkg: Package
55
86
  className?: string
56
87
  }) => {
57
- const { data: latestBuildInfo, isLoading } = useLatestPackageBuild({
58
- package_id: pkg.package_id,
59
- })
88
+ const { data: latestBuildInfo, isLoading } = useLatestPackageBuildInfo(
89
+ pkg.package_id,
90
+ )
91
+
92
+ const { data: packageRelease } = usePackageReleaseById(
93
+ latestBuildInfo?.package_release_id,
94
+ )
60
95
 
61
96
  if (isLoading && !latestBuildInfo) {
62
97
  return <ConnectedPackageCardSkeleton />
@@ -72,7 +107,7 @@ export const ConnectedPackageCard = ({
72
107
  "group relative overflow-hidden",
73
108
  "border border-gray-200",
74
109
  "hover:border-gray-300",
75
- "bg-white",
110
+ "bg-white shadow-none",
76
111
  "p-6",
77
112
  "flex flex-col",
78
113
  "min-h-[200px]",
@@ -118,46 +153,41 @@ export const ConnectedPackageCard = ({
118
153
  </a>
119
154
  </div>
120
155
 
121
- {latestBuildInfo?.commit_message && (
122
- <div className="mb-6 flex-1">
156
+ <div className="mb-6 flex-1">
157
+ {packageRelease?.commit_message && (
123
158
  <h4
124
- title={latestBuildInfo.commit_message}
159
+ title={packageRelease.commit_message}
125
160
  className="text-sm font-medium truncate text-gray-900 mb-2"
126
161
  >
127
- {latestBuildInfo.commit_message}
162
+ {packageRelease.commit_message}
128
163
  </h4>
129
- <div className="flex items-center gap-2 text-xs text-gray-500">
130
- <span>{formatTimeAgo(latestBuildInfo.created_at)} on</span>
131
- <div className="flex items-center gap-1">
132
- <GitBranch className="w-3 h-3" />
133
- <span className="bg-blue-100 text-blue-800 px-2 py-0.5 rounded-full font-medium">
134
- {latestBuildInfo.branch_name || "main"}
135
- </span>
136
- </div>
164
+ )}
165
+ <div className="flex items-center gap-2 text-xs text-gray-500">
166
+ <span>{formatTimeAgo(String(latestBuildInfo?.created_at))} on</span>
167
+ <div className="flex items-center gap-1">
168
+ <GitBranch className="w-3 h-3" />
169
+ <span className="bg-blue-100 text-blue-800 px-2 py-0.5 rounded-full font-medium">
170
+ {packageRelease?.branch_name || "main"}
171
+ </span>
137
172
  </div>
138
173
  </div>
139
- )}
174
+ </div>
140
175
 
141
176
  <div className="flex gap-2 w-full mt-auto">
142
- {latestBuildInfo?.package_build_id && (
143
- <PrefetchPageLink
144
- className="w-full"
145
- href={`/build/${latestBuildInfo.package_build_id}`}
177
+ <PrefetchPageLink className="w-full" href={`/${pkg.name}/releases`}>
178
+ <Button
179
+ size="sm"
180
+ className="bg-blue-600 w-full hover:bg-blue-700 text-white px-4 py-2"
146
181
  >
147
- <Button
148
- size="sm"
149
- className="bg-blue-600 w-full hover:bg-blue-700 text-white px-4 py-2"
150
- >
151
- View
152
- </Button>
153
- </PrefetchPageLink>
154
- )}
182
+ View
183
+ </Button>
184
+ </PrefetchPageLink>
155
185
  {latestBuildInfo?.preview_url &&
156
186
  latestBuildInfo?.package_build_id &&
157
187
  status === "success" && (
158
188
  <PrefetchPageLink
159
189
  className="w-full"
160
- href={`/build/${latestBuildInfo.package_build_id}/preview`}
190
+ href={`/${pkg.name}/releases/${latestBuildInfo.package_release_id}/preview`}
161
191
  >
162
192
  <Button size="sm" variant="outline" className="px-4 py-2 w-full">
163
193
  Preview