Skip to content

Commit

Permalink
[Admin] Component: List event details - UI component #219 (#266)
Browse files Browse the repository at this point in the history
  • Loading branch information
praivesi authored Sep 6, 2024
1 parent c0aa264 commit 7a2c3b8
Show file tree
Hide file tree
Showing 9 changed files with 304 additions and 1 deletion.
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"/>
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";
}
}
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;
}
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;
}
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;
}
3 changes: 2 additions & 1 deletion src/AzureOpenAIProxy.PlaygroundApp/Components/_Imports.razor
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@

@using AzureOpenAIProxy.PlaygroundApp
@using AzureOpenAIProxy.PlaygroundApp.Components
@using AzureOpenAIProxy.PlaygroundApp.Components.UI
@using AzureOpenAIProxy.PlaygroundApp.Components.UI
@using AzureOpenAIProxy.PlaygroundApp.Components.UI.Admin
60 changes: 60 additions & 0 deletions src/AzureOpenAIProxy.PlaygroundApp/Models/AdminEventDetails.cs
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; }
}
39 changes: 39 additions & 0 deletions src/AzureOpenAIProxy.PlaygroundApp/Models/EventDetails.cs
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; }
}
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();
}
}

0 comments on commit 7a2c3b8

Please sign in to comment.