-
Notifications
You must be signed in to change notification settings - Fork 0
⚡ Dashboard export/import API #56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- POST /api/dashboard/export - Export widgets, layout, and theme to .glance.json - POST /api/dashboard/import/preview - Validate import, detect conflicts, report missing credentials - POST /api/dashboard/import - Import with conflict resolution (overwrite/rename/skip) Supports breakpoint-specific layouts (desktop/tablet/mobile) and theme preservation.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
- DashboardExportModal: Export entire dashboard as .glance.json file - Configurable name, description, author - Downloads JSON file with all widgets, layout, and theme - DashboardImportModal: Import dashboard from .glance.json file - File upload with drag-and-drop support - Preview step showing widgets, layout, theme, credentials - Conflict resolution: overwrite/rename/skip options - Shows missing credentials that need configuration - Import options: layout, theme, clear existing - Success summary with import results - Updated DashboardHeader with dropdown menu for export/import - Mobile-responsive: buttons also available in mobile menu Tested: - Export API creates valid .glance.json - Import with preview shows conflicts and credentials - Conflict resolution works (overwrite/rename/skip) - No console errors
- Add custom_widget_id to WidgetRow interface - Use CredentialRequirement type for credential access - Use type guards for unknown body validation - Use RequestOptions type for http/https requests - Update CLAUDE.md: NEVER use any (strict rule)
Bug fixes: - Fix import skipping multiple instances of same widget - Fix renamed widgets causing false conflicts during import - Extract shared DashboardExportFormat type and validateDashboardFormat function to src/lib/dashboard-format.ts Improvements: - Add typed ExportRequestBody interface for export endpoint - Add 5MB file size limit on import to prevent DoS - Add try-catch around JSON.parse for position data in export Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
| const layout = dashboard.layout as Record<string, unknown>; | ||
| if (!Array.isArray(layout.desktop)) { | ||
| errors.push("Missing or invalid layout.desktop array"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing layout item validation causes NaN grid calculations
Medium Severity
The validateDashboardFormat function checks that layout.desktop is an array but doesn't validate that each item has the required x, y, w, h properties. When a malformed layout item passes validation and is imported, the position object has undefined values. JSON.stringify({x: undefined, ...}) produces '{}'. When the dashboard loads, getMaxY calculates undefined + undefined = NaN, causing NaN to propagate through grid calculations and potentially breaking the dashboard display.
Additional Locations (1)
| } from "@/lib/dashboard-format"; | ||
|
|
||
| // Maximum import file size (5MB) to prevent DoS | ||
| const MAX_IMPORT_SIZE = 5 * 1024 * 1024; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicated constant across import route files
Low Severity
MAX_IMPORT_SIZE constant is defined identically in both preview/route.ts and route.ts. This should be defined once in the shared src/lib/dashboard-format.ts file (which already exists for shared dashboard import/export types and utilities) and imported where needed.
Enhance the import preview to show detailed information before importing: - Widget details section with expandable source/server code previews - Full credential details with type badges and configured/missing status - Theme CSS preview with line counts - Per-widget credential badges and line count indicators Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Move WidgetPreviewDetail, CredentialPreviewDetail, ThemePreviewDetail, WidgetConflict, ImportPreviewResponse, and ImportResponse interfaces to shared dashboard-format.ts to eliminate duplication across API routes and DashboardImportModal. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cursor Bugbot has reviewed your changes and found 4 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
|
|
||
| // Check content length to prevent oversized uploads | ||
| const contentLength = request.headers.get("content-length"); | ||
| if (contentLength && parseInt(contentLength, 10) > MAX_IMPORT_SIZE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
File size limit can be bypassed via header manipulation
Medium Severity
The MAX_IMPORT_SIZE check relies on the client-provided Content-Length header, which can be omitted or spoofed. The condition contentLength && parseInt(...) short-circuits when the header is missing, allowing request.json() to process arbitrarily large payloads. This bypasses the intended DoS protection since malicious clients can send oversized requests without the header or with a falsified small value.
Additional Locations (1)
| } | ||
|
|
||
| const dashboard = dashboardData as DashboardExportFormat; | ||
| const errors: string[] = []; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
|
||
| /** | ||
| * Validates the structure of a dashboard export file | ||
| */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Orphaned JSDoc comment without associated code
Low Severity
Lines 75-77 contain an orphaned JSDoc comment "Validates the structure of a dashboard export file" that doesn't document any code. The actual validateDashboardFormat function has its own JSDoc at lines 161-163. This is a copy-paste artifact.
| </p> | ||
| </div> | ||
| )} | ||
| </div> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drag and drop UI claim lacks implementation handlers
Medium Severity
The file drop zone UI states "or drag and drop here" (line 294) but the div only has an onClick handler with no drag/drop event handlers (onDrop, onDragOver, onDragEnter, onDragLeave). Without onDragOver calling preventDefault(), the browser's default behavior occurs when a file is dropped - navigating to the file URL, which causes the user to leave the application unexpectedly.


Summary
Adds complete dashboard export/import API for sharing dashboards between Glance instances.
Endpoints
POST /api/dashboard/export— Export widgets, layout, and theme to.glance.jsonPOST /api/dashboard/import/preview— Validate import, detect slug conflicts, report missing credentialsPOST /api/dashboard/import— Import with conflict resolution strategiesConflict Resolution
Three strategies supported:
{slug}-1,{slug}-2, etc.Features
Testing
All endpoints tested via curl ✅
UI dialogs for export/import scheduled for Week 3
Note
Medium Risk
Adds new API routes that create/update/delete widget and theme records and introduces a large client-side import UI; mistakes could overwrite existing widgets/layout or allow unintended configuration changes, though access is gated by existing auth and upload size limits.
Overview
Adds full dashboard sharing via new
POST /api/dashboard/export,POST /api/dashboard/import/preview, andPOST /api/dashboard/importendpoints that serialize custom widgets, layout, theme, and required credential metadata to/from.glance.json, with validation, conflict handling (overwrite/rename/skip), and 5MB upload limits.Introduces
DashboardExportModaland a multi-stepDashboardImportModal(previewing widget code, conflicts, theme, and missing credentials) and wires both intoDashboardHeadervia a new Import/Export menu.Tightens typing in
/api/widgets/[slug]/refreshby replacinganywithhttps.RequestOptions, and updates theWidgetRowtype to includecustom_widget_idto support dashboard layout export/import.Written by Cursor Bugbot for commit 0897b2f. This will update automatically on new commits. Configure here.