feat: environment model + deployment tracking (phase 3a)
- Environment/Deployment XORM models + migration 010 - Full CRUD API: GET/POST/PATCH/DELETE /environments + /deployments - Deployment status update endpoint, publishes deployment.* NATS events - EnvironmentsPage with deploy cards, history accordion, deploy modal - Sidebar Environments nav item between Pipelines and Settings - Repo page deployment status badges (env name + SHA pill per environment) - Environment/Deployment types in types/api.ts + environments.ts query hooks
This commit is contained in:
@@ -3,6 +3,7 @@ import { useParams, useSearchParams, Link } from 'react-router-dom'
|
||||
import ReactMarkdown from 'react-markdown'
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import { useRepo, useRepoTree, useRepoBlob, useRepoBranches } from '../api/queries/repos'
|
||||
import { useEnvironments } from '../api/queries/environments'
|
||||
import { TreeBrowser } from '../components/repos/TreeBrowser'
|
||||
import { RepoListSkeleton } from '../ui/Skeleton'
|
||||
import { RepoAvatar } from '../ui/RepoAvatar'
|
||||
@@ -21,6 +22,7 @@ export default function RepoPage() {
|
||||
|
||||
const { data: repo, isLoading, isError } = useRepo(owner, repoName)
|
||||
const { data: branches } = useRepoBranches(owner, repoName)
|
||||
const { data: environments } = useEnvironments(owner, repoName)
|
||||
const { track } = useRecentRepos()
|
||||
useEffect(() => { if (owner && repoName) track(owner, repoName) }, [owner, repoName])
|
||||
|
||||
@@ -65,6 +67,37 @@ export default function RepoPage() {
|
||||
{repo.description && (
|
||||
<p className="text-sm text-[var(--c-muted)]">{repo.description}</p>
|
||||
)}
|
||||
|
||||
{/* Deployment status badges */}
|
||||
{environments && environments.length > 0 && (
|
||||
<div className="flex items-center gap-1.5 flex-wrap mt-2">
|
||||
{environments.map(env => {
|
||||
const status = env.latestDeployment?.status
|
||||
const dot: Record<string, string> = {
|
||||
success: 'bg-[var(--c-success)]',
|
||||
in_progress: 'bg-[var(--c-brand)] animate-pulse',
|
||||
failure: 'bg-[var(--c-danger)]',
|
||||
pending: 'bg-[var(--c-subtle)]',
|
||||
cancelled: 'bg-[var(--c-subtle)]',
|
||||
}
|
||||
return (
|
||||
<Link
|
||||
key={env.id}
|
||||
to={`/repos/${owner}/${repoName}/environments`}
|
||||
className="flex items-center gap-1.5 px-2 py-0.5 rounded-full border border-[var(--c-border)] bg-[var(--c-surface-muted)] hover:border-[var(--c-brand-focus)] transition-colors"
|
||||
>
|
||||
<span className={`w-1.5 h-1.5 rounded-full shrink-0 ${status ? (dot[status] ?? 'bg-[var(--c-subtle)]') : 'bg-[var(--c-subtle)]'}`} />
|
||||
<span className="text-[10px] font-medium text-[var(--c-muted)]">{env.name}</span>
|
||||
{env.latestDeployment?.sha && (
|
||||
<span className="text-[10px] font-mono text-[var(--c-subtle)]">
|
||||
{env.latestDeployment.sha.slice(0, 7)}
|
||||
</span>
|
||||
)}
|
||||
</Link>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
|
||||
Reference in New Issue
Block a user