diff --git a/.idea/.idea.HopFrame/.idea/workspace.xml b/.idea/.idea.HopFrame/.idea/workspace.xml
index a0fdd80..b43db74 100644
--- a/.idea/.idea.HopFrame/.idea/workspace.xml
+++ b/.idea/.idea.HopFrame/.idea/workspace.xml
@@ -3,14 +3,24 @@
HopFrame.Testing/HopFrame.Testing.csproj
HopFrame.Testing/HopFrame.Testing.csproj
+ testing/HopFrame.Testing.Api/HopFrame.Testing.Api.csproj
+ testing/HopFrame.Testing.Api/HopFrame.Testing.Api.csproj
testing/HopFrame.Testing/HopFrame.Testing.csproj
-
-
+
+
+
+
+
+
+
+
+
+
@@ -30,7 +40,7 @@
@@ -81,26 +91,28 @@
- {
- "keyToString": {
- ".NET Launch Settings Profile.HopFrame.Testing.executor": "Run",
- ".NET Launch Settings Profile.HopFrame.Testing: https.executor": "Run",
- ".NET Project.HopFrame.Testing.executor": "Run",
- "72b118b0-a6fc-4561-acdf-74f0b454dbb8.executor": "Debug",
- "RunOnceActivity.ShowReadmeOnStart": "true",
- "RunOnceActivity.git.unshallow": "true",
- "dcdf1689-dc07-47e4-8824-2e60a4fbf301.executor": "Debug",
- "git-widget-placeholder": "dev",
- "list.type.of.created.stylesheet": "CSS",
- "node.js.detected.package.eslint": "true",
- "node.js.detected.package.tslint": "true",
- "node.js.selected.package.eslint": "(autodetect)",
- "node.js.selected.package.tslint": "(autodetect)",
- "nodejs_package_manager_path": "npm",
- "settings.editor.selected.configurable": "preferences.environmentSetup",
- "vue.rearranger.settings.migration": "true"
+
+}]]>
@@ -132,7 +144,39 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -163,6 +207,7 @@
+
@@ -340,7 +385,15 @@
1737301230493
-
+
+
+ 1737994074137
+
+
+
+ 1737994074137
+
+
@@ -413,6 +466,7 @@
-
+
+
\ No newline at end of file
diff --git a/HopFrame.sln b/HopFrame.sln
index 877f6af..12d1549 100644
--- a/HopFrame.sln
+++ b/HopFrame.sln
@@ -16,6 +16,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Tests.Core", "test
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Tests.Web", "tests\HopFrame.Tests.Web\HopFrame.Tests.Web.csproj", "{7AB4F4FF-E938-4A40-A7EB-7B2063262896}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HopFrame.Testing.Api", "testing\HopFrame.Testing.Api\HopFrame.Testing.Api.csproj", "{B13D2C4E-3993-47CD-A525-FD0B83980F0A}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -27,6 +29,7 @@ Global
{58490069-51DF-454C-8B54-7FB7D4BDFF81} = {9EB7FDBD-49C2-4872-9666-6F7AEBA541B2}
{2E2D29E0-53FA-462D-B4D2-4678CD106E29} = {141928CB-5977-4285-A986-5BD785F2883C}
{7AB4F4FF-E938-4A40-A7EB-7B2063262896} = {141928CB-5977-4285-A986-5BD785F2883C}
+ {B13D2C4E-3993-47CD-A525-FD0B83980F0A} = {9EB7FDBD-49C2-4872-9666-6F7AEBA541B2}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4BFE21C2-EAAC-4662-8B97-500836651B2A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@@ -49,5 +52,9 @@ Global
{7AB4F4FF-E938-4A40-A7EB-7B2063262896}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7AB4F4FF-E938-4A40-A7EB-7B2063262896}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7AB4F4FF-E938-4A40-A7EB-7B2063262896}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B13D2C4E-3993-47CD-A525-FD0B83980F0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B13D2C4E-3993-47CD-A525-FD0B83980F0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B13D2C4E-3993-47CD-A525-FD0B83980F0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B13D2C4E-3993-47CD-A525-FD0B83980F0A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/src/HopFrame.Web/Components/App.razor b/src/HopFrame.Web/Components/App.razor
new file mode 100644
index 0000000..cfd71fd
--- /dev/null
+++ b/src/HopFrame.Web/Components/App.razor
@@ -0,0 +1,23 @@
+@using HopFrame.Web.Components.Pages
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/HopFrame.Web/Components/Layout/HopFrameLayout.razor b/src/HopFrame.Web/Components/Layout/HopFrameLayout.razor
index 1d469a8..c9d3fa4 100644
--- a/src/HopFrame.Web/Components/Layout/HopFrameLayout.razor
+++ b/src/HopFrame.Web/Components/Layout/HopFrameLayout.razor
@@ -5,6 +5,7 @@
+
diff --git a/src/HopFrame.Web/ServiceCollectionExtensions.cs b/src/HopFrame.Web/ServiceCollectionExtensions.cs
index dfd2606..775766c 100644
--- a/src/HopFrame.Web/ServiceCollectionExtensions.cs
+++ b/src/HopFrame.Web/ServiceCollectionExtensions.cs
@@ -1,5 +1,6 @@
using HopFrame.Core;
using HopFrame.Core.Config;
+using HopFrame.Web.Components;
using HopFrame.Web.Components.Pages;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.FluentUI.AspNetCore.Components;
@@ -15,11 +16,12 @@ public static class ServiceCollectionExtensions {
/// The service collection to add the services to
/// The configurator used to build the HopFrame configuration
/// The configuration for the FluentUI components
+ /// Set this to false if you don't want to automatically configure razor components with interactive server components
/// The same service collection that is passed in
- public static IServiceCollection AddHopFrame(this IServiceCollection services, Action configurator, LibraryConfiguration? fluentUiLibraryConfiguration = null) {
+ public static IServiceCollection AddHopFrame(this IServiceCollection services, Action configurator, LibraryConfiguration? fluentUiLibraryConfiguration = null, bool addRazorComponents = true) {
var config = new HopFrameConfig();
configurator.Invoke(new HopFrameConfigurator(config));
- return AddHopFrame(services, config, fluentUiLibraryConfiguration);
+ return AddHopFrame(services, config, fluentUiLibraryConfiguration, addRazorComponents);
}
///
@@ -28,22 +30,46 @@ public static class ServiceCollectionExtensions {
/// The service collection to add the services to
/// The config used for the HopFrame admin ui
/// The configuration for the FluentUI components
+ /// Set this to false if you don't want to automatically configure razor components with interactive server components
/// The same service collection that is passed in
- public static IServiceCollection AddHopFrame(this IServiceCollection services, HopFrameConfig config, LibraryConfiguration? fluentUiLibraryConfiguration = null) {
+ public static IServiceCollection AddHopFrame(this IServiceCollection services, HopFrameConfig config, LibraryConfiguration? fluentUiLibraryConfiguration = null, bool addRazorComponents = true) {
services.AddSingleton(config);
services.AddHopFrameServices();
services.AddFluentUIComponents(fluentUiLibraryConfiguration);
+
+ if (addRazorComponents) {
+ services.AddRazorComponents()
+ .AddInteractiveServerComponents();
+ }
+
return services;
}
///
- /// Maps the HopFrame admin ui endpoints
+ /// Adds the HopFrame admin ui endpoints
///
+ ///
+ [Obsolete($"Use '{nameof(AddHopFramePages)}' instead")]
public static RazorComponentsEndpointConventionBuilder MapHopFramePages(this RazorComponentsEndpointConventionBuilder builder) {
+ return AddHopFramePages(builder);
+ }
+
+ ///
+ /// Adds the HopFrame admin ui endpoints
+ ///
+ public static RazorComponentsEndpointConventionBuilder AddHopFramePages(this RazorComponentsEndpointConventionBuilder builder) {
builder
.AddInteractiveServerRenderMode()
.AddAdditionalAssemblies(typeof(HopFrameHome).Assembly);
return builder;
}
+
+ public static WebApplication MapHopFrame(this WebApplication app) {
+ app.UseAntiforgery();
+ app.MapStaticAssets();
+ app.MapRazorComponents()
+ .AddInteractiveServerRenderMode();
+ return app;
+ }
}
\ No newline at end of file
diff --git a/testing/HopFrame.Testing.Api/HopFrame.Testing.Api.csproj b/testing/HopFrame.Testing.Api/HopFrame.Testing.Api.csproj
new file mode 100644
index 0000000..58bb4c4
--- /dev/null
+++ b/testing/HopFrame.Testing.Api/HopFrame.Testing.Api.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/testing/HopFrame.Testing.Api/Program.cs b/testing/HopFrame.Testing.Api/Program.cs
new file mode 100644
index 0000000..23146f1
--- /dev/null
+++ b/testing/HopFrame.Testing.Api/Program.cs
@@ -0,0 +1,51 @@
+using HopFrame.Testing;
+using HopFrame.Web;
+using Microsoft.EntityFrameworkCore;
+
+var builder = WebApplication.CreateBuilder(args);
+
+// Add services to the container.
+// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
+builder.Services.AddOpenApi();
+
+builder.Services.AddHopFrame(options => {
+ options.AddDbContext();
+});
+
+builder.Services.AddDbContext(options => {
+ options.UseInMemoryDatabase("testing.web");
+});
+
+var app = builder.Build();
+
+// Configure the HTTP request pipeline.
+if (app.Environment.IsDevelopment()) {
+ app.MapOpenApi();
+}
+
+app.UseHttpsRedirection();
+
+var summaries = new[] {
+ "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
+};
+
+app.MapGet("/weatherforecast", () => {
+ var forecast = Enumerable.Range(1, 5).Select(index =>
+ new WeatherForecast
+ (
+ DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
+ Random.Shared.Next(-20, 55),
+ summaries[Random.Shared.Next(summaries.Length)]
+ ))
+ .ToArray();
+ return forecast;
+ })
+ .WithName("GetWeatherForecast");
+
+app.MapHopFrame();
+
+app.Run();
+
+record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary) {
+ public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
+}
\ No newline at end of file
diff --git a/testing/HopFrame.Testing.Api/Properties/launchSettings.json b/testing/HopFrame.Testing.Api/Properties/launchSettings.json
new file mode 100644
index 0000000..91f56a5
--- /dev/null
+++ b/testing/HopFrame.Testing.Api/Properties/launchSettings.json
@@ -0,0 +1,23 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "http://localhost:5115",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": false,
+ "applicationUrl": "https://localhost:7129;http://localhost:5115",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/testing/HopFrame.Testing.Api/appsettings.Development.json b/testing/HopFrame.Testing.Api/appsettings.Development.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/testing/HopFrame.Testing.Api/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/testing/HopFrame.Testing.Api/appsettings.json b/testing/HopFrame.Testing.Api/appsettings.json
new file mode 100644
index 0000000..10f68b8
--- /dev/null
+++ b/testing/HopFrame.Testing.Api/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/tests/HopFrame.Tests.Web/Components/Dialogs/HopFrameEditorTests.cs b/tests/HopFrame.Tests.Web/Components/Dialogs/HopFrameEditorTests.cs
index 5aee780..d32bcf8 100644
--- a/tests/HopFrame.Tests.Web/Components/Dialogs/HopFrameEditorTests.cs
+++ b/tests/HopFrame.Tests.Web/Components/Dialogs/HopFrameEditorTests.cs
@@ -5,6 +5,8 @@ using HopFrame.Tests.Web.Models;
using HopFrame.Web;
using HopFrame.Web.Components.Dialogs;
using HopFrame.Web.Models;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.FluentUI.AspNetCore.Components;
using Moq;
@@ -34,7 +36,7 @@ public class HopFrameEditorTests : TestContext {
contextExplorerMock.Setup(e => e.GetTableManager("Table1")).Returns(Mock.Of());
authHandlerMock.Setup(h => h.IsAuthenticatedAsync(It.IsAny())).ReturnsAsync(true);
- Services.AddHopFrame(config);
+ Services.AddHopFrame(config, null, false);
Services.AddSingleton(contextExplorerMock.Object);
Services.AddSingleton(authHandlerMock.Object);
Services.AddSingleton(dialogServiceMock.Object);
diff --git a/tests/HopFrame.Tests.Web/Components/Layout/HopFrameLayoutTests.cs b/tests/HopFrame.Tests.Web/Components/Layout/HopFrameLayoutTests.cs
index 068a090..ce8398f 100644
--- a/tests/HopFrame.Tests.Web/Components/Layout/HopFrameLayoutTests.cs
+++ b/tests/HopFrame.Tests.Web/Components/Layout/HopFrameLayoutTests.cs
@@ -25,7 +25,7 @@ public class HopFrameLayoutTests : TestContext {
.ReturnsAsync(true);
Services.AddSingleton(authHandlerMock.Object);
- Services.AddHopFrame(config);
+ Services.AddHopFrame(config, null, false);
JSInterop.Mode = JSRuntimeMode.Loose;
@@ -61,7 +61,7 @@ public class HopFrameLayoutTests : TestContext {
.ReturnsAsync(false);
Services.AddSingleton(navMock);
- Services.AddHopFrame(config);
+ Services.AddHopFrame(config, null, false);
Services.AddSingleton(authHandlerMock.Object);
JSInterop.Mode = JSRuntimeMode.Loose;
diff --git a/tests/HopFrame.Tests.Web/Components/Layout/HopFrameNavigationTests.cs b/tests/HopFrame.Tests.Web/Components/Layout/HopFrameNavigationTests.cs
index d1b8598..600acec 100644
--- a/tests/HopFrame.Tests.Web/Components/Layout/HopFrameNavigationTests.cs
+++ b/tests/HopFrame.Tests.Web/Components/Layout/HopFrameNavigationTests.cs
@@ -22,7 +22,7 @@ public class HopFrameNavigationTests : TestContext {
.ReturnsAsync("John Doe");
Services.AddSingleton(authHandlerMock.Object);
- Services.AddHopFrame(config);
+ Services.AddHopFrame(config, null, false);
JSInterop.Mode = JSRuntimeMode.Loose;
@@ -51,7 +51,7 @@ public class HopFrameNavigationTests : TestContext {
.ReturnsAsync("John Doe");
Services.AddSingleton(authHandlerMock.Object);
- Services.AddHopFrame(config);
+ Services.AddHopFrame(config, null, false);
JSInterop.Mode = JSRuntimeMode.Loose;
diff --git a/tests/HopFrame.Tests.Web/Components/Layout/HopFrameSideMenuTests.cs b/tests/HopFrame.Tests.Web/Components/Layout/HopFrameSideMenuTests.cs
index 6ad136e..75943e4 100644
--- a/tests/HopFrame.Tests.Web/Components/Layout/HopFrameSideMenuTests.cs
+++ b/tests/HopFrame.Tests.Web/Components/Layout/HopFrameSideMenuTests.cs
@@ -32,7 +32,7 @@ public class HopFrameSideMenuTests : TestContext {
Services.AddSingleton(contextExplorerMock.Object);
Services.AddSingleton(authHandlerMock.Object);
- Services.AddHopFrame(config);
+ Services.AddHopFrame(config, null, false);
JSInterop.Mode = JSRuntimeMode.Loose;
diff --git a/tests/HopFrame.Tests.Web/Components/Pages/HopFrameHomeTests.cs b/tests/HopFrame.Tests.Web/Components/Pages/HopFrameHomeTests.cs
index 525c1f3..b700920 100644
--- a/tests/HopFrame.Tests.Web/Components/Pages/HopFrameHomeTests.cs
+++ b/tests/HopFrame.Tests.Web/Components/Pages/HopFrameHomeTests.cs
@@ -38,7 +38,7 @@ public class HopFrameHomeTests : TestContext {
authHandlerMock.Setup(h => h.IsAuthenticatedAsync(It.IsAny()))
.ReturnsAsync(true);
- Services.AddHopFrame(config);
+ Services.AddHopFrame(config, null, false);
Services.AddSingleton(contextExplorerMock.Object);
Services.AddSingleton(authHandlerMock.Object);
diff --git a/tests/HopFrame.Tests.Web/Components/Pages/HopFrameTablePageTests.cs b/tests/HopFrame.Tests.Web/Components/Pages/HopFrameTablePageTests.cs
index a038f86..24e90da 100644
--- a/tests/HopFrame.Tests.Web/Components/Pages/HopFrameTablePageTests.cs
+++ b/tests/HopFrame.Tests.Web/Components/Pages/HopFrameTablePageTests.cs
@@ -35,7 +35,7 @@ public class HopFrameTablePageTests : TestContext {
authHandlerMock.Setup(h => h.IsAuthenticatedAsync(It.IsAny())).ReturnsAsync(true);
managerMock.Setup(m => m.LoadPage(It.IsAny(), It.IsAny())).Returns(Enumerable.Empty