From d159c5e8c7cc3012ed7cfaa5bafc87500cad6126 Mon Sep 17 00:00:00 2001 From: johndoe6345789 Date: Sat, 17 Jan 2026 09:56:58 +0000 Subject: [PATCH] Generated by Spark: Github build status information on dashboard - https://github.com/johndoe6345789/low-code-react-app-b/actions --- src/App.new.tsx | 1 + src/App.refactored.tsx | 2 +- src/components/ProjectDashboard.tsx | 12 +- .../molecules/GitHubBuildStatus.tsx | 271 ++++++++++++++++++ src/components/molecules/index.ts | 1 + src/config/pages.json | 2 +- src/hooks/use-project-state.ts | 4 + src/types/project.ts | 4 + 8 files changed, 294 insertions(+), 3 deletions(-) create mode 100644 src/components/molecules/GitHubBuildStatus.tsx diff --git a/src/App.new.tsx b/src/App.new.tsx index 7719cdc..7b53bf7 100644 --- a/src/App.new.tsx +++ b/src/App.new.tsx @@ -176,6 +176,7 @@ function App() { storybookStories={storybookStories} unitTests={unitTests} flaskConfig={flaskConfig} + nextjsConfig={nextjsConfig} /> diff --git a/src/App.refactored.tsx b/src/App.refactored.tsx index d6178e5..0735ddf 100644 --- a/src/App.refactored.tsx +++ b/src/App.refactored.tsx @@ -116,7 +116,7 @@ function App() {
- + {featureToggles.codeEditor && ( diff --git a/src/components/ProjectDashboard.tsx b/src/components/ProjectDashboard.tsx index 96163ed..36ac56e 100644 --- a/src/components/ProjectDashboard.tsx +++ b/src/components/ProjectDashboard.tsx @@ -13,8 +13,9 @@ import { CheckCircle, Warning } from '@phosphor-icons/react' -import { ProjectFile, PrismaModel, ComponentNode, ThemeConfig, PlaywrightTest, StorybookStory, UnitTest, FlaskConfig } from '@/types/project' +import { ProjectFile, PrismaModel, ComponentNode, ThemeConfig, PlaywrightTest, StorybookStory, UnitTest, FlaskConfig, NextJsConfig } from '@/types/project' import { SeedDataStatus } from '@/components/atoms' +import { GitHubBuildStatus } from '@/components/molecules/GitHubBuildStatus' interface ProjectDashboardProps { files: ProjectFile[] @@ -25,6 +26,7 @@ interface ProjectDashboardProps { storybookStories: StorybookStory[] unitTests: UnitTest[] flaskConfig: FlaskConfig + nextjsConfig: NextJsConfig } export function ProjectDashboard({ @@ -36,6 +38,7 @@ export function ProjectDashboard({ storybookStories, unitTests, flaskConfig, + nextjsConfig, }: ProjectDashboardProps) { const totalFiles = files.length const totalModels = models.length @@ -134,6 +137,13 @@ export function ProjectDashboard({ + {nextjsConfig?.githubRepo && ( + + )} + Project Details diff --git a/src/components/molecules/GitHubBuildStatus.tsx b/src/components/molecules/GitHubBuildStatus.tsx new file mode 100644 index 0000000..583f749 --- /dev/null +++ b/src/components/molecules/GitHubBuildStatus.tsx @@ -0,0 +1,271 @@ +import { useState, useEffect } from 'react' +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card' +import { Badge } from '@/components/ui/badge' +import { Button } from '@/components/ui/button' +import { + GitBranch, + CheckCircle, + XCircle, + Clock, + ArrowSquareOut, + Warning +} from '@phosphor-icons/react' +import { Skeleton } from '@/components/ui/skeleton' + +interface WorkflowRun { + id: number + name: string + status: string + conclusion: string | null + created_at: string + updated_at: string + html_url: string + head_branch: string + head_sha: string + event: string +} + +interface GitHubBuildStatusProps { + owner: string + repo: string +} + +export function GitHubBuildStatus({ owner, repo }: GitHubBuildStatusProps) { + const [workflows, setWorkflows] = useState([]) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + + useEffect(() => { + fetchWorkflowRuns() + }, [owner, repo]) + + const fetchWorkflowRuns = async () => { + try { + setLoading(true) + setError(null) + + const response = await fetch( + `https://api.github.com/repos/${owner}/${repo}/actions/runs?per_page=5`, + { + headers: { + 'Accept': 'application/vnd.github.v3+json', + }, + } + ) + + if (!response.ok) { + throw new Error(`GitHub API error: ${response.status}`) + } + + const data = await response.json() + setWorkflows(data.workflow_runs || []) + } catch (err) { + setError(err instanceof Error ? err.message : 'Failed to fetch workflows') + } finally { + setLoading(false) + } + } + + const getStatusIcon = (status: string, conclusion: string | null) => { + if (status === 'completed') { + if (conclusion === 'success') { + return + } + if (conclusion === 'failure') { + return + } + if (conclusion === 'cancelled') { + return + } + } + return + } + + const getStatusBadge = (status: string, conclusion: string | null) => { + if (status === 'completed') { + if (conclusion === 'success') { + return Success + } + if (conclusion === 'failure') { + return Failed + } + if (conclusion === 'cancelled') { + return Cancelled + } + } + return Running + } + + const formatTime = (dateString: string) => { + const date = new Date(dateString) + const now = new Date() + const diff = now.getTime() - date.getTime() + const minutes = Math.floor(diff / 60000) + const hours = Math.floor(minutes / 60) + const days = Math.floor(hours / 24) + + if (days > 0) return `${days}d ago` + if (hours > 0) return `${hours}h ago` + if (minutes > 0) return `${minutes}m ago` + return 'just now' + } + + if (loading) { + return ( + + + + + GitHub Actions + + Recent workflow runs + + + {[...Array(3)].map((_, i) => ( +
+
+ +
+ + +
+
+ +
+ ))} +
+
+ ) + } + + if (error) { + return ( + + + + + GitHub Actions + + Unable to fetch workflow status + + +
+ +
+

{error}

+ +
+
+
+
+ ) + } + + if (workflows.length === 0) { + return ( + + + + + GitHub Actions + + No workflow runs found + + +

+ No GitHub Actions workflows have been run yet. +

+
+
+ ) + } + + return ( + + +
+
+ + + GitHub Actions + + Recent workflow runs from {owner}/{repo} +
+ +
+
+ + {workflows.map((workflow) => ( +
+
+ {getStatusIcon(workflow.status, workflow.conclusion)} +
+
+

+ {workflow.name} +

+ {getStatusBadge(workflow.status, workflow.conclusion)} +
+
+ {workflow.head_branch} + + {formatTime(workflow.updated_at)} + + {workflow.event} +
+
+
+ +
+ ))} + +
+
+ ) +} diff --git a/src/components/molecules/index.ts b/src/components/molecules/index.ts index db910ae..90d77dd 100644 --- a/src/components/molecules/index.ts +++ b/src/components/molecules/index.ts @@ -5,6 +5,7 @@ export { EditorToolbar } from './EditorToolbar' export { EmptyEditorState } from './EmptyEditorState' export { EmptyState } from './EmptyState' export { FileTabs } from './FileTabs' +export { GitHubBuildStatus } from './GitHubBuildStatus' export { LabelWithBadge } from './LabelWithBadge' export { LazyInlineMonacoEditor } from './LazyInlineMonacoEditor' export { LazyMonacoEditor, preloadMonacoEditor } from './LazyMonacoEditor' diff --git a/src/config/pages.json b/src/config/pages.json index 7e9e5c2..b719244 100644 --- a/src/config/pages.json +++ b/src/config/pages.json @@ -9,7 +9,7 @@ "shortcut": "ctrl+1", "order": 1, "props": { - "state": ["files", "models", "components", "theme", "playwrightTests", "storybookStories", "unitTests", "flaskConfig"] + "state": ["files", "models", "components", "theme", "playwrightTests", "storybookStories", "unitTests", "flaskConfig", "nextjsConfig"] } }, { diff --git a/src/hooks/use-project-state.ts b/src/hooks/use-project-state.ts index b4e35b6..2341f00 100644 --- a/src/hooks/use-project-state.ts +++ b/src/hooks/use-project-state.ts @@ -33,6 +33,10 @@ const DEFAULT_NEXTJS_CONFIG: NextJsConfig = { appRouter: true, importAlias: '@/*', turbopack: false, + githubRepo: { + owner: 'johndoe6345789', + repo: 'low-code-react-app-b', + }, } const DEFAULT_NPM_SETTINGS: NpmSettings = { diff --git a/src/types/project.ts b/src/types/project.ts index cd41e77..c9db538 100644 --- a/src/types/project.ts +++ b/src/types/project.ts @@ -169,6 +169,10 @@ export interface NextJsConfig { appRouter: boolean importAlias: string turbopack?: boolean + githubRepo?: { + owner: string + repo: string + } } export interface NpmPackage {