@tscircuit/fake-snippets 0.0.81 → 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.
@@ -1,99 +1,38 @@
1
- import { useState } from "react"
2
- import {
3
- Dialog,
4
- DialogContent,
5
- DialogHeader,
6
- DialogTitle,
7
- } from "@/components/ui/dialog"
8
- import { CheckCircle, XCircle, Check, X } from "lucide-react"
9
- import { cn } from "@/lib/utils"
1
+ import { CheckCircle, XCircle, Clock, Loader2 } from "lucide-react"
2
+ import { Link, useParams } from "wouter"
10
3
 
11
4
  export interface BuildStep {
12
5
  id: string
13
6
  name: string
14
- status: "success" | "failed"
15
- message?: string
7
+ status: "pending" | "running" | "success" | "error"
16
8
  }
17
9
 
18
10
  export interface BuildStatusProps {
19
11
  step: BuildStep
12
+ packageReleaseId: string
20
13
  }
21
14
 
22
- export const BuildStatus = ({ step }: BuildStatusProps) => {
23
- const [isDialogOpen, setIsDialogOpen] = useState(false)
15
+ export const BuildStatus = ({ step, packageReleaseId }: BuildStatusProps) => {
16
+ const { author, packageName } = useParams()
17
+ const href = `/${author}/${packageName}/builds?package_release_id=${packageReleaseId}`
24
18
 
25
19
  return (
26
- <>
27
- <div
28
- onClick={() => setIsDialogOpen(true)}
29
- className={"flex items-center cursor-pointer"}
30
- >
31
- {step.status === "success" ? (
32
- <CheckCircle className="h-4 w-4 mr-2 text-green-600 dark:text-[#8b949e]" />
33
- ) : (
34
- <XCircle className="h-4 w-4 mr-2 text-red-600 dark:text-[#8b949e]" />
35
- )}
36
- <span className="text-sm text-gray-500 dark:text-[#8b949e]">
37
- {step.name}
38
- </span>
39
- </div>
40
-
41
- <Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
42
- <DialogContent className="sm:max-w-md">
43
- <DialogHeader>
44
- <DialogTitle className="flex items-center gap-2">
45
- {step.status === "success" ? (
46
- <>
47
- <CheckCircle className="h-5 w-5 text-green-600" />
48
- <span>Build Status: Passing</span>
49
- </>
50
- ) : (
51
- <>
52
- <XCircle className="h-5 w-5 text-red-600" />
53
- <span>Build Status: Failing</span>
54
- </>
55
- )}
56
- </DialogTitle>
57
- </DialogHeader>
58
-
59
- <div className="space-y-4">
60
- <div className="space-y-3">
61
- <div
62
- key={step.id}
63
- className={cn(
64
- "flex items-start gap-3 rounded-md border p-3",
65
- step.status === "success"
66
- ? "bg-green-50 border-green-200"
67
- : "bg-red-50 border-red-200",
68
- )}
69
- >
70
- <div
71
- className={cn(
72
- "rounded-full p-1 mt-0.5",
73
- step.status === "success"
74
- ? "bg-green-100 text-green-600"
75
- : "bg-red-100 text-red-600",
76
- )}
77
- >
78
- {step.status === "success" ? (
79
- <Check className="h-4 w-4" />
80
- ) : (
81
- <X className="h-4 w-4" />
82
- )}
83
- </div>
84
- <div>
85
- <div className="font-medium">{step.name}</div>
86
- {step.message && (
87
- <div className="text-sm text-muted-foreground mt-1">
88
- {step.message}
89
- </div>
90
- )}
91
- </div>
92
- </div>
93
- </div>
94
- </div>
95
- </DialogContent>
96
- </Dialog>
97
- </>
20
+ <Link href={href} className="flex items-center gap-2">
21
+ {step.status === "success" && (
22
+ <CheckCircle className="h-4 w-4 text-green-600 dark:text-[#8b949e]" />
23
+ )}
24
+ {step.status === "error" && (
25
+ <XCircle className="h-4 w-4 text-red-600 dark:text-[#8b949e]" />
26
+ )}
27
+ {step.status === "running" && (
28
+ <Loader2 className="h-4 w-4 text-blue-600 animate-spin dark:text-[#8b949e]" />
29
+ )}
30
+ {step.status === "pending" && (
31
+ <Clock className="h-4 w-4 text-yellow-600 dark:text-[#8b949e]" />
32
+ )}
33
+ <span className="text-sm text-gray-500 dark:text-[#8b949e]">
34
+ {step.name}
35
+ </span>
36
+ </Link>
98
37
  )
99
38
  }
@@ -51,8 +51,13 @@ export default function ImportantFilesView({
51
51
  const hasAiContent = Boolean(aiDescription || aiUsageInstructions)
52
52
  const hasAiReview = Boolean(aiReviewText)
53
53
 
54
- // Select the appropriate tab/file when content changes
54
+ // Select the appropriate tab/file when content changes. Once the user has
55
+ // interacted with the tabs we keep their selection and only run this logic
56
+ // if no tab has been chosen yet.
55
57
  useEffect(() => {
58
+ if (activeTab !== null) return
59
+ if (isLoading) return
60
+
56
61
  // First priority: README file if it exists
57
62
  const readmeFile = importantFiles.find(
58
63
  (file) =>
@@ -82,6 +87,8 @@ export default function ImportantFilesView({
82
87
  hasAiContent,
83
88
  hasAiReview,
84
89
  importantFiles,
90
+ activeTab,
91
+ isLoading,
85
92
  ])
86
93
 
87
94
  // Get file name from path
@@ -4,6 +4,27 @@ import { useCurrentPackageInfo } from "@/hooks/use-current-package-info"
4
4
  import { usePackageReleaseById } from "@/hooks/use-package-release"
5
5
  import { timeAgo } from "@/lib/utils/timeAgo"
6
6
  import { BuildStatus, BuildStep } from "./build-status"
7
+ import type { PackageRelease } from "fake-snippets-api/lib/db/schema"
8
+
9
+ function getTranspilationStatus(
10
+ pr?: PackageRelease | null,
11
+ ): BuildStep["status"] {
12
+ if (!pr) return "pending"
13
+ if (pr.transpilation_error) return "error"
14
+ if (pr.transpilation_in_progress) return "running"
15
+ if (pr.transpilation_completed_at) return "success"
16
+ if (pr.transpilation_started_at) return "running"
17
+ return "pending"
18
+ }
19
+
20
+ function getCircuitJsonStatus(pr?: PackageRelease | null): BuildStep["status"] {
21
+ if (!pr) return "pending"
22
+ if (pr.circuit_json_build_error) return "error"
23
+ if (pr.circuit_json_build_in_progress) return "running"
24
+ if (pr.circuit_json_build_completed_at) return "success"
25
+ if (pr.circuit_json_build_started_at) return "running"
26
+ return "pending"
27
+ }
7
28
 
8
29
  export default function SidebarReleasesSection() {
9
30
  const { packageInfo } = useCurrentPackageInfo()
@@ -15,14 +36,12 @@ export default function SidebarReleasesSection() {
15
36
  {
16
37
  id: "package_transpilation",
17
38
  name: "Package Transpilation",
18
- status: packageRelease?.has_transpiled ? "success" : "failed",
19
- message: packageRelease?.transpilation_error || undefined,
39
+ status: getTranspilationStatus(packageRelease),
20
40
  },
21
41
  {
22
42
  id: "circuit_json_build",
23
43
  name: "Circuit JSON Build",
24
- status: packageRelease?.circuit_json_build_error ? "failed" : "success",
25
- message: packageRelease?.circuit_json_build_error || undefined,
44
+ status: getCircuitJsonStatus(packageRelease),
26
45
  },
27
46
  ]
28
47
 
@@ -56,7 +75,11 @@ export default function SidebarReleasesSection() {
56
75
  </span>
57
76
  </div>
58
77
  {buildSteps.map((step) => (
59
- <BuildStatus key={step.id} step={step} />
78
+ <BuildStatus
79
+ key={step.id}
80
+ step={step}
81
+ packageReleaseId={packageRelease.package_release_id}
82
+ />
60
83
  ))}
61
84
  </div>
62
85
  {/* <a href="#" className="text-blue-600 dark:text-[#58a6ff] hover:underline text-sm">
@@ -4,7 +4,7 @@ import { autocompletion } from "@codemirror/autocomplete"
4
4
  import { indentWithTab } from "@codemirror/commands"
5
5
  import { javascript } from "@codemirror/lang-javascript"
6
6
  import { json } from "@codemirror/lang-json"
7
- import { EditorState } from "@codemirror/state"
7
+ import { EditorState, Prec } from "@codemirror/state"
8
8
  import { Decoration, hoverTooltip, keymap } from "@codemirror/view"
9
9
  import { getImportsFromCode } from "@tscircuit/prompt-benchmarks/code-runner-utils"
10
10
  import type { ATABootstrapConfig } from "@typescript/ata"
@@ -237,6 +237,14 @@ export const CodeEditor = ({
237
237
  currentFile?.endsWith(".json")
238
238
  ? json()
239
239
  : javascript({ typescript: true, jsx: true }),
240
+ Prec.high(
241
+ keymap.of([
242
+ {
243
+ key: "Mod-Enter",
244
+ run: () => true,
245
+ },
246
+ ]),
247
+ ),
240
248
  keymap.of([indentWithTab]),
241
249
  EditorState.readOnly.of(readOnly || isSaving),
242
250
  EditorView.updateListener.of((update) => {
@@ -1,10 +1,11 @@
1
1
  import { useParams } from "wouter"
2
2
  import { useCurrentPackageId } from "./use-current-package-id"
3
- import { useUrlParams } from "./use-url-params"
4
3
  import { usePackageRelease } from "./use-package-release"
4
+ import { useUrlParams } from "./use-url-params"
5
5
 
6
6
  export const useCurrentPackageRelease = (options?: {
7
- include_logs: boolean
7
+ include_logs?: boolean
8
+ refetchInterval?: number
8
9
  }) => {
9
10
  const { packageId } = useCurrentPackageId()
10
11
  const urlParams = useUrlParams()
@@ -27,6 +28,7 @@ export const useCurrentPackageRelease = (options?: {
27
28
 
28
29
  const { data: packageRelease, ...rest } = usePackageRelease(query, {
29
30
  include_logs: options?.include_logs ?? false,
31
+ refetchInterval: options?.refetchInterval,
30
32
  })
31
33
  return { packageRelease, ...rest }
32
34
  }
@@ -0,0 +1,12 @@
1
+ import { useEffect, useState } from "react"
2
+
3
+ export const useNow = (intervalMs: number = 1000) => {
4
+ const [now, setNow] = useState(Date.now())
5
+
6
+ useEffect(() => {
7
+ const id = setInterval(() => setNow(Date.now()), intervalMs)
8
+ return () => clearInterval(id)
9
+ }, [intervalMs])
10
+
11
+ return now
12
+ }
@@ -1,5 +1,5 @@
1
1
  import type { PackageRelease } from "fake-snippets-api/lib/db/schema"
2
- import { useQuery } from "react-query"
2
+ import { type UseQueryOptions, useQuery } from "react-query"
3
3
  import { useAxios } from "./use-axios"
4
4
 
5
5
  type PackageReleaseQuery =
@@ -20,7 +20,7 @@ type PackageReleaseQuery =
20
20
 
21
21
  export const usePackageRelease = (
22
22
  query: PackageReleaseQuery | null,
23
- options?: { include_logs: boolean },
23
+ options?: { include_logs?: boolean; refetchInterval?: number },
24
24
  ) => {
25
25
  const axios = useAxios()
26
26
 
@@ -50,6 +50,7 @@ export const usePackageRelease = (
50
50
  {
51
51
  retry: false,
52
52
  enabled: Boolean(query),
53
+ refetchInterval: options?.refetchInterval,
53
54
  },
54
55
  )
55
56
  }
@@ -34,8 +34,9 @@ export const DashboardPage = () => {
34
34
  data: myPackages,
35
35
  isLoading,
36
36
  error,
37
+ refetch: refetchUserPackages,
37
38
  } = useQuery<Package[]>(
38
- "userPackages",
39
+ ["userPackages", currentUser],
39
40
  async () => {
40
41
  const response = await axios.post(`/packages/list`, {
41
42
  owner_github_username: currentUser,
@@ -195,6 +196,7 @@ export const DashboardPage = () => {
195
196
  packageId={packageToDelete.package_id}
196
197
  packageName={packageToDelete.unscoped_name}
197
198
  packageOwner={packageToDelete.owner_github_username ?? ""}
199
+ refetchUserPackages={refetchUserPackages}
198
200
  />
199
201
  )}
200
202
  </div>
@@ -48,7 +48,10 @@ export const UserProfilePage = () => {
48
48
  })
49
49
  return response.data
50
50
  },
51
- { retry: false },
51
+ {
52
+ retry: false,
53
+ refetchOnWindowFocus: false,
54
+ },
52
55
  )
53
56
 
54
57
  // use the username stored in the database so the correct case is displayed
@@ -71,7 +74,10 @@ export const UserProfilePage = () => {
71
74
  })
72
75
  return response.data.packages
73
76
  },
74
- { enabled: Boolean(githubUsername) },
77
+ {
78
+ enabled: Boolean(githubUsername),
79
+ refetchOnWindowFocus: false,
80
+ },
75
81
  )
76
82
 
77
83
  const { data: starredPackages, isLoading: isLoadingStarredPackages } =
@@ -85,6 +91,7 @@ export const UserProfilePage = () => {
85
91
  },
86
92
  {
87
93
  enabled: activeTab === "starred" && Boolean(githubUsername),
94
+ refetchOnWindowFocus: false,
88
95
  },
89
96
  )
90
97
 
@@ -1,63 +0,0 @@
1
- name: Format PR
2
-
3
- on:
4
- pull_request:
5
- types: [opened, synchronize, reopened, ready_for_review]
6
-
7
- jobs:
8
- format:
9
- name: Format code
10
- runs-on: ubuntu-latest
11
- if: github.event.pull_request.draft == false
12
-
13
- steps:
14
- - name: Determine if fork
15
- id: check_fork
16
- run: |
17
- if [ "${{ github.event.pull_request.head.repo.full_name }}" = "${{ github.repository }}" ]; then
18
- echo "is_fork=false" >> $GITHUB_OUTPUT
19
- else
20
- echo "is_fork=true" >> $GITHUB_OUTPUT
21
- fi
22
-
23
- - name: Checkout code
24
- uses: actions/checkout@v4
25
- with:
26
- token: ${{ steps.check_fork.outputs.is_fork == 'true' && secrets.GITHUB_TOKEN || secrets.TSCIRCUIT_BOT_GITHUB_TOKEN }}
27
-
28
- - name: Setup bun
29
- uses: oven-sh/setup-bun@v2
30
- with:
31
- bun-version: latest
32
-
33
- - name: Get @biomejs/biome version
34
- id: get-biome-version
35
- run: echo "BIOME_VERSION=$(node -p "require('./package.json').devDependencies['@biomejs/biome']")" >> $GITHUB_OUTPUT
36
-
37
- - name: Install @biomejs/biome
38
- run: bun install @biomejs/biome@${{ steps.get-biome-version.outputs.BIOME_VERSION }}
39
-
40
- - name: Run Formatter and autofix
41
- if: steps.check_fork.outputs.is_fork == 'false'
42
- run: npx @biomejs/biome format . --write
43
-
44
- - name: Format Check (cannot autofix against forks)
45
- if: steps.check_fork.outputs.is_fork == 'true'
46
- run: npx @biomejs/biome format .
47
-
48
- - name: Restore lock files
49
- if: steps.check_fork.outputs.is_fork == 'false'
50
- run: |
51
- git checkout -- *lock.json || true
52
- git checkout -- *.lock || true
53
- git checkout -- *.lockb || true
54
-
55
- - name: Commit changes
56
- if: steps.check_fork.outputs.is_fork == 'false'
57
- uses: stefanzweifel/git-auto-commit-action@v4
58
- with:
59
- commit_message: "formatbot: Automatically format code"
60
- branch: ${{ github.head_ref }}
61
- commit_user_name: tscircuitbot
62
- commit_user_email: tscircuitbot@users.noreply.github.com
63
- commit_author: tscircuitbot <tscircuitbot@users.noreply.github.com>