Files
roboco/docs/frontend/hooks.md
T
08c02e2251 [79d686f0] Add page-scoped refresh button to the navbar (#351)
* [870467e6] Frontend: page-scoped refresh provider, hook, and navbar button (#347)

* [55376b8a] Create page-scoped refresh provider and context (#327)

* [55376b8a] feat(panel): add page-scoped refresh context and provider

* [55376b8a] docs(frontend): add page-refresh-provider component documentation

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* [a0c02d0f] Add public usePageRefresh hook (#332)

* [a0c02d0f] test(hooks): assert usePageRefresh is exported from hooks barrel

* [a0c02d0f] feat(hooks): add public usePageRefresh hook with provider and tests

* [a0c02d0f] fix(panel): move hook test wrappers to components and rename providers.tsx to unshadow barrel

* [a0c02d0f] docs(panel): document usePageRefresh hook and PageRefreshProvider API

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>

* [5f28dd9b] Add navbar refresh button and remove inline dashboard refresh buttons (#336)

* [5f28dd9b] Align PageRefreshProvider with active hook API and remove inline dashboard refresh buttons

* [5f28dd9b] Remove unused scope-keyed PageRefreshProvider, context, and associated tests

* [5f28dd9b] Address QA revision: add header refresh tests, page-scoped label, remove dead provider code and .venv symlink, revert formatting-only changes

* [5f28dd9b] Remove remaining inline dashboard refresh buttons and committed .venv symlink

* [5f28dd9b] docs(frontend): update page-refresh provider docs and panel README for navbar refresh button

* [5f28dd9b] fix(panel): remove .venv symlink, ignore root .venv entries, and thin task-detail page data fetch into useTaskDetail hook

* [5f28dd9b] Extract GitBrowser data fetching into useGitBrowser hook and add tests; verify .venv cleanup and task-detail thin hook usage

* [5f28dd9b] fix(panel): remove root .venv symlink, restore .gitignore anchored rule, and revert lifecycle.json formatting noise

* Delete .venv

---------

Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>

* [b8e1de1b] Fix navbar refresh button disabled state when registry is empty (#356) (#358)

* [b8e1de1b] fix(panel): derive navbar refresh disabled state from registry, not unused prop

PageRefreshProvider now computes `disabled` from whether any refresh
callback is currently registered (registry size > 0) instead of a
static, never-passed `disabled` prop that left the button permanently
enabled. header.tsx now destructures `disabled` from usePageRefresh()
and disables the button on `disabled || loading`. Updated the tests
that asserted the old always-enabled-by-default behavior and added a
new header test asserting the button is disabled with zero registered
callbacks.

* [b8e1de1b] docs(panel): document PageRefreshProvider disabled state derived from registry

Updated documentation to reflect the refactored PageRefreshProvider behavior: the `disabled` state is now derived from whether any refresh callbacks are currently registered (empty registry = disabled), rather than a static `disabled` prop. Clarified in both panel/README.md and the full component guide that the navbar refresh button disables when no callbacks are registered and when a refresh cycle is in progress. Updated API documentation to remove the now-removed `disabled` prop from PageRefreshProviderProps and updated code examples and test coverage descriptions to reflect the new callback-driven semantics.

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>

* test(panel): mock usePageRefresh in tests predating the provider

Merge-skew: the page-refresh feature makes CommandCenter and the agent
detail page call usePageRefresh; three tests merged from master render
them without the new provider. Mock the hook module, matching the
files' stub-everything style.

---------

Co-authored-by: Frontend Developer 1 <fe-dev-1@roboco.tech>
Co-authored-by: Frontend Documenter <fe-doc@roboco.tech>
Co-authored-by: Frontend Developer 2 <fe-dev-2@roboco.tech>
Co-authored-by: Renn F <rennf93@users.noreply.github.com>
2026-07-09 05:27:14 +02:00

4.5 KiB

Frontend hooks

This page documents the public React hooks available under panel/src/hooks.

usePageRefresh

A page-scoped refresh coordinator. Pages and panels register callbacks that refetch their data; UI chrome calls refresh() and reflects the combined loading/disabled state.

When to use it

Use usePageRefresh when several components on the same page need to refresh together from a single trigger, such as a navbar refresh button. It keeps the refresh lifecycle scoped to the current page and avoids invalidating unrelated data.

Setup

Wrap the page (or root layout) with PageRefreshProvider:

import { PageRefreshProvider } from "@/components/providers";

export default function Layout({ children }: { children: React.ReactNode }) {
  return <PageRefreshProvider>{children}</PageRefreshProvider>;
}

Basic usage

import { useEffect } from "react";
import { usePageRefresh } from "@/hooks";
import { useTasks } from "@/hooks";

export function TasksPanel() {
  const { refetch } = useTasks();
  const { register, unregister } = usePageRefresh();

  useEffect(() => {
    const refresh = () => refetch();
    register(refresh);
    return () => unregister(refresh);
  }, [register, unregister, refetch]);

  return <div>{/* task list */}</div>;
}

Triggering a refresh from UI chrome

import { usePageRefresh } from "@/hooks";

export function RefreshButton() {
  const { refresh, loading, disabled } = usePageRefresh();

  return (
    <button onClick={refresh} disabled={disabled || loading}>
      {loading ? "Refreshing…" : "Refresh"}
    </button>
  );
}

Navbar refresh button

The canonical consumer is panel/src/components/layout/header.tsx. The refresh button is rendered between the connection-status badge and the theme toggle. Its accessible label and tooltip read "Refresh only the current page", and it is disabled with a spinning icon while the registered refresh cycle is running.

Dashboard pages no longer include their own inline "Refresh" buttons. Instead, each page registers its refetch callbacks with usePageRefresh and lets the shared header button drive the refresh. See components/page-refresh-provider.md for the full list of wired pages and the registration pattern.

API reference

PageRefreshProvider

Prop Type Default Description
children React.ReactNode required React tree that can consume the context.
disabled boolean false When true, refresh() is ignored and disabled is exposed as true.

usePageRefresh

Returns a PageRefreshState object:

Property Type Description
disabled boolean Whether refresh actions are currently disabled.
loading boolean Whether a refresh cycle is currently in progress.
register (callback: RefreshCallback) => void Add a callback to invoke on the next refresh.
unregister (callback: RefreshCallback) => void Remove a previously registered callback.
refresh () => Promise<void> Run every registered callback and update loading.

RefreshCallback is () => void | Promise<void>. Synchronous and asynchronous callbacks are both supported.

Behavior

  • usePageRefresh throws if called outside a PageRefreshProvider so consumers fail fast instead of silently missing refreshes.
  • Concurrent calls to refresh() are coalesced: a second call while one is running returns immediately and does not start another cycle.
  • When disabled is true, refresh() is a no-op and callbacks are not invoked.
  • register and unregister are stable across renders and can be used as useEffect dependencies.

Exports

  • usePageRefresh from @/hooks
  • PageRefreshProvider from @/components/providers
  • Types: PageRefreshState, RefreshCallback, PageRefreshProviderProps

Migration notes

  • panel/src/components/providers.tsx was renamed to panel/src/components/app-providers.tsx so that @/components/providers could be used as a barrel export for PageRefreshProvider. Update any direct import of the root providers component from @/components/providers to @/components/app-providers.
  • The earlier scope-keyed provider files (panel/src/components/page-refresh-provider.tsx and panel/src/store/page-refresh-context.ts) were deleted. The current implementation lives in panel/src/components/providers/page-refresh-provider.tsx and is consumed through usePageRefresh from @/hooks.