Skip to content

refactor(ui): fix the react-hooks 7 compiler-era findings, and unify the app on one data layer - #9873

Merged
loopover-orb[bot] merged 13 commits into
mainfrom
chore/ui-cleanups-9588
Jul 29, 2026
Merged

refactor(ui): fix the react-hooks 7 compiler-era findings, and unify the app on one data layer#9873
loopover-orb[bot] merged 13 commits into
mainfrom
chore/ui-cleanups-9588

Conversation

@JSONbored

Copy link
Copy Markdown
Owner

Closes #9588.

What this fixes

eslint-plugin-react-hooks 5 → 7 (forced by the eslint 10 security chain in #8608) introduced four React-Compiler-era rules that flagged 27 sites across 24 files. #8608 demoted them to warn rather than smuggle real UI refactoring into a dependency bump. This does the refactoring.

26 of the 27 are fixed. purity, refs and static-components are back at error, where the recommended preset puts them.

The through-line: nothing that can be derived is stored

Most of these were state written into an effect that could simply be computed. Recurring shapes:

  • Derive by key. A settled result is stored under the exact inputs it belongs to, so "is it stale?" is a comparison rather than bookkeeping. This is what replaced useApiResource's manual request-id guard, commands-panel's reset-then-fetch, audit-feed's pagination reset, the docs rail's per-route reset, and the terminal's per-scene typing progress. It also drops superseded in-flight responses for free — they land under the old key and can never be read.
  • Read external stores as external stores. localStorage, sessionStorage, the sidebar cookie, prefers-reduced-motion, tab visibility and "have we hydrated" are all useSyncExternalStore now. Each snapshot is a primitive or memoized on one, because a fresh object per call re-renders forever.
  • Adjust state during render (React's documented pattern) where an input genuinely changes state: the progress bar, the command palette's highlighted index, the maintainer repo seed.
  • Reset by key. The try-it panel cleared five fields from an effect — a hand-maintained list that would silently miss any field added later. It is keyed on the operation instead.

Two effects turned out to change no rendered output at all and were deleted: api-status-banner already derived dismissed correctly, and chat-qa-panel back-filled a value that could be computed.

The structural part: one data layer, not two

The app already ran a QueryClient at its root while useApiResource maintained a second, parallel data layer for 80+ call sites. React's own guidance — linked from the rule's message — is that fetch-on-mount belongs in a data-fetching library, so that is what the fetch-shaped sites now use.

retry, refetchOnWindowFocus and gcTime are pinned explicitly rather than inherited: react-query defaults to three retries and a focus refetch, neither of which these call sites did. Adopting the library therefore changes no observable behaviour anywhere; loosening them is a deliberate per-surface decision, not a side effect of this PR.

Test context comes from one shared helper (src/lib/test-query-client.tsx) rather than a wrapper per file — several files had already grown their own copy. Sharing it is what keeps the client's test defaults consistent: a retrying client turns an asserted error state into a timeout, and a shared cache lets one case's response answer the next case's request.

The one site left, and why

set-state-in-effect stays at warn for docs-toc, which builds the "On this page" rail by querying the rendered DOM. The real fix is fumadocs' compiled toc, but the component renders in the docs layout while that data resolves in the child route — and it also serves docs pages that are not MDX at all and so have no compiled toc. Hacking around either would be worse than the scrape. Tracked with the full analysis in #9872; the rule goes to error there.

Validation

  • 1,053 UI tests pass (646 + 407), ui:typecheck clean, ui:build clean, git diff --check clean.
  • No behaviour change was accepted silently: every react-query adoption pins the options that would otherwise have changed, and every seeded editor gates its seed on dataUpdatedAt so a maintainer's in-progress edits survive re-renders.

JSONbored added 13 commits July 29, 2026 09:28
…nts errors (#9588)

useLocalStorage is rebuilt on useSyncExternalStore -- localStorage IS an external
store, and subscribing to it directly removes both the mount-time setState-in-effect
and the render-phase ref write the old shape needed. The snapshot is the raw string,
a primitive, so it is stable by construction; the parse happens once per change.
Incidentally removes the first-paint flash, since the stored value is now available
on the first client render rather than one effect later.

The docs route uses the client loader's useContent(path), which returns react NODES,
instead of getComponent(path), which mints a component during render -- a fresh
component identity each render remounts the whole page body.

RetryCountdown reads a 250ms clock through useSyncExternalStore rather than seeding
useState with Date.now() and ticking it from an effect. The snapshot is cached
because a bare () => Date.now() is never stable and would re-render forever; one
shared interval now serves every mounted countdown.
…riting them from effects (#9588)

useApiResource keys its settled result by the exact inputs it was fetched for, so
both "loading" and the stale-response guard (#7785) fall out of comparing that key
against the current inputs -- the request-id ref did the same job by hand, and a
disabled resource no longer renders a frame of loading before an effect corrects it.

usePreviewDataState derives isLoading from which version has settled, so bumping the
version re-enters loading on the same render that requested the refresh.

ApiProgressBar shows on the render that sees activity start, via React's documented
adjust-state-during-render pattern; only the 240ms trailing fade remains a timer,
whose setState runs in the timer callback rather than an effect body.
…bar cookie (#9588)

The api-status-banner effect changed no rendered output: `dismissed` already
compares the stored key against the current one, so a stale key reads as
not-dismissed by derivation. The effect only scrubbed state nothing consulted.

The command palette resets its highlighted index during render, so the reset lands
in the same commit as the new filtered list rather than a frame after it.

The sidebar's open state is a cookie -- an external store, now read as one instead
of copied into state by a mount effect. The server snapshot stays undefined, which
is what the hydration gate already keys on, so output is unchanged.
…s external stores (#9588)

github-stats-chip read sessionStorage into state from a mount effect; sessionStorage
IS an external store, so it is read as one. The snapshot memoizes on the raw string,
because re-parsing per call returns a fresh object every render and loops forever.

useCountUp sampled prefers-reduced-motion and tab visibility inside its effect and
then wrote the final value synchronously when either said "no animation". Both are
genuinely subscribable -- a matchMedia change list and visibilitychange -- so they
are a store, which lets the no-animation case be derived: the value simply IS the
target. Only the rAF and safety-net callbacks still set state, which they may.
…9588)

chat-qa-panel back-filled its select with the first eligible PR from an effect; the
list arrives asynchronously, so that left one render showing an empty select before
correcting itself. The value is now derived from the choice and the list together.

commands-panel keys its preview by the exact inputs it was fetched for, so clearing
on change is a derivation rather than a synchronous write at the top of the effect --
and a stale in-flight response now lands under the old key and can never be shown.
…repo field during render (#9588)

The try-it panel cleared five fields from an effect whenever the operation changed --
a hand-maintained list that would silently miss any field added later. It is now
keyed on the operation, which is React's documented way to reset state on an input
change, and the stored token is read in a lazy initializer instead.

maintainer-panel had two effects both seeding the same repo field. They are one
render-time adjustment now, so the field is populated on the render that first sees
the options; `appliedSeed` is what keeps a user's own edit from being overwritten.
…rolled effect (#9588)

The app already ran a QueryClient at its root while this hook maintained a second,
parallel data layer for 80+ call sites. Backing it with react-query removes the
mount effect that called setState, the manual request-id guard against out-of-order
responses, and the bespoke reload plumbing -- all of which the library does by
keying on the request instead of by hand.

retry, refetchOnWindowFocus and gcTime are pinned EXPLICITLY rather than inherited:
react-query defaults to three retries and a focus refetch, neither of which this
hook did. Adopting the library therefore changes no observable behaviour at any call
site; loosening them is a deliberate per-surface decision, not a side effect.

Test context comes from one shared helper rather than a wrapper per file. Several
files had already grown their own copy, and sharing it is what keeps the client's
test defaults consistent -- a retrying client turns an asserted error state into a
timeout, and a shared cache lets one case's response answer the next case's.
…ough react-query (#9588)

Both hand-rolled the load/cancel/error state machine, including a `cancelled`
callback to drop a response a newer repo selection had superseded -- which is just
keying, so the query key does it now.

AI-review settings seeds EDITABLE fields from its response, so the seed is gated on
dataUpdatedAt and applied during render: a fresh response re-seeds, and a user's own
edits survive every re-render in between.
…ugh react-query (#9588)

Same hand-rolled load/cancel/error machinery as the two panels before them; the
query key does the supersession the `cancelled` callback did by hand.

The onboarding card's unparseable-target case is now a DERIVED error rather than a
fetch that never happens -- it depends only on the target, so it needs no request
and no state to represent it.
…h react-query (#9588)

Both editors keep their content in state because both are edited; the seed is gated
on dataUpdatedAt and applied during render, so a fresh response re-seeds while a
maintainer's in-progress edits survive every re-render in between.

The focus-manifest read still renders a failure as an empty editor rather than an
error surface, exactly as before.
…9588)

Later pages are appended by loadMore, so the rendered list stays state -- seeded
from each new first-page response, which is also what resets pagination when the
filters change. A role that cannot read the feed is now a derived error rather than
a fetch that never happens.

The generation ref that invalidates an in-flight loadMore is bumped from an effect:
a ref may be written there, but not touched during render.
…effect (#9588)

The event subscription stays an effect -- that is what effects are for. What moved
out is the mount-time fetch. The query owns only WHEN the read runs; the session
itself stays in the state that sign-in, sign-out and the preview path already write,
so every consumer keeps seeing one value from one place.
…long to (#9588)

The typing progress belongs to one scene and the TOC to one route, so both are
stored under that key -- advancing the scene or navigating resets them by
derivation rather than by setState calls at the top of an effect. Reduced motion
needs no state at all: the finished frame is the pure value.

purity, refs and static-components are back at error, where the recommended preset
puts them. set-state-in-effect stays at warn for the single remaining site: the
docs rail reads its headings from the rendered DOM, and sourcing them from the
compiled MDX toc needs the layout/child-route split resolved first (#9872).
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 29, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
loopover-ui 8decdcf Commit Preview URL

Branch Preview URL
Jul 29 2026, 05:31 PM

@loopover-orb

loopover-orb Bot commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Tip

✅ LoopOver review result - approve/merge recommended

Review updated: 2026-07-29 17:36:33 UTC

43 files · 1 AI reviewer · no blockers · readiness 98/100 · CI green · clean

✅ Suggested Action - Approve/Merge

  • safe to merge

Review summary
This PR is a targeted, well-reasoned refactor that fixes the 26 remaining react-hooks 7 compiler-era violations (set-state-in-effect, purity, refs, static-components) demoted to warn in #8608, and restores three of the four rules to error, closing #9588. The through-line — deriving state during render instead of writing it in effects, using useSyncExternalStore for genuinely external stores (localStorage, cookies, matchMedia, visibility, a shared clock), and consolidating ad-hoc fetch effects onto react-query — is applied consistently and the traced logic (e.g. the localStorage cell's legacy-migration fallback, the seededAt render-time re-seed pattern, docs-toc's per-route derivation) holds up correctly on inspection. The most notable risk is not a defect but disproportion: 769 added source lines against only 42 added test lines (many of which are just test-helper wrapper swaps), which is thin for a repo that expects ~97% patch, branch-counted coverage on the new derived-state branches this diff introduces.

Nits — 6 non-blocking
  • Test-to-code ratio is 0.05 (769 source / 42 test) — new branches like maintainer-settings.tsx's seededAt-gated render-time setState, use-api-resource.ts's DISABLED_STATE/LOADING_STATE selection, and use-local-storage.ts's legacy-migration + refresh() path don't appear to get dedicated new test coverage beyond the existing QueryClient wrapper swap.
  • apps/loopover-ui/src/lib/api/use-api-resource.ts:24-38 casts the frozen `DISABLED_STATE`/`LOADING_STATE` sentinels from `ResourceState<never>` to `ResourceState<T>` — functionally fine since `data` is always `null` there, but worth a one-line comment noting the cast is safe only because those fields are never read as `T`.
  • Several panels (ai-review-settings.tsx, ams-miner-[context]-card.tsx, activation-preview.tsx, maintainer-settings.tsx, onboarding-preview-card.tsx) repeat the identical `{ retry: false, refetchOnWindowFocus: false, gcTime: 0 }` react-query options object; consider a shared constant even though the PR's own comments explain why it's pinned explicitly per call site.
  • maintainer-panel.tsx (~528 lines) and maintainer-settings.tsx (~562 lines) remain oversized files this PR touches but doesn't split — not introduced by this diff, so not blocking, but a candidate for a follow-up now that both are being actively edited.
  • Add a couple of focused tests for the render-time derivation branches called out above (seededAt gating in maintainer-settings.tsx / ai-review-settings.tsx / focus-manifest editor, and the DISABLED_STATE branch in use-api-resource.ts) to keep patch coverage healthy on `src/**`.
  • PR author also opened the linked issue — Link an issue that was opened by a different contributor, or provide a rationale for why this self-authored issue represents genuine discovery work.

Decision drivers

  • ✅ Code review — No blockers (1 reviewer)
  • ✅ Gate result — Passing (No configured blocker found.)
Context & advisory signals — never blocks the verdict
Signal Result Evidence
Linked issue ✅ Linked #9588
Related work ✅ No active overlap found No same-issue or scoped active PR overlap found.
Change scope ✅ 20/20 Low review scope from cached public metadata (1 linked issue).
Validation posture ✅ 25/25 PR body includes validation/test evidence.
Contributor workload ✅ 10/10 Author activity: 14 registered-repo PR(s), 13 merged, 334 issue(s).
Contributor context ✅ Confirmed Gittensor contributor JSONbored; Gittensor profile; 14 PR(s), 334 issue(s).
Improvement ✅ Minor risk: clean · value: minor · LLM: significant
Linked issue satisfaction

Addressed
The PR fixes 26 of 27 flagged sites across the 24 files, restores purity, refs, and static-components rules to error, and the description states the remaining single site among set-state-in-effect findings is not yet fixed, though the diff shows substantial, well-reasoned refactoring toward derived state and useSyncExternalStore per the issue's guidance.

Review context
  • Author: JSONbored
  • Role context: owner (maintainer lane)
  • Public audience mode: oss maintainer
  • Lane context: Repository is registered but has no active allocation in the current snapshot.
  • Public profile languages: Python, TypeScript, Ruby, Go, MDX, Shell, Solidity, JavaScript
  • Official Gittensor activity: 14 PR(s), 334 issue(s).
  • PR-specific overlap: none found.
Contributor next steps
  • Start here: Treat this as maintainer-lane context rather than normal contributor-lane activity.
  • Then work through the remaining 1 step in the Signals table above.
Signal definitions
  • Related work = same linked issue, overlapping active PRs, or title/path similarity.
  • Change scope = cached public metadata such as size labels, draft state, and review-burden hints.
  • Validation posture = whether the PR provides enough public validation/test evidence for maintainer review.
  • Contributor workload = public contributor activity and cleanup pressure, not a repo-wide quality failure.
  • Contributor context = public GitHub/Gittensor identity context; non-Gittensor status is not a blocker.
🧪 Chat with LoopOver

Ask LoopOver a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.

  • @loopover ask &lt;question&gt; answers contribution-quality Q&A with source citations and freshness.
  • @loopover chat &lt;question&gt; answers in natural prose from cached decision-pack facts via local inference (maintainer/collaborator; read-only).
  • A plain-language @loopover mention with a real question is routed to the closest matching read-only command automatically — no exact syntax required.

Full command reference: https://loopover.ai/docs/loopover-commands

🧪 Experimental — new and may change.

Visual preview
Route Viewport Before (production) After (this PR's preview) Diff
/ desktop before /
before /
after /
after /
/ mobile before / (mobile)
before / (mobile)
after / (mobile)
after / (mobile)
/app/test desktop before /app/test
before /app/test
after /app/test
after /app/test
/app/test mobile before /app/test (mobile)
before /app/test (mobile)
after /app/test (mobile)
after /app/test (mobile)

Click any thumbnail to open the full-size screenshot. Before = production · After = this PR's preview deploy.

Scroll preview
Route Before (production) After (this PR's preview)
/ before / (scroll)
before / (scroll)
after / (scroll)
after / (scroll)
/app/test before /app/test (scroll)
before /app/test (scroll)
after /app/test (scroll)
after /app/test (scroll)

A short scroll-through clip (desktop) — click either thumbnail to open the full animation. Evidence for scroll-linked behavior a single screenshot can't show.

🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed


💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →.

Checked by LoopOver, a quiet PR intelligence layer for OSS maintainers.

  • Re-run LoopOver review

@superagent-security

Copy link
Copy Markdown
Contributor

Superagent didn't find any vulnerabilities or security issues in this PR.

@codecov

codecov Bot commented Jul 29, 2026

Copy link
Copy Markdown

Bundle Report

Changes will increase total bundle size by 2.0kB (0.03%) ⬆️. This is within the configured threshold ✅

Detailed changes
Bundle name Size Change
loopover-ui 7.92MB 2.0kB (0.03%) ⬆️

Affected Assets, Files, and Routes:

view changes for bundle: loopover-ui

Assets Changed:

Asset Name Size Change Total Size Change (%)
assets/add-scalar-classes-D41R-T27.js (New) 2.16MB 2.16MB 100.0% 🚀
assets/tanstack-vendor-KsQ4HaYp.js (New) 932.08kB 932.08kB 100.0% 🚀
assets/docs.fumadocs-spike-api-reference-C4N4waNy.js (New) 443.45kB 443.45kB 100.0% 🚀
assets/AgentScalarChatInterface.vue-2lC6DiYb.js (New) 201.7kB 201.7kB 100.0% 🚀
assets/modal-CHtpkJft.js (New) 184.5kB 184.5kB 100.0% 🚀
assets/client-Bt4YtpQ3.js (New) 151.47kB 151.47kB 100.0% 🚀
assets/styles-DJFWcZy-.css (New) 129.97kB 129.97kB 100.0% 🚀
assets/maintainer-panel-BlBWJPyV.js (New) 78.96kB 78.96kB 100.0% 🚀
assets/routes-CdgPIiwD.js (New) 36.4kB 36.4kB 100.0% 🚀
assets/owner-panel-CYUisJuf.js (New) 28.18kB 28.18kB 100.0% 🚀
assets/app-DNngSU6Q.js (New) 25.82kB 25.82kB 100.0% 🚀
assets/ui-vendor-CR2nADRA.js (New) 24.57kB 24.57kB 100.0% 🚀
assets/miner-panel-DLwwuy_N.js (New) 20.24kB 20.24kB 100.0% 🚀
assets/app.runs-sSAE0Yx_.js (New) 20.22kB 20.22kB 100.0% 🚀
assets/api._op-CoLRQU8k.js (New) 17.54kB 17.54kB 100.0% 🚀
assets/self-hosting-docs-audit-DNrqZHNN.js (New) 16.6kB 16.6kB 100.0% 🚀
assets/docs._slug-peft3wcA.js (New) 15.63kB 15.63kB 100.0% 🚀
assets/playground-panel-PU3NYke4.js (New) 14.42kB 14.42kB 100.0% 🚀
assets/fairness-BWgcmo7k.js (New) 13.98kB 13.98kB 100.0% 🚀
assets/app.audit-Dkh3Yazl.js (New) 10.22kB 10.22kB 100.0% 🚀
assets/app.config-generator-DbggvvSW.js (New) 10.06kB 10.06kB 100.0% 🚀
assets/maintainers-CXSZzLmI.js (New) 8.06kB 8.06kB 100.0% 🚀
assets/miners-BpWKfqxQ.js (New) 7.91kB 7.91kB 100.0% 🚀
assets/agents-DV_-Id6N.js (New) 7.74kB 7.74kB 100.0% 🚀
assets/commands-panel-Bode-dwD.js (New) 6.74kB 6.74kB 100.0% 🚀
assets/maintainer-workflow-DNfy_YfM.js (New) 6.52kB 6.52kB 100.0% 🚀
assets/digest-panel-B_Zg9qeS.js (New) 6.15kB 6.15kB 100.0% 🚀
assets/repos._owner._repo.quality-Dqn9AzON.js (New) 6.14kB 6.14kB 100.0% 🚀
assets/docs-nav-BIqKFbvi.js (New) 6.06kB 6.06kB 100.0% 🚀
assets/docs.index-BHb0IhbG.js (New) 5.95kB 5.95kB 100.0% 🚀
assets/api.index-CQT2uHxh.js (New) 4.7kB 4.7kB 100.0% 🚀
assets/docs-qAiOT2qu.js (New) 2.93kB 2.93kB 100.0% 🚀
assets/api-Cb0Rx4f9.js (New) 2.69kB 2.69kB 100.0% 🚀
assets/docs-page-Bdlrzgq_.js (New) 2.1kB 2.1kB 100.0% 🚀
assets/table-DFBbmNy7.js (New) 1.75kB 1.75kB 100.0% 🚀
assets/app.workbench-B8-aXEvJ.js (New) 1.58kB 1.58kB 100.0% 🚀
assets/tabs-51LZa_y5.js (New) 1.39kB 1.39kB 100.0% 🚀
assets/app.repos-B9e650Bs.js (New) 1.07kB 1.07kB 100.0% 🚀
assets/input-CfDdeNaY.js (New) 796 bytes 796 bytes 100.0% 🚀
assets/file-cog-BhUULYTt.js (New) 758 bytes 758 bytes 100.0% 🚀
assets/app.maintainer-BxjJPAe0.js (New) 502 bytes 502 bytes 100.0% 🚀
assets/app.owner-kwP-3r4_.js (New) 474 bytes 474 bytes 100.0% 🚀
assets/app.commands-RQvVEVdF.js (New) 455 bytes 455 bytes 100.0% 🚀
assets/app.playground-mFGRLVQD.js (New) 442 bytes 442 bytes 100.0% 🚀
assets/index-zcw-Wl3B.js (New) 438 bytes 438 bytes 100.0% 🚀
assets/app.digest-DaEzua5u.js (New) 430 bytes 430 bytes 100.0% 🚀
assets/eye-off-BLg9e0B5.js (New) 430 bytes 430 bytes 100.0% 🚀
assets/app.miner-BBxXhAIL.js (New) 422 bytes 422 bytes 100.0% 🚀
assets/key-round-BvsOy7nV.js (New) 355 bytes 355 bytes 100.0% 🚀
assets/bot-C2APo0Tw.js (New) 328 bytes 328 bytes 100.0% 🚀
assets/trash-2-2CT9Jvtw.js (New) 328 bytes 328 bytes 100.0% 🚀
assets/save-B8bWpvvI.js (New) 327 bytes 327 bytes 100.0% 🚀
assets/git-pull-request-arrow-ChIHEQO_.js (New) 321 bytes 321 bytes 100.0% 🚀
assets/list-checks-DcfQhF8P.js (New) 279 bytes 279 bytes 100.0% 🚀
assets/compass-DmNwz_Q2.js (New) 251 bytes 251 bytes 100.0% 🚀
assets/history-Ca4ByVVG.js (New) 237 bytes 237 bytes 100.0% 🚀
assets/message-square-CQ_NkbeU.js (New) 233 bytes 233 bytes 100.0% 🚀
assets/lock-E_1n_O0s.js (New) 206 bytes 206 bytes 100.0% 🚀
assets/rotate-cw-qjwRykgm.js (New) 201 bytes 201 bytes 100.0% 🚀
assets/play-dR-echoq.js (New) 190 bytes 190 bytes 100.0% 🚀
assets/circle-check-DtcukxQF.js (New) 178 bytes 178 bytes 100.0% 🚀
assets/search-kXpgX4hs.js (New) 174 bytes 174 bytes 100.0% 🚀
assets/add-scalar-classes-Dqxd2m2W.js (Deleted) -2.16MB 0 bytes -100.0% 🗑️
assets/tanstack-vendor-BfgALU9h.js (Deleted) -930.96kB 0 bytes -100.0% 🗑️
assets/docs.fumadocs-spike-api-reference-B-vF6wxq.js (Deleted) -443.45kB 0 bytes -100.0% 🗑️
assets/AgentScalarChatInterface.vue-DCNv3dNP.js (Deleted) -201.7kB 0 bytes -100.0% 🗑️
assets/modal-D9o8RBej.js (Deleted) -184.5kB 0 bytes -100.0% 🗑️
assets/client-ZlaVrHLD.js (Deleted) -151.47kB 0 bytes -100.0% 🗑️
assets/styles-B0FjzULh.css (Deleted) -129.94kB 0 bytes -100.0% 🗑️
assets/maintainer-panel-CDcYEmsg.js (Deleted) -78.99kB 0 bytes -100.0% 🗑️
assets/routes-G_ATk-qg.js (Deleted) -35.96kB 0 bytes -100.0% 🗑️
assets/owner-panel-BHgwdt1R.js (Deleted) -28.18kB 0 bytes -100.0% 🗑️
assets/app-DdWO_K_d.js (Deleted) -25.78kB 0 bytes -100.0% 🗑️
assets/ui-vendor-DNzS58g6.js (Deleted) -24.57kB 0 bytes -100.0% 🗑️
assets/miner-panel-DxUNlWat.js (Deleted) -20.24kB 0 bytes -100.0% 🗑️
assets/app.runs-DptC81WN.js (Deleted) -20.22kB 0 bytes -100.0% 🗑️
assets/api._op-DxookC8e.js (Deleted) -17.57kB 0 bytes -100.0% 🗑️
assets/self-hosting-docs-audit-6kCzTzfs.js (Deleted) -16.6kB 0 bytes -100.0% 🗑️
assets/docs._slug-ByNwCxTT.js (Deleted) -15.65kB 0 bytes -100.0% 🗑️
assets/playground-panel-DQvdoyhH.js (Deleted) -14.42kB 0 bytes -100.0% 🗑️
assets/fairness-CiOSbw1j.js (Deleted) -13.98kB 0 bytes -100.0% 🗑️
assets/app.audit-BLtUZK61.js (Deleted) -10.08kB 0 bytes -100.0% 🗑️
assets/app.config-generator-Dkj-Fdqj.js (Deleted) -10.06kB 0 bytes -100.0% 🗑️
assets/maintainers-B5c8-N2u.js (Deleted) -8.06kB 0 bytes -100.0% 🗑️
assets/miners-DxpFAEdu.js (Deleted) -7.91kB 0 bytes -100.0% 🗑️
assets/agents-D0sAA8dq.js (Deleted) -7.74kB 0 bytes -100.0% 🗑️
assets/commands-panel-DXTywvl0.js (Deleted) -6.65kB 0 bytes -100.0% 🗑️
assets/maintainer-workflow-DLXdxUFh.js (Deleted) -6.52kB 0 bytes -100.0% 🗑️
assets/digest-panel-BlxCQQ-Y.js (Deleted) -6.15kB 0 bytes -100.0% 🗑️
assets/repos._owner._repo.quality-B6PCkl0x.js (Deleted) -6.14kB 0 bytes -100.0% 🗑️
assets/docs-nav-veZZBCqK.js (Deleted) -6.06kB 0 bytes -100.0% 🗑️
assets/docs.index-CKomTPRc.js (Deleted) -5.95kB 0 bytes -100.0% 🗑️
assets/api.index-D5ySVhru.js (Deleted) -4.7kB 0 bytes -100.0% 🗑️
assets/docs-BdgnX8f0.js (Deleted) -2.7kB 0 bytes -100.0% 🗑️
assets/api-F2UNdst7.js (Deleted) -2.69kB 0 bytes -100.0% 🗑️
assets/docs-page-DsYuR1Ec.js (Deleted) -2.1kB 0 bytes -100.0% 🗑️
assets/table-I9tUVJzn.js (Deleted) -1.75kB 0 bytes -100.0% 🗑️
assets/app.workbench-COLhsxik.js (Deleted) -1.58kB 0 bytes -100.0% 🗑️
assets/tabs--wPrV0Ox.js (Deleted) -1.39kB 0 bytes -100.0% 🗑️
assets/app.repos-a7SBzs_Y.js (Deleted) -1.07kB 0 bytes -100.0% 🗑️
assets/input-Uqq3scxC.js (Deleted) -796 bytes 0 bytes -100.0% 🗑️
assets/file-cog-BcS3-8TV.js (Deleted) -758 bytes 0 bytes -100.0% 🗑️
assets/app.maintainer-DeFc7tub.js (Deleted) -502 bytes 0 bytes -100.0% 🗑️
assets/app.owner-BceMghTw.js (Deleted) -474 bytes 0 bytes -100.0% 🗑️
assets/app.commands-BZQMzxt1.js (Deleted) -455 bytes 0 bytes -100.0% 🗑️
assets/app.playground-C_LUQG4s.js (Deleted) -442 bytes 0 bytes -100.0% 🗑️
assets/index-BjG-0hlM.js (Deleted) -438 bytes 0 bytes -100.0% 🗑️
assets/app.digest-JTU_XlPK.js (Deleted) -430 bytes 0 bytes -100.0% 🗑️
assets/eye-off-BF5SLAnn.js (Deleted) -430 bytes 0 bytes -100.0% 🗑️
assets/app.miner-B88ZR198.js (Deleted) -422 bytes 0 bytes -100.0% 🗑️
assets/key-round-BG2t_IuU.js (Deleted) -355 bytes 0 bytes -100.0% 🗑️
assets/bot-D8A9EGXC.js (Deleted) -328 bytes 0 bytes -100.0% 🗑️
assets/trash-2-BoZeJOf7.js (Deleted) -328 bytes 0 bytes -100.0% 🗑️
assets/save-Duj5j6Dz.js (Deleted) -327 bytes 0 bytes -100.0% 🗑️
assets/git-pull-request-arrow-DfD6igTw.js (Deleted) -321 bytes 0 bytes -100.0% 🗑️
assets/list-checks-N4Y9b-4t.js (Deleted) -279 bytes 0 bytes -100.0% 🗑️
assets/compass-GAj65P6G.js (Deleted) -251 bytes 0 bytes -100.0% 🗑️
assets/history-DJmJf-uR.js (Deleted) -237 bytes 0 bytes -100.0% 🗑️
assets/message-square-Cug6NkZI.js (Deleted) -233 bytes 0 bytes -100.0% 🗑️
assets/lock-Cj2FTxRR.js (Deleted) -206 bytes 0 bytes -100.0% 🗑️
assets/rotate-cw-BOdwOfgz.js (Deleted) -201 bytes 0 bytes -100.0% 🗑️
assets/play-ChadOJzq.js (Deleted) -190 bytes 0 bytes -100.0% 🗑️
assets/circle-check-CxpRf-Tg.js (Deleted) -178 bytes 0 bytes -100.0% 🗑️
assets/search-CKy_ZjiZ.js (Deleted) -174 bytes 0 bytes -100.0% 🗑️

@loopover-orb loopover-orb Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LoopOver approves — the gate is satisfied and CI is green.

@loopover-orb
loopover-orb Bot merged commit 8e2d51d into main Jul 29, 2026
10 checks passed
@loopover-orb
loopover-orb Bot deleted the chore/ui-cleanups-9588 branch July 29, 2026 17:36
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.

ui: fix the 24 files flagged by react-hooks 7's compiler-era rules, then restore them to error

1 participant