Skip to content

fix: empty view name 405 + draft views not appearing in view switcher#2754

Closed
akarma-synetal wants to merge 4 commits into
objectstack-ai:mainfrom
akarma-synetal:fix/view-create-empty-name
Closed

fix: empty view name 405 + draft views not appearing in view switcher#2754
akarma-synetal wants to merge 4 commits into
objectstack-ai:mainfrom
akarma-synetal:fix/view-create-empty-name

Conversation

@akarma-synetal

Copy link
Copy Markdown
Contributor

Summary

Fixes two issues when creating views via the "Add View" dialog in the record list page:

  1. 405 Method Not Allowed — when the dialog produced an empty view name, the client sent PUT /api/v1/meta/view/ (no :name segment), which the server rejects.

  2. Draft views not appearing in view switcherlistViews() only fetched published views. Runtime-created draft views were invisible until the user explicitly published them, leaving no way to verify a newly created view.

Changes

1. Empty name guards (metadata-client.ts, runtime-metadata-persistence.ts)

Early-exit validation in MetadataClient.save() and createRuntimeMetadata() throws a clear error instead of hitting the server with a malformed URL.

2. Producer fix — fallback name + object stamp (ObjectView.tsx)

  • When the dialog supplies no name, generate a unique fallback (e.g. showcase_task_grid_mrsyt56j).
  • Stamp object and data.object on the create spec so the view passes the listViews() object-name filter.

3. Reader fix — fetch draft views (index.ts)

listViews() now fetches draft views via GET /api/v1/meta/view?preview=draft, filters items tagged _draft === true, and merges them into the view list. Users can now verify views immediately after creation, then publish when ready.

Test plan

  • Existing tests pass: listViews.test.ts (4/4), metadata-client.test.ts (20/20), runtime-metadata-persistence.test.ts (15/15)
  • Verify: open a record list page → "Add View" → new view appears in tab bar as draft → verify columns/type → Publish

Made with Cursor

akarma-synetal and others added 3 commits July 20, 2026 15:25
PUT /meta/:type/:name requires a non-empty :name segment. When handleViewCreate
produced an empty draftName (all of config.name, config.id, and spec.id
undefined), the client sent PUT /api/v1/meta/view/ which returned 405 Method
Not Allowed.

Add early-exit guards in MetadataClient.save() and createRuntimeMetadata() so
the error is surfaced clearly instead of hitting the server with a malformed
URL.

Co-authored-by: Cursor <cursoragent@cursor.com>
Two issues in handleViewCreate when creating views via the "Add View" dialog:

1. Name: when the dialog supplies no name, generate a unique fallback
   (e.g. "showcase_task_grid_mrsyt56j") instead of sending an empty :name
   to PUT /meta/view/ — the server rejects that with 405.

2. Object: runtime-created views saved via createRuntimeMetadata had no
   `object` or `data.object` field, so listViews() filtered them out
   (obj !== objectName). Stamp `object: objectName` and
   `data: { provider: "object", object: objectName }` on the spec before
   saving, matching what dataSource.createView() already does.

This follows AGENTS.md rule #0.1 — fix the metadata at the producer, not
by adding lenient fallbacks in the renderer.

Co-authored-by: Cursor <cursoragent@cursor.com>
…before publish

listViews() only fetched active (published) views via getItems('view').
Runtime-created draft views were invisible in the view switcher until the user
explicitly published them — there was no way to verify a newly created view.

Fix: fetch draft views via GET /api/v1/meta/view?preview=draft in parallel,
filter for items tagged _draft === true, and merge them into the view list.
This lets users see and verify their views immediately after creation, then
publish when ready.

Co-authored-by: Cursor <cursoragent@cursor.com>
@vercel

vercel Bot commented Jul 20, 2026

Copy link
Copy Markdown

@akarma-synetal is attempting to deploy a commit to the Object Stack Team on Vercel.

A member of the Team first needs to authorize it.

@os-zhuang os-zhuang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this — the 405 fix is solid, but one of the three changes needs rework before merge. Splitting the assessment by change:

① Empty-name 405 guards (metadata-client.ts, runtime-metadata-persistence.ts) — 👍 good, keep.
Rejecting an empty :name before it hits PUT /meta/view/ is the right defensive fix, and doing it at both seams is fine.

object / data.object stamp + fallback name (ObjectView.tsx) — 👍 mostly good.
The object stamp is actually a necessary correctness fix: listViews() filters on data.object === objectName, so without it a created view wouldn't match the filter even after publishing. One suggestion: prefer making the "Add View" dialog require a name over auto-generating showcase_task_grid_mrsyt56j-style names — the fallback is a fine safety net but an auto name is a poor default identifier for a user-facing view.

