@tscircuit/fake-snippets 0.0.104 → 0.0.106

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.
@@ -1,6 +1,7 @@
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 { Skeleton } from "@/components/ui/skeleton"
4
5
  import {
5
6
  Clock,
6
7
  GitBranch,
@@ -9,7 +10,6 @@ import {
9
10
  Loader2,
10
11
  MoreHorizontal,
11
12
  GitCommit,
12
- Plus,
13
13
  } from "lucide-react"
14
14
  import {
15
15
  DropdownMenu,
@@ -25,9 +25,13 @@ import {
25
25
  TableHeader,
26
26
  TableRow,
27
27
  } from "@/components/ui/table"
28
- import { getBuildStatus, MOCK_DEPLOYMENTS, PackageBuild, StatusIcon } from "."
28
+ import { getBuildStatus, StatusIcon } from "."
29
29
  import { formatTimeAgo } from "@/lib/utils/formatTimeAgo"
30
- import { Package } from "fake-snippets-api/lib/db/schema"
30
+ 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"
33
+ import { useQueries } from "react-query"
34
+ import { useAxios } from "@/hooks/use-axios"
31
35
 
32
36
  export const BuildsList = ({
33
37
  pkg,
@@ -36,206 +40,281 @@ export const BuildsList = ({
36
40
  pkg: Package
37
41
  onSelectBuild?: (build: PackageBuild) => void
38
42
  }) => {
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>
43
+ const { data: builds, isLoading } = usePackageBuilds({
44
+ package_id: pkg.package_id,
45
+ })
46
+ const axios = useAxios()
48
47
 
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)
48
+ const uniqueReleaseIds = [
49
+ ...new Set(
50
+ builds?.map((build) => build.package_release_id).filter(Boolean) || [],
51
+ ),
52
+ ]
70
53
 
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>
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
+ )
68
+
69
+ const packageReleasesMap = new Map()
70
+ packageReleaseQueries.forEach((query, index) => {
71
+ if (query.data) {
72
+ packageReleasesMap.set(uniqueReleaseIds[index], query.data)
73
+ }
74
+ })
75
+ return (
76
+ <>
77
+ <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>
160
82
  </div>
161
- </CardContent>
162
- </Card>
83
+ </div>
163
84
 
164
- <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
165
85
  <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>
86
+ <CardHeader>
87
+ <CardTitle>Recent Deployments</CardTitle>
88
+ </CardHeader>
89
+ <CardContent>
90
+ <div className="overflow-x-auto [&>div]:no-scrollbar">
91
+ <Table className="no-scrollbar">
92
+ <TableHeader>
93
+ <TableRow>
94
+ <TableHead>Status</TableHead>
95
+ <TableHead>Build ID</TableHead>
96
+ <TableHead>Branch/PR</TableHead>
97
+ <TableHead>Commit</TableHead>
98
+ <TableHead>Author</TableHead>
99
+ <TableHead>Created</TableHead>
100
+ <TableHead>Actions</TableHead>
101
+ </TableRow>
102
+ </TableHeader>
103
+ <TableBody>
104
+ {isLoading
105
+ ? Array.from({ length: 3 }).map((_, i) => (
106
+ <TableRow key={i}>
107
+ <TableCell>
108
+ <Skeleton className="h-6 w-20" />
109
+ </TableCell>
110
+ <TableCell>
111
+ <Skeleton className="h-6 w-16" />
112
+ </TableCell>
113
+ <TableCell>
114
+ <Skeleton className="h-6 w-12" />
115
+ </TableCell>
116
+ <TableCell>
117
+ <Skeleton className="h-6 w-32" />
118
+ </TableCell>
119
+ <TableCell>
120
+ <Skeleton className="h-6 w-20" />
121
+ </TableCell>
122
+ <TableCell>
123
+ <Skeleton className="h-6 w-16" />
124
+ </TableCell>
125
+ <TableCell>
126
+ <Skeleton className="h-6 w-8" />
127
+ </TableCell>
128
+ </TableRow>
129
+ ))
130
+ : builds?.map((build) => {
131
+ const { status, label } = getBuildStatus(build)
132
+ const packageRelease = packageReleasesMap.get(
133
+ build.package_release_id,
134
+ )
135
+ return (
136
+ <TableRow
137
+ key={build.package_build_id}
138
+ className="cursor-pointer hover:bg-gray-50 no-scrollbar"
139
+ onClick={() => onSelectBuild?.(build)}
140
+ >
141
+ <TableCell>
142
+ <div className="flex items-center gap-2">
143
+ <StatusIcon status={status} />
144
+ <Badge
145
+ variant={
146
+ status === "success"
147
+ ? "default"
148
+ : status === "error"
149
+ ? "destructive"
150
+ : "secondary"
151
+ }
152
+ className="text-xs"
153
+ >
154
+ {label}
155
+ </Badge>
156
+ </div>
157
+ </TableCell>
158
+ <TableCell>
159
+ <code className="text-sm bg-gray-100 px-2 py-1 rounded">
160
+ {build.package_build_id.slice(-8)}
161
+ </code>
162
+ </TableCell>
163
+ <TableCell>
164
+ <div className="flex items-center gap-2">
165
+ {packageRelease?.is_pr_preview ? (
166
+ <GitBranch className="w-3 h-3 text-gray-500" />
167
+ ) : (
168
+ <GitCommit className="w-3 h-3 text-gray-500" />
169
+ )}
170
+ <Badge variant="outline" className="text-xs">
171
+ {packageRelease?.is_pr_preview
172
+ ? `#${packageRelease.github_pr_number}`
173
+ : packageRelease?.branch_name || "main"}
174
+ </Badge>
175
+ </div>
176
+ </TableCell>
177
+ <TableCell>
178
+ <div className="max-w-xs">
179
+ <p className="text-sm font-medium truncate">
180
+ {build.commit_message || "No commit message"}
181
+ </p>
182
+ </div>
183
+ </TableCell>
184
+ <TableCell>
185
+ <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)}
192
+ </span>
193
+ </TableCell>
194
+ <TableCell>
195
+ <div className="flex items-center gap-2">
196
+ <DropdownMenu>
197
+ <DropdownMenuTrigger asChild>
198
+ <Button
199
+ variant="ghost"
200
+ size="sm"
201
+ onClick={(e) => e.stopPropagation()}
202
+ >
203
+ <MoreHorizontal className="w-3 h-3" />
204
+ </Button>
205
+ </DropdownMenuTrigger>
206
+ <DropdownMenuContent align="end">
207
+ <DropdownMenuItem
208
+ onClick={() => onSelectBuild?.(build)}
209
+ >
210
+ View Details
211
+ </DropdownMenuItem>
212
+ <DropdownMenuItem
213
+ onClick={() => onSelectBuild?.(build)}
214
+ >
215
+ View Logs
216
+ </DropdownMenuItem>
217
+ </DropdownMenuContent>
218
+ </DropdownMenu>
219
+ </div>
220
+ </TableCell>
221
+ </TableRow>
222
+ )
223
+ })}
224
+ </TableBody>
225
+ </Table>
180
226
  </div>
181
227
  </CardContent>
182
228
  </Card>
183
229
 
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>
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>
198
249
  </div>
199
- </div>
200
- </CardContent>
201
- </Card>
250
+ </CardContent>
251
+ </Card>
202
252
 
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>
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>
218
271
  </div>
219
- </div>
220
- </CardContent>
221
- </Card>
272
+ </CardContent>
273
+ </Card>
222
274
 
223
- <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" />
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>
228
293
  </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>
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>
234
313
  </div>
235
- </div>
236
- </CardContent>
237
- </Card>
314
+ </CardContent>
315
+ </Card>
316
+ </div>
238
317
  </div>
239
- </div>
318
+ </>
240
319
  )
241
320
  }
