Skip to content

[UI] Add DashboardLayout and WidgetPicker components - #1706

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

[UI] Add DashboardLayout and WidgetPicker components#1706
NSTKrishna wants to merge 12 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, and structurally integrates a standardized empty state universally across both ecosystems.

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.
  • Accessible Drawer Puller: The mobile drawer includes a swipeable puller handle (styled with the semantic theme.palette.divider token) that is fully keyboard-operable (role="button", tabIndex={0}).
  • 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.

3. Universal WidgetEmptyState Integration
Structurally embedded the newly designed <WidgetEmptyState /> natively into Sistent's core data-display components to automatically standardize empty states across all consumers.

  • ResponsiveDataTable: Intercepts string-based empty messages and safely wraps them in the beautiful empty state, while strictly adhering to MUIDataTableOptions typing to avoid object mutation bugs.
  • PlainCard: Natively renders the empty state when the resources array is empty.

Changes Made

  • Added src/custom/DashboardLayout/DashboardLayout.tsx (abstracted away from the index).
  • Added src/custom/WidgetPicker/WidgetPicker.tsx.
  • Exported all new layout components consistently from src/custom/index.ts, src/custom/index.tsx, and src/index.tsx (named exports).
  • Integrated WidgetEmptyState directly into ResponsiveDataTable.tsx and PlainCard.tsx.
  • Cleaned up the LatestBlogs widget empty state dummy data inside the Meshery consumer.
  • Addressed all CodeRabbit accessibility, typing, and semantic theme feedback.

Related Issues

  • Extracted to resolve code duplication between meshery and meshery-cloud dashboards and properly support mobile views.
  • Ensures uniform empty state UI across all tables and lists in both dashboards without requiring consumer-side widget rewrites.

Testing Performed

  • Built and tested locally (npm run build, npm run lint - all linters passing cleanly).
  • Validated via direct node_modules local link 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 via both swipe and keyboard events.
  • Verified that empty tables and lists (e.g. LatestBlogs) safely trigger the new WidgetEmptyState without causing infinite loops or call stack errors.

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.

Summary by CodeRabbit

  • New Features

    • Added a responsive DashboardLayout with a sticky sidebar on larger screens and a bottom drawer sidebar on mobile.
    • Introduced WidgetPicker to browse and add widgets, including optional thumbnails and customizable header colors (with optional close control).
    • Added WidgetEmptyState for centered empty states with optional icon and action button.
    • Expanded package exports to include DashboardLayout, WidgetPicker, and WidgetEmptyState.
  • UX Improvements

    • Updated PlainCard empty rendering and ResponsiveDataTable “no data” messaging to use WidgetEmptyState.

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 Outdated
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 thread src/custom/DashboardLayout/index.tsx Outdated
@NSTKrishna
NSTKrishna requested review from banana-three-join and removed request for KhushamBansal July 23, 2026 16:33

@banana-three-join banana-three-join 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.

Other than the requested changes, it looks good to me!

Comment thread src/custom/DashboardLayout/index.tsx Outdated
Comment thread src/custom/WidgetPicker/index.tsx Outdated
Comment thread src/custom/DashboardLayout/index.tsx Outdated
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds responsive DashboardLayout, WidgetPicker, and WidgetEmptyState components, integrates standardized empty states into existing widgets, and exposes the components and related types through custom and package entrypoints.

Changes

Dashboard and widget components

