Repository navigation
Commit 97e7d4e
fix(app-shell,react): lookup links on record pages and custom pages carry the console base path (objectui#12233) (#12239)
Fixes #12233
Clause-②: no
Item 4 of the list card objectui#12211. The parent stays open for its
other items.
## What was wrong
A console can be mounted under a router basename. Hosted HotCRM serves
it at `/_console`. On a record page, a valued lookup renders as a real
anchor through `ReferencedRecordLink` in `@object-ui/fields`, which
takes its href from the host's `RelatedRecordActionsValue.recordHref`.
On the record page that host is `RelatedRecordActionsBridge`, which
`RecordDetailView` mounts around the whole page. Its builder returned
the bare router path `/apps/APP/OBJECT/record/ID?from=…`.
- A plain left click worked. The anchor hands it to `openRecord`, which
calls `navigate`, and `navigate` adds the basename.
- A new tab, a middle-click or a copied link sent the browser to the
bare route on the server, which answers `ENDPOINT_NOT_FOUND`.
## Premise check, on objectui `origin/main` `6eca5b5a7`
- The console's `BrowserRouter basename` comes from the injected base
tag (`resolveBasename` in `apps/console/src/App.tsx`), so a hosted
console's router lives at `/_console`. Confirmed.
- `ReferencedRecordLink` is the only anchor in `@object-ui/fields` that
draws a record link. `LookupCellRenderer` uses it for every valued
lookup. The owner link is a lookup to `sys_user` through the same
renderer, and `UserCellRenderer` draws no link.
- Only the bridge's builder adds the `?from=` trail that the measured
href carries, so the bridge is the producer.
- `RecordDetailView` has two other record-route literals: the favourite
entry and the recent-item entry. Both are router paths, and their
readers use `navigate` and router `Link`s, so they are correct as they
are. This PR leaves `RecordDetailView.tsx` untouched.
- The list page's producer (`listRecordActionsValue` in
`ObjectView.tsx`) already returns a document path, because it derives
from `window.location.pathname`, which includes the basename. The two
producers disagreed. Applying the basename in the consumers would have
doubled it on the list page, so the fix belongs in the producer.
## The fix
Round 2 (head `cc0777aa`) extends round 1 to the second producer of the
same defect, under surface amendment `6123360584` on objectui#12233.
Both hosts that publish `RelatedRecordActionsValue.recordHref` now share
one join. These are the record page's `RelatedRecordActionsBridge` and
the custom page's `pageRecordActionsValue`. The join is
`documentHref(rootHref, routerPath)`, in the internal module
`packages/app-shell/src/views/documentHref.ts`:
- Each host keeps one router-path builder (`recordPath`). `openRecord`
navigates by that router path, as before, and the router adds the
basename.
- `recordHref` returns `documentHref(useHref('/'), path)`: the router's
own root href, which carries the basename, joined to the path. It equals
the href react-router's `Link` renders for that route. A console mounted
at the root keeps the bare href.
- `PageView` reads `useHref('/')` beside its other router hooks and
passes it to `pageRecordActionsValue`, which takes it as a new fourth
argument.
No widget changes. No `/_console` or `BASE_URL` literal is added
anywhere.
## Published contract
- `RelatedRecordActionsValue.recordHref` is a member of a published type
in `@object-ui/react`. Its type is unchanged. Round 2 adds one sentence
to its doc: the value is a document href and carries the host router's
basename, while `openRecord` navigates by the router path. Both
producers now meet that doc.
- `RelatedRecordActionsBridge`, `pageRecordActionsValue` and
`documentHref` are not reachable from the `@object-ui/app-shell` entry.
Its `exports` are `.` and `./styles.css`, and the barrels name none of
the three; `PageView` in the same barrels is the positive control.
- No package entry gains or loses an export, a prop or a type member.
The only signature change is on the internal `pageRecordActionsValue`.
That is the basis for `Clause-②: no`.
- The changeset declares `@object-ui/app-shell` `patch` and
`@object-ui/react` `patch` (doc only).
## Tests
-
`packages/app-shell/src/views/__tests__/RelatedRecordActionsBridge.basenameHref-12233.test.tsx`
(round 1). It mounts the real bridge under a `MemoryRouter`, with the
real `LookupCellRenderer` for the three measured links (account,
contact, and owner on `sys_user`):
- with basename `/_console`, each href equals react-router's `Link` href
and keeps `?from=`;
- a left click routes to the named record with the basename applied
once;
- a no-basename control keeps the bare route.
-
`packages/app-shell/src/views/__tests__/PageView.lookupHrefBasename-12233.test.tsx`
(round 2). It mounts the real `PageView` under a real `MemoryRouter`,
with the real `LookupCellRenderer`. It checks basename `/_console`
against a react-router `Link` oracle and the left-click destination,
with a no-basename control.
- `PageView.recordNavigator-11293.test.tsx` gains a basename case, and
its builder calls pass `'/'` explicitly; no assertion is weakened.
- Four `PageView` tests gain a `useHref` entry returning `'/'` in their
`react-router-dom` factory mock: `PageView.test.tsx`,
`PageView.context-9673`, `PageView.editInStudioNeedsAuthoring-10899` and
`page-kind-writing-end-9718`. Without it they fail; see B2.
Reverse checks, each from a committed fix through `ablation-replace`. In
each, the anchor hit once and the blob changed, and the restore was
proven: the blob equals HEAD and `git diff HEAD` is empty.
- **A1** (at `3a5e7950`): the bridge's href goes back to the bare router
path. Result: `Tests 2 failed | 1 passed (3)`, `expected
'/apps/hotcrm/crm_account/record/A-1' to be
'/_console/apps/hotcrm/crm_account/record/A-1'`.
- **A2** (at `3a5e7950`): the naive fix, where a left click navigates
with the prefixed href. Result: `Tests 1 failed | 2 passed (3)`, with a
doubled basename.
- **B1** (at `cc0777aa`): `pageRecordActionsValue`'s href goes back to
the bare path. Result: `Tests 2 failed | 6 passed (8)`, Expected
`/_console/apps/crm/account/record/A-1`, Received
`/apps/crm/account/record/A-1`; the controls stay green.
- **B2** (at `cc0777aa`): `useHref` dropped from `PageView.test.tsx`'s
mock. Result: `Error: [vitest] No "useHref" export is defined on the
"react-router-dom" mock`.
## Gates, at HEAD `cc0777aa`
| command | exit | verdict line |
|:--|:-:|:--|
| `turbo run build --filter='@object-ui/app-shell^...' --concurrency=2`
(dependency closure) | 0 | `Tasks: 28 successful, 28 total` |
| `pnpm --filter @object-ui/app-shell type-check` | 0 | no diagnostics |
| `pnpm --filter @object-ui/react type-check` | 0 | no diagnostics |
| `pnpm --filter @object-ui/app-shell lint` | 0 | `0 errors`; no warning
on a changed line |
| `pnpm --filter @object-ui/react lint` | 0 | `0 errors`; the one
warning in `RelatedRecordActionsContext.tsx` is on an existing export,
not the doc lines |
| `pnpm exec vitest run` over the narrowed set below | 0 | `Test Files
317 passed (317)`, `Tests 3340 passed (3340)` |
| `node scripts/check-changeset-no-major.mjs` | 0 | `No changeset
declares a major bump.` |
| `node scripts/check-changeset-presence.mjs` | 0 | `12 source file(s)
of 2 released package(s) changed, and this change declares 1
changeset(s)` |
| `pnpm check:changeset-claims`, `check:control-bytes`,
`check:new-line-citations`, `check:pending-changeset-literals`,
`check:test-path-roots`, `check:vi-mock-specifiers`,
`check:vi-mock-inherit`, `check:vi-mock-override-shape`,
`check:phantom-deps`, `check:unreferenced-sources` | 0 each | OK |
**Declared narrowing of the test run.** The run covers every
`packages/app-shell` and `apps/console` test whose source names any of
these: the bridge, `RecordDetailView`, `recordHref`, `openRecord`,
`LookupCellRenderer`, `ReferencedRecordLink`, `AppContent`,
`ConsoleShell`, `useRelatedRecordActions`,
`RelatedRecordActionsProvider`, `PageView`, `pageRecordActions` or
`documentHref`. It also covers such tests elsewhere that import
`@object-ui/app-shell`, all 109 `@object-ui/react` test files, and
`packages/fields/src/__tests__/lookupCellRecordLink.test.tsx`. The full
`@object-ui/app-shell` suite is left to CI's `Test` shards, which are
green on this head.
## Acceptance notes
- **Sibling PR coordination:** objectui#12198's branch adds a test that
mounts `PageView` under a `react-router-dom` mock with no `useHref`.
Whichever PR lands second needs a `useHref` entry returning `'/'` in
that mock. The seat has handed this to objectui#12198's dev.
- **Other record routes:** `RecordDetailView`'s favourite and
recent-item record routes are router paths read through `navigate` and
router `Link`s, so they are correct as they are and untouched.
Session: `https://claude.ai/code/session_01G5TSaEwbEQsKMjhzTB4rEd`
---
_Generated by [Claude
Code](https://claude.ai/code/session_01G5TSaEwbEQsKMjhzTB4rEd)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 21fdeb3 commit 97e7d4e
13 files changed
Lines changed: 381 additions & 23 deletions
File tree
- .changeset
- packages
- app-shell/src/views
- __tests__
- react/src/context
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
13 | | - | |
| 13 | + | |
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
| |||
67 | 67 | | |
68 | 68 | | |
69 | 69 | | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
70 | 73 | | |
71 | 74 | | |
72 | 75 | | |
| |||
130 | 133 | | |
131 | 134 | | |
132 | 135 | | |
133 | | - | |
| 136 | + | |
134 | 137 | | |
135 | 138 | | |
136 | 139 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
69 | 69 | | |
70 | 70 | | |
71 | 71 | | |
72 | | - | |
| 72 | + | |
73 | 73 | | |
74 | 74 | | |
75 | 75 | | |
| |||
85 | 85 | | |
86 | 86 | | |
87 | 87 | | |
| 88 | + | |
88 | 89 | | |
89 | 90 | | |
90 | 91 | | |
| |||
250 | 251 | | |
251 | 252 | | |
252 | 253 | | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
253 | 257 | | |
254 | 258 | | |
255 | 259 | | |
| |||
260 | 264 | | |
261 | 265 | | |
262 | 266 | | |
263 | | - | |
| 267 | + | |
264 | 268 | | |
265 | | - | |
266 | | - | |
267 | | - | |
268 | | - | |
269 | | - | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
270 | 274 | | |
271 | 275 | | |
272 | 276 | | |
273 | 277 | | |
274 | | - | |
| 278 | + | |
275 | 279 | | |
276 | 280 | | |
277 | 281 | | |
| |||
296 | 300 | | |
297 | 301 | | |
298 | 302 | | |
299 | | - | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
300 | 328 | | |
301 | 329 | | |
302 | | - | |
303 | | - | |
| 330 | + | |
| 331 | + | |
304 | 332 | | |
305 | | - | |
| 333 | + | |
306 | 334 | | |
307 | 335 | | |
308 | 336 | | |
| |||
425 | 453 | | |
426 | 454 | | |
427 | 455 | | |
428 | | - | |
| 456 | + | |
429 | 457 | | |
430 | 458 | | |
431 | 459 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
38 | 38 | | |
39 | 39 | | |
40 | 40 | | |
| 41 | + | |
| 42 | + | |
41 | 43 | | |
42 | 44 | | |
43 | 45 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
31 | 31 | | |
32 | 32 | | |
33 | 33 | | |
| 34 | + | |
| 35 | + | |
34 | 36 | | |
35 | 37 | | |
36 | 38 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
34 | 34 | | |
35 | 35 | | |
36 | 36 | | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
37 | 40 | | |
38 | 41 | | |
39 | 42 | | |
| |||
115 | 118 | | |
116 | 119 | | |
117 | 120 | | |
118 | | - | |
| 121 | + | |
119 | 122 | | |
120 | 123 | | |
121 | 124 | | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
122 | 134 | | |
123 | | - | |
124 | | - | |
| 135 | + | |
| 136 | + | |
125 | 137 | | |
126 | 138 | | |
127 | 139 | | |
128 | 140 | | |
129 | 141 | | |
130 | 142 | | |
131 | | - | |
| 143 | + | |
132 | 144 | | |
133 | 145 | | |
134 | 146 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22 | 22 | | |
23 | 23 | | |
24 | 24 | | |
| 25 | + | |
| 26 | + | |
25 | 27 | | |
26 | 28 | | |
27 | 29 | | |
| |||
0 commit comments