lablup / lablup/backend.ai-webui
Settle the non-blocking loader contract for the session list
- Dominant language
- TypeScript
- Stars
- 133
- Forks
- 81
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 355
Description
## Question
This is the centre of the map. Given the fixed UX ("new page shell immediately + skeleton", so no blocking loader) and what FR-3639 and FR-3637 turned up, decide the exact contract the session list route will use — precisely enough that the prototype has nothing left to invent.
Decide, with the owner:
1. **Shape.** Loader returns a synchronously-created `PreloadedQuery`, page reads it via `useQueryLoader(Query, loaderRef)` + `usePreloadedQuery`? Or a different shape (EntryPoint, a module-level prefetch triggered from the nav link, hover-intent warming via `useFetcher().load()`)?
1. **Who owns refetch.** The page refetches on filter, pagination, sort, type-tab, `fetchKey` poll and manual refresh. Does the loader own only the first fetch and hand over, or does loader revalidation own some of these? nuqs runs `shallow: false` with `history: 'replace'`, so every filter change is a navigation — say explicitly whether the loader re-runs and how a double-fetch is prevented.
1. **Disposal.** Who calls `dispose()` on the loader-created ref, and when. Name the mechanism, not the intention.
1. **Fetch policy.** What replaces the current `store-and-network` → `network-only` switch.
1. **Failure.** What happens when the loader cannot build valid variables, and what renders when the preloaded query errors.
1. **How far the contract reaches.** Only the top-level page query, or also the five sibling count fields and the inner Suspense boundaries?
**Deliverable**: the contract written out as a short spec — a code sketch of the route entry plus the page's hook wiring, and a numbered list of rules a reviewer could check the prototype against.
Map: FR-3636.
----
## Amendment (2026-08-23, after FR-3638 and FR-3639 resolved)
Research settled more than expected and also moved one fork this ticket did not have. Read FR-3639's findings and its resolution addendum (GitHub #8985) before starting — the recommended shape, the C1–C7 conditions, and a 15-item reviewer checklist are already written there. What remains:
**Settled, do not re-decide.**
- The router version: **6.30.4**. v7 is irrelevant to this goal (FR-3638) and out of the map's scope.
- The bridge: `useQueryLoader(query, refFromLoader)` **adopts** the loader's ref, re-adopts a changed one on every navigation (identity-inequality check in the render body), and releases superseded refs plus everything on unmount. Verified in the compiled runtime and test-covered at v20.1.1. A bare `usePreloadedQuery(query, useLoaderData())` leaks a permanent `_roots` entry per distinct variables tuple, for the session.
- EntryPoints: no-go. `@preloadable` panics the installed compiler without `persistConfig`, and no `JSResource` implementation ships.
- The loader can build its variables synchronously: `globalThis.backendaiclient.groupIds` is a login-time name→UUID map (`react/src/helper/loginSessionAuth.ts:131-137`).
**New fork this ticket now owns —** `v7_partialHydration`. FR-3639's "a loader must never `await` or the whole app blanks" is real for the current config but removable **today on 6.30.4**, with no upgrade. The gate, verified in the installed dist (`react/node_modules/react-router-dom/dist/index.js:590`), is `state.initialized || router.future.v7_partialHydration ? : fallbackElement`. Decide:
- Keep the flag off and hold C1 absolutely (loader is a plain sync function, forever, enforced by review or lint), or
- Turn on `future: { v7_partialHydration: true `} and give the pilot route a `HydrateFallback`, which converts whole-app-blank into page-level skeleton and makes an awaiting loader viable. Note `App.tsx:21` passes no options object at all today, so this is a real change to how the router is constructed, and with the flag on and no `HydrateFallback` anywhere the render falls to `null` — still blank. Sequence against FR-3638's PR A, which proposed turning all six `v7_*` flags on and would change this landscape underneath the pilot.
**Fork #5 is answered — negatively.** FR-3639 framed `v7_startTransition: true` as an upside; FR-3638 measured it as a **regression** on project switching (v6 shows the skeleton, v7 holds stale content) and derived a worse cold-suspension failure mode from React 19.2.8's `shellBoundary` gating. Drop it from the option set unless that measurement is overturned.
**The question this ticket must not dodge.** FR-3639's own verdict is that as a _latency_ optimization the shape does not pay for itself on the warm path — one React render pass, zero frames — and that the honest case for it is architectural. FR-3637 will say whether the cold path changes that. If it does not, this ticket's real output may be "do not do this", and that is a legitimate resolution. Decide the contract _and_ whether it is worth having.
**Residual to decide:** `backendaiclient.groupIds` is built from `group.list(true, false, …)` and `useAccessibleProjects.tsx:34-38` says the login-time list omits MODEL_STORE projects. An `if (!projectId) return null` guard makes a miss safe (page owns the fetch) rather than wrong — decide whether a silent fallback there is acceptable or whether the miss should be loud.
JIRA Issue: FR-3640
Contributor guide
No contributing guide indexed for this repository
Research direction
Read FR-3639 and its resolution addendum (#8985), then inspect App.tsx:21 and the router construction before tracing the session-list route's useQueryLoader wiring. Done means a reviewed short spec and route/page code sketch that settles refetch, disposal, failure handling, the groupIds miss, and the v7_partialHydration decision without leaving the prototype to invent behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- frontend
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100