Layer / File(s) Summary
Responsive dashboard layout
src/custom/DashboardLayout/*
Adds mobile drawer and desktop sticky-sidebar rendering with synchronized state and configurable sizing.
Widget picker behavior
src/custom/WidgetPicker/*
Adds widget contracts and picker UI with close handling, thumbnails, empty-state messaging, and add-widget callbacks.
Widget empty-state rendering
src/custom/WidgetEmptyState/index.tsx
Adds an ARIA-live status component with optional message, icon, and action button.
Empty-state integrations
src/custom/DashboardWidgets/PlainCard.tsx, src/custom/ResponsiveDataTable.tsx
Uses WidgetEmptyState for empty resources and string no-match table labels, with typed DataTable options.
Public component exports
src/custom/*, src/index.tsx
Exposes the new components and related types through module barrels and the package entrypoint.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: rishiraj38

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main addition of the DashboardLayout and WidgetPicker components.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

Introduces a new `WidgetEmptyState` component with optional icon and action button support, and exports it through both `custom` and root barrels. Refactors `DashboardLayout` into its own file with explicit type/value re-exports and updates mobile sidebar rendering so the drawer is only mounted when the sidebar is open. Also switches `WidgetPicker` to explicit named/type exports for a clearer public API surface.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/custom/DashboardLayout/index.tsx`:
- Around line 104-110: Update the puller Box styling in DashboardLayout to
replace the hard-coded light/dark background colors with the semantic theme
token theme.palette.divider, preserving the existing dimensions and border
radius.
- Around line 82-102: The minimized drawer trigger in DashboardLayout must be
keyboard-operable and accessible. Replace the interactive Box behavior with a
focusable labelled button (or Sistent button) rendered outside the drawer when
minimized, reuse the existing toggle logic, and expose isMobileDrawerOpen
through the button’s expanded state.

In `@src/custom/index.tsx`:
- Line 193: Update the custom barrel in src/custom/index.tsx to re-export
DashboardLayout alongside WidgetPicker, using the existing DashboardLayout
export from the custom domain index; preserve the current exports and ensure the
symbol is available through the feature-local, domain, and root barrel chain.

In `@src/custom/WidgetPicker/WidgetPicker.tsx`:
- Around line 40-52: Update the `WidgetPicker` component’s `Box` `sx` prop to
compose the base styles and `containerSx` as an array, preserving callback and
array-based `SxProps` values instead of spreading `containerSx` into the base
object.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f6f90140-acf6-4123-bd39-b29179641844

📥 Commits

Reviewing files that changed from the base of the PR and between cc1436e and 6eec363.

📒 Files selected for processing (6)
  • src/custom/DashboardLayout/index.tsx
  • src/custom/WidgetPicker/WidgetPicker.tsx
  • src/custom/WidgetPicker/index.tsx
  • src/custom/index.ts
  • src/custom/index.tsx
  • src/index.tsx

Comment thread src/custom/DashboardLayout/index.tsx Outdated
Comment thread src/custom/DashboardLayout/index.tsx Outdated
Comment thread src/custom/index.tsx
Comment thread src/custom/WidgetPicker/WidgetPicker.tsx Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/custom/DashboardLayout/DashboardLayout.tsx`:
- Around line 25-36: Remove the unused onClose prop from DashboardLayoutProps,
delete its callback documentation, and stop destructuring it in DashboardLayout.
Keep the component’s internal close behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 361b392d-3dc7-4524-bcbb-7fac97080c43

📥 Commits

Reviewing files that changed from the base of the PR and between 6eec363 and d24fc97.

📒 Files selected for processing (6)
  • src/custom/DashboardLayout/DashboardLayout.tsx
  • src/custom/DashboardLayout/index.tsx
  • src/custom/WidgetEmptyState/index.tsx
  • src/custom/WidgetPicker/index.tsx
  • src/custom/index.ts
  • src/index.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/custom/index.ts
  • src/index.tsx

Comment thread src/custom/DashboardLayout/DashboardLayout.tsx Outdated
This updates several dashboard-related components for better UX and consistency: DashboardLayout drops an unused `onClose` prop, adds keyboard-accessible sidebar toggle behavior, and uses theme divider color for the drawer handle. PlainCard and ResponsiveDataTable now show `WidgetEmptyState` when content is empty (including table `noMatch` text), and WidgetPicker now merges `containerSx` safely by supporting array/object forms. It also exports `DashboardLayout` from the custom barrel.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/custom/ResponsiveDataTable.tsx`:
- Around line 167-178: Update the options transformation around bodyTextLabels
and updatedOptions to always assign WidgetEmptyState for noMatch, using the
existing string value when provided and a fallback message otherwise. Build a
fresh body object with the resolved noMatch value instead of mutating
bodyTextLabels or any caller-owned options object.
- Around line 163-164: Update the textLabels declaration in ResponsiveDataTable
to use MUIDataTableOptions or a narrow local type whose body.noMatch accepts
string | React.ReactNode. Remove both any casts and the eslint suppression while
preserving the existing fallback to an empty labels object.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0a9896c3-7d47-4e3c-a46f-b9137e960ed3

📥 Commits

Reviewing files that changed from the base of the PR and between d24fc97 and 80ee06b.

📒 Files selected for processing (5)
  • src/custom/DashboardLayout/DashboardLayout.tsx
  • src/custom/DashboardWidgets/PlainCard.tsx
  • src/custom/ResponsiveDataTable.tsx
  • src/custom/WidgetPicker/WidgetPicker.tsx
  • src/custom/index.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/custom/index.tsx
  • src/custom/WidgetPicker/WidgetPicker.tsx

Comment thread src/custom/ResponsiveDataTable.tsx Outdated
Comment thread src/custom/ResponsiveDataTable.tsx Outdated
NSTKrishna and others added 2 commits July 28, 2026 03:06
Use `MUIDataTableOptions` for `ResponsiveDataTableProps.options` instead of `object`, removing `any` casts around `textLabels`. The no-match handling now consistently renders `WidgetEmptyState`, using the provided `body.noMatch` string when available and falling back to `"No data available"`.

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

Copy link
Copy Markdown
Contributor Author

Once this is merged #1653 , we should replace the existing SwipeableDrawer in DashboardLayout with the new BottomSheet

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.

6 participants