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 65374bf ui events: fix missed start edge + add config-resolution step
65374bf is described below
commit 65374bf51c774b5d0c269f7c5a67db6e5e4df002
Author: Wu Sheng <[email protected]>
AuthorDate: Sun May 17 11:53:51 2026 +0800
ui events: fix missed start edge + add config-resolution step
Two fixes so the ticker shows the full page-assembly sequence
(config → service → instance/endpoint → widget):
1. useQueryEvents missed the rising edge when vue-query flipped
isFetching synchronously during the surrounding useQuery() call
(the query is auto-fired the moment `enabled` is truthy, before
the watch attaches). Now we snapshot the mount-time state
explicitly: in-flight → retroactive `start`; cache hit → one-shot
`info`; empty → wait for the watch's first transition. That's why
so11y_java_agent's instance call surfaced "Loaded N" but never
"Loading…".
2. useLayerDashboardConfig now emits a `config` event the moment its
bundle/network resolution resolves, so the ticker reports
"instance dashboard config ready · 7 widgets (preloaded)" at the
top of the page-assembly chain.
---
apps/ui/src/controls/useQueryEvents.ts | 21 ++++++++++-----
.../render/layer-dashboard/useLayerDashboard.ts | 30 ++++++++++++++++++++--
2 files changed, 43 insertions(+), 8 deletions(-)
diff --git a/apps/ui/src/controls/useQueryEvents.ts
b/apps/ui/src/controls/useQueryEvents.ts
index 1b3a32d..ce685b3 100644
--- a/apps/ui/src/controls/useQueryEvents.ts
+++ b/apps/ui/src/controls/useQueryEvents.ts
@@ -57,15 +57,24 @@ export function useQueryEvents<T>(
q: QueryLike<T>,
labels: QueryEventLabels<T>,
): void {
- // Cache-hit echo — when the composable mounts and the query already
- // has data, emit an info line so the ticker doesn't go silent on
- // fast-path revisits.
- if (labels.cached && q.data.value !== undefined && !q.isFetching.value) {
+ // Snapshot the mount-time state. vue-query can flip `isFetching`
+ // synchronously during the surrounding `useQuery(...)` call (the
+ // query is auto-fired the moment `enabled` is truthy), so by the
+ // time this composable runs we may have already missed the
+ // false→true edge. Cover the three possible initial states
+ // explicitly:
+ // - in-flight ⇒ retroactive `start` (the watch below will then
+ // pick up the matching falling edge as `ok`/`err`).
+ // - cache hit ⇒ one-shot `info` line so the ticker doesn't go
+ // silent on fast-path revisits.
+ // - empty ⇒ no event yet; the watch will catch the upcoming
+ // rising edge once the query actually fires.
+ if (q.isFetching.value) {
+ pushEvent(topic, 'start', labels.start());
+ } else if (labels.cached && q.data.value !== undefined) {
pushEvent(topic, 'info', labels.cached(q.data.value));
}
- // Fetch in-flight — push `start` on rising edge, push `ok`/`err`
- // on falling edge based on whether the result is an error.
watch(
() => q.isFetching.value,
(now, before) => {
diff --git a/apps/ui/src/render/layer-dashboard/useLayerDashboard.ts
b/apps/ui/src/render/layer-dashboard/useLayerDashboard.ts
index 39acda3..8311ce1 100644
--- a/apps/ui/src/render/layer-dashboard/useLayerDashboard.ts
+++ b/apps/ui/src/render/layer-dashboard/useLayerDashboard.ts
@@ -27,9 +27,10 @@
* viewed service is instant.
*/
-import { computed, type Ref } from 'vue';
+import { computed, watch, type Ref } from 'vue';
import { useQuery } from '@tanstack/vue-query';
import { useQueryEvents } from '@/controls/useQueryEvents';
+import { pushEvent } from '@/controls/eventLog';
import { useAutoRefreshSubscribe } from
'../../controls/useAutoRefreshSubscribe';
import { bffClient } from '@/api/client';
import {
@@ -63,8 +64,33 @@ export function useLayerDashboardConfig(layerKey:
Ref<string>, scope?: Ref<strin
});
useAutoRefreshSubscribe(() => q.refetch());
+ const config = computed(() => bundled.value ?? q.data.value ?? null);
+ // Surface the config-resolution step in the event ticker so the
+ // operator sees the page-assembly sequence start at the very top
+ // (config → services → instances/endpoints → widgets). The bundle
+ // hit fires the moment localStorage resolves; the network fallback
+ // gets its own start/ok event via useQueryEvents below.
+ let configReported = false;
+ watch(
+ config,
+ (c) => {
+ if (!c || configReported) return;
+ const s = (scope?.value ?? 'service') as string;
+ const widgetN = c.widgets?.length ?? 0;
+ const source = bundled.value ? 'preloaded' : 'network';
+ pushEvent('config', 'info', `${s} dashboard config ready · ${widgetN}
widget${widgetN === 1 ? '' : 's'} (${source})`);
+ configReported = true;
+ },
+ { immediate: true },
+ );
+ useQueryEvents('config-net', q, {
+ start: () => `Fetching ${scope?.value ?? 'service'} dashboard config for
${layerKey.value}…`,
+ ok: () => `Dashboard config loaded from BFF`,
+ err: (e) => `Dashboard config fetch failed: ${e instanceof Error ?
e.message : String(e)}`,
+ });
+
return {
- config: computed(() => bundled.value ?? q.data.value ?? null),
+ config,
isLoading: computed(() => !loaded.value && q.isLoading.value),
error: q.error,
};