File: Model\Interaction\InputViewModel.cs
Web Access
Project: src\src\Aspire.Dashboard\Aspire.Dashboard.csproj (Aspire.Dashboard)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Globalization;
using Aspire.DashboardService.Proto.V1;
 
namespace Aspire.Dashboard.Model.Interaction;
 
public sealed class InputViewModel
{
    public InteractionInput Input { get; private set; } = default!;
 
    public InputViewModel(InteractionInput input)
    {
        SetInput(input);
    }
 
    public void SetInput(InteractionInput input)
    {
        string value;
        if (Input == null)
        {
            value = input.Value;
        }
        else
        {
            // Only overwrite the local value if the input was loading and is no longer loading (update could have come from server)
            // This avoids changes in local values being overwritten by a dynamic server update.
            if (Input.Loading && !input.Loading)
            {
                value = input.Value;
            }
            else
            {
                value = Input.Value;
            }
        }
        input.Value = value;
 
        Input = input;
        if (input.InputType == InputType.Choice && input.Options != null)
        {
            var optionsVM = input.Options
                .Select(option => new SelectViewModel<string> { Id = option.Key, Name = option.Value, })
                .ToList();
 
            SelectOptions = optionsVM;
 
            // Default to the first option if no placeholder is set, the value is empty, and custom choice is disabled.
            // This is done so the input model value matches frontend behavior (FluentSelect defaults to the first option)
            if (string.IsNullOrEmpty(input.Placeholder) && string.IsNullOrEmpty(input.Value) && optionsVM.Count > 0 && !input.AllowCustomChoice)
            {
                input.Value = optionsVM[0].Id;
            }
        }
    }
 
    public List<SelectViewModel<string>> SelectOptions { get; private set; } = [];
 
    public IEnumerable<SelectViewModel<string>> FilteredOptions()
    {
        if (Value is not { Length: > 0 } value)
        {
            return SelectOptions;
        }
 
        return SelectOptions.Where(vm => vm.Name.Contains(value, StringComparison.OrdinalIgnoreCase));
    }
 
    public string? Value
    {
        get => Input.Value;
        set => Input.Value = value;
    }
 
    // Used when binding to FluentCheckbox.
    public bool IsChecked
    {
        get => bool.TryParse(Input.Value, out var result) && result;
        set => Input.Value = value ? "true" : "false";
    }
 
    // Used when binding to FluentNumberField.
    public int? NumberValue
    {
        get => int.TryParse(Input.Value, CultureInfo.InvariantCulture, out var result) ? result : null;
        set => Input.Value = value?.ToString(CultureInfo.InvariantCulture) ?? string.Empty;
    }
 
    public bool InputDisabled => Input.Disabled || Input.Loading;
}