-
Notifications
You must be signed in to change notification settings - Fork 856
Add notification center, command response message, and markdown support to Dashboard #15906
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
Changes from all commits
7513cc8
d3c9fd4
9407ede
fb0895a
fdb2ca0
3d10a3f
ff686cc
297f91e
79f4780
a4d5287
2407c85
f350398
356a639
0a23e40
8a74654
3416da5
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,44 @@ | ||
| @using Aspire.Dashboard.Model | ||
| @using Aspire.Dashboard.Otlp.Model | ||
| @using Aspire.Dashboard.Resources | ||
| @using Microsoft.FluentUI.AspNetCore.Components.Extensions | ||
| @inject TimeProvider TimeProvider | ||
| @inject IStringLocalizer<Dialogs> Loc | ||
|
|
||
| <div class="notification-entry @IntentClass"> | ||
| @* Header *@ | ||
| <div class="notification-entry-icon"> | ||
| <FluentIcon Value="@Icon" Color="@IconColor" /> | ||
| </div> | ||
| <div class="notification-entry-message"> | ||
| @Entry.Title | ||
| </div> | ||
| <div class="notification-entry-close"> | ||
| <FluentButton Appearance="Appearance.Stealth" | ||
| aria-label="@Loc[nameof(Dialogs.NotificationEntryDismiss)]" | ||
| OnClick="@HandleDismiss"> | ||
| <FluentIcon Value="@(new Icons.Regular.Size16.Dismiss())" Color="@Color.Neutral" /> | ||
| </FluentButton> | ||
| </div> | ||
|
|
||
| @* Detailed content *@ | ||
| <div class="notification-entry-content"> | ||
| @if (!string.IsNullOrEmpty(Entry.Body)) | ||
| { | ||
| @OtlpHelpers.TruncateString(Entry.Body, 500) | ||
| } | ||
| @if (Entry.PrimaryAction is { } primaryAction) | ||
| { | ||
| <FluentButton Appearance="Appearance.Neutral" | ||
| OnClick="@HandlePrimaryAction" | ||
| Class="notification-entry-action"> | ||
| @primaryAction.Text | ||
| </FluentButton> | ||
| } | ||
| </div> | ||
|
|
||
| @* Timestamp *@ | ||
| <div class="notification-entry-time"> | ||
| @((TimeProvider.GetUtcNow() - Entry.Timestamp).ToTimeAgo()) | ||
|
Member
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. nit: The relative timestamp ( |
||
| </div> | ||
| </div> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| // 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 Microsoft.AspNetCore.Components; | ||
| using Microsoft.FluentUI.AspNetCore.Components; | ||
| using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons; | ||
|
|
||
| namespace Aspire.Dashboard.Components.Dialogs; | ||
|
|
||
| public partial class NotificationEntryComponent : ComponentBase | ||
| { | ||
| [Parameter, EditorRequired] | ||
| public required NotificationEntry Entry { get; set; } | ||
|
|
||
| [Parameter] | ||
| public EventCallback OnDismiss { get; set; } | ||
|
|
||
| private string IntentClass => Entry.Intent switch | ||
| { | ||
| MessageIntent.Success => "intent-success", | ||
| MessageIntent.Error => "intent-error", | ||
| MessageIntent.Warning => "intent-warning", | ||
| _ => "intent-info" | ||
| }; | ||
|
|
||
| private Icon Icon => Entry.Intent switch | ||
| { | ||
| MessageIntent.Success => new Icons.Filled.Size20.CheckmarkCircle(), | ||
| MessageIntent.Error => new Icons.Filled.Size20.DismissCircle(), | ||
| MessageIntent.Warning => new Icons.Filled.Size20.Warning(), | ||
| _ => new Icons.Filled.Size20.Info() | ||
| }; | ||
|
|
||
| private Color IconColor => Entry.Intent switch | ||
| { | ||
| MessageIntent.Success => Color.Success, | ||
| MessageIntent.Error => Color.Error, | ||
| MessageIntent.Warning => Color.Warning, | ||
| _ => Color.Info | ||
| }; | ||
|
|
||
| private async Task HandleDismiss() | ||
| { | ||
| await OnDismiss.InvokeAsync(); | ||
| } | ||
|
|
||
| private async Task HandlePrimaryAction() | ||
| { | ||
| if (Entry.PrimaryAction is { } primaryAction) | ||
| { | ||
| await primaryAction.OnClick(); | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| .notification-entry { | ||
| font-family: var(--body-font); | ||
| color: var(--neutral-foreground-rest); | ||
| display: grid; | ||
| grid-template-columns: 24px 1fr auto; | ||
| width: 100%; | ||
| min-height: 36px; | ||
| padding: 0 8px; | ||
| column-gap: 4px; | ||
| border-top: calc(var(--stroke-width) * 1px) solid var(--neutral-stroke-divider-rest); | ||
| } | ||
|
|
||
| .notification-entry.intent-info { | ||
| fill: var(--info); | ||
| } | ||
|
|
||
| .notification-entry.intent-warning { | ||
| fill: var(--warning); | ||
| } | ||
|
|
||
| .notification-entry.intent-error { | ||
| fill: var(--error); | ||
| } | ||
|
|
||
| .notification-entry.intent-success { | ||
| fill: var(--success); | ||
| } | ||
|
|
||
| .notification-entry-icon { | ||
| grid-column: 1; | ||
| grid-row: 1; | ||
| display: flex; | ||
| justify-content: center; | ||
| align-self: center; | ||
| } | ||
|
|
||
| .notification-entry-message { | ||
| grid-column: 2; | ||
| grid-row: 1; | ||
| padding: 10px 0; | ||
| align-self: center; | ||
| font-weight: 600; | ||
| font-size: 12px; | ||
| line-height: 16px; | ||
| white-space: unset; | ||
| } | ||
|
|
||
| .notification-entry-close { | ||
| grid-column: 3; | ||
| grid-row: 1; | ||
| padding: 4px; | ||
| display: flex; | ||
| justify-content: center; | ||
| justify-self: center; | ||
| cursor: pointer; | ||
| } | ||
|
|
||
| .notification-entry-content { | ||
| grid-column: 1 / 4; | ||
| grid-row: 2; | ||
| padding: 6px 6px; | ||
| display: flex; | ||
| flex-direction: column; | ||
| align-items: flex-start; | ||
| gap: 8px; | ||
| font-size: 12px; | ||
| word-break: break-word; | ||
| } | ||
|
|
||
| .notification-entry-time { | ||
| grid-column: 2 / 4; | ||
| grid-row: 3; | ||
| font-size: 12px; | ||
| text-align: right; | ||
| padding: 4px 4px 8px 0px; | ||
| color: var(--foreground-subtext-rest); | ||
| } | ||
|
|
||
| ::deep .notification-entry-action { | ||
| height: 24px; | ||
| font-size: 12px; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the experience not consistent with no pop-ups showing up for Migrate Database when there is one for Get Connection String? It feels a little incongruous
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They're test commands. It's for testing different scenarios.