-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
- Loading branch information
Showing
9 changed files
with
304 additions
and
1 deletion.
There are no files selected for viewing
9 changes: 9 additions & 0 deletions
9
src/AzureOpenAIProxy.PlaygroundApp/Components/Pages/AdminEvents.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
@page "/admin/events" | ||
|
||
<PageTitle>AdminEvents</PageTitle> | ||
|
||
<h1>AdminEvents</h1> | ||
|
||
<p>This component demonstrates showing admin events.</p> | ||
|
||
<AdminEventsComponent @rendermode="InteractiveServer"/> |
18 changes: 18 additions & 0 deletions
18
src/AzureOpenAIProxy.PlaygroundApp/Components/UI/Admin/AdminEventIsActiveComponent.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
<div class="admin-event-active-state"> | ||
<div class="@GetActiveClass(IsActive)"></div> | ||
</div> | ||
|
||
@code { | ||
[Parameter] | ||
public required bool IsActive { get; set; } | ||
|
||
private string GetActiveClass(bool? isActive) | ||
{ | ||
if (!isActive.HasValue) | ||
{ | ||
return "deactivated"; | ||
} | ||
|
||
return isActive.Value ? "activated" : "deactivated"; | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
src/AzureOpenAIProxy.PlaygroundApp/Components/UI/Admin/AdminEventIsActiveComponent.razor.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
.admin-event-active-state { | ||
display: flex; | ||
flex-direction: column; | ||
justify-content: center; | ||
align-items: center; | ||
height: 100%; | ||
} | ||
|
||
.activated { | ||
width: 10px; | ||
height: 10px; | ||
background-color: green; | ||
border-radius: 50%; | ||
display: inline-block; | ||
} | ||
|
||
.deactivated { | ||
width: 10px; | ||
height: 10px; | ||
background-color: red; | ||
border-radius: 50%; | ||
display: inline-block; | ||
} |
89 changes: 89 additions & 0 deletions
89
src/AzureOpenAIProxy.PlaygroundApp/Components/UI/Admin/AdminEventsComponent.razor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
@using AzureOpenAIProxy.PlaygroundApp.Models | ||
|
||
<div id="admin-events-component"> | ||
@if (eventDetails == null) | ||
{ | ||
<p><em>Loading...</em></p> | ||
} | ||
else | ||
{ | ||
<div id="admin-events-table"> | ||
<FluentDataGrid Items="@eventDetails" Pagination="@pagination" > | ||
<PropertyColumn Class="fluent-datagrid-cell" Property="@(p => p.Title)" Align="@Align.Center" Sortable="true" /> | ||
<PropertyColumn Class="fluent-datagrid-cell" Property="@(p => p.DateStart)" Format="yyyy-MM-dd" Align="@Align.Center" Sortable="true" /> | ||
<PropertyColumn Class="fluent-datagrid-cell" Property="@(p => p.DateEnd)" Format="yyyy-MM-dd" Align="@Align.Center" Sortable="true" /> | ||
<PropertyColumn Class="fluent-datagrid-cell" Property="@(p => p.TimeZone)" Align="@Align.Center" Sortable="true" /> | ||
<PropertyColumn Class="fluent-datagrid-cell" Property="@(p => p.OrganizerName)" Align="@Align.Center" Sortable="true" /> | ||
<PropertyColumn Class="fluent-datagrid-cell" Property="@(p => p.CoorganizerName)" Align="@Align.Center" Sortable="true" /> | ||
<PropertyColumn Class="fluent-datagrid-cell" Property="@(p => p.MaxTokenCap)" Align="@Align.Center" Sortable="true" /> | ||
<PropertyColumn Class="fluent-datagrid-cell" Property="@(p => p.DailyRequestCap)" Align="@Align.Center" Sortable="true" /> | ||
<TemplateColumn Class="fluent-datagrid-cell" Title="Active" Align="@Align.Center"> | ||
<AdminEventIsActiveComponent IsActive="@(((AdminEventDetails)@context).IsActive)" /> | ||
</TemplateColumn> | ||
<TemplateColumn Class="fluent-datagrid-cell" Title="Actions" Align="@Align.Center"> | ||
<FluentButton aria-label="Edit item" IconEnd="@(new Icons.Regular.Size16.Edit())" /> | ||
<FluentButton aria-label="Delete item" IconEnd="@(new Icons.Regular.Size16.Delete())" /> | ||
</TemplateColumn> | ||
</FluentDataGrid> | ||
</div> | ||
|
||
<div class="page-button-box"> | ||
@if (pagination.TotalItemCount.HasValue) | ||
{ | ||
for (var pageIndex = 0; pageIndex <= pagination.LastPageIndex; pageIndex++) | ||
{ | ||
var capturedIndex = pageIndex; | ||
<FluentButton class="page-button" @onclick="@(() => GoToPageAsync(capturedIndex))" Appearance="@PageButtonAppearance(capturedIndex)" | ||
aria-current="@AriaCurrentValue(capturedIndex)"> | ||
@(capturedIndex + 1) | ||
</FluentButton> | ||
} | ||
} | ||
</div> | ||
} | ||
</div> | ||
|
||
@code { | ||
private IQueryable<AdminEventDetails>? eventDetails; | ||
private PaginationState pagination = new PaginationState { ItemsPerPage = 10 }; | ||
|
||
protected override async Task OnInitializedAsync() | ||
{ | ||
// Simulate asynchronous loading to demonstrate streaming rendering | ||
await Task.Delay(100); | ||
|
||
var startDate = DateOnly.FromDateTime(DateTime.Now); | ||
|
||
// make dummy data | ||
eventDetails = Enumerable.Range(1, 150).Select(index => new AdminEventDetails | ||
{ | ||
EventId = Guid.NewGuid(), | ||
Title = $"event title #{index}", | ||
Summary = "dummy summary", | ||
Description = "dummy description", | ||
DateStart = DateTimeOffset.Now, | ||
DateEnd = DateTimeOffset.Now.AddDays(7 + index), | ||
TimeZone = "KST", | ||
IsActive = index % 3 == 0, | ||
OrganizerName = $"Charlie_{index}", | ||
OrganizerEmail = $"user_{index}@gmail.com", | ||
CoorganizerName = $"Bravo_{index}", | ||
CoorganizerEmail = $"support_{index}@gmail.com", | ||
MaxTokenCap = (100 + index) * 100, | ||
DailyRequestCap = index * 10 | ||
}).AsQueryable(); | ||
|
||
pagination.TotalItemCountChanged += (sender, eventArgs) => StateHasChanged(); | ||
} | ||
|
||
private async Task GoToPageAsync(int pageIndex) | ||
{ | ||
await pagination.SetCurrentPageIndexAsync(pageIndex); | ||
} | ||
|
||
private Appearance PageButtonAppearance(int pageIndex) | ||
=> pagination.CurrentPageIndex == pageIndex ? Appearance.Accent : Appearance.Neutral; | ||
|
||
private string? AriaCurrentValue(int pageIndex) | ||
=> pagination.CurrentPageIndex == pageIndex ? "page" : null; | ||
} |
17 changes: 17 additions & 0 deletions
17
src/AzureOpenAIProxy.PlaygroundApp/Components/UI/Admin/AdminEventsComponent.razor.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
.fluent-datagrid-cell { | ||
display: flex; | ||
align-items: center; | ||
justify-content: center; | ||
height: 100%; | ||
} | ||
|
||
.page-button-box { | ||
display: flex; | ||
justify-content: center; | ||
align-items: center; | ||
margin-top: 20px; | ||
} | ||
|
||
.page-button { | ||
margin-left: 10px; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
60 changes: 60 additions & 0 deletions
60
src/AzureOpenAIProxy.PlaygroundApp/Models/AdminEventDetails.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
using System.Text.Json.Serialization; | ||
|
||
namespace AzureOpenAIProxy.PlaygroundApp.Models; | ||
|
||
/// <summary> | ||
/// This represent the event detail data for response by admin event endpoint. | ||
/// </summary> | ||
public class AdminEventDetails : EventDetails | ||
{ | ||
/// <summary> | ||
/// Gets or sets the event description. | ||
/// </summary> | ||
public string? Description { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the event start date. | ||
/// </summary> | ||
[JsonRequired] | ||
public DateTimeOffset DateStart { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the event end date. | ||
/// </summary> | ||
[JsonRequired] | ||
public DateTimeOffset DateEnd { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the event start to end date timezone. | ||
/// </summary> | ||
[JsonRequired] | ||
public string TimeZone { get; set; } = string.Empty; | ||
|
||
/// <summary> | ||
/// Gets or sets the event active status. | ||
/// </summary> | ||
[JsonRequired] | ||
public bool IsActive { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the event organizer name. | ||
/// </summary> | ||
[JsonRequired] | ||
public string OrganizerName { get; set; } = string.Empty; | ||
|
||
/// <summary> | ||
/// Gets or sets the event organizer email. | ||
/// </summary> | ||
[JsonRequired] | ||
public string OrganizerEmail { get; set; } = string.Empty; | ||
|
||
/// <summary> | ||
/// Gets or sets the event coorganizer name. | ||
/// </summary> | ||
public string? CoorganizerName { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the event coorganizer email. | ||
/// </summary> | ||
public string? CoorganizerEmail { get; set; } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
using System.Text.Json.Serialization; | ||
|
||
namespace AzureOpenAIProxy.PlaygroundApp.Models; | ||
|
||
/// <summary> | ||
/// This represents the event's detailed data for response by EventEndpoint. | ||
/// </summary> | ||
public class EventDetails | ||
{ | ||
/// <summary> | ||
/// Gets or sets the event id. | ||
/// </summary> | ||
[JsonRequired] | ||
public Guid EventId { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the event title name. | ||
/// </summary> | ||
[JsonRequired] | ||
public string Title { get; set; } = string.Empty; | ||
|
||
/// <summary> | ||
/// Gets or sets the event summary. | ||
/// </summary> | ||
[JsonRequired] | ||
public string Summary { get; set; } = string.Empty; | ||
|
||
/// <summary> | ||
/// Gets or sets the Azure OpenAI Service request max token capacity. | ||
/// </summary> | ||
[JsonRequired] | ||
public int MaxTokenCap { get; set; } | ||
|
||
/// <summary> | ||
/// Gets or sets the Azure OpenAI Service daily request capacity. | ||
/// </summary> | ||
[JsonRequired] | ||
public int DailyRequestCap { get; set; } | ||
} |
47 changes: 47 additions & 0 deletions
47
test/AzureOpenAIProxy.PlaygroundApp.Tests/Pages/AdminEventsPageTests.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
using FluentAssertions; | ||
|
||
using Microsoft.Playwright; | ||
using Microsoft.Playwright.NUnit; | ||
|
||
namespace AzureOpenAIProxy.PlaygroundApp.Tests.Pages; | ||
|
||
[Parallelizable(ParallelScope.Self)] | ||
[TestFixture] | ||
[Property("Category", "Integration")] | ||
public class AdminEventsPageTests : PageTest | ||
{ | ||
public override BrowserNewContextOptions ContextOptions() => new() | ||
{ | ||
IgnoreHTTPSErrors = true, | ||
}; | ||
|
||
[SetUp] | ||
public async Task Setup() | ||
{ | ||
await Page.GotoAsync("https://localhost:5001/admin/events"); | ||
await Page.WaitForLoadStateAsync(LoadState.NetworkIdle); | ||
} | ||
|
||
[Test] | ||
public async Task Given_Events_Page_When_Navigated_Then_It_Should_Have_ListEventDetailsComponent() | ||
{ | ||
// Act | ||
var adminEventsComponent = await Page.QuerySelectorAsync("#admin-events-component"); | ||
|
||
// Assert | ||
adminEventsComponent.Should().NotBeNull(); | ||
} | ||
|
||
[Test] | ||
public async Task Given_Events_Page_When_Navigated_Then_It_Should_Have_EventDetailsTable() | ||
{ | ||
// wait for construct table | ||
await Task.Delay(2000); | ||
|
||
// Act | ||
var adminEventsTable = await Page.QuerySelectorAsync("#admin-events-table"); | ||
|
||
// Assert | ||
adminEventsTable.Should().NotBeNull(); | ||
} | ||
} |