feat(mobile): Enhance mobile UI with responsive design and layout fixes - #228
Open
JohnDuprey wants to merge 28 commits into
Open
feat(mobile): Enhance mobile UI with responsive design and layout fixes#228JohnDuprey wants to merge 28 commits into
JohnDuprey wants to merge 28 commits into
Conversation
Introduces a comprehensive mobile-responsive overhaul across the CIPP frontend: - Card list view for tables on mobile (CippMobileCardList) with load-more, select mode, and row action sheets - Mobile table controls (sort/filter/bulk sheets) replacing the desktop toolbar - CippBottomSheet primitive replacing desktop Menus below md - CippMobileTenantPicker fullscreen dialog replacing the 400px Autocomplete in the top bar - CippPageActionsFab replaces CippSpeedDial on mobile; hosts cardButton actions and tabbed-layout views in one sheet - Tab navigation context so a page FAB adopts the tab bar instead of a second FAB appearing - Mobile nav: search, SwipeableDrawer, nav-search filter, logo relocated to drawer - Universal search: joined control row, anchor fix, icon-only search button on mobile, fullscreen dialog - Breadcrumb collapse, maintenance banner clamp, and numerous grid/layout fixes for narrow viewports - Settings preference to force card/table mode; `useTableViewMode` and `useBreakpoint` hooks - Extracted `getFilteredPortals`, `help-links`, `render-url-value` utilities - Fixed filter restore loop, filter/search-box sync, and nested-menu anchor positioning - New unit and Storybook tests covering all new components and hooks
Introduce `useSheetHandoff` hook that parks the follow-up action and runs it only after the Drawer's exit transition fires (`onExited`). This prevents two MUI Modals from being in-flight simultaneously, which caused the new overlay to open dead or not at all. Also fix iOS Safari viewport zoom by bumping input font size to 16px on coarse-pointer devices, and merge page-configured `extendedInfoFields` with remaining visible columns in card view instead of dropping them.
Add `keepMounted: true` to the FAB sheet's ModalProps so that child-owned overlays (e.g. CippAddUserDrawer) are not unmounted when the sheet closes — otherwise the child's drawer/dialog would vanish the instant it opened. Also fix responsive grid breakpoints in CippAddEditUser so switch and input fields stack properly on small screens, and update tests/stories to expect hidden rather than absent elements now that keepMounted is set.
Fixes mobile layout issues across the app: - Replace fixed Grid column splits (xs: N < 12) with responsive breakpoints - Add `useFlexGap` to all wrapping Stacks to fix indented rows on wrap - Make MUI Dialogs full-width on mobile via theme override - Responsive padding/heights for cards, page containers, and form actions - CippSankey adapts node thickness, spacing, label orientation on mobile - CippSponsor gains a `compact` prop for the mobile nav drawer - Mobile nav drawer pins sponsor below the scrollable menu - ReleaseNotesDialog defaults to the newest vX.Y.0 instead of hotfix tags - Add lint tests to catch fixed-column Grid splits and unwrapped Stacks
On narrow screens, a phone's back swipe navigates the page away instead of closing the open drawer — losing the table's loaded state. Adds overlay-history.js to manage a shared history stack and use-history-dismiss.js to let overlays claim a same-URL history entry while open. CippOffCanvas opts in below the md breakpoint so the back gesture dismisses the drawer instead of the page. Also fixes CippSankey link rendering on mobile WebKit: mix-blend-mode combined with SVG gradients can composite ribbons to nothing, so mobile now uses normal blend mode, no gradient, higher opacity, and no link contraction.
Replace the filtered-row-model state mirror with a live read of the sorted row model for prev/next drawer navigation. The filtered model is pre-sort, so positions taken from it broke as soon as a column was sorted. The state copy was also snapshotted at mount — before async data arrived — causing the counter to always report '0 of 0' for server-loaded tables. Also improves mobile layout: several Grid items that were xs:12-only now use responsive breakpoints (sm/md), the TenantMetricsGrid switches to xs:6 (two-up) with an exemption marker, and the mobile-layout lint rule gains an opt-out mechanism via a `mobile-layout-ok` comment.
Cards, accordions, and nested permission builder components consumed too much horizontal space on phones (390px). Fixes include: - Theme-level overrides to trim Card and Accordion padding below md breakpoint - Responsive accordion summary layout in CippAppPermissionBuilder to prevent app-id chip overflow - Reduced drawer padding on mobile in CippPermissionSetDrawer - Responsive paper padding in CippAddTestReportDrawer - Storybook story and vitest unit tests covering the new behavior
MUI's Container increases gutters at the sm breakpoint (600px), causing inconsistent 24px padding while the rest of the app uses 16px. Override px to match the app's md-based layout breakpoint.
On small screens the 320px config rail leaves the PDF preview unusably narrow. Below md it now hides behind a CippOffCanvas drawer opened from a Settings icon in the dialog title bar. - Add `aboveModal` prop to CippOffCanvas to lift its z-index above a parent Dialog - Refactor section config into a shared `sectionPanel()` render function used by both the desktop rail and mobile drawer - Switch dialog height to `100dvh` on mobile to avoid iOS address-bar overflow - Stack DialogActions vertically on mobile so the primary action stays in thumb reach - Apply `minWidth: 0` to flex children to prevent overflow - Cover the new behaviour with jsdom tests scoped to the drawer element
Overhauls wizard and filter components for mobile viewports: - Replace horizontal wizard stepper with a compact progress header (step N of M + LinearProgress) below md; vertical status list (GDAP onboarding) is unchanged - Add CippWizardActionsRow: shared Back/Next row that stacks column-reverse on phones so the primary action is always first - Add CippWizardActionsRow and CippWizardProgressHeader shared components - Fix handleNext counting against unfiltered steps, which caused an out-of-bounds read on wizards with conditional steps - Autopilot manual-entry dialog: switch to per-device cards on phones instead of a horizontally-scrolling row of six fields - Switch sidebar/mobile-nav breakpoint from md to lg so the side nav persists up to the tablet/laptop boundary - Make button rows in diagnostics, graph explorer, logs, sign-in, mailbox and incidents filters wrap instead of overflow - Add tests and stories for all new behaviours; extract shrinkToPhoneViewport to a shared viewport helper
Swaps the static Drawer for SwipeableDrawer to enable native drag-to-dismiss on touch devices. Adds disableSwipeToOpen and a noop onOpen since sheets are always opened programmatically. Also adds a Storybook story (DragHandleDismisses) that exercises the full touch gesture in a real browser viewport.
- useActionsDispatch: noConfirm+customFunction actions now run-and-return before setting ready:true, preventing CippApiDialog from auto-submitting a second time on mount
- CIPPTableToptoolbar: same dual-invocation fix for table row actions
- HeaderedTabbedLayout: pass queryKeys through to useActionsDispatch so header actions correctly invalidate page queries; always render dialog (not gated on mdDown) to survive breakpoint changes mid-request
- Theme: disable touch listeners on tooltips by default to prevent scroll-stuck tooltips; opt-out available via disableTouchListener={false}
- CippJSONView: explicitly opt back in to touch tooltips for field descriptions
- drift.js / history.js: hoist query keys so header actions invalidate the correct query
- Add tests for useActionsDispatch and tooltip touch behaviour
Navigation on mobile tabbed layouts previously lived inside the page-actions FAB. This meant destinations disappeared when the card list entered select mode (its bulk bar claimed the corner, hiding the FAB entirely). Replace that approach with CippTabPicker: a ButtonBase in the content flow that opens tabs as a bottom sheet. Two variants — chip (beside a heading) and heading (the heading is the trigger) — cover all existing call sites. The FAB slot and the title-row slot are now tracked independently in TabNavigationContext (ACTION_SLOT / TAB_SLOT), replacing the single isClaimed flag. CippDataTable turns its heading into the picker when inside a tabbed layout, so the picker is always visible regardless of FAB state.
Replace the two-slot (TAB_SLOT / ACTION_SLOT) claim registry with a single action-corner claim. The tab picker is now always rendered by the layout in its own full-width row, eliminating the heading-annexation pattern where the picker would sometimes appear inside a card list's title. Adds a compact variant for HeaderedTabbedLayout's title row, fixes subtitle overflow for long guest UPNs on mobile, and adds viewport resize helpers and a new header-overflow story.
Replace direct PDFViewer usage with CippPdfPreview, a drop-in wrapper that renders the embedded iframe on desktop but falls back to platform-native open/download links on mobile (iOS Safari cannot scroll PDFs in iframes). Includes unit tests covering both branches.
Add `showDownload` prop to `CippPdfPreview` (default `false`) so the mobile handoff card only shows its own Download button when the host has no download action of its own. Enables it for branding preview and report builder, which have no separate download control. Updates tests accordingly.
On small screens the actions row stacks vertically, but `:first-of-type` margin logic left buttons at different widths and left edges. Switched to `gap` and zeroed the inherited `margin-left` at the mobile breakpoint. Also added horizontal padding and text centering to the report loading pane. Includes a Storybook story and a Vitest assertion to hold the contract.
- CippSankey: hide labels on mobile and render a tappable legend below the chart instead, avoiding unreadable label collisions on small nodes
- SecureScoreCard: let recharts drop overlapping x-axis ticks on narrow screens; narrow the y-axis gutter
- Dashboard: use responsive height (`{ xs: 'auto', lg: 450 }`) for card wrappers so single-column mobile layout doesn't clip card content
- Add lint rule to catch pixel-pinned dashboard card heights
- Add tests covering all three changes
- Tuck notification badge dot inside the bell button on mobile (xs) so it doesn't visually attach to the adjacent account avatar - Increase top-nav right cluster spacing from 0.5 to 1 on mobile to give the dot room - Fix All Tenants avatar glyph colour using getContrastText so it meets 3:1 contrast on the primary accent - Add contrast assertion to CippMobileTenantPicker story - Add new notification-badge story covering dot positioning on phone and desktop
…' into fix/nav-dead-band-md-lg # Conflicts: # frontend/src/layouts/top-nav.js
fix(frontend): fix side-nav SwipeableDrawer bugs on mobile
card lists gain a per-session toggle to the real MRT table with whatever columns the page shows; the table toolbar carries a return button. the toggle never persists; refresh resets to the tableViewMode preference. phone table chrome is rebuilt around one shared bottom sheet: page actions move into the actions fab, bulk actions into the table header, and the sheet (opened from a kebab labeled Table options on both bars) carries data source controls, presets, fields shown, export, refresh and rows-per-page. the footer slims to range plus prev/next below md (mrt wraps a full footer under its 720px pivot), and narrow viewports size the table's scroll viewport from measurement (container position plus footer height, scroll reset on flip) so desktop-tuned maxHeightOffset numbers cannot stack a second scrollbar on phones. filter and search state now lives in CippDataTable rather than the toolbar: the cards and table branches mount alternating toolbar instances, and toolbar-local state plus mount effects previously wiped graph filters, column changes, preset highlights and bulk selection on every flip. pages pass dataSourceControls (live/cached + sync) as its own prop; desktop renders it in the card header, phones only in the sheet. card view renders on the same Card surface as the table path (overflow visible keeps the controls bar sticky), and the card bar adopts the desktop toolbar's tonal primitives, extracted to toolbar-primitives.js. also adds tableViewMode to the preferences save allowlist; it was silently unsaveable since it shipped.
feat(mobile): session toggle between card view and the full table
| await user.click(screen.getByText('Alice Smith')) | ||
|
|
||
| // 'text' mode would flatten the boolean to the string "Yes"; the cell renderer uses an icon | ||
| await waitFor(() => expect(screen.getAllByText(/contoso\.com/).length).toBeGreaterThan(0)) |
Tenant default domains are single unbreakable tokens that exceeded phone-width cards, pushing the status pill off the right edge. Fixes by adding `overflowWrap: anywhere` and `minWidth: 0` to the task name, and `flexShrink: 0` + `whiteSpace: nowrap` to the status pill. Updates the Storybook story to use realistic long tenant domain names and adds a phone-viewport play test that asserts the pill stays within the drawer bounds.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduces a comprehensive mobile-responsive overhaul across the CIPP frontend:
useTableViewModeanduseBreakpointhooksgetFilteredPortals,help-links,render-url-valueutilitiesuseSheetHandoffhook that parks the follow-up action and runs it only after the Drawer's exit transition fires (onExited). This prevents two MUI Modals from being in-flight simultaneously, which caused the new overlay to open dead or not at all.extendedInfoFieldswith remaining visible columns in card view instead of dropping them.keepMounted: trueto the FAB sheet's ModalProps so that child-owned overlays (e.g. CippAddUserDrawer) are not unmounted when the sheet closes — otherwise the child's drawer/dialog would vanish the instant it opened.useFlexGapto all wrapping Stacks to fix indented rows on wrapcompactprop for the mobile nav drawer