Skip to content

Commit

Permalink
Merge pull request #48 from SSchulze1989/feature/member-result-filter
Browse files Browse the repository at this point in the history
Feature/member result filter
  • Loading branch information
SSchulze1989 authored Mar 26, 2023
2 parents 61b3192 + b767c82 commit ea8519f
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
General Settings
</button>
</h2>
<div class="accordion-collapse collapse show input-group-list input-group-list-flush" id="collapseGeneralSettings">
<div class="accordion-collapse collapse show input-group-list input-group-list-flush" id="collapseGeneralSettings" data-bs-parent="#resultConfigSections">
<InputGroup Label="Name" ValidationFor="() => Vm.Name">
<InputText class="form-control" id="input-name" placeholder="Name..." aria-label="input-name" @bind-Value=Vm.Name data-bs-toggle="tooltip" title="Identifying name of the result config" />
</InputGroup>
Expand Down Expand Up @@ -55,7 +55,7 @@
Filters
</button>
</h2>
<div class="accordion-collapse collapse input-group-list input-group-list-flush" id="collapseFilters">
<div class="accordion-collapse collapse input-group-list input-group-list-flush" id="collapseFilters" data-bs-parent="#resultConfigSections">
<InputGroup Label="Points Filter">
<button class="form-control" type="button" @onclick=PointsFilterClick data-bs-toggle="tooltip" title="Filter rows that can score points. Only rows that fulfill all filter requirements will be given points. Rows are still displayed in the output result set">
@if (Vm.FiltersForPoints.Count == 0)
Expand Down Expand Up @@ -89,7 +89,7 @@
Session Scorings
</button>
</h2>
<div class="accordion-collapse collapse show m-1 mt-2" id="collapseSessionScorings">
<div class="accordion-collapse collapse m-1 mt-2" id="collapseSessionScorings" data-bs-parent="#resultConfigSections">
@foreach(var scoring in @Bind(Vm, x => x.Scorings).Where(x => x.IsCombinedResult == false))
{
<div class="input-group-list mb-3">
Expand All @@ -113,7 +113,7 @@
Combined Result
</button>
</h2>
<div class="accordion-collapse collapse input-group-list input-group-list-flush" id="collapseCombined">
<div class="accordion-collapse collapse input-group-list input-group-list-flush" id="collapseCombined" data-bs-parent="#resultConfigSections">
<div class="input-group" disabled>
<div class="input-group-text">
<InputCheckbox class="form-check-input mt-0" @bind-Value=Vm.CalculateCombinedResult/>
Expand Down Expand Up @@ -147,12 +147,14 @@
return;
}
await Vm.LoadAvailableResultConfigs(Cts.Token);
await Vm.LoadLeagueMembers(Cts.Token);
}

