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 284e3bdd9e73e6a7071bb55624fcc7145f61ca8b
Author: Evan Rusackas <[email protected]>
AuthorDate: Fri Jan 9 12:24:20 2026 -0800

    feat(mobile): clean up dashboard header for mobile
    
    - Hide star icon on mobile (moved to overflow menu)
    - Add favorite toggle, status, owner, modified info to overflow menu
    - Hide Edit dashboard button on mobile
    - Hide Enter fullscreen and Manage email report menu items on mobile
    - Center logo on mobile with 3-column layout for future left icon
    
    🤖 Generated with [Claude Code](https://claude.com/claude-code)
    
    Co-Authored-By: Claude Opus 4.5 <[email protected]>
---
 .../src/dashboard/components/Header/index.jsx      | 19 ++++--
 .../src/dashboard/components/Header/types.ts       |  4 ++
 .../Header/useHeaderActionsDropdownMenu.tsx        | 68 ++++++++++++++++++++--
 superset-frontend/src/features/home/Menu.tsx       | 15 ++++-
 4 files changed, 95 insertions(+), 11 deletions(-)

diff --git a/superset-frontend/src/dashboard/components/Header/index.jsx 
b/superset-frontend/src/dashboard/components/Header/index.jsx
index 16bec548f9..9ee450bfe6 100644
--- a/superset-frontend/src/dashboard/components/Header/index.jsx
+++ b/superset-frontend/src/dashboard/components/Header/index.jsx
@@ -40,6 +40,7 @@ import {
   Tooltip,
   DeleteModal,
   UnsavedChangesModal,
+  Grid,
 } from '@superset-ui/core/components';
 import { findPermission } from 'src/utils/findPermission';
 import { safeStringify } from 'src/utils/safeStringify';
@@ -163,8 +164,12 @@ const discardChanges = () => {
   window.location.assign(url);
 };
 
+const { useBreakpoint } = Grid;
+
 const Header = () => {
   const dispatch = useDispatch();
+  const screens = useBreakpoint();
+  const isMobile = !screens.md;
   const [didNotifyMaxUndoHistoryToast, setDidNotifyMaxUndoHistoryToast] =
     useState(false);
   const [emphasizeUndo, setEmphasizeUndo] = useState(false);
@@ -607,7 +612,7 @@ const Header = () => {
 
   const titlePanelAdditionalItems = useMemo(
     () => [
-      !editMode && (
+      !editMode && !isMobile && (
         <PublishedStatus
           dashboardId={dashboardInfo.id}
           isPublished={isPublished}
@@ -617,12 +622,13 @@ const Header = () => {
           visible={!editMode}
         />
       ),
-      !editMode && !isEmbedded && metadataBar,
+      !editMode && !isEmbedded && !isMobile && metadataBar,
     ],
     [
       boundActionCreators.savePublished,
       dashboardInfo.id,
       editMode,
+      isMobile,
       metadataBar,
       isEmbedded,
       isPublished,
@@ -715,7 +721,7 @@ const Header = () => {
         ) : (
           <div css={actionButtonsStyle}>
             {NavExtension && <NavExtension />}
-            {userCanEdit && (
+            {userCanEdit && !isMobile && (
               <Button
                 buttonStyle="secondary"
                 onClick={handleEnterEditMode}
@@ -743,6 +749,7 @@ const Header = () => {
       handleCtrlZ,
       handleEnterEditMode,
       hasUnsavedChanges,
+      isMobile,
       overwriteDashboard,
       redoLength,
       toggleEditMode,
@@ -780,6 +787,10 @@ const Header = () => {
     userCanSave: userCanSaveAs,
     userCanCurate,
     isLoading,
+    isMobile,
+    isStarred,
+    isPublished,
+    saveFaveStar: boundActionCreators.saveFaveStar,
     showReportModal,
     showPropertiesModal,
     showRefreshModal,
@@ -806,7 +817,7 @@ const Header = () => {
           onOpenChange: setIsDropdownVisible,
         }}
         additionalActionsMenu={menu}
-        showFaveStar={user?.userId && dashboardInfo?.id}
+        showFaveStar={user?.userId && dashboardInfo?.id && !isMobile}
         showTitlePanelItems
       />
       {showingPropertiesModal && (
diff --git a/superset-frontend/src/dashboard/components/Header/types.ts 
b/superset-frontend/src/dashboard/components/Header/types.ts
index 564635f605..cde8bc6676 100644
--- a/superset-frontend/src/dashboard/components/Header/types.ts
+++ b/superset-frontend/src/dashboard/components/Header/types.ts
@@ -48,6 +48,10 @@ export interface HeaderDropdownProps {
   forceRefreshAllCharts: () => void;
   hasUnsavedChanges: boolean;
   isLoading: boolean;
+  isMobile?: boolean;
+  isStarred?: boolean;
+  isPublished?: boolean;
+  saveFaveStar?: (id: number, isStarred: boolean) => void;
   layout: Layout;
   onSave: () => void;
   refreshFrequency: number;
diff --git 
a/superset-frontend/src/dashboard/components/Header/useHeaderActionsDropdownMenu.tsx
 
b/superset-frontend/src/dashboard/components/Header/useHeaderActionsDropdownMenu.tsx
index 99d7a0c0a8..d4754614e5 100644
--- 
a/superset-frontend/src/dashboard/components/Header/useHeaderActionsDropdownMenu.tsx
+++ 
b/superset-frontend/src/dashboard/components/Header/useHeaderActionsDropdownMenu.tsx
@@ -35,6 +35,7 @@ import { getActiveFilters } from 
'src/dashboard/util/activeDashboardFilters';
 import { getUrlParam } from 'src/utils/urlUtils';
 import { MenuKeys, RootState } from 'src/dashboard/types';
 import { HeaderDropdownProps } from 'src/dashboard/components/Header/types';
+import getOwnerName from 'src/utils/getOwnerName';
 
 export const useHeaderActionsMenu = ({
   customCss,
@@ -53,6 +54,10 @@ export const useHeaderActionsMenu = ({
   userCanSave,
   userCanCurate,
   isLoading,
+  isMobile,
+  isStarred,
+  isPublished,
+  saveFaveStar,
   lastModifiedTime,
   addSuccessToast,
   addDangerToast,
@@ -105,6 +110,11 @@ export const useHeaderActionsMenu = ({
         case MenuKeys.ManageEmbedded:
           manageEmbedded();
           break;
+        case 'toggle-favorite':
+          if (saveFaveStar) {
+            saveFaveStar(dashboardId, isStarred);
+          }
+          break;
         default:
           break;
       }
@@ -116,6 +126,10 @@ export const useHeaderActionsMenu = ({
       showPropertiesModal,
       showRefreshModal,
       manageEmbedded,
+      saveFaveStar,
+      dashboardId,
+      isStarred,
+      history,
     ],
   );
 
@@ -183,6 +197,46 @@ export const useHeaderActionsMenu = ({
 
     const menuItems: MenuItem[] = [];
 
+    // Mobile-only: show dashboard info items in menu
+    if (isMobile && !editMode) {
+      // Favorite toggle
+      if (saveFaveStar) {
+        menuItems.push({
+          key: 'toggle-favorite',
+          label: isStarred ? t('Remove from favorites') : t('Add to 
favorites'),
+        });
+      }
+
+      // Published status
+      menuItems.push({
+        key: 'status-info',
+        label: isPublished ? t('Status: Published') : t('Status: Draft'),
+        disabled: true,
+      });
+
+      // Owner info
+      const ownerNames =
+        dashboardInfo?.owners?.length > 0
+          ? dashboardInfo.owners.map(getOwnerName).join(', ')
+          : t('None');
+      menuItems.push({
+        key: 'owner-info',
+        label: `${t('Owner')}: ${ownerNames}`,
+        disabled: true,
+      });
+
+      // Last modified
+      const modifiedBy =
+        getOwnerName(dashboardInfo?.changed_by) || t('Not available');
+      menuItems.push({
+        key: 'modified-info',
+        label: `${t('Modified')} ${dashboardInfo?.changed_on_delta_humanized 
|| ''} ${t('by')} ${modifiedBy}`,
+        disabled: true,
+      });
+
+      menuItems.push({ type: 'divider' });
+    }
+
     // Refresh dashboard
     if (!editMode) {
       menuItems.push({
@@ -199,8 +253,8 @@ export const useHeaderActionsMenu = ({
       });
     }
 
-    // Toggle fullscreen
-    if (!editMode && !isEmbedded) {
+    // Toggle fullscreen (hide on mobile)
+    if (!editMode && !isEmbedded && !isMobile) {
       menuItems.push({
         key: MenuKeys.ToggleFullscreen,
         label: getUrlParam(URL_PARAMS.standalone)
@@ -268,15 +322,15 @@ export const useHeaderActionsMenu = ({
 
     // Only add divider if there are items after it
     const hasItemsAfterDivider =
-      (!editMode && reportMenuItem) ||
+      (!editMode && reportMenuItem && !isMobile) ||
       (editMode && !isEmpty(dashboardInfo?.metadata?.filter_scopes));
 
     if (hasItemsAfterDivider) {
       menuItems.push({ type: 'divider' });
     }
 
-    // Report dropdown
-    if (!editMode && reportMenuItem) {
+    // Report dropdown (hide on mobile)
+    if (!editMode && reportMenuItem && !isMobile) {
       menuItems.push(reportMenuItem);
     }
 
@@ -314,11 +368,15 @@ export const useHeaderActionsMenu = ({
     expandedSlices,
     handleMenuClick,
     isLoading,
+    isMobile,
+    isPublished,
+    isStarred,
     lastModifiedTime,
     layout,
     onSave,
     refreshFrequency,
     reportMenuItem,
+    saveFaveStar,
     shareMenuItems,
     shouldPersistRefreshFrequency,
     userCanCurate,
diff --git a/superset-frontend/src/features/home/Menu.tsx 
b/superset-frontend/src/features/home/Menu.tsx
index 99fdadd543..cec2879375 100644
--- a/superset-frontend/src/features/home/Menu.tsx
+++ b/superset-frontend/src/features/home/Menu.tsx
@@ -323,7 +323,18 @@ export function Menu({
   return (
     <StyledHeader className="top" id="main-menu" role="navigation">
       <StyledRow>
-        <StyledCol md={16} xs={screens.md ? 24 : 12}>
+        {/* Mobile: left placeholder for future icon */}
+        {!screens.md && <Col xs={4} />}
+        <StyledCol
+          md={16}
+          xs={screens.md ? 24 : 16}
+          css={
+            !screens.md &&
+            css`
+              justify-content: center;
+            `
+          }
+        >
           <Tooltip
             id="brand-tooltip"
             placement="bottomLeft"
@@ -366,7 +377,7 @@ export function Menu({
             />
           )}
         </StyledCol>
-        <Col md={8} xs={screens.md ? 24 : 12}>
+        <Col md={8} xs={screens.md ? 24 : 4}>
           <RightMenu
             align="flex-end"
             settings={settings}

Reply via email to