Skip to content

"Set as Default" is dead on every saved view — handleSetDefaultView calls updateView unbound, so this.connect() throws before any request is issued #4463

Description

@baozhoutao

Found by a retest of records-forms.saved-view-management (framework QA run objectstack-ai/objectstack#7439) against the console at pin 6314e87f2d49. The fix under retest — #4139 / PR b42558a4c — is verified working; this is a separate, pre-existing defect on the same surface.

Symptom

Clicking Set as Default on any saved view issues zero network requests. The console logs:

[ViewTabBar] Failed to set default view: TypeError: Cannot read properties of undefined (reading 'connect')

and shows a toast "Failed to set default view". The view never gains isDefault, and the prior defaults are untouched. Reproduced 3× — on a draft-addressed view, on a published view, and in a repeat focused run.

Reproduction

  1. As the seeded admin, open /_console/apps/com.example.showcase/showcase_task.
  2. Create any saved view via the + tab (data-testid=view-tab-add) — e.g. a kanban, machine key rt5_board.
  3. Open that tab's actions menu (data-testid=view-tab-actions-showcase_task.rt5_board).
  4. Click Set as Default (data-testid=view-tab-menu-default-showcase_task.rt5_board).

Expected: a PUT /api/v1/meta/view/<name> setting isDefault:true (plus PUTs unsetting the prior default); the view is default after reload.
Actual: no requests at all; the console error above; server state unchanged.

Root cause

packages/app-shell/src/views/ObjectView.tsx — handleSetDefaultView does:

const updateView = (dataSource as any).updateView;
…
updateView(objectName, /* … */);   // called UNBOUND

this is therefore undefined inside the adapter method, whose first statement is await this.connect().

The cleanest confirmation is the sibling: handlePinView calls (dataSource as any).updateView(...) as a method and works — which is exactly why rename and pin pass in the same menu while set-default does not.

handleReorderViews in the same file repeats the identical unbound-call pattern and is presumably broken the same way (not exercised in this run).

Not a regression from #4139

Verified by reading the call site at b42558a4c^ (the commit before the #4139 fix): the same const updateView = (dataSource as any).updateView call was already there, and updateView already began with await this.connect(). This is pre-existing.

Secondary defect on the same surface (lower severity)

deleteView was not taught the draft qualifier that updateView gained in #4139. Deleting a view that exists only as a draft issues DELETE /api/v1/meta/view/<name> against the published overlay and returns 200 {"success":true,"reset":false,"message":"No view '<name>' found — nothing to delete."} — while the draft survives and the tab is still present after reload. Worth closing in the same pass.

What is verified working (so this card is narrowly scoped)

Source

Retest of records-forms.saved-view-management at console pin 6314e87f2d49, framework b602d536. The set-default failure blocks the item's clause 1 and makes its "two views flagged default" negative unexercisable.

Activity

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

    @yinlianghui
    Collaborator

    CLAIM — session session_017Qqyix2QcnpUC9XeYVDzx3, branch claude/issue-4463-setdefault-unbound.

    Ruling: fix as diagnosed. (1) handleSetDefaultView AND handleReorderViews (same unbound pattern, same file) call the adapter method as a method — the working sibling handlePinView is the in-file convention. Red-first: a test reproducing the TypeError: Cannot read properties of undefined (reading 'connect') path pre-fix, asserting the update is issued post-fix. (2) The secondary defect (deleteView never learned #4139's draft qualifier): measure first — if it is the mechanical mirror of #4139's updateView change in the adapter, fix in the same PR with its own red-first (draft-only view delete currently no-ops with reset:false); if it is NOT mechanical, stop on that half and report — it becomes its own card.

    Grading: patch @object-ui/app-shell; if the adapter half lands, patch @object-ui/data-objectstack — both by emitted-.d.ts measurement, never major.

    Surface (mutual exclusion): packages/app-shell/src/views/ObjectView.tsx + its tests; packages/data-objectstack (deleteView draft mirror ONLY, if mechanical); changesets. Disjoint from in-flight #4431 (chatbot/core/fields/ledger), #4472 (console/organizations/manage), #4473 (console landing), #4471 (root configs/e2e).


    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions