Skip to content

[UI] Add DashboardLayout and WidgetPicker components#1706

Open
NSTKrishna wants to merge 6 commits into
layer5io:masterfrom
NSTKrishna:feat/dashboard-layout-mobile-responsive
Open

[UI] Add DashboardLayout and WidgetPicker components#1706
NSTKrishna wants to merge 6 commits into
layer5io:masterfrom
NSTKrishna:feat/dashboard-layout-mobile-responsive

Conversation

@NSTKrishna

@NSTKrishna NSTKrishna commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Description

This PR introduces two new reusable components to @sistent/sistent to support responsive, widget-based dashboard layouts across Meshery and Meshery Cloud.

1. DashboardLayout
A layout wrapper that manages the main content area and a sidebar for configuration/widgets.

  • Responsive Design: On desktop (md+), the sidebar is rendered as a sticky side panel. On mobile (down to md), it transforms into a bottom-sheet using MUI's SwipeableDrawer.
  • Drawer Puller: The mobile drawer includes a swipeable puller handle with an indicator bar for intuitive mobile interaction.
  • Customizable: Accepts props for sidebarWidth, sidebarTopOffset, and sidebarHeight for easy integration with different navigation structures.
  • Scoped Styling: Drawer height and overflow styles are cleanly scoped via the sx prop to avoid polluting other MuiDrawer instances on the page.

2. WidgetPicker
A component for displaying and adding widgets to a layout.

  • Clean Separation: Takes a list of widgetsToAdd and an onAddWidget callback, keeping it completely decoupled from domain logic.
  • Configurable Header: Supports custom background and text colors for its header.
  • Custom Scrollbar: Includes a customized, slim scrollbar for a polished look.
  • Empty State: Gracefully handles the case where all widgets have been added.

Changes Made

  • Added src/custom/DashboardLayout/index.tsx
  • Added src/custom/WidgetPicker/WidgetPicker.tsx
  • Exported both components from src/custom/index.ts, src/custom/index.tsx, and src/index.tsx
  • Removed duplicate heading in mobile DashboardLayout SwipeableDrawer

Related Issues

  • Extracted to resolve code duplication between meshery and meshery-cloud dashboards and properly support mobile views.

Testing Performed

  • Built and tested locally (npm run build, npm test - all 324 tests passing).
  • Validated via npm pack tarball integration in both meshery and meshery-cloud development environments.
  • Confirmed responsive behavior switches correctly at the md breakpoint.
  • Verified that the SwipeableDrawer handles opening/closing correctly without duplicate labeling.

Demo

Screen.Recording.2026-07-13.at.6.43.33.AM.mov
Screen.Recording.2026-07-13.at.10.29.58.AM.mov

Notes for Reviewers

This PR fixes #

Signed commits

  • Yes, I signed my commits.

Introduce a responsive DashboardLayout (sticky sidebar on desktop, bottom SwipeableDrawer on mobile) and a WidgetPicker UI with types for WidgetItem. Added files: src/custom/DashboardLayout/index.tsx, src/custom/WidgetPicker/WidgetPicker.tsx, src/custom/WidgetPicker/index.tsx. Updated exports in src/custom/index.ts, src/custom/index.tsx and root src/index.tsx to re-export the new components and their props/types so they are available from the package API.

Signed-off-by: NSTKrishna <krishnagehlot936@gmail.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces two new custom components: DashboardLayout, which provides a responsive layout with a sticky sidebar on desktop and a swipeable bottom drawer on mobile, and WidgetPicker, which displays a list of available widgets to add. The feedback highlights a critical state desync issue in DashboardLayout where the onClose callback is not triggered when the mobile drawer is closed. Additionally, improvements are suggested for WidgetPicker to enhance type safety by replacing an any type with a more specific type, and to correct a discrepancy in the JSDoc documentation regarding the default header background color.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/custom/DashboardLayout/index.tsx
Comment thread src/custom/DashboardLayout/index.tsx Outdated
Comment thread src/custom/WidgetPicker/WidgetPicker.tsx Outdated
Comment thread src/custom/WidgetPicker/WidgetPicker.tsx Outdated
Invoke the optional onClose callback when the mobile drawer is closed (in SwipeableDrawer.onClose and the header toggle). Remove an unused Drawer import. Improve WidgetPicker typings: use unknown for the extra properties index signature and change onAddWidget to accept the widget payload without its 'key'. Also update the headerBackgroundColor JSDoc default. These changes ensure proper close propagation and stronger type safety.

Signed-off-by: NSTKrishna <krishnagehlot936@gmail.com>
@NSTKrishna NSTKrishna requested a review from Copilot July 13, 2026 01:33

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@NSTKrishna NSTKrishna requested a review from rishiraj38 July 13, 2026 01:48
Remove the isSidebarOpen condition from the mobile SwipeableDrawer to ensure the drawer is always displayed on mobile devices, regardless of sidebar state.

Signed-off-by: NSTKrishna <krishnagehlot936@gmail.com>
Only expose the swipe area when the sidebar is open, and stop firing the layout `onClose` callback from mobile drawer toggles. This keeps mobile drawer state changes local while preserving the wider sidebar interaction area when appropriate.

Signed-off-by: NSTKrishna <krishnagehlot936@gmail.com>
Drops the unused `onClose` prop from `DashboardLayout`'s public props and implementation, simplifying the component API.

Signed-off-by: NSTKrishna <krishnagehlot936@gmail.com>

@Katotodan Katotodan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@NSTKrishna, thanks for the work.
Can you consider adding some accessibility features to clickable elements of this PR?

Comment on lines +40 to +49
const [isMobileDrawerOpen, setIsMobileDrawerOpen] = useState(false);
const drawerBleeding = 56;

useEffect(() => {
if (isSidebarOpen) {
setIsMobileDrawerOpen(true);
} else {
setIsMobileDrawerOpen(false);
}
}, [isSidebarOpen]);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my understanding, the DashboardLayout can be opened or closed in two different ways:

  • The parent component controls it through the isSidebarOpen prop.
  • The DashboardLayout also updates its own state when the user interacts with the SwipeableDrawer.

Could this lead to state inconsistencies or bugs in the future? For example, the drawer could be closed from within DashboardLayout while the parent component still considers it open. Would it make sense to have a single source of truth for the open state (for example, by notifying the parent of open/close events) so both remain synchronized?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants