diff --git a/README.md b/README.md index d54a812..795b14e 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ GridView component for Blazor **Version 0.11.0 contains new Triggers feature more info in [wiki](https://github.com/Mewriick/Blazor.FlexGrid/wiki/Triggers)** # Installation -[![NuGet Pre Release](https://img.shields.io/badge/nuget-0.11.0-orange.svg)](https://www.nuget.org/packages/Blazor.FlexGrid) +[![NuGet Pre Release](https://img.shields.io/badge/nuget-0.11.1-orange.svg)](https://www.nuget.org/packages/Blazor.FlexGrid) After nuget instalation you must create in Blazor.Client app Linker.xml file because nuget use some features which are not supported in default mono managed interpreter from WebAssembly (https://github.com/mono/mono/issues/8872) @@ -409,6 +409,8 @@ public void Configure(EntityTypeBuilder builder) conf.AllowDeleting = true; conf.DeletePermissionRestriction = perm => perm.IsInRole("TestRole"); }); + + builder.DoNotUseDeleteConfirmDialog(); // Disable confirmation dialog before delete operation } ``` You can also configure which columns will be editable for current logger user, see **Permission restriction** section. If you are using diff --git a/demo/Blazor.Components.Demo.FlexGrid/GridConfigurations/WeatherForecastGridConfiguration.cs b/demo/Blazor.Components.Demo.FlexGrid/GridConfigurations/WeatherForecastGridConfiguration.cs index c667cac..12a9a49 100644 --- a/demo/Blazor.Components.Demo.FlexGrid/GridConfigurations/WeatherForecastGridConfiguration.cs +++ b/demo/Blazor.Components.Demo.FlexGrid/GridConfigurations/WeatherForecastGridConfiguration.cs @@ -14,7 +14,7 @@ public void Configure(EntityTypeBuilder builder) conf.CreateUri = "/api/SampleData/WeatherForecast"; }); - builder.AllowInlineEdit(); + builder.AllowInlineEdit(cfg => cfg.AllowDeleting = true); builder.Property(e => e.Date) .HasCaption("Date") @@ -67,6 +67,8 @@ public void Configure(EntityTypeBuilder builder) //.HasValueFormatter(s => $"{s}!"); .HasCompositeValueFormatter(f => $"{f.Summary} {f.TemperatureF}"); //.HasBlazorEditComponent(weatherSummaryEdit); + + // builder.DoNotUseDeleteConfirmDialog(); } } } diff --git a/src/Blazor.FlexGrid/Blazor.FlexGrid.csproj b/src/Blazor.FlexGrid/Blazor.FlexGrid.csproj index c019c09..8cec12b 100644 --- a/src/Blazor.FlexGrid/Blazor.FlexGrid.csproj +++ b/src/Blazor.FlexGrid/Blazor.FlexGrid.csproj @@ -9,14 +9,14 @@ false 7.3 Blazor.FlexGrid - 0.11.0 + 0.11.1 Blazor.FlexGrid GridView component for Blazor Jaroslav Surala https://github.com/Mewriick/Blazor.FlexGrid Blazor;GridView;Component - 0.11.0 - Add triggers feature + 0.11.1 + Add delete confirm dialog https://msdnshared.blob.core.windows.net/media/2018/04/Blazor-300x280.jpg https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json; diff --git a/src/Blazor.FlexGrid/Components/Configuration/Builders/EntityTypeBuilder.cs b/src/Blazor.FlexGrid/Components/Configuration/Builders/EntityTypeBuilder.cs index ce87cf4..6f485b1 100644 --- a/src/Blazor.FlexGrid/Components/Configuration/Builders/EntityTypeBuilder.cs +++ b/src/Blazor.FlexGrid/Components/Configuration/Builders/EntityTypeBuilder.cs @@ -117,6 +117,21 @@ public virtual EntityTypeBuilder AllowCreateItem ConfigureDeleteItem(Action configureDeleteItem) + { + if (configureDeleteItem is null) + { + throw new ArgumentNullException(nameof(configureDeleteItem)); + } + + var deleteItemOptions = new DeleteItemOptions(); + configureDeleteItem.Invoke(deleteItemOptions); + + Builder.DeleteItemConfiguration(deleteItemOptions); + + return this; + } + public virtual EntityTypeBuilder EnableSortingForAllProperties() { foreach (var property in typeof(TEntity).GetProperties()) @@ -149,5 +164,12 @@ public virtual EntityTypeBuilder HasEmptyItemsMessage(string message) return this; } + + public virtual EntityTypeBuilder DoNotUseDeleteConfirmDialog() + { + ConfigureDeleteItem(cfg => cfg.UseConfirmationDialog = false); + + return this; + } } } diff --git a/src/Blazor.FlexGrid/Components/Configuration/Builders/InternalEntityTypeBuilder.cs b/src/Blazor.FlexGrid/Components/Configuration/Builders/InternalEntityTypeBuilder.cs index a2b3ea8..dc9b8c6 100644 --- a/src/Blazor.FlexGrid/Components/Configuration/Builders/InternalEntityTypeBuilder.cs +++ b/src/Blazor.FlexGrid/Components/Configuration/Builders/InternalEntityTypeBuilder.cs @@ -50,6 +50,7 @@ public bool AppendCssClasses(Action gridCssClassesConfig) gridCssClasses.AppendDefaultCssClasses(new DefaultGridCssClasses()); gridCssClasses.AppendDefaultFooterCssClasses(new DefaultFooterCssClasses()); gridCssClasses.AppendDefaultCreateFormCssClasses(new DefaultCreateFormCssClasses()); + gridCssClasses.AppendDefaultDeleteDialogCssClasses(new DefaultDeleteDialogCssClasses()); return HasAnnotation(GridViewAnnotationNames.CssClasses, gridCssClasses); } @@ -77,6 +78,9 @@ public bool AllowInlineEdit(InlineEditOptions inlineEditOptions) public bool AllowCreateItem(CreateItemOptions createItemOptions) => HasAnnotation(GridViewAnnotationNames.CreateItemOptions, createItemOptions); + public bool DeleteItemConfiguration(DeleteItemOptions deleteItemOptions) + => HasAnnotation(GridViewAnnotationNames.DeleteItemOptions, deleteItemOptions); + public bool HasEmptyItemsMessage(string message) => HasAnnotation(GridViewAnnotationNames.EmptyItemsMessage, message); } diff --git a/src/Blazor.FlexGrid/Components/Configuration/DeleteItemOptions.cs b/src/Blazor.FlexGrid/Components/Configuration/DeleteItemOptions.cs new file mode 100644 index 0000000..64f3342 --- /dev/null +++ b/src/Blazor.FlexGrid/Components/Configuration/DeleteItemOptions.cs @@ -0,0 +1,18 @@ +namespace Blazor.FlexGrid.Components.Configuration +{ + public class DeleteItemOptions + { + public const string DialogName = "deleteDialog"; + + public bool UseConfirmationDialog { get; set; } + } + + public class DefaulDeleteItemOptions : DeleteItemOptions + { + public DefaulDeleteItemOptions() + : base() + { + UseConfirmationDialog = true; + } + } +} diff --git a/src/Blazor.FlexGrid/Components/Configuration/GridCssClasses.cs b/src/Blazor.FlexGrid/Components/Configuration/GridCssClasses.cs index f09e903..8fb2a65 100644 --- a/src/Blazor.FlexGrid/Components/Configuration/GridCssClasses.cs +++ b/src/Blazor.FlexGrid/Components/Configuration/GridCssClasses.cs @@ -24,6 +24,8 @@ public class GridCssClasses public CreateFormCssClasses CreateFormCssClasses { get; set; } = NullCreateFormCssClasses.Instance; + public DeleteDialogCssClasses DeleteDialogCssClasses { get; set; } = new DeleteDialogCssClasses(); + internal void AppendDefaultCssClasses(DefaultGridCssClasses defaultCssClasses) { Table = $"{defaultCssClasses.Table} {Table}".TrimEnd(); @@ -60,6 +62,15 @@ internal void AppendDefaultCreateFormCssClasses(DefaultCreateFormCssClasses defa ModalSize = $"{defaultCreateFormCssClasses.ModalSize} {CreateFormCssClasses.ModalSize}".TrimEnd() }; } + + internal void AppendDefaultDeleteDialogCssClasses(DefaultDeleteDialogCssClasses defaultDeleteDialogCssClasses) + { + DeleteDialogCssClasses = new DeleteDialogCssClasses + { + DeleteButton = $"{defaultDeleteDialogCssClasses.DeleteButton} {DeleteDialogCssClasses.DeleteButton}".TrimEnd(), + CancelButton = $"{defaultDeleteDialogCssClasses.CancelButton} {DeleteDialogCssClasses.CancelButton}".TrimEnd() + }; + } } public class GridFooterCssClasses @@ -88,6 +99,12 @@ public class CreateFormCssClasses public string ModalFooter { get; set; } = string.Empty; } + public class DeleteDialogCssClasses + { + public string DeleteButton { get; set; } = string.Empty; + + public string CancelButton { get; set; } = string.Empty; + } public class DefaultGridCssClasses : GridCssClasses { @@ -104,6 +121,7 @@ public DefaultGridCssClasses() TableGroupRowCell = "table-group-row-cell"; FooterCssClasses = new DefaultFooterCssClasses(); CreateFormCssClasses = new DefaultCreateFormCssClasses(); + DeleteDialogCssClasses = new DefaultDeleteDialogCssClasses(); } } @@ -136,6 +154,15 @@ public DefaultCreateFormCssClasses() } } + public class DefaultDeleteDialogCssClasses : DeleteDialogCssClasses + { + public DefaultDeleteDialogCssClasses() + { + CancelButton = "btn btn-light"; + DeleteButton = "btn btn-danger"; + } + } + public class NullCreateFormCssClasses : CreateFormCssClasses { public static NullCreateFormCssClasses Instance = new NullCreateFormCssClasses(); diff --git a/src/Blazor.FlexGrid/Components/Configuration/GridViewAnnotationNames.cs b/src/Blazor.FlexGrid/Components/Configuration/GridViewAnnotationNames.cs index 564a715..6ab1124 100644 --- a/src/Blazor.FlexGrid/Components/Configuration/GridViewAnnotationNames.cs +++ b/src/Blazor.FlexGrid/Components/Configuration/GridViewAnnotationNames.cs @@ -12,6 +12,7 @@ public static class GridViewAnnotationNames public const string DetailDeleteUrl = "DetailDeleteUrl"; public const string InlineEditOptions = "InlineEditOptions"; public const string CreateItemOptions = "CreateItemOptions"; + public const string DeleteItemOptions = "DeleteItemOptions"; public const string MasterDetailOptions = "MasterDetailOptions"; public const string OnlyShowExplicitProperties = "OnlyShowExplicitProperties"; public const string GroupingOptions = "GroupingOptions"; diff --git a/src/Blazor.FlexGrid/Components/Configuration/MetaData/GridAnotations.cs b/src/Blazor.FlexGrid/Components/Configuration/MetaData/GridAnotations.cs index bf025ec..e54e8f6 100644 --- a/src/Blazor.FlexGrid/Components/Configuration/MetaData/GridAnotations.cs +++ b/src/Blazor.FlexGrid/Components/Configuration/MetaData/GridAnotations.cs @@ -80,7 +80,19 @@ public CreateItemOptions CreateItemOptions } } + public DeleteItemOptions DeleteItemOptions + { + get + { + var deleteItemOptions = annotations[GridViewAnnotationNames.DeleteItemOptions]; + if (deleteItemOptions is NullAnotationValue) + { + return new DefaulDeleteItemOptions(); + } + return (DeleteItemOptions)deleteItemOptions; + } + } public bool OnlyShowExplicitProperties { diff --git a/src/Blazor.FlexGrid/Components/Configuration/MetaData/IGridViewAnotations.cs b/src/Blazor.FlexGrid/Components/Configuration/MetaData/IGridViewAnotations.cs index 3db4fbc..3cc4e43 100644 --- a/src/Blazor.FlexGrid/Components/Configuration/MetaData/IGridViewAnotations.cs +++ b/src/Blazor.FlexGrid/Components/Configuration/MetaData/IGridViewAnotations.cs @@ -16,6 +16,8 @@ public interface IGridViewAnotations CreateItemOptions CreateItemOptions { get; } + DeleteItemOptions DeleteItemOptions { get; } + GridCssClasses CssClasses { get; } GlobalGroupingOptions GroupingOptions { get; } diff --git a/src/Blazor.FlexGrid/Components/FlexGridContext.cs b/src/Blazor.FlexGrid/Components/FlexGridContext.cs index ac56502..5e4bca4 100644 --- a/src/Blazor.FlexGrid/Components/FlexGridContext.cs +++ b/src/Blazor.FlexGrid/Components/FlexGridContext.cs @@ -16,6 +16,8 @@ public class FlexGridContext public bool FirstPageLoaded { get; set; } + public object SelectedItem { get; private set; } + public FlexGridContext(FilterContext filterContext, IFeatureCollection features) { FilterContext = filterContext ?? throw new ArgumentNullException(nameof(filterContext)); @@ -34,5 +36,9 @@ public void SetRequestRendererNotification(Action requestRendererNotification) public bool IsFeatureActive() where TFeature : IFeature => Features.Contains(); + + public void SelectItem(object item) => SelectedItem = item; + + public void RemoveSelection() => SelectedItem = null; } } diff --git a/src/Blazor.FlexGrid/Components/Renderers/DeleteModalRenderer.cs b/src/Blazor.FlexGrid/Components/Renderers/DeleteModalRenderer.cs new file mode 100644 index 0000000..045b6db --- /dev/null +++ b/src/Blazor.FlexGrid/Components/Renderers/DeleteModalRenderer.cs @@ -0,0 +1,67 @@ +using Blazor.FlexGrid.Components.Configuration; +using Blazor.FlexGrid.Permission; +using Microsoft.AspNetCore.Components; +using Microsoft.AspNetCore.Components.Web; +using System; + +namespace Blazor.FlexGrid.Components.Renderers +{ + public class DeleteModalRenderer : GridPartRenderer + { + private readonly FlexGridInterop flexGridInterop; + + public DeleteModalRenderer(FlexGridInterop flexGridInterop) + { + this.flexGridInterop = flexGridInterop ?? throw new ArgumentNullException(nameof(flexGridInterop)); + } + + public override bool CanRender(GridRendererContext rendererContext) + { + return true; + } + + protected override void BuildRendererTreeInternal(GridRendererContext rendererContext, PermissionContext permissionContext) + { + rendererContext + .RendererTreeBuilder + .OpenElement(HtmlTagNames.Div, "modal") + .AddAttribute(HtmlAttributes.Id, DeleteItemOptions.DialogName) + .AddAttribute("role", "dialog") + .OpenElement(HtmlTagNames.Div, $"modal-dialog modal-dialog-centered") + .AddAttribute(HtmlAttributes.Id, CreateItemOptions.CreateItemModalSizeDiv) + .OpenElement(HtmlTagNames.Div, "modal-content") + .OpenElement(HtmlTagNames.Div, "modal-header") + .OpenElement(HtmlTagNames.H4, "modal-title") + .AddContent("Confirm delete") + .CloseElement() + .CloseElement() + .OpenElement(HtmlTagNames.Div, "modal-body") + .AddContent("Are you sure you want to delete item?") + .CloseElement() + .OpenElement(HtmlTagNames.Div, "modal-footer") + .OpenElement(HtmlTagNames.Button, rendererContext.CssClasses.DeleteDialogCssClasses.CancelButton) + .AddAttribute(HtmlAttributes.Type, "button") + .AddAttribute("data-dismiss", "modal") + .AddAttribute(HtmlJSEvents.OnClick, EventCallback.Factory.Create(this, (MouseEventArgs e) => flexGridInterop.HideModal(DeleteItemOptions.DialogName))) + .AddContent("Cancel") + .CloseElement() + .OpenElement(HtmlTagNames.Button, rendererContext.CssClasses.DeleteDialogCssClasses.DeleteButton) + .AddAttribute(HtmlAttributes.Type, "button") + .AddAttribute("data-dismiss", "modal") + .AddAttribute(HtmlJSEvents.OnClick, + EventCallback.Factory.Create(this, (MouseEventArgs e) => + { + rendererContext.TableDataSet.DeleteItem(rendererContext.FlexGridContext.SelectedItem); + rendererContext.FlexGridContext.RemoveSelection(); + flexGridInterop.HideModal(DeleteItemOptions.DialogName); + rendererContext.RequestRerenderNotification?.Invoke(); + })) + .AddContent("Delete") + .CloseElement() + .CloseElement() + .CloseElement() + .CloseElement() + .CloseElement(); + } + } +} diff --git a/src/Blazor.FlexGrid/Components/Renderers/GridActionButtonsRenderer.cs b/src/Blazor.FlexGrid/Components/Renderers/GridActionButtonsRenderer.cs index 777ea1e..3ba62e7 100644 --- a/src/Blazor.FlexGrid/Components/Renderers/GridActionButtonsRenderer.cs +++ b/src/Blazor.FlexGrid/Components/Renderers/GridActionButtonsRenderer.cs @@ -1,11 +1,20 @@ -using Blazor.FlexGrid.Permission; +using Blazor.FlexGrid.Components.Configuration; +using Blazor.FlexGrid.Permission; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Components.Web; +using System; namespace Blazor.FlexGrid.Components.Renderers { public class GridActionButtonsRenderer : GridPartRenderer { + private readonly FlexGridInterop flexGridInterop; + + public GridActionButtonsRenderer(FlexGridInterop flexGridInterop) + { + this.flexGridInterop = flexGridInterop ?? throw new ArgumentNullException(nameof(flexGridInterop)); + } + public override bool CanRender(GridRendererContext rendererContext) => rendererContext.IsLastColumn && rendererContext.GridConfiguration.InlineEditOptions.InlineEditIsAllowed; @@ -83,8 +92,16 @@ private void RenderDeleteButton(GridRendererContext rendererContext, PermissionC rendererContext.AddOnClickEvent( EventCallback.Factory.Create(this, (MouseEventArgs e) => { - rendererContext.TableDataSet.DeleteItem(localActualItem); - rendererContext.RequestRerenderNotification?.Invoke(); + if (rendererContext.GridConfiguration.DeleteItemOptions.UseConfirmationDialog) + { + rendererContext.FlexGridContext.SelectItem(localActualItem); + flexGridInterop.ShowModal(DeleteItemOptions.DialogName); + } + else + { + rendererContext.TableDataSet.DeleteItem(localActualItem); + rendererContext.RequestRerenderNotification?.Invoke(); + } }) ); diff --git a/src/Blazor.FlexGrid/FlexGridServiceCollectionExtensions.cs b/src/Blazor.FlexGrid/FlexGridServiceCollectionExtensions.cs index 7b3c0e3..139be40 100644 --- a/src/Blazor.FlexGrid/FlexGridServiceCollectionExtensions.cs +++ b/src/Blazor.FlexGrid/FlexGridServiceCollectionExtensions.cs @@ -132,7 +132,7 @@ private static object CreateGridRenderer(IServiceProvider provider) .AddRenderer(new GridCellMasterActionRenderer()) .AddRenderer(new GridCellRenderer(provider.GetRequiredService())) .AddRenderer(new GridTabControlRenderer(provider.GetRequiredService()), RendererType.AfterTag) - .AddRenderer(new GridActionButtonsRenderer()); + .AddRenderer(new GridActionButtonsRenderer(provider.GetRequiredService())); var gridBodySimpleRenderer = new GridBodySimpleRenderer(provider.GetRequiredService>()) .AddRenderer(gridRowRenderer); @@ -147,7 +147,8 @@ private static object CreateGridRenderer(IServiceProvider provider) .AddRenderer(new GridHeaderRenderer(provider.GetRequiredService())) .AddRenderer(new GridEmptyItemsRenderer()) .AddRenderer(gridBodyRenderer) - .AddRenderer(new GridFooterRenderer(), RendererType.AfterTag); + .AddRenderer(new GridFooterRenderer(), RendererType.AfterTag) + .AddRenderer(new DeleteModalRenderer(provider.GetRequiredService()), RendererType.AfterTag); return gridRenderer; }