@tscircuit/fake-snippets 0.0.100 → 0.0.102

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 (61) hide show
  1. package/api/generated-index.js +23 -1
  2. package/bun.lock +2 -2
  3. package/dist/bundle.js +620 -412
  4. package/dist/index.d.ts +33 -4
  5. package/dist/index.js +43 -1
  6. package/dist/schema.d.ts +94 -1
  7. package/dist/schema.js +17 -1
  8. package/fake-snippets-api/lib/db/db-client.ts +38 -1
  9. package/fake-snippets-api/lib/db/schema.ts +15 -0
  10. package/fake-snippets-api/lib/public-mapping/public-map-package.ts +2 -0
  11. package/fake-snippets-api/routes/api/accounts/search.ts +20 -0
  12. package/fake-snippets-api/routes/api/github/installations/create_new_installation_redirect.ts +75 -0
  13. package/fake-snippets-api/routes/api/github/repos/list_available.ts +91 -0
  14. package/fake-snippets-api/routes/api/packages/update.ts +4 -0
  15. package/package.json +2 -2
  16. package/src/App.tsx +10 -1
  17. package/src/components/CmdKMenu.tsx +154 -19
  18. package/src/components/CreateReleaseDialog.tsx +124 -0
  19. package/src/components/FileSidebar.tsx +128 -23
  20. package/src/components/Header2.tsx +106 -25
  21. package/src/components/PackageBuildsPage/package-build-header.tsx +28 -16
  22. package/src/components/PageSearchComponent.tsx +2 -2
  23. package/src/components/SearchComponent.tsx +2 -2
  24. package/src/components/SuspenseRunFrame.tsx +2 -2
  25. package/src/components/TrendingPackagesCarousel.tsx +2 -2
  26. package/src/components/ViewPackagePage/components/important-files-view.tsx +18 -13
  27. package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +1 -0
  28. package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +1 -0
  29. package/src/components/dialogs/GitHubRepositorySelector.tsx +123 -0
  30. package/src/components/dialogs/create-use-dialog.tsx +8 -2
  31. package/src/components/dialogs/edit-package-details-dialog.tsx +22 -3
  32. package/src/components/dialogs/view-ts-files-dialog.tsx +178 -33
  33. package/src/components/package-port/CodeAndPreview.tsx +4 -1
  34. package/src/components/package-port/CodeEditor.tsx +42 -35
  35. package/src/components/package-port/CodeEditorHeader.tsx +26 -20
  36. package/src/components/package-port/EditorNav.tsx +94 -37
  37. package/src/components/preview/BuildsList.tsx +238 -0
  38. package/src/components/preview/ConnectedRepoDashboard.tsx +258 -0
  39. package/src/components/preview/ConnectedRepoOverview.tsx +454 -0
  40. package/src/components/preview/ConnectedRepoSettings.tsx +343 -0
  41. package/src/components/preview/ConnectedReposCards.tsx +191 -0
  42. package/src/components/preview/index.tsx +207 -0
  43. package/src/components/ui/tree-view.tsx +23 -6
  44. package/src/hooks/use-axios.ts +2 -2
  45. package/src/hooks/use-create-release-dialog.ts +160 -0
  46. package/src/hooks/use-package-details-form.ts +7 -0
  47. package/src/hooks/use-packages-base-api-url.ts +1 -1
  48. package/src/hooks/use-sign-in.ts +2 -2
  49. package/src/hooks/useFileManagement.ts +22 -2
  50. package/src/index.css +4 -0
  51. package/src/lib/utils/formatTimeAgo.ts +10 -0
  52. package/src/lib/utils/isValidFileName.ts +15 -3
  53. package/src/pages/dashboard.tsx +2 -2
  54. package/src/pages/dev-login.tsx +2 -2
  55. package/src/pages/landing.tsx +1 -1
  56. package/src/pages/latest.tsx +2 -2
  57. package/src/pages/preview-build.tsx +380 -0
  58. package/src/pages/search.tsx +2 -2
  59. package/src/pages/trending.tsx +2 -2
  60. package/src/pages/user-profile.tsx +32 -24
  61. package/src/pages/view-connected-repo.tsx +24 -0
