Skip to content

Conversation

@fmontes
Copy link
Member

@fmontes fmontes commented Dec 24, 2025

  • Redesigned Usage Dashboard UI: Updated layout with card-based design, improved spacing, and added "Last Updated" timestamp with development mode indicator
  • Refactored DotUsageService: Moved service from portlets to data-access library for better reusability and added comprehensive unit tests
  • Implemented local state management: Replaced service-level signals with component-level state for better encapsulation
  • Enhanced loading and error states: Added skeleton loaders and improved error handling UI with retry functionality
  • Added "Refresh Data" button: New refresh functionality with localization support for last updated timestamp

Before

image

After

image

- 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.
- 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.
@fmontes fmontes linked an issue Dec 24, 2025 that may be closed by this pull request
6 tasks
@fmontes fmontes changed the title Issue #34166 usage UI Update usage dashboard UI to match official dotCMS UI Dec 24, 2025
@fmontes fmontes requested review from a team, KevinDavilaDotCMS, Copilot, dario-daza, rjvelazco and spbolton and removed request for a team December 24, 2025 18:52
Copy link
Contributor

Copilot AI left a 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

<p-card>
<ng-template pTemplate="header">
<h3 class="flex align-items-center gap-2">
<i class="pi pi-exclamation-triangle"></i>
Copy link

Copilot AI Dec 24, 2025

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".

Suggested change
<i class="pi pi-exclamation-triangle"></i>
<i
class="pi pi-exclamation-triangle"
role="img"
[attr.aria-label]="'usage.dashboard.error.title' | dm"></i>

Copilot uses AI. Check for mistakes.
</p-card>
}
@if (loading()) {
<div class="flex flex-column gap-6">
Copy link

Copilot AI Dec 24, 2025

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.

Suggested change
<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>

Copilot uses AI. Check for mistakes.
Comment on lines 75 to 99
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' });
});
Copy link

Copilot AI Dec 24, 2025

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.

Copilot uses AI. Check for mistakes.
Comment on lines 50 to 63
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);
}
});
Copy link

Copilot AI Dec 24, 2025

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.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[TASK] Update usage dashboard UI to match official dotCMS UI

2 participants