listViews() fetching ?preview=draft and merging drafts into the switcher — 🔴 please rework (see inline comment).
This one conflicts with the draft/publish model documented in ADR-0033 / ADR-0037. Showing drafts unconditionally in the runtime switcher (a) bypasses the publish gate that's meant to be the only commit point, (b) leaks a globally-stored draft to every viewer of the object with no builder/admin gate — a risk ADR-0037 explicitly flags — and (c) reimplements a raw fetch instead of the existing, purpose-built MetadataClient.withPreviewDrafts() / PreviewModeContext path that already gates draft reads to preview mode.

The underlying need — verify a view before publishing — is legitimate and already solved by the builder-gated Live Canvas (?preview=draft, ADR-0037). The fix should make the draft merge conditional on preview mode rather than always-on.

Recommendation: land ① and ② (they stand on their own), and either drop ③ or rework it to honor previewDrafts/preview mode.


Generated by Claude Code

Comment thread packages/data-objectstack/src/index.ts Outdated
…anonical ViewItem shape

- Draft fetch: gate on options?.previewDrafts (ADR-0037), threaded through
  usePreviewDrafts() context — normal runtime sees only published views.
- Name: use config.label + slugify() instead of random fallback, matching
  what the user typed. Fallback still present as defense-in-depth.
- Body: send canonical ViewItem shape ({ name, object, viewKind, config })
  with provider: "object" in data, matching ViewItemSchema / ADR-0017.
- Object stamp: preserve existing config.data via spread.
- ObjectDataPage.tsx: same fixes for the "Save as view" path.
- listViews type: add options?: { previewDrafts?: boolean }.

Co-authored-by: Cursor <cursoragent@cursor.com>
os-zhuang added a commit that referenced this pull request Jul 21, 2026
…fts, canonical naming (#2768)

Rebuilds the record-list "Add View" / "Save as view" create path so a
runtime-created view has one canonical identity and is verifiable before
publish. Supersedes #2754; fixes #2767.

P1 — unified identity. New `viewEnvelope(objectName, spec, { name, label })`
seam emits the canonical ViewItem `{ name: '<object>.<key>', object,
viewKind: 'list', label, config }` (config.data stamped), mirroring the Studio
`anchors.ts:createBuildBody`. The qualified name is used as BOTH the
`PUT /meta/view/:name` URL segment and `body.name`, so the sys_metadata row
key, the ViewTabBar tab id, and the body identity agree and the draft → read →
publish loop resolves. `ObjectView` and `ObjectDataPage` share the one helper.

Empty-name 405. `MetadataClient.save()` and `createRuntimeMetadata()` throw a
clear error instead of emitting `PUT /meta/view/` (empty :name).

P2/P3/P4 — draft visibility. `listViews(objectName, { previewDrafts })`: in
preview mode the adapter makes a single `MetadataClient.withPreviewDrafts(true)
.list('view')` request and uses the server's already-overlaid list (draft wins
by name, `_draft` tagged) — replacing, not appending, so a draft that edits a
published view can't double-tab. No hand-rolled metadata fetch at the adapter.
After a create in normal mode the console navigates to the new view with
`?preview=draft` so the DraftPreviewBar is visible and Publish is one click.

P5 — CJK naming. `CreateViewDialog` gains an editable machine-name field,
prefilled via slugify(label) and required (submit disabled) when slugify is
empty for non-Latin labels — no silent random names. New i18n keys (en/zh).

Tests: viewEnvelope/deriveViewKey, empty-name guards, and the listViews
preview branch (single request, no dupe, _draft passthrough). Docs updated.


Claude-Session: https://claude.ai/code/session_01Y2ZKbzgbsYndkWYojr1NTc

Co-authored-by: Claude <noreply@anthropic.com>

Copy link
Copy Markdown
Contributor

Superseded by #2768, which is now merged into main.

Per the re-implementation spec in #2767, the "Add View" create flow was rebuilt from scratch to address the structural issues this PR left open (P1–P6): unified <object>.<key> identity used as both the row key and body.name (P1), single-request preview=draft overlay via MetadataClient.withPreviewDrafts() that replaces rather than appends (P2/P3), auto-navigation into draft-preview so a new view is verifiable before publish (P4), a CJK-aware editable machine-name field (P5), and a shared viewEnvelope helper removing the duplicated envelope code (P6). It also keeps the two fixes this PR got right — the empty-name guards and draft visibility.

Verified end-to-end in a real browser against the showcase backend (empty-name 405 gone, PUT /meta/view/<object>.<key> → 200, create lands in ?preview=draft with the new tab visible).

Closing in favor of #2768. Thanks for the original diagnosis and fix — it framed the problem well.


Generated by Claude Code

@os-zhuang os-zhuang closed this Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants