-
Notifications
You must be signed in to change notification settings - Fork 481
Update usage dashboard UI to match official dotCMS UI #34168
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
base: main
Are you sure you want to change the base?
Conversation
- Replaced the usage header with a PrimeNG toolbar for better action handling. - Enhanced loading state with a more structured skeleton layout for site metrics, system configuration, and user activity. - Updated error handling to use PrimeNG card components for a cleaner presentation. - Refactored dashboard content layout to utilize flexbox for better responsiveness. - Adjusted SCSS styles to align with new component structure and improve overall styling consistency. This update enhances the user experience and maintains a modern design approach.
…yling - Adjusted skeleton component heights for better visual consistency. - Added margin utility class to paragraph elements within skeleton templates. - Enhanced SCSS styles for skeleton display and h3 elements to improve layout and readability. These changes aim to refine the user interface and enhance the loading experience in the dot-usage-shell component.
…ttpClient providers
- Introduced DotUsageService to fetch usage summary metrics from the backend API. - Implemented error handling for various HTTP status codes. - Added unit tests for DotUsageService to validate summary retrieval and error handling. - Updated dot-usage-shell component to manage loading and error states using signals. - Refactored component tests to utilize the new service structure. These changes enhance the functionality and reliability of the dot-usage feature, ensuring accurate data retrieval and user-friendly error messages.
…ading state management
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.
Pull request overview
This PR redesigns the Usage Dashboard UI to align with the official dotCMS design system, transitioning from service-level to component-level state management and relocating the DotUsageService to the data-access library for better reusability.
Key Changes:
- Moved DotUsageService from portlets library to data-access library with simplified state management
- Redesigned UI with card-based layout, improved spacing, and PrimeNG Toolbar component
- Implemented component-level signal-based state management replacing service-level signals
- Enhanced UX with skeleton loaders, error handling UI, and "Last Updated" timestamp with localization
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
dotCMS/src/main/webapp/WEB-INF/messages/Language.properties |
Added translation key for "Last Updated" label |
core-web/libs/portlets/dot-usage/src/lib/services/dot-usage.service.spec.ts |
Removed old service tests (service moved to data-access) |
core-web/libs/portlets/dot-usage/src/lib/dot-usage-shell/dot-usage-shell.component.ts |
Refactored to use component-level signals instead of service signals, added lastUpdated tracking |
core-web/libs/portlets/dot-usage/src/lib/dot-usage-shell/dot-usage-shell.component.spec.ts |
Updated tests to reflect component-level state management and new UI structure |
core-web/libs/portlets/dot-usage/src/lib/dot-usage-shell/dot-usage-shell.component.scss |
Simplified styles using design tokens, removed extensive custom styling |
core-web/libs/portlets/dot-usage/src/lib/dot-usage-shell/dot-usage-shell.component.html |
Complete UI redesign with PrimeNG Toolbar, improved skeleton loaders, and card-based layout |
core-web/libs/portlets/dot-usage/src/index.ts |
Removed service export (now exported from data-access) |
core-web/libs/data-access/src/lib/dot-usage/dot-usage.service.ts |
Relocated service with removed signal-based state, made getErrorMessage public |
core-web/libs/data-access/src/lib/dot-usage/dot-usage.service.spec.ts |
New comprehensive test suite for relocated service |
core-web/libs/data-access/src/index.ts |
Added export for DotUsageService |
core-web/libs/portlets/dot-usage/src/lib/dot-usage-shell/dot-usage-shell.component.html
Show resolved
Hide resolved
core-web/libs/portlets/dot-usage/src/lib/dot-usage-shell/dot-usage-shell.component.scss
Show resolved
Hide resolved
| <p-card> | ||
| <ng-template pTemplate="header"> | ||
| <h3 class="flex align-items-center gap-2"> | ||
| <i class="pi pi-exclamation-triangle"></i> |
Copilot
AI
Dec 24, 2025
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.
The error icon lacks an accessible label. Screen reader users won't know what the icon represents. Add an aria-label attribute to the icon element to describe its purpose, such as aria-label="Error".
| <i class="pi pi-exclamation-triangle"></i> | |
| <i | |
| class="pi pi-exclamation-triangle" | |
| role="img" | |
| [attr.aria-label]="'usage.dashboard.error.title' | dm"></i> |
| </p-card> | ||
| } | ||
| @if (loading()) { | ||
| <div class="flex flex-column gap-6"> |
Copilot
AI
Dec 24, 2025
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.
Loading state lacks ARIA live region announcement. Screen reader users won't be notified when data is loading or when loading completes. Consider adding an aria-live region to announce loading state changes, or use aria-busy attribute on the container.
| <div class="flex flex-column gap-6"> | |
| <div | |
| class="flex flex-column gap-6" | |
| role="status" | |
| aria-live="polite" | |
| [attr.aria-busy]="loading()"> | |
| <span class="visually-hidden"> | |
| {{ 'usage.dashboard.loading' | dm }} | |
| </span> |
| it('should handle HTTP errors', (done) => { | ||
| service.getSummary().subscribe({ | ||
| next: () => fail('Should have failed'), | ||
| error: (error) => { | ||
| expect(error.status).toBe(401); | ||
| done(); | ||
| } | ||
| }); | ||
|
|
||
| const req = httpMock.expectOne('/api/v1/usage/summary'); | ||
| req.flush('Unauthorized', { status: 401, statusText: 'Unauthorized' }); | ||
| }); | ||
|
|
||
| it('should handle server errors', (done) => { | ||
| service.getSummary().subscribe({ | ||
| next: () => fail('Should have failed'), | ||
| error: (error) => { | ||
| expect(error.status).toBe(500); | ||
| done(); | ||
| } | ||
| }); | ||
|
|
||
| const req = httpMock.expectOne('/api/v1/usage/summary'); | ||
| req.flush('Internal Server Error', { status: 500, statusText: 'Internal Server Error' }); | ||
| }); |
Copilot
AI
Dec 24, 2025
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.
Tests that trigger error paths don't mock console.error, which will pollute test output with expected error messages. Consider adding a spy on console.error at the beginning of these tests to suppress expected error logging during test execution.
| this.usageService.getSummary().subscribe({ | ||
| next: () => { | ||
| // Data is automatically updated via signals | ||
| next: (summary) => { | ||
| this.summary.set(summary); | ||
| this.loading.set(false); | ||
| this.lastUpdated.set(new Date()); | ||
| }, | ||
| error: (error) => { | ||
| const errorMessage = this.usageService.getErrorMessage(error); | ||
| this.error.set(errorMessage); | ||
| this.errorStatus.set(error.status || null); | ||
| this.loading.set(false); | ||
| console.error('Failed to load usage data:', error); | ||
| } | ||
| }); |
Copilot
AI
Dec 24, 2025
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.
The subscription in loadData() is not managed and could cause memory leaks. Since this component implements OnInit but not OnDestroy, and the component can be destroyed while requests are pending, you should either use the async pipe in the template or implement proper subscription cleanup using takeUntilDestroyed() from @angular/core/rxjs-interop or similar pattern.
Before
After