Skip to content
This repository was archived by the owner on Nov 4, 2026. It is now read-only.
This repository was archived by the owner on Nov 4, 2026. It is now read-only.

Studio Data pillar ignores its renderListView slot's refreshKey — the prop was forwarded to a component that never declared it #4549

Closed

Description

@yinlianghui

Surfaced by the repo-wide type-check canary in #4528 (PR pending), which is the first thing ever to check ListView's call sites. Filed rather than fixed there: #4528 is a type-only card and wiring this is a behaviour change.

What was measured

packages/app-shell/src/views/studio-design/StudioDesignSurface.tsx renders the Data pillar's grid through the plugin ObjectView's renderListView slot. That slot supplies a refreshKey (declared at packages/plugin-view/src/ObjectView.tsx:207), and renderStudioGridList forwarded it straight on:

<ListView
  schema={...}
  dataSource={ds as never}
  onEdit={onEdit}
  onAddRecord={onAddRecord}
  className={className}
  refreshKey={refreshKey}
/>

refreshKey is not a prop of ListView, and it is not a prop of anything ListView renders. ListView keeps its own refreshKey local state (ListView.tsx:831) and drives refetching off schema.refreshTrigger plus that state; ObjectGrid likewise keeps its own local refreshKey state and declares no such prop. The incoming value rode ListView's {...props} forward into SchemaRenderer and was dropped.

Grepping the whole repo for refreshKey?: as a prop declaration returns plugin-view/ObjectView.tsx (the slot contract), StudioDesignSurface itself, and four unrelated components — no view component in the forward chain.

It type-checked only because ListViewProps carried a [key: string]: any that erased the whole interface (#4528), so no ListView call site was checked at all.

Why it was invisible

Bumping the prop still re-renders ListView (new prop object), and the Studio grid re-renders constantly anyway because its schema is a fresh object literal on every render. So "the list looks like it updates" — it just never refetches because of refreshKey.

The working precedent, 300 lines away

packages/app-shell/src/views/ObjectView.tsx:1592 consumes the same slot value correctly — it folds it into React's key so the subtree remounts:

const combinedRefreshKey = refreshKey + (pluginRefreshKey || 0);
const key = `${objectName}-${activeView.id}-${combinedRefreshKey}`;

Current state

#4528's PR removes the dead prop (behaviour-preserving) and leaves a comment at the declaration pointing here. So today the Studio Data pillar has no refreshKey path at all, which is what it effectively had before — the difference is that it is now visible.

Worth deciding

Whether the Studio Data pillar needs the slot refresh at all. If it does, the key fold above is the established shape. If it does not, the slot prop can be dropped from renderStudioGridList's signature entirely. Someone who knows what user action is meant to trigger it (record create / delete / publish?) should judge, since "remount the grid" also discards scroll position, selection and in-progress inline edits — AGENTS.md #8's "refresh data, don't rebuild UI" argues against the key fold as the long-term answer even though it is what the sibling does.

Refs #4528, #1126.


Generated by Claude Code

Activity

  1. self-assigned this
    on Aug 13, 2026
  2. yinlianghui commented on Aug 13, 2026

    @yinlianghui
    ContributorAuthor

    CLAIM — session_017Qqyix2QcnpUC9XeYVDzx3, branch claude/issue-4549-studio-grid-refresh. Dispatching a dev agent now (#4548's canary measured app-shell clean under the ruled option B, so StudioDesignSurface is safe to take).

    PM ruling (delegated decision authority; maintainer veto window open — record objections here): measure-first with a preference order, honoring AGENTS.md #8 ("refresh data, don't rebuild UI"):

    1. First measure whether the slot value ever bumps in the Studio mount — what increments plugin-view ObjectView's refreshKey (~:207), and whether any of those triggers fire on the Studio Data pillar path. If the slot value provably never changes there, the fix is deletion: drop the dead parameter from renderStudioGridList's signature and close the card as dead code — say so with the measurement.
    2. If it does bump: prefer ListView's existing declarative refresh input — measure schema.refreshTrigger's semantics (does a CHANGED value refetch?); if yes, pass the slot refreshKey through it. Zero new API, no remount, scroll/selection/in-progress edits survive.
    3. Else: ListViewHandle — measure whether the imperative handle already exposes a refresh; drive it from an effect on the slot value.
    4. Key-fold is last resort only (the sibling's shape), with the UX cost (scroll/selection/edit loss) declared — and if reached, say why 1 and 2 measured unavailable.
      If a real refresh channel is measured MISSING from ListView entirely (1 and 2 both unavailable), adding one is a plugin-list API change — STOP and report rather than inventing it under this card.

    Red-first: bump the slot value → the grid refetches (find called again with the same params); pre-fix nothing refetches because of it. Pins: no bump ⇒ no extra fetch; the #4528-removed dead prop stays removed; Studio Data pillar's other behaviors (including the #4558 panel gating) untouched.

    Changeset: '@object-ui/app-shell' patch expected (module-local wiring); plugin-list only if a measured channel edit is unavoidable (then STOP first). Never major.

    Mutual exclusion: ⛔ #4548 in flight (packages/react + consumer fixes in plugin-dashboard/plugin-report — ZERO app-shell edits per its ruling); #4305 (app-shell FLOW files — disjoint from studio-design); #4564 (types/data-objectstack); #4553-p2 (fields/gantt). StudioDesignSurface's #4558-landed panel/inspector wiring is landed context — do not disturb it.


    Generated by Claude Code


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions