Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make features of entity picker configurable #211

Merged
merged 2 commits into from
Jan 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,9 @@ public static void AddPersonCollection(this ICmsConfig config)
// so this field will allow the user to select an entity that is one level deeper in the person-tree
section.AddField(x => x.FavouriteChildId)
.SetName("Favorite child")
.SetType(EditorType.Select)
.SetType(EditorType.EntityPicker)
// use the Picker configuration class to configure EntityPicker and EntitiesPicker editors
.SetConfiguration(new Picker(PageSize: 3))
.VisibleWhen((person, state) => state == EntityState.IsExisting)
.SetCollectionRelation<Person>("person", config =>
{
Expand Down
7 changes: 7 additions & 0 deletions src/RapidCMS.Core/Models/Configuration/Picker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace RapidCMS.Core.Models.Configuration;

public record Picker(
bool EnableSelectAll = false,
bool EnableUnselectAll = false,
bool EnableReset = false,
int PageSize = 25);
11 changes: 8 additions & 3 deletions src/RapidCMS.Core/Providers/CollectionDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
using RapidCMS.Core.Forms;
using RapidCMS.Core.Models.Data;
using RapidCMS.Core.Models.EventArgs.Mediators;
using RapidCMS.Core.Models.Setup;

namespace RapidCMS.Core.Providers;

Expand Down Expand Up @@ -156,13 +155,19 @@ public async Task<IReadOnlyList<IElement>> GetRelatedElementsAsync()
return elements.Where(x => _relatedIds.Contains(x.Id)).ToList();
}

public void AddElement(object id) => _relatedIds.Add(id);
public void AddElement(object id)
{
if (!_relatedIds.Contains(id))
{
_relatedIds.Add(id);
}
}

public void RemoveElement(object id) => _relatedIds.Remove(id);

public bool IsRelated(object id) => _relatedIds.Any(x => x.Equals(id));

public IReadOnlyList<object> GetCurrentRelatedElementIds() => _relatedIds;
public IReadOnlyList<object> GetCurrentRelatedElementIds() => _relatedIds.ToList();

public Type GetRelatedEntityType() => _relatedEntityType ?? typeof(object);

Expand Down
61 changes: 58 additions & 3 deletions src/RapidCMS.UI/Components/Editors/BasePicker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using RapidCMS.Core.Abstractions.Data;
using RapidCMS.Core.Abstractions.UI;
using RapidCMS.Core.Models.Configuration;
using RapidCMS.Core.Models.Data;
using RapidCMS.UI.Extensions;

namespace RapidCMS.UI.Components.Editors;

public abstract class BasePicker : BaseDataEditor
public abstract class BasePicker : BaseDataEditor, IWantConfiguration<Picker>
{
protected string? _searchTerm;
protected int _currentPage = 1;
Expand All @@ -25,15 +28,19 @@

protected virtual bool IsMultiple { get; set; }

protected Picker Config { get; set; }

Check warning on line 31 in src/RapidCMS.UI/Components/Editors/BasePicker.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Config' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 31 in src/RapidCMS.UI/Components/Editors/BasePicker.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Config' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 31 in src/RapidCMS.UI/Components/Editors/BasePicker.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Config' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

Check warning on line 31 in src/RapidCMS.UI/Components/Editors/BasePicker.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'Config' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.

[Inject]
private IJSRuntime JsRuntime { get; set; } = null!;

private IRelationDataCollection RelationDataCollection
=> DataCollection as IRelationDataCollection
=> DataCollection as IRelationDataCollection
?? throw new InvalidOperationException("Incorrect DataCollection assigned to Entity/iesPicker");

protected override async Task OnInitializedAsync()
{
Config = await this.GetConfigAsync() ?? new();

if (DataCollection != null)
{
DataCollection.OnDataChange += UpdateOptionsAsync;
Expand Down Expand Up @@ -83,14 +90,62 @@
await UpdateOptionsAsync();
}

protected async Task SelectAllAsync()
{
if (RelationDataCollection == null)
{
return;
}

var page = 1;
do
{
var view = View.Create(Config.PageSize, page, null, null);
var data = await RelationDataCollection.GetAvailableElementsAsync(view);

foreach (var item in data)
{
RelationDataCollection.AddElement(item.Id);
}

if (data.Count < Config.PageSize)
{
break;
}
else
{
page++;
}
}
while (true);

StateHasChanged();
}

protected async Task UnselectAllAsync()

Check warning on line 125 in src/RapidCMS.UI/Components/Editors/BasePicker.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 125 in src/RapidCMS.UI/Components/Editors/BasePicker.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 125 in src/RapidCMS.UI/Components/Editors/BasePicker.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

Check warning on line 125 in src/RapidCMS.UI/Components/Editors/BasePicker.cs

View workflow job for this annotation

GitHub Actions / build

This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.
{
if (RelationDataCollection == null)
{
return;
}

var items = RelationDataCollection.GetCurrentRelatedElementIds();
foreach (var item in items)
{
RelationDataCollection.RemoveElement(item);
}

StateHasChanged();
}

private async Task UpdateOptionsAsync()
{
if (DataCollection == null)
{
return;
}

var view = View.Create(25, _currentPage, _searchTerm, default);
var view = View.Create(Config.PageSize, _currentPage, _searchTerm, default);
_options = await DataCollection.GetAvailableElementsAsync(view);

if (view.MoreDataAvailable)
Expand Down
4 changes: 2 additions & 2 deletions src/RapidCMS.UI/Components/Editors/EntitiesPicker.razor
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
@inherits BaseMultiplePickerEditor
@attribute [Relation(RelationType.Many)]

@if (_options != null)
@if (_options != null && Config != null)
{
var index = 0;

<div class="form-control form-control-select-list @(CssHelper.GetDisplayModifier(DisplayType)) @(CssHelper.GetValidationClass(State))" id=@ElementId>
<SearchBar OnResetView="ResetViewAsync" OnSearch="SearchAsync" />
<SearchBar OnResetView="ResetViewAsync" OnSelectAll="SelectAllAsync" OnUnselectAll="UnselectAllAsync" OnSearch="SearchAsync" Config="Config" />

@foreach (var option in _options)
{
Expand Down
4 changes: 2 additions & 2 deletions src/RapidCMS.UI/Components/Editors/EntityPicker.razor
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
@inherits BasePicker
@attribute [Relation(RelationType.One)]

@if (_options != null)
@if (_options != null && Config != null)
{
var index = 0;

<div class="form-control form-control-select-list @(CssHelper.GetDisplayModifier(DisplayType)) @(CssHelper.GetValidationClass(State))" id=@ElementId>
<SearchBar OnResetView="ResetViewAsync" OnSearch="SearchAsync" />
<SearchBar OnResetView="ResetViewAsync" OnSearch="SearchAsync" Config="Config" />

@foreach (var option in _options)
{
Expand Down
26 changes: 22 additions & 4 deletions src/RapidCMS.UI/Components/Editors/Parts/SearchBar.razor
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
<ul class="nav nav-tabs">
<li class="nav-item">
<button type="button" class="btn btn-light" @onclick="@(async (x) => await OnResetView.InvokeAsync())"><Icon Name="Refresh" /> Reset</button>
</li>
@if (Config.EnableSelectAll)
{
<li class="nav-item">
<button type="button" class="btn btn-light" @onclick="@(async (x) => await OnSelectAll.InvokeAsync())"><Icon Name="MultiSelect" /> Select all</button>
</li>
}
@if (Config.EnableUnselectAll)
{
<li class="nav-item">
<button type="button" class="btn btn-light" @onclick="@(async (x) => await OnUnselectAll.InvokeAsync())"><Icon Name="RemoveFilter" /> Unselect all</button>
</li>
}
@if (Config.EnableReset)
{
<li class="nav-item">
<button type="button" class="btn btn-light" @onclick="@(async (x) => await OnResetView.InvokeAsync())"><Icon Name="Refresh" /> Reset</button>
</li>
}

<li class="nav-item search">
<div class="input-group">
Expand All @@ -24,5 +39,8 @@
private string? _searchTerm;

[Parameter] public EventCallback OnResetView { get; set; } = default!;
[Parameter] public EventCallback OnSelectAll { get; set; } = default!;
[Parameter] public EventCallback OnUnselectAll { get; set; } = default!;
[Parameter] public EventCallback<string> OnSearch { get; set; } = default!;
}
[Parameter] public Picker Config { get; set; } = default!;
}
Loading