-
Notifications
You must be signed in to change notification settings - Fork 720
Interaction service #9943
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
Interaction service #9943
Changes from all commits
fdd6668
eedd8c4
715190c
cdf8f09
3c2d4c2
ff29d7e
fdc91e4
6316cef
0e88404
d6a5234
6a8d2d0
7e59dba
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| @using Aspire.Dashboard.Components.Controls.Chart | ||
| @using Aspire.Dashboard.Model | ||
| @using Aspire.Dashboard.Model.Otlp | ||
| @using Aspire.Dashboard.Otlp.Model | ||
| @using Aspire.Dashboard.Resources | ||
| @using Aspire.Dashboard.Utils | ||
| @using Aspire.Dashboard.Extensions | ||
| @using System.Globalization | ||
| @using Aspire.Dashboard.Components.Controls.Grid | ||
| @using Aspire.ResourceService.Proto.V1 | ||
| @using Dialogs = Aspire.Dashboard.Resources.Dialogs | ||
| @implements IDialogContentComponent<InteractionsInputsDialogViewModel> | ||
|
|
||
| @inject IStringLocalizer<Dialogs> Loc | ||
|
|
||
| <FluentDialogHeader ShowDismiss="true"> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO we should put the icon next to the header since it looks awkward next to the body. Thoughts? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm using the built-in message box from FluentUI: https://www.fluentui-blazor.net/MessageBox. Moving the icon would require creating a custom dialog. We could do it in the future, but for now I think the default is good enough. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ooooh I was looking at DialogBox in docs. Fine by me! |
||
| <FluentStack VerticalAlignment="VerticalAlignment.Center"> | ||
| <FluentLabel Typo="Typography.PaneHeader"> | ||
| @Dialog.Instance.Parameters.Title | ||
| </FluentLabel> | ||
| </FluentStack> | ||
| </FluentDialogHeader> | ||
|
|
||
| <FluentDialogBody Class="interaction-input-dialog"> | ||
| @if (!string.IsNullOrEmpty(Content.Interaction.Message)) | ||
| { | ||
| <p>@((MarkupString)Content.Interaction.Message)</p> | ||
| } | ||
|
|
||
| <EditForm EditContext="@_editContext"> | ||
| <FluentStack Orientation="Orientation.Vertical" VerticalGap="12"> | ||
| @foreach (var ss in Content.Inputs) | ||
| { | ||
| var localItem = ss; | ||
| <div class="interaction-input"> | ||
| @switch (ss.InputType) | ||
| { | ||
| case InputType.Text: | ||
| <FluentTextField @bind-Value="localItem.Value" Label="@localItem.Label" Placeholder="@localItem.Placeholder" Required="localItem.Required" /> | ||
| <ValidationMessage For="@(() => localItem.Value)" /> | ||
| break; | ||
| case InputType.Password: | ||
| <FluentTextField @bind-Value="localItem.Value" Label="@localItem.Label" Placeholder="@localItem.Placeholder" Required="localItem.Required" TextFieldType="TextFieldType.Password" /> | ||
| <ValidationMessage For="@(() => localItem.Value)" /> | ||
| break; | ||
| case InputType.Select: | ||
| <FluentSelect TOption="SelectViewModel<string>" | ||
| @bind-Value="localItem.Value" | ||
| Label="@localItem.Label" | ||
| Placeholder="@localItem.Placeholder" | ||
| Required="localItem.Required" | ||
| Items="localItem.Options.Select(o => new SelectViewModel<string> { Id = o.Key, Name = o.Value })" | ||
| OptionValue="@(vm => vm.Id)" | ||
| OptionText="@(vm => vm.Name)" | ||
| Height="250px" | ||
| Position="SelectPosition.Below" /> | ||
| <ValidationMessage For="@(() => localItem.Value)" /> | ||
| break; | ||
| case InputType.Checkbox: | ||
| <FluentCheckbox @bind-Value="localItem.IsChecked" Label="@localItem.Label" Placeholder="@localItem.Placeholder" /> | ||
| break; | ||
| case InputType.Number: | ||
| <FluentNumberField @bind-Value="localItem.NumberValue" Label="@localItem.Label" Placeholder="@localItem.Placeholder" Required="localItem.Required" /> | ||
| <ValidationMessage For="@(() => localItem.NumberValue)" /> | ||
| break; | ||
| default: | ||
| @* Ignore unexpected InputTypes *@ | ||
| break; | ||
| } | ||
| </div> | ||
| } | ||
| </FluentStack> | ||
| </EditForm> | ||
| </FluentDialogBody> | ||
|
|
||
| <FluentDialogFooter> | ||
| <FluentButton Appearance="Appearance.Accent" OnClick="@OkAsync"> | ||
| @Dialog.Instance.Parameters.PrimaryAction | ||
| </FluentButton> | ||
| @if (!string.IsNullOrEmpty(Dialog.Instance.Parameters.SecondaryAction)) | ||
| { | ||
| <FluentButton Appearance="Appearance.Neutral" OnClick="@CancelAsync"> | ||
| @Dialog.Instance.Parameters.SecondaryAction | ||
| </FluentButton> | ||
| } | ||
| </FluentDialogFooter> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| using Aspire.Dashboard.Model; | ||
| using Aspire.ResourceService.Proto.V1; | ||
| using Microsoft.AspNetCore.Components; | ||
| using Microsoft.AspNetCore.Components.Forms; | ||
| using Microsoft.FluentUI.AspNetCore.Components; | ||
|
|
||
| namespace Aspire.Dashboard.Components.Dialogs; | ||
|
|
||
| public partial class InteractionsInputDialog | ||
| { | ||
| [Parameter] | ||
| public InteractionsInputsDialogViewModel Content { get; set; } = default!; | ||
|
|
||
| [CascadingParameter] | ||
| public FluentDialog Dialog { get; set; } = default!; | ||
|
|
||
| private EditContext _editContext = default!; | ||
| private ValidationMessageStore _validationMessages = default!; | ||
|
|
||
| protected override void OnInitialized() | ||
| { | ||
| _editContext = new EditContext(Content); | ||
| _validationMessages = new ValidationMessageStore(_editContext); | ||
|
|
||
| _editContext.OnValidationRequested += (s, e) => ValidateModel(); | ||
| _editContext.OnFieldChanged += (s, e) => ValidateField(e.FieldIdentifier); | ||
| } | ||
|
|
||
| private void ValidateModel() | ||
| { | ||
| _validationMessages.Clear(); | ||
|
|
||
| foreach (var inputModel in Content.Inputs) | ||
| { | ||
| var field = new FieldIdentifier(inputModel, nameof(inputModel.Value)); | ||
| if (IsMissingRequiredValue(inputModel)) | ||
| { | ||
| _validationMessages.Add(field, $"{inputModel.Label} is required."); | ||
| } | ||
| } | ||
|
|
||
| _editContext.NotifyValidationStateChanged(); | ||
| } | ||
|
|
||
| private void ValidateField(FieldIdentifier field) | ||
| { | ||
| _validationMessages.Clear(field); | ||
|
|
||
| if (field.Model is InteractionInput inputModel) | ||
| { | ||
| if (IsMissingRequiredValue(inputModel)) | ||
| { | ||
| _validationMessages.Add(field, $"{inputModel.Label} is required."); | ||
| } | ||
| } | ||
|
|
||
| _editContext.NotifyValidationStateChanged(); | ||
| } | ||
|
|
||
| private static bool IsMissingRequiredValue(InteractionInput inputModel) | ||
| { | ||
| return inputModel.Required && | ||
| inputModel.InputType != InputType.Checkbox && | ||
| string.IsNullOrWhiteSpace(inputModel.Value); | ||
| } | ||
|
|
||
| private async Task OkAsync() | ||
| { | ||
| if (_editContext.Validate()) | ||
| { | ||
| await Dialog.CloseAsync(Content); | ||
| } | ||
| } | ||
|
|
||
| private async Task CancelAsync() | ||
| { | ||
| await Dialog.CancelAsync(); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| .interaction-input-dialog .interaction-input ::deep { | ||
| width: 100%; | ||
| } | ||
|
|
||
| .interaction-input-dialog .interaction-input ::deep fluent-text-field, .interaction-input-dialog .interaction-input ::deep fluent-select { | ||
| width: 75%; | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.