private async Task PointsFilterClick()
{
var parameters = new ModalParameters()
.Add(nameof(EditResultFilterModal.Model), Vm.GetModel().FiltersForPoints);
var parameters = new ModalParameters<EditResultFilterModal>()
.Add(x => x.Model, Vm.GetModel().FiltersForPoints)
.Add(x => x.LeagueMembers, Vm.LeagueMembers);
var options = new ModalOptions()
{
DisableBackgroundCancel = true,
Expand All @@ -167,8 +169,9 @@

private async Task ResultFilterClick()
{
var parameters = new ModalParameters()
.Add(nameof(EditResultFilterModal.Model), Vm.GetModel().FiltersForResult);
var parameters = new ModalParameters<EditResultFilterModal>()
.Add(x => x.Model, Vm.GetModel().FiltersForResult)
.Add(x => x.LeagueMembers, Vm.LeagueMembers);
var options = new ModalOptions()
{
DisableBackgroundCancel = true,
Expand Down
160 changes: 116 additions & 44 deletions src/iRLeagueManager.Web/Components/Settings/EditResultFilterModal.razor
Original file line number Diff line number Diff line change
Expand Up @@ -18,54 +18,97 @@
<span class="oi oi-trash"/>
</button>
</InputGroup>
<InputGroup Label="Type">
<InputSelect class="form-select" id="input-type-select" aria-label="input-type-select" @bind-Value=filter.Comparator>
@foreach(var compType in Enum.GetValues<ComparatorType>())
{
<option value=@compType>@compType.ToString()</option>
}
<InputGroup Label="Action">
<InputSelect class="form-select" id="input-action-select" aria-label="input-action-select" @bind-Value=filter.Action>
<option value="@MatchedValueAction.Keep">Keep</option>
<option value="@MatchedValueAction.Remove">Remove</option>
</InputSelect>
</InputGroup>
<InputGroup Label="@(@Bind(filter, x => x.Comparator) == ComparatorType.InList ? "Values" : "Value")">
@{
var propertyType = GetColumnPropertyType(filter.ColumnPropertyName);
}
@if (propertyType is null)
{
<label class="form-control disabled" type="text" />
}
else if (filter.Comparator == ComparatorType.InList)
{
<BlazoredTypeahead
@bind-Values=filter.FilterValues
SearchMethod=@(str => Task.FromResult((IEnumerable<string>)Array.Empty<string>()))
AddItemOnEmptyResultMethod=@(str => Task.FromResult(str))
DeleteItemsOnBackspace=false
class="form-control">
<SelectedTemplate Context=value>
@value
@if (filter.FilterType == FilterType.Member)
{
<InputGroup Label="Members">
<BlazoredTypeahead @bind-Values=filter.FilterValues
class="form-control p-0"
style="border-top-right-radius:0; border-top-left-radius:0;"
EnableDropDown=true
SearchMethod=SearchMembers
ConvertMethod="@(item => item.MemberId.ToString())"
MinimumLength=1
MaximumSuggestions=100
DeleteItemsOnBackspace=false
placeholder="Search driver by name...">

<SelectedTemplate Context=memberId>
@{var member = LeagueMembers.FirstOrDefault(x => x.MemberId.ToString() == memberId); }
@if (member is null)
{
@memberId
}
else
{
@member.FirstName @member.LastName
}
</SelectedTemplate>
<ResultTemplate Context=value>
@value
<ResultTemplate Context=member>
@member.FirstName @member.LastName (@member.IRacingId)
</ResultTemplate>
<NotFoundTemplate Context=value>
@value
<NotFoundTemplate Context=name>
<span>Driver <b>@name</b> Not found!</span>
</NotFoundTemplate>
</BlazoredTypeahead>
}
else if (propertyType == typeof(string))
{
<InputText class="form-control" @bind-Value=filter.Value />
}
else if (propertyType == typeof(double) || propertyType == typeof(double?) || propertyType == typeof(int) || propertyType == typeof(int?))
{
<input type="number" class="form-control" value=@filter.Value @onchange=@((ChangeEventArgs args) => filter.Value = args.Value?.ToString() ?? string.Empty) />
}
else
{
<label class="form-control">Not supported</label>
}
</InputGroup>
</InputGroup>
}
else if (filter.FilterType == FilterType.ColumnProperty)
{
<InputGroup Label="Type">
<InputSelect class="form-select" id="input-type-select" aria-label="input-type-select" @bind-Value=filter.Comparator>
@foreach (var compType in Enum.GetValues<ComparatorType>())
{
<option value=@compType>@compType.ToString()</option>
}
</InputSelect>
</InputGroup>
<InputGroup Label="@(@Bind(filter, x => x.Comparator) == ComparatorType.InList ? "Values" : "Value")">
@{
var propertyType = GetColumnPropertyType(filter.ColumnPropertyName);
}
@if (propertyType is null)
{
<label class="form-control disabled" type="text" />
}
else if (filter.Comparator == ComparatorType.InList)
{
<BlazoredTypeahead
@bind-Values=filter.FilterValues
SearchMethod=@(str => Task.FromResult((IEnumerable<string>)Array.Empty<string>()))
AddItemOnEmptyResultMethod=@(str => Task.FromResult(str))
DeleteItemsOnBackspace=false
class="form-control">
<SelectedTemplate Context=value>
@value
</SelectedTemplate>
<ResultTemplate Context=value>
@value
</ResultTemplate>
<NotFoundTemplate Context=value>
@value
</NotFoundTemplate>
</BlazoredTypeahead>
}
else if (propertyType == typeof(string))
{
<InputText class="form-control" @bind-Value=filter.Value />
}
else if (propertyType == typeof(double) || propertyType == typeof(double?) || propertyType == typeof(int) || propertyType == typeof(int?))
{
<input type="number" class="form-control" value=@filter.Value @onchange=@((ChangeEventArgs args) => filter.Value = args.Value?.ToString() ?? string.Empty) />
}
else
{
<label class="form-control">Not supported</label>
}
</InputGroup>
}
</div>
</EditForm>
}
Expand All @@ -81,6 +124,9 @@
[Parameter]
public IEnumerable<ResultFilterModel> Model { get; set; } = default!;

[Parameter]
public IEnumerable<MemberModel> LeagueMembers { get; set; } = default!;

private static IEnumerable<string> ColumnNames { get; } = new[]
{
nameof(ResultRowModel.Car),
Expand All @@ -94,12 +140,38 @@
nameof(ResultRowModel.NewIrating),
nameof(ResultRowModel.OldSafetyRating),
nameof(ResultRowModel.NewSafetyRating),
"Member",
};

private async Task<IEnumerable<MemberModel>> SearchMembers(string searchString)
{
if (string.IsNullOrEmpty(searchString))
{
return await Task.FromResult(LeagueMembers);
}

var terms = searchString.ToLower().Split(',', ' ', ';')
.Where(x => string.IsNullOrWhiteSpace(x) == false)
.ToArray();
return await Task.FromResult(LeagueMembers
.Where(x => MatchMemberSearchTerms(x, terms)));
}

private bool MatchMemberSearchTerms(MemberModel member, params string[] terms)
{
var searchName = member.FirstName + member.LastName;
var iracingId = member.IRacingId.ToString();
return terms
.Any(x => searchName.Contains(x, StringComparison.OrdinalIgnoreCase) ||
iracingId.Contains(x)
);
}

protected override void OnParametersSet()
{
_ = ModalInstance ?? throw BlazorParameterNullException.New(this, ModalInstance);
_ = Model ?? throw BlazorParameterNullException.New(this, Model);
BlazorParameterNullException.ThrowIfNull(this, ModalInstance);
BlazorParameterNullException.ThrowIfNull(this, Model);
BlazorParameterNullException.ThrowIfNull(this, LeagueMembers);
}

protected override void OnAfterRender(bool firstRender)
Expand Down
27 changes: 27 additions & 0 deletions src/iRLeagueManager.Web/ViewModels/ResultConfigViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ public bool CalculateCombinedResult
private ObservableCollection<ResultConfigModel> availableResultConfigs;
public ObservableCollection<ResultConfigModel> AvailableResultConfigs { get => availableResultConfigs; set => Set(ref availableResultConfigs, value); }

private ObservableCollection<MemberModel> leagueMembers;
public ObservableCollection<MemberModel> LeagueMembers { get => leagueMembers; set => Set(ref leagueMembers, value); }

public override void SetModel(ResultConfigModel model)
{
base.SetModel(model);
Expand Down Expand Up @@ -123,6 +126,30 @@ public async Task<StatusResult> LoadAvailableResultConfigs(CancellationToken can
return result.ToStatusResult();
}

public async Task<StatusResult> LoadLeagueMembers(CancellationToken cancellationToken = default)
{
if (CurrentLeague is null)
{
return LeagueNullResult();
}

try
{
Loading = true;
var result = await CurrentLeague.Members()
.Get(cancellationToken);
if (result.Success && result.Content is not null)
{
LeagueMembers = new(result.Content);
}
return result.ToStatusResult();
}
finally
{
Loading = false;
}
}

public async Task<StatusResult> SaveChangesAsync(CancellationToken cancellationToken)
{
if (ApiService.CurrentLeague is null)
Expand Down
31 changes: 29 additions & 2 deletions src/iRLeagueManager.Web/ViewModels/ResultFilterViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,36 @@ public ResultFilterViewModel(ILoggerFactory loggerFactory, LeagueApiService apiS

public long LeagueId => model.LeagueId;
public long ResultsFilterId => model.FilterOptionId;
public string ColumnPropertyName { get => model.ColumnPropertyName; set => SetP(model.ColumnPropertyName, value => model.ColumnPropertyName = value, value); }
public string ColumnPropertyName
{
get => model.ColumnPropertyName;
set
{
if (SetP(model.ColumnPropertyName, value => model.ColumnPropertyName = value, value))
{
UpdateFilterType();
}
}

}
public ComparatorType Comparator { get => model.Comparator; set => SetP(model.Comparator, value => model.Comparator = value, value); }
public FilterType FilterType { get => model.FilterType; set => SetP(model.FilterType, value => model.FilterType = value, value); }
public FilterType FilterType { get => model.FilterType; private set => SetP(model.FilterType, value => model.FilterType = value, value); }
public IList<string> FilterValues { get => (IList<string>)model.FilterValues; set => SetP(model.FilterValues, value => model.FilterValues = value, value); }
public string Value { get => model.FilterValues.FirstOrDefault() ?? string.Empty; set => SetP(model.FilterValues.FirstOrDefault() ?? string.Empty, value => model.FilterValues = new[] { value }.ToList(), value); }
public MatchedValueAction Action { get => model.Action; set => SetP(model.Action, value => model.Action = value, value); }

public override void SetModel(ResultFilterModel model)
{
base.SetModel(model);
UpdateFilterType();
}

private void UpdateFilterType()
{
FilterType = ColumnPropertyName switch
{
"Member" => FilterType.Member,
_ => FilterType.ColumnProperty,
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public ResultFiltersViewModel(ILoggerFactory loggerFactory, LeagueApiService api
}

private ObservableCollection<ResultFilterViewModel> filters;
public ObservableCollection<ResultFilterViewModel> Filters { get => filters; set => SetP(filters, value => filters = value, value); }
public ObservableCollection<ResultFilterViewModel> Filters { get => filters; set => Set(ref filters, value); }

public void SetModel(IEnumerable<ResultFilterModel> model)
{
Expand Down
4 changes: 2 additions & 2 deletions src/iRLeagueManager.Web/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
}
},
"AllowedHosts": "*",
//"APIServer": "http://localhost:5000",
"APIServer": "https://irleaguemanager.net/api/",
"APIServer": "http://localhost:5000",
//"APIServer": "https://irleaguemanager.net/api/",
"DefaultUser": "testuser",
"DefaultPassword": "TestPass123!"
}
6 changes: 3 additions & 3 deletions src/iRLeagueManager.Web/iRLeagueManager.Web.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Version>0.5.2</Version>
<Version>0.5.3-dev.1</Version>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>aspnet-iRLeagueManager.Web-2B05F9DC-55A3-49D1-BD64-31507000EDF3</UserSecretsId>
Expand Down Expand Up @@ -130,8 +130,8 @@
<ItemGroup>
<PackageReference Include="Blazored.LocalStorage" Version="4.3.0" />
<PackageReference Include="Blazored.Modal" Version="7.1.0" />
<PackageReference Include="iRLeagueApiCore.Client" Version="0.5.0" />
<PackageReference Include="iRLeagueApiCore.Common" Version="0.5.1-dev.1" />
<PackageReference Include="iRLeagueApiCore.Client" Version="0.5.2-dev.1" />
<PackageReference Include="iRLeagueApiCore.Common" Version="0.5.2-dev.2" />
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Identity.UI" Version="6.0.3" />
Expand Down

0 comments on commit ea8519f

Please sign in to comment.