@@ -10,10 +10,10 @@ import {
10
10
  getBuildStatus,
11
11
  getLatestBuildForPackage,
12
12
  MOCK_DEPLOYMENTS,
13
- PackageBuild,
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 { useLatestPackageBuild } from "@/hooks/use-package-builds"
17
17
 
18
18
  export const ConnectedPackageCardSkeleton = () => {
19
19
  return (
@@ -54,8 +54,18 @@ export const ConnectedPackageCard = ({
54
54
  pkg: Package
55
55
  className?: string
56
56
  }) => {
57
- const latestBuildInfo: PackageBuild = getLatestBuildForPackage(pkg)
58
- const { status, label } = getBuildStatus(latestBuildInfo)
57
+ const { data: latestBuildInfo, isLoading } = useLatestPackageBuild({
58
+ package_id: pkg.package_id,
59
+ })
60
+
61
+ if (isLoading && !latestBuildInfo) {
62
+ return <ConnectedPackageCardSkeleton />
63
+ }
64
+
65
+ const { status, label } = latestBuildInfo
66
+ ? getBuildStatus(latestBuildInfo)
67
+ : { status: "pending", label: "Pending" }
68
+
59
69
  return (
60
70
  <Card
61
71
  className={cn(
@@ -75,7 +85,7 @@ export const ConnectedPackageCard = ({
75
85
  href="#"
76
86
  className="text-lg font-semibold text-gray-900 hover:text-blue-600 transition-colors"
77
87
  >
78
- tsc-deploy
88
+ {pkg.unscoped_name}
79
89
  </a>
80
90
  </div>
81
91
 
@@ -108,7 +118,7 @@ export const ConnectedPackageCard = ({
108
118
  </a>
109
119
  </div>
110
120
 
111
- {latestBuildInfo.commit_message && (
121
+ {latestBuildInfo?.commit_message && (
112
122
  <div className="mb-6 flex-1">
113
123
  <h4
114
124
  title={latestBuildInfo.commit_message}
@@ -129,27 +139,31 @@ export const ConnectedPackageCard = ({
129
139
  )}
130
140
 
131
141
  <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" && (
142
+ {latestBuildInfo?.package_build_id && (
144
143
  <PrefetchPageLink
145
144
  className="w-full"
146
- href={`/build/${latestBuildInfo.package_build_id}/preview`}
145
+ href={`/build/${latestBuildInfo.package_build_id}`}
147
146
  >
148
- <Button size="sm" variant="outline" className="px-4 py-2 w-full">
149
- Preview
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
150
152
  </Button>
151
153
  </PrefetchPageLink>
152
154
  )}
155
+ {latestBuildInfo?.preview_url &&
156
+ latestBuildInfo?.package_build_id &&
157
+ status === "success" && (
158
+ <PrefetchPageLink
159
+ className="w-full"
160
+ href={`/build/${latestBuildInfo.package_build_id}/preview`}
161
+ >
162
+ <Button size="sm" variant="outline" className="px-4 py-2 w-full">
163
+ Preview
164
+ </Button>
165
+ </PrefetchPageLink>
166
+ )}
153
167
  </div>
154
168
  </Card>
155
169
  )
@@ -158,9 +172,7 @@ export const ConnectedPackageCard = ({
158
172
  export const ConnectedPackagesList = ({
159
173
  packages,
160
174
  }: { packages: Package[] }) => {
161
- const [pkgs, setpkgs] = useState(MOCK_DEPLOYMENTS)
162
-
163
- if (pkgs.length === 0) {
175
+ if (packages.length === 0) {
164
176
  return (
165
177
  <div className="flex flex-col items-center justify-center py-20 text-black">
166
178
  <Rocket className="w-12 h-12 mb-4 text-black" />