diff --git a/src/iRLeagueManager.Web/Components/Dialogs/SelectPromptDialog.razor b/src/iRLeagueManager.Web/Components/Dialogs/SelectPromptDialog.razor
index 1d55b672..7c968bb4 100644
--- a/src/iRLeagueManager.Web/Components/Dialogs/SelectPromptDialog.razor
+++ b/src/iRLeagueManager.Web/Components/Dialogs/SelectPromptDialog.razor
@@ -8,7 +8,8 @@
Label="@Label"
HelperText="@HelperText"
Variant="Variant"
- AnchorOrigin="Origin.BottomCenter">
+ AnchorOrigin="Origin.BottomCenter"
+ ToStringFunc="ToStringFunc">
@if (ItemTemplate is not null)
{
@foreach (var item in Items)
diff --git a/src/iRLeagueManager.Web/Components/DisplayMarkdown.razor b/src/iRLeagueManager.Web/Components/DisplayMarkdown.razor
index 6f54f438..97a409ad 100644
--- a/src/iRLeagueManager.Web/Components/DisplayMarkdown.razor
+++ b/src/iRLeagueManager.Web/Components/DisplayMarkdown.razor
@@ -4,11 +4,17 @@
@inject MarkdownPipeline Pipeline
@inject HtmlSanitizer Sanitizer
-@((MarkupString)RenderBody())
+
+ @((MarkupString)RenderBody())
+
@code {
[Parameter, EditorRequired]
public string Text { get; set; } = string.Empty;
+ [Parameter]
+ public string Class { get; set; } = string.Empty;
+ [Parameter]
+ public string Style { get; set; } = string.Empty;
private string RenderBody()
{
diff --git a/src/iRLeagueManager.Web/Components/InputMarkdown.razor b/src/iRLeagueManager.Web/Components/InputMarkdown.razor
index e2be569b..ebe1c5eb 100644
--- a/src/iRLeagueManager.Web/Components/InputMarkdown.razor
+++ b/src/iRLeagueManager.Web/Components/InputMarkdown.razor
@@ -4,22 +4,20 @@
@inherits InputBase
-
-
+
+
+
+
+
+
+
+
+
+
@code {
diff --git a/src/iRLeagueManager.Web/Components/Settings/Dialogs/EditLeagueDescriptionDialog.razor b/src/iRLeagueManager.Web/Components/Settings/Dialogs/EditLeagueDescriptionDialog.razor
deleted file mode 100644
index 0655aeff..00000000
--- a/src/iRLeagueManager.Web/Components/Settings/Dialogs/EditLeagueDescriptionDialog.razor
+++ /dev/null
@@ -1,19 +0,0 @@
-@namespace iRLeagueManager.Web.Components
-@using Ganss.Xss
-@using iRLeagueApiCore.Common.Models
-@inherits EditDialogBase
-@inject HtmlSanitizer Sanitizer
-
-
-
-
-
-
-@code {
- protected override async Task Submit()
- {
- // sanitize input before saving
- Vm.Description = Sanitizer.Sanitize(Vm.Description);
- await base.Submit();
- }
-}
diff --git a/src/iRLeagueManager.Web/Components/Settings/Dialogs/LeagueDescriptionDialog.razor b/src/iRLeagueManager.Web/Components/Settings/Dialogs/LeagueDescriptionDialog.razor
new file mode 100644
index 00000000..720fae4d
--- /dev/null
+++ b/src/iRLeagueManager.Web/Components/Settings/Dialogs/LeagueDescriptionDialog.razor
@@ -0,0 +1,26 @@
+@namespace iRLeagueManager.Web.Components
+@using Ganss.Xss
+@using iRLeagueManager.Web.Components
+@using iRLeagueApiCore.Common.Models
+@inherits PromptDialog
+@inject HtmlSanitizer Sanitizer
+
+
+
+
+
+
+
+
+
+
+
+
+@code {
+ protected override async Task Submit()
+ {
+ // sanitize input before saving
+ Value = Sanitizer.Sanitize(Value);
+ await base.Submit();
+ }
+}
diff --git a/src/iRLeagueManager.Web/Components/Settings/Dialogs/PointSettingsDialog.razor b/src/iRLeagueManager.Web/Components/Settings/Dialogs/PointSettingsDialog.razor
index 1e110e29..51672489 100644
--- a/src/iRLeagueManager.Web/Components/Settings/Dialogs/PointSettingsDialog.razor
+++ b/src/iRLeagueManager.Web/Components/Settings/Dialogs/PointSettingsDialog.razor
@@ -1,130 +1,134 @@
@namespace iRLeagueManager.Web.Components
@using iRLeagueApiCore.Common.Models
+@using iRLeagueApiCore.Common.Enums
+@using MudBlazor.Utilities
@inherits PromptDialog
@inject PointRuleViewModel PointRule
@inject IJSRuntime jsRuntime
-
-
- Max points + Drop-off
- Point List
-
+
+
+
+ Point List
+ Max points + Drop-off
+ Formula
+
- @switch (PointRule.RuleType)
- {
- case PointRuleViewModel.PointRuleType.MaxPoints:
-
-
-
-
-
-
-
-
- break;
- case PointRuleViewModel.PointRuleType.PointList:
-
- @{
- var pointsPerPlace = PointRule.PointsPerPlace;
- }
-
-
-
- Pos. |
- @foreach (var position in pointsPerPlace.Select((x, i) => i + 1))
- {
- @position. |
- }
- @(PointRule.PointsPerPlace.Count() + 1). |
-
-
-
-
- Pts. |
- @foreach ((var points, var index) in pointsPerPlace.Select((x, i) => ((int?)x, i)))
- {
+ @switch (ruleType)
+ {
+ case PointRuleType.MaxPointsDropOff:
+
+
+
+
+
+
+
+
+ break;
+ case PointRuleType.PointList:
+
+ @{
+ var pointsPerPlace = PointRule.PointsPerPlace;
+ }
+
+
+
+ Pos. |
+ @foreach (var position in pointsPerPlace.Select((x, i) => i + 1))
+ {
+ @position. |
+ }
+ @(PointRule.PointsPerPlace.Count() + 1). |
+
+
+
+
+ Pts. |
+ @foreach ((var points, var index) in pointsPerPlace.Select((x, i) => ((int?)x, i)))
+ {
+
+
+ |
+ }
-
|
- }
-
-
- |
-
-
- |
-
-
-
-
- break;
- }
-
+
+
+ |
+
+
+
+
+ break;
+ case PointRuleType.Formula:
+
+
+
+
+
+
+
+
+
+
+ @foreach (var parameter in FormulaParameters.Parameters)
+ {
+
+ @string.Join(", ", parameter.Aliases.Select(x => "[" + x + "]")) |
+ => |
+ @parameter.Description |
+
+ }
+
+
+
+
+
+
+ break;
+ }
+
+
-@* *@
-
@code {
+ MudForm Form { get; set; } = default!;
+ MudIconButton? FormulaHelpButton { get; set; }
MudInput NewNumberInput { get; set; } = default!;
ElementReference ScrollDummy { get; set; }
+ private PointRuleType? ruleType;
+
private int? newValue = default(int?);
private int? NewValue
{
@@ -138,17 +142,20 @@
}
}
- protected override async void OnAfterRender(bool firstRender)
+ private bool formulaHelpOpen = false;
+
+ protected override void OnParametersSet()
{
- if (firstRender == false)
- {
- return;
- }
+ base.OnParametersSet();
if (PointRule.GetModel() != Value)
{
PointRule.SetModel(Value ?? new());
}
- await InvokeAsync(StateHasChanged);
+ ruleType = PointRule switch
+ {
+ var rule when rule.RuleType == PointRuleType.PointList && rule.PointsPerPlace.None() => null,
+ var rule => rule.RuleType,
+ };
}
private async Task NewPointValue(int? value)
@@ -172,9 +179,15 @@
PointRule.PointsPerPlace[index] = value.Value;
}
- protected override Task Submit()
+ protected override async Task Submit()
{
- if (PointRule.RuleType == PointRuleViewModel.PointRuleType.MaxPoints && PointRule.PointDropOff > 0)
+ await Form.Validate();
+ if (Form.IsValid == false)
+ {
+ return;
+ }
+ PointRule.RuleType = ruleType ?? PointRuleType.PointList;
+ if (PointRule.RuleType == PointRuleType.MaxPointsDropOff && PointRule.PointDropOff > 0)
{
var points = PointRule.MaxPoints;
PointRule.PointsPerPlace.Clear();
@@ -189,6 +202,29 @@
PointRule.MaxPoints = 0;
PointRule.PointDropOff = 0;
}
- return base.Submit();
+ if (PointRule.RuleType == PointRuleType.Formula || ruleType is null)
+ {
+ PointRule.PointsPerPlace.Clear();
+ }
+ await base.Submit();
+ }
+
+ private string ValidateFormula(string formula)
+ {
+ var rnd = new Random();
+ var expression = new NCalc.Expression(formula);
+ foreach (var (key, parameter) in FormulaParameters.ParameterDict)
+ {
+ expression.Parameters[key] = rnd.NextDouble();
+ }
+ try
+ {
+ expression.Evaluate();
+ }
+ catch (Exception e) when (e is ArgumentException or NCalc.EvaluationException)
+ {
+ return e.Message;
+ }
+ return string.Empty;
}
}
diff --git a/src/iRLeagueManager.Web/Components/Settings/ResultConfigSettings.razor b/src/iRLeagueManager.Web/Components/Settings/ResultConfigSettings.razor
index 6dd62056..38dc0421 100644
--- a/src/iRLeagueManager.Web/Components/Settings/ResultConfigSettings.razor
+++ b/src/iRLeagueManager.Web/Components/Settings/ResultConfigSettings.razor
@@ -23,6 +23,18 @@
}
}
+ @{
+ var sourceHelperText = Config.SourceResultConfig != null ? $"Reuse results calculated in {Config.SourceResultConfig.ChampionshipName} - {Config.SourceResultConfig.Name}" : "Use uploaded result data";
+ }
+
+
+ @sourceConfig?.ChampionshipName - @sourceConfig?.Name
+
+
@@ -64,8 +76,8 @@
{
+ Icon="@Icons.Material.Outlined.Delete"
+ OnClick="DeleteConfigClick" />
}
}
diff --git a/src/iRLeagueManager.Web/Components/Settings/ScoringSettings.razor b/src/iRLeagueManager.Web/Components/Settings/ScoringSettings.razor
index 43d7b1b5..4bde76ef 100644
--- a/src/iRLeagueManager.Web/Components/Settings/ScoringSettings.razor
+++ b/src/iRLeagueManager.Web/Components/Settings/ScoringSettings.razor
@@ -17,11 +17,14 @@
Label="Configure Points"
Scroll="true">
@GetPointTypeString()
-
+ @if (PointRuleModel.PointsPerPlace.Any())
+ {
+
+ }
Scoring.PointRule.GetModel();
- set
+ set
{
var scoringModel = Scoring.GetModel();
scoringModel.PointRule = value;
@@ -105,22 +108,17 @@
return sb.ToString();
}
- private string GetPointTypeString()
+ private MarkupString GetPointTypeString()
{
- if (Scoring.PointRule.PointsPerPlace.Count() == 0)
- {
- return "Keep points";
- }
- switch (Scoring.PointRule.RuleType)
+ var typeString = Scoring.PointRule switch
{
- case PointRuleViewModel.PointRuleType.PointList:
- return "Points per place";
- case PointRuleViewModel.PointRuleType.MaxPoints:
- return $"Max pts.: {Scoring.PointRule.MaxPoints}; Drop-off: {Scoring.PointRule.PointDropOff}";
- case PointRuleViewModel.PointRuleType.Formula:
- return $"Formula";
- }
- return "Unknown";
+ var rule when rule.RuleType == PointRuleType.PointList && rule.PointsPerPlace.Any() == false => "Keep points",
+ { RuleType: PointRuleType.PointList } => "Points per place",
+ var rule when rule.RuleType == PointRuleType.MaxPointsDropOff => $"Max pts.: {rule.MaxPoints}; Drop-off: {rule.PointDropOff}",
+ var rule when rule.RuleType == PointRuleType.Formula => $"""Formula: {rule.Formula}
""",
+ _ => "Unknown",
+ };
+ return (MarkupString)typeString;
}
private async Task OnPointSettingsClick()
diff --git a/src/iRLeagueManager.Web/Components/Settings/SettingsItem.razor b/src/iRLeagueManager.Web/Components/Settings/SettingsItem.razor
index c1defb0e..acda37b6 100644
--- a/src/iRLeagueManager.Web/Components/Settings/SettingsItem.razor
+++ b/src/iRLeagueManager.Web/Components/Settings/SettingsItem.razor
@@ -15,7 +15,7 @@
{
}
-
+
@if (ChildContent is null)
{
@Text
diff --git a/src/iRLeagueManager.Web/Components/Settings/SettingsSelectPrompt.razor b/src/iRLeagueManager.Web/Components/Settings/SettingsSelectPrompt.razor
index 71fddef5..2ed416f9 100644
--- a/src/iRLeagueManager.Web/Components/Settings/SettingsSelectPrompt.razor
+++ b/src/iRLeagueManager.Web/Components/Settings/SettingsSelectPrompt.razor
@@ -4,6 +4,7 @@
@inject IDialogService DialogService
x.HelperText, HelperText },
{ x => x.Items, Items },
{ x => x.ItemTemplate, ItemTemplate },
+ { x => x.ToStringFunc, ToStringFunc },
};
var options = new DialogOptions()
- {
- NoHeader = string.IsNullOrEmpty(DialogHeader),
- };
+ {
+ NoHeader = string.IsNullOrEmpty(DialogHeader),
+ };
var result = await DialogService.Show>(DialogHeader, parameters: parameters, options: options).Result;
if (!result.Canceled)
diff --git a/src/iRLeagueManager.Web/Data/FormulaParameters.cs b/src/iRLeagueManager.Web/Data/FormulaParameters.cs
new file mode 100644
index 00000000..9f2e1850
--- /dev/null
+++ b/src/iRLeagueManager.Web/Data/FormulaParameters.cs
@@ -0,0 +1,27 @@
+namespace iRLeagueManager.Web.Data;
+
+public record FormulaParameter(string[] Aliases, string Description);
+
+public static class FormulaParameters
+{
+ public static IEnumerable Parameters { get; } = new List()
+ {
+ new(["pos", "position"], "Finish position"),
+ new(["start", "start_position"], "Starting position"),
+ new(["irating"], "Irating at the start of the session"),
+ new(["sof", "strength_of_field"], "SOF - Strength of field (Irating)"),
+ new(["count", "driver_count"], "Number of drivers/teams in the result"),
+ new(["flap", "fastest_lap"], "Personal fastest lap"),
+ new(["qlap", "qualy_lap"], "Personal qualy lap"),
+ new(["avglap", "avg_lap"], "Personal avg. lap"),
+ new(["flapsession", "session_fastest_lap"], "Fastest lap in the session"),
+ new(["qlapsession", "session_fastest_qualy_lap"], "Fastest qualy lap in the session"),
+ new(["avglapsession", "session_fastest_avg_lap"], "Fastest avg. lap in the session"),
+ };
+
+ public static IDictionary ParameterDict => Parameters
+ .SelectMany(x => x.Aliases.Select(y => (name: y, parameter: x)))
+ .ToDictionary(k => k.name, v => v.parameter);
+
+ public static IEnumerable<(string[] aliases, string description)> ParameterInfo => Parameters.Select(x => (x.Aliases, x.Description));
+}
diff --git a/src/iRLeagueManager.Web/Pages/Settings/ChampionShipSettingsPage.razor b/src/iRLeagueManager.Web/Pages/Settings/ChampionShipSettingsPage.razor
index acf78612..7478e89e 100644
--- a/src/iRLeagueManager.Web/Pages/Settings/ChampionShipSettingsPage.razor
+++ b/src/iRLeagueManager.Web/Pages/Settings/ChampionShipSettingsPage.razor
@@ -148,6 +148,14 @@
await ChampSeason.LoadResultConfigs(CancellationToken);
}
SelectedResultConfig = ChampSeason.ResultConfigViewModels.FirstOrDefault(x => x.ResultConfigId == ResultConfigId) ?? SelectedResultConfig;
+ if (SelectedResultConfig is not null)
+ {
+ await SelectedResultConfig.LoadAvailableResultConfigs(CancellationToken);
+ }
+ else if (ChampSeason.ResultConfigViewModels.Any())
+ {
+ await ChampSeason.ResultConfigViewModels.First().LoadAvailableResultConfigs(CancellationToken);
+ }
LeagueMembers = (await MemberService.GetLeagueMembers(CancellationToken)).Content ?? Enumerable.Empty();
Teams = (await MemberService.GetLeagueTeams(CancellationToken)).Content ?? Enumerable.Empty();
UpdateBreadCrumb();
diff --git a/src/iRLeagueManager.Web/Pages/Settings/LeagueSettings.razor b/src/iRLeagueManager.Web/Pages/Settings/LeagueSettings.razor
index 7bf010be..d7871867 100644
--- a/src/iRLeagueManager.Web/Pages/Settings/LeagueSettings.razor
+++ b/src/iRLeagueManager.Web/Pages/Settings/LeagueSettings.razor
@@ -38,16 +38,15 @@
-
-
-
- @((MarkupString)RenderDescriptionPreview(League.Description))
-
-
-
+
+
+ @((MarkupString)RenderDescriptionPreview(League.Description))
+
+
@@ -162,20 +161,6 @@
}
}
- private async Task EditDescriptionClick(LeagueViewModel league)
- {
- var parameters = new DialogParameters()
- {
- {x => x.Model, league.CopyModel()},
- {x => x.OnSubmit, (vm, cancellation) => vm.SaveChangesAsync(cancellation)},
- };
- var result = await DialogService.Show("Edit description", parameters).Result;
- if (result.Canceled == false && result.Data is LeagueModel model)
- {
- league.SetModel(model);
- }
- }
-
private string RenderDescriptionPreview(string markdown)
{
return Markdig.Markdown.ToHtml(markdown, MarkdownPipeline);
diff --git a/src/iRLeagueManager.Web/ViewModels/PointRuleViewModel.cs b/src/iRLeagueManager.Web/ViewModels/PointRuleViewModel.cs
index 75ca4c8a..3f3b44e6 100644
--- a/src/iRLeagueManager.Web/ViewModels/PointRuleViewModel.cs
+++ b/src/iRLeagueManager.Web/ViewModels/PointRuleViewModel.cs
@@ -19,19 +19,7 @@ public PointRuleViewModel(ILoggerFactory loggerFactory, LeagueApiService apiServ
public long LeagueId => model.LeagueId;
public long PointRuleId => model.PointRuleId;
- private PointRuleType ruleType;
- public PointRuleType RuleType
- {
- get => ruleType;
- set
- {
- if (Set(ref ruleType, value))
- {
- RuleTypeChanged(value);
- }
- }
- }
-
+ public PointRuleType RuleType { get => model.RuleType; set => SetP(model.RuleType, value => model.RuleType = value, value); }
public int MaxPoints { get => model.MaxPoints; set => SetP(model.MaxPoints, value => model.MaxPoints = value, value); }
public int PointDropOff { get => model.PointDropOff; set => SetP(model.PointDropOff, value => model.PointDropOff = value, value); }
public IList PointsPerPlace { get => model.PointsPerPlace; set => SetP(model.PointsPerPlace, value => model.PointsPerPlace = value, value); }
@@ -56,36 +44,5 @@ public IEnumerable BonusPointConfigs
public ICollection AutoPenalties { get => model.AutoPenalties; set => SetP(model.AutoPenalties, value => model.AutoPenalties = value, value); }
- public enum PointRuleType
- {
- MaxPoints = 0,
- PointList = 1,
- Formula = 2,
- }
-
- protected override void SetModel(PointRuleModel model)
- {
- base.SetModel(model);
- RuleType = InferRuleType(model);
- }
-
- private void RuleTypeChanged(PointRuleType ruleType)
- {
- switch (ruleType)
- {
- case PointRuleType.MaxPoints:
- break;
- default:
- break;
- }
- }
-
- private static PointRuleType InferRuleType(PointRuleModel model)
- {
- if (model.MaxPoints != 0)
- {
- return PointRuleType.MaxPoints;
- }
- return PointRuleType.PointList;
- }
+ public string Formula { get => model.Formula; set => SetP(model.Formula, value => model.Formula = value, value); }
}
diff --git a/src/iRLeagueManager.Web/ViewModels/ResultConfigViewModel.cs b/src/iRLeagueManager.Web/ViewModels/ResultConfigViewModel.cs
index 9e2be5f4..fca01f98 100644
--- a/src/iRLeagueManager.Web/ViewModels/ResultConfigViewModel.cs
+++ b/src/iRLeagueManager.Web/ViewModels/ResultConfigViewModel.cs
@@ -1,10 +1,6 @@
-using iRLeagueApiCore.Common.Enums;
-using iRLeagueApiCore.Common.Models;
+using iRLeagueApiCore.Common.Models;
using iRLeagueManager.Web.Data;
using iRLeagueManager.Web.Extensions;
-using Microsoft.Extensions.Configuration.EnvironmentVariables;
-using MudBlazor.Charts;
-using System.Runtime.CompilerServices;
namespace iRLeagueManager.Web.ViewModels;
@@ -36,7 +32,7 @@ public ResultConfigViewModel(ILoggerFactory loggerFactory, LeagueApiService apiS
public long SourceResultConfigId
{
get => SourceResultConfig?.ResultConfigId ?? 0;
- set => SetP(SourceResultConfig, value => SourceResultConfig = value, GetConfigInfoModel(AvailableResultConfigs.FirstOrDefault(x => x.ResultConfigId == value)));
+ set => SetP(SourceResultConfig, value => SourceResultConfig = value, AvailableResultConfigs.FirstOrDefault(x => x.ResultConfigId == value));
}
public bool CalculateCombinedResult
{
@@ -74,8 +70,8 @@ public IEnumerable FiltersForPoints
private ObservableCollection filtersForResult;
public ObservableCollection FiltersForResult { get => filtersForResult; set => Set(ref filtersForResult, value); }
- private ObservableCollection availableResultConfigs;
- public ObservableCollection AvailableResultConfigs { get => availableResultConfigs; set => Set(ref availableResultConfigs, value); }
+ private ObservableCollection availableResultConfigs;
+ public ObservableCollection AvailableResultConfigs { get => availableResultConfigs; set => Set(ref availableResultConfigs, value); }
private ObservableCollection leagueMembers;
public ObservableCollection LeagueMembers { get => leagueMembers; set => Set(ref leagueMembers, value); }
@@ -166,7 +162,7 @@ public async Task LoadAvailableResultConfigs(CancellationToken can
var result = await request;
if (result.Success && result.Content is not null)
{
- AvailableResultConfigs = new(result.Content);
+ AvailableResultConfigs = new(result.Content.Select(GetConfigInfoModel).NotNull());
}
return result.ToStatusResult();
@@ -281,6 +277,8 @@ private void UpdateModelScorings()
return new()
{
+ ChampionshipName = model.ChampionshipName,
+ ChampSeasonId = model.ChampSeasonId,
Name = model.Name,
DisplayName = model.DisplayName,
LeagueId = model.LeagueId,
diff --git a/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj b/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj
index 24918b59..cb8a6460 100644
--- a/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj
+++ b/src/iRLeagueManager.Web/iRLeagueManager.Web.csproj
@@ -2,120 +2,14 @@
net7.0
- 0.11.6
+ 0.11.7
enable
enable
aspnet-iRLeagueManager.Web-2B05F9DC-55A3-49D1-BD64-31507000EDF3
Debug;Release;
- 11
+ 12
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -137,9 +31,10 @@
+
-
-
+
+