fix(dashboard): fix resize, drag-drop, overflow, and add auto-migration
Multiple critical fixes for dashboard v2: **1. ResizeHandler error - updateContainerWidth is not a function** - resizeHandler.js:288 was calling non-existent method - Removed call - containerWidth tracked by ResizeObserver - Resizing now functional **2. DragDrop bug - widgets can't be released** - endDrag() destructured widgets, originalX, originalY from dragState - These fields were never added in startDrag() - Added widgets parameter to initWidget() and startDrag() - Store originalX, originalY, widgets in dragState - dashboardManager now passes current tab widgets - Widgets can now be dropped properly **3. Widget content overflow** - Added base .rpg-widget CSS: overflow: hidden, box-sizing: border-box - Prevents content extending beyond widget bounds - max-width: 100% on children **4. Automatic layout migration** - Old 12-column layouts (w: 8, w: 12) cause 500%+ widths in 2-4 column grid - Added migrateOldLayouts() method - Detects widgets with w > current column count - Runs auto-layout to reposition for responsive grid - Clears and re-renders current tab with new positions - Saves migrated layout automatically **5. Tab rendering** - Implemented renderTabs() method - Displays tab buttons with icons and names - Active state highlighting - Click handlers to switch tabs **6. Collision prevention** - Modified dragDrop endDrag() to check collisions - Same-size widgets: swap positions - Different sizes: revert to original - Prevents overlapping widgets **7. Edit mode fixes** - Fixed edit button to call toggleEditMode() - Added CSS to hide resize handles when not in edit mode - Handles only visible in edit mode **8. Icon-only header buttons** - Auto-Arrange and Edit buttons now icon-only - Saves horizontal space in header All issues from user testing resolved.
This commit is contained in:
@@ -182,6 +182,12 @@ export class DashboardManager {
|
||||
// Measure container width and set up responsive sizing
|
||||
this.setupContainerSizing();
|
||||
|
||||
// Migrate old 12-column layouts to new responsive grid
|
||||
this.migrateOldLayouts();
|
||||
|
||||
// Render tab navigation
|
||||
this.renderTabs();
|
||||
|
||||
console.log('[DashboardManager] All systems initialized');
|
||||
this.notifyChange('initialized');
|
||||
}
|
||||
@@ -256,6 +262,104 @@ export class DashboardManager {
|
||||
console.log('[DashboardManager] Viewport resize listener added');
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate old 12-column layouts to new responsive grid
|
||||
* Detects if any widgets have widths exceeding current column count
|
||||
* and automatically runs auto-layout to fix them
|
||||
*/
|
||||
migrateOldLayouts() {
|
||||
console.log('[DashboardManager] Checking for old layouts to migrate...');
|
||||
|
||||
let needsMigration = false;
|
||||
|
||||
// Check all tabs
|
||||
this.dashboard.tabs.forEach(tab => {
|
||||
if (!tab.widgets || tab.widgets.length === 0) return;
|
||||
|
||||
// Check if any widget has width exceeding current column count
|
||||
tab.widgets.forEach(widget => {
|
||||
if (widget.w > this.gridEngine.columns) {
|
||||
console.warn(`[DashboardManager] Widget ${widget.id} has width ${widget.w} exceeding column count ${this.gridEngine.columns}`);
|
||||
needsMigration = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (needsMigration) {
|
||||
console.log(`[DashboardManager] Migrating tab ${tab.id} to new responsive grid...`);
|
||||
// Run auto-layout on this tab's widgets
|
||||
this.gridEngine.autoLayout(tab.widgets, { preferFullWidth: true });
|
||||
console.log(`[DashboardManager] Tab ${tab.id} migrated successfully`);
|
||||
}
|
||||
});
|
||||
|
||||
if (needsMigration) {
|
||||
// Save migrated layout
|
||||
this.triggerAutoSave();
|
||||
|
||||
// Re-render current tab with new positions
|
||||
this.clearGrid();
|
||||
const currentTab = this.tabManager.getTab(this.currentTabId);
|
||||
if (currentTab && currentTab.widgets) {
|
||||
currentTab.widgets.forEach(widget => {
|
||||
const definition = this.registry.get(widget.type);
|
||||
if (definition) {
|
||||
this.renderWidget(widget, definition);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
console.log('[DashboardManager] Old layouts migrated, saved, and re-rendered');
|
||||
} else {
|
||||
console.log('[DashboardManager] No migration needed');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render tab navigation UI
|
||||
*/
|
||||
renderTabs() {
|
||||
if (!this.tabContainer) {
|
||||
console.warn('[DashboardManager] Tab container not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear existing tabs
|
||||
this.tabContainer.innerHTML = '';
|
||||
|
||||
// Get all tabs sorted by order
|
||||
const tabs = this.tabManager.getTabs();
|
||||
|
||||
if (tabs.length === 0) {
|
||||
console.warn('[DashboardManager] No tabs to render');
|
||||
return;
|
||||
}
|
||||
|
||||
// Create tab buttons
|
||||
tabs.forEach(tab => {
|
||||
const button = document.createElement('button');
|
||||
button.className = 'rpg-dashboard-tab';
|
||||
button.dataset.tabId = tab.id;
|
||||
button.innerHTML = `
|
||||
<span class="rpg-tab-icon">${tab.icon}</span>
|
||||
<span class="rpg-tab-name">${tab.name}</span>
|
||||
`;
|
||||
|
||||
// Mark active tab
|
||||
if (tab.id === this.currentTabId) {
|
||||
button.classList.add('active');
|
||||
}
|
||||
|
||||
// Tab click handler
|
||||
button.addEventListener('click', () => {
|
||||
this.switchTab(tab.id);
|
||||
});
|
||||
|
||||
this.tabContainer.appendChild(button);
|
||||
});
|
||||
|
||||
console.log(`[DashboardManager] Rendered ${tabs.length} tabs`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new widget to the dashboard
|
||||
* @param {string} type - Widget type (must be registered)
|
||||
@@ -425,13 +529,17 @@ export class DashboardManager {
|
||||
// Render widget content
|
||||
this.renderWidgetContent(element, widget, definition);
|
||||
|
||||
// Get current tab's widgets for collision detection
|
||||
const currentTab = this.tabManager.getTab(this.currentTabId);
|
||||
const allWidgets = currentTab ? currentTab.widgets : [];
|
||||
|
||||
// Initialize drag & drop
|
||||
this.dragHandler.initWidget(element, widget, (updated, newX, newY) => {
|
||||
widget.x = newX;
|
||||
widget.y = newY;
|
||||
this.repositionWidget(element, widget);
|
||||
this.triggerAutoSave();
|
||||
});
|
||||
}, allWidgets);
|
||||
|
||||
// Initialize resize
|
||||
this.resizeHandler.initWidget(element, widget, (updated, newW, newH, newX, newY) => {
|
||||
@@ -573,6 +681,9 @@ export class DashboardManager {
|
||||
console.log(`[DashboardManager] Switching to tab: ${tabId}`);
|
||||
this.currentTabId = tabId;
|
||||
|
||||
// Re-render tabs to update active state
|
||||
this.renderTabs();
|
||||
|
||||
// Clear grid
|
||||
this.clearGrid();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user