From f3b152e8d11d2c94cfc2dd01f9eca0a861c7428d Mon Sep 17 00:00:00 2001 From: liangshiwei Date: Fri, 25 Feb 2022 00:25:11 +0800 Subject: [PATCH] Initial commit --- .gitattributes | 2 + .gitignore | 398 ++++++++++++ .../.idea/.gitignore | 13 + .../.idea/encodings.xml | 4 + .../.idea/indexLayout.xml | 8 + LICENSE | 21 + README.md | 2 + configureawait.props | 9 + lsw.Abp.AntDesignUI.sln | 21 + src/BreadcrumbItem.cs | 19 + .../AbpAntDesignUIModule.cs | 20 + src/Lsw.Abp.AntDesignUI/AbpCrudPageBase.cs | 595 ++++++++++++++++++ .../AntDesignExtensions.cs | 8 + .../AntDesignUiMessageService.cs | 98 +++ .../AntDesignUiNotificationService.cs | 72 +++ .../AntDesignUiPageProgressService.cs | 27 + src/Lsw.Abp.AntDesignUI/BreadcrumbItem.cs | 17 + .../Components/AbpExtensibleDataGrid.razor | 76 +++ .../Components/AbpExtensibleDataGrid.razor.cs | 72 +++ .../Components/ActionType.cs | 7 + .../Components/EntityAction.razor | 28 + .../Components/EntityAction.razor.cs | 76 +++ .../Components/EntityActions.razor | 39 ++ .../Components/EntityActions.razor.cs | 69 ++ .../Components/PageAlert.razor | 51 ++ .../Components/TableEntityActionsColumn.razor | 20 + .../Components/ToolbarButton.razor | 25 + .../Components/UiPageProgress.razor | 12 + .../Components/UiPageProgress.razor.cs | 47 ++ src/Lsw.Abp.AntDesignUI/FodyWeavers.xml | 3 + .../Lsw.Abp.AntDesignUI.csproj | 16 + src/Lsw.Abp.AntDesignUI/_Imports.razor | 2 + 32 files changed, 1877 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .idea/.idea.lsw.Abp.AntDesignUI/.idea/.gitignore create mode 100644 .idea/.idea.lsw.Abp.AntDesignUI/.idea/encodings.xml create mode 100644 .idea/.idea.lsw.Abp.AntDesignUI/.idea/indexLayout.xml create mode 100644 LICENSE create mode 100644 README.md create mode 100644 configureawait.props create mode 100644 lsw.Abp.AntDesignUI.sln create mode 100644 src/BreadcrumbItem.cs create mode 100644 src/Lsw.Abp.AntDesignUI/AbpAntDesignUIModule.cs create mode 100644 src/Lsw.Abp.AntDesignUI/AbpCrudPageBase.cs create mode 100644 src/Lsw.Abp.AntDesignUI/AntDesignExtensions.cs create mode 100644 src/Lsw.Abp.AntDesignUI/AntDesignUiMessageService.cs create mode 100644 src/Lsw.Abp.AntDesignUI/AntDesignUiNotificationService.cs create mode 100644 src/Lsw.Abp.AntDesignUI/AntDesignUiPageProgressService.cs create mode 100644 src/Lsw.Abp.AntDesignUI/BreadcrumbItem.cs create mode 100644 src/Lsw.Abp.AntDesignUI/Components/AbpExtensibleDataGrid.razor create mode 100644 src/Lsw.Abp.AntDesignUI/Components/AbpExtensibleDataGrid.razor.cs create mode 100644 src/Lsw.Abp.AntDesignUI/Components/ActionType.cs create mode 100644 src/Lsw.Abp.AntDesignUI/Components/EntityAction.razor create mode 100644 src/Lsw.Abp.AntDesignUI/Components/EntityAction.razor.cs create mode 100644 src/Lsw.Abp.AntDesignUI/Components/EntityActions.razor create mode 100644 src/Lsw.Abp.AntDesignUI/Components/EntityActions.razor.cs create mode 100644 src/Lsw.Abp.AntDesignUI/Components/PageAlert.razor create mode 100644 src/Lsw.Abp.AntDesignUI/Components/TableEntityActionsColumn.razor create mode 100644 src/Lsw.Abp.AntDesignUI/Components/ToolbarButton.razor create mode 100644 src/Lsw.Abp.AntDesignUI/Components/UiPageProgress.razor create mode 100644 src/Lsw.Abp.AntDesignUI/Components/UiPageProgress.razor.cs create mode 100644 src/Lsw.Abp.AntDesignUI/FodyWeavers.xml create mode 100644 src/Lsw.Abp.AntDesignUI/Lsw.Abp.AntDesignUI.csproj create mode 100644 src/Lsw.Abp.AntDesignUI/_Imports.razor diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..426d76d --- /dev/null +++ b/.gitignore @@ -0,0 +1,398 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml diff --git a/.idea/.idea.lsw.Abp.AntDesignUI/.idea/.gitignore b/.idea/.idea.lsw.Abp.AntDesignUI/.idea/.gitignore new file mode 100644 index 0000000..550a3af --- /dev/null +++ b/.idea/.idea.lsw.Abp.AntDesignUI/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/projectSettingsUpdater.xml +/contentModel.xml +/.idea.lsw.Abp.AntDesignUI.iml +/modules.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/.idea.lsw.Abp.AntDesignUI/.idea/encodings.xml b/.idea/.idea.lsw.Abp.AntDesignUI/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/.idea/.idea.lsw.Abp.AntDesignUI/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/.idea.lsw.Abp.AntDesignUI/.idea/indexLayout.xml b/.idea/.idea.lsw.Abp.AntDesignUI/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/.idea/.idea.lsw.Abp.AntDesignUI/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d4279b5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 liangshiwei + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..4a9024f --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Lsw.Abp.AntDesignUI + diff --git a/configureawait.props b/configureawait.props new file mode 100644 index 0000000..b0cf9ef --- /dev/null +++ b/configureawait.props @@ -0,0 +1,9 @@ + + + + + All + runtime; build; native; contentfiles; analyzers + + + \ No newline at end of file diff --git a/lsw.Abp.AntDesignUI.sln b/lsw.Abp.AntDesignUI.sln new file mode 100644 index 0000000..7579f07 --- /dev/null +++ b/lsw.Abp.AntDesignUI.sln @@ -0,0 +1,21 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{6C9F4322-BDC7-42DA-ACBD-1AC641B907B4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lsw.Abp.AntDesignUI", "src\Lsw.Abp.AntDesignUI\Lsw.Abp.AntDesignUI.csproj", "{9EA4AA35-DEFC-4C25-8333-78137853EC5D}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9EA4AA35-DEFC-4C25-8333-78137853EC5D} = {6C9F4322-BDC7-42DA-ACBD-1AC641B907B4} + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {9EA4AA35-DEFC-4C25-8333-78137853EC5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9EA4AA35-DEFC-4C25-8333-78137853EC5D}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9EA4AA35-DEFC-4C25-8333-78137853EC5D}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9EA4AA35-DEFC-4C25-8333-78137853EC5D}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/src/BreadcrumbItem.cs b/src/BreadcrumbItem.cs new file mode 100644 index 0000000..4c1c951 --- /dev/null +++ b/src/BreadcrumbItem.cs @@ -0,0 +1,19 @@ +using Blazorise; + +namespace Lsw.Abp.AntDesignUI; + +public class BreadcrumbItem +{ + public string Text { get; set; } + + public object Icon { get; set; } + + public string Url { get; set; } + + public BreadcrumbItem(string text, string url = null, object icon = null) + { + Text = text; + Url = url; + Icon = icon; + } +} diff --git a/src/Lsw.Abp.AntDesignUI/AbpAntDesignUIModule.cs b/src/Lsw.Abp.AntDesignUI/AbpAntDesignUIModule.cs new file mode 100644 index 0000000..136aa6b --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/AbpAntDesignUIModule.cs @@ -0,0 +1,20 @@ +using Microsoft.Extensions.DependencyInjection; +using Volo.Abp.Application; +using Volo.Abp.AspNetCore.Components.Web; +using Volo.Abp.Authorization; +using Volo.Abp.Modularity; + +namespace Lsw.Abp.AntDesignUI; + +[DependsOn( + typeof(AbpAspNetCoreComponentsWebModule), + typeof(AbpDddApplicationContractsModule), + typeof(AbpAuthorizationModule) +)] +public class AbpAntDesignUIModule : AbpModule +{ + public override void ConfigureServices(ServiceConfigurationContext context) + { + context.Services.AddAntDesign(); + } +} diff --git a/src/Lsw.Abp.AntDesignUI/AbpCrudPageBase.cs b/src/Lsw.Abp.AntDesignUI/AbpCrudPageBase.cs new file mode 100644 index 0000000..9d77599 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/AbpCrudPageBase.cs @@ -0,0 +1,595 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using AntDesign; +using AntDesign.TableModels; +using JetBrains.Annotations; +using Localization.Resources.AbpUi; +using Lsw.Abp.AntDesignUI.Components; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; +using Microsoft.Extensions.Localization; +using Volo.Abp.Application.Dtos; +using Volo.Abp.Application.Services; +using Volo.Abp.AspNetCore.Components; +using Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions; +using Volo.Abp.AspNetCore.Components.Web.Extensibility.TableColumns; +using Volo.Abp.Authorization; + +namespace Lsw.Abp.AntDesignUI; + +public abstract class AbpCrudPageBase< + TAppService, + TEntityDto, + TKey> + : AbpCrudPageBase< + TAppService, + TEntityDto, + TKey, + PagedAndSortedResultRequestDto> + where TAppService : ICrudAppService< + TEntityDto, + TKey> + where TEntityDto : class, IEntityDto, new() +{ +} + +public abstract class AbpCrudPageBase< + TAppService, + TEntityDto, + TKey, + TGetListInput> + : AbpCrudPageBase< + TAppService, + TEntityDto, + TKey, + TGetListInput, + TEntityDto> + where TAppService : ICrudAppService< + TEntityDto, + TKey, + TGetListInput> + where TEntityDto : class, IEntityDto, new() + where TGetListInput : new() +{ +} + +public abstract class AbpCrudPageBase< + TAppService, + TEntityDto, + TKey, + TGetListInput, + TCreateInput> + : AbpCrudPageBase< + TAppService, + TEntityDto, + TKey, + TGetListInput, + TCreateInput, + TCreateInput> + where TAppService : ICrudAppService< + TEntityDto, + TKey, + TGetListInput, + TCreateInput> + where TEntityDto : IEntityDto + where TCreateInput : class, new() + where TGetListInput : new() +{ +} + +public abstract class AbpCrudPageBase< + TAppService, + TEntityDto, + TKey, + TGetListInput, + TCreateInput, + TUpdateInput> + : AbpCrudPageBase< + TAppService, + TEntityDto, + TEntityDto, + TKey, + TGetListInput, + TCreateInput, + TUpdateInput> + where TAppService : ICrudAppService< + TEntityDto, + TKey, + TGetListInput, + TCreateInput, + TUpdateInput> + where TEntityDto : IEntityDto + where TCreateInput : class, new() + where TUpdateInput : class, new() + where TGetListInput : new() +{ +} + +public abstract class AbpCrudPageBase< + TAppService, + TGetOutputDto, + TGetListOutputDto, + TKey, + TGetListInput, + TCreateInput, + TUpdateInput> + : AbpCrudPageBase< + TAppService, + TGetOutputDto, + TGetListOutputDto, + TKey, + TGetListInput, + TCreateInput, + TUpdateInput, + TGetListOutputDto, + TCreateInput, + TUpdateInput> + where TAppService : ICrudAppService< + TGetOutputDto, + TGetListOutputDto, + TKey, + TGetListInput, + TCreateInput, + TUpdateInput> + where TGetOutputDto : IEntityDto + where TGetListOutputDto : IEntityDto + where TCreateInput : class, new() + where TUpdateInput : class, new() + where TGetListInput : new() +{ +} + +public abstract class AbpCrudPageBase< + TAppService, + TGetOutputDto, + TGetListOutputDto, + TKey, + TGetListInput, + TCreateInput, + TUpdateInput, + TListViewModel, + TCreateViewModel, + TUpdateViewModel> + : AbpComponentBase + where TAppService : ICrudAppService< + TGetOutputDto, + TGetListOutputDto, + TKey, + TGetListInput, + TCreateInput, + TUpdateInput> + where TGetOutputDto : IEntityDto + where TGetListOutputDto : IEntityDto + where TCreateInput : class + where TUpdateInput : class + where TGetListInput : new() + where TListViewModel : IEntityDto + where TCreateViewModel : class, new() + where TUpdateViewModel : class, new() +{ + [Inject] protected TAppService AppService { get; set; } + + [Inject] protected IStringLocalizer UiLocalizer { get; set; } + + protected virtual int PageSize { get; } = LimitedResultRequestDto.DefaultMaxResultCount; + + protected int CurrentPage = 1; + protected string CurrentSorting; + protected int? TotalCount; + protected bool Loading = false; + protected TGetListInput GetListInput = new(); + protected IReadOnlyList Entities = Array.Empty(); + protected TCreateViewModel NewEntity; + protected TKey EditingEntityId; + protected TUpdateViewModel EditingEntity; + protected Modal CreateModal; + protected bool CreateModalVisible; + protected Modal EditModal; + protected bool EditModalVisible; + protected Form CreateFormRef; + protected Form EditFormRef; + protected List BreadcrumbItems = new(2); + protected TableEntityActionsColumn EntityActionsColumn; + protected EntityActionDictionary EntityActions { get; set; } + protected TableColumnDictionary TableColumns { get; set; } + + protected string CreatePolicyName { get; set; } + protected string UpdatePolicyName { get; set; } + protected string DeletePolicyName { get; set; } + + public bool HasCreatePermission { get; set; } + public bool HasUpdatePermission { get; set; } + public bool HasDeletePermission { get; set; } + + protected AbpCrudPageBase() + { + NewEntity = new TCreateViewModel(); + EditingEntity = new TUpdateViewModel(); + TableColumns = new TableColumnDictionary(); + EntityActions = new EntityActionDictionary(); + } + + protected override async Task OnInitializedAsync() + { + await SetPermissionsAsync(); + await SetEntityActionsAsync(); + await SetTableColumnsAsync(); + await InvokeAsync(StateHasChanged); + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + await base.OnAfterRenderAsync(true); + await SetToolbarItemsAsync(); + await SetBreadcrumbItemsAsync(); + } + } + + protected virtual async Task SetPermissionsAsync() + { + if (CreatePolicyName != null) + { + HasCreatePermission = await AuthorizationService.IsGrantedAsync(CreatePolicyName); + } + + if (UpdatePolicyName != null) + { + HasUpdatePermission = await AuthorizationService.IsGrantedAsync(UpdatePolicyName); + } + + if (DeletePolicyName != null) + { + HasDeletePermission = await AuthorizationService.IsGrantedAsync(DeletePolicyName); + } + } + + protected virtual async Task GetEntitiesAsync() + { + try + { + Loading = true; + await UpdateGetListInputAsync(); + var result = await AppService.GetListAsync(GetListInput); + Entities = MapToListViewModel(result.Items); + TotalCount = (int?)result.TotalCount; + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + + Loading = false; + } + + private IReadOnlyList MapToListViewModel(IReadOnlyList dtos) + { + if (typeof(TGetListOutputDto) == typeof(TListViewModel)) + { + return dtos.As>(); + } + + return ObjectMapper.Map, List>(dtos); + } + + protected virtual Task UpdateGetListInputAsync() + { + if (GetListInput is ISortedResultRequest sortedResultRequestInput) + { + sortedResultRequestInput.Sorting = CurrentSorting; + } + + if (GetListInput is IPagedResultRequest pagedResultRequestInput) + { + pagedResultRequestInput.SkipCount = (CurrentPage - 1) * PageSize; + } + + if (GetListInput is ILimitedResultRequest limitedResultRequestInput) + { + limitedResultRequestInput.MaxResultCount = PageSize; + } + + return Task.CompletedTask; + } + + protected virtual async Task SearchEntitiesAsync() + { + CurrentPage = 1; + + await GetEntitiesAsync(); + + await InvokeAsync(StateHasChanged); + } + + protected virtual async Task OnDataGridReadAsync(QueryModel e) + { + CurrentSorting = e.SortModel + .Select(c => c.FieldName + (c.Sort == "descend" ? " DESC" : "")) + .JoinAsString(","); + CurrentPage = e.PageIndex; + + await GetEntitiesAsync(); + + await InvokeAsync(StateHasChanged); + } + + protected virtual async Task OpenCreateModalAsync() + { + try + { + CreateFormRef.Reset(); + + await CheckCreatePolicyAsync(); + + NewEntity = new TCreateViewModel(); + + await InvokeAsync(() => + { + StateHasChanged(); + CreateModalVisible = true; + + return Task.CompletedTask; + }); + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } + + protected virtual Task CloseCreateModalAsync() + { + NewEntity = new TCreateViewModel(); + + return InvokeAsync(() => + { + CreateModalVisible = false; + }); + } + + protected virtual Task ClosingCreateModal(MouseEventArgs eventArgs) + { + return Task.CompletedTask; + } + + protected virtual async Task OpenEditModalAsync(TListViewModel entity) + { + try + { + EditFormRef.Reset(); + + await CheckUpdatePolicyAsync(); + + var entityDto = await AppService.GetAsync(entity.Id); + + EditingEntityId = entity.Id; + EditingEntity = MapToEditingEntity(entityDto); + + await InvokeAsync(() => + { + StateHasChanged(); + EditModalVisible = true; + + return Task.CompletedTask; + }); + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } + + protected virtual TUpdateViewModel MapToEditingEntity(TGetOutputDto entityDto) + { + return ObjectMapper.Map(entityDto); + } + + protected virtual TCreateInput MapToCreateInput(TCreateViewModel createViewModel) + { + if (typeof(TCreateInput) == typeof(TCreateViewModel)) + { + return createViewModel.As(); + } + + return ObjectMapper.Map(createViewModel); + } + + protected virtual TUpdateInput MapToUpdateInput(TUpdateViewModel updateViewModel) + { + if (typeof(TUpdateInput) == typeof(TUpdateViewModel)) + { + return updateViewModel.As(); + } + + return ObjectMapper.Map(updateViewModel); + } + + protected virtual Task CloseEditModalAsync() + { + InvokeAsync(() => + { + EditModalVisible = false; + }); + return Task.CompletedTask; + } + + protected virtual Task ClosingEditModal(MouseEventArgs eventArgs) + { + return Task.CompletedTask; + } + + protected virtual async Task CreateEntityAsync() + { + try + { + var validate = true; + if (CreateFormRef != null) + { + validate = CreateFormRef.Validate(); + } + + if (validate) + { + await OnCreatingEntityAsync(); + + await CheckCreatePolicyAsync(); + var createInput = MapToCreateInput(NewEntity); + await AppService.CreateAsync(createInput); + + await OnCreatedEntityAsync(); + } + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } + + protected virtual Task OnCreatingEntityAsync() + { + return Task.CompletedTask; + } + + protected virtual async Task OnCreatedEntityAsync() + { + NewEntity = new TCreateViewModel(); + await GetEntitiesAsync(); + + await InvokeAsync(() => + { + CreateModalVisible = false; + }); + } + + protected virtual async Task UpdateEntityAsync() + { + try + { + var validate = true; + if (EditFormRef != null) + { + validate = EditFormRef.Validate(); + } + + if (validate) + { + await OnUpdatingEntityAsync(); + + await CheckUpdatePolicyAsync(); + var updateInput = MapToUpdateInput(EditingEntity); + await AppService.UpdateAsync(EditingEntityId, updateInput); + + await OnUpdatedEntityAsync(); + } + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } + + protected virtual Task OnUpdatingEntityAsync() + { + return Task.CompletedTask; + } + + protected virtual async Task OnUpdatedEntityAsync() + { + await GetEntitiesAsync(); + + await InvokeAsync(() => + { + EditModalVisible = false; + }); + } + + protected virtual async Task DeleteEntityAsync(TListViewModel entity) + { + try + { + await CheckDeletePolicyAsync(); + await OnDeletingEntityAsync(); + await AppService.DeleteAsync(entity.Id); + await OnDeletedEntityAsync(); + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } + + protected virtual Task OnDeletingEntityAsync() + { + return Task.CompletedTask; + } + + protected virtual async Task OnDeletedEntityAsync() + { + await GetEntitiesAsync(); + await InvokeAsync(StateHasChanged); + await Notify.Success(L["SuccessfullyDeleted"]); + } + + protected virtual string GetDeleteConfirmationMessage(TListViewModel entity) + { + return UiLocalizer["ItemWillBeDeletedMessage"]; + } + + protected virtual async Task CheckCreatePolicyAsync() + { + await CheckPolicyAsync(CreatePolicyName); + } + + protected virtual async Task CheckUpdatePolicyAsync() + { + await CheckPolicyAsync(UpdatePolicyName); + } + + protected virtual async Task CheckDeletePolicyAsync() + { + await CheckPolicyAsync(DeletePolicyName); + } + + /// + /// Calls IAuthorizationService.CheckAsync for the given . + /// Throws if given policy was not granted for the current user. + /// + /// Does nothing if is null or empty. + /// + /// A policy name to check + protected virtual async Task CheckPolicyAsync([CanBeNull] string policyName) + { + if (string.IsNullOrEmpty(policyName)) + { + return; + } + + await AuthorizationService.CheckAsync(policyName); + } + + protected virtual ValueTask SetBreadcrumbItemsAsync() + { + return ValueTask.CompletedTask; + } + + protected virtual ValueTask SetEntityActionsAsync() + { + return ValueTask.CompletedTask; + } + + protected virtual ValueTask SetTableColumnsAsync() + { + return ValueTask.CompletedTask; + } + + protected virtual ValueTask SetToolbarItemsAsync() + { + return ValueTask.CompletedTask; + } +} + + diff --git a/src/Lsw.Abp.AntDesignUI/AntDesignExtensions.cs b/src/Lsw.Abp.AntDesignUI/AntDesignExtensions.cs new file mode 100644 index 0000000..7de810e --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/AntDesignExtensions.cs @@ -0,0 +1,8 @@ +using AntDesign; + +namespace Lsw.Abp.AntDesignUI; + +public static class AntDesignExtensions +{ + +} diff --git a/src/Lsw.Abp.AntDesignUI/AntDesignUiMessageService.cs b/src/Lsw.Abp.AntDesignUI/AntDesignUiMessageService.cs new file mode 100644 index 0000000..00949d9 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/AntDesignUiMessageService.cs @@ -0,0 +1,98 @@ +using System; +using System.Threading.Tasks; +using AntDesign; +using Localization.Resources.AbpUi; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; +using Volo.Abp.AspNetCore.Components.Messages; +using Volo.Abp.DependencyInjection; + +namespace Lsw.Abp.AntDesignUI; + +[Dependency(ReplaceServices = true)] +public class AntDesignUiMessageService : IUiMessageService , IScopedDependency +{ + [Inject] + public ConfirmService ConfirmService { get; set; } + + [Inject] + public ModalService ModalService { get; set; } + + private readonly IStringLocalizer _localizer; + + public AntDesignUiMessageService(IStringLocalizer localizer) + { + _localizer = localizer; + } + + public async Task Info(string message, string title = null, Action options = null) + { + var uiMessageOptions = CreateDefaultOptions(); + options?.Invoke(uiMessageOptions); + + await ModalService.InfoAsync(CreateConfirmOptions(message, title ?? _localizer["Info"], uiMessageOptions, ConfirmButtons.OK)); + } + + public async Task Success(string message, string title = null, Action options = null) + { + var uiMessageOptions = CreateDefaultOptions(); + options?.Invoke(uiMessageOptions); + + await ModalService.SuccessAsync(CreateConfirmOptions(message, title ?? _localizer["Success"], uiMessageOptions, ConfirmButtons.OK)); + } + + public async Task Warn(string message, string title = null, Action options = null) + { + var uiMessageOptions = CreateDefaultOptions(); + options?.Invoke(uiMessageOptions); + + await ModalService.WarningAsync(CreateConfirmOptions(message, title ?? _localizer["Warn"], uiMessageOptions, ConfirmButtons.YesNo)); + } + + public async Task Error(string message, string title = null, Action options = null) + { + var uiMessageOptions = CreateDefaultOptions(); + options?.Invoke(uiMessageOptions); + + await ModalService.ErrorAsync(CreateConfirmOptions(message, title ?? _localizer["Error"], uiMessageOptions, ConfirmButtons.YesNo)); + } + + public async Task Confirm(string message, string title = null, Action options = null) + { + var uiMessageOptions = CreateDefaultOptions(); + options?.Invoke(uiMessageOptions); + + return await ModalService.ConfirmAsync(CreateConfirmOptions(message, title ?? _localizer["Confirm"], uiMessageOptions, ConfirmButtons.YesNo)); + } + + protected virtual ConfirmOptions CreateConfirmOptions(string message, string title, UiMessageOptions uiMessageOptions, ConfirmButtons confirmButtons) + { + var options = new ConfirmOptions + { + OkText = uiMessageOptions.ConfirmButtonText, + CancelText = uiMessageOptions.CancelButtonText, + Content = message, + Title = title + }; + + if (confirmButtons == ConfirmButtons.YesNoCancel) + { + options.Button2Props.ChildContent = uiMessageOptions.OkButtonText; + options.Button3Props.ChildContent = uiMessageOptions.CancelButtonText; + } + + return options; + } + + protected virtual UiMessageOptions CreateDefaultOptions() + { + return new UiMessageOptions + { + CenterMessage = true, + ShowMessageIcon = true, + OkButtonText = _localizer["Ok"], + CancelButtonText = _localizer["Cancel"], + ConfirmButtonText = _localizer["Yes"], + }; + } +} diff --git a/src/Lsw.Abp.AntDesignUI/AntDesignUiNotificationService.cs b/src/Lsw.Abp.AntDesignUI/AntDesignUiNotificationService.cs new file mode 100644 index 0000000..fe6a3d9 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/AntDesignUiNotificationService.cs @@ -0,0 +1,72 @@ +using System; +using System.Threading.Tasks; +using AntDesign; +using Localization.Resources.AbpUi; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; +using Volo.Abp.AspNetCore.Components.Notifications; +using Volo.Abp.DependencyInjection; + +namespace Lsw.Abp.AntDesignUI; + +[Dependency(ReplaceServices = true)] +public class AntDesignUiNotificationService: IUiNotificationService, IScopedDependency +{ + [Inject] + protected NotificationService NoticeService { get; set; } + + private readonly IStringLocalizer _localizer; + + public AntDesignUiNotificationService(IStringLocalizer localizer) + { + _localizer = localizer; + } + + public async Task Info(string message, string title = null, Action options = null) + { + var uiNotificationOptions = CreateDefaultOptions(); + options?.Invoke(uiNotificationOptions); + + await Notify(title ?? _localizer["Info"], message, NotificationType.Info); + } + + public async Task Success(string message, string title = null, Action options = null) + { + var uiNotificationOptions = CreateDefaultOptions(); + options?.Invoke(uiNotificationOptions); + + await Notify(title ?? _localizer["Success"], message, NotificationType.Success); + } + + public async Task Warn(string message, string title = null, Action options = null) + { + var uiNotificationOptions = CreateDefaultOptions(); + options?.Invoke(uiNotificationOptions); + + await Notify(title ?? _localizer["Warn"], message, NotificationType.Warning); + } + + public async Task Error(string message, string title = null, Action options = null) + { + var uiNotificationOptions = CreateDefaultOptions(); + options?.Invoke(uiNotificationOptions); + + await Notify(title ?? _localizer["Error"], message, NotificationType.Error); + } + + protected virtual async Task Notify(string title, string message, NotificationType notificationType) + { + await NoticeService.Open(new NotificationConfig + { + Message = title, + Description = message, + Placement = NotificationPlacement.BottomRight, + NotificationType = notificationType + }); + } + + protected virtual UiNotificationOptions CreateDefaultOptions() + { + return new UiNotificationOptions(); + } +} diff --git a/src/Lsw.Abp.AntDesignUI/AntDesignUiPageProgressService.cs b/src/Lsw.Abp.AntDesignUI/AntDesignUiPageProgressService.cs new file mode 100644 index 0000000..3339796 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/AntDesignUiPageProgressService.cs @@ -0,0 +1,27 @@ +using System; +using System.Threading.Tasks; +using Volo.Abp.AspNetCore.Components.Progression; +using Volo.Abp.DependencyInjection; + +namespace Lsw.Abp.AntDesignUI; + +[Dependency(ReplaceServices = true)] +public class AntDesignUiPageProgressService: IUiPageProgressService, IScopedDependency +{ + public event EventHandler ProgressChanged; + + public Task Go(int? percentage, Action options = null) + { + var uiPageProgressOptions = CreateDefaultOptions(); + options?.Invoke(uiPageProgressOptions); + + ProgressChanged?.Invoke(this, new UiPageProgressEventArgs(percentage, uiPageProgressOptions)); + + return Task.CompletedTask; + } + + protected virtual UiPageProgressOptions CreateDefaultOptions() + { + return new UiPageProgressOptions(); + } +} diff --git a/src/Lsw.Abp.AntDesignUI/BreadcrumbItem.cs b/src/Lsw.Abp.AntDesignUI/BreadcrumbItem.cs new file mode 100644 index 0000000..5cab3aa --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/BreadcrumbItem.cs @@ -0,0 +1,17 @@ +namespace Lsw.Abp.AntDesignUI; + +public class BreadcrumbItem +{ + public string Text { get; set; } + + public object Icon { get; set; } + + public string Url { get; set; } + + public BreadcrumbItem(string text, string url = null, object icon = null) + { + Text = text; + Url = url; + Icon = icon; + } +} diff --git a/src/Lsw.Abp.AntDesignUI/Components/AbpExtensibleDataGrid.razor b/src/Lsw.Abp.AntDesignUI/Components/AbpExtensibleDataGrid.razor new file mode 100644 index 0000000..d6f7a39 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Components/AbpExtensibleDataGrid.razor @@ -0,0 +1,76 @@ +@typeparam TItem + + + + @if (Columns != null) + { + foreach (var column in Columns) + { + if (column.Actions.Any()) + { + + + @foreach (var action in column.Actions) + { + if (action.ConfirmationMessage != null) + { + + + } + else + { + + + } + } + + + } + else + { + if (column.Component != null) + { + + @RenderCustomTableColumnComponent(column.Component, context) + + } + else + { + if (column.ValueConverter == null) + { + + @GetColumnValue(context, column.Data); + + } + else + { + + @(GetConvertedFieldValue(context, column)) + + } + } + } + } + } +
diff --git a/src/Lsw.Abp.AntDesignUI/Components/AbpExtensibleDataGrid.razor.cs b/src/Lsw.Abp.AntDesignUI/Components/AbpExtensibleDataGrid.razor.cs new file mode 100644 index 0000000..d3e50e6 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Components/AbpExtensibleDataGrid.razor.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using AntDesign.TableModels; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; +using Volo.Abp.AspNetCore.Components.Web.Extensibility.TableColumns; + +namespace Lsw.Abp.AntDesignUI.Components; + +public partial class AbpExtensibleDataGrid : ComponentBase +{ + protected const string DataFieldAttributeName = "Data"; + + protected Dictionary> ActionColumns = new(); + + [Parameter] + public IEnumerable Data { get; set; } + + [Parameter] + public int? TotalItems { get; set; } + + [Parameter] + public int PageSize { get; set; } + + [Parameter] + public IEnumerable Columns { get; set; } + + [Parameter] + public EventCallback> OnChange { get; set; } + + [Parameter] + public int CurrentPage { get; set; } = 1; + + [Parameter] + public string Class { get; set; } + + [Parameter] + public bool Responsive { get; set; } + + [Parameter] + public bool Loading { get; set; } + + [Inject] + public IStringLocalizerFactory StringLocalizerFactory { get; set; } + + protected virtual RenderFragment RenderCustomTableColumnComponent(Type type, object data) + { + return (builder) => + { + builder.OpenComponent(0, type); + builder.AddAttribute(0, DataFieldAttributeName, data); + builder.CloseComponent(); + }; + } + + protected virtual object GetColumnValue(object data, string fieldName) + { + return data.GetType().GetProperty(fieldName)?.GetValue(data); + } + + protected virtual string GetConvertedFieldValue(TItem item, TableColumn columnDefinition) + { + var convertedValue = columnDefinition.ValueConverter.Invoke(item); + if (!columnDefinition.DisplayFormat.IsNullOrEmpty()) + { + return string.Format(columnDefinition.DisplayFormatProvider, columnDefinition.DisplayFormat, + convertedValue); + } + + return convertedValue; + } +} diff --git a/src/Lsw.Abp.AntDesignUI/Components/ActionType.cs b/src/Lsw.Abp.AntDesignUI/Components/ActionType.cs new file mode 100644 index 0000000..626dc2a --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Components/ActionType.cs @@ -0,0 +1,7 @@ +namespace Lsw.Abp.AntDesignUI.Components; + +public enum ActionType +{ + Dropdown, + Button +} diff --git a/src/Lsw.Abp.AntDesignUI/Components/EntityAction.razor b/src/Lsw.Abp.AntDesignUI/Components/EntityAction.razor new file mode 100644 index 0000000..57ec7b5 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Components/EntityAction.razor @@ -0,0 +1,28 @@ +@typeparam TItem + +@if (Visible && HasPermission) +{ + if (ParentActions.Type == ActionType.Dropdown) + { + if (!Primary) + { + + @Text + + } + } + else + { + + } +} diff --git a/src/Lsw.Abp.AntDesignUI/Components/EntityAction.razor.cs b/src/Lsw.Abp.AntDesignUI/Components/EntityAction.razor.cs new file mode 100644 index 0000000..3e2de69 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Components/EntityAction.razor.cs @@ -0,0 +1,76 @@ +using System; +using System.Threading.Tasks; +using AntDesign; +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Components; +using Volo.Abp.AspNetCore.Components.Messages; + +namespace Lsw.Abp.AntDesignUI.Components; + +public partial class EntityAction : ComponentBase +{ + internal bool HasPermission { get; set; } = true; + + [Parameter] + public bool Visible { get; set; } = true; + + [Parameter] + public bool Disabled { get; set; } = false; + + [Parameter] + public string Text { get; set; } + + [Parameter] + public string Icon { get; set; } + + [Parameter] + public string Color { get; set; } = ButtonType.Default; + + [Parameter] + public bool Primary { get; set; } + + [Parameter] + public EventCallback Clicked { get; set; } + + [Parameter] + public Func ConfirmationMessage { get; set; } + + [Parameter] + public string RequiredPolicy { get; set; } + + [CascadingParameter] + public EntityActions ParentActions { get; set; } + + [Inject] + protected IAuthorizationService AuthorizationService { get; set; } + + [Inject] + protected IUiMessageService UiMessageService { get; set; } + + protected override async Task OnInitializedAsync() + { + await base.OnInitializedAsync(); + + if (!RequiredPolicy.IsNullOrEmpty()) + { + HasPermission = await AuthorizationService.IsGrantedAsync(RequiredPolicy); + } + + ParentActions.AddAction(this); + } + + public virtual async Task ActionClickedAsync() + { + if (ConfirmationMessage != null) + { + if (await UiMessageService.Confirm(ConfirmationMessage())) + { + await InvokeAsync(async () => await Clicked.InvokeAsync()); + } + } + else + { + await Clicked.InvokeAsync(); + } + } +} diff --git a/src/Lsw.Abp.AntDesignUI/Components/EntityActions.razor b/src/Lsw.Abp.AntDesignUI/Components/EntityActions.razor new file mode 100644 index 0000000..861c85f --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Components/EntityActions.razor @@ -0,0 +1,39 @@ +@typeparam TItem + + + + @if (Type == ActionType.Dropdown) + { + if (HasPrimaryAction) + { + + + + @ChildContent + + + + @PrimaryAction.Text + + + } + else + { + + + + @ChildContent + + + + + + + } + } + else + { + @ChildContent + } + + diff --git a/src/Lsw.Abp.AntDesignUI/Components/EntityActions.razor.cs b/src/Lsw.Abp.AntDesignUI/Components/EntityActions.razor.cs new file mode 100644 index 0000000..6c8e9d9 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Components/EntityActions.razor.cs @@ -0,0 +1,69 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using AntDesign; +using Localization.Resources.AbpUi; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; + +namespace Lsw.Abp.AntDesignUI.Components; + +public partial class EntityActions : ComponentBase +{ + protected readonly List> Actions = new(); + + protected bool HasPrimaryAction => Actions.Any(t => t.Primary); + + protected EntityAction PrimaryAction => Actions.FirstOrDefault(t => t.Primary); + + [Parameter] + public ActionType Type { get; set; } = ActionType.Dropdown; + + [Parameter] + public bool Disabled { get; set; } = false; + + [Parameter] + public string ToggleColor { get; set; } = ButtonType.Primary; + + [Parameter] + public string ToggleText { get; set; } + + [Parameter] + public RenderFragment ChildContent { get; set; } + + [Parameter] + public TableEntityActionsColumn EntityActionsColumn { get; set; } + + [CascadingParameter] + public TableEntityActionsColumn ParentEntityActionsColumn { get; set; } + + [Inject] + public IStringLocalizer UiLocalizer { get; set; } + + protected override void OnInitialized() + { + base.OnInitialized(); + ToggleText = UiLocalizer["Actions"]; + } + + protected override async Task OnAfterRenderAsync(bool firstRender) + { + if (firstRender) + { + if (ParentEntityActionsColumn != null) + { + ParentEntityActionsColumn.Hidden = !Actions.Any(t => t.Visible && t.HasPermission); + } + + await InvokeAsync(StateHasChanged); + } + + await base.OnAfterRenderAsync(firstRender); + } + + internal void AddAction(EntityAction action) + { + Actions.Add(action); + } + +} diff --git a/src/Lsw.Abp.AntDesignUI/Components/PageAlert.razor b/src/Lsw.Abp.AntDesignUI/Components/PageAlert.razor new file mode 100644 index 0000000..1b63288 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Components/PageAlert.razor @@ -0,0 +1,51 @@ +@using Volo.Abp.AspNetCore.Components.Alerts +@using System.Collections.Specialized +@using Microsoft.AspNetCore.Components.Routing + +@foreach (var message in _messages) +{ + +} + +@code { + + private readonly List _messages = new(); + + [Inject] + protected IAlertManager AlertManager { get; set; } + + [Inject] + protected NavigationManager NavigationManager { get; set; } + + protected override void OnInitialized() + { + base.OnInitialized(); + AlertManager.Alerts.CollectionChanged += Alerts_CollectionChanged; + NavigationManager.LocationChanged += NavigationManager_LocationChanged; + + _messages.AddRange(AlertManager.Alerts); + } + + private void NavigationManager_LocationChanged(object sender, LocationChangedEventArgs e) + { + AlertManager.Alerts.Clear(); + _messages.Clear(); + } + + protected virtual void Alerts_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (e.Action == NotifyCollectionChangedAction.Add) + { + foreach (var item in e.NewItems) + { + _messages.Add((AlertMessage)item); + } + } + InvokeAsync(StateHasChanged); + } + +} diff --git a/src/Lsw.Abp.AntDesignUI/Components/TableEntityActionsColumn.razor b/src/Lsw.Abp.AntDesignUI/Components/TableEntityActionsColumn.razor new file mode 100644 index 0000000..04a050d --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Components/TableEntityActionsColumn.razor @@ -0,0 +1,20 @@ +@typeparam TItem +@using Localization.Resources.AbpUi +@using Microsoft.Extensions.Localization +@inherits Column + + @ChildContent + + +@code { + [Inject] + public IStringLocalizer UiLocalizer { get; set; } + + protected override void OnInitialized() + { + Title = UiLocalizer["Actions"]; + Sortable = false; + base.OnInitialized(); + } + +} diff --git a/src/Lsw.Abp.AntDesignUI/Components/ToolbarButton.razor b/src/Lsw.Abp.AntDesignUI/Components/ToolbarButton.razor new file mode 100644 index 0000000..e940cb9 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Components/ToolbarButton.razor @@ -0,0 +1,25 @@ + + +@code { + + [Parameter] + public string Color { get; set; } = ButtonType.Default; + + [Parameter] + public object Icon { get; set; } + + [Parameter] + public string Text { get; set; } + + [Parameter] + public Func Clicked { get; set; } + + [Parameter] + public bool Disabled { get; set; } +} diff --git a/src/Lsw.Abp.AntDesignUI/Components/UiPageProgress.razor b/src/Lsw.Abp.AntDesignUI/Components/UiPageProgress.razor new file mode 100644 index 0000000..3a76b5d --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Components/UiPageProgress.razor @@ -0,0 +1,12 @@ +@if (_percent is >= 0 and <= 100) +{ + if (_progressStatus == ProgressStatus.Active) + { + + } + else + { + + } + +} diff --git a/src/Lsw.Abp.AntDesignUI/Components/UiPageProgress.razor.cs b/src/Lsw.Abp.AntDesignUI/Components/UiPageProgress.razor.cs new file mode 100644 index 0000000..b7e39c1 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Components/UiPageProgress.razor.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using AntDesign; +using Microsoft.AspNetCore.Components; +using Volo.Abp.AspNetCore.Components.Progression; + +namespace Lsw.Abp.AntDesignUI.Components; + +public partial class UiPageProgress : ComponentBase +{ + private int? _percent; + + private ProgressStatus _progressStatus; + + private Dictionary _gradients = new() + { + { "0%", "#108ee9" }, + { "100%", "#87d068" } + }; + + [Inject] + protected IUiPageProgressService UiPageProgressService { get; set; } + + protected override void OnInitialized() + { + base.OnInitialized(); + UiPageProgressService.ProgressChanged += OnProgressChanged; + } + + protected virtual void OnProgressChanged(object sender, UiPageProgressEventArgs e) + { + _percent = e.Percentage; + SetProgressStatus(e.Options.Type); + } + + protected virtual void SetProgressStatus(UiPageProgressType pageProgressType) + { + _progressStatus = pageProgressType switch + { + UiPageProgressType.Info => ProgressStatus.Active, + UiPageProgressType.Default => ProgressStatus.Active, + UiPageProgressType.Success => ProgressStatus.Success, + UiPageProgressType.Warning => ProgressStatus.Normal, + UiPageProgressType.Error => ProgressStatus.Exception, + _ => _progressStatus + }; + } +} diff --git a/src/Lsw.Abp.AntDesignUI/FodyWeavers.xml b/src/Lsw.Abp.AntDesignUI/FodyWeavers.xml new file mode 100644 index 0000000..bc5a74a --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/FodyWeavers.xml @@ -0,0 +1,3 @@ + + + diff --git a/src/Lsw.Abp.AntDesignUI/Lsw.Abp.AntDesignUI.csproj b/src/Lsw.Abp.AntDesignUI/Lsw.Abp.AntDesignUI.csproj new file mode 100644 index 0000000..b024585 --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/Lsw.Abp.AntDesignUI.csproj @@ -0,0 +1,16 @@ + + + + + + net6.0 + + + + + + + + + + diff --git a/src/Lsw.Abp.AntDesignUI/_Imports.razor b/src/Lsw.Abp.AntDesignUI/_Imports.razor new file mode 100644 index 0000000..c2316af --- /dev/null +++ b/src/Lsw.Abp.AntDesignUI/_Imports.razor @@ -0,0 +1,2 @@ +@using Microsoft.AspNetCore.Components.Web +@using AntDesign