lxbme opened a new pull request, #3459:
URL: https://github.com/apache/apisix-dashboard/pull/3459

   Please answer these questions before submitting a pull request, **or your PR 
will get closed**.
   
   **Why submit this pull request?**
   
   - [ ] Bugfix
   - [x] New feature provided
   - [ ] Improve performance
   - [ ] Backport patches
   
   **What changes will this PR take into?**
   
   `upstream_id`, `service_id`, `plugin_config_id` and `group_id` rendered as 
plain text inputs holding a bare id. There was no name resolution and nothing 
to click, so answering "which upstream is this route actually using?" meant 
copying the id, navigating to Upstreams, and searching by hand.
   
   Each field now resolves its id and offers a link to the referenced resource. 
Four fields in two files cover the four referenceable resource types — 
`FormPartRoute/index.tsx` (`upstream_id`, `plugin_config_id`, `service_id`) and 
`FormPartConsumer.tsx` (`group_id`) — because the form sections that hold these 
fields are shared between routes, stream routes, services and consumers. The 
change is far smaller than "every resource with an id field": it targets 
exactly the four fields that reference another top-level resource.
   
   ### Why the control is an anchor, not `RouteLinkBtn`
   
   The repo's existing `RouteLinkBtn` is a Mantine `Button`. `FormSection` 
renders a `<fieldset>` and passes `disabled` when the section is read-only — 
most visibly in the nested service → route view, where the whole form is 
disabled while browsing. A disabled `<fieldset>` disables every descendant form 
control, including a `<button>`-based link, which would make it dead exactly 
where a route's inline upstream is being reviewed. A real `<a>` (via 
`createLink` wrapping a Mantine `Anchor`) is left untouched by `disabled` on an 
ancestor `<fieldset>`, so it stays clickable in both read-only and edit views. 
`RouteLinkBtn`'s own call sites are deliberately left untouched by this change.
   
   ### Dangling references and non-404 failures
   
   A reference that resolves to nothing gets a warning icon rather than a link 
— sending the user to a page that only reports the resource missing is a wasted 
round trip, and a broken reference is worth stating explicitly rather than 
silently. Anything that is not a 404 — in flight, a network error, a 500 — 
renders nothing at all: the dashboard could not ask whether the resource 
exists, which is not the same as the reference being broken, so it makes no 
claim either way.
   
   ### The query carries its own retry rule
   
   Resolving a reference means a `GET` that 404s whenever the reference is 
dangling, and the app's global policy retries anything that is not a 401 three 
times. A 404 here is not a failure — it is the answer "no such resource" — so 
inheriting that policy meant ~8s of backoff before the warning appeared, 
repeated on every typing pause in edit mode and every window refocus. The query 
therefore carries its own predicate, in the same shape as the one already in 
`usePluginMetadataList`, which brings that to ~1.1s on load and ~0.4s while 
typing. Those are measured, and the e2e timeouts were tightened from 15s to 3s 
so a return of the backoff fails the spec instead of passing slowly.
   
   ### Interaction with #3458
   
   #3458 (open) makes the same judgement globally: it stops retrying Admin API 
404s and silences their toast for reads. Once it lands, the local predicate 
here becomes redundant and should collapse into it — the code says so at the 
point where it would be removed. Until then, one thing this branch does **not** 
fix on its own: a dangling reference still raises the gateway's `Key not found` 
toast, because suppressing that would mean either threading a skip header 
through the shared detail-query factory or importing #3458's global rule. That 
is left to #3458 rather than duplicated here.
   
   ### Compatibility with the other in-flight PRs
   
   This branch was verified against a local octopus merge of all five branches 
currently queued against `master`: #3454, #3456, #3457, #3458 and this one. The 
merge is clean on top of the other four — the only conflict in that merge is 
between #3456 and #3458 themselves (both rewrite the route detail page's 
`PageHeader`), and is unrelated to this change. A maintainer merging all five 
in one pass will hit that conflict once, in `src/routes/routes/detail.$id.tsx`; 
the resolution is to keep both sides (the test-request button from #3456 and 
the id-bearing title from #3458).
   
   **Related issues**
   
   Part of #3453
   
   **Checklist:**
   
   - [x] Did you explain what problem does this PR solve? Or what new features 
have been added?
   - [x] Have you added corresponding test cases?
   - [ ] Have you modified the corresponding document?
   - [x] Is this PR backward compatible? If it is not backward compatible, 
please discuss on the mailing list first
   
   Tests:
   
   - `e2e/tests/regression/form.cross-references.spec.ts` — four tests: a 
resolved reference renders as a real link (asserted via `getByRole('link')`, 
which fails if it ever regresses to a button) to the referenced resource's 
detail page; a dangling reference shows a warning and no link; the resolved 
state follows what is currently typed into the field, not the saved value; and 
a consumer group reference resolves the same way on the consumer page, covering 
the second call-site shape and the no-`name` fallback (consumer groups have no 
`name` field). The seeded upstream is deliberately named with an ampersand so 
the accessible name is pinned unescaped.
   
     Note on the dangling fixture: it is created by force-deleting a referenced 
upstream, not by writing a route that points at nothing — APISIX 3.17.0 rejects 
the latter with a 400. Force-deletion is also how real deployments acquire 
dangling references.
   
   - `src/components/form/ResourceRef.test.ts` — pins each of the four 
resources to its own detail query and its own route. The table that pairs them 
is behind a cast that TanStack's `queryOptions()` forces, so the type system 
checks the route strings but not the pairing; swapping two factories compiles 
clean and this test is what catches it.
   
   Verified: `pnpm test`, `pnpm exec tsc -b`, `pnpm lint` and a production 
`pnpm build` all clean, on this branch alone and again on the five-branch 
octopus merge described above. The full Playwright suite run on that merged 
tree: 232 passed, 2 failed, both environmental and unrelated to this change — a 
Monaco editor render race in `plugin_metadata.crud-all-fields` (finishes 
suspiciously fast on the failing run, 5.6s vs its usual ~7-9s, consistent with 
a race rather than a real failure) and `stream_routes.show-disabled-error`, 
which restarts a compose project that does not exist on this machine. Neither 
failure is specific to the merged tree or to this branch.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to