Skip to content

feat: full implementation of GitHub tracker dashboard#2

Merged
wgordon17 merged 60 commits intogordon-code:mainfrom
wgordon17:feat/full-implementation
Mar 23, 2026
Merged

feat: full implementation of GitHub tracker dashboard#2
wgordon17 merged 60 commits intogordon-code:mainfrom
wgordon17:feat/full-implementation

Conversation

@wgordon17
Copy link
Copy Markdown
Member

Summary

  • Complete SolidJS dashboard with OAuth, issues/PRs/actions tabs, polling, notifications, dark mode
  • 142 tests across 8 test files, typecheck clean, 244KB JS / 31KB CSS production build
  • Search API + GraphQL optimizations for efficient GitHub API usage

- QA-001: fetchAllData reads userLogin from auth store (was hardcoded empty)
- QA-002/003/004: DashboardPage uses static imports and passes props to all tabs
- QA-005: ActionsTab error prop uses ApiError[] consistently
- SEC-001: refreshAccessToken validates token before storing (SDR-013)
- PERF-003: adds onCleanup for MediaQueryList listener in SettingsPage
- ADV-007: uses Navigate component instead of window.location.replace
- ADV-006: adds isRefreshing guard against concurrent poll fetches
- ADV-011: fixes IDB eviction to use cursor instead of index keys
- ADV-012: removes dead _previousData signal from DashboardPage
- ADV-001: adds global error store with dismissable banners in DashboardPage
- ADV-009: adds Vary: Origin, Access-Control-Max-Age to CORS preflight
- ADV-010: adds 30s tick signal to FilterBar for live Updated X ago
- ADV-013: replaces startsWith URL check with proper hostname parsing
- PERF-002: adds 2-min maxAge to check-status cache entries
- PERF-005: wraps ActionsTab filteredRuns/repoGroups in createMemo
- SEC-002: extracts isSafeGitHubUrl to shared lib, uses everywhere
- SEC-003: adds ghr_ prefix regex validation for refresh tokens
- removes dead exports (isItemIgnored), dead code (preChecked)
- de-duplicates SortIcon, ErrorBannerList, PaginationControls, relativeTime
- combines duplicate imports in config.ts, DashboardPage.tsx
Replaces per-repo API calls with batched Search API queries to
dramatically reduce API call count (~85% reduction for 75 repos):

- Issues: 225 calls to ~3 (batched search with involves qualifier)
- PRs: 75 calls to ~6 search + N detail (involves + review-requested)
- Workflow runs: ~450 calls to 75 (single /actions/runs per repo)

Search API uses separate 30 req/min rate limit, preserving the core
5000/hr budget for PR details and check status.
Replaces 2N REST calls (commit status + check runs per PR) with one
GraphQL query using statusCheckRollup.state, which combines both
legacy status API and modern check runs into a single field.

Uses parameterized GraphQL variables to prevent injection, batches
at 50 PRs per call, and falls back to null on GraphQL errors.
- Errors from batch search, PR detail, and workflow run failures now
  surface through DashboardData.errors to the existing error banner UI
- fetchWorkflowRuns paginates beyond 100 runs per repo
- IDB cache evicts stale pr-detail: entries not in the active PR set
- Adds API-level test gaps (Task 9b) to testing plan
- fixes 429 double-handling between plugin-retry and plugin-throttling
- fixes onSecondaryRateLimit infinite retry by adding retryCount guard
- adds If-Modified-Since/Last-Modified support alongside ETags in cache
- adds notifications API gate to skip full fetch when nothing changed
- adds created-since filter to workflow runs for smaller payloads
- adds GraphQL rateLimit monitoring to check status queries
- adds test for lastModified conditional header propagation
- fixes doNotRetry replacing default list instead of extending it
- removes createdSince/updatedSince filters that break full-replace pattern
- handles skipped flag in doFetch to prevent detectNewItems corruption
- removes dead code (unused updatedSince params on fetchIssues/fetchPullRequests)
prevents dashboard from staying stale indefinitely when notifications
do not cover all change types (workflow runs on unwatched repos, label
changes). Forces full fetch after 10 minutes regardless of gate result.
- resets poll state on logout to prevent stale notifications gate across sessions
- only sets _lastSuccessfulFetch when at least one fetch succeeded
- removes updateRateLimitFromGraphQL to prevent overwriting REST rate limit signal
- corrects misleading If-Modified-Since comment about token refresh
- auto-disables notifications gate after 403 to stop wasting rate limit
  tokens when app lacks notifications permission
- adds lastModified: null to evictStaleEntries test entries to match
  CacheEntry interface
replaces direct import of resetPollState in auth.ts with onAuthCleared
callback pattern. poll.ts registers its reset function at module load
via onAuthCleared(resetPollState) — no circular import needed.
- removes data: from CSP img-src, relaxes OAuth code regex to [a-zA-Z0-9_-]{1,40}

- validates token BEFORE storing in OAuth callback (SDR-013 pre-flight)

- converts mutable metadata Maps to createMemo for SolidJS reactivity

- replaces Date object creation with string comparison for date sorting

- REST fallback fetches Check Runs API alongside Status API for full fidelity

- extracts extractRejectionError helper, uses IDBKeyRange in evictByPrefix

- exports filter field types from view store, migrates Settings Data to SettingRow

- adds 49 new tests: REST fallback branches, poll coordinator guards, cache eviction, worker refresh parity, auth edge cases, empty userLogin short-circuit
Security: adds AuthGuard on protected routes, moves refresh token to HttpOnly cookie (Worker sets/reads/clears via Set-Cookie), adds CSP hash CI verification, adds CORS credentials support, documents Worker API endpoints in DEPLOY.md.

Correctness: fixes clearErrors wiping in-flight pushError calls, resets notification seen-sets on logout, fixes fork PR check status GraphQL lookup, adds try-catch around onAuthCleared callbacks, fixes formatDuration type.

Performance: chunks PR detail fetches (batches of 10), memoizes selectedSet in RepoSelector, debounces view state persistence (200ms).

Code quality: extracts SkeletonRows and ChevronIcon shared components, unifies ErrorBannerList with onDismiss, exports storage key constants, removes dead code.

Tests: adds coverage for QuotaExceededError eviction, onAuthCleared callbacks, poll skipped path, cachedRequest If-Modified-Since fallback, worker regex boundaries, HttpOnly cookie refresh flow, and logout endpoint.
@wgordon17 wgordon17 force-pushed the feat/full-implementation branch from 18fe8b6 to f383a3f Compare March 23, 2026 21:46
@wgordon17 wgordon17 merged commit 0af9511 into gordon-code:main Mar 23, 2026
@wgordon17 wgordon17 deleted the feat/full-implementation branch April 8, 2026 17:00
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