@tscircuit/fake-snippets 0.0.108 → 0.0.110
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.
- package/.github/workflows/bun-formatcheck.yml +2 -2
- package/.github/workflows/bun-pver-release.yml +3 -3
- package/.github/workflows/bun-test.yml +1 -1
- package/.github/workflows/bun-typecheck.yml +2 -2
- package/.github/workflows/update-snapshots.yml +1 -1
- package/README.md +4 -0
- package/api/generated-index.js +37 -3
- package/biome.json +2 -1
- package/bun-tests/fake-snippets-api/fixtures/get-test-server.ts +31 -3
- package/bun-tests/fake-snippets-api/fixtures/preload.ts +18 -0
- package/bun-tests/fake-snippets-api/routes/orgs/add_member.test.ts +26 -0
- package/bun-tests/fake-snippets-api/routes/orgs/create.test.ts +37 -0
- package/bun-tests/fake-snippets-api/routes/orgs/get.test.ts +52 -0
- package/bun-tests/fake-snippets-api/routes/orgs/list.test.ts +17 -0
- package/bun-tests/fake-snippets-api/routes/orgs/list_members.test.ts +23 -0
- package/bun-tests/fake-snippets-api/routes/orgs/remove_member.test.ts +81 -0
- package/bun-tests/fake-snippets-api/routes/orgs/update.test.ts +99 -0
- package/bun-tests/fake-snippets-api/routes/package_builds/get.test.ts +1 -1
- package/bun-tests/fake-snippets-api/routes/package_files/create.test.ts +15 -13
- package/bun-tests/fake-snippets-api/routes/package_files/create_or_update.test.ts +26 -24
- package/bun-tests/fake-snippets-api/routes/package_files/delete.test.ts +9 -9
- package/bun-tests/fake-snippets-api/routes/package_files/download.test.ts +4 -4
- package/bun-tests/fake-snippets-api/routes/package_files/get.test.ts +38 -28
- package/bun-tests/fake-snippets-api/routes/package_files/list.test.ts +23 -15
- package/bun-tests/fake-snippets-api/routes/package_releases/create.test.ts +33 -0
- package/bun-tests/fake-snippets-api/routes/package_releases/get.test.ts +4 -4
- package/bun-tests/fake-snippets-api/routes/package_releases/get_image_generation_fields.test.ts +38 -0
- package/bun-tests/fake-snippets-api/routes/packages/create.test.ts +19 -0
- package/bun-tests/fake-snippets-api/routes/packages/fork.test.ts +3 -4
- package/bun-tests/fake-snippets-api/routes/packages/get.test.ts +30 -0
- package/bun-tests/fake-snippets-api/routes/packages/images.test.ts +4 -2
- package/bun-tests/fake-snippets-api/routes/packages/list-1.test.ts +34 -0
- package/bun.lock +389 -450
- package/bunfig.toml +2 -1
- package/dist/bundle.js +1255 -625
- package/dist/index.d.ts +296 -4
- package/dist/index.js +325 -24
- package/dist/schema.d.ts +282 -1
- package/dist/schema.js +54 -2
- package/fake-snippets-api/lib/db/autoload-dev-packages.ts +31 -20
- package/fake-snippets-api/lib/db/db-client.ts +214 -3
- package/fake-snippets-api/lib/db/schema.ts +62 -0
- package/fake-snippets-api/lib/db/seed.ts +100 -0
- package/fake-snippets-api/lib/middleware/with-session-auth.ts +1 -1
- package/fake-snippets-api/lib/package_file/get-package-file-id-from-file-descriptor.ts +2 -2
- package/fake-snippets-api/lib/public-mapping/public-map-org.ts +32 -0
- package/fake-snippets-api/lib/public-mapping/public-map-package-build.ts +10 -0
- package/fake-snippets-api/lib/public-mapping/public-map-package-release.ts +17 -0
- package/fake-snippets-api/routes/api/orgs/add_member.ts +52 -0
- package/fake-snippets-api/routes/api/orgs/create.ts +46 -0
- package/fake-snippets-api/routes/api/orgs/get.ts +39 -0
- package/fake-snippets-api/routes/api/orgs/list.ts +31 -0
- package/fake-snippets-api/routes/api/orgs/list_members.ts +67 -0
- package/fake-snippets-api/routes/api/orgs/remove_member.ts +46 -0
- package/fake-snippets-api/routes/api/orgs/update.ts +93 -0
- package/fake-snippets-api/routes/api/package_files/get.ts +3 -6
- package/fake-snippets-api/routes/api/package_files/list.ts +7 -4
- package/fake-snippets-api/routes/api/packages/create.ts +54 -10
- package/fake-snippets-api/routes/api/packages/get.ts +23 -0
- package/fake-snippets-api/routes/api/packages/images/[owner_github_username]/[unscoped_name]/[view_format].ts +13 -11
- package/fake-snippets-api/routes/api/packages/list.ts +29 -2
- package/fake-snippets-api/routes/api/packages/update_ai_description.ts +37 -0
- package/package.json +27 -24
- package/renovate.json +1 -1
- package/scripts/generate-sitemap.ts +1 -1
- package/src/App.tsx +29 -10
- package/src/ContextProviders.tsx +25 -2
- package/src/components/CircuitJsonImportDialog.tsx +1 -1
- package/src/components/CmdKMenu.tsx +281 -247
- package/src/components/DownloadButtonAndMenu.tsx +133 -36
- package/src/components/FileSidebar.tsx +41 -50
- package/src/components/Footer.tsx +8 -10
- package/src/components/Header.tsx +19 -32
- package/src/components/Header2.tsx +16 -32
- package/src/components/HeaderDropdown.tsx +13 -8
- package/src/components/HeaderLogin.tsx +44 -16
- package/src/components/HiddenFilesDropdown.tsx +0 -2
- package/src/components/NotFound.tsx +5 -5
- package/src/components/PackageBreadcrumb.tsx +6 -12
- package/src/components/PackageCard.tsx +0 -1
- package/src/components/PackageSearchResults.tsx +1 -1
- package/src/components/PrefetchPageLink.tsx +7 -1
- package/src/components/ProfileRouter.tsx +32 -0
- package/src/components/SearchComponent.tsx +12 -8
- package/src/components/UserCard.tsx +80 -0
- package/src/components/ViewPackagePage/components/ShikiCodeViewer.tsx +20 -11
- package/src/components/ViewPackagePage/components/build-status.tsx +1 -1
- package/src/components/ViewPackagePage/components/important-files-view.tsx +174 -87
- package/src/components/ViewPackagePage/components/main-content-header.tsx +8 -4
- package/src/components/ViewPackagePage/components/main-content-view-selector.tsx +1 -2
- package/src/components/ViewPackagePage/components/mobile-sidebar.tsx +54 -20
- package/src/components/ViewPackagePage/components/package-header.tsx +26 -37
- package/src/components/ViewPackagePage/components/preview-image-squares.tsx +11 -19
- package/src/components/ViewPackagePage/components/repo-page-content.tsx +33 -25
- package/src/components/ViewPackagePage/components/sidebar-about-section.tsx +16 -10
- package/src/components/ViewPackagePage/components/sidebar-releases-section.tsx +11 -11
- package/src/components/ViewPackagePage/components/sidebar.tsx +0 -2
- package/src/components/ViewPackagePage/components/tab-views/files-view.tsx +18 -17
- package/src/components/ViewPackagePage/components/tab-views/pcb-view.tsx +1 -2
- package/src/components/ViewPackagePage/components/tab-views/schematic-view.tsx +2 -1
- package/src/components/ViewPackagePage/components/theme-toggle.tsx +0 -2
- package/src/components/ViewPackagePage/hooks/use-toast.tsx +0 -1
- package/src/components/dialogs/GitHubRepositorySelector.tsx +56 -49
- package/src/components/dialogs/edit-package-details-dialog.tsx +5 -6
- package/src/components/dialogs/import-component-dialog.tsx +16 -9
- package/src/components/dialogs/import-package-dialog.tsx +3 -2
- package/src/components/dialogs/new-package-save-prompt-dialog.tsx +190 -0
- package/src/components/organization/OrganizationCard.tsx +204 -0
- package/src/components/organization/OrganizationCardSkeleton.tsx +55 -0
- package/src/components/organization/OrganizationHeader.tsx +154 -0
- package/src/components/organization/OrganizationMembers.tsx +146 -0
- package/src/components/package-port/CodeAndPreview.tsx +32 -46
- package/src/components/package-port/CodeEditor.tsx +28 -31
- package/src/components/package-port/CodeEditorHeader.tsx +128 -63
- package/src/components/package-port/EditorNav.tsx +32 -49
- package/src/components/preview/ConnectedPackagesList.tsx +8 -8
- package/src/components/preview/ConnectedRepoOverview.tsx +102 -2
- package/src/components/preview/PackageReleasesDashboard.tsx +53 -36
- package/src/components/ui/tree-view.tsx +6 -3
- package/src/hooks/use-add-org-member-mutation.ts +51 -0
- package/src/hooks/use-create-org-mutation.ts +38 -0
- package/src/hooks/use-create-package-mutation.ts +3 -0
- package/src/hooks/use-current-package-id.ts +5 -30
- package/src/hooks/use-current-package-info.ts +29 -5
- package/src/hooks/use-current-package-release.ts +4 -3
- package/src/hooks/use-download-zip.ts +2 -2
- package/src/hooks/use-global-store.ts +6 -4
- package/src/hooks/use-jlcpcb-component-import.tsx +164 -0
- package/src/hooks/use-list-org-members.ts +27 -0
- package/src/hooks/use-list-user-orgs.ts +25 -0
- package/src/hooks/use-org-by-github-handle.ts +26 -0
- package/src/hooks/use-org.ts +24 -0
- package/src/hooks/use-organization.ts +42 -0
- package/src/hooks/use-package-as-snippet.ts +4 -2
- package/src/hooks/use-package-builds.ts +6 -2
- package/src/hooks/use-package-files.ts +5 -3
- package/src/hooks/use-package-release-by-id-or-version.ts +29 -20
- package/src/hooks/use-package-release-images.ts +105 -0
- package/src/hooks/use-package-release.ts +2 -2
- package/src/hooks/use-package-stars.ts +80 -4
- package/src/hooks/use-preview-images.ts +6 -3
- package/src/hooks/use-remove-org-member-mutation.ts +32 -0
- package/src/hooks/use-update-ai-description-mutation.ts +42 -0
- package/src/hooks/use-update-org-mutation.ts +41 -0
- package/src/hooks/use-warn-user-on-page-change.ts +71 -4
- package/src/hooks/useFileManagement.ts +183 -35
- package/src/hooks/useOptimizedPackageFilesLoader.ts +136 -0
- package/src/hooks/usePackageFilesLoader.ts +2 -2
- package/src/hooks/useUpdatePackageFilesMutation.ts +15 -1
- package/src/lib/download-fns/download-circuit-png.ts +11 -3
- package/src/lib/download-fns/download-gltf-from-circuit-json.ts +44 -0
- package/src/lib/download-fns/download-kicad-files.ts +12 -11
- package/src/lib/normalize-svg-for-tile.ts +50 -0
- package/src/lib/posthog.ts +11 -9
- package/src/lib/react-query-api-failure-tracking.ts +148 -0
- package/src/lib/sentry.ts +14 -0
- package/src/lib/templates/blank-circuit-board-template.ts +0 -4
- package/src/lib/ts-lib-cache.ts +122 -7
- package/src/lib/utils/checkIfManualEditsImported.ts +4 -4
- package/src/lib/utils/findTargetFile.ts +45 -10
- package/src/lib/utils/isComponentExported.ts +10 -0
- package/src/main.tsx +2 -1
- package/src/pages/authorize.tsx +0 -2
- package/src/pages/create-organization.tsx +168 -0
- package/src/pages/dashboard.tsx +38 -6
- package/src/pages/datasheet.tsx +1 -1
- package/src/pages/datasheets.tsx +3 -3
- package/src/pages/editor.tsx +4 -6
- package/src/pages/landing.tsx +6 -7
- package/src/pages/latest.tsx +3 -0
- package/src/pages/organization-profile.tsx +199 -0
- package/src/pages/organization-settings.tsx +566 -0
- package/src/pages/package-editor.tsx +21 -21
- package/src/pages/preview-release.tsx +76 -136
- package/src/pages/quickstart.tsx +159 -123
- package/src/pages/release-detail.tsx +119 -31
- package/src/pages/search.tsx +192 -57
- package/src/pages/settings-redirect.tsx +44 -0
- package/src/pages/trending.tsx +29 -20
- package/src/pages/user-profile.tsx +58 -7
- package/src/pages/view-package.tsx +21 -26
- package/vite.config.ts +9 -0
- package/fake-snippets-api/routes/api/autocomplete/create_autocomplete.ts +0 -133
- package/src/components/Footer2.tsx +0 -100
- package/src/components/JLCPCBImportDialog.tsx +0 -280
- package/src/components/PackageBuildsPage/LogContent.tsx +0 -72
- package/src/components/PackageBuildsPage/PackageBuildDetailsPage.tsx +0 -115
- package/src/components/PackageBuildsPage/build-preview-content.tsx +0 -27
- package/src/components/PackageBuildsPage/collapsible-section.tsx +0 -63
- package/src/components/PackageBuildsPage/package-build-details-panel.tsx +0 -166
- package/src/components/PackageBuildsPage/package-build-header.tsx +0 -79
- package/src/components/PageSearchComponent.tsx +0 -148
- package/src/components/ShippingInformationForm.tsx +0 -423
- package/src/components/StaticViewSnippetHeader.tsx +0 -70
- package/src/components/ViewPackagePage/components/file-explorer.tsx +0 -67
- package/src/components/ViewPackagePage/components/readme-view.tsx +0 -58
- package/src/components/ViewPackagePage/components/repo-header-button.tsx +0 -36
- package/src/components/ViewPackagePage/components/repo-header.tsx +0 -4
- package/src/components/ViewPackagePage/components/sidebar-contributors-section.tsx +0 -31
- package/src/components/ViewSnippetHeader.tsx +0 -181
- package/src/components/ui/input-otp.tsx +0 -69
- package/src/pages/package-builds.tsx +0 -33
- package/src/pages/settings.tsx +0 -25
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useCallback } from "react"
|
|
1
|
+
import React, { useState, useCallback, useMemo } from "react"
|
|
2
2
|
import { Button } from "@/components/ui/button"
|
|
3
3
|
import { handleManualEditsImportWithSupportForMultipleFiles } from "@/lib/handleManualEditsImportWithSupportForMultipleFiles"
|
|
4
4
|
import { useImportComponentDialog } from "@/components/dialogs/import-component-dialog"
|
|
@@ -25,11 +25,14 @@ import {
|
|
|
25
25
|
TooltipProvider,
|
|
26
26
|
TooltipTrigger,
|
|
27
27
|
} from "@/components/ui/tooltip"
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
28
|
+
import {
|
|
29
|
+
JlcpcbComponentTsxLoadedPayload,
|
|
30
|
+
KicadStringSelectedPayload,
|
|
31
|
+
TscircuitPackageSelectedPayload,
|
|
32
|
+
} from "@tscircuit/runframe/runner"
|
|
31
33
|
import { ICreateFileProps, ICreateFileResult } from "@/hooks/useFileManagement"
|
|
32
34
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
35
|
+
import { openJlcpcbImportIssue } from "@/hooks/use-jlcpcb-component-import"
|
|
33
36
|
|
|
34
37
|
export type FileName = string
|
|
35
38
|
|
|
@@ -41,6 +44,7 @@ interface CodeEditorHeaderProps {
|
|
|
41
44
|
handleFileChange: (filename: FileName) => void
|
|
42
45
|
entrypointFileName?: string
|
|
43
46
|
appendNewFile: (path: string, content: string) => void
|
|
47
|
+
isLoadingFiles: boolean
|
|
44
48
|
createFile: (props: ICreateFileProps) => ICreateFileResult
|
|
45
49
|
aiAutocompleteState: [boolean, React.Dispatch<React.SetStateAction<boolean>>]
|
|
46
50
|
}
|
|
@@ -49,8 +53,8 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
49
53
|
currentFile,
|
|
50
54
|
files,
|
|
51
55
|
updateFileContent,
|
|
52
|
-
appendNewFile,
|
|
53
56
|
fileSidebarState,
|
|
57
|
+
isLoadingFiles = true,
|
|
54
58
|
handleFileChange,
|
|
55
59
|
entrypointFileName = "index.tsx",
|
|
56
60
|
createFile,
|
|
@@ -58,12 +62,18 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
58
62
|
}) => {
|
|
59
63
|
const { Dialog: ImportComponentDialog, openDialog: openImportDialog } =
|
|
60
64
|
useImportComponentDialog()
|
|
61
|
-
const { toast
|
|
65
|
+
const { toast } = useToast()
|
|
62
66
|
const [sidebarOpen, setSidebarOpen] = fileSidebarState
|
|
63
|
-
const API_BASE = useApiBaseUrl()
|
|
64
67
|
const [aiAutocompleteEnabled, setAiAutocompleteEnabled] = aiAutocompleteState
|
|
65
68
|
const session = useGlobalStore((s) => s.session)
|
|
66
69
|
|
|
70
|
+
const jlcpcbProxyRequestHeaders = useMemo(() => {
|
|
71
|
+
if (!session?.token) return undefined
|
|
72
|
+
return {
|
|
73
|
+
Authorization: `Bearer ${session.token}`,
|
|
74
|
+
}
|
|
75
|
+
}, [session?.token])
|
|
76
|
+
|
|
67
77
|
const handleFormatFile = useCallback(() => {
|
|
68
78
|
if (!window.prettier || !window.prettierPlugins) return
|
|
69
79
|
if (!currentFile) return
|
|
@@ -153,54 +163,114 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
153
163
|
}
|
|
154
164
|
}, [currentFile, files, toast, updateFileContent])
|
|
155
165
|
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
166
|
+
const handleTscircuitPackageSelected = useCallback(
|
|
167
|
+
async ({ fullPackageName }: TscircuitPackageSelectedPayload) => {
|
|
168
|
+
if (!currentFile) {
|
|
169
|
+
const message = "Select a file before importing a component."
|
|
170
|
+
toast({
|
|
171
|
+
title: "No file selected",
|
|
172
|
+
description: message,
|
|
173
|
+
variant: "destructive",
|
|
174
|
+
})
|
|
175
|
+
throw new Error(message)
|
|
164
176
|
}
|
|
165
177
|
|
|
166
|
-
const
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
)
|
|
185
|
-
const tsxComponent = await convertRawEasyToTsx(jlcpcbComponent)
|
|
186
|
-
let componentName = component.name.replace(/ /g, "-")
|
|
187
|
-
let componentPath = `imports/${componentName}.tsx`
|
|
188
|
-
if (files[componentPath] || files[`./${componentPath}`]) {
|
|
189
|
-
componentName = `${componentName}-1`
|
|
190
|
-
componentPath = `imports/${componentName}.tsx`
|
|
191
|
-
}
|
|
192
|
-
const createFileResult = createFile({
|
|
193
|
-
newFileName: componentPath,
|
|
194
|
-
content: tsxComponent,
|
|
195
|
-
onError: (error) => {
|
|
196
|
-
throw error
|
|
197
|
-
},
|
|
178
|
+
const existingContent = files[currentFile] ?? ""
|
|
179
|
+
const newContent = `import {} from "${fullPackageName}"\n${existingContent}`
|
|
180
|
+
updateFileContent(currentFile, newContent)
|
|
181
|
+
toast({
|
|
182
|
+
title: "Component imported",
|
|
183
|
+
description: `Added ${fullPackageName} to ${currentFile}.`,
|
|
198
184
|
})
|
|
199
|
-
|
|
200
|
-
|
|
185
|
+
},
|
|
186
|
+
[currentFile, files, toast, updateFileContent],
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
const handleJlcpcbComponentTsxLoaded = useCallback(
|
|
190
|
+
async ({ result, tsx }: JlcpcbComponentTsxLoadedPayload) => {
|
|
191
|
+
const partNumber = result.component.partNumber || "component"
|
|
192
|
+
|
|
193
|
+
try {
|
|
194
|
+
const sanitizedBaseName = partNumber
|
|
195
|
+
.toLowerCase()
|
|
196
|
+
.replace(/[^a-z0-9_-]/gi, "-")
|
|
197
|
+
let componentPath = `imports/${sanitizedBaseName}.tsx`
|
|
198
|
+
let suffix = 1
|
|
199
|
+
while (files[componentPath] || files[`./${componentPath}`]) {
|
|
200
|
+
componentPath = `imports/${sanitizedBaseName}-${suffix}.tsx`
|
|
201
|
+
suffix += 1
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const createFileResult = createFile({
|
|
205
|
+
newFileName: componentPath,
|
|
206
|
+
content: tsx,
|
|
207
|
+
onError: (error) => {
|
|
208
|
+
throw error
|
|
209
|
+
},
|
|
210
|
+
})
|
|
211
|
+
|
|
212
|
+
if (!createFileResult.newFileCreated) {
|
|
213
|
+
throw new Error("Failed to create component file")
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
toast({
|
|
217
|
+
title: "Component imported",
|
|
218
|
+
description: `${partNumber} saved to ${componentPath}.`,
|
|
219
|
+
})
|
|
220
|
+
} catch (error) {
|
|
221
|
+
const message =
|
|
222
|
+
error instanceof Error
|
|
223
|
+
? error.message
|
|
224
|
+
: "Failed to import component from JLCPCB"
|
|
225
|
+
|
|
226
|
+
toast({
|
|
227
|
+
title: "JLCPCB import failed",
|
|
228
|
+
description: (
|
|
229
|
+
<div className="space-y-2">
|
|
230
|
+
<p>{message}</p>
|
|
231
|
+
<button
|
|
232
|
+
className="text-sm text-blue-500 hover:underline"
|
|
233
|
+
onClick={(event) => {
|
|
234
|
+
event.preventDefault()
|
|
235
|
+
openJlcpcbImportIssue(partNumber, message)
|
|
236
|
+
}}
|
|
237
|
+
>
|
|
238
|
+
File issue on GitHub
|
|
239
|
+
</button>
|
|
240
|
+
</div>
|
|
241
|
+
),
|
|
242
|
+
variant: "destructive",
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
throw new Error(message)
|
|
201
246
|
}
|
|
202
|
-
}
|
|
203
|
-
|
|
247
|
+
},
|
|
248
|
+
[createFile, files, toast],
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
const handleKicadStringSelected = useCallback(
|
|
252
|
+
async ({ footprint, result }: KicadStringSelectedPayload) => {
|
|
253
|
+
try {
|
|
254
|
+
await navigator.clipboard.writeText(footprint)
|
|
255
|
+
toast({
|
|
256
|
+
title: "KiCad footprint copied",
|
|
257
|
+
description: `${result.footprint.qualifiedName} copied to clipboard.`,
|
|
258
|
+
})
|
|
259
|
+
} catch (error) {
|
|
260
|
+
const message =
|
|
261
|
+
error instanceof Error
|
|
262
|
+
? error.message
|
|
263
|
+
: "Failed to copy KiCad footprint to clipboard"
|
|
264
|
+
toast({
|
|
265
|
+
title: "KiCad import failed",
|
|
266
|
+
description: message,
|
|
267
|
+
variant: "destructive",
|
|
268
|
+
})
|
|
269
|
+
throw new Error(message)
|
|
270
|
+
}
|
|
271
|
+
},
|
|
272
|
+
[toast],
|
|
273
|
+
)
|
|
204
274
|
|
|
205
275
|
return (
|
|
206
276
|
<>
|
|
@@ -230,7 +300,9 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
230
300
|
(filename) => !isHiddenFile(filename),
|
|
231
301
|
).length > 0
|
|
232
302
|
? "Select file"
|
|
233
|
-
:
|
|
303
|
+
: isLoadingFiles
|
|
304
|
+
? "Loading files..."
|
|
305
|
+
: "No files"
|
|
234
306
|
}
|
|
235
307
|
/>
|
|
236
308
|
</SelectTrigger>
|
|
@@ -342,17 +414,10 @@ export const CodeEditorHeader: React.FC<CodeEditorHeaderProps> = ({
|
|
|
342
414
|
</Button>
|
|
343
415
|
</div>
|
|
344
416
|
<ImportComponentDialog
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
error: (error) => (
|
|
350
|
-
<p>
|
|
351
|
-
Error importing component: {error.message || String(error)}
|
|
352
|
-
</p>
|
|
353
|
-
),
|
|
354
|
-
})
|
|
355
|
-
}}
|
|
417
|
+
onTscircuitPackageSelected={handleTscircuitPackageSelected}
|
|
418
|
+
onJlcpcbComponentTsxLoaded={handleJlcpcbComponentTsxLoaded}
|
|
419
|
+
onKicadStringSelected={handleKicadStringSelected}
|
|
420
|
+
jlcpcbProxyRequestHeaders={jlcpcbProxyRequestHeaders}
|
|
356
421
|
/>
|
|
357
422
|
</div>
|
|
358
423
|
</>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Button } from "@/components/ui/button"
|
|
2
|
-
import { GitFork, Star } from "lucide-react"
|
|
2
|
+
import { GitFork, Loader2, Star } from "lucide-react"
|
|
3
3
|
import {
|
|
4
4
|
DropdownMenu,
|
|
5
5
|
DropdownMenuContent,
|
|
@@ -42,7 +42,6 @@ import { useViewTsFilesDialog } from "@/components/dialogs/view-ts-files-dialog"
|
|
|
42
42
|
import { DownloadButtonAndMenu } from "@/components/DownloadButtonAndMenu"
|
|
43
43
|
import { TypeBadge } from "@/components/TypeBadge"
|
|
44
44
|
import { useForkPackageMutation } from "@/hooks/useForkPackageMutation"
|
|
45
|
-
import tscircuitCorePkg from "@tscircuit/core/package.json"
|
|
46
45
|
import { useRenamePackageDialog } from "../dialogs/rename-package-dialog"
|
|
47
46
|
import { useUpdatePackageDescriptionDialog } from "../dialogs/update-package-description-dialog"
|
|
48
47
|
import { useCreateReleaseDialog } from "@/hooks/use-create-release-dialog"
|
|
@@ -295,52 +294,37 @@ export default function EditorNav({
|
|
|
295
294
|
Not logged in, can't save
|
|
296
295
|
</div>
|
|
297
296
|
)}
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
297
|
+
{(canSavePackage || (isLoggedIn && pkg)) && (
|
|
298
|
+
<Button
|
|
299
|
+
variant="outline"
|
|
300
|
+
size="sm"
|
|
301
|
+
className={"ml-1 h-6 px-2 text-xs save-button"}
|
|
302
|
+
disabled={
|
|
303
|
+
canSavePackage && pkg ? !hasUnsavedChanges : !isLoggedIn
|
|
304
|
+
}
|
|
305
|
+
onClick={canSavePackage ? onSave : () => forkSnippet()}
|
|
306
|
+
>
|
|
307
|
+
{canSavePackage ? (
|
|
308
|
+
<>
|
|
309
|
+
<Save className="mr-1 h-3 w-3" />
|
|
310
|
+
Save
|
|
311
|
+
</>
|
|
312
|
+
) : (
|
|
313
|
+
<>
|
|
314
|
+
<GitFork className="mr-1 h-3 w-3" />
|
|
315
|
+
Fork
|
|
316
|
+
</>
|
|
317
|
+
)}
|
|
318
|
+
</Button>
|
|
319
|
+
)}
|
|
317
320
|
{isSaving && (
|
|
318
|
-
<div className="animate-fadeIn bg-blue-100 text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded flex items-center">
|
|
319
|
-
<
|
|
320
|
-
className="animate-spin h-3 w-3 mr-2 text-blue-600"
|
|
321
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
322
|
-
fill="none"
|
|
323
|
-
viewBox="0 0 24 24"
|
|
324
|
-
>
|
|
325
|
-
<circle
|
|
326
|
-
className="opacity-25"
|
|
327
|
-
cx="12"
|
|
328
|
-
cy="12"
|
|
329
|
-
r="10"
|
|
330
|
-
stroke="currentColor"
|
|
331
|
-
strokeWidth="4"
|
|
332
|
-
></circle>
|
|
333
|
-
<path
|
|
334
|
-
className="opacity-75"
|
|
335
|
-
fill="currentColor"
|
|
336
|
-
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
|
|
337
|
-
></path>
|
|
338
|
-
</svg>
|
|
321
|
+
<div className="animate-fadeIn bg-blue-100 select-none text-blue-800 text-xs font-medium px-2.5 py-0.5 rounded flex items-center">
|
|
322
|
+
<Loader2 className="animate-spin h-3 w-3 mr-2 text-blue-600" />
|
|
339
323
|
Saving...
|
|
340
324
|
</div>
|
|
341
325
|
)}
|
|
342
326
|
{hasUnsavedChanges && !isSaving && isLoggedIn && (
|
|
343
|
-
<div className="animate-fadeIn bg-yellow-100 text-yellow-800 text-xs font-medium px-2.5 py-0.5 rounded">
|
|
327
|
+
<div className="animate-fadeIn bg-yellow-100 select-none text-yellow-800 text-xs font-medium px-2.5 py-0.5 rounded">
|
|
344
328
|
{pkg ? "unsaved changes" : "unsaved"}
|
|
345
329
|
</div>
|
|
346
330
|
)}
|
|
@@ -359,7 +343,6 @@ export default function EditorNav({
|
|
|
359
343
|
</div>
|
|
360
344
|
<div className="flex items-center justify-end -space-x-1">
|
|
361
345
|
<div className="flex mx-2 items-center space-x-1">
|
|
362
|
-
{pkg && <TypeBadge type={`${packageType ?? pkg.snippet_type}`} />}
|
|
363
346
|
{/* <Button
|
|
364
347
|
variant="ghost"
|
|
365
348
|
size="sm"
|
|
@@ -481,9 +464,6 @@ export default function EditorNav({
|
|
|
481
464
|
</DropdownMenuItem>
|
|
482
465
|
</>
|
|
483
466
|
)}
|
|
484
|
-
<DropdownMenuItem className="text-xs text-gray-500" disabled>
|
|
485
|
-
@tscircuit/core@{tscircuitCorePkg.version}
|
|
486
|
-
</DropdownMenuItem>
|
|
487
467
|
</DropdownMenuContent>
|
|
488
468
|
</DropdownMenu>
|
|
489
469
|
|
|
@@ -505,7 +485,7 @@ export default function EditorNav({
|
|
|
505
485
|
)}
|
|
506
486
|
</Button>
|
|
507
487
|
</div>
|
|
508
|
-
<div className="flex items-center
|
|
488
|
+
<div className="flex items-center">
|
|
509
489
|
<DropdownMenu>
|
|
510
490
|
<DropdownMenuTrigger asChild>
|
|
511
491
|
<div className="md:hidden rounded-full p-1 hover:bg-gray-100 cursor-pointer">
|
|
@@ -514,7 +494,7 @@ export default function EditorNav({
|
|
|
514
494
|
</Button>
|
|
515
495
|
</div>
|
|
516
496
|
</DropdownMenuTrigger>
|
|
517
|
-
<DropdownMenuContent>
|
|
497
|
+
<DropdownMenuContent className="z-[101]">
|
|
518
498
|
{hasUnsavedChanges && onDiscard && (
|
|
519
499
|
<DropdownMenuItem
|
|
520
500
|
className="text-xs text-red-600"
|
|
@@ -601,6 +581,9 @@ export default function EditorNav({
|
|
|
601
581
|
<RenameDialog
|
|
602
582
|
packageId={pkg?.package_id ?? ""}
|
|
603
583
|
currentName={pkg?.unscoped_name ?? ""}
|
|
584
|
+
onRename={() => {
|
|
585
|
+
qc.invalidateQueries({ queryKey: ["package", pkg?.package_id] })
|
|
586
|
+
}}
|
|
604
587
|
/>
|
|
605
588
|
<DeleteDialog
|
|
606
589
|
packageId={pkg?.package_id ?? ""}
|
|
@@ -3,7 +3,7 @@ import { Badge } from "@/components/ui/badge"
|
|
|
3
3
|
import { Button } from "@/components/ui/button"
|
|
4
4
|
import { GitBranch, Rocket, Github } from "lucide-react"
|
|
5
5
|
import { cn } from "@/lib/utils"
|
|
6
|
-
import {
|
|
6
|
+
import { Link } from "wouter"
|
|
7
7
|
import { formatTimeAgo } from "@/lib/utils/formatTimeAgo"
|
|
8
8
|
import { getBuildStatus, StatusIcon } from "."
|
|
9
9
|
import { Package } from "fake-snippets-api/lib/db/schema"
|
|
@@ -116,12 +116,12 @@ export const ConnectedPackageCard = ({
|
|
|
116
116
|
>
|
|
117
117
|
<div className="flex items-start justify-between mb-4">
|
|
118
118
|
<div className="flex items-center gap-3">
|
|
119
|
-
<
|
|
120
|
-
href=
|
|
119
|
+
<Link
|
|
120
|
+
href={`/${pkg.owner_github_username}/${pkg.unscoped_name}`}
|
|
121
121
|
className="text-lg font-semibold text-gray-900 hover:text-blue-600 transition-colors"
|
|
122
122
|
>
|
|
123
123
|
{pkg.unscoped_name}
|
|
124
|
-
</
|
|
124
|
+
</Link>
|
|
125
125
|
</div>
|
|
126
126
|
|
|
127
127
|
<div className="flex items-center justify-center gap-2">
|
|
@@ -174,25 +174,25 @@ export const ConnectedPackageCard = ({
|
|
|
174
174
|
</div>
|
|
175
175
|
|
|
176
176
|
<div className="flex gap-2 w-full mt-auto">
|
|
177
|
-
<
|
|
177
|
+
<Link className="w-full" href={`/${pkg.name}/releases`}>
|
|
178
178
|
<Button
|
|
179
179
|
size="sm"
|
|
180
180
|
className="bg-blue-600 w-full hover:bg-blue-700 text-white px-4 py-2"
|
|
181
181
|
>
|
|
182
182
|
View
|
|
183
183
|
</Button>
|
|
184
|
-
</
|
|
184
|
+
</Link>
|
|
185
185
|
{latestBuildInfo?.preview_url &&
|
|
186
186
|
latestBuildInfo?.package_build_id &&
|
|
187
187
|
status === "success" && (
|
|
188
|
-
<
|
|
188
|
+
<Link
|
|
189
189
|
className="w-full"
|
|
190
190
|
href={`/${pkg.name}/releases/${latestBuildInfo.package_release_id}/preview`}
|
|
191
191
|
>
|
|
192
192
|
<Button size="sm" variant="outline" className="px-4 py-2 w-full">
|
|
193
193
|
Preview
|
|
194
194
|
</Button>
|
|
195
|
-
</
|
|
195
|
+
</Link>
|
|
196
196
|
)}
|
|
197
197
|
</div>
|
|
198
198
|
</Card>
|
|
@@ -41,6 +41,7 @@ export const ConnectedRepoOverview = ({
|
|
|
41
41
|
const [openSections, setOpenSections] = useState({
|
|
42
42
|
transpilation: false,
|
|
43
43
|
circuitJson: false,
|
|
44
|
+
imageGeneration: false,
|
|
44
45
|
})
|
|
45
46
|
|
|
46
47
|
// Gracefully handle when there is no build yet
|
|
@@ -120,15 +121,25 @@ export const ConnectedRepoOverview = ({
|
|
|
120
121
|
1000,
|
|
121
122
|
)
|
|
122
123
|
: 0
|
|
124
|
+
const imageGenerationDuration = packageBuild?.image_generation_started_at
|
|
125
|
+
? Math.floor(
|
|
126
|
+
(new Date(
|
|
127
|
+
packageBuild.image_generation_completed_at || new Date(),
|
|
128
|
+
).getTime() -
|
|
129
|
+
new Date(packageBuild.image_generation_started_at).getTime()) /
|
|
130
|
+
1000,
|
|
131
|
+
)
|
|
132
|
+
: 0
|
|
123
133
|
|
|
124
134
|
if (
|
|
125
135
|
!packageBuild?.transpilation_started_at &&
|
|
126
|
-
!packageBuild?.circuit_json_build_started_at
|
|
136
|
+
!packageBuild?.circuit_json_build_started_at &&
|
|
137
|
+
!packageBuild?.image_generation_started_at
|
|
127
138
|
) {
|
|
128
139
|
return null
|
|
129
140
|
}
|
|
130
141
|
|
|
131
|
-
return transpilationDuration + circuitJsonDuration
|
|
142
|
+
return transpilationDuration + circuitJsonDuration + imageGenerationDuration
|
|
132
143
|
})()
|
|
133
144
|
const toggleSection = (section: keyof typeof openSections) => {
|
|
134
145
|
setOpenSections((prev) => ({ ...prev, [section]: !prev[section] }))
|
|
@@ -482,6 +493,95 @@ export const ConnectedRepoOverview = ({
|
|
|
482
493
|
</div>
|
|
483
494
|
</CollapsibleContent>
|
|
484
495
|
</Collapsible>
|
|
496
|
+
|
|
497
|
+
<Collapsible
|
|
498
|
+
open={openSections.imageGeneration}
|
|
499
|
+
onOpenChange={() => toggleSection("imageGeneration")}
|
|
500
|
+
>
|
|
501
|
+
<CollapsibleTrigger asChild>
|
|
502
|
+
<div className="flex items-center justify-between p-4 bg-white border border-gray-200 rounded-lg cursor-pointer hover:bg-gray-50">
|
|
503
|
+
<div className="flex items-center gap-3">
|
|
504
|
+
<ChevronRight
|
|
505
|
+
className={`w-4 h-4 transition-transform ${openSections.imageGeneration ? "rotate-90" : ""}`}
|
|
506
|
+
/>
|
|
507
|
+
{packageBuild.image_generation_error ? (
|
|
508
|
+
<AlertCircle className="w-5 h-5 text-red-500" />
|
|
509
|
+
) : packageBuild.image_generation_completed_at ? (
|
|
510
|
+
<CheckCircle className="w-5 h-5 text-green-500" />
|
|
511
|
+
) : packageBuild.image_generation_in_progress ? (
|
|
512
|
+
<Loader2 className="w-5 h-5 text-blue-500 animate-spin" />
|
|
513
|
+
) : (
|
|
514
|
+
<Clock className="w-5 h-5 text-gray-400" />
|
|
515
|
+
)}
|
|
516
|
+
<span className="font-medium">Image Generation</span>
|
|
517
|
+
</div>
|
|
518
|
+
<div className="flex items-center gap-2">
|
|
519
|
+
{getStepDuration(
|
|
520
|
+
packageBuild.image_generation_started_at,
|
|
521
|
+
packageBuild.image_generation_completed_at,
|
|
522
|
+
) && (
|
|
523
|
+
<span className="text-sm text-gray-600">
|
|
524
|
+
{getStepDuration(
|
|
525
|
+
packageBuild.image_generation_started_at,
|
|
526
|
+
packageBuild.image_generation_completed_at,
|
|
527
|
+
)}
|
|
528
|
+
</span>
|
|
529
|
+
)}
|
|
530
|
+
<Badge
|
|
531
|
+
variant={
|
|
532
|
+
getStepStatus(
|
|
533
|
+
packageBuild.image_generation_error,
|
|
534
|
+
packageBuild.image_generation_completed_at,
|
|
535
|
+
packageBuild.image_generation_in_progress,
|
|
536
|
+
) === "success"
|
|
537
|
+
? "default"
|
|
538
|
+
: getStepStatus(
|
|
539
|
+
packageBuild.image_generation_error,
|
|
540
|
+
packageBuild.image_generation_completed_at,
|
|
541
|
+
packageBuild.image_generation_in_progress,
|
|
542
|
+
) === "error"
|
|
543
|
+
? "destructive"
|
|
544
|
+
: "secondary"
|
|
545
|
+
}
|
|
546
|
+
className="text-xs"
|
|
547
|
+
>
|
|
548
|
+
{packageBuild.image_generation_error
|
|
549
|
+
? "Failed"
|
|
550
|
+
: packageBuild.image_generation_completed_at
|
|
551
|
+
? "Completed"
|
|
552
|
+
: packageBuild.image_generation_in_progress
|
|
553
|
+
? "Running"
|
|
554
|
+
: "Queued"}
|
|
555
|
+
</Badge>
|
|
556
|
+
</div>
|
|
557
|
+
</div>
|
|
558
|
+
</CollapsibleTrigger>
|
|
559
|
+
<CollapsibleContent>
|
|
560
|
+
<div className="bg-white border-x border-b border-gray-200 rounded-b-lg p-4">
|
|
561
|
+
<div className="font-mono text-xs space-y-1">
|
|
562
|
+
{packageBuild.image_generation_error ? (
|
|
563
|
+
<div className="text-red-600 whitespace-pre-wrap">
|
|
564
|
+
{packageBuild.image_generation_error}
|
|
565
|
+
</div>
|
|
566
|
+
) : packageBuild.image_generation_logs &&
|
|
567
|
+
packageBuild.image_generation_logs.length > 0 ? (
|
|
568
|
+
packageBuild.image_generation_logs.map(
|
|
569
|
+
(log: any, i: number) => (
|
|
570
|
+
<div
|
|
571
|
+
key={i}
|
|
572
|
+
className="text-gray-600 whitespace-pre-wrap"
|
|
573
|
+
>
|
|
574
|
+
{log.msg || log.message || JSON.stringify(log)}
|
|
575
|
+
</div>
|
|
576
|
+
),
|
|
577
|
+
)
|
|
578
|
+
) : (
|
|
579
|
+
<div className="text-gray-500">No logs available</div>
|
|
580
|
+
)}
|
|
581
|
+
</div>
|
|
582
|
+
</div>
|
|
583
|
+
</CollapsibleContent>
|
|
584
|
+
</Collapsible>
|
|
485
585
|
</div>
|
|
486
586
|
</div>
|
|
487
587
|
)
|