@tscircuit/fake-snippets 0.0.105 → 0.0.107

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 (33) hide show
  1. package/CLAUDE.md +92 -0
  2. package/api/generated-index.js +3 -4
  3. package/bun-tests/fake-snippets-api/routes/package_builds/get.test.ts +294 -0
  4. package/bun-tests/fake-snippets-api/routes/package_builds/list.test.ts +304 -0
  5. package/dist/bundle.js +698 -335
  6. package/dist/index.d.ts +147 -4
  7. package/dist/index.js +195 -7
  8. package/dist/schema.d.ts +206 -1
  9. package/dist/schema.js +31 -2
  10. package/fake-snippets-api/lib/db/db-client.ts +60 -3
  11. package/fake-snippets-api/lib/db/schema.ts +31 -0
  12. package/fake-snippets-api/lib/db/seed.ts +139 -2
  13. package/fake-snippets-api/lib/public-mapping/public-map-package-build.ts +41 -0
  14. package/fake-snippets-api/routes/api/package_builds/get.ts +70 -0
  15. package/fake-snippets-api/routes/api/package_builds/list.ts +97 -0
  16. package/package.json +3 -2
  17. package/src/App.tsx +21 -5
  18. package/src/components/PackageBreadcrumb.tsx +111 -0
  19. package/src/components/ViewPackagePage/components/sidebar-releases-section.tsx +22 -11
  20. package/src/components/preview/BuildsList.tsx +196 -211
  21. package/src/components/preview/ConnectedPackagesList.tsx +54 -25
  22. package/src/components/preview/ConnectedRepoOverview.tsx +63 -35
  23. package/src/components/preview/{ConnectedRepoDashboard.tsx → PackageReleasesDashboard.tsx} +33 -71
  24. package/src/components/preview/index.tsx +20 -77
  25. package/src/hooks/use-package-builds.ts +87 -0
  26. package/src/hooks/use-package-release-by-id-or-version.ts +36 -0
  27. package/src/hooks/use-package-release.ts +32 -0
  28. package/src/lib/utils/isUuid.ts +5 -0
  29. package/src/pages/preview-build.tsx +3 -3
  30. package/src/pages/release-builds.tsx +107 -0
  31. package/src/pages/release-detail.tsx +118 -0
  32. package/src/pages/releases.tsx +51 -0
  33. package/src/pages/view-connected-repo.tsx +0 -18
@@ -1,16 +1,8 @@
1
1
  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
