// Additional pages — Repositories dashboard, Updates inbox, Templates gallery, Deployments. const { useState: useStateP, useMemo: useMemoP } = React; const _userLogin = window.DEVEX_INIT?.user?.login || 'org'; // ---------- Mini sparkline ---------- function Spark({ data, color = 'var(--accent)', w = 90, h = 24 }) { const max = Math.max(...data); const min = Math.min(...data); const pts = data.map((v, i) => { const x = (i / (data.length - 1)) * w; const y = h - ((v - min) / (max - min || 1)) * (h - 2) - 1; return [x, y]; }); const d = pts.map((p, i) => `${i ? 'L' : 'M'}${p[0].toFixed(1)} ${p[1].toFixed(1)}`).join(' '); return ( ); } // ---------- Status pill ---------- function StatusPill({ status }) { const map = { live: { bg: 'var(--green-tint)', col: 'var(--green)', label: '● live' }, deploying: { bg: 'var(--accent-tint)', col: 'var(--accent)', label: '◐ deploying' }, archived: { bg: 'var(--surface-2)', col: 'var(--muted)', label: '○ archived' }, failed: { bg: 'var(--accent-tint)', col: 'var(--accent)', label: '✕ failed' }, }; const m = map[status] || map.archived; return {m.label}; } function CIBadge({ ci }) { const map = { success: { col: 'var(--green)', sym: '✓' }, running: { col: 'var(--accent)', sym: '◐' }, failed: { col: 'var(--accent)', sym: '✕' }, skipped: { col: 'var(--muted)', sym: '—' }, }; const m = map[ci] || map.skipped; return {m.sym}; } // ---------- Repositories Dashboard ---------- function ReposPage() { const I = window.I; const { REPOS, DEPLOY_SPARK } = window.DEVEX_DATA; const [filter, setFilter] = useStateP('all'); const [query, setQuery] = useStateP(''); const filtered = useMemoP(() => REPOS.filter(r => { if (filter !== 'all' && r.status !== filter) return false; if (query && !r.name.includes(query.toLowerCase())) return false; return true; }), [filter, query]); const featured = REPOS.slice(0, 3); return ( <>

Repository
registry.

// every repo, ownership, deploy state.

{/* Filters */}
All repositories
setQuery(e.target.value)}/>
{['all','live','deploying','archived'].map(f => ( ))}
{['Repo','Template','Owner','Endpoint','CI','Status','Version',''].map(h => ( ))} {filtered.map(r => ( ))}
{h}
{_userLogin}/{r.name} {r.template} {r.owner} {r.endpoint !== '—' ? {r.endpoint} : } {r.version} {r.updateAvail && ● update}
); } // ---------- Updates Inbox ---------- function UpdatesPage() { const I = window.I; const { UPDATES } = window.DEVEX_DATA; const [active, setActive] = useStateP(UPDATES[0].id); const current = UPDATES.find(u => u.id === active); const kindColor = { security: 'var(--accent)', breaking: 'var(--accent)', patch: 'var(--green)', feature: 'var(--text)' }; return ( <>

Stack
drift.

// pending update PRs. review, apply, dismiss.

{/* Inbox list */}
Inbox
{UPDATES.length} open
{UPDATES.map(u => (
setActive(u.id)} style={{ padding: '14px 18px', borderBottom: '1px solid var(--border)', cursor: 'pointer', background: active === u.id ? 'var(--accent-tint)' : 'var(--bg)', borderLeft: active === u.id ? '3px solid var(--accent)' : '3px solid transparent', display: 'flex', flexDirection: 'column', gap: 6, }}>
{u.kind} {u.id} {u.opened}
{u.title}
{_userLogin}/{u.repo} · {u.from} → {u.to}
{u.files} files +{u.additions} −{u.deletions}
))}
{/* Diff preview */}
{current.id} · {current.title}
repo · {_userLogin}/{current.repo}
from · {current.from}
to · {current.to}
by · devex-bot
{current.diff.map((d, i) => (
{d.f}
{d.d.split('\n').map((line, j) => (
  
{line || '\u00a0'}
))}
))}
); } // ---------- Templates Gallery ---------- function TemplatesPage() { const I = window.I; const { TEMPLATES_EXPANDED } = window.DEVEX_DATA; const [cat, setCat] = useStateP('all'); const cats = ['all', ...new Set(TEMPLATES_EXPANDED.map(t => t.category || 'Stack'))]; const list = TEMPLATES_EXPANDED.filter(t => cat === 'all' || (t.category || 'Stack') === cat); return ( <>

Template
library.

// curated, versioned scaffolds.

{cats.map(c => ( ))}
{list.map(t => (
{t.name}
{t.author === 'devex-core' && core}
{t.desc}
{(t.stack || []).map(s => {s})}
{t.usage ? `${t.usage} uses` : 'new'} {t.author || 'devex-core'}
))}
); } // ---------- Deployments (lightweight) ---------- function DeploymentsPage() { const I = window.I; const { REPOS } = window.DEVEX_DATA; const live = REPOS.filter(r => r.status === 'live' || r.status === 'deploying'); return ( <>

Deploy
timeline.

// every workflow run.

{live.map((r, i) => (
{r.created}
{_userLogin}/{r.name}
{r.template} · {r.endpoint}
))}
); } window.ReposPage = ReposPage; window.UpdatesPage = UpdatesPage; window.TemplatesPage = TemplatesPage; window.DeploymentsPage = DeploymentsPage;