Persistence
Dashboard layout is stored per-user in the WorkDesk backend database as a JSON document. It survives logout, browser close, device changes, and WorkDesk version updates. Your layout is exactly as you left it every time you return.
Storage Architecture
The dashboard layout is stored in the WorkDesk_UserDashboardConfig table:
CREATE TABLE WorkDesk_UserDashboardConfig (
UserId UNIQUEIDENTIFIER PRIMARY KEY,
TenantId UNIQUEIDENTIFIER NOT NULL,
TemplateId UNIQUEIDENTIFIER NULL, -- null = user has customized
LayoutJson NVARCHAR(MAX) NOT NULL, -- JSON array of DashboardWidget
LastModified DATETIME2 NOT NULL DEFAULT GETUTCDATE(),
Version INT NOT NULL DEFAULT 1,
INDEX IX_Dashboard_Tenant (TenantId, UserId)
);
Save vs. Auto-Save
| Scenario | When Layout Saves |
|---|---|
| Adding a widget | Immediately after widget is added (auto-save) |
| Dragging/resizing in Edit Mode | When "Save Layout" button is clicked (manual save) |
| Removing a widget | Immediately when widget is removed (auto-save) |
| Widget config changes | When widget settings form is saved (auto-save) |
Cross-Device Behavior
Since layout is stored server-side, the same layout appears on all devices. However, the grid renders differently depending on screen width:
- Desktop (1024px+) — full 3-column grid as configured
- Tablet (768–1023px) — collapses to 2-column grid; 3-column-wide widgets become 2-column-wide
- Mobile (<768px) — single column; all widgets stack vertically in the order they were configured
The configured layout (col, row, w, h values) always represents the desktop 3-column layout. Responsive rendering is handled by the CSS grid system automatically.
Layout Versioning
The Version column in the table increments with each save. This enables future migration support — if a new WorkDesk version adds or removes widget types, the migration service can safely transform stored layout JSON from old versions to the new schema.
Optimistic Save Strategy
// Dashboard layout save — optimistic
async function saveDashboardLayout(widgets: DashboardWidget[]) {
// 1. Immediately update local state (no spinner)
setWidgets(widgets);
// 2. Save to backend in background
try {
await api.put('/workdesk/dashboard', { widgets });
// Success — layout persisted, no UI change needed
} catch (error) {
// Failure — show error + rollback option
showErrorToast(
'Dashboard save failed. Changes may be lost on refresh.',
{ action: 'Retry', onClick: () => saveDashboardLayout(widgets) }
);
}
}
WorkDesk also stores the layout in localStorage as a fallback cache. If the server save fails, the local cache ensures your layout persists within the same browser session. On next session, the server version is authoritative — the local cache is discarded.