📌 Description
Both register() and deregister() in AnchorsPanel (src/components/AnchorsPanel.tsx) call reload() from useAsync after a successful mutation. reload() immediately sets state to { status: "loading" }, which swaps the entire anchors Card body — the status filter buttons, search box, and table — for a bare TableSkeleton until the re-fetch resolves, then re-renders everything from scratch. Every registration or deactivation therefore causes the whole anchors list to flash out and back in, discarding the user's scroll position within the table and any visible sort indicator state momentarily, purely to reflect what is usually a single added/changed row. useAsync's refresh() exists precisely to re-fetch without this disruption and is already the established pattern this codebase uses elsewhere for exactly this kind of "silently pick up the latest data" need.
🧩 Requirements and context
- After a successful
register() or deregister(), the anchors list should update without dropping back to a full loading-skeleton state.
- The status filter, search box, and sort state must remain visible and unaffected throughout the update.
- The existing toast notifications and the
pending state used to disable the register form while submitting must be unchanged.
🛠️ Suggested execution
- In
src/components/AnchorsPanel.tsx, destructure refresh from useAsync(load) alongside (or instead of) reload, and call await refresh() in both register() and deregister() instead of reload().
- Extend
src/components/AnchorsPanel.test.tsx with a test that registers a new anchor and asserts the filter buttons/search box/table remain rendered throughout (no interim TableSkeleton), unlike a reload()-driven flash.
✅ Acceptance criteria
🔒 Security notes
No new attack surface; a client-side UX consistency fix reusing an already-authenticated read endpoint.
📋 Guidelines
- Minimum 95% test coverage
- Clear documentation
- Timeframe: 96 hours
📌 Description
Both
register()andderegister()inAnchorsPanel(src/components/AnchorsPanel.tsx) callreload()fromuseAsyncafter a successful mutation.reload()immediately sets state to{ status: "loading" }, which swaps the entire anchorsCardbody — the status filter buttons, search box, and table — for a bareTableSkeletonuntil the re-fetch resolves, then re-renders everything from scratch. Every registration or deactivation therefore causes the whole anchors list to flash out and back in, discarding the user's scroll position within the table and any visible sort indicator state momentarily, purely to reflect what is usually a single added/changed row.useAsync'srefresh()exists precisely to re-fetch without this disruption and is already the established pattern this codebase uses elsewhere for exactly this kind of "silently pick up the latest data" need.🧩 Requirements and context
register()orderegister(), the anchors list should update without dropping back to a full loading-skeleton state.pendingstate used to disable the register form while submitting must be unchanged.🛠️ Suggested execution
src/components/AnchorsPanel.tsx, destructurerefreshfromuseAsync(load)alongside (or instead of)reload, and callawait refresh()in bothregister()andderegister()instead ofreload().src/components/AnchorsPanel.test.tsxwith a test that registers a new anchor and asserts the filter buttons/search box/table remain rendered throughout (no interimTableSkeleton), unlike areload()-driven flash.✅ Acceptance criteria
🔒 Security notes
No new attack surface; a client-side UX consistency fix reusing an already-authenticated read endpoint.
📋 Guidelines