From 76bd5dd822aff4e87f2efb691335fb446caefccc Mon Sep 17 00:00:00 2001 From: Omkar Kesarkhane <127078473+omkarK06@users.noreply.github.com> Date: Fri, 12 Jun 2026 13:15:30 +0530 Subject: [PATCH] fix: added skeleton loading for traces table (#12593) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Why The custom spinner-based loading states were inconsistent across traces views anddid not align with the logs TenstackTable skeleton pattern already established inthe codebase. The new skeleton provides a unified, low-friction loading experience — shimmer pills at column-aligned positions that mirror real cell widths — and removes the need for each consumer to write its own loading template. --- web/src/components/TenstackTable.spec.ts | 23 +- web/src/components/TenstackTable.vue | 157 +++++++++++- .../traces/ServiceGraphNodeSidePanel.vue | 228 ++++++++---------- web/src/plugins/traces/ServicesCatalog.vue | 29 --- .../components/TracesSearchResultList.spec.ts | 11 +- .../components/TracesSearchResultList.vue | 36 --- 6 files changed, 273 insertions(+), 211 deletions(-) diff --git a/web/src/components/TenstackTable.spec.ts b/web/src/components/TenstackTable.spec.ts index b6e313b6ab..ffdfe78a65 100644 --- a/web/src/components/TenstackTable.spec.ts +++ b/web/src/components/TenstackTable.spec.ts @@ -325,13 +325,28 @@ describe("TenstackTable", () => { // ── Loading state ───────────────────────────────────────────────────────── describe("loading state", () => { - it("should show the default loading indicator when loading=true and no rows", () => { + it("should show the skeleton loading body when loading=true and no rows", () => { wrapper = mountTable({ rows: [], loading: true }); expect( - wrapper.find('[data-test="tenstack-table-loading-indicator"]').exists(), + wrapper.find('[data-test="tenstack-table-skeleton-body"]').exists(), + ).toBe(true); + }); + + it("should not show the skeleton body when a custom loading slot is provided", () => { + wrapper = mountTable( + { rows: [], loading: true }, + { loading: '
Loading…
' }, + ); + expect( + wrapper.find('[data-test="tenstack-table-skeleton-body"]').exists(), + ).toBe(false); + }); + + it("should show the skeleton body when loading=true (follows O2 pattern)", () => { + wrapper = mountTable({ loading: true }); + expect( + wrapper.find('[data-test="tenstack-table-skeleton-body"]').exists(), ).toBe(true); - // i18n key is rendered as-is by the mock - expect(wrapper.html()).toContain("confirmDialog.loading"); }); it("should render a custom loading slot when loading=true and rows is empty", () => { diff --git a/web/src/components/TenstackTable.vue b/web/src/components/TenstackTable.vue index 3da93c5e1b..4c5292d400 100644 --- a/web/src/components/TenstackTable.vue +++ b/web/src/components/TenstackTable.vue @@ -304,8 +304,13 @@ along with this program. If not, see . - - + + . opacity: 0.7, }" > - -
- - {{ t("confirmDialog.loading") }} -
-
+ - + @@ -392,6 +390,58 @@ along with this program. If not, see . + + + + + + + + - - - - - -