-
Notifications
You must be signed in to change notification settings - Fork 1
feat: add pluggable dashboard framework #30
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
… governance and rollout features - Create standalone dashboard NuGet packages (Dashboard, Dashboard.UI, Dashboard.Api, Dashboard.Abstractions, Dashboard.Analytics) - Implement full governance UI with lifecycle management, approvals, policies, versions, and audit trail - Add experiment-specific rollout management with staged deployment and progress tracking - Implement multi-tenancy support with pluggable ITenantResolver (HttpHeader, Claim, Subdomain, Composite) - Add authorization delegation via IAuthorizationProvider with claims-based permissions - Create comprehensive API endpoints for experiments, governance, analytics, rollout, and targeting - Migrate dashboard pages from AspireDemo.Web to reusable Dashboard.UI components - Implement real-time killswitch synchronization across dashboard and downstream apps - Add informational messages to governance pages when persistence is not configured - Add XML documentation to resolve all CS1591 warnings - Update blog plugin endpoints to respect killswitch state for proper experiment control - Implement polling mechanism for killswitch state updates every 3 seconds - Add DashboardHost sample application demonstrating dashboard integration - Configure AspireDemo.Web to use embedded dashboard via /dashboard route
…ce and experiment integration - Add IRolloutPersistenceBackplane interface for rollout configuration storage - Implement InMemoryRolloutPersistence for development/testing - Integrate rollout endpoints with IMutableExperimentRegistry for real-time experiment percentage updates - Update rollout advancement to modify actual experiment rollout percentages - Add rollout completion logic that sets experiments to 100% when rollout completes - Add rollout rollback functionality that resets experiments to 0% - Validate target variants exist before creating rollouts - Update RolloutConfiguration and RolloutStageDto models in Dashboard.Abstractions - Migrate ExperimentApiClient to use shared rollout DTOs from Abstractions - Update Rollout.razor UI to use new RolloutConfiguration model - Register InMemoryRolloutPersistence as default implementation in DI - Add tenant-aware rollout configuration storage - Implement pause, resume, restart rollout operations - Add user-facing error messages when persistence not configured
…ations - Remove required constraint from RolloutConfiguration.ExperimentName to allow JSON deserialization - Add Rollout property to Dashboard.Abstractions.ExperimentInfo - Update DefaultDashboardDataProvider to fetch and populate rollout configurations from IRolloutPersistenceBackplane - Inject IRolloutPersistenceBackplane into DefaultDashboardDataProvider constructor - Make GetExperimentsAsync and GetExperimentAsync async to support rollout data loading - Ensure ExperimentName is populated when returning rollout configurations - Fix "JSON deserialization for type 'RolloutConfiguration' was missing required properties" error
- Add ASP.NET Core Identity with Entity Framework Core and SQLite - Create ApplicationUser model with custom properties (FullName, Department, permissions) - Implement ApplicationDbContext for Identity data storage - Add IdentitySeeder to create default roles (Admin, Experimenter, Viewer, Analyst) - Seed 4 test users with different roles and permission levels - Create Login page with quick-login buttons for demo users - Create Logout and AccessDenied pages - Configure authentication and authorization middleware in Program.cs - Add authorization policies (CanAccessExperiments, CanModifyExperiments, CanManageRollouts, AdminOnly) - Enable database migration and seeding on application startup Test Users: - admin@experimentdemo.com / Admin123! - Full access - experimenter@experimentdemo.com / Experimenter123! - Can modify experiments - viewer@experimentdemo.com / Viewer123! - Read-only access - analyst@experimentdemo.com / Analyst123! - Analytics focus fix(rollout): improve UI responsiveness and error handling - Add StateHasChanged() calls to ensure UI updates after rollout actions - Add detailed error logging for failed rollout operations - Fix rollout stage initialization when switching between experiments - Improve rollout wizard state management
- Wrap MainLayout in AuthorizeView to require authentication - Add user profile section to sidebar showing authenticated user - Display user avatar, name, and role badge in sidebar - Add color-coded role badges (Admin=red, Experimenter=blue, Analyst=green, Viewer=gray) - Add logout button to sidebar user section - Show "Authentication Required" page for unauthorized users - Enable RequireAuthorization in dashboard options with "CanAccessExperiments" policy - Add CSS styling for sidebar-user section and unauthorized page - Ignore SQLite database files in gitignore The dashboard now requires authentication and displays the current user's information in the sidebar. Unauthorized users see a friendly prompt to sign in.
- Create initial Identity migration with all AspNet* tables - Add ApplicationUser custom properties to schema - Generate migration files for Identity database schema - Fix "SQLite Error 1: no such table: AspNetRoles" error The migrations will now automatically create the Identity tables (AspNetUsers, AspNetRoles, AspNetUserRoles, AspNetUserClaims, etc.) when the application starts.
- Update DashboardMiddleware to redirect unauthenticated users to login page - Add returnUrl query parameter support to preserve original destination - Redirect authenticated users without proper permissions to AccessDenied page - Update Login page to accept and use returnUrl parameter after successful login - Remove full-page AuthorizeView from MainLayout (middleware handles auth now) - Keep AuthorizeView only for sidebar user section display - Wrap MainLayout in CascadingAuthenticationState for proper auth context Authentication Flow: 1. Unauthenticated user visits /dashboard → Redirected to /Account/Login?returnUrl=/dashboard 2. User logs in successfully → Redirected back to /dashboard (or original returnUrl) 3. Authenticated user without permissions → Redirected to /Account/AccessDenied 4. Dashboard pages are now only accessible to authenticated users with proper roles This ensures users cannot see any dashboard content without authentication, and they're automatically redirected back to their intended destination after login.
…uthentication - Added UseExperimentDashboard() method to register middleware before endpoint mapping - Register DashboardOptions as singleton (in addition to IOptions pattern) - Update Program.cs to call UseExperimentDashboard() after UseAuthentication/UseAuthorization - Fixes issue where RequireAuthorization was not being enforced
…ributes - Add MinimalLayout for unauthenticated pages (landing, login, access denied) - Set all Dashboard.UI pages to use Dashboard MainLayout with [Authorize] attribute - Landing page (/) now uses MinimalLayout with no sidebar - Dashboard pages require authentication at component level AND middleware level
…thorizeView support
…mode - Added [SupplyParameterFromForm] attribute to login model for .NET 8+ form handling - Added @rendermode InteractiveServer to Login and Home pages - Added null checks for model in login methods - Fixed form submission issue requiring FormName attribute
…ve mode - InteractiveServer render mode doesn't use FormName/SupplyParameterFromForm - Reverted to simple two-way binding with EditForm - Removed null checks since model is no longer nullable
- Set prerender: false on Login and Home pages - Prevents static SSR phase that requires FormName attribute - Pages now render only in interactive mode
- Added FormName='LoginForm' to EditForm - .NET 8+ requires FormName on all forms for identification - Keep simple model binding without SupplyParameterFromForm for interactive mode
…r demo cards - Added Enhance attribute to EditForm for enhanced navigation - Added AntiforgeryToken component for CSRF protection - Changed demo user cards from div to button type='button' to prevent form submission - Ensures click handlers don't accidentally trigger form post
…nteractive mode - Removed FormName - not needed in fully interactive mode - Removed Enhance - only for static SSR forms - Removed AntiforgeryToken - not needed for SignalR-based forms - Pure interactive Blazor forms work through event handlers, not form posts
…ractive components - Created AccountEndpoints with /api/account/login and /api/account/logout - Login uses traditional HTML form POST to avoid 'headers already started' error - Demo user cards now use individual forms with hidden fields - Logout auto-submits form to logout endpoint - Fixes issue where SignInManager can't set cookies in interactive Blazor components
…iddleware auth - Removed [Authorize] attribute from Dashboard.UI _Imports.razor - Middleware already enforces authentication via DashboardMiddleware - Component-level auth after form POST redirect was causing blank screen - Middleware auth is sufficient and works correctly with form-based login
- Move DefaultLayout parameter from Router to AuthorizeRouteView component - Add comprehensive CSS reset to eliminate browser default margins/padding - Implement dark mode support with media queries and .theme-dark classes - Fix navigation link styling with !important flags for proper rendering - Add cache-busting version parameters to CSS files - Correct DSL editor route from /dashboard/dsl-editor to /dashboard/dsl - Fix @media query syntax in Razor files (use @@media)
- Auto-load current configuration on DSL editor page initialization - Add change detection logic to only show modified experiments in preview - Implement HasChanges() method to compare experiment configurations - Skip unchanged experiments in validation preview panel - Fall back to sample YAML if auto-load fails
- Auto-discover plugins during application initialization - Remove manual 'Discover Plugins' button from UI - Log plugin discovery events to audit trail - Update empty state message to reflect automatic discovery - Plugins are now available immediately upon dashboard access
- Automate termination of running Aspire processes - Clean and rebuild solution - Start AppHost and test endpoints - Provide detailed test results and application URLs
- Add Plugin source type to ExperimentSource enum - Plugin services now appear as experiments in Experiments page - Add visual distinction with purple border and Plugin badge - Support variant activation for plugin implementations - Add Plugins category filter - Convert Source property to string for JSON serialization compatibility - Add SourceEnum internal property for code use with JsonIgnore attribute
- Configure experiment governance in ApiService with in-memory persistence - Set up approval gates for lifecycle state transitions - Initialize governance system with 8 demo experiments on startup - Fix API endpoint paths to include /lifecycle/ segment for governance calls - Add JSON property name attributes to DTOs for correct camelCase deserialization - Create LifecycleHistoryResponse wrapper class to match API response structure - Add StateHasChanged() calls in Lifecycle.razor to trigger UI updates - Implement loading states and error handling in governance UI - Add diagnostic endpoints for troubleshooting governance system - Add debug logging to trace API calls and responses
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 introduces a comprehensive pluggable dashboard framework for managing A/B tests and experiments. The dashboard provides a Hangfire-style embeddable web UI with features including experiment management, analytics, governance workflows, rollout management, targeting rules, and plugin support. The framework supports multi-tenancy through pluggable tenant resolvers and delegates authorization to ASP.NET Core.
Key Changes
- Added complete dashboard infrastructure with middleware, options, and dependency injection setup
- Implemented multi-tenancy support with four tenant resolver strategies (HTTP header, subdomain, claims, composite)
- Created comprehensive test suite including integration tests with WebApplicationFactory
- Built Blazor-based UI components with Monaco editor integration and theme support
Reviewed changes
Copilot reviewed 133 out of 135 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/ExperimentFramework.Dashboard.Tests/*.cs | Integration test suite with factory pattern for dashboard endpoints and configuration |
| src/ExperimentFramework.Dashboard/DashboardOptions.cs | Configuration options class with tenant resolver and authorization settings |
| src/ExperimentFramework.Dashboard/DashboardMiddleware.cs | ASP.NET Core middleware handling tenant resolution and authorization |
| src/ExperimentFramework.Dashboard/ServiceCollectionExtensions.cs | DI registration for dashboard services with default implementations |
| src/ExperimentFramework.Dashboard/EndpointRouteBuilderExtensions.cs | Endpoint mapping extensions for dashboard API routes |
| src/ExperimentFramework.Dashboard/TenantResolvers/*.cs | Four tenant resolver implementations for multi-tenancy scenarios |
| src/ExperimentFramework.Dashboard/Theming/DefaultThemeProvider.cs | Default theme provider with customizable colors |
| src/ExperimentFramework.Dashboard/Persistence/InMemoryRolloutPersistence.cs | In-memory rollout configuration storage |
| src/ExperimentFramework.Dashboard/Data/DefaultDashboardDataProvider.cs | Default data provider bridging experiment registry to dashboard |
| src/ExperimentFramework.Dashboard/Authorization/ClaimsPrincipalAuthProvider.cs | Claims-based authorization provider |
| src/ExperimentFramework.Dashboard.UI/Services/*.cs | UI service layer including API client, state management, code generation, and theming |
| src/ExperimentFramework.Dashboard.UI/Components/**/*.razor | Blazor pages and shared components for the dashboard UI |
| src/ExperimentFramework.Dashboard.UI/wwwroot/*.js | JavaScript interop for Monaco editor and theme management |
| src/ExperimentFramework.Dashboard/DASHBOARD_README.md | Comprehensive documentation with usage examples |
Files not reviewed (1)
- samples/ExperimentFramework.AspireDemo/AspireDemo.Web/Data/Migrations/20260105033931_InitialIdentity.Designer.cs: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
...es/ExperimentFramework.AspireDemo/AspireDemo.ApiService/Services/RuntimeExperimentManager.cs
Outdated
Show resolved
Hide resolved
samples/ExperimentFramework.AspireDemo/AspireDemo.Web/Data/IdentitySeeder.cs
Outdated
Show resolved
Hide resolved
src/ExperimentFramework.Dashboard.Api/Endpoints/RolloutEndpoints.cs
Outdated
Show resolved
Hide resolved
src/ExperimentFramework.Dashboard/TenantResolvers/CompositeTenantResolver.cs
Show resolved
Hide resolved
samples/ExperimentFramework.AspireDemo/AspireDemo.Web/Components/Pages/LiveDemo.razor
Outdated
Show resolved
Hide resolved
src/ExperimentFramework.Dashboard.UI/Components/Pages/Governance/Lifecycle.razor
Show resolved
Hide resolved
src/ExperimentFramework.Dashboard.Api/Endpoints/AnalyticsEndpoints.cs
Outdated
Show resolved
Hide resolved
src/ExperimentFramework.Dashboard.UI/Components/Pages/Rollout.razor
Outdated
Show resolved
Hide resolved
src/ExperimentFramework.Dashboard.UI/Components/Pages/Rollout.razor
Outdated
Show resolved
Hide resolved
samples/ExperimentFramework.AspireDemo/AspireDemo.Web/Pages/Login.cshtml.cs
Fixed
Show fixed
Hide fixed
samples/ExperimentFramework.AspireDemo/AspireDemo.Web/Pages/Login.cshtml.cs
Fixed
Show fixed
Hide fixed
samples/ExperimentFramework.AspireDemo/AspireDemo.Web/Pages/Login.cshtml.cs
Fixed
Show fixed
Hide fixed
samples/ExperimentFramework.AspireDemo/AspireDemo.Web/Pages/Login.cshtml.cs
Fixed
Show fixed
Hide fixed
samples/ExperimentFramework.AspireDemo/AspireDemo.Web/Pages/Login.cshtml.cs
Dismissed
Show dismissed
Hide dismissed
Replace fixed 1-second delay with polling approach that waits up to 5 seconds for the file watcher callback to be invoked. This makes the test more reliable in CI environments where file system watchers can be slower. - Add WaitForConditionAsync helper method for polling with timeout - Update Hot_reload_callback_invoked_on_file_change to use polling - Add clearer assertion message when callback is not received
Security fixes: - Add SanitizeForLog helper to prevent log-forging vulnerabilities in Login.cshtml.cs - Sanitize HttpContext.Request.Path and QueryString before logging Code quality improvements: - Replace empty catch blocks with proper error logging in LiveDemo.razor - Remove unused variables: tenantContext (AnalyticsEndpoints.cs), isPending (Rollout.razor), effectiveTheme (theme.js) - Replace foreach loops with LINQ: RuntimeExperimentManager.cs, IdentitySeeder.cs, RolloutEndpoints.cs - Use ternary operator for conditional assignment in Rollout.razor These changes address all issues raised in PR review #30
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #30 +/- ##
=======================================
Coverage ? 83.20%
=======================================
Files ? 184
Lines ? 6860
Branches ? 962
=======================================
Hits ? 5708
Misses ? 1152
Partials ? 0
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
… user input Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
… user input Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Code Coverage |
No description provided.