The OpenKMS frontend is built with ASP.NET Core 8 Blazor Server, providing a rich, interactive user experience with modern web technologies. Components are organized logically to promote reusability, maintainability, and clear separation of concerns.
- Framework: ASP.NET Core 8 Blazor Server
- Language: C# 12
- UI Framework: Bootstrap 5 with custom design system
- Authentication: JWT-based authentication with local storage
- State Management: Component-scoped state with service layer
- Routing: Blazor Router with NavigationManager
openkms-frontend/Components/
├── Auth/ # Authentication components
│ ├── Login.razor # Login page component
│ └── Register.razor # Registration page component
├── Admin/ # Administration components
│ ├── Dashboard.razor # Admin dashboard overview
│ ├── Settings.razor # System settings
│ ├── Trainings.razor # Training management
│ ├── Users.razor # User management
│ └── Reports.razor # System reports
├── Training/ # Training-related components
│ ├── TrainingList.razor # Browse trainings
│ ├── TrainingDetails.razor # Training detail view
│ ├── MyRegistrations.razor # User's training registrations
│ └── Calendar.razor # Training calendar
├── Layout/ # Layout components
│ ├── MainLayout.razor # Main application layout
│ └── NavMenu.razor # Navigation menu
├── Shared/ # Reusable components
│ └── UserCreateModal.razor # User creation modal
└── _Imports.razor # Global component imports
File: Components/Layout/MainLayout.razor
Purpose: Main application layout providing navigation structure and authentication state management.
Key Features:
- Authentication state checking with automatic redirect
- Role-based navigation menu display
- Responsive Bootstrap navbar
- User profile display in header
- Error handling and user data loading
Usage:
// Automatically used as root layout
// Implements role-based navigation accessEvent Handlers:
CheckAuthentication(): Validates user authentication statusLoadUserData(): Loads current user informationLogout(): Handles user logout and cleanup
Parameters/Properties:
showNavbar: Controls navigation visibilitycurrentUser: Current authenticated userUserHasAdminRole: Admin role visibility flag
File: Components/Layout/NavMenu.razor
Purpose: Navigation menu component with collapsible mobile support.
Key Features:
- Responsive mobile-first navigation
- Active route highlighting
- Role-based menu item visibility
- Bootstrap collapse integration
Usage:
// Integrated into MainLayout
// Automatically highlights active routesFile: Components/Auth/Login.razor
Purpose: User authentication page with form validation and error handling.
Key Features:
- Form validation with DataAnnotationsValidator
- Loading state management
- Error message display
- Authentication failure handling
- Automatic redirect on successful login
Usage:
// Navigate to /login for authentication
// Handles credential submission and JWT storageEvent Handlers:
HandleLogin(): Processes login form submissionOnAfterRenderAsync(): Initializes authentication service
Parameters/Properties:
loginRequest: UserLoginRequest modelisLoading: Loading state indicatorshowError: Error visibility flagerrorMessage: Error message content
Example Form:
<EditForm Model="@loginRequest" OnValidSubmit="@HandleLogin">
<DataAnnotationsValidator />
<InputText @bind-Value="loginRequest.Username" />
<InputText type="password" @bind-Value="loginRequest.Password" />
<button type="submit" disabled="@isLoading">Sign in</button>
</EditForm>File: Components/Auth/Register.razor
Purpose: User registration page with comprehensive form validation.
Key Features:
- Multi-step form validation
- Password strength validation
- Confirmation password matching
- Role selection (for admin users)
- Account creation feedback
Usage:
// Navigate to /register for new user creation
// Supports user self-registration and admin creationEvent Handlers:
HandleRegister(): Processes registration form submissionValidatePassword(): Validates password strengthGenerateUsername(): Auto-generates username suggestions
File: Components/Admin/Users.razor
Purpose: User management dashboard with CRUD operations and role-based access control.
Key Features:
- User listing with search and filtering
- Role assignment and status management
- User creation modal integration
- Pagination support
- Bulk operations (active/inactive toggle)
Usage:
// Navigate to /admin/users for user management
// Requires ADMIN role accessKey Methods:
LoadUsers(): Loads user list with filtersShowUserCreateModal(): Opens user creation dialogHandleUserCreated(): Processes modal form submissionToggleUserStatus(): Activates/deactivates users
Data Binding:
// User list data binding
private List<UserResponse> users = new();
// Modal state management
private bool showCreateModal = false;
// Search/filter parameters
private string searchQuery = "";
private UserRole? selectedRole = null;
private bool? activeFilter = true;File: Components/Admin/Dashboard.razor
Purpose: Administrative overview dashboard with system metrics and analytics.
Key Features:
- Real-time statistics cards
- User engagement metrics
- Training completion rates
- System health indicators
- Recent activity feed
- Quick action buttons
Usage:
// Navigate to /admin for dashboard view
// Requires ADMIN role accessData Models:
public class DashboardMetrics
{
public int TotalUsers { get; set; }
public int ActiveUsers { get; set; }
public int TotalTrainings { get; set; }
public int PendingRegistrations { get; set; }
public int CompletedTrainingsThisMonth { get; set; }
}File: Components/Admin/Settings.razor
Purpose: System configuration and settings management.
Key Features:
- Application-wide settings configuration
- Email notification settings
- Security policy configuration
- Integration setup (LDAP, OAuth)
- Backup configuration
Usage:
// Navigate to /admin/settings for configuration
// Requires ADMIN role accessFile: Components/Training/TrainingList.razor
Purpose: Training program browsing and discovery interface.
Key Features:
- Search and advanced filtering
- Grid/list view toggle
- Category and level filters
- Credit information display
- Registration status indicators
- Pagination support
Usage:
// Navigate to /trainings for training browsing
// Available to all authenticated usersEvent Handlers:
HandleSearch(): Processes search queriesHandleFilterChange(): Updates filter parametersRegisterForTraining(): Handles training registration
Search Implementation:
// Search input with two-way binding
<InputText id="search" @bind-Value="searchText" placeholder="Search trainings..." />
// Filter dropdowns
<InputSelect @bind-Value="selectedCategory">
<option value="">All Categories</option>
<option value="SECURITY">Security</option>
<option value="LEADERSHIP">Leadership</option>
</InputSelect>File: `Components/Training/TrainingDetails.razor**
Purpose: Detailed training program information and registration interface.
Key Features:
- Training information display
- Schedule information
- Prerequisites listing
- Registration status management
- Materials download
- Feedback submission
Usage:
// Navigate to /trainings/{id} for details
// Parameters: trainingId (from route)Route Parameters:
[Parameter]
public int TrainingId { get; set; }
// Component initialization
protected override async Task OnInitializedAsync()
{
await LoadTrainingDetails();
}File: Components/Training/MyRegistrations.razor
Purpose: User's training registration history and management interface.
Key Features:
- Registration status display
- Certificate generation
- Feedback submission
- Cancellation options
- Completion tracking
Usage:
// Navigate to /my-registrations for personal training management
// Available to all authenticated usersFile: Components/Training/Calendar.razor
Purpose: Training schedule calendar with month/week/day views.
Key Features:
- Multiple view modes (month/week/day)
- Event filtering by category
- Registration links from calendar
- Recurring event support
- Export functionality (PDF, iCal)
Usage:
// Navigate to /calendar for training schedule view
// Available to all authenticated usersCalendar Integration:
// Calendar data source
private List<CalendarEvent> TrainingEvents = new();
// Event click handler
private void HandleEventClick(CalendarEvent @event)
{
NavigationManager.NavigateTo($"/trainings/{@event.TrainingId}");
}File: Components/Shared/UserCreateModal.razor
Purpose: Modal dialog for creating new users with comprehensive form validation.
Key Features:
- Bootstrap modal integration
- Multi-section form organization
- Password visibility toggle
- Real-time validation feedback
- Role-based field visibility
- Form submission handling
Usage:
<!-- In parent component -->
<UserCreateModal OnUserCreated="HandleUserCreated" />
<!-- Event handler in parent component -->
private async Task HandleUserCreated(UserCreateRequest userRequest)
{
// Process user creation
await LoadUsers();
}Parameters:
OnUserCreated: Event callback for successful user creationShowModal: Controls modal visibility (optional)
Form Sections:
- Basic Information: Username, full name, email
- Password Setup: Password with confirmation
- Role Assignment: User role selection
- Organizational Info: Department, office location
Validation Rules:
[Required(ErrorMessage = "Username is required")]
[StringLength(50, ErrorMessage = "Username cannot exceed 50 characters")]
[RegularExpression(@"^[a-zA-Z0-9_]+$", ErrorMessage = "Username can only contain letters, numbers, and underscores")]
public string Username { get; set; } = "";protected override async Task OnInitializedAsync()
{
await LoadData();
}
private async Task LoadData()
{
try
{
IsLoading = true;
Data = await ApiService.GetDataAsync();
}
catch (Exception ex)
{
ErrorMessage = ex.Message;
ShowError = true;
}
finally
{
IsLoading = false;
StateHasChanged();
}
}<EditForm Model="@Model" OnValidSubmit="@HandleValidSubmit">
<DataAnnotationsValidator />
<ValidationSummary />
<div class="form-group">
<label for="field">Field *</label>
<InputText id="field" @bind-Value="Model.Field" class="form-control" />
<ValidationMessage For="@(() => Model.Field)" class="text-danger" />
</div>
<button type="submit" disabled="@isLoading">Submit</button>
</EditForm>@if (IsLoading)
{
<div class="loading-spinner">
<span class="spinner spinner-sm"></span>
Loading...
</div>
}
else if (ShowError)
{
<div class="alert alert-error">
@ErrorMessage
</div>
}
else
{
@* Main component content *@
}<div class="row g-3">
<div class="col-12 col-md-6 col-lg-4">
<!-- Stack on mobile, 50% width on tablet, 33% on desktop -->
</div>
</div>
<div class="d-none d-md-block">
<!-- Hidden on mobile, visible on tablet+ -->
</div>// Authentication service integration
@inject AuthService AuthService
// Authentication check
var isAuthenticated = await AuthService.IsAuthenticatedAsync();
// Get current user
var currentUser = await AuthService.GetCurrentUserAsync();
// Login/Logout
await AuthService.LoginAsync(loginRequest);
await AuthService.LogoutAsync();// Navigation service injection
@inject NavigationManager NavigationManager
// Navigation examples
NavigationManager.NavigateTo("/login");
NavigationManager.NavigateTo($"/trainings/{trainingId}");
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);<!-- Design system variables in CSS -->
:root {
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 1.875rem;
--color-primary: #2563eb;
--color-success: #10b981;
--color-warning: #f59e0b;
--color-error: #ef4444;
}<!-- Bootstrap utility classes -->
<div class="card shadow-sm">
<div class="card-body">
<h5 class="card-title">Title</h5>
<p class="card-text">Content</p>
<button class="btn btn-primary">Action</button>
</div>
</div><!-- Responsive design patterns -->
<div class="row">
<div class="col-12 d-lg-none">Mobile only</div>
<div class="col-12 d-none d-lg-block">Desktop only</div>
</div>- Virtualization: Use
Virtualizecomponent for large lists - Lazy Loading: Implement
if (visible)for complex components - State Management: Keep component state minimal
- Data Caching: Cache API responses appropriately
- Rendering Optimization: Avoid unnecessary
StateHasChanged()calls
protected override void OnParametersSet() { }
protected override void OnAfterRender(bool firstRender) { }
protected override async Task OnInitializedAsync() { }
protected override bool ShouldRender() { return true; }// Dispose resources properly
public class MyComponent : ComponentBase, IDisposable
{
private Timer _timer;
public void Dispose()
{
_timer?.Dispose();
}
}// Testing component rendering
var cut = RenderComponent<MyComponent>();
// Test parameter passing
cut.SetParametersAndRender(parameters => parameters
.Add(p => p.Title, "Test Title"));
// Test event handlers
await cut.Find("button").ClickAsync();
// Assert DOM content
cut.Find("h1").MarkupMatches("<h1>Test Title</h1>");// Test user interaction
await cut.Find("#username").ChangeAsync("testuser");
await cut.Find("#password").ChangeAsync("password123");
await cut.Find("form").SubmitAsync();
// Test navigation
cut.NavigateTo("/login");- Component Design: Single responsibility, focused purpose
- Parameter Validation: Use
[Parameter]with validation attributes - Error Handling: Comprehensive try-catch blocks
- Accessibility: ARIA labels, keyboard navigation support
- Performance: Minimal state, efficient rendering
- Consistent Spacing: Use spacing scale (2, 4, 8, 16px)
- Loading States: Always show loading indicators
- Error Messages: Clear, actionable error feedback
- Mobile First: Design for mobile, enhance for desktop
- Color Usage: Semantic color application (success, error, warning)
- Input Validation: Always validate user input
- Authentication: Check user roles and permissions
- CSRF Protection: Use antiforgery tokens for forms
- XSS Prevention: Properly escape user-generated content
- Secure Storage: Don't store sensitive data in component state
Component Not Rendering:
- Check route configuration in
_Imports.razor - Verify component name and namespace
- Check for compilation errors
State Not Updating:
- Call
StateHasChanged()after state updates - Check if using
@bind-Valuecorrectly - Verify event handler signatures
JavaScript Interop Issues:
- Ensure component is in interactive mode
- Check IJSRuntime injection
- Handle interop exceptions gracefully
API Integration Problems:
- Verify service registration in Program.cs
- Check base URL configuration
- Handle HTTP errors properly
- Update Blazor Server to InteractiveServer render mode
- Migrate to new authentication patterns
- Update component lifecycle methods
- Upgrade to Bootstrap 5 components
- Update namespaces and imports
- Migrate event handlers to new patterns
- Update parameter binding
- Test with new authentication flow
- Verify responsive design
- WebAssembly Support: Hybrid Blazor deployment
- Progressive Web App: Offline support and push notifications
- Real-time Updates: SignalR integration for live updates
- Advanced Search: Elasticsearch integration
- Analytics Dashboard: Enhanced reporting and metrics
- Dark Mode: Theme toggle support
- Advanced Charts: Data visualization components
- Drag & Drop: File upload and dashboard customization
- Keyboard Shortcuts: Enhanced accessibility
- Internationalization: Multi-language support
Last updated: December 1, 2023