@@ -27,7 +27,7 @@ import {
27
27
  } from "@/components/ui/tooltip"
28
28
  import { convertRawEasyToTsx, fetchEasyEDAComponent } from "easyeda/browser"
29
29
  import { ComponentSearchResult } from "@tscircuit/runframe/runner"
30
- import { usePackagesBaseApiUrl } from "@/hooks/use-packages-base-api-url"
30
+ import { useApiBaseUrl } from "@/hooks/use-packages-base-api-url"
31
31
  import { ICreateFileProps, ICreateFileResult } from "@/hooks/useFileManagement"
32
32
  import { useGlobalStore } from "@/hooks/use-global-store"
33
33
 
@@ -60,7 +60,7 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
60
60
  useImportComponentDialog()
61
61
  const { toast, toastLibrary } = useToast()
62
62
  const [sidebarOpen, setSidebarOpen] = fileSidebarState
63
- const API_BASE = usePackagesBaseApiUrl()
63
+ const API_BASE = useApiBaseUrl()
64
64
  const [aiAutocompleteEnabled, setAiAutocompleteEnabled] = aiAutocompleteState
65
65
  const session = useGlobalStore((s) => s.session)
66
66
 
@@ -162,29 +162,35 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
162
162
  if (!session?.token) {
163
163
  throw new Error("You need to be logged in to import jlcpcb component")
164
164
  }
165
- const jlcpcbComponent = await fetchEasyEDAComponent("C1", {
166
- fetch: ((url, options: any) => {
167
- return fetch(`${API_BASE}/proxy`, {
168
- body: options.body,
169
- method: options.method,
170
- headers: {
171
- authority: options.headers.authority,
172
- Authorization: `Bearer ${session?.token}`,
173
- "X-Target-Url": url.toString(),
174
- "X-Sender-Host": options.headers.origin,
175
- "X-Sender-Origin": options.headers.origin,
176
- "content-type": options.headers["content-type"],
177
- },
178
- })
179
- }) as typeof fetch,
180
- })
165
+
166
+ const jlcpcbComponent = await fetchEasyEDAComponent(
167
+ component.partNumber ?? component.name,
168
+ {
169
+ fetch: ((url, options: any) => {
170
+ return fetch(`${API_BASE}/proxy`, {
171
+ body: options.body,
172
+ method: options.method,
173
+ headers: {
174
+ authority: options.headers.authority,
175
+ Authorization: `Bearer ${session?.token}`,
176
+ "X-Target-Url": url.toString(),
177
+ "X-Sender-Host": options.headers.origin,
178
+ "X-Sender-Origin": options.headers.origin,
179
+ "content-type": options.headers["content-type"],
180
+ },
181
+ })
182
+ }) as typeof fetch,
183
+ },
184
+ )
181
185
  const tsxComponent = await convertRawEasyToTsx(jlcpcbComponent)
182
186
  let componentName = component.name.replace(/ /g, "-")