- import {
5
- Clock,
6
- GitBranch,
7
- AlertCircle,
8
- CheckCircle,
9
- Loader2,
10
- MoreHorizontal,
11
- GitCommit,
12
- Plus,
13
- } from "lucide-react"
4
+ import { Skeleton } from "@/components/ui/skeleton"
5
+ import { GitBranch, MoreHorizontal, GitCommit } from "lucide-react"
14
6
  import {
15
7
  DropdownMenu,
16
8
  DropdownMenuContent,
@@ -25,217 +17,210 @@ import {
25
17
  TableHeader,
26
18
  TableRow,
27
19
  } from "@/components/ui/table"
28
- import { getBuildStatus, MOCK_DEPLOYMENTS, PackageBuild, StatusIcon } from "."
20
+ import { getBuildStatus, StatusIcon } from "."
29
21
  import { formatTimeAgo } from "@/lib/utils/formatTimeAgo"
30
22
  import { Package } from "fake-snippets-api/lib/db/schema"
23
+ import { usePackageReleasesByPackageId } from "@/hooks/use-package-release"
24
+ import { useQueries } from "react-query"
25
+ import { useAxios } from "@/hooks/use-axios"
31
26
 
32
- export const BuildsList = ({
33
- pkg,
34
- onSelectBuild,
35
- }: {
36
- pkg: Package
37
- onSelectBuild?: (build: PackageBuild) => void
38
- }) => {
39
- const builds = MOCK_DEPLOYMENTS
40
- return (
41
- <div className="space-y-6">
42
- <div className="flex items-center justify-between">
43
- <div>
44
- <h2 className="text-2xl font-bold text-gray-900">Builds</h2>
45
- <p className="text-gray-600">Manage and monitor your builds</p>
46
- </div>
47
- </div>
48
-
49
- <Card>
50
- <CardHeader>
51
- <CardTitle>Recent Deployments</CardTitle>
52
- </CardHeader>
53
- <CardContent>
54
- <div className="overflow-x-auto">
55
- <Table>
56
- <TableHeader>
57
- <TableRow>
58
- <TableHead>Status</TableHead>
59
- <TableHead>Build ID</TableHead>
60
- <TableHead>Branch</TableHead>
61
- <TableHead>Commit</TableHead>
62
- <TableHead>Author</TableHead>
63
- <TableHead>Created</TableHead>
64
- <TableHead>Actions</TableHead>
65
- </TableRow>
66
- </TableHeader>
67
- <TableBody>
68
- {builds.map((build) => {
69
- const { status, label } = getBuildStatus(build)
70
-
71
- return (
72
- <TableRow
73
- key={build.package_build_id}
74
- className="cursor-pointer hover:bg-gray-50"
75
- onClick={() => onSelectBuild?.(build)}
76
- >
77
- <TableCell>
78
- <div className="flex items-center gap-2">
79
- <StatusIcon status={status} />
80
- <Badge
81
- variant={
82
- status === "success"
83
- ? "default"
84
- : status === "error"
85
- ? "destructive"
86
- : "secondary"
87
- }
88
- className="text-xs"
89
- >
90
- {label}
91
- </Badge>
92
- </div>
93
- </TableCell>
94
- <TableCell>
95
- <code className="text-sm bg-gray-100 px-2 py-1 rounded">
96
- {build.package_build_id.slice(-8)}
97
- </code>
98
- </TableCell>
99
- <TableCell>
100
- <div className="flex items-center gap-2">
101
- {build.branch_name?.includes("/") ? (
102
- <GitBranch className="w-3 h-3 text-gray-500" />
103
- ) : (
104
- <GitCommit className="w-3 h-3 text-gray-500" />
105
- )}
106
- <Badge variant="outline" className="text-xs">
107
- {build.branch_name || "main"}
108
- </Badge>
109
- </div>
110
- </TableCell>
111
- <TableCell>
112
- <div className="max-w-xs">
113
- <p className="text-sm font-medium truncate">
114
- {build.commit_message || "No commit message"}
115
- </p>
116
- </div>
117
- </TableCell>
118
- <TableCell>
119
- <span className="text-sm text-gray-600">
120
- {build.commit_author || "Unknown"}
121
- </span>
122
- </TableCell>
123
- <TableCell>
124
- <span className="text-sm text-gray-600">
125
- {formatTimeAgo(build.created_at)}
126
- </span>
127
- </TableCell>
128
- <TableCell>
129
- <div className="flex items-center gap-2">
130
- <DropdownMenu>
131
- <DropdownMenuTrigger asChild>
132
- <Button
133
- variant="ghost"
134
- size="sm"
135
- onClick={(e) => e.stopPropagation()}
136
- >
137
- <MoreHorizontal className="w-3 h-3" />
138
- </Button>
139
- </DropdownMenuTrigger>
140
- <DropdownMenuContent align="end">
141
- <DropdownMenuItem
142
- onClick={() => onSelectBuild?.(build)}
143
- >
144
- View Details
145
- </DropdownMenuItem>
146
- <DropdownMenuItem
147
- onClick={() => onSelectBuild?.(build)}
148
- >
149
- View Logs
150
- </DropdownMenuItem>
151
- </DropdownMenuContent>
152
- </DropdownMenu>
153
- </div>
154
- </TableCell>
155
- </TableRow>
156
- )
157
- })}
158
- </TableBody>
159
- </Table>
160
- </div>
161
- </CardContent>
162
- </Card>
163
-
164
- <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
165
- <Card>
166
- <CardContent className="p-6">
167
- <div className="flex items-center gap-3">
168
- <div className="p-2 bg-green-100 rounded-lg">
169
- <CheckCircle className="w-5 h-5 text-green-600" />
170
- </div>
171
- <div>
172
- <p className="text-sm text-gray-600">Successful</p>
173
- <p className="text-2xl font-bold text-gray-900">
174
- {
175
- builds.filter((d) => getBuildStatus(d).status === "success")
176
- .length
177
- }
178
- </p>
179
- </div>
180
- </div>
181
- </CardContent>
182
- </Card>
27
+ export const BuildsList = ({ pkg }: { pkg: Package }) => {
28
+ const { data: releases, isLoading: isLoadingReleases } =
29
+ usePackageReleasesByPackageId(pkg.package_id)
30
+ const axios = useAxios()
183
31
 
184
- <Card>
185
- <CardContent className="p-6">
186
- <div className="flex items-center gap-3">
187
- <div className="p-2 bg-red-100 rounded-lg">
188
- <AlertCircle className="w-5 h-5 text-red-600" />
189
- </div>
190
- <div>
191
- <p className="text-sm text-gray-600">Failed</p>
192
- <p className="text-2xl font-bold text-gray-900">
193
- {
194
- builds.filter((d) => getBuildStatus(d).status === "error")
195
- .length
196
- }
197
- </p>
198
- </div>
199
- </div>
200
- </CardContent>
201
- </Card>
32
+ // Get the latest build for each release to show status
33
+ const latestBuildQueries = useQueries(
34
+ (releases || [])
35
+ .filter((release) => release.latest_package_build_id)
36
+ .map((release) => ({
37
+ queryKey: ["packageBuild", release.latest_package_build_id],
38
+ queryFn: async () => {
39
+ if (!release.latest_package_build_id) return null
40
+ const { data } = await axios.get("/package_builds/get", {
41
+ params: { package_build_id: release.latest_package_build_id },
42
+ })
43
+ return data.package_build
44
+ },
45
+ enabled: Boolean(release.latest_package_build_id),
46
+ retry: false,
47
+ refetchOnWindowFocus: false,
48
+ })),
49
+ )
202
50
 
203
- <Card>
204
- <CardContent className="p-6">
205
- <div className="flex items-center gap-3">
206
- <div className="p-2 bg-blue-100 rounded-lg">
207
- <Loader2 className="w-5 h-5 text-blue-600 animate-spin" />
208
- </div>
209
- <div>
210
- <p className="text-sm text-gray-600">Building</p>
211
- <p className="text-2xl font-bold text-gray-900">
212
- {
213
- builds.filter(
214
- (d) => getBuildStatus(d).status === "building",
215
- ).length
216
- }
217
- </p>
218
- </div>
219
- </div>
220
- </CardContent>
221
- </Card>
51
+ const isLoading =
52
+ isLoadingReleases || latestBuildQueries.some((q) => q.isLoading)
222
53
 
54
+ // Create a map of release ID to latest build for easy access
55
+ const latestBuildsMap = new Map()
56
+ latestBuildQueries.forEach((query, index) => {
57
+ if (query.data && releases?.[index]) {
58
+ latestBuildsMap.set(releases[index].package_release_id, query.data)
59
+ }
60
+ })
61
+ return (
62
+ <>
63
+ <div className="space-y-6">
223
64
  <Card>
224
- <CardContent className="p-6">
225
- <div className="flex items-center gap-3">
226
- <div className="p-2 bg-gray-100 rounded-lg">
227
- <Clock className="w-5 h-5 text-gray-600" />
228
- </div>
229
- <div>
230
- <p className="text-sm text-gray-600">Total</p>
231
- <p className="text-2xl font-bold text-gray-900">
232
- {builds.length}
233
- </p>
234
- </div>
65
+ <CardHeader>
66
+ <CardTitle>Recent Releases</CardTitle>
67
+ </CardHeader>
68
+ <CardContent>
69
+ <div className="overflow-x-auto [&>div]:no-scrollbar">
70
+ <Table className="no-scrollbar">
71
+ <TableHeader>
72
+ <TableRow>
73
+ <TableHead>Status</TableHead>
74
+ <TableHead>Release ID</TableHead>
75
+ <TableHead>Version</TableHead>
76
+ <TableHead>Branch/PR</TableHead>
77
+ <TableHead>Latest Build</TableHead>
78
+ <TableHead>Created</TableHead>
79
+ <TableHead>Actions</TableHead>
80
+ </TableRow>
81
+ </TableHeader>
82
+ <TableBody>
83
+ {isLoading
84
+ ? Array.from({ length: 3 }).map((_, i) => (
85
+ <TableRow key={i}>
86
+ <TableCell>
87
+ <Skeleton className="h-6 w-20" />
88
+ </TableCell>
89
+ <TableCell>
90
+ <Skeleton className="h-6 w-16" />
91
+ </TableCell>
92
+ <TableCell>
93
+ <Skeleton className="h-6 w-12" />
94
+ </TableCell>
95
+ <TableCell>
96
+ <Skeleton className="h-6 w-32" />
97
+ </TableCell>
98
+ <TableCell>
99
+ <Skeleton className="h-6 w-20" />
100
+ </TableCell>
101
+ <TableCell>
102
+ <Skeleton className="h-6 w-16" />
103
+ </TableCell>
104
+ <TableCell>
105
+ <Skeleton className="h-6 w-8" />
106
+ </TableCell>
107
+ </TableRow>
108
+ ))
109
+ : releases?.map((release) => {
110
+ const latestBuild = latestBuildsMap.get(
111
+ release.package_release_id,
112
+ )
113
+ const { status, label } = latestBuild
114
+ ? getBuildStatus(latestBuild)
115
+ : { status: "unknown", label: "No builds" }
116
+ return (
117
+ <TableRow
118
+ key={release.package_release_id}
119
+ className="cursor-pointer hover:bg-gray-50 no-scrollbar"
120
+ onClick={() => {
121
+ window.location.href = `/${pkg.name}/release/${release.package_release_id}`
122
+ }}
123
+ >
124
+ <TableCell>
125
+ <div className="flex items-center gap-2">
126
+ <StatusIcon status={status} />
127
+ <Badge
128
+ variant={
129
+ status === "success"
130
+ ? "default"
131
+ : status === "error"
132
+ ? "destructive"
133
+ : "secondary"
134
+ }
135
+ className="text-xs"
136
+ >
137
+ {label}
138
+ </Badge>
139
+ </div>
140
+ </TableCell>
141
+ <TableCell>
142
+ <code className="text-sm bg-gray-100 px-2 py-1 rounded">
143
+ {release.package_release_id.slice(-8)}
144
+ </code>
145
+ </TableCell>
146
+ <TableCell>
147
+ <span className="text-sm font-medium">
148
+ {release.version ||
149
+ "v" + release.package_release_id.slice(-6)}
150
+ </span>
151
+ </TableCell>
152
+ <TableCell>
153
+ <div className="flex items-center gap-2">
154
+ {release.is_pr_preview ? (
155
+ <GitBranch className="w-3 h-3 text-gray-500" />
156
+ ) : (
157
+ <GitCommit className="w-3 h-3 text-gray-500" />
158
+ )}
159
+ <Badge variant="outline" className="text-xs">
160
+ {release.is_pr_preview
161
+ ? `#${release.github_pr_number}`
162
+ : "main"}
163
+ </Badge>
164
+ </div>
165
+ </TableCell>
166
+ <TableCell>
167
+ <div className="max-w-xs">
168
+ {latestBuild ? (
169
+ <p className="text-sm text-gray-600">
170
+ {formatTimeAgo(latestBuild.created_at)}
171
+ </p>
172
+ ) : (
173
+ <p className="text-sm text-gray-400">
174
+ No builds
175
+ </p>
176
+ )}
177
+ </div>
178
+ </TableCell>
179
+ <TableCell>
180
+ <span className="text-sm text-gray-600">
181
+ {formatTimeAgo(release.created_at)}
182
+ </span>
183
+ </TableCell>
184
+ <TableCell>
185
+ <div className="flex items-center gap-2">
186
+ <DropdownMenu>
187
+ <DropdownMenuTrigger asChild>
188
+ <Button
189
+ variant="ghost"
190
+ size="sm"
191
+ onClick={(e) => e.stopPropagation()}
192
+ >
193
+ <MoreHorizontal className="w-3 h-3" />
194
+ </Button>
195
+ </DropdownMenuTrigger>
196
+ <DropdownMenuContent align="end">
197
+ <DropdownMenuItem
198
+ onClick={() => {
199
+ window.location.href = `/${pkg.name}/release/${release.package_release_id}`
200
+ }}
201
+ >
202
+ View Release
203
+ </DropdownMenuItem>
204
+ <DropdownMenuItem
205
+ onClick={() => {
206
+ window.location.href = `/${pkg.name}/release/${release.package_release_id}/builds`
207
+ }}
208
+ >
209
+ View All Builds
210
+ </DropdownMenuItem>
211
+ </DropdownMenuContent>
212
+ </DropdownMenu>
213
+ </div>
214
+ </TableCell>
215
+ </TableRow>
216
+ )
217
+ })}
218
+ </TableBody>
219
+ </Table>
235
220
  </div>
236
221
  </CardContent>
237
222
  </Card>
238
223
  </div>
239
- </div>
224
+ </>
240
225
  )
241
226
  }
@@ -9,11 +9,12 @@ import { formatTimeAgo } from "@/lib/utils/formatTimeAgo"
9
9
  import {
10
10
  getBuildStatus,
11
11
  getLatestBuildForPackage,
12
- MOCK_DEPLOYMENTS,
13
- PackageBuild,
12
+ MOCK_PACKAGE_BUILDS,
14
13
  StatusIcon,
15
14
  } from "."
16
- import { Package } from "fake-snippets-api/lib/db/schema"
15
+ import { Package, PackageBuild } from "fake-snippets-api/lib/db/schema"
16
+ import { usePackageBuild } from "@/hooks/use-package-builds"
17
+ import { useLatestPackageRelease } from "@/hooks/use-package-release"
17
18
 
18
19
  export const ConnectedPackageCardSkeleton = () => {
19
20
  return (
@@ -47,6 +48,22 @@ export const ConnectedPackageCardSkeleton = () => {
47
48
  )
48
49
  }
49
50
 
51
+ // Custom hook to get latest package build info
52
+ const useLatestPackageBuildInfo = (packageId: string) => {
53
+ const { data: latestRelease, isLoading: releaseLoading } =
54
+ useLatestPackageRelease(packageId)
55
+ const { data: latestBuild, isLoading: buildLoading } = usePackageBuild(
56
+ latestRelease?.latest_package_build_id || null,
57
+ )
58
+
59
+ return {
60
+ data: latestBuild,
61
+ isLoading:
62
+ releaseLoading ||
63
+ (latestRelease?.latest_package_build_id && buildLoading),
64
+ }
65
+ }
66
+
50
67
  export const ConnectedPackageCard = ({
51
68
  pkg,
52
69
  className,
@@ -54,8 +71,18 @@ export const ConnectedPackageCard = ({
54
71
  pkg: Package
55
72
  className?: string
56
73
  }) => {
57
- const latestBuildInfo: PackageBuild = getLatestBuildForPackage(pkg)
58
- const { status, label } = getBuildStatus(latestBuildInfo)
74
+ const { data: latestBuildInfo, isLoading } = useLatestPackageBuildInfo(
75
+ pkg.package_id,
76
+ )
77
+
78
+ if (isLoading && !latestBuildInfo) {
79
+ return <ConnectedPackageCardSkeleton />
80
+ }
81
+
82
+ const { status, label } = latestBuildInfo
83
+ ? getBuildStatus(latestBuildInfo)
84
+ : { status: "pending", label: "Pending" }
85
+
59
86
  return (
60
87
  <Card
61
88
  className={cn(
@@ -75,7 +102,7 @@ export const ConnectedPackageCard = ({
75
102
  href="#"
76
103
  className="text-lg font-semibold text-gray-900 hover:text-blue-600 transition-colors"
77
104
  >
78
- tsc-deploy
105
+ {pkg.unscoped_name}
79
106
  </a>
80
107
  </div>
81
108
 
@@ -108,7 +135,7 @@ export const ConnectedPackageCard = ({
108
135
  </a>
109
136
  </div>
110
137
 
111
- {latestBuildInfo.commit_message && (
138
+ {latestBuildInfo?.commit_message && (
112
139
  <div className="mb-6 flex-1">
113
140
  <h4
114
141
  title={latestBuildInfo.commit_message}
@@ -129,27 +156,31 @@ export const ConnectedPackageCard = ({
129
156
  )}
130
157
 
131
158
  <div className="flex gap-2 w-full mt-auto">
132
- <PrefetchPageLink
133
- className="w-full"
134
- href={`/build/${latestBuildInfo.package_build_id}`}
135
- >
136
- <Button
137
- size="sm"
138
- className="bg-blue-600 w-full hover:bg-blue-700 text-white px-4 py-2"
139
- >
140
- View
141
- </Button>
142
- </PrefetchPageLink>
143
- {latestBuildInfo.preview_url && status === "success" && (
159
+ {latestBuildInfo?.package_build_id && (
144
160
  <PrefetchPageLink
145
161
  className="w-full"
146
- href={`/build/${latestBuildInfo.package_build_id}/preview`}
162
+ href={`/build/${latestBuildInfo.package_build_id}`}
147
163
  >
148
- <Button size="sm" variant="outline" className="px-4 py-2 w-full">
149
- Preview
164
+ <Button
165
+ size="sm"
166
+ className="bg-blue-600 w-full hover:bg-blue-700 text-white px-4 py-2"
167
+ >
168
+ View
150
169
  </Button>
151
170
  </PrefetchPageLink>
152
171
  )}
172
+ {latestBuildInfo?.preview_url &&
173
+ latestBuildInfo?.package_build_id &&
174
+ status === "success" && (
175
+ <PrefetchPageLink
176
+ className="w-full"
177
+ href={`/build/${latestBuildInfo.package_build_id}/preview`}
178
+ >
179
+ <Button size="sm" variant="outline" className="px-4 py-2 w-full">
180
+ Preview
181
+ </Button>
182
+ </PrefetchPageLink>
183
+ )}
153
184
  </div>
154
185
  </Card>
155
186
  )
@@ -158,9 +189,7 @@ export const ConnectedPackageCard = ({
158
189
  export const ConnectedPackagesList = ({
159
190
  packages,
160
191
  }: { packages: Package[] }) => {
161
- const [pkgs, setpkgs] = useState(MOCK_DEPLOYMENTS)
162
-
163
- if (pkgs.length === 0) {
192
+ if (packages.length === 0) {
164
193
  return (
165
194
  <div className="flex flex-col items-center justify-center py-20 text-black">
166
195
  <Rocket className="w-12 h-12 mb-4 text-black" />