fix: empty view name 405 + draft views not appearing in view switcher#2754
fix: empty view name 405 + draft views not appearing in view switcher#2754akarma-synetal wants to merge 4 commits into
Conversation
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>
|
@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
left a comment
There was a problem hiding this comment.
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
…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>
…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>
|
Superseded by #2768, which is now merged into 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 Verified end-to-end in a real browser against the showcase backend (empty-name 405 gone, Closing in favor of #2768. Thanks for the original diagnosis and fix — it framed the problem well. Generated by Claude Code |
Summary
Fixes two issues when creating views via the "Add View" dialog in the record list page:
405 Method Not Allowed — when the dialog produced an empty view name, the client sent
PUT /api/v1/meta/view/(no:namesegment), which the server rejects.Draft views not appearing in view switcher —
listViews()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()andcreateRuntimeMetadata()throws a clear error instead of hitting the server with a malformed URL.2. Producer fix — fallback name +
objectstamp (ObjectView.tsx)showcase_task_grid_mrsyt56j).objectanddata.objecton the create spec so the view passes thelistViews()object-name filter.3. Reader fix — fetch draft views (
index.ts)listViews()now fetches draft views viaGET /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
listViews.test.ts(4/4),metadata-client.test.ts(20/20),runtime-metadata-persistence.test.ts(15/15)Made with Cursor