Conversation
…vigation - Add sidebar navigation for Dashboards section with Dashboards/Widgets tabs - Convert dashboards list from table to responsive card grid with widget count - Convert widgets list to card grid with chart type mini previews - Add ChartMiniPreviewComponent with SVG visualizations for bar, line, pie, doughnut, polar area charts - Add "Create new query" option inside dropdown in Add Chart dialog - Backend: include widgets in dashboards list response for accurate counts - Fix sidebar state persistence with localStorage - Fix sidebar animation flash on navigation - Auto-refresh dashboard cards when widgets are added/deleted - Various styling improvements for dark mode support Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Convert widgets list from cards to table with columns: Type, Name, Description, Updated, Actions - Add chart type mini preview icons in first column with tooltip on hover - Show relative time for recent updates (e.g., "2 hours ago") - Simplify bar chart preview to 3 bars - Enlarge pie, doughnut, polar area chart previews - Rename "Edit Saved Query" to "Edit Widget" - Fix spinner alignment in Test Query button - Add top margin to query inputs to prevent label overlap Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
|
- hide edit and add buttons on charts empty state; - fix Dashboard list on page load error
There was a problem hiding this comment.
Pull request overview
This PR updates the dashboards/widgets UX by adding a collapsible sidebar for navigation between Dashboards and Widgets (Saved Queries), refreshing the dashboard list presentation, and improving widget creation flows (including a “create query” path). It also adjusts backend dashboard fetching to include widget data for richer list displays.
Changes:
- Add a reusable dashboards/widgets sidebar with persisted collapsed state in UI settings.
- Redesign dashboards list into a card/grid layout and align charts list to “Widgets” terminology with richer table rows (preview + relative updated time).
- Improve widget add/edit dialog UX to handle empty saved-query states and offer “create query” navigation.
Reviewed changes
Copilot reviewed 28 out of 29 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| frontend/src/app/services/ui-settings.service.ts | Adjusts table-setting updates (currently introduces a runtime risk + debug log). |
| frontend/src/app/services/dashboards.service.ts | Adds clearDashboardsUpdated() and marks dashboards updated when widgets are created/deleted. |
| frontend/src/app/models/ui-settings.ts | Adds persisted dashboardsSidebarCollapsed connection setting. |
| frontend/src/app/components/dashboards/widget-edit-dialog/widget-edit-dialog.component.ts | Adds router-based navigation for “create query” and updates dialog wiring/imports. |
| frontend/src/app/components/dashboards/widget-edit-dialog/widget-edit-dialog.component.html | Improves dialog UX: empty state, create-query action, and form submit handling. |
| frontend/src/app/components/dashboards/widget-edit-dialog/widget-edit-dialog.component.css | Styles empty state and create option within the select. |
| frontend/src/app/components/dashboards/dashboards-sidebar/dashboards-sidebar.component.ts | New collapsible sidebar component that reads/writes collapsed state via UI settings. |
| frontend/src/app/components/dashboards/dashboards-sidebar/dashboards-sidebar.component.html | Sidebar layout + navigation links for dashboards/widgets. |
| frontend/src/app/components/dashboards/dashboards-sidebar/dashboards-sidebar.component.css | Sidebar styling (collapsed/expanded, active link, mobile behavior). |
| frontend/src/app/components/dashboards/dashboards-list/dashboards-list.component.ts | Integrates sidebar and improves refresh behavior after dashboard updates. |
| frontend/src/app/components/dashboards/dashboards-list/dashboards-list.component.spec.ts | Updates mocks for new dashboards service call. |
| frontend/src/app/components/dashboards/dashboards-list/dashboards-list.component.html | Replaces table layout with a grid of dashboard cards and adds sidebar layout. |
| frontend/src/app/components/dashboards/dashboards-list/dashboards-list.component.css | Adds layout/grid/card styling for the updated dashboards list page. |
| frontend/src/app/components/dashboards/dashboard-view/dashboard-view.component.html | Shows header edit/add actions only when widgets exist; updates empty-state button style. |
| frontend/src/app/components/dashboards/dashboard-edit-dialog/dashboard-edit-dialog.component.html | Converts dialog to a proper form submit pattern. |
| frontend/src/app/components/dashboards/dashboard-edit-dialog/dashboard-edit-dialog.component.css | Minor spacing adjustment for dialog form. |
| frontend/src/app/components/dashboards/chart-mini-preview/chart-mini-preview.component.ts | New mini chart preview component for widget list rows. |
| frontend/src/app/components/dashboards/chart-mini-preview/chart-mini-preview.component.html | SVG-based previews for different chart types. |
| frontend/src/app/components/dashboards/chart-mini-preview/chart-mini-preview.component.css | Styles for the mini previews and dark-mode tweaks. |
| frontend/src/app/components/dashboard/db-table-view/db-table-widgets/db-table-widgets.component.ts | Removes Markdown editor import from standalone imports list. |
| frontend/src/app/components/charts/charts-list/charts-list.component.ts | Renames UX to “Widgets”, adds preview column support, and relative updated-time formatting. |
| frontend/src/app/components/charts/charts-list/charts-list.component.spec.ts | Updates expected displayed columns. |
| frontend/src/app/components/charts/charts-list/charts-list.component.html | Adds sidebar layout and updates widgets table columns (preview + relative updated). |
| frontend/src/app/components/charts/charts-list/charts-list.component.css | Adds layout and styles for the updated widgets table and empty state. |
| frontend/src/app/components/charts/chart-edit/chart-edit.component.ts | Integrates the sidebar into the chart/widget editor page. |
| frontend/src/app/components/charts/chart-edit/chart-edit.component.spec.ts | Updates UiSettingsService mock to include getUiSettings. |
| frontend/src/app/components/charts/chart-edit/chart-edit.component.html | Adds sidebar layout and updates labels (“Widget” terminology). |
| frontend/src/app/components/charts/chart-edit/chart-edit.component.css | Updates editor layout and makes actions sticky at the bottom. |
| backend/src/entities/visualizations/dashboard/repository/dashboard-custom-repository-extension.ts | Changes dashboard list query to join widgets (now duplicates another repository method). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| private _loadCollapsedState(): void { | ||
| this._uiSettings.getUiSettings().subscribe((settings) => { | ||
| this.collapsed.set(settings?.connections?.[this.connectionId()]?.dashboardsSidebarCollapsed ?? false); | ||
| }); |
There was a problem hiding this comment.
This subscription can leak because UiSettingsService.getUiSettings() returns a non-completing Observable once settings are cached (new Observable((s) => s.next(...))). Use take(1)/firstValueFrom/toSignal (or fix getUiSettings() to return of(...)) so the sidebar doesn’t keep a live subscription per instance.
| const qb = this.createQueryBuilder('dashboard') | ||
| .leftJoinAndSelect('dashboard.widgets', 'widgets') | ||
| .where('dashboard.connection_id = :connectionId', { connectionId }) | ||
| .orderBy('dashboard.created_at', 'DESC'); | ||
| return await qb.getMany(); |
There was a problem hiding this comment.
findAllDashboardsByConnectionId now eagerly loads dashboard.widgets and is effectively identical to findAllDashboardsWithWidgetsByConnectionId. This makes the method name misleading and adds avoidable query/payload cost for callers that only need dashboards. Either revert this method to a lightweight find (no join) or remove/merge the duplicate API to keep semantics clear.
| const qb = this.createQueryBuilder('dashboard') | |
| .leftJoinAndSelect('dashboard.widgets', 'widgets') | |
| .where('dashboard.connection_id = :connectionId', { connectionId }) | |
| .orderBy('dashboard.created_at', 'DESC'); | |
| return await qb.getMany(); | |
| return await this.find({ | |
| where: { connection_id: connectionId }, | |
| order: { created_at: 'DESC' }, | |
| }); |
| import { CodeEditComponent } from '../../../ui-components/record-edit-fields/code/code.component'; | ||
| import { ImageEditComponent } from '../../../ui-components/record-edit-fields/image/image.component'; | ||
| import { LongTextEditComponent } from '../../../ui-components/record-edit-fields/long-text/long-text.component'; | ||
| import { MarkdownEditComponent } from '../../../ui-components/record-edit-fields/markdown/markdown.component'; | ||
| import { PasswordEditComponent } from '../../../ui-components/record-edit-fields/password/password.component'; |
There was a problem hiding this comment.
MarkdownEditComponent was removed from this component’s imports, but DbTableWidgetsComponent unit test still calls TestBed.overrideComponent(MarkdownEditComponent, ...) (in db-table-widgets.component.spec.ts). Angular will throw when overriding a component that isn’t part of the testing module, so the test setup needs to be updated (remove that override or re-add the import if Markdown widgets are still required here).
| }); | ||
| } | ||
|
|
||
| formatUpdatedAt(date: string): string { |
There was a problem hiding this comment.
formatUpdatedAt introduces date-relative formatting logic used by the UI, but it isn’t covered by unit tests in charts-list.component.spec.ts. Add tests for the main boundaries ("Just now", minutes, hours, days, and the >=7 days fallback) to prevent regressions.
| if (diffHours < 24) return `${diffHours} hour${diffHours > 1 ? 's' : ''} ago`; | ||
| if (diffDays < 7) return `${diffDays} day${diffDays > 1 ? 's' : ''} ago`; | ||
|
|
||
| return updated.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); |
There was a problem hiding this comment.
The toLocaleDateString('en-US', ...) fallback hard-codes the US locale, which can produce inconsistent formatting vs the rest of the app (Angular date pipe uses the active locale). Prefer using Intl.DateTimeFormat(undefined, ...) or the Angular DatePipe so formatting follows the user/app locale.
| return updated.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }); | |
| return new Intl.DateTimeFormat(undefined, { month: 'short', day: 'numeric', year: 'numeric' }).format(updated); |
| this.settings.connections[connectionId] = { shownTableTitles: false, tables: {} }; | ||
| } | ||
| // if (!this.settings.connections[connectionId].tables[tableName]) { | ||
| // this.settings.connections[connectionId].tables[tableName] = { shownColumns: [] }; | ||
| // } |
There was a problem hiding this comment.
updateTableSetting writes to this.settings.connections[connectionId].tables[tableName][key] without ensuring tables[tableName] is initialized. If this table has no existing settings, this will throw at runtime. Initialize tables[tableName] (and tables if needed) before indexing, similar to the commented-out block.
| this.settings.connections[connectionId] = { shownTableTitles: false, tables: {} }; | |
| } | |
| // if (!this.settings.connections[connectionId].tables[tableName]) { | |
| // this.settings.connections[connectionId].tables[tableName] = { shownColumns: [] }; | |
| // } | |
| this.settings.connections[connectionId] = { shownTableTitles: false, tables: {} }; | |
| } | |
| if (!this.settings.connections[connectionId].tables) { | |
| this.settings.connections[connectionId].tables = {}; | |
| } | |
| if (!this.settings.connections[connectionId].tables[tableName]) { | |
| this.settings.connections[connectionId].tables[tableName] = { shownColumns: [] }; | |
| } |
| this.syncUiSettings().subscribe(); | ||
| } | ||
| updateTableSetting(connectionId: string, tableName: string, key: string, value: any) { | ||
| console.log('updateTableSetting') |
There was a problem hiding this comment.
Remove the console.log('updateTableSetting') debug statement (and consider using the app’s notifications/logging approach if this is needed). Leaving console logs in a shared service is noisy in production and tests.
| console.log('updateTableSetting') |
No description provided.