From c2bb83c32109df38e69bc7123af9cf6a1dfc53ca Mon Sep 17 00:00:00 2001 From: Niraj Soni <23270244+ns8482e@users.noreply.github.com> Date: Thu, 15 Feb 2024 08:25:11 -0600 Subject: [PATCH 1/4] - Add Blazor to orchard core - Options Editor and ModalDialog in Blazor - Using blazor in PredefinedList --- OrchardCore.sln | 28 +- .../Dependencies.AspNetCore.props | 5 + .../OrchardCore.Cms.Web.csproj | 5 +- src/OrchardCore.Cms.Web/Program.cs | 6 +- .../Properties/launchSettings.json | 1 + .../Directory.Build.props | 10 + .../Directory.Build.targets | 5 + .../OrchardAdminApp.razor | 5 + .../OrchardCore.Admin.Components.csproj | 21 ++ .../_Imports.razor | 1 + .../Initializer.razor | 5 + .../OrchardCore.Admin.WebAssembly.App.csproj | 22 ++ .../Program.cs | 12 + .../_Imports.razor | 9 + .../ColloctedJSComponent.cs | 43 +++ .../ModalDialog.razor | 59 ++++ .../OptionEditor.razor | 309 ++++++++++++++++++ .../OptionEditor.razor.js | 10 + .../OrchardCore.Common.Components.csproj | 19 ++ .../_Imports.razor | 4 + .../OrchardCore.Admin.csproj | 8 +- .../OrchardCore.Admin/Startup.cs | 32 ++ .../OrchardCore.ContentFields.csproj | 1 + ...ldPredefinedListEditorSettings.Edit.cshtml | 61 ++-- .../ResourceManagementOptionsConfiguration.cs | 10 + .../TheAdmin/Views/Layout.cshtml | 8 +- 26 files changed, 669 insertions(+), 30 deletions(-) create mode 100644 src/OrchardCore.Components/Directory.Build.props create mode 100644 src/OrchardCore.Components/Directory.Build.targets create mode 100644 src/OrchardCore.Components/OrchardCore.Admin.Components/OrchardAdminApp.razor create mode 100644 src/OrchardCore.Components/OrchardCore.Admin.Components/OrchardCore.Admin.Components.csproj create mode 100644 src/OrchardCore.Components/OrchardCore.Admin.Components/_Imports.razor create mode 100644 src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/Initializer.razor create mode 100644 src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/OrchardCore.Admin.WebAssembly.App.csproj create mode 100644 src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/Program.cs create mode 100644 src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/_Imports.razor create mode 100644 src/OrchardCore.Components/OrchardCore.Common.Components/ColloctedJSComponent.cs create mode 100644 src/OrchardCore.Components/OrchardCore.Common.Components/ModalDialog.razor create mode 100644 src/OrchardCore.Components/OrchardCore.Common.Components/OptionEditor.razor create mode 100644 src/OrchardCore.Components/OrchardCore.Common.Components/OptionEditor.razor.js create mode 100644 src/OrchardCore.Components/OrchardCore.Common.Components/OrchardCore.Common.Components.csproj create mode 100644 src/OrchardCore.Components/OrchardCore.Common.Components/_Imports.razor diff --git a/OrchardCore.sln b/OrchardCore.sln index a390bc69109..a3695492c63 100644 --- a/OrchardCore.sln +++ b/OrchardCore.sln @@ -511,9 +511,17 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Search.AzureAI" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Search.AzureAI.Core", "src\OrchardCore\OrchardCore.Search.AzureAI.Core\OrchardCore.Search.AzureAI.Core.csproj", "{E9428DE8-5D81-4359-BF84-31435041FF1A}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCore.Media.Indexing.Pdf", "src\OrchardCore.Modules\OrchardCore.Media.Indexing.Pdf\OrchardCore.Media.Indexing.Pdf.csproj", "{95187E6A-5B74-4475-8FEB-758ACD012DCC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Media.Indexing.Pdf", "src\OrchardCore.Modules\OrchardCore.Media.Indexing.Pdf\OrchardCore.Media.Indexing.Pdf.csproj", "{95187E6A-5B74-4475-8FEB-758ACD012DCC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrchardCore.Media.Indexing.OpenXML", "src\OrchardCore.Modules\OrchardCore.Media.Indexing.OpenXML\OrchardCore.Media.Indexing.OpenXML.csproj", "{47777735-7432-4CCA-A8C5-672E9EE65121}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Media.Indexing.OpenXML", "src\OrchardCore.Modules\OrchardCore.Media.Indexing.OpenXML\OrchardCore.Media.Indexing.OpenXML.csproj", "{47777735-7432-4CCA-A8C5-672E9EE65121}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "OrchardCore.Components", "OrchardCore.Components", "{7525406F-AEA0-4397-8E6B-3837ABEC2A36}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Admin.Components", "src\OrchardCore.Components\OrchardCore.Admin.Components\OrchardCore.Admin.Components.csproj", "{0734E6A3-5D42-4698-91F1-4068364E8FCC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Admin.WebAssembly.App", "src\OrchardCore.Components\OrchardCore.Admin.WebAssembly.App\OrchardCore.Admin.WebAssembly.App.csproj", "{361B5892-DE24-4249-827E-3D144CC68643}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "OrchardCore.Common.Components", "src\OrchardCore.Components\OrchardCore.Common.Components\OrchardCore.Common.Components.csproj", "{2C2CD2A9-BFD8-4A9C-A30F-3CA973E734B7}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -1359,6 +1367,18 @@ Global {47777735-7432-4CCA-A8C5-672E9EE65121}.Debug|Any CPU.Build.0 = Debug|Any CPU {47777735-7432-4CCA-A8C5-672E9EE65121}.Release|Any CPU.ActiveCfg = Release|Any CPU {47777735-7432-4CCA-A8C5-672E9EE65121}.Release|Any CPU.Build.0 = Release|Any CPU + {0734E6A3-5D42-4698-91F1-4068364E8FCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0734E6A3-5D42-4698-91F1-4068364E8FCC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0734E6A3-5D42-4698-91F1-4068364E8FCC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0734E6A3-5D42-4698-91F1-4068364E8FCC}.Release|Any CPU.Build.0 = Release|Any CPU + {361B5892-DE24-4249-827E-3D144CC68643}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {361B5892-DE24-4249-827E-3D144CC68643}.Debug|Any CPU.Build.0 = Debug|Any CPU + {361B5892-DE24-4249-827E-3D144CC68643}.Release|Any CPU.ActiveCfg = Release|Any CPU + {361B5892-DE24-4249-827E-3D144CC68643}.Release|Any CPU.Build.0 = Release|Any CPU + {2C2CD2A9-BFD8-4A9C-A30F-3CA973E734B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {2C2CD2A9-BFD8-4A9C-A30F-3CA973E734B7}.Debug|Any CPU.Build.0 = Debug|Any CPU + {2C2CD2A9-BFD8-4A9C-A30F-3CA973E734B7}.Release|Any CPU.ActiveCfg = Release|Any CPU + {2C2CD2A9-BFD8-4A9C-A30F-3CA973E734B7}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1594,6 +1614,10 @@ Global {E9428DE8-5D81-4359-BF84-31435041FF1A} = {F23AC6C2-DE44-4699-999D-3C478EF3D691} {95187E6A-5B74-4475-8FEB-758ACD012DCC} = {90030E85-0C4F-456F-B879-443E8A3F220D} {47777735-7432-4CCA-A8C5-672E9EE65121} = {90030E85-0C4F-456F-B879-443E8A3F220D} + {7525406F-AEA0-4397-8E6B-3837ABEC2A36} = {275E087F-A4E2-4A7B-A924-ED68E3A52086} + {0734E6A3-5D42-4698-91F1-4068364E8FCC} = {7525406F-AEA0-4397-8E6B-3837ABEC2A36} + {361B5892-DE24-4249-827E-3D144CC68643} = {7525406F-AEA0-4397-8E6B-3837ABEC2A36} + {2C2CD2A9-BFD8-4A9C-A30F-3CA973E734B7} = {7525406F-AEA0-4397-8E6B-3837ABEC2A36} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {46A1D25A-78D1-4476-9CBF-25B75E296341} diff --git a/src/OrchardCore.Build/Dependencies.AspNetCore.props b/src/OrchardCore.Build/Dependencies.AspNetCore.props index 213d63860e0..d86f7cebe10 100644 --- a/src/OrchardCore.Build/Dependencies.AspNetCore.props +++ b/src/OrchardCore.Build/Dependencies.AspNetCore.props @@ -42,6 +42,11 @@ + + + + + diff --git a/src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj b/src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj index a5ac7fee774..ecb0407c3ea 100644 --- a/src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj +++ b/src/OrchardCore.Cms.Web/OrchardCore.Cms.Web.csproj @@ -1,4 +1,4 @@ - + @@ -30,10 +30,13 @@ + + + diff --git a/src/OrchardCore.Cms.Web/Program.cs b/src/OrchardCore.Cms.Web/Program.cs index f5e06716d21..dbc1af10d87 100644 --- a/src/OrchardCore.Cms.Web/Program.cs +++ b/src/OrchardCore.Cms.Web/Program.cs @@ -10,7 +10,11 @@ var app = builder.Build(); -if (!app.Environment.IsDevelopment()) +if (app.Environment.IsDevelopment()) +{ + app.UseWebAssemblyDebugging(); +} +else { app.UseExceptionHandler("/Error"); } diff --git a/src/OrchardCore.Cms.Web/Properties/launchSettings.json b/src/OrchardCore.Cms.Web/Properties/launchSettings.json index ef8cc6e703c..e6a7de11e84 100644 --- a/src/OrchardCore.Cms.Web/Properties/launchSettings.json +++ b/src/OrchardCore.Cms.Web/Properties/launchSettings.json @@ -18,6 +18,7 @@ "Kestrel": { "commandName": "Project", "launchBrowser": true, + "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", "launchUrl": "https://localhost:5001", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" diff --git a/src/OrchardCore.Components/Directory.Build.props b/src/OrchardCore.Components/Directory.Build.props new file mode 100644 index 00000000000..a49d641582b --- /dev/null +++ b/src/OrchardCore.Components/Directory.Build.props @@ -0,0 +1,10 @@ + + + + + + + $(CommonTargetFrameworks) + + + diff --git a/src/OrchardCore.Components/Directory.Build.targets b/src/OrchardCore.Components/Directory.Build.targets new file mode 100644 index 00000000000..f20824469e8 --- /dev/null +++ b/src/OrchardCore.Components/Directory.Build.targets @@ -0,0 +1,5 @@ + + + + + diff --git a/src/OrchardCore.Components/OrchardCore.Admin.Components/OrchardAdminApp.razor b/src/OrchardCore.Components/OrchardCore.Admin.Components/OrchardAdminApp.razor new file mode 100644 index 00000000000..dfe4bf31dc4 --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Admin.Components/OrchardAdminApp.razor @@ -0,0 +1,5 @@ +

Future Admin App in Blazor

+ +@code { + +} diff --git a/src/OrchardCore.Components/OrchardCore.Admin.Components/OrchardCore.Admin.Components.csproj b/src/OrchardCore.Components/OrchardCore.Admin.Components/OrchardCore.Admin.Components.csproj new file mode 100644 index 00000000000..73a3385b13d --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Admin.Components/OrchardCore.Admin.Components.csproj @@ -0,0 +1,21 @@ + + + + $(CommonTargetFrameworks) + enable + enable + + + + + + + + + + + + + + + diff --git a/src/OrchardCore.Components/OrchardCore.Admin.Components/_Imports.razor b/src/OrchardCore.Components/OrchardCore.Admin.Components/_Imports.razor new file mode 100644 index 00000000000..77285129dab --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Admin.Components/_Imports.razor @@ -0,0 +1 @@ +@using Microsoft.AspNetCore.Components.Web diff --git a/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/Initializer.razor b/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/Initializer.razor new file mode 100644 index 00000000000..c863efaac91 --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/Initializer.razor @@ -0,0 +1,5 @@ +

Initializer

+ +@code { + +} diff --git a/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/OrchardCore.Admin.WebAssembly.App.csproj b/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/OrchardCore.Admin.WebAssembly.App.csproj new file mode 100644 index 00000000000..9c989392163 --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/OrchardCore.Admin.WebAssembly.App.csproj @@ -0,0 +1,22 @@ + + + + $(CommonTargetFrameworks) + + enable + enable + true + Default + + + + + + + + + + + + + diff --git a/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/Program.cs b/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/Program.cs new file mode 100644 index 00000000000..2fd586a0722 --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/Program.cs @@ -0,0 +1,12 @@ +using Microsoft.AspNetCore.Components.Web; +using Microsoft.AspNetCore.Components.WebAssembly.Hosting; +using OrchardCore.Admin.WebAssembly.App; +using OrchardCore.Common.Components; + +var builder = WebAssemblyHostBuilder.CreateDefault(args); +builder.RootComponents.RegisterCustomElement("option-editor"); +builder.RootComponents.RegisterCustomElement("init"); +builder.Services.AddScoped(); + + +await builder.Build().RunAsync(); diff --git a/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/_Imports.razor b/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/_Imports.razor new file mode 100644 index 00000000000..8a2c0c8c0a4 --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/_Imports.razor @@ -0,0 +1,9 @@ +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop +@using OrchardCore.Admin.WebAssembly.App diff --git a/src/OrchardCore.Components/OrchardCore.Common.Components/ColloctedJSComponent.cs b/src/OrchardCore.Components/OrchardCore.Common.Components/ColloctedJSComponent.cs new file mode 100644 index 00000000000..9725457134a --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Common.Components/ColloctedJSComponent.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; + +namespace OrchardCore.Common.Components; + +public class ColloctedJSComponent : ComponentBase, IAsyncDisposable +{ + [Inject] + private IJSRuntime? JS { get; set; } + + [Parameter] + public bool RaiseDomEvents { get; set; } + + protected IJSObjectReference? JSModule { get; private set; } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + var ns = GetType().Namespace; + var cmp = GetType().Name; + if (JS is not null) + { + JSModule = await JS.InvokeAsync("import", + $"./_content/{ns}/{cmp}.razor.js"); + } + } + } + + async ValueTask IAsyncDisposable.DisposeAsync() + { + if (JSModule is not null) + { + await JSModule.DisposeAsync(); + } + } + +} diff --git a/src/OrchardCore.Components/OrchardCore.Common.Components/ModalDialog.razor b/src/OrchardCore.Components/OrchardCore.Common.Components/ModalDialog.razor new file mode 100644 index 00000000000..8ff6dfd03b0 --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Common.Components/ModalDialog.razor @@ -0,0 +1,59 @@ + + +@if (ShowBackdrop && IsOpen) +{ + +} + +@code { + + [Parameter] + public string? Title { get; set; } + [Parameter] + public bool ShowBackdrop { get; set; } + [Parameter] + public RenderFragment? Body { get; set; } + [Parameter] + public RenderFragment? Actions { get; set; } + + + public bool IsOpen { get; set; } + + string IsOpenClass { get; set; } = string.Empty; + + string IsOpenDisplayStyle { get; set; } = "none"; + + public async Task Open() + { + IsOpenDisplayStyle = "block"; + IsOpen = true; + await Task.Delay(100);//Delay allows bootstrap to perform nice fade animation + IsOpenClass = "show"; + StateHasChanged(); + + } + + public async Task Close() + { + IsOpenClass = ""; + IsOpen = false; + await Task.Delay(250);//Delay allows bootstrap to perform nice fade animation + IsOpenDisplayStyle = "none"; + StateHasChanged(); + } +} diff --git a/src/OrchardCore.Components/OrchardCore.Common.Components/OptionEditor.razor b/src/OrchardCore.Components/OrchardCore.Common.Components/OptionEditor.razor new file mode 100644 index 00000000000..ac70feb63ad --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Common.Components/OptionEditor.razor @@ -0,0 +1,309 @@ +@using System.Text.Json +@using System.ComponentModel.DataAnnotations +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.JSInterop + +@inherits ColloctedJSComponent + + + + + + + + + + + + + + + + + @for (var keyIndex = 0; keyIndex < Options!.Count; keyIndex++) + { + var option = Options![keyIndex]; + + + + + + + + + + + } + + + + + + + +
Option LabelValueDefault?
+ + +
+ + +
+
+ + +
+ +
+
+ +
+ + + + +
+ + + @("A JSON representation of the allowed values, e.g. {0}") @("[{ name: 'First option', value: 'option1' }, { name: 'Second option', value: 'option2' } ]") +
+
+ + + @("(Optional) The default to assign to the text field.") +
+ + + + + +
+ +@code { + [Parameter] + public string? OptionsJson { get; set; } + + [Parameter] + public string? DefaultValue { get; set; } + + + ElementReference tableElement; + + private ModalDialog? Modal { get; set; } + + private List? Options { get; set; } + private string? OptionsJsonInternal { get; set; } + private string? DefaultValueInternal { get; set; } + private string IsInvalidClass { get; set; } = string.Empty; + private const string OptionsJsonEmpty = "[]"; + + + + private void SetOptionsEmpty() + { + Options = new List(); + OptionsJsonInternal = OptionsJsonEmpty; + } + + private bool TryJsonValid(string? json) + { + if (string.IsNullOrWhiteSpace(json)) + return false; + try + { + _ = JsonSerializer.Deserialize>(json, new JsonSerializerOptions(JsonSerializerDefaults.Web)); + return true; + } + catch (JsonException) + { + return false; + } + } + + private bool TryUpdateOptions(string? json) + { + if (string.IsNullOrWhiteSpace(json)) + return false; + try + { + + var updated = JsonSerializer.Deserialize>(json, new JsonSerializerOptions(JsonSerializerDefaults.Web)); + if (updated != null && !Options!.Equals(updated)) + { + Options.Clear(); + Options.AddRange(updated!); + } + return true; + } + catch (JsonException ex) + { + Console.WriteLine(ex); + return false; + } + } + + private bool TryUpdateOptionsJson(List? options) + { + if (options is null) + return false; + try + { + OptionsJsonInternal = JsonSerializer.Serialize(options!, new JsonSerializerOptions(JsonSerializerDefaults.Web)); + return true; + } + catch (JsonException ex) + { + Console.WriteLine(ex); + return false; + } + } + + private async Task OptionItemChangeAsync(Action update) + { + update(); + TryUpdateOptionsJson(Options); + await TriggerEventAsync(); + } + + + protected override Task OnInitializedAsync() + { + SetOptionsEmpty(); + return base.OnInitializedAsync(); + } + + + protected override Task OnParametersSetAsync() + { + if (!string.IsNullOrWhiteSpace(OptionsJson)) + { + if (TryUpdateOptions(OptionsJson)) + { + OptionsJsonInternal = OptionsJson; + } + } + + if (!string.IsNullOrWhiteSpace(DefaultValue)) + DefaultValueInternal = DefaultValue.Trim(); + else + DefaultValueInternal = string.Empty; + + return base.OnParametersSetAsync(); + } + private Task AddNewOptionAsync() + { + Options!.Add(new OptionsModel()); + TryUpdateOptionsJson(Options); + return TriggerEventAsync(); + } + + private Task RemoveOptionAsync(OptionsModel option) + { + Options!.Remove(option); + TryUpdateOptionsJson(Options); + return TriggerEventAsync(); + } + + async Task DefaultOptionChangedAsync(ChangeEventArgs args) + { + DefaultValueInternal = args.Value?.ToString(); + await TriggerEventAsync(); + } + + async Task OptionsJsonChangedAsync(ChangeEventArgs e) + { + var newVal = e.Value?.ToString(); + if (TryJsonValid(newVal)) + { + IsInvalidClass = ""; + OptionsJsonInternal = newVal; + } + else + { + IsInvalidClass = "is-invalid"; + } + + await Task.CompletedTask; + } + + async Task SubmitAsync() + { + if (TryUpdateOptions(OptionsJsonInternal)) + { + await Modal!.Close(); + await TriggerEventAsync(); + StateHasChanged(); + } + } + + async Task CancelAsync() + { + TryUpdateOptionsJson(Options); + await Modal!.Close(); + } + + public class OptionsModel + { + [Required(AllowEmptyStrings = false, ErrorMessage = "Provide option name")] + public string? Name { get; set; } + [Required(AllowEmptyStrings = false, ErrorMessage = "Provide option value")] + public string? Value { get; set; } + } + + + int currentIndex; + + void StartDrag(OptionsModel item) + => currentIndex = GetIndex(item); + + int GetIndex(OptionsModel item) + => Options!.FindIndex(a => string.Equals(a.Name, item.Name)); + + async Task Drop(OptionsModel item) + { + if (item != null) + { + var index = GetIndex(item); + + // get current item + var current = Options![currentIndex]; + + // remove game from current index + Options!.RemoveAt(currentIndex); + Options!.Insert(index, current); + + // update current selection + currentIndex = index; + + TryUpdateOptionsJson(Options); + await TriggerEventAsync(); + } + else + { + await Task.CompletedTask; + } + } + + async Task TriggerEventAsync() + { + StateHasChanged(); + if (JSModule is not null) + { + await JSModule.InvokeVoidAsync("optionsChanged", tableElement, OptionsJsonInternal, DefaultValueInternal); + } + } + +} diff --git a/src/OrchardCore.Components/OrchardCore.Common.Components/OptionEditor.razor.js b/src/OrchardCore.Components/OrchardCore.Common.Components/OptionEditor.razor.js new file mode 100644 index 00000000000..ae59baa0fa1 --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Common.Components/OptionEditor.razor.js @@ -0,0 +1,10 @@ +export function optionsChanged(element, jsonValue, defaultValue) { + const evt = new CustomEvent("blazor:optionsChanged", { + bubbles: true, + detail: { + options: jsonValue, + defaultValue: defaultValue + } + }); + element.dispatchEvent(evt); +} diff --git a/src/OrchardCore.Components/OrchardCore.Common.Components/OrchardCore.Common.Components.csproj b/src/OrchardCore.Components/OrchardCore.Common.Components/OrchardCore.Common.Components.csproj new file mode 100644 index 00000000000..2dc00f31670 --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Common.Components/OrchardCore.Common.Components.csproj @@ -0,0 +1,19 @@ + + + + $(CommonTargetFrameworks) + enable + enable + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/OrchardCore.Components/OrchardCore.Common.Components/_Imports.razor b/src/OrchardCore.Components/OrchardCore.Common.Components/_Imports.razor new file mode 100644 index 00000000000..d96cabe770a --- /dev/null +++ b/src/OrchardCore.Components/OrchardCore.Common.Components/_Imports.razor @@ -0,0 +1,4 @@ +@using Microsoft.AspNetCore.Components.Web +@using System.Text.Json + + diff --git a/src/OrchardCore.Modules/OrchardCore.Admin/OrchardCore.Admin.csproj b/src/OrchardCore.Modules/OrchardCore.Admin/OrchardCore.Admin.csproj index 0c2da034003..cb6f73eb467 100644 --- a/src/OrchardCore.Modules/OrchardCore.Admin/OrchardCore.Admin.csproj +++ b/src/OrchardCore.Modules/OrchardCore.Admin/OrchardCore.Admin.csproj @@ -14,8 +14,12 @@ - + + + + + @@ -24,5 +28,5 @@ - +
diff --git a/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs index 7d08f46eabb..5298051afc9 100644 --- a/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs @@ -1,14 +1,19 @@ using System; using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Rendering; +using Microsoft.AspNetCore.Components.Web; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.ApplicationModels; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; +using OrchardCore.Admin.Components; using OrchardCore.Admin.Controllers; using OrchardCore.Admin.Drivers; using OrchardCore.Admin.Models; +using OrchardCore.Common.Components; using OrchardCore.DisplayManagement.Handlers; using OrchardCore.DisplayManagement.Theming; using OrchardCore.Environment.Shell.Configuration; @@ -85,6 +90,33 @@ public override void ConfigureServices(IServiceCollection services) } } + + public class AdminComponentsStartup : StartupBase + { + public override int Order => 1; + + public override void ConfigureServices(IServiceCollection services) + { + services.AddRazorComponents() + .AddInteractiveServerComponents() + .AddInteractiveWebAssemblyComponents(); + ; + + } + + public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) + { + app.UseStaticFiles(); + routes.MapRazorComponents() + .AddInteractiveServerRenderMode() + .AddInteractiveWebAssemblyRenderMode() + .AddAdditionalAssemblies(typeof(OptionEditor).Assembly) + ; + + } + } + + [RequireFeatures("OrchardCore.Deployment")] public class DeploymentStartup : StartupBase { diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/OrchardCore.ContentFields.csproj b/src/OrchardCore.Modules/OrchardCore.ContentFields/OrchardCore.ContentFields.csproj index d50cedac85f..782a30f5356 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/OrchardCore.ContentFields.csproj +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/OrchardCore.ContentFields.csproj @@ -15,6 +15,7 @@ + diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/Views/TextFieldPredefinedListEditorSettings.Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.ContentFields/Views/TextFieldPredefinedListEditorSettings.Edit.cshtml index 448266b0a1b..345aa6d5c43 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/Views/TextFieldPredefinedListEditorSettings.Edit.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/Views/TextFieldPredefinedListEditorSettings.Edit.cshtml @@ -1,13 +1,20 @@ +@using Microsoft.AspNetCore.Components +@using Microsoft.AspNetCore.Components.Endpoints +@using Microsoft.AspNetCore.Components.Web +@using Microsoft.Extensions.DependencyInjection +@using OrchardCore.Admin.Components +@using OrchardCore.Common.Components @using OrchardCore.ContentFields.Settings @model OrchardCore.ContentFields.ViewModels.PredefinedListSettingsViewModel - +@* - - - + *@ +@* + *@
-
-
- - -
-
+
+
+ + +
+
-
-
- - - - -
-
+
+
+ + @* + *@ + + +
+
+ \ No newline at end of file diff --git a/src/OrchardCore.Modules/OrchardCore.Resources/ResourceManagementOptionsConfiguration.cs b/src/OrchardCore.Modules/OrchardCore.Resources/ResourceManagementOptionsConfiguration.cs index d29aa803543..f8f6e1cbc9b 100644 --- a/src/OrchardCore.Modules/OrchardCore.Resources/ResourceManagementOptionsConfiguration.cs +++ b/src/OrchardCore.Modules/OrchardCore.Resources/ResourceManagementOptionsConfiguration.cs @@ -500,6 +500,16 @@ ResourceManifest BuildManifest() .SetDependencies("monaco-loader") .SetVersion(MonacoEditorVersion); + manifest + .DefineScript("blazor-custom-elements") + .SetUrl("~/_content/Microsoft.AspNetCore.Components.CustomElements/Microsoft.AspNetCore.Components.CustomElements.lib.module.js") + .SetVersion("8.0.1"); + + manifest + .DefineScript("blazor-web-js") + .SetUrl("~/_framework/blazor.web.js") + .SetVersion("8.0.1"); + return manifest; } diff --git a/src/OrchardCore.Themes/TheAdmin/Views/Layout.cshtml b/src/OrchardCore.Themes/TheAdmin/Views/Layout.cshtml index f1f5e2e92c2..1b446466215 100644 --- a/src/OrchardCore.Themes/TheAdmin/Views/Layout.cshtml +++ b/src/OrchardCore.Themes/TheAdmin/Views/Layout.cshtml @@ -21,8 +21,8 @@ - - + + @@ -39,10 +39,13 @@ } + + @await RenderSectionAsync("HeadMeta", required: false) +
@@ -91,5 +94,6 @@
+ From f6a165e4ac28d0202d9d35ccb97ad449b910a80f Mon Sep 17 00:00:00 2001 From: Niraj Soni <23270244+ns8482e@users.noreply.github.com> Date: Thu, 15 Feb 2024 17:40:36 -0600 Subject: [PATCH 2/4] fix error --- .../OrchardCore.Admin.WebAssembly.App/Program.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/Program.cs b/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/Program.cs index 2fd586a0722..d66eeba41d8 100644 --- a/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/Program.cs +++ b/src/OrchardCore.Components/OrchardCore.Admin.WebAssembly.App/Program.cs @@ -6,7 +6,6 @@ var builder = WebAssemblyHostBuilder.CreateDefault(args); builder.RootComponents.RegisterCustomElement("option-editor"); builder.RootComponents.RegisterCustomElement("init"); -builder.Services.AddScoped(); await builder.Build().RunAsync(); From dcb336bc4775931f36b07f8d5fbde305ba7318a7 Mon Sep 17 00:00:00 2001 From: Niraj Soni <23270244+ns8482e@users.noreply.github.com> Date: Sat, 17 Feb 2024 11:31:18 -0600 Subject: [PATCH 3/4] fixed typo --- .../{ColloctedJSComponent.cs => CollocatedJSComponent.cs} | 2 +- .../OrchardCore.Common.Components/OptionEditor.razor | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/OrchardCore.Components/OrchardCore.Common.Components/{ColloctedJSComponent.cs => CollocatedJSComponent.cs} (93%) diff --git a/src/OrchardCore.Components/OrchardCore.Common.Components/ColloctedJSComponent.cs b/src/OrchardCore.Components/OrchardCore.Common.Components/CollocatedJSComponent.cs similarity index 93% rename from src/OrchardCore.Components/OrchardCore.Common.Components/ColloctedJSComponent.cs rename to src/OrchardCore.Components/OrchardCore.Common.Components/CollocatedJSComponent.cs index 9725457134a..fde28f25fdd 100644 --- a/src/OrchardCore.Components/OrchardCore.Common.Components/ColloctedJSComponent.cs +++ b/src/OrchardCore.Components/OrchardCore.Common.Components/CollocatedJSComponent.cs @@ -8,7 +8,7 @@ namespace OrchardCore.Common.Components; -public class ColloctedJSComponent : ComponentBase, IAsyncDisposable +public class CollocatedJSComponent : ComponentBase, IAsyncDisposable { [Inject] private IJSRuntime? JS { get; set; } diff --git a/src/OrchardCore.Components/OrchardCore.Common.Components/OptionEditor.razor b/src/OrchardCore.Components/OrchardCore.Common.Components/OptionEditor.razor index ac70feb63ad..2183b811b8b 100644 --- a/src/OrchardCore.Components/OrchardCore.Common.Components/OptionEditor.razor +++ b/src/OrchardCore.Components/OrchardCore.Common.Components/OptionEditor.razor @@ -3,7 +3,7 @@ @using Microsoft.AspNetCore.Components.Forms @using Microsoft.JSInterop -@inherits ColloctedJSComponent +@inherits CollocatedJSComponent From bb976fac4c150dad7f50b94cb70b82950dc84aae Mon Sep 17 00:00:00 2001 From: Niraj Soni <23270244+ns8482e@users.noreply.github.com> Date: Mon, 19 Feb 2024 09:58:01 -0600 Subject: [PATCH 4/4] Blazor UI as feature --- .../Properties/launchSettings.json | 3 ++- .../OrchardAdminApp.razor | 12 ++++++----- .../_Imports.razor | 9 ++++++++- .../OrchardCore.Admin/Manifest.cs | 20 +++++++++++++++++-- .../OrchardCore.Admin/Startup.cs | 4 +++- .../Modules/Manifest/ManifestConstants.cs | 5 +++++ 6 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/OrchardCore.Cms.Web/Properties/launchSettings.json b/src/OrchardCore.Cms.Web/Properties/launchSettings.json index e6a7de11e84..f849a819433 100644 --- a/src/OrchardCore.Cms.Web/Properties/launchSettings.json +++ b/src/OrchardCore.Cms.Web/Properties/launchSettings.json @@ -21,7 +21,8 @@ "inspectUri": "{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}", "launchUrl": "https://localhost:5001", "environmentVariables": { - "ASPNETCORE_ENVIRONMENT": "Development" + "ASPNETCORE_ENVIRONMENT": "Development", + "ORCHARD_APP_DATA": "C:\\k8s\\oc_github" }, "applicationUrl": "https://localhost:5001;http://localhost:5000" } diff --git a/src/OrchardCore.Components/OrchardCore.Admin.Components/OrchardAdminApp.razor b/src/OrchardCore.Components/OrchardCore.Admin.Components/OrchardAdminApp.razor index dfe4bf31dc4..770e28d99ed 100644 --- a/src/OrchardCore.Components/OrchardCore.Admin.Components/OrchardAdminApp.razor +++ b/src/OrchardCore.Components/OrchardCore.Admin.Components/OrchardAdminApp.razor @@ -1,5 +1,7 @@ -

Future Admin App in Blazor

- -@code { - -} +@using Microsoft.AspNetCore.Components.Routing + + + + + + \ No newline at end of file diff --git a/src/OrchardCore.Components/OrchardCore.Admin.Components/_Imports.razor b/src/OrchardCore.Components/OrchardCore.Admin.Components/_Imports.razor index 77285129dab..97a9ff29cf3 100644 --- a/src/OrchardCore.Components/OrchardCore.Admin.Components/_Imports.razor +++ b/src/OrchardCore.Components/OrchardCore.Admin.Components/_Imports.razor @@ -1 +1,8 @@ -@using Microsoft.AspNetCore.Components.Web +@using System.Net.Http +@using System.Net.Http.Json +@using Microsoft.AspNetCore.Components.Forms +@using Microsoft.AspNetCore.Components.Routing +@using Microsoft.AspNetCore.Components.Web +@using static Microsoft.AspNetCore.Components.Web.RenderMode +@using Microsoft.AspNetCore.Components.Web.Virtualization +@using Microsoft.JSInterop \ No newline at end of file diff --git a/src/OrchardCore.Modules/OrchardCore.Admin/Manifest.cs b/src/OrchardCore.Modules/OrchardCore.Admin/Manifest.cs index d97764dd742..d6c11303f0c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Admin/Manifest.cs +++ b/src/OrchardCore.Modules/OrchardCore.Admin/Manifest.cs @@ -4,11 +4,27 @@ Name = "Admin", Author = ManifestConstants.OrchardCoreTeam, Website = ManifestConstants.OrchardCoreWebsite, - Version = ManifestConstants.OrchardCoreVersion, - Description = "Creates an admin section for the site.", + Version = ManifestConstants.OrchardCoreVersion +)] + +[assembly: Feature( + Id = "OrchardCore.Admin", + Name = "Admin", + Description = "Creates an admin section for the site.", Category = "Infrastructure", Dependencies = [ "OrchardCore.Settings" ] )] + +[assembly: Feature( + Id = ManifestConstants.Features.BlazorUI, + Name = "Blazor UI for Admin", + Category = "Infrastructure", + Description = "Adds support for the Blazor UI for Admin section.", + Dependencies = + [ + "OrchardCore.Admin" + ] +)] diff --git a/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs index 5298051afc9..f17f0e0c4c2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Admin/Startup.cs @@ -19,6 +19,7 @@ using OrchardCore.Environment.Shell.Configuration; using OrchardCore.Environment.Shell.Scope; using OrchardCore.Modules; +using OrchardCore.Modules.Manifest; using OrchardCore.Mvc.Core.Utilities; using OrchardCore.Mvc.Routing; using OrchardCore.Navigation; @@ -90,7 +91,7 @@ public override void ConfigureServices(IServiceCollection services) } } - + [Modules.Feature(ManifestConstants.Features.BlazorUI)] public class AdminComponentsStartup : StartupBase { public override int Order => 1; @@ -106,6 +107,7 @@ public override void ConfigureServices(IServiceCollection services) public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder routes, IServiceProvider serviceProvider) { + app.UseAntiforgery(); app.UseStaticFiles(); routes.MapRazorComponents() .AddInteractiveServerRenderMode() diff --git a/src/OrchardCore/OrchardCore.Abstractions/Modules/Manifest/ManifestConstants.cs b/src/OrchardCore/OrchardCore.Abstractions/Modules/Manifest/ManifestConstants.cs index e01761f5c0f..e88f0584658 100644 --- a/src/OrchardCore/OrchardCore.Abstractions/Modules/Manifest/ManifestConstants.cs +++ b/src/OrchardCore/OrchardCore.Abstractions/Modules/Manifest/ManifestConstants.cs @@ -10,4 +10,9 @@ public static class ManifestConstants public const string OrchardCoreWebsite = "https://orchardcore.net"; public const string AdminTag = "Admin"; + + public static class Features + { + public const string BlazorUI = "OrchardCore.Admin.BlazorUI"; + } }