Add display names to option choices
This commit is contained in:
parent
c7f0423a8c
commit
97fdb68899
8 changed files with 118 additions and 11 deletions
|
|
@ -1,4 +1,8 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace LANCommander.SDK.Models
|
||||
{
|
||||
|
|
@ -36,6 +40,28 @@ namespace LANCommander.SDK.Models
|
|||
}
|
||||
}
|
||||
|
||||
public class OptionChoice
|
||||
{
|
||||
public string Value { get; set; }
|
||||
public string DisplayName { get; set; }
|
||||
|
||||
[YamlIgnore]
|
||||
public string Label => !string.IsNullOrWhiteSpace(DisplayName) ? DisplayName : Value;
|
||||
|
||||
public OptionChoice() { }
|
||||
|
||||
public OptionChoice(string value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public OptionChoice(string value, string displayName)
|
||||
{
|
||||
Value = value;
|
||||
DisplayName = displayName;
|
||||
}
|
||||
}
|
||||
|
||||
public class OptionDefinition
|
||||
{
|
||||
public string Type { get; set; }
|
||||
|
|
@ -44,7 +70,69 @@ namespace LANCommander.SDK.Models
|
|||
public string Default { get; set; }
|
||||
public string Description { get; set; }
|
||||
public bool Required { get; set; }
|
||||
public List<string> Choices { get; set; }
|
||||
public List<OptionChoice> Choices { get; set; }
|
||||
public Dictionary<string, OptionDefinition> Options { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles deserializing OptionChoice from both plain strings and mapping objects.
|
||||
/// Plain string "foo" becomes OptionChoice { Value = "foo" }.
|
||||
/// Mapping { Value: "foo", DisplayName: "Foo" } becomes OptionChoice { Value = "foo", DisplayName = "Foo" }.
|
||||
/// </summary>
|
||||
public class OptionChoiceYamlConverter : IYamlTypeConverter
|
||||
{
|
||||
public bool Accepts(Type type) => type == typeof(OptionChoice);
|
||||
|
||||
public object ReadYaml(IParser parser, Type type, ObjectDeserializer rootDeserializer)
|
||||
{
|
||||
if (parser.TryConsume<Scalar>(out var scalar))
|
||||
{
|
||||
return new OptionChoice(scalar.Value);
|
||||
}
|
||||
|
||||
if (parser.TryConsume<MappingStart>(out _))
|
||||
{
|
||||
var choice = new OptionChoice();
|
||||
|
||||
while (!parser.TryConsume<MappingEnd>(out _))
|
||||
{
|
||||
var key = parser.Consume<Scalar>();
|
||||
var value = parser.Consume<Scalar>();
|
||||
|
||||
switch (key.Value)
|
||||
{
|
||||
case "Value":
|
||||
choice.Value = value.Value;
|
||||
break;
|
||||
case "DisplayName":
|
||||
choice.DisplayName = value.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return choice;
|
||||
}
|
||||
|
||||
throw new YamlException("Expected a scalar or mapping for OptionChoice");
|
||||
}
|
||||
|
||||
public void WriteYaml(IEmitter emitter, object value, Type type, ObjectSerializer serializer)
|
||||
{
|
||||
var choice = (OptionChoice)value;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(choice.DisplayName))
|
||||
{
|
||||
emitter.Emit(new Scalar(choice.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
emitter.Emit(new MappingStart());
|
||||
emitter.Emit(new Scalar("Value"));
|
||||
emitter.Emit(new Scalar(choice.Value));
|
||||
emitter.Emit(new Scalar("DisplayName"));
|
||||
emitter.Emit(new Scalar(choice.DisplayName));
|
||||
emitter.Emit(new MappingEnd());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ namespace LANCommander.SDK.PowerShell.Cmdlets
|
|||
{
|
||||
var deserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||
.WithTypeConverter(new SDK.Models.OptionChoiceYamlConverter())
|
||||
.IgnoreUnmatchedProperties()
|
||||
.Build();
|
||||
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@ namespace LANCommander.SDK
|
|||
{
|
||||
var deserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||
.WithTypeConverter(new OptionChoiceYamlConverter())
|
||||
.IgnoreUnmatchedProperties()
|
||||
.Build();
|
||||
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ public class ConfigToOptionSchemaService
|
|||
|
||||
var serializer = new SerializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||
.WithTypeConverter(new OptionChoiceYamlConverter())
|
||||
.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitNull | DefaultValuesHandling.OmitDefaults | DefaultValuesHandling.OmitEmptyCollections)
|
||||
.Build();
|
||||
|
||||
|
|
@ -153,13 +154,13 @@ public class ConfigToOptionSchemaService
|
|||
break;
|
||||
|
||||
case JsonValueKind.Array:
|
||||
var choices = new List<string>();
|
||||
var choices = new List<OptionChoice>();
|
||||
foreach (var item in prop.Value.EnumerateArray())
|
||||
{
|
||||
if (item.ValueKind == JsonValueKind.String)
|
||||
choices.Add(item.GetString() ?? "");
|
||||
choices.Add(new OptionChoice(item.GetString() ?? ""));
|
||||
else
|
||||
choices.Add(item.GetRawText());
|
||||
choices.Add(new OptionChoice(item.GetRawText()));
|
||||
}
|
||||
|
||||
options[SanitizeKey(prop.Name)] = new OptionDefinition
|
||||
|
|
|
|||
|
|
@ -28,8 +28,8 @@
|
|||
|
||||
@if (_model.Type == "choice")
|
||||
{
|
||||
<FormItem Label="Choices (one per line)">
|
||||
<TextArea @bind-Value="_choicesText" Rows="4" Placeholder="Option1 Option2 Option3" />
|
||||
<FormItem Label="Choices (one per line, use Value|Display Name for display names)">
|
||||
<TextArea @bind-Value="_choicesText" Rows="4" Placeholder="value1|Display Name 1 value2|Display Name 2 value3" />
|
||||
</FormItem>
|
||||
}
|
||||
|
||||
|
|
@ -92,9 +92,20 @@
|
|||
if (_model.Type == "choice" && !string.IsNullOrWhiteSpace(_choicesText))
|
||||
{
|
||||
lines.Add($"{indent}Choices:");
|
||||
foreach (var choice in _choicesText.Split('\n', StringSplitOptions.RemoveEmptyEntries))
|
||||
foreach (var line in _choicesText.Split('\n', StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
lines.Add($"{indent} - {choice.Trim()}");
|
||||
var trimmed = line.Trim();
|
||||
var parts = trimmed.Split('|', 2);
|
||||
|
||||
if (parts.Length == 2)
|
||||
{
|
||||
lines.Add($"{indent} - Value: {parts[0].Trim()}");
|
||||
lines.Add($"{indent} DisplayName: {parts[1].Trim()}");
|
||||
}
|
||||
else
|
||||
{
|
||||
lines.Add($"{indent} - {trimmed}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
<FormItem Label="@label">
|
||||
@if (!string.IsNullOrWhiteSpace(option.Description) && !string.IsNullOrWhiteSpace(option.DisplayName))
|
||||
{
|
||||
<p style="color: rgba(0,0,0,0.45); margin: -8px 0 8px;">@option.Description</p>
|
||||
<p style="color: rgba(255,255,255,0.45); font-size: 12px; margin: -8px 0 8px;">@option.Description</p>
|
||||
}
|
||||
@if (option.Type == "bool")
|
||||
{
|
||||
|
|
@ -40,9 +40,11 @@
|
|||
}
|
||||
else if ((option.Type == "enum" || option.Type == "choice") && option.Choices != null)
|
||||
{
|
||||
<Select TItem="string"
|
||||
<Select TItem="OptionChoice"
|
||||
TItemValue="string"
|
||||
DataSource="option.Choices"
|
||||
ValueName="@nameof(OptionChoice.Value)"
|
||||
LabelName="@nameof(OptionChoice.Label)"
|
||||
Value="@GetOptionValue(optionKey, option.Default)"
|
||||
ValueChanged="(string v) => SetValue(optionKey, v)"
|
||||
Placeholder="@(option.Default ?? "")" />
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
@using LANCommander.SDK.Enums
|
||||
@using OptionSchema = LANCommander.SDK.Models.OptionSchema
|
||||
@using OptionChoiceYamlConverter = LANCommander.SDK.Models.OptionChoiceYamlConverter
|
||||
@using LANCommander.Server.Extensions
|
||||
@using YamlDotNet.Serialization
|
||||
@using YamlDotNet.Serialization.NamingConventions
|
||||
|
|
@ -350,6 +351,7 @@
|
|||
{
|
||||
var deserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||
.WithTypeConverter(new OptionChoiceYamlConverter())
|
||||
.IgnoreUnmatchedProperties()
|
||||
.Build();
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
<span style="color: rgba(0,0,0,0.45);">This redistributable has no configurable options.</span>
|
||||
<span style="color: rgba(255,255,255,.45);">This redistributable has no configurable options.</span>
|
||||
}
|
||||
</ChildContent>
|
||||
</Panel>
|
||||
|
|
@ -188,6 +188,7 @@
|
|||
{
|
||||
var deserializer = new DeserializerBuilder()
|
||||
.WithNamingConvention(PascalCaseNamingConvention.Instance)
|
||||
.WithTypeConverter(new SDK.Models.OptionChoiceYamlConverter())
|
||||
.IgnoreUnmatchedProperties()
|
||||
.Build();
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue