feat(dashboard): rearrange panels via drag and drop - #2611
Conversation
Panels can now be reordered directly on the dashboard by dragging their header icon, in the same or into another column. The new order is saved to the same layout settings used by the settings dialog, so both stay in sync. Hidden panels and panels of currently unavailable services keep their position relative to their stored neighbours. Signed-off-by: Åsmund Collin <aakjaergaard@gmail.com>
|
Hi @Hannott, thanks for your interest in contributing to Mainsail! 👋 This pull request has been automatically closed because pull requests may only be opened by vouched contributors, and you are not yet on our vouched list. This is not a rejection of your work. A maintainer can vouch for you and once that happens, simply reopen this PR or comment Please see our contributing guidelines for more details: |
📝 WalkthroughWalkthroughChangesThe dashboard now renders responsive columns with cross-column draggable panels. It merges stored layouts, preserves panel metadata, resizes drag clones, and persists reordered columns. Tests cover layout merging. Panel header icons receive a CSS class when rendered from the ChangesDashboard layout
Sequence Diagram(s)sequenceDiagram
participant Dashboard
participant draggable
participant gui_saveSetting
Dashboard->>draggable: Render panels in responsive columns
draggable->>Dashboard: Emit drag start and drag end events
Dashboard->>Dashboard: Merge stored and reordered panels
Dashboard->>gui_saveSetting: Save the merged column layout
Possibly related issues
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
20260726-2251-39.6646299.mp4screen-20260727-144625-1785156379169.mp4 |
|
/recheck |
Fold the global style block back into the scoped one. The three selectors that reach into the panel go through ::v-deep, the rules for the dropzone and for the dragged panel itself match the scoped elements directly. Signed-off-by: Åsmund Collin <aakjaergaard@gmail.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Signed-off-by: Åsmund Collin <aakjaergaard@gmail.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Only one viewport is rendered at a time, so the drag group never had to be viewport specific. The group itself stays, sortable rejects drops between two lists that have no group name. Signed-off-by: Åsmund Collin <aakjaergaard@gmail.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
develop already carried the original squashed macros fix (30cd662) and an earlier draft of the dashboard drag and drop feature (e617487). Brings both up to the state of the currently open upstream PRs after review: - SettingsMacrosTabExpert.vue: macroListLoaded now treats a genuinely empty, fully loaded macro list as loaded instead of requiring allMacros.length > 0, so real deletions are reported once Klipper is ready rather than only once at least one macro exists. - Dashboard.vue / store/gui/getters.ts: scoped styles use ::v-deep for the three selectors that reach into Panel.vue instead of a global style block, the drag group is a constant instead of a per viewport getter (only one viewport ever renders), and the comment on getStoredPanels is gone, per meteyou's review on mainsail-crew#2611. All other files already matched between develop and the current PR branches. Signed-off-by: Åsmund Collin <aakjaergaard@gmail.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
meteyou
left a comment
There was a problem hiding this comment.
In this case, the location of the tests fits and I think we can merge these tests.
- Move mergeLayout from DashboardMixin to src/pages/dashboardLayout.ts - Move getStoredPanels from the gui store getters to a PageDashboard method - Move the mergeLayout unit tests to tests/pages/dashboardLayout.spec.ts Signed-off-by: Åsmund Collin <aakjaergaard@gmail.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/pages/Dashboard.vue (1)
155-160: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winExtract the duplicated
layoutNameconstruction into one helper.
getStoredPanels(Line 156) andsaveColumn(Line 205) both computecolumn ? \${viewport}Layout${column}` : `${viewport}Layout`` independently. Keeping one formula in one place avoids the two implementations drifting apart if the naming convention changes.♻️ Proposed refactor
+ getLayoutName(viewport: string, column: number): keyof GuiStateDashboard { + return (column ? `${viewport}Layout${column}` : `${viewport}Layout`) as keyof GuiStateDashboard + } + getStoredPanels(viewport: string, column: number): GuiStateLayoutoption[] { - const layoutName = (column ? `${viewport}Layout${column}` : `${viewport}Layout`) as keyof GuiStateDashboard + const layoutName = this.getLayoutName(viewport, column) const panels = this.$store.state.gui.dashboard[layoutName] as GuiStateLayoutoption[] return panels?.filter((element) => element !== null) ?? [] }saveColumn(column: number, panels: GuiStateLayoutoption[]) { - const layoutName = column ? `${this.viewport}Layout${column}` : `${this.viewport}Layout` + const layoutName = this.getLayoutName(this.viewport, column) const storedPanels = this.getStoredPanels(this.viewport, column) this.$store.dispatch('gui/saveSetting', { name: `dashboard.${layoutName}`, value: this.mergeLayout(storedPanels, this.panelsByColumn[column] ?? [], panels), }) }Also applies to: 204-212
🤖 Prompt for 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. In `@src/pages/Dashboard.vue` around lines 155 - 160, Extract the shared layout-name construction used by getStoredPanels and saveColumn into a single helper, preserving the existing viewport and optional column naming behavior. Update both methods to call that helper and remove their duplicated inline formula.
🤖 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.
Nitpick comments:
In `@src/pages/Dashboard.vue`:
- Around line 155-160: Extract the shared layout-name construction used by
getStoredPanels and saveColumn into a single helper, preserving the existing
viewport and optional column naming behavior. Update both methods to call that
helper and remove their duplicated inline formula.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 22250c41-e04a-4cde-bc43-6c739ca58fce
📒 Files selected for processing (2)
src/pages/Dashboard.vuetests/pages/Dashboard.spec.ts
Description
This PR adds drag and drop rearranging of panels directly on the dashboard, as an alternative to the sortable lists in the settings dialog.
dashboard.<viewport>Layout<n>settings used by the settings dialog, so both stay in sync. Because the dashboard only renders visible and currently available panels, the reordered list is merged back into the stored layout, so hidden panels and panels of currently unavailable services (e.g. Spoolman offline) keep their position relative to their stored neighbours. The merge logic is covered by unit tests.Related Tickets & Documents
None - feature is described above.
Mobile & Desktop Screenshots/Recordings
A screen recording will be added as a comment below.
[optional] Are there any post-deployment tasks we need to perform?
None.
Signed-off-by: Åsmund Collin aakjaergaard@gmail.com
🤖 This Pull Request was created with the help of Claude Code.