feat(frontend): add status page, changelog tabs, book demo CTA, and footer status badge#130
Conversation
…ooter status badge - Add /status page fetching real data from Betterstack via backend proxy - Add Web App tab to /changelog with real git history compiled into 7 versions - Add Book a Demo CTA to hero section and enterprise pricing card - Add live status badge to footer (fallbacks to status.refactron.dev if API unreachable) - Add /status route to App.tsx without PageLayout wrapper - Add Status link to footer Company section Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughWalkthroughThis PR introduces a new system status page with live API status tracking and auto-refresh, splits the changelog into web and CLI versions with a tabbed UI, adds a status badge to the footer, and updates demo CTAs across the site to point to a calendar booking system instead of static links. Changes
Sequence DiagramsequenceDiagram
participant User
participant App as App/StatusPage
participant API as Backend API
participant UI as UI Components
User->>App: Navigate to /status
App->>API: GET /api/status (initial load)
API-->>App: Return {data: {overall, services, incidents}}
App->>UI: Render status banner, services list, incidents
UI-->>User: Display live status page
par Auto-refresh loop
Note over App: Every 60 seconds
App->>API: GET /api/status
API-->>App: Updated status data
App->>UI: Update with fresh data & timestamps
UI-->>User: Display updated status
end
User->>User: View incident details
App->>UI: Toggle incident expand/collapse
UI-->>User: Show/hide incident timestamps & duration
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
👋 Thanks for opening this pull request! A maintainer will review it soon. Please make sure all CI checks pass. |
There was a problem hiding this comment.
Pull request overview
Adds a public status surface and enhances marketing/navigation CTAs by introducing a /status page (fed via backend proxy), adding a Web App tab to the /changelog, and updating primary CTAs plus the footer with a live status badge and link.
Changes:
- Introduce
/statuspage UI that polls/api/statusand renders services + incident history. - Add Web App vs CLI tabs on
/changelogwith a newwebChangelogdataset. - Update “Book a Demo” CTAs and add footer status link + live status badge with external fallback.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/data/webChangelog.ts | Adds static Web App changelog entries used by the new changelog tab. |
| src/components/StatusPage.tsx | Implements the new /status page UI, polling logic, and incident/service rendering. |
| src/components/Changelog.tsx | Adds tab switching between web and CLI changelog datasets. |
| src/components/PricingSection.tsx | Updates Enterprise CTA to open a demo booking link. |
| src/components/HeroSection.tsx | Changes secondary hero CTA from docs to “Book a Demo”. |
| src/components/Footer.tsx | Adds “Status” link and a live status badge (with fallback URL). |
| src/App.tsx | Registers the /status route without the PageLayout wrapper. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const overall: Overall | 'checking' = loading | ||
| ? 'checking' | ||
| : (data?.overall ?? 'operational'); | ||
| const banner = BANNER_CFG[overall]; |
There was a problem hiding this comment.
overall is derived from loading only, which causes two user-facing inconsistencies: (1) every auto-refresh sets loading=true and flips the banner to the “Checking…” state even when previous data exists (visual flicker), and (2) if the initial fetch fails (error=true and data=null), the banner falls back to “operational” while the error message says the API is unreachable. Consider separating “refreshing” from “initial load”, and compute overall to reflect error/missing data (e.g., keep last known data.overall during refresh; show an explicit unknown/outage state when error && !data).
| { label: 'Avg 90-day uptime', value: `${avgUptime}%` }, | ||
| { |
There was a problem hiding this comment.
When data is null, avgUptime is set to '—', but the stats strip always renders it as ${avgUptime}%, producing a UI value like —%. It would be clearer to only append % when you have numeric uptime data (or keep avgUptime numeric and format at render time).
| { label: 'Avg 90-day uptime', value: `${avgUptime}%` }, | |
| { | |
| { | |
| label: 'Avg 90-day uptime', | |
| value: data ? `${avgUptime}%` : '—', | |
| }, | |
| { |
| const [loading, setLoading] = useState(true); | ||
| const [error, setError] = useState(false); | ||
| const [secondsAgo, setSecondsAgo] = useState(0); | ||
| const timerRef = useRef<NodeJS.Timeout | null>(null); |
There was a problem hiding this comment.
The interval ref is typed as NodeJS.Timeout, which is a Node type and can be awkward/inaccurate in a browser React app (and inconsistent with other components here that use window.setInterval). Prefer ReturnType<typeof setInterval> (or number with window.setInterval) to avoid type mismatches across TS lib/type configurations.
| const timerRef = useRef<NodeJS.Timeout | null>(null); | |
| const timerRef = useRef<ReturnType<typeof setInterval> | null>(null); |
| useEffect(() => { | ||
| const apiBase = getApiBaseUrl(); | ||
| fetch(`${apiBase}/api/status`) | ||
| .then(r => r.json()) | ||
| .then(json => setStatus(json?.data?.overall ?? 'operational')) | ||
| .catch(() => { | ||
| setStatus('operational'); | ||
| setHref(FALLBACK_URL); | ||
| }); |
There was a problem hiding this comment.
StatusBadge treats any response as success (no r.ok check) and on fetch failure it sets status to 'operational'. Both cases can incorrectly display “All systems operational.” when the status API is unreachable or returning an error. Consider checking r.ok and, on error, rendering a distinct state/label (e.g. “Status unavailable”) while still linking to the external fallback URL.
Summary by CodeRabbit