Uh oh!
There was an error while loading. Please reload this page.
feat(app-shell): add /:objectName/data parameterized bare data surface (#2251) - #2255
Merged
Merged
Conversation
#2251) Add a URL-addressable data surface that is NOT anchored to any saved view: /apps/:app/:objectName/data renders everything row-level permissions allow, with URL conditions (filter[<field>]=<value>) applied on top and rendered as visible, removable chips. The existing /:objectName (workspace, default view) and /view/:viewId routes are untouched — this is purely additive. - ObjectDataPage (new, modeled on InterfaceListPage / ADR-0047 filters mode): no saved-view tab bar, no write-back to saved views, auto-derived columns and userFilters bar trimmed by field-level permissions, uf_* URL persistence, ListView-internal visualization switcher so switching presentation preserves URL filter state, read-permission route gate (403 empty state), record drawer via ?recordId, and an admin "Save as view" exit that materializes the current conditions as a named view and navigates to /view/:id - NavigationItem.filters (types + zod): object nav items can target the surface declaratively; resolveHref serializes them to /data?filter[...] with {current_user_id}/{current_org_id} template substitution; precedence recordId -> filters -> viewName; covered by new resolveHref unit tests (12 cases) - i18n: console.objectData.* keys (en, zh) - docs: app-composition guide (skills + content/docs) gains the /data rule — URL filters for one-off/parameterized slices, named views for curated ones Client-side field trims are UX only; the server remains the enforcement point for row-level filters and predicates on unreadable fields (#2251 security model). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018m3GX7EMKNPDZuee152EKK
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
- docs/adr/0055-parameterized-bare-data-surface.md: decision record for the third list context (amends ADR-0053's two-mode table) — surface contract, security model, rejected alternatives, follow-ups - ADR-0053: add 'Amended by ADR-0055' header note - content/docs/guide/console-architecture.md: add the /data row to the console route table - app-composition guide: link the ADR from the Related section - ObjectDataPage / AppContent comments now cite ADR-0055 (stable ref) instead of only the issue number Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018m3GX7EMKNPDZuee152EKK
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
os-zhuang
marked this pull request as ready for review
July 5, 2026 06:34
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Jul 5, 2026
os-zhuang added a commit
that referenced
this pull request
Jul 5, 2026
…-up) (#2265) Positive-path eval for the /data bare surface: dashboard drill-through and an 'assigned to me' shareable link must be expressed as object nav items with filters ({current_user_id} templating) rather than authored views or pages. Completes the discovery chain shipped in #2255 / framework#2626 (spec describe -> skill rules -> prompt one-liner -> eval regression guard). Claude-Session: https://claude.ai/code/session_018m3GX7EMKNPDZuee152EKK Co-authored-by: Claude <noreply@anthropic.com>
os-zhuang added a commit
that referenced
this pull request
Jul 5, 2026
…deep-links (#2272) and AppNavInspector four-landing-mode rework (#2245) (#2273) * feat(layout): resolveActiveNavItem — single-winner inverse of resolveHref (#2272) The whole nav tree now elects exactly ONE active item per location: resolveActiveNavItem parses the URL into a typed target and ranks matches by specificity (record deep-link > filters slice > named view > exact > object sub-route weak claim > boundary prefix), ties breaking to tree order. NavigationRenderer computes the winner once and provides it via context; per-item active state and group auto-expansion are id comparisons. The old per-item computeIsActive prefix heuristics (and its accreted special cases) are deleted. Fixes the #2255 gap where a filters item never highlighted (its href carries ?filter[...] which pathname matching can't see) while the bare object sibling wrongly claimed /data. Behavior improvements: bare object items weak-claim /view/* and /data when no more-specific sibling is registered (orientation is kept instead of nothing highlighting), and view matching tolerates qualified <object>.<key> ids. resolveHref <-> resolveActiveNavItem are round-trip tested for every leaf shape (11 new cases). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018m3GX7EMKNPDZuee152EKK * feat(app-shell): nav-id designer deep-links + edit-navigation affordance (#2272) The designer's selected menu is now URL-addressable by the nav item's spec-required snake_case id (?sel=nav:<id>) instead of being an in-memory positional state: - nav-selection.ts: id <-> positional-path translation at the designer boundary (positions never leave component state; ids survive reorder) - ResourceEditPage (metadata-admin app editor): applies ?sel=nav:<id> on load (implies edit mode), mirrors nav selections back to the URL (replace, ADR-0047 convention) so the selection is shareable and reload-safe - StudioDesignSurface (Interfaces pillar): same wiring for navSel - AppSidebar: new 'Edit Navigation' app-switcher item that resolves the CURRENTLY ACTIVE menu via resolveActiveNavItem (the resolveHref inverse) and deep-links to /metadata/app/:name?sel=nav:<id> — runtime -> designer jumps land on the menu you were looking at - i18n: layout.appSwitcher.editNavigation (en, zh) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018m3GX7EMKNPDZuee152EKK * feat(app-shell): AppNavInspector type + four-landing-mode target editing (#2245) Replace the off-spec path/kind free-text editing (runtime never read either key) with contract-first target editing: - type selector over the spec union (object/page/dashboard/report/url/ group); page/dashboard/report targets are metadata-backed comboboxes (client.list), url is free text + target select - object items expose the FOUR landing modes matching resolveHref precedence (ADR-0055): default view / named view (picker scoped to the object's <object>.<key> views) / record deep-link (template-var hint + view|edit mode) / filters slice (key-value editor with field picker per field-level readability) - the mode is DERIVED from field presence, never persisted; switching type or mode clears the other targets plus every legacy key (path/kind/href/route/object/page/...), so editing a legacy item IS its migration — a stale recordId can no longer hijack precedence - every write ensures a snake_case id (ensureNavId, uniqued against siblings) and an explicit type - live 'Resolved link' preview renders the REAL runtime landing via resolveHref with template vars kept visible — declared = enforced, observable while editing - pure logic extracted to nav-target.ts with 12 unit tests - AppNavCanvas.addItem now creates {id, type:'object', label} instead of the save-invalid {label, path:''} placeholder; AppPreview's empty fallback root key is 'navigation' (the only spec'd write target), not 'nav' - i18n: engine.inspector.appNav.* reworked (en, zh); dead path/kind keys removed Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018m3GX7EMKNPDZuee152EKK --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the objectui half of #2251 — the three-route model, purely additive:
/:objectName/:objectName/view/:viewId/:objectName/data±filter[...]/uf_*What
ObjectDataPage(new, modeled onInterfaceListPage/ ADR-0047 filters mode rather than carved out of the 1.9k-lineObjectView— zero regression surface on existing routes):filter[<field>]=<value>conditions apply over everything row-level security permits — no saved-view filter is baked in; conditions render as visible, removable chips (deliberately unlike Odoo's invisible action domain)CreateViewDialog+createRuntimeMetadataand navigates to the new/view/:viewId— the one exit into the workspaceuserFiltersbar (ADR-0047uf_*URL persistence, same wiring asInterfaceListPage)data-testid="object-data-403"); auto-derived columns, filter-bar fields, and URL predicates are trimmed to readable fields viauseFieldPermissions— client-side trims are UX only, the server remains the enforcement point?recordId(shareable, refresh-safe — same convention as ObjectView)NavigationItem.filters?: Record<string, string>(types + zod, mirrorsrecordIddocs);resolveHrefserializes object items withfiltersto/data?filter[...]with{current_user_id}/{current_org_id}template substitution and precedencerecordId → filters → viewName. Items withoutfiltersproduce byte-identical output.:objectName/dataregistered inAppContent.tsx(lazy,datajoinsnew/view/recordas reserved segments).console.objectData.*(en, zh; other locales fall back todefaultValue).filtersfor one-off/parameterized slices, named views for curated ones; one-sentence generation rule updated.Verification
pnpm turbo run buildfor types/layout/app-shell (+ deps): 29/29 pass (tsc typecheck included)resolveHref.test.tscovers 12 cases (bare/viewName/filters/empty-filters/precedence/template substitution/dropped unresolved entries/non-object targets)NavigationRendererstatic-componentserrors reproduce without this diff — verified via stash)vite dev): app boots with the new lazy chunk registered, zero page errors. Driving the/dataroute with real data isn't possible in this environment (console requires an ObjectStack backend + auth — the same constraint that keeps the repo's deeper e2e specs.skipped), so runtime acceptance on seeded data still needs a manual pass.Out of scope (tracked in #2251)
@objectstack/specsync forfilters(framework repo) — local@object-ui/typesmirrors it here, flagged for spec alignment before publishfilter[field][gte]=...)Closes nothing on its own; primary implementation PR for #2251.
🤖 Generated with Claude Code
https://claude.ai/code/session_018m3GX7EMKNPDZuee152EKK
Generated by Claude Code