From 17b870a0df981c77b0c3380812bf8ff6c7122e5b Mon Sep 17 00:00:00 2001 From: capdiem Date: Mon, 12 Aug 2024 14:39:26 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=86=95=20feat(PopupService):=20add=20supp?= =?UTF-8?q?ort=20for=20clearing=20all=20opended=20popups=20(#2098)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🆕 feat(PopupService): add support for clearing all opended popups * 📝 docs: add support for adding api meta for non-components * missing files --- .../Pages/Components.razor.cs | 8 ++- .../Services/BlazorDocService.cs | 27 +++++++- .../popup-service/IPopupService-en-US.json | 12 ++++ .../popup-service/IPopupService-zh-CN.json | 12 ++++ .../wwwroot/data/other-apis.json | 30 +++++++++ .../wwwroot/data/page-to-api.json | 3 + src/Masa.Blazor/Components/App/MApp.razor | 2 +- src/Masa.Blazor/Components/App/MApp.razor.cs | 8 ++- .../ServiceCollectionExtensions.cs | 1 - .../EnqueuedSnackbars.razor.cs | 4 +- src/Masa.Blazor/Popup/IPopupProvider.cs | 12 ---- src/Masa.Blazor/Popup/IPopupService.cs | 34 +++++++--- src/Masa.Blazor/Popup/PopupProvider.cs | 46 -------------- src/Masa.Blazor/Popup/PopupService.cs | 63 +++++++++++++++---- src/Masa.Blazor/Popup/ProviderItem.cs | 26 ++------ 15 files changed, 181 insertions(+), 107 deletions(-) create mode 100644 docs/Masa.Blazor.Docs/wwwroot/data/apis/popup-service/IPopupService-en-US.json create mode 100644 docs/Masa.Blazor.Docs/wwwroot/data/apis/popup-service/IPopupService-zh-CN.json create mode 100644 docs/Masa.Blazor.Docs/wwwroot/data/other-apis.json delete mode 100644 src/Masa.Blazor/Popup/IPopupProvider.cs delete mode 100644 src/Masa.Blazor/Popup/PopupProvider.cs diff --git a/docs/Masa.Blazor.Docs/Pages/Components.razor.cs b/docs/Masa.Blazor.Docs/Pages/Components.razor.cs index f7b8f412ce..2cf4dac39c 100644 --- a/docs/Masa.Blazor.Docs/Pages/Components.razor.cs +++ b/docs/Masa.Blazor.Docs/Pages/Components.razor.cs @@ -203,7 +203,7 @@ private async Task ReadApisAsync() foreach (var item in apis) { var (dir, componentName) = Resolve(item, Page); - _apiData[componentName] = await getApiGroupAsync(dir, componentName, true); + _apiData[componentName] = await getApiGroupAsync(dir, componentName, true); } } else @@ -214,7 +214,9 @@ private async Task ReadApisAsync() async Task>> getApiGroupAsync(string dir, string componentName, bool isFullname = false) { + var otherApis = await BlazorDocService.GetOtherApisAsync(); var componentApiMetas = GetAllComponentApiMetas(); + componentApiMetas.AddRange(otherApis); var component = isFullname ? componentApiMetas.FirstOrDefault(u => u.Name == componentName) @@ -224,7 +226,7 @@ async Task>> getApiGroupAsync(string dir, if (component is not null) { componentName = component.Name; - + var parametersCacheValue = component.Parameters; parametersCacheValue = parametersCacheValue.Where(item => item.Value.Count > 0).ToDictionary(item => item.Key, item => item.Value); @@ -265,7 +267,7 @@ async Task>> getApiGroupAsync(string dir, return name?.TrimEnd('s').ToPascal(); } - private static IEnumerable GetAllComponentApiMetas() + private static List GetAllComponentApiMetas() { var list = ApiGenerator.ComponentMetas.ToList(); list.AddRange(SomethingSkiaApiGenerator.ComponentMetas); diff --git a/docs/Masa.Blazor.Docs/Services/BlazorDocService.cs b/docs/Masa.Blazor.Docs/Services/BlazorDocService.cs index 88212b7267..cf978f00b1 100644 --- a/docs/Masa.Blazor.Docs/Services/BlazorDocService.cs +++ b/docs/Masa.Blazor.Docs/Services/BlazorDocService.cs @@ -1,4 +1,5 @@ using System.Net.Http.Json; +using System.Text.Json; namespace Masa.Blazor.Docs.Services; @@ -12,6 +13,7 @@ public class BlazorDocService private readonly Lazy>>?>> _commonApis; private Dictionary>? _apiInPageCache; + private List? _otherApis; public BlazorDocService(IHttpClientFactory factory, I18n i18n) { @@ -61,6 +63,29 @@ public async Task>> ReadPageToApiAsync() return _apiInPageCache ?? new Dictionary>(); } + public async Task> GetOtherApisAsync() + { + if (_otherApis is not null) + { + return _otherApis; + } + + try + { + var json = await _httpClient.GetStringAsync("_content/Masa.Blazor.Docs/data/other-apis.json"); + _otherApis = JsonSerializer.Deserialize>(json, new JsonSerializerOptions(JsonSerializerDefaults.Web) + { + UnmappedMemberHandling = System.Text.Json.Serialization.JsonUnmappedMemberHandling.Skip + }); + } + catch (Exception) + { + // ignored + } + + return _otherApis ?? []; + } + public async Task>?> ReadApisAsync(string kebabCaseComponent, string? apiName = null) { var key = $"{kebabCaseComponent}/{(apiName is null ? "" : apiName + "-")}{_i18n.Culture.Name}"; @@ -96,7 +121,7 @@ public async Task>> ReadPageToApiAsync() api.TryAdd(prop, desc); } } - + if (commonApiInfo.TryGetValue(category, out var commonApi)) { foreach (var (prop, desc) in commonApi) diff --git a/docs/Masa.Blazor.Docs/wwwroot/data/apis/popup-service/IPopupService-en-US.json b/docs/Masa.Blazor.Docs/wwwroot/data/apis/popup-service/IPopupService-en-US.json new file mode 100644 index 0000000000..3af5a7ce0c --- /dev/null +++ b/docs/Masa.Blazor.Docs/wwwroot/data/apis/popup-service/IPopupService-en-US.json @@ -0,0 +1,12 @@ +{ + "props": {}, + "events": {}, + "contents": {}, + "methods": { + "openAsync": "Open the specified type of popup component and wait for the result.", + "open": "Open the specified type of popup component.", + "close": "Close the specified type of popup component.", + "clear": "Clear all opened popup components.", + "enqueueSnackbarAsync": "Enqueue a snackbar to show." + } +} \ No newline at end of file diff --git a/docs/Masa.Blazor.Docs/wwwroot/data/apis/popup-service/IPopupService-zh-CN.json b/docs/Masa.Blazor.Docs/wwwroot/data/apis/popup-service/IPopupService-zh-CN.json new file mode 100644 index 0000000000..fac191b5cb --- /dev/null +++ b/docs/Masa.Blazor.Docs/wwwroot/data/apis/popup-service/IPopupService-zh-CN.json @@ -0,0 +1,12 @@ +{ + "props": {}, + "events": {}, + "contents": {}, + "methods": { + "openAsync": "打开指定类型的弹出组件,可等待结果", + "open": "打开指定类型的弹出组件", + "close": "关闭指定类型的弹出组件", + "clear": "关闭所有弹出组件", + "enqueueSnackbarAsync": "新增消息提示" + } +} \ No newline at end of file diff --git a/docs/Masa.Blazor.Docs/wwwroot/data/other-apis.json b/docs/Masa.Blazor.Docs/wwwroot/data/other-apis.json new file mode 100644 index 0000000000..ec1f70ffff --- /dev/null +++ b/docs/Masa.Blazor.Docs/wwwroot/data/other-apis.json @@ -0,0 +1,30 @@ +[ + { + "name": "IPopupService", + "parameters": { + "methods": [ + { + "name": "OpenAsync", + "type": "(Type componentType, Dictionary parameters) => Task" + }, + { + "name": "Open", + "type": "(Type componentType, Dictionary parameters) => void" + }, + { + "name": "Close", + "type": "(Type componentType) => void" + }, + { + "name": "Clear", + "type": "() => void", + "releasedOn": "v1.7.0" + }, + { + "name": "EnqueueSnackbarAsync", + "type": "(SnackbarOptions options) => Task" + } + ] + } + } +] diff --git a/docs/Masa.Blazor.Docs/wwwroot/data/page-to-api.json b/docs/Masa.Blazor.Docs/wwwroot/data/page-to-api.json index 6f54681f46..d96f1c6147 100644 --- a/docs/Masa.Blazor.Docs/wwwroot/data/page-to-api.json +++ b/docs/Masa.Blazor.Docs/wwwroot/data/page-to-api.json @@ -139,6 +139,9 @@ "PPageContainer", "PPageProvider" ], + "popup-service": [ + "IPopupService" + ], "radios": [ "MRadio", "MRadioGroup" diff --git a/src/Masa.Blazor/Components/App/MApp.razor b/src/Masa.Blazor/Components/App/MApp.razor index 8f7fbd0831..336f731688 100644 --- a/src/Masa.Blazor/Components/App/MApp.razor +++ b/src/Masa.Blazor/Components/App/MApp.razor @@ -13,7 +13,7 @@ @ChildContent - @foreach (var item in PopupProvider.GetItems()) + @foreach (var item in PopupService.GetItems()) { diff --git a/src/Masa.Blazor/Components/App/MApp.razor.cs b/src/Masa.Blazor/Components/App/MApp.razor.cs index 5bdf49a907..2ec5054e1c 100644 --- a/src/Masa.Blazor/Components/App/MApp.razor.cs +++ b/src/Masa.Blazor/Components/App/MApp.razor.cs @@ -9,7 +9,7 @@ public partial class MApp : MasaComponentBase, IDefaultsProvider { [Inject] private MasaBlazor MasaBlazor { get; set; } = null!; - [Inject] private IPopupProvider PopupProvider { get; set; } = null!; + [Inject] private IPopupService InternalPopupService { get; set; } = null!; [Parameter] public RenderFragment? ChildContent { get; set; } @@ -17,11 +17,13 @@ public partial class MApp : MasaComponentBase, IDefaultsProvider protected bool IsDark => MasaBlazor?.Theme is { Dark: true }; + private PopupService PopupService => (PopupService)InternalPopupService; + protected override void OnInitialized() { base.OnInitialized(); - PopupProvider.StateChanged += OnStateChanged; + PopupService.StateChanged += OnStateChanged; MasaBlazor.OnThemeChange += OnThemeChange; MasaBlazor.RTLChanged += OnRTLChanged; MasaBlazor.DefaultsChanged += OnDefaultsChanged; @@ -87,7 +89,7 @@ protected override IEnumerable BuildComponentClass() protected override ValueTask DisposeAsyncCore() { - PopupProvider.StateChanged -= OnStateChanged; + PopupService.StateChanged -= OnStateChanged; MasaBlazor.OnThemeChange -= OnThemeChange; MasaBlazor.RTLChanged -= OnRTLChanged; MasaBlazor.DefaultsChanged -= OnDefaultsChanged; diff --git a/src/Masa.Blazor/Extensions/DependencyInjection/ServiceCollectionExtensions.cs b/src/Masa.Blazor/Extensions/DependencyInjection/ServiceCollectionExtensions.cs index acabdce3a5..ea3234fd15 100644 --- a/src/Masa.Blazor/Extensions/DependencyInjection/ServiceCollectionExtensions.cs +++ b/src/Masa.Blazor/Extensions/DependencyInjection/ServiceCollectionExtensions.cs @@ -73,7 +73,6 @@ private static IMasaBlazorBuilder AddMasaBlazorInternal(this IServiceCollection options.Defaults); }, masaBlazorServiceLifetime)); - services.TryAdd(masaBlazorServiceLifetime); services.TryAdd(masaBlazorServiceLifetime); services.TryAddScoped(); diff --git a/src/Masa.Blazor/Popup/Components/EnqueuedSnackbars/EnqueuedSnackbars.razor.cs b/src/Masa.Blazor/Popup/Components/EnqueuedSnackbars/EnqueuedSnackbars.razor.cs index afd9d6ab15..8faa3ac67e 100644 --- a/src/Masa.Blazor/Popup/Components/EnqueuedSnackbars/EnqueuedSnackbars.razor.cs +++ b/src/Masa.Blazor/Popup/Components/EnqueuedSnackbars/EnqueuedSnackbars.razor.cs @@ -3,7 +3,7 @@ public partial class EnqueuedSnackbars : ComponentBase, IAsyncDisposable { [Inject] - private IPopupService PopupService { get; set; } = null!; + private IPopupService InternalPopupService { get; set; } = null!; [Inject] private MasaBlazor MasaBlazor { get; set; } = null!; @@ -40,6 +40,8 @@ public partial class EnqueuedSnackbars : ComponentBase, IAsyncDisposable private PEnqueuedSnackbars? _enqueuedSnackbars; + private PopupService PopupService => (PopupService)InternalPopupService; + protected override async Task OnInitializedAsync() { PopupService.SnackbarOpen += OnSnackbarOpenAsync; diff --git a/src/Masa.Blazor/Popup/IPopupProvider.cs b/src/Masa.Blazor/Popup/IPopupProvider.cs deleted file mode 100644 index 933d9e0c03..0000000000 --- a/src/Masa.Blazor/Popup/IPopupProvider.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Masa.Blazor.Popup; - -public interface IPopupProvider -{ - event EventHandler StateChanged; - - ProviderItem Add(Type componentType, IDictionary? attributes, object service, string serviceName); - - void Remove(ProviderItem item); - - IEnumerable GetItems(); -} diff --git a/src/Masa.Blazor/Popup/IPopupService.cs b/src/Masa.Blazor/Popup/IPopupService.cs index 7cffc80f2b..83198e614c 100644 --- a/src/Masa.Blazor/Popup/IPopupService.cs +++ b/src/Masa.Blazor/Popup/IPopupService.cs @@ -2,16 +2,36 @@ public interface IPopupService { - Task OpenAsync(Type componentType, IDictionary parameters); - - void Open(Type componentType, IDictionary? parameters = null); + /// + /// Clear all opened popup components. + /// + void Clear(); + /// + /// Close the specified type of popup component. + /// + /// void Close(Type componentType); - #region Snackbar - - event Func SnackbarOpen; + /// + /// Enqueue a snackbar to show. + /// + /// + /// + /// Open the specified type of popup component and wait for the result. + /// + /// + /// + /// + Task OpenAsync(Type componentType, IDictionary parameters); + + /// + /// Open the specified type of popup component. + /// + /// + /// + void Open(Type componentType, IDictionary? parameters = null); } diff --git a/src/Masa.Blazor/Popup/PopupProvider.cs b/src/Masa.Blazor/Popup/PopupProvider.cs deleted file mode 100644 index a8021bac4d..0000000000 --- a/src/Masa.Blazor/Popup/PopupProvider.cs +++ /dev/null @@ -1,46 +0,0 @@ -namespace Masa.Blazor.Popup; - -public class PopupProvider : IPopupProvider -{ - private readonly List _items = new(); - private readonly object _obj = new(); - - public event EventHandler? StateChanged; - - public ProviderItem Add(Type componentType, IDictionary? attributes, object service, string serviceName) - { - var item = new ProviderItem(componentType, attributes, this, service, serviceName); - - lock (_obj) - { - _items.Add(item); - } - - StateHasChanged(); - - return item; - } - - public void Remove(ProviderItem item) - { - lock (_obj) - { - _items.Remove(item); - } - - StateHasChanged(); - } - - public IEnumerable GetItems() - { - lock (_obj) - { - return _items; - } - } - - private void StateHasChanged() - { - StateChanged?.Invoke(this, EventArgs.Empty); - } -} diff --git a/src/Masa.Blazor/Popup/PopupService.cs b/src/Masa.Blazor/Popup/PopupService.cs index 3e64054555..2e87ce4c1d 100644 --- a/src/Masa.Blazor/Popup/PopupService.cs +++ b/src/Masa.Blazor/Popup/PopupService.cs @@ -5,45 +5,84 @@ namespace Masa.Blazor; public class PopupService : IPopupService { - private readonly IPopupProvider _popupProvider; + private readonly List _items = []; + private readonly object _obj = new(); - public event Func? SnackbarOpen; + internal event EventHandler? StateChanged; + internal event Func? SnackbarOpen; - public PopupService(IPopupProvider popupProvider) + public PopupService() { - _popupProvider = popupProvider; - _ = OpenAsync(typeof(EnqueuedSnackbars), new Dictionary()); } public void Open(Type componentType, IDictionary? parameters = null) { - OpenComponent(componentType, parameters); + Add(componentType, parameters); } public Task OpenAsync(Type componentType, IDictionary parameters) { - return OpenComponent(componentType, parameters).TaskCompletionSource.Task; + return Add(componentType, parameters).TaskCompletionSource.Task; } public void Close(Type componentType) { - var item = _popupProvider.GetItems().LastOrDefault(u => u.ComponentType == componentType); + var item = GetItems().LastOrDefault(u => u.ComponentType == componentType); if (item is not null) { - _popupProvider.Remove(item); + Remove(item); } } + public void Clear() + { + _items.Clear(); + StateHasChanged(); + } + public async Task EnqueueSnackbarAsync(SnackbarOptions options) { - if (SnackbarOpen is null) return; + if (SnackbarOpen is null) + return; await SnackbarOpen.Invoke(options); } - private ProviderItem OpenComponent(Type componentType, IDictionary? parameters) + internal ProviderItem Add(Type componentType, IDictionary? attributes) + { + var item = new ProviderItem(componentType, attributes, this); + + lock (_obj) + { + _items.Add(item); + + StateHasChanged(); + + return item; + } + } + + internal void Remove(ProviderItem item) + { + lock (_obj) + { + _items.Remove(item); + + StateHasChanged(); + } + } + + internal IEnumerable GetItems() + { + lock (_obj) + { + return _items; + } + } + + private void StateHasChanged() { - return _popupProvider.Add(componentType, parameters, this, nameof(PopupService)); + StateChanged?.Invoke(this, EventArgs.Empty); } } diff --git a/src/Masa.Blazor/Popup/ProviderItem.cs b/src/Masa.Blazor/Popup/ProviderItem.cs index 8cbfdbb641..a8e7f094e6 100644 --- a/src/Masa.Blazor/Popup/ProviderItem.cs +++ b/src/Masa.Blazor/Popup/ProviderItem.cs @@ -1,32 +1,18 @@ namespace Masa.Blazor.Popup; -public class ProviderItem +public class ProviderItem(Type componentType, IDictionary? parameters, PopupService service) { - public Type ComponentType { get; set; } + public Type ComponentType { get; set; } = componentType; - public PopupProvider Provider { get; set; } + public PopupService Service { get; set; } = service; - public TaskCompletionSource TaskCompletionSource { get; set; } + public TaskCompletionSource TaskCompletionSource { get; set; } = new(); - public object Service { get; set; } - - public string ServiceName { get; set; } - - public IDictionary? Parameters { get; set; } - - public ProviderItem(Type componentType, IDictionary? parameters, PopupProvider provider, object service, string serviceName) - { - TaskCompletionSource = new(); - Parameters = parameters; - ComponentType = componentType; - Provider = provider; - Service = service; - ServiceName = serviceName; - } + public IDictionary? Parameters { get; set; } = parameters; public void Discard(object? result) { TaskCompletionSource.TrySetResult(result); - Provider.Remove(this); + Service.Remove(this); } }