@tscircuit/fake-snippets 0.0.80 → 0.0.82

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 (37) hide show
  1. package/bun-tests/fake-snippets-api/routes/package_releases/create.test.ts +6 -0
  2. package/bun-tests/fake-snippets-api/routes/package_releases/update.test.ts +3 -0
  3. package/bun.lock +24 -18
  4. package/dist/bundle.js +25 -9
  5. package/dist/index.d.ts +10 -0
  6. package/dist/index.js +4 -1
  7. package/dist/schema.d.ts +16 -0
  8. package/dist/schema.js +4 -1
  9. package/fake-snippets-api/lib/db/schema.ts +4 -0
  10. package/fake-snippets-api/routes/api/package_releases/update.ts +14 -1
  11. package/fake-snippets-api/routes/api/packages/generate_from_jlcpcb.ts +3 -3
  12. package/package.json +5 -5
  13. package/src/components/JLCPCBImportDialog.tsx +164 -62
  14. package/src/components/PackageBuildsPage/LogContent.tsx +12 -5
  15. package/src/components/PackageBuildsPage/PackageBuildDetailsPage.tsx +8 -7
  16. package/src/components/PackageBuildsPage/build-preview-content.tsx +1 -1
  17. package/src/components/PackageBuildsPage/collapsible-section.tsx +14 -46
  18. package/src/components/PackageBuildsPage/package-build-details-panel.tsx +28 -10
  19. package/src/components/PackageBuildsPage/package-build-header.tsx +14 -2
  20. package/src/components/ViewPackagePage/components/build-status.tsx +24 -85
  21. package/src/components/ViewPackagePage/components/important-files-view.tsx +65 -2
  22. package/src/components/ViewPackagePage/components/repo-page-content.tsx +13 -0
  23. package/src/components/ViewPackagePage/components/sidebar-releases-section.tsx +28 -5
  24. package/src/components/package-port/CodeAndPreview.tsx +7 -1
  25. package/src/components/package-port/CodeEditor.tsx +9 -1
  26. package/src/hooks/use-current-package-release.ts +4 -2
  27. package/src/hooks/use-now.ts +12 -0
  28. package/src/hooks/use-package-release.ts +3 -2
  29. package/src/hooks/use-rebuild-package-release-mutation.ts +41 -0
  30. package/src/hooks/use-request-ai-review-mutation.ts +45 -0
  31. package/src/hooks/useFileManagement.ts +1 -2
  32. package/src/lib/codemirror/basic-setup.ts +17 -1
  33. package/src/pages/dashboard.tsx +3 -1
  34. package/src/pages/editor.tsx +5 -1
  35. package/src/pages/user-profile.tsx +9 -2
  36. package/src/pages/view-package.tsx +1 -0
  37. package/.github/workflows/formatbot.yml +0 -63
