This is an automated email from the ASF dual-hosted git repository. wu-sheng pushed a commit to branch refactor/decompose-large-files in repository https://gitbox.apache.org/repos/asf/skywalking-horizon-ui.git
commit b163842869d11e4c7a2d24aab10dca0825c09627 Author: Wu Sheng <[email protected]> AuthorDate: Sat Jun 27 07:49:08 2026 +0800 feat(browser-errors): manual-fire query gate (match Logs) Browser Errors now stages filter edits (version / page / time) into an applied snapshot and fetches only on Run query — a fresh tab shows the "Pick your conditions, then click Run query" prompt, and a service switch resets to it (clearing the category filter). page + pageSize stay live (paging is a direct action). Mirrors the per-layer Logs manual-fire. --- CHANGELOG.md | 2 +- .../browser-errors/LayerBrowserErrorsView.vue | 60 ++++++++++++++++++---- .../layer/browser-errors/useLayerBrowserErrors.ts | 5 +- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b3c3b00..cd59520 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ The version line is shared by every package in the monorepo (apps + shared packa ### Logs -- **Logs query on demand, not on every edit.** The per-layer Logs tab and cross-layer Log inspect now stage condition changes and fetch only when you press **Run query** — a fresh tab shows a "Pick your conditions, then click Run query" prompt, and switching service resets to that prompt and clears the level / tag filters, so the previous service's logs never linger under the new one. +- **Log and browser-error lists query on demand, not on every edit.** The per-layer Logs tab, cross-layer Log inspect, and the Browser Errors tab now stage condition changes and fetch only when you press **Run query** — a fresh tab shows a "Pick your conditions, then click Run query" prompt, and switching service resets to that prompt (clearing the level / tag / category filters), so the previous service's data never lingers under the new one. ### Alarms diff --git a/apps/ui/src/layer/browser-errors/LayerBrowserErrorsView.vue b/apps/ui/src/layer/browser-errors/LayerBrowserErrorsView.vue index 91b72f2..6140735 100644 --- a/apps/ui/src/layer/browser-errors/LayerBrowserErrorsView.vue +++ b/apps/ui/src/layer/browser-errors/LayerBrowserErrorsView.vue @@ -162,24 +162,65 @@ function clearPage(): void { pageQuery.value = ''; } +// Manual-fire: filter edits (version / page / time) stage into `applied`; +// the query reads that snapshot, so it fires only on Run query — never the +// prior service's errors on a fresh tab. page + pageSize stay live (paging +// is a direct action, not a staged filter). +const hasQueried = ref(false); +interface AppliedBrowserConditions { + service: string | null; + serviceVersionId: string; + pagePathId: string; + windowMinutes: number; + startMs: number | null; + endMs: number | null; +} +function snapshotConditions(): AppliedBrowserConditions { + return { + service: serviceName.value, + serviceVersionId: selectedVersionId.value, + pagePathId: selectedPageId.value, + windowMinutes: windowMinutesEffective.value, + startMs: startMsRef.value, + endMs: endMsRef.value, + }; +} +const applied = ref<AppliedBrowserConditions>(snapshotConditions()); +function applyConditions(): void { + applied.value = snapshotConditions(); +} + const { logs, total, reachable, queryError, isFetching, refetch } = useLayerBrowserErrors(layerKey, { - service: serviceName, - serviceVersionId: selectedVersionId, - pagePathId: selectedPageId, + service: computed(() => applied.value.service), + serviceVersionId: computed(() => applied.value.serviceVersionId), + pagePathId: computed(() => applied.value.pagePathId), category: allCategories, page, pageSize, - windowMinutes: windowMinutesEffective, - startMs: startMsRef, - endMs: endMsRef, + windowMinutes: computed(() => applied.value.windowMinutes), + startMs: computed(() => applied.value.startMs), + endMs: computed(() => applied.value.endMs), + enabled: hasQueried, }); +function runQuery(): void { + applyConditions(); + page.value = 1; + hasQueried.value = true; + void refetch(); +} -// Version/page ids belong to the previous service — drop them on app change. +// Service switch is a context change → cascade-clear back to the Run-query +// prompt; never show the prior service's errors under the new one. watch(serviceName, () => { selectedVersionId.value = ''; clearPage(); + hasQueried.value = false; + page.value = 1; + applyConditions(); }); -watch([serviceName, windowMinutes, customStart, customEnd, selectedVersionId, selectedPageId, pageSize], () => { +// pageSize is a live pagination control (reset page + refetch); filter edits +// stage into `applied` and wait for Run query. +watch(pageSize, () => { page.value = 1; }); // `expanded` is an index into `filteredLogs`; drop it when the set changes. @@ -285,7 +326,7 @@ function loc(row: BrowserErrorRow): string { {{ t('Source maps') }} <span class="be-maps-count">{{ sourceMaps.length }}</span> </button> - <button class="sw-btn primary" type="button" :disabled="isFetching" @click="refetch()">{{ t('Run query') }}</button> + <button class="sw-btn primary" type="button" :disabled="isFetching" @click="runQuery">{{ t('Run query') }}</button> </div> </div> <div class="lg-conditions"> @@ -370,6 +411,7 @@ function loc(row: BrowserErrorRow): string { </DensityHistogram> <div v-if="!serviceName" class="lg-empty">{{ t('Select an app to view its browser logs.') }}</div> + <div v-else-if="!hasQueried" class="lg-empty">{{ t('Pick your conditions, then click Run query.') }}</div> <div v-else-if="isFetching && logs.length === 0" class="lg-empty">{{ t('Reading data…') }}</div> <div v-else-if="!reachable" class="lg-empty">{{ t('Backend unreachable.') }}<span v-if="queryError"> {{ queryError }}</span></div> <div v-else-if="filteredLogs.length === 0" class="lg-empty"> diff --git a/apps/ui/src/layer/browser-errors/useLayerBrowserErrors.ts b/apps/ui/src/layer/browser-errors/useLayerBrowserErrors.ts index d128f2a..c5f8d84 100644 --- a/apps/ui/src/layer/browser-errors/useLayerBrowserErrors.ts +++ b/apps/ui/src/layer/browser-errors/useLayerBrowserErrors.ts @@ -36,6 +36,9 @@ export interface BrowserErrorParams { * `windowMinutes`. The BFF applies the OAP timezone offset. */ startMs?: Ref<number | null>; endMs?: Ref<number | null>; + /** Gate the query — when false it never runs. Manual-fire holds it until + * the operator presses Run query. Defaults to always-on. */ + enabled?: Ref<boolean>; } export function useLayerBrowserErrors(layerKey: Ref<string>, params: BrowserErrorParams) { @@ -69,7 +72,7 @@ export function useLayerBrowserErrors(layerKey: Ref<string>, params: BrowserErro page: params.page.value, pageSize: params.pageSize.value, }), - enabled: computed(() => layerKey.value.length > 0), + enabled: computed(() => layerKey.value.length > 0 && (params.enabled ? params.enabled.value : true)), staleTime: 15_000, }); // No auto-refresh subscription: this is a triage page that owns its time
