Skip to content

feat(status): add GitHub status tracking badge - #123

Merged
wgordon17 merged 17 commits into
gordon-code:mainfrom
wgordon17:feat/github-status-tracking
Aug 8, 2026
Merged

feat(status): add GitHub status tracking badge#123
wgordon17 merged 17 commits into
gordon-code:mainfrom
wgordon17:feat/github-status-tracking

Conversation

@wgordon17

Copy link
Copy Markdown
Member

Summary

  • Adds a header badge that surfaces GitHub's own status/outage info for the services this dashboard depends on (Actions, API Requests, Git Operations, Issues, Pull Requests), checked on the existing full-refresh poll cycle with no new poll coordinator
  • Notifies via the existing toast/drawer system on incident start and resolution, and shows incident detail in a click-to-open popover with a link to githubstatus.com
  • CSP allowlist scoped to the exact githubstatus.com origin, third-party response validated with Zod before use, and all third-party text rendered via plain JSX (never innerHTML)

Fetches GitHub's status summary API, filters to five tracked
components (Actions, API Requests, Git Operations, Issues, Pull
Requests), blends severity, and exposes it via a SolidJS signal.
Validates the third-party response shape with Zod and includes a
live-network smoke test (excluded from the default suite) guarding
against silent component-name drift.
Adds the exact origin (no wildcard, no regional subdomains) so the
new GitHub status polling fetch is not blocked by CSP.
Calls fetchGitHubStatus() fire-and-forget from doFetch(), alongside
the existing fetchRateLimitDetails() call, so it inherits the poll
coordinator's interval, manual-refresh trigger, and hidden-tab skip
behavior for free.
Renders a severity-colored dot in the header with a click-to-open
Kobalte Popover showing active-incident detail. Adds an optional
forceClosed prop to the shared Tooltip component so the badge's
hover tooltip can be suppressed while its Popover is open.
Places the badge between the user avatar and the Settings icon in
the header's icon row.
Updates the documented convention to present-indicative mood
("adds feature"), matching what this environment's commit-msg
hook actually enforces — the prior imperative-mood example
contradicted every commit accepted in practice.
Extracts a shared recordFetchFailure() helper so both the
schema-validation-failure branch and the catch block go through
the same CONSECUTIVE_FAILURE_THRESHOLD gate added in 087ae11 —
the schema-drift path previously called dismissNotificationBySource
unconditionally, reintroducing the CR-002 bug via a different
trigger. Adds a test confirming the counter is shared across both
failure types.
Adds coverage for three previously-untested branches: an unrecognized component status string falling back to "none" severity, an empty incident_updates array yielding an empty latestUpdateBody, and resetGitHubStatusState() clearing the current status back to null.
Dismissing the Popover via Escape or an outside click bypasses the Tooltip trigger's own onClick/onPointerLeave/onBlur handlers entirely (Kobalte's DismissableLayer calls context.close directly), so isHovered/isFocused could be left stale as true. If the pointer was still resting on the trigger, the tooltip would flash back open on its own once forceClosed flipped back to false.

Adds a createEffect(on(...)) that resets both signals on that specific true-to-false transition, using SolidJS's built-in previous-value parameter rather than a hand-rolled tracking variable, matching this codebase's existing on() idiom. Adds a direct regression test in Tooltip.test.tsx toggling forceClosed via a signal.
Replaces two status()!.incidents non-null assertions with an incidentList createMemo narrowing to GitHubStatusIncident[] | null, plus a single Show callback-narrowing block, matching this codebase's established idiom (StatusDot.tsx, Header.tsx, ItemRow.tsx). The shared fallback helper is named statusSummaryRow rather than neutralStatus, since a tracked component can be critical with zero recorded incidents yet.

Also extends the checking-state test to open the popover and assert its fallback content, and adds a regression test dismissing the popover via Escape while simulating a held hover to confirm the tooltip does not reopen.
detectNewItems() in lib/notifications.ts mutates module-level Sets on every call — calling it "pure" in the comment above notifyTransitions() was wrong. Reworded to describe the change-detector/dispatcher split without the incorrect purity claim.
vitest.smoke.config.ts duplicated plugins/environment/globals/setupFiles verbatim from vitest.config.ts. Rewrites it to extend the base config via mergeConfig, setting test.include as a direct post-merge assignment since mergeConfig concatenates array values instead of replacing them.

Also replaces the smoke test's per-name expect(liveNames.has(tracked)).toBe(true) loop with a single missing-names array assertion, so a failure reports exactly which tracked component name drifted instead of a bare true/false.
The github-status smoke test existed but was never wired into CI, so Statuspage component-name drift would only surface if someone remembered to run pnpm test:status-smoke manually. Adds a scheduled GitHub Actions workflow (weekly cron + workflow_dispatch) mirroring ci.yml's existing setup steps.
pnpm test:status-smoke existed since the original implementation but was never listed in the Running checks section, and now has a real CI consumer (the new weekly workflow).
@wgordon17
wgordon17 marked this pull request as ready for review August 8, 2026 14:40
@wgordon17
wgordon17 requested a review from a team August 8, 2026 14:40
@wgordon17
wgordon17 merged commit 4722071 into gordon-code:main Aug 8, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant