@tscircuit/fake-snippets 0.0.74 → 0.0.76
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/bun-tests/fake-snippets-api/routes/package_releases/get.test.ts +38 -0
- package/bun-tests/fake-snippets-api/routes/packages/images.test.ts +14 -11
- package/bun.lock +1 -4
- package/dist/bundle.js +20 -8
- package/fake-snippets-api/lib/public-mapping/public-map-package-release.ts +11 -0
- package/fake-snippets-api/routes/api/package_releases/get.ts +6 -1
- package/fake-snippets-api/routes/api/package_releases/update.ts +4 -1
- package/package.json +1 -2
- package/src/components/DownloadButtonAndMenu.tsx +26 -8
- package/src/components/Header.tsx +7 -7
- package/src/components/PackageBuildsPage/ErrorObject.ts +12 -0
- package/src/components/PackageBuildsPage/LogContent.tsx +32 -0
- package/src/components/PackageBuildsPage/PackageBuildDetailsPage.tsx +62 -4
- package/src/components/PackageBuildsPage/build-preview-content.tsx +21 -5
- package/src/components/PackageBuildsPage/capitalCase.ts +4 -0
- package/src/components/PackageBuildsPage/collapsible-section.tsx +34 -9
- package/src/components/PackageBuildsPage/getColorForDisplayStatus.ts +17 -0
- package/src/components/PackageBuildsPage/package-build-details-panel.tsx +80 -17
- package/src/components/PackageBuildsPage/package-build-header.tsx +15 -30
- package/src/components/ViewPackagePage/components/main-content-header.tsx +1 -1
- package/src/components/ViewPackagePage/components/package-header.tsx +0 -1
- package/src/components/dialogs/pcb-download-dialog.tsx +113 -0
- package/src/lib/download-fns/download-pcb-svg.ts +35 -0
- package/src/lib/utils/timeAgo.ts +14 -3
- package/bun-tests/fake-snippets-api/fixtures/get-circuit-json.ts +0 -10
|
@@ -2,6 +2,11 @@ import * as ZT from "fake-snippets-api/lib/db/schema"
|
|
|
2
2
|
|
|
3
3
|
export const publicMapPackageRelease = (
|
|
4
4
|
internal_package_release: ZT.PackageRelease,
|
|
5
|
+
options: {
|
|
6
|
+
include_logs?: boolean
|
|
7
|
+
} = {
|
|
8
|
+
include_logs: false,
|
|
9
|
+
},
|
|
5
10
|
): ZT.PackageRelease => {
|
|
6
11
|
return {
|
|
7
12
|
...internal_package_release,
|
|
@@ -9,5 +14,11 @@ export const publicMapPackageRelease = (
|
|
|
9
14
|
circuit_json_build_error_last_updated_at:
|
|
10
15
|
internal_package_release.circuit_json_build_error_last_updated_at,
|
|
11
16
|
circuit_json_build_error: internal_package_release.circuit_json_build_error,
|
|
17
|
+
transpilation_logs: options.include_logs
|
|
18
|
+
? internal_package_release.transpilation_logs
|
|
19
|
+
: [],
|
|
20
|
+
circuit_json_build_logs: options.include_logs
|
|
21
|
+
? internal_package_release.circuit_json_build_logs
|
|
22
|
+
: [],
|
|
12
23
|
}
|
|
13
24
|
}
|
|
@@ -6,6 +6,9 @@ import { z } from "zod"
|
|
|
6
6
|
export default withRouteSpec({
|
|
7
7
|
methods: ["POST"],
|
|
8
8
|
auth: "none",
|
|
9
|
+
commonParams: z.object({
|
|
10
|
+
include_logs: z.boolean().optional().default(false),
|
|
11
|
+
}),
|
|
9
12
|
jsonBody: z.object({
|
|
10
13
|
package_release_id: z.string().optional(),
|
|
11
14
|
package_name_with_version: z.string().optional(),
|
|
@@ -115,6 +118,8 @@ export default withRouteSpec({
|
|
|
115
118
|
|
|
116
119
|
return ctx.json({
|
|
117
120
|
ok: true,
|
|
118
|
-
package_release: publicMapPackageRelease(foundRelease
|
|
121
|
+
package_release: publicMapPackageRelease(foundRelease, {
|
|
122
|
+
include_logs: req.commonParams?.include_logs,
|
|
123
|
+
}),
|
|
119
124
|
})
|
|
120
125
|
})
|
|
@@ -11,6 +11,7 @@ export default withRouteSpec({
|
|
|
11
11
|
is_latest: z.boolean().optional(),
|
|
12
12
|
license: z.string().optional(),
|
|
13
13
|
fs_sha: z.string().optional(),
|
|
14
|
+
ready_to_build: z.boolean().optional(),
|
|
14
15
|
}),
|
|
15
16
|
jsonResponse: z.object({
|
|
16
17
|
ok: z.boolean(),
|
|
@@ -23,6 +24,7 @@ export default withRouteSpec({
|
|
|
23
24
|
is_latest,
|
|
24
25
|
license,
|
|
25
26
|
fs_sha,
|
|
27
|
+
ready_to_build,
|
|
26
28
|
} = req.jsonBody
|
|
27
29
|
let releaseId = package_release_id
|
|
28
30
|
|
|
@@ -47,7 +49,7 @@ export default withRouteSpec({
|
|
|
47
49
|
})
|
|
48
50
|
}
|
|
49
51
|
|
|
50
|
-
const delta = { is_locked, is_latest, license, fs_sha }
|
|
52
|
+
const delta = { is_locked, is_latest, license, fs_sha, ready_to_build }
|
|
51
53
|
if (
|
|
52
54
|
Object.keys(delta).filter(
|
|
53
55
|
(k) => delta[k as keyof typeof delta] !== undefined,
|
|
@@ -76,6 +78,7 @@ export default withRouteSpec({
|
|
|
76
78
|
...(is_latest !== undefined && { is_latest }),
|
|
77
79
|
...(license !== undefined && { license }),
|
|
78
80
|
...(fs_sha !== undefined && { fs_sha }),
|
|
81
|
+
...(ready_to_build !== undefined && { ready_to_build }),
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
// Handle is_latest updates atomically
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tscircuit/fake-snippets",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.76",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -70,7 +70,6 @@
|
|
|
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/eval": "^0.0.198",
|
|
74
73
|
"@tscircuit/footprinter": "^0.0.169",
|
|
75
74
|
"@tscircuit/layout": "^0.0.29",
|
|
76
75
|
"@tscircuit/math-utils": "^0.0.10",
|
|
@@ -13,6 +13,8 @@ import { downloadFabricationFiles } from "@/lib/download-fns/download-fabricatio
|
|
|
13
13
|
import { downloadSchematicSvg } from "@/lib/download-fns/download-schematic-svg"
|
|
14
14
|
import { downloadReadableNetlist } from "@/lib/download-fns/download-readable-netlist"
|
|
15
15
|
import { downloadAssemblySvg } from "@/lib/download-fns/download-assembly-svg"
|
|
16
|
+
import { downloadPcbSvg } from "@/lib/download-fns/download-pcb-svg"
|
|
17
|
+
import { usePcbDownloadDialog } from "@/components/dialogs/pcb-download-dialog"
|
|
16
18
|
import { downloadKicadFiles } from "@/lib/download-fns/download-kicad-files"
|
|
17
19
|
import { AnyCircuitElement } from "circuit-json"
|
|
18
20
|
import { ChevronDown, Download, Hammer } from "lucide-react"
|
|
@@ -31,18 +33,19 @@ export function DownloadButtonAndMenu({
|
|
|
31
33
|
circuitJson,
|
|
32
34
|
}: DownloadButtonAndMenuProps) {
|
|
33
35
|
const notImplemented = useNotImplementedToast()
|
|
36
|
+
const { Dialog: PcbDownloadDialog, openDialog: openPcbDownloadDialog } =
|
|
37
|
+
usePcbDownloadDialog()
|
|
34
38
|
|
|
35
39
|
if (!circuitJson) {
|
|
36
40
|
return (
|
|
37
41
|
<div className={className}>
|
|
38
42
|
<Button
|
|
39
43
|
disabled
|
|
40
|
-
variant="ghost"
|
|
41
44
|
size="sm"
|
|
42
|
-
className="h-9
|
|
45
|
+
className="h-9 bg-muted text-muted-foreground border border-input cursor-not-allowed"
|
|
43
46
|
>
|
|
44
47
|
<Download className="h-4 w-4 mr-1.5" />
|
|
45
|
-
|
|
48
|
+
Download
|
|
46
49
|
<ChevronDown className="h-4 w-4 ml-0.5" />
|
|
47
50
|
</Button>
|
|
48
51
|
</div>
|
|
@@ -54,13 +57,12 @@ export function DownloadButtonAndMenu({
|
|
|
54
57
|
<DropdownMenu>
|
|
55
58
|
<DropdownMenuTrigger asChild>
|
|
56
59
|
<Button
|
|
57
|
-
variant="outline"
|
|
58
60
|
size="sm"
|
|
59
|
-
className="
|
|
61
|
+
className="bg-white text-gray-900 hover:bg-gray-100 border border-gray-300 px-1 pl-2"
|
|
60
62
|
>
|
|
61
|
-
<Download className="
|
|
62
|
-
|
|
63
|
-
<ChevronDown className="
|
|
63
|
+
<Download className="w-4 h-4 mr-2" />
|
|
64
|
+
Download
|
|
65
|
+
<ChevronDown className="w-4 h-4 ml-1" />
|
|
64
66
|
</Button>
|
|
65
67
|
</DropdownMenuTrigger>
|
|
66
68
|
<DropdownMenuContent>
|
|
@@ -175,6 +177,18 @@ export function DownloadButtonAndMenu({
|
|
|
175
177
|
svg
|
|
176
178
|
</span>
|
|
177
179
|
</DropdownMenuItem>
|
|
180
|
+
<DropdownMenuItem
|
|
181
|
+
className="text-xs"
|
|
182
|
+
onSelect={() => {
|
|
183
|
+
openPcbDownloadDialog()
|
|
184
|
+
}}
|
|
185
|
+
>
|
|
186
|
+
<Download className="mr-1 h-3 w-3" />
|
|
187
|
+
<span className="flex-grow mr-6">PCB SVG</span>
|
|
188
|
+
<span className="text-[0.6rem] opacity-80 bg-blue-500 text-white font-mono rounded-md px-1 text-center py-0.5 mr-1">
|
|
189
|
+
svg
|
|
190
|
+
</span>
|
|
191
|
+
</DropdownMenuItem>
|
|
178
192
|
<DropdownMenuItem
|
|
179
193
|
className="text-xs"
|
|
180
194
|
onSelect={() => {
|
|
@@ -219,6 +233,10 @@ export function DownloadButtonAndMenu({
|
|
|
219
233
|
</DropdownMenuItem>
|
|
220
234
|
</DropdownMenuContent>
|
|
221
235
|
</DropdownMenu>
|
|
236
|
+
<PcbDownloadDialog
|
|
237
|
+
circuitJson={circuitJson}
|
|
238
|
+
fileName={snippetUnscopedName || "circuit"}
|
|
239
|
+
/>
|
|
222
240
|
</div>
|
|
223
241
|
)
|
|
224
242
|
}
|
|
@@ -2,14 +2,9 @@ import { HeaderLogin } from "@/components/HeaderLogin"
|
|
|
2
2
|
import { Button } from "@/components/ui/button"
|
|
3
3
|
import { useGlobalStore } from "@/hooks/use-global-store"
|
|
4
4
|
import { cn } from "@/lib/utils"
|
|
5
|
-
import {
|
|
6
|
-
GitHubLogoIcon,
|
|
7
|
-
OpenInNewWindowIcon,
|
|
8
|
-
ChatBubbleIcon,
|
|
9
|
-
DiscordLogoIcon,
|
|
10
|
-
} from "@radix-ui/react-icons"
|
|
5
|
+
import { GitHubLogoIcon, DiscordLogoIcon } from "@radix-ui/react-icons"
|
|
11
6
|
import { Menu, X } from "lucide-react"
|
|
12
|
-
import React, { useState } from "react"
|
|
7
|
+
import React, { useEffect, useState } from "react"
|
|
13
8
|
import { useLocation } from "wouter"
|
|
14
9
|
import { PrefetchPageLink } from "./PrefetchPageLink"
|
|
15
10
|
import CmdKMenu from "./CmdKMenu"
|
|
@@ -55,6 +50,11 @@ const HeaderButton = ({
|
|
|
55
50
|
export default function Header() {
|
|
56
51
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
|
57
52
|
const isLoggedIn = useGlobalStore((s) => Boolean(s.session))
|
|
53
|
+
const sessionToken = useGlobalStore((s) => s.session?.token)
|
|
54
|
+
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
window.TSCIRCUIT_REGISTRY_TOKEN = sessionToken ?? ""
|
|
57
|
+
}, [sessionToken])
|
|
58
58
|
|
|
59
59
|
return (
|
|
60
60
|
<header className="px-4 py-3">
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
type ErrorObject =
|
|
2
|
+
| {
|
|
3
|
+
message: string
|
|
4
|
+
}
|
|
5
|
+
| string
|
|
6
|
+
|
|
7
|
+
const getErrorText = (error: ErrorObject | string) => {
|
|
8
|
+
if (typeof error === "string") {
|
|
9
|
+
return error
|
|
10
|
+
}
|
|
11
|
+
return error.message
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export const LogContent = ({
|
|
15
|
+
logs,
|
|
16
|
+
error,
|
|
17
|
+
}: { logs: any[]; error?: ErrorObject | string | null }) => {
|
|
18
|
+
return (
|
|
19
|
+
<div className="whitespace-pre-wrap font-mono text-xs">
|
|
20
|
+
{logs.map((log) =>
|
|
21
|
+
log.msg || log.message ? (
|
|
22
|
+
<div>{log.msg ?? log.message}</div>
|
|
23
|
+
) : (
|
|
24
|
+
<div>
|
|
25
|
+
<pre>{log.message}</pre>
|
|
26
|
+
</div>
|
|
27
|
+
),
|
|
28
|
+
)}
|
|
29
|
+
{error && <div className="text-red-600">{getErrorText(error)}</div>}
|
|
30
|
+
</div>
|
|
31
|
+
)
|
|
32
|
+
}
|
|
@@ -5,10 +5,40 @@ import { BuildPreviewContent } from "./build-preview-content"
|
|
|
5
5
|
import { PackageBuildDetailsPanel } from "./package-build-details-panel"
|
|
6
6
|
import { PackageBuildHeader } from "./package-build-header"
|
|
7
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
|
+
|
|
12
|
+
function computeDuration(
|
|
13
|
+
startedAt: string | null | undefined,
|
|
14
|
+
completedAt: string | null | undefined,
|
|
15
|
+
) {
|
|
16
|
+
if (!startedAt || !completedAt) return ""
|
|
17
|
+
return `${Math.floor((new Date(completedAt).getTime() - new Date(startedAt).getTime()) / 1000)}s`
|
|
18
|
+
}
|
|
8
19
|
|
|
9
20
|
export const PackageBuildDetailsPage = () => {
|
|
21
|
+
const { packageRelease } = useCurrentPackageRelease()
|
|
10
22
|
const [openSections, setOpenSections] = useState<Record<string, boolean>>({})
|
|
11
23
|
|
|
24
|
+
const {
|
|
25
|
+
circuit_json_build_logs,
|
|
26
|
+
circuit_json_build_completed_at,
|
|
27
|
+
circuit_json_build_in_progress,
|
|
28
|
+
circuit_json_build_is_stale,
|
|
29
|
+
circuit_json_build_started_at,
|
|
30
|
+
circuit_json_build_error,
|
|
31
|
+
circuit_json_build_error_last_updated_at,
|
|
32
|
+
transpilation_completed_at,
|
|
33
|
+
transpilation_in_progress,
|
|
34
|
+
transpilation_is_stale,
|
|
35
|
+
transpilation_logs,
|
|
36
|
+
transpilation_started_at,
|
|
37
|
+
circuit_json_build_display_status,
|
|
38
|
+
transpilation_display_status,
|
|
39
|
+
transpilation_error,
|
|
40
|
+
} = packageRelease ?? ({} as Partial<PackageRelease>)
|
|
41
|
+
|
|
12
42
|
const toggleSection = (section: string) => {
|
|
13
43
|
setOpenSections((prev) => ({
|
|
14
44
|
...prev,
|
|
@@ -38,17 +68,45 @@ export const PackageBuildDetailsPage = () => {
|
|
|
38
68
|
<div className="space-y-4 mb-8">
|
|
39
69
|
<CollapsibleSection
|
|
40
70
|
title="Transpilation Logs"
|
|
41
|
-
duration=
|
|
71
|
+
duration={computeDuration(
|
|
72
|
+
transpilation_started_at,
|
|
73
|
+
transpilation_completed_at,
|
|
74
|
+
)}
|
|
75
|
+
displayStatus={transpilation_display_status}
|
|
76
|
+
error={transpilation_error}
|
|
42
77
|
isOpen={openSections.summary}
|
|
43
78
|
onToggle={() => toggleSection("summary")}
|
|
44
|
-
|
|
79
|
+
>
|
|
80
|
+
<LogContent
|
|
81
|
+
logs={
|
|
82
|
+
packageRelease?.transpilation_logs ?? [
|
|
83
|
+
{ msg: "No transpilation logs available" },
|
|
84
|
+
]
|
|
85
|
+
}
|
|
86
|
+
error={transpilation_error}
|
|
87
|
+
/>
|
|
88
|
+
</CollapsibleSection>
|
|
45
89
|
|
|
46
90
|
<CollapsibleSection
|
|
47
91
|
title="Circuit JSON Build Logs"
|
|
48
|
-
duration=
|
|
92
|
+
duration={computeDuration(
|
|
93
|
+
circuit_json_build_started_at,
|
|
94
|
+
circuit_json_build_completed_at,
|
|
95
|
+
)}
|
|
96
|
+
displayStatus={circuit_json_build_display_status}
|
|
97
|
+
error={circuit_json_build_error}
|
|
49
98
|
isOpen={openSections.logs}
|
|
50
99
|
onToggle={() => toggleSection("logs")}
|
|
51
|
-
|
|
100
|
+
>
|
|
101
|
+
<LogContent
|
|
102
|
+
logs={
|
|
103
|
+
packageRelease?.circuit_json_build_logs ?? [
|
|
104
|
+
{ msg: "No Circuit JSON logs available" },
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
error={circuit_json_build_error!}
|
|
108
|
+
/>
|
|
109
|
+
</CollapsibleSection>
|
|
52
110
|
</div>
|
|
53
111
|
</div>
|
|
54
112
|
</div>
|
|
@@ -1,11 +1,27 @@
|
|
|
1
|
+
import { useCurrentPackageInfo } from "@/hooks/use-current-package-info"
|
|
2
|
+
import { useCurrentPackageRelease } from "@/hooks/use-current-package-release"
|
|
3
|
+
|
|
1
4
|
export function BuildPreviewContent() {
|
|
5
|
+
const { packageRelease } = useCurrentPackageRelease()
|
|
6
|
+
const { packageInfo } = useCurrentPackageInfo()
|
|
7
|
+
|
|
8
|
+
if (!packageRelease) {
|
|
9
|
+
return (
|
|
10
|
+
<div className="flex items-center justify-center">
|
|
11
|
+
<div className="w-48 h-48 bg-gray-200 rounded animate-pulse-slow"></div>
|
|
12
|
+
</div>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
|
|
2
16
|
return (
|
|
3
17
|
<div className="flex items-center justify-center">
|
|
4
|
-
<
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
18
|
+
<div className="rounded overflow-hidden">
|
|
19
|
+
<img
|
|
20
|
+
src={`https://api.tscircuit.com/packages/images/${packageInfo?.name}/pcb.png`}
|
|
21
|
+
alt="Package build preview"
|
|
22
|
+
className="object-contain rounded max-h-[360px]"
|
|
23
|
+
/>
|
|
24
|
+
</div>
|
|
9
25
|
</div>
|
|
10
26
|
)
|
|
11
27
|
}
|
|
@@ -6,24 +6,34 @@ import {
|
|
|
6
6
|
CollapsibleContent,
|
|
7
7
|
CollapsibleTrigger,
|
|
8
8
|
} from "@/components/ui/collapsible"
|
|
9
|
+
import { getColorForDisplayStatus } from "./getColorForDisplayStatus"
|
|
10
|
+
import { PackageRelease } from "fake-snippets-api/lib/db/schema"
|
|
11
|
+
import { ErrorObjectOrString, getErrorText } from "./ErrorObject"
|
|
12
|
+
import { capitalCase } from "./capitalCase"
|
|
13
|
+
|
|
14
|
+
type BadgeInfo = {
|
|
15
|
+
text: string
|
|
16
|
+
variant?: "default" | "secondary" | "destructive"
|
|
17
|
+
className?: string
|
|
18
|
+
icon?: React.ReactNode
|
|
19
|
+
}
|
|
9
20
|
|
|
10
21
|
interface CollapsibleSectionProps {
|
|
11
22
|
title: string
|
|
12
23
|
duration?: string
|
|
24
|
+
error?: ErrorObjectOrString | null
|
|
25
|
+
displayStatus?: PackageRelease["display_status"]
|
|
13
26
|
isOpen: boolean
|
|
14
27
|
onToggle: () => void
|
|
15
|
-
badges?: Array<
|
|
16
|
-
text: string
|
|
17
|
-
icon?: React.ReactNode
|
|
18
|
-
variant?: "default" | "secondary"
|
|
19
|
-
className?: string
|
|
20
|
-
}>
|
|
28
|
+
badges?: Array<BadgeInfo>
|
|
21
29
|
children?: React.ReactNode
|
|
22
30
|
}
|
|
23
31
|
|
|
24
32
|
export function CollapsibleSection({
|
|
25
33
|
title,
|
|
26
34
|
duration,
|
|
35
|
+
error,
|
|
36
|
+
displayStatus,
|
|
27
37
|
isOpen,
|
|
28
38
|
onToggle,
|
|
29
39
|
badges = [],
|
|
@@ -40,7 +50,17 @@ export function CollapsibleSection({
|
|
|
40
50
|
<span className="font-medium">{title}</span>
|
|
41
51
|
</div>
|
|
42
52
|
<div className="flex items-center gap-2">
|
|
43
|
-
{
|
|
53
|
+
{[
|
|
54
|
+
...badges,
|
|
55
|
+
...(error
|
|
56
|
+
? [
|
|
57
|
+
{
|
|
58
|
+
text: getErrorText(error),
|
|
59
|
+
variant: "destructive",
|
|
60
|
+
} as BadgeInfo,
|
|
61
|
+
]
|
|
62
|
+
: []),
|
|
63
|
+
].map((badge, index) => (
|
|
44
64
|
<Badge
|
|
45
65
|
key={index}
|
|
46
66
|
variant={badge.variant || "secondary"}
|
|
@@ -56,13 +76,18 @@ export function CollapsibleSection({
|
|
|
56
76
|
{duration && (
|
|
57
77
|
<span className="text-sm text-gray-600">{duration}</span>
|
|
58
78
|
)}
|
|
59
|
-
<
|
|
79
|
+
<div
|
|
80
|
+
className={`w-2 h-2 rounded-lg ${getColorForDisplayStatus(displayStatus)}`}
|
|
81
|
+
/>
|
|
82
|
+
<div className="text-gray-600 text-xs font-medium">
|
|
83
|
+
{capitalCase(displayStatus) || "???"}
|
|
84
|
+
</div>
|
|
60
85
|
</div>
|
|
61
86
|
</div>
|
|
62
87
|
</CollapsibleTrigger>
|
|
63
88
|
<CollapsibleContent>
|
|
64
89
|
<div className="p-4 bg-white border-x border-b border-gray-200 rounded-b-lg">
|
|
65
|
-
{children
|
|
90
|
+
{children}
|
|
66
91
|
</div>
|
|
67
92
|
</CollapsibleContent>
|
|
68
93
|
</Collapsible>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PackageRelease } from "fake-snippets-api/lib/db/schema"
|
|
2
|
+
|
|
3
|
+
export const getColorForDisplayStatus = (
|
|
4
|
+
display_status?: PackageRelease["display_status"] | null,
|
|
5
|
+
) => {
|
|
6
|
+
switch (display_status) {
|
|
7
|
+
case "pending":
|
|
8
|
+
return "bg-yellow-500"
|
|
9
|
+
case "building":
|
|
10
|
+
return "bg-blue-500"
|
|
11
|
+
case "successful":
|
|
12
|
+
return "bg-green-500"
|
|
13
|
+
case "failed":
|
|
14
|
+
return "bg-red-500"
|
|
15
|
+
}
|
|
16
|
+
return "bg-gray-500"
|
|
17
|
+
}
|
|
@@ -1,7 +1,61 @@
|
|
|
1
1
|
import { Globe, GitBranch, GitCommit, Clock } from "lucide-react"
|
|
2
2
|
import { Badge } from "@/components/ui/badge"
|
|
3
|
+
import { useCurrentPackageRelease } from "@/hooks/use-current-package-release"
|
|
4
|
+
import { useParams } from "wouter"
|
|
5
|
+
import { timeAgo } from "@/lib/utils/timeAgo"
|
|
6
|
+
import { PackageRelease } from "fake-snippets-api/lib/db/schema"
|
|
7
|
+
|
|
8
|
+
const capitalCase = (str: string) => {
|
|
9
|
+
return str.charAt(0).toUpperCase() + str.slice(1)
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function getColorFromDisplayStatus(
|
|
13
|
+
display_status: PackageRelease["display_status"],
|
|
14
|
+
) {
|
|
15
|
+
switch (display_status) {
|
|
16
|
+
case "pending":
|
|
17
|
+
return "bg-yellow-500"
|
|
18
|
+
case "building":
|
|
19
|
+
return "bg-blue-500"
|
|
20
|
+
case "successful":
|
|
21
|
+
return "bg-green-500"
|
|
22
|
+
case "failed":
|
|
23
|
+
return "bg-red-500"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
3
26
|
|
|
4
27
|
export function PackageBuildDetailsPanel() {
|
|
28
|
+
const { packageRelease } = useCurrentPackageRelease()
|
|
29
|
+
const { author } = useParams() // TODO use packageRelease.author_account_id when it's added by backed
|
|
30
|
+
|
|
31
|
+
if (!packageRelease) {
|
|
32
|
+
// TODO show skeleton instead
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const {
|
|
37
|
+
circuit_json_build_display_status,
|
|
38
|
+
circuit_json_build_in_progress,
|
|
39
|
+
circuit_json_build_is_stale,
|
|
40
|
+
circuit_json_build_logs,
|
|
41
|
+
transpilation_display_status,
|
|
42
|
+
transpilation_in_progress,
|
|
43
|
+
transpilation_logs,
|
|
44
|
+
circuit_json_build_completed_at,
|
|
45
|
+
transpilation_is_stale,
|
|
46
|
+
display_status,
|
|
47
|
+
created_at,
|
|
48
|
+
has_transpiled,
|
|
49
|
+
circuit_json_build_started_at,
|
|
50
|
+
circuit_json_build_error,
|
|
51
|
+
circuit_json_build_error_last_updated_at,
|
|
52
|
+
total_build_duration_ms,
|
|
53
|
+
transpilation_completed_at,
|
|
54
|
+
transpilation_error,
|
|
55
|
+
transpilation_started_at,
|
|
56
|
+
commit_sha,
|
|
57
|
+
} = packageRelease
|
|
58
|
+
|
|
5
59
|
return (
|
|
6
60
|
<div className="space-y-6 bg-white p-4 border border-gray-200 rounded-lg">
|
|
7
61
|
{/* Created */}
|
|
@@ -11,8 +65,10 @@ export function PackageBuildDetailsPanel() {
|
|
|
11
65
|
<div className="w-6 h-6 bg-orange-500 rounded-full flex items-center justify-center text-xs font-bold">
|
|
12
66
|
I
|
|
13
67
|
</div>
|
|
14
|
-
<span className="text-sm">
|
|
15
|
-
<span className="text-sm text-gray-500">
|
|
68
|
+
<span className="text-sm">{author}</span>
|
|
69
|
+
<span className="text-sm text-gray-500">
|
|
70
|
+
{timeAgo(packageRelease?.created_at, "")}
|
|
71
|
+
</span>
|
|
16
72
|
</div>
|
|
17
73
|
</div>
|
|
18
74
|
|
|
@@ -20,26 +76,33 @@ export function PackageBuildDetailsPanel() {
|
|
|
20
76
|
<div>
|
|
21
77
|
<h3 className="text-sm font-medium text-gray-600 mb-2">Status</h3>
|
|
22
78
|
<div className="flex items-center gap-2">
|
|
23
|
-
<div
|
|
24
|
-
|
|
25
|
-
|
|
79
|
+
<div
|
|
80
|
+
className={`w-2 h-2 ${getColorFromDisplayStatus(display_status)} rounded-full`}
|
|
81
|
+
></div>
|
|
82
|
+
<span className="text-sm">{capitalCase(display_status)}</span>
|
|
83
|
+
{/* <Badge
|
|
26
84
|
variant="secondary"
|
|
27
85
|
className="bg-gray-200 text-gray-700 text-xs"
|
|
28
86
|
>
|
|
29
87
|
Latest
|
|
30
|
-
</Badge>
|
|
88
|
+
</Badge> */}
|
|
31
89
|
</div>
|
|
32
90
|
</div>
|
|
33
91
|
|
|
34
|
-
{/* Time to Ready */}
|
|
35
92
|
<div>
|
|
36
|
-
<h3 className="text-sm font-medium text-gray-600 mb-2">
|
|
37
|
-
Time to Ready
|
|
38
|
-
</h3>
|
|
93
|
+
<h3 className="text-sm font-medium text-gray-600 mb-2">Build Time</h3>
|
|
39
94
|
<div className="flex items-center gap-2">
|
|
40
95
|
<Clock className="w-4 h-4 text-gray-500" />
|
|
41
|
-
|
|
42
|
-
|
|
96
|
+
{circuit_json_build_completed_at && (
|
|
97
|
+
<span className="text-sm">
|
|
98
|
+
{total_build_duration_ms
|
|
99
|
+
? `${Math.floor(total_build_duration_ms / 1000)}s`
|
|
100
|
+
: ""}
|
|
101
|
+
</span>
|
|
102
|
+
)}
|
|
103
|
+
<span className="text-sm text-gray-500">
|
|
104
|
+
{timeAgo(circuit_json_build_completed_at, "waiting...")}
|
|
105
|
+
</span>
|
|
43
106
|
</div>
|
|
44
107
|
</div>
|
|
45
108
|
|
|
@@ -48,10 +111,10 @@ export function PackageBuildDetailsPanel() {
|
|
|
48
111
|
<h3 className="text-sm font-medium text-gray-600 mb-2">Version</h3>
|
|
49
112
|
<div className="flex items-center gap-2">
|
|
50
113
|
<Globe className="w-4 h-4 text-gray-500" />
|
|
51
|
-
<span className="text-sm">
|
|
52
|
-
<Badge variant="default" className="bg-blue-600 text-white text-xs">
|
|
114
|
+
<span className="text-sm">{packageRelease.version}</span>
|
|
115
|
+
{/* <Badge variant="default" className="bg-blue-600 text-white text-xs">
|
|
53
116
|
Current
|
|
54
|
-
</Badge>
|
|
117
|
+
</Badge> */}
|
|
55
118
|
</div>
|
|
56
119
|
</div>
|
|
57
120
|
|
|
@@ -64,7 +127,7 @@ export function PackageBuildDetailsPanel() {
|
|
|
64
127
|
</div>
|
|
65
128
|
|
|
66
129
|
{/* Source */}
|
|
67
|
-
<div>
|
|
130
|
+
{/* <div>
|
|
68
131
|
<h3 className="text-sm font-medium text-gray-600 mb-2">Source</h3>
|
|
69
132
|
<div className="space-y-2">
|
|
70
133
|
<div className="flex items-center gap-2">
|
|
@@ -78,7 +141,7 @@ export function PackageBuildDetailsPanel() {
|
|
|
78
141
|
</span>
|
|
79
142
|
</div>
|
|
80
143
|
</div>
|
|
81
|
-
</div>
|
|
144
|
+
</div> */}
|
|
82
145
|
</div>
|
|
83
146
|
)
|
|
84
147
|
}
|