Repository navigation
Phase 1a–1c: Dioxus fullstack open-source health dashboard (PRs, Devin workbench, Releases, CI) - #1
Draft
jkelleyrtp wants to merge 30 commits into
Draft
jkelleyrtp wants to merge 30 commits into
jkelleyrtp wants to merge 30 commits into
Conversation
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
Note: I can only respond to comments from users who have write access to this repository. ⚙️ Control Options:
|
…ration
- stars_7d_delta is null unless a snapshot >=7 days old exists; UI renders
it as a signed count
- sync closed/merged PRs (updatedAt > 30d, paginated pullRequests
states:[MERGED,CLOSED]) and closed issues per monitored repo; chosen over
GraphQL search because it avoids the search rate limit
- fix use_effect debounce loop in prs/issues that read-and-wrote the same
signal, spawning unbounded tasks and exhausting the wasm externref table
('table grow failure' broke hydration on /prs)
- wrap PR table and repo detail in SuspenseBoundary + suspend() so SSR
renders real data
- pin wasm-bindgen =0.2.121 to match dx 0.8.0-alpha.1's bundled CLI
Sync carry-overs: closed PR/issue queries fetch labels and update only lifecycle columns; open-issue sync marks DB rows absent from the fetch as closed. GitHub App auth via octocrab AppAuth (JWT mint + installation token refresh handled internally); PAT remains the fallback.
backend/devin.rs talks to the org-scoped v3 sessions API; backend/actions.rs renders per-kind prompts and dispatches sessions behind a daily llm_budget; collector polls pending sessions every 60s; new server fns for dispatch, assess (cached per head_sha), session list/refresh/message, devin status.
- consume daily budget only after devin create_session succeeds - map_status treats populated structured_output/pull_requests as finished regardless of devin status (structured_output_required sessions park at running/waiting_for_user); poll_session upserts pr_assessments on it - use_server_future instead of use_resource for list_prs/get_repo so results serialize for hydration; fixes client-side hydrate_node crash that left all /prs row clicks unbound - get_assessment/list_sessions switched to #[post] (GET server fns cannot send args in a request body)
…ck_now - declare [profile.server-dev]/[profile.wasm-dev] in workspace Cargo.toml (inherit dev) so plain cargo uses the same profiles dx builds with; canonical commands documented in README/ARCHITECTURE. Dep artifacts share with dx when --target matches dx's layout; cargo test builds a parallel tree once because the dioxus-ssr dev-dep changes features - map_status: (running, working, has_result) stays working so sessions that produce a result mid-run keep being polled - commit missing db::budget_check_now used by actions::dispatch
- replace sidebar with sticky header.topnav; active link via route prefix,
admin badge when logged in
- html { background, color-scheme: dark } + data-theme=dark on mount so
overscroll and dxc components stay dark
- AdminState context provided by Layout, populated via api::is_admin();
settings login updates it
- author association text badge replaced by colored .author.<kind> name
with the association word in title (prs, issues, repo detail)
- filter-bar controls share one rule (34px, 6px radius); Columns button
no longer a pill
- PrsTable keeps last_rows and renders them from the suspense fallback during refetch (no loading flash); 'syncing...' indicator while pending; committed only set when the query actually changes - Columns popover: pick visible columns, persisted to localStorage 'prs.columns'; number/last_by hidden by default; title locked on - admin-only 'devin' column with per-row Assess button (expands row on success, spinner + inline error) - document::eval: use .await (join) instead of .recv() — recv waits for dioxus.send() and never resolves on 'return', so URL ?q= init and the localStorage read were dead; both work now - repos page: sort select (pushed/stars/prs/issues/name), list_repos orders by pushed_at desc - ci.yml: fmt, clippy server+web (dx profiles), test; no dx install
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Replaces the hello-world scaffold with a Dioxus
0.8.0-alpha.1fullstack app (packages/status, cratedioxus-status) that collects GitHub + crates.io data into SQLite, serves the dashboard pages, and drives Devin sessions against PRs. Design lives inDESIGN.md, implementation notes inARCHITECTURE.md.Data collection (
src/backend/, server feature only)github.rs: GraphQL overreqwestfor org repos, open + recently closed/merged PRs (review decision, mergeability, CI rollup, review threads, files, linked issues, timeline →last_activity_by ∈ {maintainer, contributor, bot}), open + recently closed issues, releases. Paginated, rate-limit aware. Items that vanish from the open set are marked closed with a targeted lifecycle update (rich rows are never replaced by partial ones).AppAuth(GITHUB_APP_ID+GITHUB_APP_PRIVATE_KEY[_PATH], installation discovered by org unlessGITHUB_APP_INSTALLATION_IDis set), falling back toGITHUB_TOKEN. The app givesmembersWithRole, so maintainer classification works.crates_io.rs: per-crate totals + 90-day daily downloads + versions for a configurable crate list.scoring.rs: deterministic 0–100 mergeability score with a per-factor breakdown (ScorePart). Tested.collector.rs: periodic syncs with per-kind mutex, manualsync_now(kind), plus a Devin poller (≤20 pending sessions / 60s).db.rs+migrations/000{1,2,3}_*.sql: sqlx runtime queries, DB at$DATA_DIR/status.db.auth.rs: v1 admin =ADMIN_TOKEN→ HMAC cookie;require_admin()gates every mutating server fn.Devin workbench (
devin.rs,actions.rs) — v3 org-scoped API ({DEVIN_API_BASE}/v3/organizations/{DEVIN_ORG_ID}/sessions; the enterprise service-user key only works there, not on/v1).assess rebase address_reviews deslop add_tests deep_review split changelog_entry custom. Every prompt carries the PR facts (title/body/labels/CI/mergeability/threads/files) and the rules: never force-push the contributor branch, push todevin/pr-{n}-{kind}, no Co-Authored-By.assessis the lazy LLM path:structured_output_schema+max_acu_limit: 2, result cached inpr_assessmentskeyed by(repo, number, head_sha);assess_pr(force=false)returns the cache when the head hasn't moved. No background sweeps.llm_budget, default 50, overridable in Settings):budget_check_now()→create_session→budget_consume(), so a failed API call costs nothing.map_status(status, detail, has_result): structured-output sessions park atrunning/waiting_for_userwhen done, so a populated result maps tofinishedunlessdetail == working. Tested.dispatch_action,assess_pr,get_assessment,list_sessions(prompt stripped for non-admins),refresh_session,send_session_message,get_devin_status,set_llm_budget.Server fns (
src/api/mod.rs):get_overview,list_prs(PrFilter),get_pr,list_issues,list_repos,get_repo,get_health,get_settings,admin_login/logout,set_monitored_repos,set_crates,sync_now+ the Devin set above.list_prscompiles a GitHub-style query (repo:x author:y label:z -label:z is:draft|green|red|approved|conflict|stale|first-timer+ free text) into a bound SQL statement. Server fns that take args are#[post]—#[get]with args fails on the client (no body on GET).UI (
src/ui/): GitHub-style top navbar (header.topnav,html { background: var(--bg) }so overscroll doesn't flash), Overview (health strip + ready-to-merge / quick wins / going stale / waiting-on-maintainer / first-timers / Devin activity), PR table with search + chips + sort + expandable row (score breakdown, assessment card, Devin action buttons, session history), Issues, Repos + drill-down, Health (SVG charts), Bots (budget, session table, refresh/message), Settings (admin login, monitored repos, crates, budget, sync), Releases (below).PR table details:
use_cachedhook below; a smallsyncing…marker sits by the filter bar while a refetch runs.PR_COLUMNS, default hides#andlast by, persisted inlocalStorage['prs.columns']); author association is a color class on the name (.author.maintainer|first-timer|bot) instead of a text badge.devincolumn with a per-row Assess button (assess_pr(force=false)→ expands the row to show the card).db::list_reposnow orders bypushed_at DESC.document::eval("return x").recv()never resolves — return values come via.await; both the?q=URL init and the localStorage read use.await.Navigation cache (
ui/cache.rs):use_cached(key, fetch) -> Cached<T>wrapsuse_loaderwith a web-only, in-memory (thread-local) stale-while-revalidate map keyed by a string that includes all query args. Only a first-ever uncached visit / SSR suspends; revisits render the last value instantly and refetch in the background. Chosen over localStorage because SSR already delivers data on hard reloads, so persisting payloads would only add hydration-mismatch risk. Preferences (columns, overview repo filter, debounced search) go throughui/storage.rs(use_persisted_signal,use_debounced).Overview repo filter:
get_overview(repos: Option<Vec<String>>)—None= all repos,Some([])= none (AND 1=0), otherwiseAND repo IN (?,…)applied to counts, stars, stars-delta, downloads (viacrates.repo) and all six PR lists. Client model isenum RepoFilter { All, Only(Vec<String>) }persisted inlocalStorage['overview.repos']; unchecking fromAllexpands to every monitored repo minus that one, and a fullOnlyset collapses back toAll. Menu rows useMenuCheckbox(a plain button) because the vendoredCheckboxcallsset_focuson click, which blurs the dropdown trigger and closes the menu.Deslop pass (per
deslop-rust-skill): typedActionKind/SyncKind/TargetKind/SizeBucketenums (FromStr/Displayproduce the exact strings stored in the DB and sent on the wire — no format change), named constants for limits/windows/budgets,From<&DbPr> for PrSummary,days_since_rfc3339,str_list,db::upsert_release,urlencodingcrate replacing hand-rolled percent-decoding (which mangled multi-byte UTF-8 in?q=).Releases (Phase 1c) (
ui/releases.rs,migrations/0004_releases.sql)/releases: card per monitored repo — latest stable tag, days since (severity-colored), latest prerelease, unreleased merged-PR count, median cadence of recent stable gaps, next open milestone, must-ship open/total./releases/:repo: last 10 releases, unreleased changelog since the latest stable tag (one fixed-column table, grouped Breaking / Features / Fixes / Docs / Other / Internal by label +feat:/fix:prefix + bot author), open milestones with progress, must-ship checklist, copy-as-markdown.sync_releases→sync_milestones(REST; milestones closed upstream are deleted) →sync_merged_since(latest stable date, 180d fallback)via GraphQL searchis:merged merged:>=…, capped at 300/repo, written with the lifecycle-aware update so rich rows survive.release_targets(pr|issue|note, optional number, manualdone); linked PR merged / issue closed counts as complete automatically. Add/remove/toggle arerequire_admin(); reads are public.CI:
.github/workflows/ci.yml— fmt check, both clippy invocations, server tests (cargo only, no dx).Hydration note: list data uses
use_server_future(notuse_resource().suspend()), which is what serializes results into the SSR payload; without it the client crashed inhydrate_nodeand no row listeners were bound.Build: dx builds with cargo profiles
server-dev(always with--target x86_64-unknown-linux-gnu) andwasm-dev; both are declared in the workspaceCargo.tomlso the README'scargo check/clippy/test --profile … --target …commands share dx's artifacts (verified:dx buildafter them recompiles 0 crates).cargo testbuilds its own dep tree once because thedioxus-ssrdev-dep changes feature resolution.Vendored (
vendor/,src/components/):dioxus-primitivesanddioxus-attributesfrom dioxus-components'0.8branch bumped to alpha.1, a 4-icon inline-SVG replacement fordioxus-icons, and a minimaldioxus-sdk-timeshim.Known gaps / notes
dx serveneeds--hot-patch false --hot-reload falseon rustc 1.94.Screenshots
Running locally
Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/2203bdc5b6e5485fab5c3f02ddd15e9b
Open in Devin Desktop: https://dioxus.staging.devinenterprise.com/desktop/session/2203bdc5b6e5485fab5c3f02ddd15e9b?variant=devin-insiders
Requested by: @jkelleyrtp