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

rusackas pushed a commit to branch mobile-dashboard-support
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 4989fddc83fcdb95a6af760ed391c5cb9d959454
Author: Evan Rusackas <[email protected]>
AuthorDate: Thu Jan 8 15:35:39 2026 -0800

    feat(dashboard): add mobile-friendly dashboard consumption mode
    
    - Filter global nav to show only Dashboards on mobile (<768px)
    - Stack dashboard charts vertically instead of row layout on mobile
    - Make dashboard tabs sticky for easier navigation on mobile
    - Hide native filters on mobile for simplified viewing
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    Co-Authored-By: Claude Opus 4.5 <[email protected]>
---
 .../DashboardBuilder/DashboardBuilder.tsx          |  5 +--
 .../components/gridComponents/Row/Row.tsx          |  9 +++++
 .../gridComponents/TabsRenderer/TabsRenderer.tsx   | 10 ++++++
 superset-frontend/src/features/home/Menu.tsx       | 38 ++++++++++++----------
 4 files changed, 42 insertions(+), 20 deletions(-)

diff --git 
a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
 
b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
index 38f0dcac2b..0afe5222e5 100644
--- 
a/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
+++ 
b/superset-frontend/src/dashboard/components/DashboardBuilder/DashboardBuilder.tsx
@@ -22,7 +22,7 @@ import { memo, useCallback, useEffect, useMemo, useRef, 
useState } from 'react';
 import { addAlpha, JsonObject, t, useElementOnScreen } from 
'@superset-ui/core';
 import { css, styled, useTheme } from '@apache-superset/core/ui';
 import { useDispatch, useSelector } from 'react-redux';
-import { EmptyState, Loading } from '@superset-ui/core/components';
+import { EmptyState, Grid, Loading } from '@superset-ui/core/components';
 import { ErrorBoundary, BasicErrorAlert } from 'src/components';
 import BuilderComponentPane from 
'src/dashboard/components/BuilderComponentPane';
 import DashboardHeader from 'src/dashboard/components/Header';
@@ -363,6 +363,7 @@ const DashboardBuilder = () => {
   const dispatch = useDispatch();
   const uiConfig = useUiConfig();
   const theme = useTheme();
+  const { md: isNotMobile } = Grid.useBreakpoint();
 
   const dashboardId = useSelector<RootState, string>(
     ({ dashboardInfo }) => `${dashboardInfo.id}`,
@@ -459,7 +460,7 @@ const DashboardBuilder = () => {
     ELEMENT_ON_SCREEN_OPTIONS,
   );
 
-  const showFilterBar = !editMode && nativeFiltersEnabled;
+  const showFilterBar = isNotMobile && !editMode && nativeFiltersEnabled;
 
   const offset =
     FILTER_BAR_HEADER_HEIGHT +
diff --git 
a/superset-frontend/src/dashboard/components/gridComponents/Row/Row.tsx 
b/superset-frontend/src/dashboard/components/gridComponents/Row/Row.tsx
index e4a6915ba1..4c7b37efe3 100644
--- a/superset-frontend/src/dashboard/components/gridComponents/Row/Row.tsx
+++ b/superset-frontend/src/dashboard/components/gridComponents/Row/Row.tsx
@@ -124,6 +124,15 @@ const GridRow = styled.div<{ editMode: boolean }>`
     &.grid-row--empty {
       min-height: ${theme.sizeUnit * 25}px;
     }
+
+    @media (max-width: 767px) {
+      flex-direction: column;
+
+      & > :not(.hover-menu) {
+        width: 100% !important;
+        margin-right: 0 !important;
+      }
+    }
   `}
 `;
 
diff --git 
a/superset-frontend/src/dashboard/components/gridComponents/TabsRenderer/TabsRenderer.tsx
 
b/superset-frontend/src/dashboard/components/gridComponents/TabsRenderer/TabsRenderer.tsx
index 906150a5f3..a51195bb56 100644
--- 
a/superset-frontend/src/dashboard/components/gridComponents/TabsRenderer/TabsRenderer.tsx
+++ 
b/superset-frontend/src/dashboard/components/gridComponents/TabsRenderer/TabsRenderer.tsx
@@ -81,6 +81,16 @@ const StyledTabsContainer = styled.div<{ isDragging?: 
boolean }>`
       display: none !important;
     }
   `}
+
+  /* Sticky tabs on mobile */
+  @media (max-width: 767px) {
+    .ant-tabs-nav {
+      position: sticky;
+      top: 0;
+      z-index: 100;
+      background-color: ${({ theme }) => theme.colorBgContainer};
+    }
+  }
 `;
 
 export interface TabItem {
diff --git a/superset-frontend/src/features/home/Menu.tsx 
b/superset-frontend/src/features/home/Menu.tsx
index 9d8c35341b..feaabd3e4f 100644
--- a/superset-frontend/src/features/home/Menu.tsx
+++ b/superset-frontend/src/features/home/Menu.tsx
@@ -343,24 +343,26 @@ export function Menu({
             className="main-nav"
             selectedKeys={activeTabs}
             disabledOverflow
-            items={menu.map(item => {
-              const props = {
-                ...item,
-                isFrontendRoute: isFrontendRoute(item.url),
-                childs: item.childs?.map(c => {
-                  if (typeof c === 'string') {
-                    return c;
-                  }
-
-                  return {
-                    ...c,
-                    isFrontendRoute: isFrontendRoute(c.url),
-                  };
-                }),
-              };
-
-              return buildMenuItem(props);
-            })}
+            items={menu
+              .filter(item => screens.md || item.label === 'Dashboards')
+              .map(item => {
+                const props = {
+                  ...item,
+                  isFrontendRoute: isFrontendRoute(item.url),
+                  childs: item.childs?.map(c => {
+                    if (typeof c === 'string') {
+                      return c;
+                    }
+
+                    return {
+                      ...c,
+                      isFrontendRoute: isFrontendRoute(c.url),
+                    };
+                  }),
+                };
+
+                return buildMenuItem(props);
+              })}
           />
         </StyledCol>
         <Col md={8} xs={24}>

Reply via email to