183
- if (files[`${componentName}.tsx`] || files[`./${componentName}.tsx`]) {
187
+ let componentPath = `imports/${componentName}.tsx`
188
+ if (files[componentPath] || files[`./${componentPath}`]) {
184
189
  componentName = `${componentName}-1`
190
+ componentPath = `imports/${componentName}.tsx`
185
191
  }
186
192
  const createFileResult = createFile({
187
- newFileName: `${componentName}.tsx`,
193
+ newFileName: componentPath,
188
194
  content: tsxComponent,
189
195
  onError: (error) => {
190
196
  throw error
@@ -45,6 +45,9 @@ import { useForkPackageMutation } from "@/hooks/useForkPackageMutation"
45
45
  import tscircuitCorePkg from "@tscircuit/core/package.json"
46
46
  import { useRenamePackageDialog } from "../dialogs/rename-package-dialog"
47
47
  import { useUpdatePackageDescriptionDialog } from "../dialogs/update-package-description-dialog"
48
+ import { useCreateReleaseDialog } from "@/hooks/use-create-release-dialog"
49
+ import { Tag } from "lucide-react"
50
+ import { CreateReleaseDialog } from "../CreateReleaseDialog"
48
51
 
49
52
  export default function EditorNav({
50
53
  circuitJson,
@@ -58,6 +61,8 @@ export default function EditorNav({
58
61
  onDiscard,
59
62
  packageType,
60
63
  isSaving,
64
+ files,
65
+ packageFilesMeta,
61
66
  }: {
62
67
  pkg?: Package | null
63
68
  circuitJson?: AnyCircuitElement[] | null
@@ -70,6 +75,13 @@ export default function EditorNav({
70
75
  isSaving: boolean
71
76
  onSave: () => void
72
77
  onDiscard?: () => void
78
+ files?: { path: string; content: string }[]
79
+ packageFilesMeta?: {
80
+ created_at: string
81
+ file_path: string
82
+ package_file_id: string
83
+ package_release_id: string
84
+ }[]
73
85
  }) {
74
86
  const [, navigate] = useLocation()
75
87
  const isLoggedIn = useGlobalStore((s) => Boolean(s.session))
@@ -84,6 +96,18 @@ export default function EditorNav({
84
96
  useConfirmDeletePackageDialog()
85
97
  const { Dialog: ViewTsFilesDialog, openDialog: openViewTsFilesDialog } =
86
98
  useViewTsFilesDialog()
99
+ const createReleaseDialog = useCreateReleaseDialog({
100
+ packageId: pkg?.package_id ?? "",
101
+ packageName: pkg?.unscoped_name ?? "",
102
+ currentVersion: pkg?.latest_version || undefined,
103
+ onSuccess: () => {
104
+ qc.invalidateQueries({ queryKey: ["packages"] })
105
+ qc.invalidateQueries({ queryKey: ["packages", pkg?.package_id] })
106
+ },
107
+ files: files || [],
108
+ currentPackage: pkg || undefined,
109
+ packageFilesMeta: packageFilesMeta || [],
110
+ })
87
111
 
88
112
  const [isChangingType, setIsChangingType] = useState(false)
89
113
  const [currentType, setCurrentType] = useState(
@@ -229,14 +253,25 @@ export default function EditorNav({
229
253
  </span>
230
254
  )}
231
255
  {pkg.owner_github_username === session?.github_username && (
232
- <Button
233
- variant="ghost"
234
- size="icon"
235
- className="h-6 w-6 ml-2"
236
- onClick={() => openRenameDialog()}
237
- >
238
- <Pencil className="h-3 w-3 text-gray-700" />
239
- </Button>
256
+ <>
257
+ <Button
258
+ variant="ghost"
259
+ size="icon"
260
+ className="h-6 w-6 ml-2"
261
+ onClick={() => openRenameDialog()}
262
+ >
263
+ <Pencil className="h-3 w-3 text-gray-700" />
264
+ </Button>
265
+ <Button
266
+ variant="ghost"
267
+ size="icon"
268
+ className="h-6 w-6 ml-2"
269
+ onClick={() => createReleaseDialog.openDialog()}
270
+ disabled={hasUnsavedChanges || isSaving}
271
+ >
272
+ <Tag className="h-3 w-3 text-gray-700" />
273
+ </Button>
274
+ </>
240
275
  )}
241
276
  {isPrivate && (
242
277
  <div className="relative group">
@@ -363,22 +398,23 @@ export default function EditorNav({
363
398
  <Eye className="mr-1 h-3 w-3" />
364
399
  Public
365
400
  </Button> */}
366
- {pkg && (
367
- <DropdownMenu>
368
- <DropdownMenuTrigger asChild>
369
- <Button variant="ghost" size="icon" className="hidden md:flex">
370
- <MoreVertical className="h-3 w-3" />
371
- </Button>
372
- </DropdownMenuTrigger>
373
- <DropdownMenuContent>
374
- <DropdownMenuItem
375
- className="text-xs"
376
- onClick={() => openViewTsFilesDialog()}
377
- >
378
- <File className="mr-2 h-3 w-3" />
379
- View Files
380
- </DropdownMenuItem>
381
- {session?.github_username === pkg.owner_github_username && (
401
+
402
+ <DropdownMenu>
403
+ <DropdownMenuTrigger asChild>
404
+ <Button variant="ghost" size="icon" className="hidden md:flex">
405
+ <MoreVertical className="h-3 w-3" />
406
+ </Button>
407
+ </DropdownMenuTrigger>
408
+ <DropdownMenuContent>
409
+ <DropdownMenuItem
410
+ className="text-xs"
411
+ onClick={() => openViewTsFilesDialog()}
412
+ >
413
+ <File className="mr-2 h-3 w-3" />
414
+ View Files
415
+ </DropdownMenuItem>
416
+ {pkg &&
417
+ session?.github_username === pkg?.owner_github_username && (
382
418
  <>
383
419
  <DropdownMenuItem
384
420
  className="text-xs"
@@ -436,21 +472,21 @@ export default function EditorNav({
436
472
  </DropdownMenuItem>
437
473
  </DropdownMenuSubContent>
438
474
  </DropdownMenuSub>
475
+ <DropdownMenuItem
476
+ className="text-xs text-red-600"
477
+ onClick={() => openDeleteDialog()}
478
+ >
479
+ <Trash2 className="mr-2 h-3 w-3" />
480
+ Delete Package
481
+ </DropdownMenuItem>
439
482
  </>
440
483
  )}
441
- <DropdownMenuItem
442
- className="text-xs text-red-600"
443
- onClick={() => openDeleteDialog()}
444
- >
445
- <Trash2 className="mr-2 h-3 w-3" />
446
- Delete Package
447
- </DropdownMenuItem>
448
- <DropdownMenuItem className="text-xs text-gray-500" disabled>
449
- @tscircuit/core@{tscircuitCorePkg.version}
450
- </DropdownMenuItem>
451
- </DropdownMenuContent>
452
- </DropdownMenu>
453
- )}
484
+ <DropdownMenuItem className="text-xs text-gray-500" disabled>
485
+ @tscircuit/core@{tscircuitCorePkg.version}
486
+ </DropdownMenuItem>
487
+ </DropdownMenuContent>
488
+ </DropdownMenu>
489
+
454
490
  <Button
455
491
  variant="ghost"
456
492
  size="icon"
@@ -488,6 +524,17 @@ export default function EditorNav({
488
524
  Discard Changes
489
525
  </DropdownMenuItem>
490
526
  )}
527
+ {pkg &&
528
+ session?.github_username === pkg?.owner_github_username && (
529
+ <DropdownMenuItem
530
+ className="text-xs"
531
+ onClick={() => createReleaseDialog.openDialog()}
532
+ disabled={hasUnsavedChanges || isSaving}
533
+ >
534
+ <Tag className="mr-1 h-3 w-3" />
535
+ Create Release
536
+ </DropdownMenuItem>
537
+ )}
491
538
  <DropdownMenuItem
492
539
  className="text-xs"
493
540
  onClick={() => {
@@ -561,6 +608,16 @@ export default function EditorNav({
561
608
  packageOwner={pkg?.owner_github_username ?? ""}
562
609
  />
563
610
  <ViewTsFilesDialog />
611
+ <CreateReleaseDialog
612
+ isOpen={createReleaseDialog.isOpen}
613
+ onClose={createReleaseDialog.closeDialog}
614
+ currentVersion={createReleaseDialog.currentVersion}
615
+ version={createReleaseDialog.version}
616
+ setVersion={createReleaseDialog.setVersion}
617
+ isLoading={createReleaseDialog.isLoading}
618
+ error={createReleaseDialog.error}
619
+ onCreateRelease={createReleaseDialog.handleCreateRelease}
620
+ />
564
621
  </nav>
565
622
  )
566
623
  }
@@ -0,0 +1,238 @@
1
+ import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
2
+ import { Badge } from "@/components/ui/badge"
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"
14
+ import {
15
+ DropdownMenu,
16
+ DropdownMenuContent,
17
+ DropdownMenuItem,
18
+ DropdownMenuTrigger,
19
+ } from "@/components/ui/dropdown-menu"
20
+ import {
21
+ Table,
22
+ TableBody,
23
+ TableCell,
24
+ TableHead,
25
+ TableHeader,
26
+ TableRow,
27
+ } from "@/components/ui/table"
28
+ import { getBuildStatus, PackageBuild, StatusIcon } from "."
29
+ import { formatTimeAgo } from "@/lib/utils/formatTimeAgo"
30
+
31
+ interface BuildsListProps {
32
+ builds: PackageBuild[]
33
+ onSelectBuild?: (build: PackageBuild) => void
34
+ }
35
+
36
+ export const BuildsList = ({ builds, onSelectBuild }: BuildsListProps) => {
37
+ return (
38
+ <div className="space-y-6">
39
+ <div className="flex items-center justify-between">
40
+ <div>
41
+ <h2 className="text-2xl font-bold text-gray-900">Builds</h2>
42
+ <p className="text-gray-600">Manage and monitor your builds</p>
43
+ </div>
44
+ <Button className="flex items-center gap-2">
45
+ <Plus className="w-4 h-4" />
46
+ Create Build
47
+ </Button>
48
+ </div>
49
+
50
+ <Card>
51
+ <CardHeader>
52
+ <CardTitle>Recent Deployments</CardTitle>
53
+ </CardHeader>
54
+ <CardContent>
55
+ <div className="overflow-x-auto">
56
+ <Table>
57
+ <TableHeader>
58
+ <TableRow>
59
+ <TableHead>Status</TableHead>
60
+ <TableHead>Build ID</TableHead>
61
+ <TableHead>Branch</TableHead>
62
+ <TableHead>Commit</TableHead>
63
+ <TableHead>Author</TableHead>
64
+ <TableHead>Created</TableHead>
65
+ <TableHead>Actions</TableHead>
66
+ </TableRow>
67
+ </TableHeader>
68
+ <TableBody>
69
+ {builds.map((build) => {
70
+ const { status, label } = getBuildStatus(build)
71
+
72
+ return (
73
+ <TableRow
74
+ key={build.package_build_id}
75
+ className="cursor-pointer hover:bg-gray-50"
76
+ onClick={() => onSelectBuild?.(build)}
77
+ >
78
+ <TableCell>
79
+ <div className="flex items-center gap-2">
80
+ <StatusIcon status={status} />
81
+ <Badge
82
+ variant={
83
+ status === "success"
84
+ ? "default"
85
+ : status === "error"
86
+ ? "destructive"
87
+ : "secondary"
88
+ }
89
+ className="text-xs"
90
+ >
91
+ {label}
92
+ </Badge>
93
+ </div>
94
+ </TableCell>
95
+ <TableCell>
96
+ <code className="text-sm bg-gray-100 px-2 py-1 rounded">
97
+ {build.package_build_id.slice(-8)}
98
+ </code>
99
+ </TableCell>
100
+ <TableCell>
101
+ <div className="flex items-center gap-2">
102
+ {build.branch_name?.includes("/") ? (
103
+ <GitBranch className="w-3 h-3 text-gray-500" />
104
+ ) : (
105
+ <GitCommit className="w-3 h-3 text-gray-500" />
106
+ )}
107
+ <Badge variant="outline" className="text-xs">
108
+ {build.branch_name || "main"}
109
+ </Badge>
110
+ </div>
111
+ </TableCell>
112
+ <TableCell>
113
+ <div className="max-w-xs">
114
+ <p className="text-sm font-medium truncate">
115
+ {build.commit_message || "No commit message"}
116
+ </p>
117
+ </div>
118
+ </TableCell>
119
+ <TableCell>
120
+ <span className="text-sm text-gray-600">
121
+ {build.commit_author || "Unknown"}
122
+ </span>
123
+ </TableCell>
124
+ <TableCell>
125
+ <span className="text-sm text-gray-600">
126
+ {formatTimeAgo(build.created_at)}
127
+ </span>
128
+ </TableCell>
129
+ <TableCell>
130
+ <div className="flex items-center gap-2">
131
+ <DropdownMenu>
132
+ <DropdownMenuTrigger asChild>
133
+ <Button
134
+ variant="ghost"
135
+ size="sm"
136
+ onClick={(e) => e.stopPropagation()}
137
+ >
138
+ <MoreHorizontal className="w-3 h-3" />
139
+ </Button>
140
+ </DropdownMenuTrigger>
141
+ <DropdownMenuContent align="end">
142
+ <DropdownMenuItem>View Details</DropdownMenuItem>
143
+ <DropdownMenuItem>View Logs</DropdownMenuItem>
144
+ <DropdownMenuItem>Redeploy</DropdownMenuItem>
145
+ <DropdownMenuItem className="text-red-600">
146
+ Cancel
147
+ </DropdownMenuItem>
148
+ </DropdownMenuContent>
149
+ </DropdownMenu>
150
+ </div>
151
+ </TableCell>
152
+ </TableRow>
153
+ )
154
+ })}
155
+ </TableBody>
156
+ </Table>
157
+ </div>
158
+ </CardContent>
159
+ </Card>
160
+
161
+ <div className="grid grid-cols-1 md:grid-cols-4 gap-4">
162
+ <Card>
163
+ <CardContent className="p-6">
164
+ <div className="flex items-center gap-3">
165
+ <div className="p-2 bg-green-100 rounded-lg">
166
+ <CheckCircle className="w-5 h-5 text-green-600" />
167
+ </div>
168
+ <div>
169
+ <p className="text-sm text-gray-600">Successful</p>
170
+ <p className="text-2xl font-bold text-gray-900">
171
+ {
172
+ builds.filter((d) => getBuildStatus(d).status === "success")
173
+ .length
174
+ }
175
+ </p>
176
+ </div>
177
+ </div>
178
+ </CardContent>
179
+ </Card>
180
+
181
+ <Card>
182
+ <CardContent className="p-6">
183
+ <div className="flex items-center gap-3">
184
+ <div className="p-2 bg-red-100 rounded-lg">
185
+ <AlertCircle className="w-5 h-5 text-red-600" />
186
+ </div>
187
+ <div>
188
+ <p className="text-sm text-gray-600">Failed</p>
189
+ <p className="text-2xl font-bold text-gray-900">
190
+ {
191
+ builds.filter((d) => getBuildStatus(d).status === "error")
192
+ .length
193
+ }
194
+ </p>
195
+ </div>
196
+ </div>
197
+ </CardContent>
198
+ </Card>
199
+
200
+ <Card>
201
+ <CardContent className="p-6">
202
+ <div className="flex items-center gap-3">
203
+ <div className="p-2 bg-blue-100 rounded-lg">
204
+ <Loader2 className="w-5 h-5 text-blue-600" />
205
+ </div>
206
+ <div>
207
+ <p className="text-sm text-gray-600">Building</p>
208
+ <p className="text-2xl font-bold text-gray-900">
209
+ {
210
+ builds.filter(
211
+ (d) => getBuildStatus(d).status === "building",
212
+ ).length
213
+ }
214
+ </p>
215
+ </div>
216
+ </div>
217
+ </CardContent>
218
+ </Card>
219
+
220
+ <Card>
221
+ <CardContent className="p-6">
222
+ <div className="flex items-center gap-3">
223
+ <div className="p-2 bg-gray-100 rounded-lg">
224
+ <Clock className="w-5 h-5 text-gray-600" />
225
+ </div>
226
+ <div>
227
+ <p className="text-sm text-gray-600">Total</p>
228
+ <p className="text-2xl font-bold text-gray-900">
229
+ {builds.length}
230
+ </p>
231
+ </div>
232
+ </div>
233
+ </CardContent>
234
+ </Card>
235
+ </div>
236
+ </div>
237
+ )
238
+ }