This is an automated email from the ASF dual-hosted git repository.

michael-s-molina pushed a commit to branch 6.1
in repository https://gitbox.apache.org/repos/asf/superset.git


The following commit(s) were added to refs/heads/6.1 by this push:
     new f8490fc9af7 fix(event-log): add event logging for embedded Superset 
(#41938)
f8490fc9af7 is described below

commit f8490fc9af7118a00a7eceded5e8161bda9a6922
Author: Luiz Otavio <[email protected]>
AuthorDate: Mon Jul 13 15:23:05 2026 -0300

    fix(event-log): add event logging for embedded Superset (#41938)
    
    Co-authored-by: Claude Opus 4.8 <[email protected]>
---
 superset-frontend/src/middleware/logger.test.ts    | 32 ++++++++++++++++++++++
 .../src/middleware/loggerMiddleware.ts             | 23 +++++++++++++---
 2 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/superset-frontend/src/middleware/logger.test.ts 
b/superset-frontend/src/middleware/logger.test.ts
index 5b989e21713..9b23587530b 100644
--- a/superset-frontend/src/middleware/logger.test.ts
+++ b/superset-frontend/src/middleware/logger.test.ts
@@ -142,6 +142,38 @@ describe('logger middleware', () => {
     }
   });
 
+  const getSourceForPath = (href: string): string | undefined => {
+    const originalHref = window.location.href;
+    Object.defineProperty(window, 'location', {
+      value: { href },
+      writable: true,
+    });
+    try {
+      (logger as Function)(mockStore)(next)(action);
+      jest.advanceTimersByTime(2000);
+      const { events } = postStub.mock.calls[0][0].postPayload;
+      return events[0].source;
+    } finally {
+      Object.defineProperty(window, 'location', {
+        value: { href: originalHref },
+        writable: true,
+      });
+    }
+  };
+
+  test.each([
+    ['/dashboard/123/embedded/', 'embedded_dashboard'],
+    ['/embedded/abc-def-uuid/', 'embedded_dashboard'],
+    // React Router also matches these routes without a trailing slash
+    ['/dashboard/123/embedded', 'embedded_dashboard'],
+    ['/embedded/abc-def-uuid', 'embedded_dashboard'],
+    ['/dashboard/123/', 'dashboard'],
+    // slug is literally "embedded" - must not be treated as embedded
+    ['/dashboard/embedded/', 'dashboard'],
+  ])('classifies %s as source "%s"', (path, expectedSource) => {
+    expect(getSourceForPath(`http://localhost${path}`)).toBe(expectedSource);
+  });
+
   test('should debounce a few log requests to one', () => {
     (logger as Function)(mockStore)(next)(action);
     (logger as Function)(mockStore)(next)(action);
diff --git a/superset-frontend/src/middleware/loggerMiddleware.ts 
b/superset-frontend/src/middleware/loggerMiddleware.ts
index 55c476f9bc2..af67db08d2b 100644
--- a/superset-frontend/src/middleware/loggerMiddleware.ts
+++ b/superset-frontend/src/middleware/loggerMiddleware.ts
@@ -33,7 +33,12 @@ import { ensureAppRoot } from '../utils/pathUtils';
 import type { DashboardInfo, DashboardLayoutState } from '../dashboard/types';
 import type { QueryEditor } from '../SqlLab/types';
 
-type LogEventSource = 'dashboard' | 'explore' | 'sqlLab' | 'slice';
+type LogEventSource =
+  | 'dashboard'
+  | 'embedded_dashboard'
+  | 'explore'
+  | 'sqlLab'
+  | 'slice';
 
 interface LogEventData {
   source?: LogEventSource;
@@ -99,7 +104,7 @@ const sendBeacon = (events: LogEventData[]): void => {
   const [firstEvent] = events;
   const { source, source_id } = firstEvent;
   // backend logs treat these request params as first-class citizens
-  if (source === 'dashboard') {
+  if (source === 'dashboard' || source === 'embedded_dashboard') {
     endpoint += `&dashboard_id=${source_id}`;
   } else if (source === 'slice') {
     endpoint += `&slice_id=${source_id}`;
@@ -131,6 +136,12 @@ const logMessageQueue = new 
DebouncedMessageQueue<LogEventData>({
   delayThreshold: 1000,
 });
 
+// Embedded dashboards are served from `/dashboard/:idOrSlug/embedded/` and
+// `/embedded/:uuid/`. Matching these specific shapes avoids false positives
+// for regular dashboards (e.g. a dashboard whose slug is "embedded").
+const EMBEDDED_ROUTE_REGEX =
+  /\/dashboard\/[^/]+\/embedded\/?|\/embedded\/[^/]+\/?/;
+
 let lastEventId: string | number = 0;
 
 const loggerMiddleware: Middleware<
@@ -162,9 +173,13 @@ const loggerMiddleware: Middleware<
     }
     const path = navPath || window?.location?.href;
 
-    if (dashboardInfo?.id && path?.includes('/dashboard/')) {
+    // Match the actual embedded route patterns 
(`/dashboard/:idOrSlug/embedded/`
+    // and `/embedded/:uuid/`) rather than any URL containing "/embedded/", 
which
+    // would misclassify a regular dashboard whose slug is "embedded".
+    const isEmbedded = EMBEDDED_ROUTE_REGEX.test(path ?? '');
+    if (dashboardInfo?.id && (path?.includes('/dashboard/') || isEmbedded)) {
       logMetadata = {
-        source: 'dashboard',
+        source: isEmbedded ? 'embedded_dashboard' : 'dashboard',
         source_id: dashboardInfo.id,
         dashboard_id: dashboardInfo.id,
         ...logMetadata,

Reply via email to