This is an automated email from the ASF dual-hosted git repository.
wu-sheng pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git
The following commit(s) were added to refs/heads/main by this push:
new 26aa105 ui: preserve URL ?instance= on first service auto-fill +
don't flag empty widgets as errors
26aa105 is described below
commit 26aa10558aafd1d1d24eae26f4732c19631b0a1c
Author: Wu Sheng <[email protected]>
AuthorDate: Sun May 17 17:50:57 2026 +0800
ui: preserve URL ?instance= on first service auto-fill + don't flag empty
widgets as errors
Two fixes:
1. /layer/general/instance?instance=X used to land with ?instance=
stripped — the service auto-pick (URL had no ?service=) called
`setSelected(firstServiceId)`, which unconditionally cleared
the narrower picks. Now `setSelected` only drops `?instance=` /
`?endpoint=` when it's REPLACING an existing service (current
was already truthy). First-time auto-fill (current === null)
preserves whatever the URL carried — operators who deep-link
to a specific instance now keep their pick after the auto-
service settles.
This doesn't reopen the mesh_dp "sticky pick" issue: that was
about REPLACING a service the operator already had set; this
change only affects the null-current path.
2. The per-widget event glyph went red (✕) when the BFF returned
`error: "no data"` — which is a non-fatal sentinel meaning the
widget's MQE has nothing to plot for this entity right now, not
an actual backend error. Now treated as `info` so the ticker
doesn't flash red for ordinary empty cells. Real errors (OAP
unreachable, MQE parse failures, etc.) keep the ✕ kind.
---
apps/ui/src/layer/useSelectedService.ts | 17 ++++++++++++-----
.../render/layer-dashboard/useLayerPageOrchestrator.ts | 7 ++++++-
2 files changed, 18 insertions(+), 6 deletions(-)
diff --git a/apps/ui/src/layer/useSelectedService.ts
b/apps/ui/src/layer/useSelectedService.ts
index a8d84b5..d090144 100644
--- a/apps/ui/src/layer/useSelectedService.ts
+++ b/apps/ui/src/layer/useSelectedService.ts
@@ -42,11 +42,18 @@ export function useSelectedService() {
if (id === current) return;
if (id) next.service = id;
else delete next.service;
- // Instance / endpoint choices are derived from the selected service.
- // When the service changes, drop the narrower entity so each
- // dashboard can auto-pick from the new service's own list.
- delete next.instance;
- delete next.endpoint;
+ // Drop the narrower picks (?instance=, ?endpoint=) ONLY when
+ // we're replacing an existing service. First-time auto-fill
+ // (`current === null` — URL arrived with no ?service= at all)
+ // preserves any `?instance=` / `?endpoint=` URL hints the
+ // operator typed or that a sharable link carried, because
+ // those were the explicit intent. Without this, hitting
+ // `/layer/general/instance?instance=X` dropped X immediately
+ // and the auto-picked service's first instance won the race.
+ if (current !== null) {
+ delete next.instance;
+ delete next.endpoint;
+ }
// `replace` instead of `push` — switching services shouldn't bloat
// the browser back stack with N entries.
void router.replace({ path: route.path, query: next });
diff --git a/apps/ui/src/render/layer-dashboard/useLayerPageOrchestrator.ts
b/apps/ui/src/render/layer-dashboard/useLayerPageOrchestrator.ts
index 89a00f4..146c96a 100644
--- a/apps/ui/src/render/layer-dashboard/useLayerPageOrchestrator.ts
+++ b/apps/ui/src/render/layer-dashboard/useLayerPageOrchestrator.ts
@@ -268,7 +268,12 @@ export function useLayerPageOrchestrator(refs:
OrchestratorRefs): {
const label = titleById.get(r.id) ?? r.id;
let kind: 'ok' | 'err' | 'info' = 'info';
let detail = 'no data';
- if (r.error) {
+ // The BFF uses `error: "no data"` as a non-fatal sentinel
+ // when a widget's MQE returned nothing (metric not reporting
+ // for this entity right now). Treat that as `info`, not
+ // `err`, so the ticker doesn't light up red for ordinary
+ // empty cells. Real backend errors keep the ✕ kind.
+ if (r.error && r.error !== 'no data') {
kind = 'err';
detail = `error: ${r.error}`;
} else if (r.value != null) {