package/dist/index.d.ts CHANGED
@@ -435,6 +435,8 @@ declare const packageReleaseSchema: z.ZodObject<{
435
435
  circuit_json_build_completed_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
436
436
  circuit_json_build_logs: z.ZodDefault<z.ZodArray<z.ZodAny, "many">>;
437
437
  circuit_json_build_is_stale: z.ZodDefault<z.ZodBoolean>;
438
+ ai_review_text: z.ZodDefault<z.ZodNullable<z.ZodString>>;
439
+ ai_review_requested: z.ZodDefault<z.ZodBoolean>;
438
440
  }, "strip", z.ZodTypeAny, {
439
441
  package_release_id: string;
440
442
  created_at: string;
@@ -452,6 +454,8 @@ declare const packageReleaseSchema: z.ZodObject<{
452
454
  circuit_json_build_in_progress: boolean;
453
455
  circuit_json_build_logs: any[];
454
456
  circuit_json_build_is_stale: boolean;
457
+ ai_review_text: string | null;
458
+ ai_review_requested: boolean;
455
459
  commit_sha?: string | null | undefined;
456
460
  license?: string | null | undefined;
457
461
  circuit_json_build_error?: string | null | undefined;
@@ -491,6 +495,8 @@ declare const packageReleaseSchema: z.ZodObject<{
491
495
  circuit_json_build_completed_at?: string | null | undefined;
492
496
  circuit_json_build_logs?: any[] | undefined;
493
497
  circuit_json_build_is_stale?: boolean | undefined;
498
+ ai_review_text?: string | null | undefined;
499
+ ai_review_requested?: boolean | undefined;
494
500
  }>;
495
501
  type PackageRelease = z.infer<typeof packageReleaseSchema>;
496
502
  declare const packageFileSchema: z.ZodObject<{
@@ -760,6 +766,8 @@ declare const createDatabase: ({ seed }?: {
760
766
  circuit_json_build_in_progress: boolean;
761
767
  circuit_json_build_logs: any[];
762
768
  circuit_json_build_is_stale: boolean;
769
+ ai_review_text: string | null;
770
+ ai_review_requested: boolean;
763
771
  commit_sha?: string | null | undefined;
764
772
  license?: string | null | undefined;
765
773
  circuit_json_build_error?: string | null | undefined;
@@ -1070,6 +1078,8 @@ declare const createDatabase: ({ seed }?: {
1070
1078
  circuit_json_build_in_progress: boolean;
1071
1079
  circuit_json_build_logs: any[];
1072
1080
  circuit_json_build_is_stale: boolean;
1081
+ ai_review_text: string | null;
1082
+ ai_review_requested: boolean;
1073
1083
  commit_sha?: string | null | undefined;
1074
1084
  license?: string | null | undefined;
1075
1085
  circuit_json_build_error?: string | null | undefined;
package/dist/index.js CHANGED
@@ -165,7 +165,10 @@ var packageReleaseSchema = z.object({
165
165
  circuit_json_build_started_at: z.string().datetime().nullable().optional(),
166
166
  circuit_json_build_completed_at: z.string().datetime().nullable().optional(),
167
167
  circuit_json_build_logs: z.array(z.any()).default([]),
168
- circuit_json_build_is_stale: z.boolean().default(false)
168
+ circuit_json_build_is_stale: z.boolean().default(false),
169
+ // AI Review
170
+ ai_review_text: z.string().nullable().default(null),
171
+ ai_review_requested: z.boolean().default(false)
169
172
  });
170
173
  var packageFileSchema = z.object({
171
174
  package_file_id: z.string(),
package/dist/schema.d.ts CHANGED
@@ -560,6 +560,8 @@ declare const packageReleaseSchema: z.ZodObject<{
560
560
  circuit_json_build_completed_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
561
561
  circuit_json_build_logs: z.ZodDefault<z.ZodArray<z.ZodAny, "many">>;
562
562
  circuit_json_build_is_stale: z.ZodDefault<z.ZodBoolean>;
563
+ ai_review_text: z.ZodDefault<z.ZodNullable<z.ZodString>>;
564
+ ai_review_requested: z.ZodDefault<z.ZodBoolean>;
563
565
  }, "strip", z.ZodTypeAny, {
564
566
  package_release_id: string;
565
567
  created_at: string;
@@ -577,6 +579,8 @@ declare const packageReleaseSchema: z.ZodObject<{
577
579
  circuit_json_build_in_progress: boolean;
578
580
  circuit_json_build_logs: any[];
579
581
  circuit_json_build_is_stale: boolean;
582
+ ai_review_text: string | null;
583
+ ai_review_requested: boolean;
580
584
  commit_sha?: string | null | undefined;
581
585
  license?: string | null | undefined;
582
586
  circuit_json_build_error?: string | null | undefined;
@@ -616,6 +620,8 @@ declare const packageReleaseSchema: z.ZodObject<{
616
620
  circuit_json_build_completed_at?: string | null | undefined;
617
621
  circuit_json_build_logs?: any[] | undefined;
618
622
  circuit_json_build_is_stale?: boolean | undefined;
623
+ ai_review_text?: string | null | undefined;
624
+ ai_review_requested?: boolean | undefined;
619
625
  }>;
620
626
  type PackageRelease = z.infer<typeof packageReleaseSchema>;
621
627
  declare const packageFileSchema: z.ZodObject<{
@@ -939,6 +945,8 @@ declare const databaseSchema: z.ZodObject<{
939
945
  circuit_json_build_completed_at: z.ZodOptional<z.ZodNullable<z.ZodString>>;
940
946
  circuit_json_build_logs: z.ZodDefault<z.ZodArray<z.ZodAny, "many">>;
941
947
  circuit_json_build_is_stale: z.ZodDefault<z.ZodBoolean>;
948
+ ai_review_text: z.ZodDefault<z.ZodNullable<z.ZodString>>;
949
+ ai_review_requested: z.ZodDefault<z.ZodBoolean>;
942
950
  }, "strip", z.ZodTypeAny, {
943
951
  package_release_id: string;
944
952
  created_at: string;
@@ -956,6 +964,8 @@ declare const databaseSchema: z.ZodObject<{
956
964
  circuit_json_build_in_progress: boolean;
957
965
  circuit_json_build_logs: any[];
958
966
  circuit_json_build_is_stale: boolean;
967
+ ai_review_text: string | null;
968
+ ai_review_requested: boolean;
959
969
  commit_sha?: string | null | undefined;
960
970
  license?: string | null | undefined;
961
971
  circuit_json_build_error?: string | null | undefined;
@@ -995,6 +1005,8 @@ declare const databaseSchema: z.ZodObject<{
995
1005
  circuit_json_build_completed_at?: string | null | undefined;
996
1006
  circuit_json_build_logs?: any[] | undefined;
997
1007
  circuit_json_build_is_stale?: boolean | undefined;
1008
+ ai_review_text?: string | null | undefined;
1009
+ ai_review_requested?: boolean | undefined;
998
1010
  }>, "many">>;
999
1011
  packageFiles: z.ZodDefault<z.ZodArray<z.ZodObject<{
1000
1012
  package_file_id: z.ZodString;
@@ -1602,6 +1614,8 @@ declare const databaseSchema: z.ZodObject<{
1602
1614
  circuit_json_build_in_progress: boolean;
1603
1615
  circuit_json_build_logs: any[];
1604
1616
  circuit_json_build_is_stale: boolean;
1617
+ ai_review_text: string | null;
1618
+ ai_review_requested: boolean;
1605
1619
  commit_sha?: string | null | undefined;
1606
1620
  license?: string | null | undefined;
1607
1621
  circuit_json_build_error?: string | null | undefined;
@@ -1845,6 +1859,8 @@ declare const databaseSchema: z.ZodObject<{
1845
1859
  circuit_json_build_completed_at?: string | null | undefined;
1846
1860
  circuit_json_build_logs?: any[] | undefined;
1847
1861
  circuit_json_build_is_stale?: boolean | undefined;
1862
+ ai_review_text?: string | null | undefined;
1863
+ ai_review_requested?: boolean | undefined;
1848
1864
  }[] | undefined;
1849
1865
  packageFiles?: {
1850
1866
  package_release_id: string;
package/dist/schema.js CHANGED
@@ -160,7 +160,10 @@ var packageReleaseSchema = z.object({
160
160
  circuit_json_build_started_at: z.string().datetime().nullable().optional(),
161
161
  circuit_json_build_completed_at: z.string().datetime().nullable().optional(),
162
162
  circuit_json_build_logs: z.array(z.any()).default([]),
163
- circuit_json_build_is_stale: z.boolean().default(false)
163
+ circuit_json_build_is_stale: z.boolean().default(false),
164
+ // AI Review
165
+ ai_review_text: z.string().nullable().default(null),
166
+ ai_review_requested: z.boolean().default(false)
164
167
  });
165
168
  var packageFileSchema = z.object({
166
169
  package_file_id: z.string(),
@@ -201,6 +201,10 @@ export const packageReleaseSchema = z.object({
201
201
  circuit_json_build_completed_at: z.string().datetime().nullable().optional(),
202
202
  circuit_json_build_logs: z.array(z.any()).default([]),
203
203
  circuit_json_build_is_stale: z.boolean().default(false),
204
+
205
+ // AI Review
206
+ ai_review_text: z.string().nullable().default(null),
207
+ ai_review_requested: z.boolean().default(false),
204
208
  })
205
209
  export type PackageRelease = z.infer<typeof packageReleaseSchema>
206
210
 
@@ -12,6 +12,7 @@ export default withRouteSpec({
12
12
  license: z.string().optional(),
13
13
  fs_sha: z.string().optional(),
14
14
  ready_to_build: z.boolean().optional(),
15
+ ai_review_requested: z.boolean().optional(),
15
16
  }),
16
17
  jsonResponse: z.object({
17
18
  ok: z.boolean(),
@@ -25,6 +26,7 @@ export default withRouteSpec({
25
26
  license,
26
27
  fs_sha,
27
28
  ready_to_build,
29
+ ai_review_requested,
28
30
  } = req.jsonBody
29
31
  let releaseId = package_release_id
30
32
 
@@ -49,7 +51,14 @@ export default withRouteSpec({
49
51
  })
50
52
  }
51
53
 
52
- const delta = { is_locked, is_latest, license, fs_sha, ready_to_build }
54
+ const delta = {
55
+ is_locked,
56
+ is_latest,
57
+ license,
58
+ fs_sha,
59
+ ready_to_build,
60
+ ai_review_requested,
61
+ }
53
62
  if (
54
63
  Object.keys(delta).filter(
55
64
  (k) => delta[k as keyof typeof delta] !== undefined,
@@ -79,6 +88,10 @@ export default withRouteSpec({
79
88
  ...(license !== undefined && { license }),
80
89
  ...(fs_sha !== undefined && { fs_sha }),
81
90
  ...(ready_to_build !== undefined && { ready_to_build }),
91
+ ...(ai_review_requested !== undefined && { ai_review_requested }),
92
+ ...(ai_review_requested === true && {
93
+ ai_review_text: "Placeholder AI Review Text",
94
+ }),
82
95
  }
83
96
 
84
97
  // Handle is_latest updates atomically
@@ -46,9 +46,9 @@ export default withRouteSpec({
46
46
  const existingPackage = ctx.db.packages.find((p) => p.name === packageName)
47
47
 
48
48
  if (existingPackage) {
49
- return ctx.json({
50
- ok: true,
51
- package: existingPackage,
49
+ return ctx.error(409, {
50
+ error_code: "package_already_exists",
51
+ message: componentName,
52
52
  })
53
53
  }
54
54
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tscircuit/fake-snippets",
3
- "version": "0.0.80",
3
+ "version": "0.0.82",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -70,7 +70,7 @@
70
70
  "@radix-ui/react-toggle": "^1.1.0",
71
71
  "@radix-ui/react-toggle-group": "^1.1.0",
72
72
  "@radix-ui/react-tooltip": "^1.1.2",
73
- "@tscircuit/footprinter": "^0.0.169",
73
+ "@tscircuit/footprinter": "^0.0.176",
74
74
  "@tscircuit/layout": "^0.0.29",
75
75
  "@tscircuit/math-utils": "^0.0.10",
76
76
  "@tscircuit/mm": "^0.0.8",
@@ -126,7 +126,7 @@
126
126
  "recharts": "^2.12.7",
127
127
  "remark-gfm": "^4.0.1",
128
128
  "rollup-plugin-visualizer": "^5.12.0",
129
- "schematic-symbols": "^0.0.140",
129
+ "schematic-symbols": "^0.0.155",
130
130
  "sitemap": "^8.0.0",
131
131
  "sonner": "^1.5.0",
132
132
  "states-us": "^1.1.1",
@@ -146,7 +146,7 @@
146
146
  "@tailwindcss/typography": "^0.5.16",
147
147
  "@tscircuit/core": "^0.0.433",
148
148
  "@tscircuit/prompt-benchmarks": "^0.0.28",
149
- "@tscircuit/runframe": "^0.0.507",
149
+ "@tscircuit/runframe": "^0.0.562",
150
150
  "@types/babel__standalone": "^7.1.7",
151
151
  "@types/bun": "^1.1.10",
152
152
  "@types/country-list": "^2.1.4",
@@ -160,7 +160,7 @@
160
160
  "@typescript/vfs": "^1.6.0",
161
161
  "@vitejs/plugin-react": "^4.3.1",
162
162
  "autoprefixer": "^10.4.20",
163
- "circuit-to-svg": "^0.0.136",
163
+ "circuit-to-svg": "^0.0.152",
164
164
  "get-port": "^7.1.0",
165
165
  "globals": "^15.9.0",
166
166
  "he": "^1.2.0",
@@ -20,43 +20,102 @@ interface JLCPCBImportDialogProps {
20
20
  onOpenChange: (open: boolean) => void
21
21
  }
22
22
 
23
- export function JLCPCBImportDialog({
24
- open,
25
- onOpenChange,
26
- }: JLCPCBImportDialogProps) {
27
- const [partNumber, setPartNumber] = useState("")
28
- const [isLoading, setIsLoading] = useState(false)
29
- const [error, setError] = useState<string | null>(null)
30
- const [hasBeenImportedToAccountAlready, setHasBeenImportedToAccountAlready] =
31
- useState<boolean>(false)
23
+ interface ImportState {
24
+ isLoading: boolean
25
+ error: string | null
26
+ existingComponent: {
27
+ partNumber: string
28
+ username: string
29
+ } | null
30
+ }
31
+
32
+ interface JLCPCBResponse {
33
+ ok: boolean
34
+ package: {
35
+ package_id: string
36
+ }
37
+ }
38
+
39
+ interface APIError {
40
+ status: number
41
+ data?: {
42
+ message?: string
43
+ existing_part_number?: string
44
+ part_number?: string
45
+ error?: {
46
+ message?: string
47
+ }
48
+ }
49
+ }
50
+
51
+ const extractErrorMessage = (error: APIError): string => {
52
+ return (
53
+ error?.data?.message ||
54
+ error?.data?.error?.message ||
55
+ "An unexpected error occurred"
56
+ )
57
+ }
58
+
59
+ const extractExistingPartNumber = (
60
+ error: APIError,
61
+ fallback: string,
62
+ ): string => {
63
+ return error?.data?.message || error?.data?.error?.message || fallback
64
+ }
65
+
66
+ const useJLCPCBImport = () => {
67
+ const [state, setState] = useState<ImportState>({
68
+ isLoading: false,
69
+ error: null,
70
+ existingComponent: null,
71
+ })
72
+
32
73
  const axios = useAxios()
33
74
  const { toast } = useToast()
34
75
  const [, navigate] = useLocation()
35
- const isLoggedIn = useGlobalStore((s) => Boolean(s.session))
36
76
  const session = useGlobalStore((s) => s.session)
37
77
 
38
- const handleImport = async () => {
39
- if (!partNumber.startsWith("C")) {
78
+ const resetState = () => {
79
+ setState({
80
+ isLoading: false,
81
+ error: null,
82
+ existingComponent: null,
83
+ })
84
+ }
85
+
86
+ const importComponent = async (partNumber: string) => {
87
+ if (!partNumber.startsWith("C") || partNumber.length < 2) {
40
88
  toast({
41
89
  title: "Invalid Part Number",
42
- description: "JLCPCB part numbers should start with 'C'.",
90
+ description:
91
+ "JLCPCB part numbers should start with 'C' and be at least 2 characters long.",
43
92
  variant: "destructive",
44
93
  })
45
- return
94
+ return { success: false }
46
95
  }
47
96
 
48
- setIsLoading(true)
49
- setError(null)
50
- setHasBeenImportedToAccountAlready(false)
97
+ setState((prev) => ({
98
+ ...prev,
99
+ isLoading: true,
100
+ error: null,
101
+ existingComponent: null,
102
+ }))
51
103
 
52
104
  try {
53
- const response = await axios.post("/packages/generate_from_jlcpcb", {
54
- jlcpcb_part_number: partNumber,
55
- })
105
+ const response = await axios.post<JLCPCBResponse>(
106
+ "/packages/generate_from_jlcpcb",
107
+ {
108
+ jlcpcb_part_number: partNumber,
109
+ },
110
+ )
111
+
56
112
  if (!response.data.ok) {
57
- setError("Failed to generate package from JLCPCB part")
58
- setIsLoading(false)
59
- return
113
+ setState((prev) => ({
114
+ ...prev,
115
+ isLoading: false,
116
+ error: "Failed to generate package from JLCPCB part",
117
+ }))
118
+ return { success: false }
60
119
  }
61
120
 
62
121
  const { package: generatedPackage } = response.data
@@ -66,27 +125,84 @@ export function JLCPCBImportDialog({
66
125
  description: "JLCPCB component has been imported successfully.",
67
126
  })
68
127
 
69
- onOpenChange(false)
70
128
  navigate(`/editor?package_id=${generatedPackage.package_id}`)
129
+ return { success: true }
71
130
  } catch (error: any) {
72
- if (error.response?.status === 404) {
73
- setError(`Component with JLCPCB part number ${partNumber} not found`)
74
- } else if (error.response?.data?.message) {
75
- setError(error.response.data.message)
131
+ const apiError = error as APIError
132
+
133
+ if (apiError.status === 404) {
134
+ setState((prev) => ({
135
+ ...prev,
136
+ isLoading: false,
137
+ error: `Component with JLCPCB part number ${partNumber} not found`,
138
+ }))
139
+ } else if (apiError.status === 409) {
140
+ const existingPartNumber = extractExistingPartNumber(
141
+ apiError,
142
+ partNumber,
143
+ )
144
+ setState((prev) => ({
145
+ ...prev,
146
+ isLoading: false,
147
+ existingComponent: {
148
+ partNumber: existingPartNumber,
149
+ username: session?.github_username || "",
150
+ },
151
+ }))
76
152
  } else {
77
- setError("Failed to import the JLCPCB component. Please try again.")
153
+ const errorMessage = extractErrorMessage(apiError)
154
+ setState((prev) => ({ ...prev, isLoading: false, error: errorMessage }))
155
+
78
156
  toast({
79
157
  title: "Import Failed",
80
- description:
81
- "Failed to import the JLCPCB component. Please try again.",
158
+ description: errorMessage,
82
159
  variant: "destructive",
83
160
  })
84
161
  }
85
- } finally {
86
- setIsLoading(false)
162
+
163
+ return { success: false }
164
+ }
165
+ }
166
+
167
+ return {
168
+ ...state,
169
+ importComponent,
170
+ resetState,
171
+ }
172
+ }
173
+
174
+ export function JLCPCBImportDialog({
175
+ open,
176
+ onOpenChange,
177
+ }: JLCPCBImportDialogProps) {
178
+ const [partNumber, setPartNumber] = useState("")
179
+ const isLoggedIn = useGlobalStore((s) => Boolean(s.session))
180
+
181
+ const { isLoading, error, existingComponent, importComponent, resetState } =
182
+ useJLCPCBImport()
183
+
184
+ const handleImport = async () => {
185
+ const result = await importComponent(partNumber)
186
+ if (result.success) {
187
+ onOpenChange(false)
87
188
  }
88
189
  }
89
190
 
191
+ const handleInputChange = (value: string) => {
192
+ setPartNumber(value)
193
+ resetState()
194
+ }
195
+
196
+ const createGitHubIssue = () => {
197
+ const issueTitle = `[${partNumber}] Failed to import from JLCPCB`
198
+ const issueBody = `I tried to import the part number ${partNumber} from JLCPCB, but it failed. Here's the error I got:\n\`\`\`\n${error}\n\`\`\`\n\nCould be an issue in \`fetchEasyEDAComponent\` or \`convertRawEasyEdaToTs\``
199
+ const issueLabels = "snippets,good first issue"
200
+ const url = `https://github.com/tscircuit/easyeda-converter/issues/new?title=${encodeURIComponent(
201
+ issueTitle,
202
+ )}&body=${encodeURIComponent(issueBody)}&labels=${encodeURIComponent(issueLabels)}`
203
+ window.open(url, "_blank")
204
+ }
205
+
90
206
  return (
91
207
  <Dialog open={open} onOpenChange={onOpenChange}>
92
208
  <DialogContent>
@@ -96,6 +212,7 @@ export function JLCPCBImportDialog({
96
212
  Enter the JLCPCB part number to import the component.
97
213
  </DialogDescription>
98
214
  </DialogHeader>
215
+
99
216
  <div className="py-4 text-center">
100
217
  <a
101
218
  href="https://yaqwsx.github.io/jlcparts/#/"
@@ -105,16 +222,13 @@ export function JLCPCBImportDialog({
105
222
  >
106
223
  JLCPCB Part Search
107
224
  </a>
225
+
108
226
  <Input
109
227
  className="mt-3"
110
228
  placeholder="Enter JLCPCB part number (e.g., C46749)"
111
229
  value={partNumber}
112
230
  disabled={isLoading}
113
- onChange={(e) => {
114
- setPartNumber(e.target.value)
115
- setError(null)
116
- setHasBeenImportedToAccountAlready(false)
117
- }}
231
+ onChange={(e) => handleInputChange(e.target.value)}
118
232
  onKeyDown={(e) => {
119
233
  if (
120
234
  e.key === "Enter" &&
@@ -126,43 +240,31 @@ export function JLCPCBImportDialog({
126
240
  }
127
241
  }}
128
242
  />
129
- {error && !hasBeenImportedToAccountAlready && (
130
- <p className="bg-red-100 p-2 mt-2 pre-wrap">{error}</p>
131
- )}
132
243
 
133
- {error && !hasBeenImportedToAccountAlready && (
134
- <div className="flex justify-end mt-2">
135
- <Button
136
- variant="default"
137
- onClick={() => {
138
- const issueTitle = `[${partNumber}] Failed to import from JLCPCB`
139
- const issueBody = `I tried to import the part number ${partNumber} from JLCPCB, but it failed. Here's the error I got:\n\`\`\`\n${error}\n\`\`\`\n\nCould be an issue in \`fetchEasyEDAComponent\` or \`convertRawEasyEdaToTs\``
140
- const issueLabels = "snippets,good first issue"
141
- const url = `https://github.com/tscircuit/easyeda-converter/issues/new?title=${encodeURIComponent(
142
- issueTitle,
143
- )}&body=${encodeURIComponent(
144
- issueBody,
145
- )}&labels=${encodeURIComponent(issueLabels)}`
146
- window.open(url, "_blank")
147
- }}
148
- >
149
- File Issue on GitHub (prefilled)
150
- </Button>
151
- </div>
244
+ {error && !existingComponent && (
245
+ <>
246
+ <p className="bg-red-100 p-2 mt-2 pre-wrap">{error}</p>
247
+ <div className="flex justify-end mt-2">
248
+ <Button variant="default" onClick={createGitHubIssue}>
249
+ File Issue on GitHub (prefilled)
250
+ </Button>
251
+ </div>
252
+ </>
152
253
  )}
153
254
 
154
- {hasBeenImportedToAccountAlready && (
255
+ {existingComponent && (
155
256
  <p className="p-2 mt-2 pre-wrap text-md text-green-600">
156
257
  This part number has already been imported to your profile.{" "}
157
258
  <PrefetchPageLink
158
259
  className="text-blue-500 hover:underline"
159
- href={`/${session?.github_username}/${partNumber}`}
260
+ href={`/${existingComponent.username}/${existingComponent.partNumber}`}
160
261
  >
161
262
  View it here
162
263
  </PrefetchPageLink>
163
264
  </p>
164
265
  )}
165
266
  </div>
267
+
166
268
  <DialogFooter>
167
269
  <Button onClick={handleImport} disabled={isLoading || !isLoggedIn}>
168
270
  {!isLoggedIn
@@ -23,26 +23,33 @@ export const LogContent = ({
23
23
  error?: ErrorObject | string | null
24
24
  }) => {
25
25
  return (
26
- <div className="whitespace-pre-wrap font-mono text-xs">
26
+ <div className="font-mono text-xs space-y-1 min-w-0">
27
27
  {logs.map(
28
28
  (log, i) =>
29
29
  log.timestamp &&
30
30
  log.message && (
31
31
  <div
32
32
  key={i}
33
- className={
33
+ className={`break-words whitespace-pre-wrap ${
34
34
  log.type === "error"
35
35
  ? "text-red-600"
36
36
  : log.type === "success"
37
37
  ? "text-green-600"
38
38
  : "text-gray-600"
39
- }
39
+ }`}
40
40
  >
41
- {new Date(log.timestamp).toLocaleTimeString()} {log.message}
41
+ <span className="text-gray-500 whitespace-nowrap">
42
+ {new Date(log.timestamp).toLocaleTimeString()}
43
+ </span>{" "}
44
+ <span className="break-all">{log.message}</span>
42
45
  </div>
43
46
  ),
44
47
  )}
45
- {error && <div className="text-red-600">{getErrorText(error)}</div>}
48
+ {error && (
49
+ <div className="text-red-600 break-words whitespace-pre-wrap">
50
+ {getErrorText(error)}
51
+ </div>
52
+ )}
46
53
  </div>
47
54
  )
48
55
  }
@@ -1,13 +1,13 @@
1
1
  "use client"
2
2
 
3
+ import { useCurrentPackageRelease } from "@/hooks/use-current-package-release"
4
+ import { PackageRelease } from "fake-snippets-api/lib/db/schema"
3
5
  import { useState } from "react"
6
+ import { LogContent } from "./LogContent"
4
7
  import { BuildPreviewContent } from "./build-preview-content"
8
+ import { CollapsibleSection } from "./collapsible-section"
5
9
  import { PackageBuildDetailsPanel } from "./package-build-details-panel"
6
10
  import { PackageBuildHeader } from "./package-build-header"
7
- import { CollapsibleSection } from "./collapsible-section"
8
- import { useCurrentPackageRelease } from "@/hooks/use-current-package-release"
9
- import { LogContent } from "./LogContent"
10
- import { PackageRelease } from "fake-snippets-api/lib/db/schema"
11
11
 
12
12
  function computeDuration(
13
13
  startedAt: string | null | undefined,
@@ -18,7 +18,10 @@ function computeDuration(
18
18
  }
19
19
 
20
20
  export const PackageBuildDetailsPage = () => {
21
- const { packageRelease } = useCurrentPackageRelease({ include_logs: true })
21
+ const { packageRelease } = useCurrentPackageRelease({
22
+ include_logs: true,
23
+ refetchInterval: 2000,
24
+ })
22
25
  const [openSections, setOpenSections] = useState<Record<string, boolean>>({})
23
26
 
24
27
  const {
@@ -73,7 +76,6 @@ export const PackageBuildDetailsPage = () => {
73
76
  transpilation_completed_at,
74
77
  )}
75
78
  displayStatus={transpilation_display_status}
76
- error={transpilation_error}
77
79
  isOpen={openSections.summary}
78
80
  onToggle={() => toggleSection("summary")}
79
81
  >
@@ -94,7 +96,6 @@ export const PackageBuildDetailsPage = () => {
94
96
  circuit_json_build_completed_at,
95
97
  )}
96
98
  displayStatus={circuit_json_build_display_status}
97
- error={circuit_json_build_error}
98
99
  isOpen={openSections.logs}
99
100
  onToggle={() => toggleSection("logs")}
100
101
  >
@@ -2,7 +2,7 @@ import { useCurrentPackageInfo } from "@/hooks/use-current-package-info"
2
2
  import { useCurrentPackageRelease } from "@/hooks/use-current-package-release"
3
3
 
4
4
  export function BuildPreviewContent() {
5
- const { packageRelease } = useCurrentPackageRelease()
5
+ const { packageRelease } = useCurrentPackageRelease({ refetchInterval: 2000 })
6
6
  const { packageInfo } = useCurrentPackageInfo()
7
7
 
8
8
  if (!packageRelease) {