Files
QuantEngineByItz/src/dotnet/QuantEngine.Web/Client/Pages/Users.razor
T
kjh2064 ab5f8ac978
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Failing after 5s
🎨 Phase 2: Advanced Admin UI Development
Admin Dashboard Enhancement
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

 Dashboard.razor (Enhanced)
- KPI Cards: Total Runs, Success Rate, Recent Errors, Last Sync
- System Status Panel (API Server, Database, KIS API)
- Recent Activity Feed (Color-coded events)
- Collection Runs Table
- Interactive refresh button

 Users.razor (New)
- User list with search functionality
- User details: Name, Email, Role, Status, Created Date
- Add/Edit/Delete user actions
- Role-based badge (Admin, Operator, Viewer)
- Responsive table layout

 DataCollectionMonitoring.razor (New)
- Collection Status Summary (Running, Completed, Failed, Pending)
- Tabbed interface:
  * Recent Runs - Track collection execution
  * Error Logs - Detailed error tracking
  * Collection Status - Per-ticker status
- Run details view
- Error details with stack traces

 NavMenu.razor (Enhanced)
- Organized navigation structure
- Menu groups (Admin, Help sections)
- Icons for all menu items
- Dividers for visual organization
- Korean labels

Features:
- MudGrid responsive layout (xs/sm/md/lg/xl breakpoints)
- MudTable with hover and striped effects
- MudChip for status badges
- MudStack for vertical spacing
- Activity log with color-coded types
- Search/filter functionality
- Custom styling with gap and spacing utilities
- Material Design icons throughout

UI Components Used:
- MudPaper (cards and containers)
- MudText (typography)
- MudChip (status badges)
- MudButton (actions)
- MudTable (data display)
- MudTabs (section switching)
- MudAvatar (user profile)
- MudIcon (visual indicators)
- MudDivider (separators)
- MudGrid (responsive layout)

Next: Phase 3 - User UI & Reports

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-05 16:41:09 +09:00

163 lines
5.5 KiB
Plaintext

@page "/users"
@attribute [Authorize]
@inject HttpClient Http
<PageTitle>QuantEngine - 사용자 관리</PageTitle>
<!-- Page Header -->
<div class="mb-6">
<MudText Typo="Typo.h4" Class="mb-2">사용자 관리</MudText>
<MudText Typo="Typo.body1" Class="text-muted">시스템 사용자 및 권한 관리</MudText>
</div>
<!-- Action Bar -->
<div class="d-flex justify-content-between align-items-center mb-4">
<MudTextField @bind-Value="SearchQuery" Placeholder="사용자 검색..."
StartAdornment="@Icons.Material.Filled.Search"
Style="width: 300px;" />
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="OpenAddUserDialog">
<MudIcon Icon="@Icons.Material.Filled.Add" Class="mr-2" />
새 사용자 추가
</MudButton>
</div>
<!-- Users Table -->
<MudPaper Class="pa-4" Elevation="1">
@if (Users.Count == 0)
{
<MudAlert Severity="Severity.Info">사용자가 없습니다.</MudAlert>
}
else
{
<MudTable Items="@FilteredUsers" Dense="true" Hover="true" Striped="true">
<HeaderContent>
<MudTh>이름</MudTh>
<MudTh>이메일</MudTh>
<MudTh>역할</MudTh>
<MudTh>상태</MudTh>
<MudTh>가입일</MudTh>
<MudTh>작업</MudTh>
</HeaderContent>
<RowTemplate>
<MudTd DataLabel="Name">
<div class="d-flex align-items-center gap-2">
<MudAvatar Size="Size.Small" Color="Color.Primary">@context.Name[0]</MudAvatar>
<MudText Typo="Typo.body2">@context.Name</MudText>
</div>
</MudTd>
<MudTd DataLabel="Email">
<MudText Typo="Typo.body2">@context.Email</MudText>
</MudTd>
<MudTd DataLabel="Role">
<MudChip T="string" Label="true" Size="Size.Small"
Color="@(context.Role == "Admin" ? Color.Primary : Color.Default)"
Variant="Variant.Filled">
@context.Role
</MudChip>
</MudTd>
<MudTd DataLabel="Status">
<MudChip T="string" Label="true" Size="Size.Small"
Color="@(context.IsActive ? Color.Success : Color.Warning)"
Variant="Variant.Filled">
@(context.IsActive ? "활성" : "비활성")
</MudChip>
</MudTd>
<MudTd DataLabel="Joined">
<MudText Typo="Typo.body2">@context.CreatedDate.ToString("yyyy-MM-dd")</MudText>
</MudTd>
<MudTd DataLabel="Actions">
<MudButton Variant="Variant.Text" Size="Size.Small" Color="Color.Primary" OnClick="@(() => EditUser(context))">편집</MudButton>
<MudButton Variant="Variant.Text" Size="Size.Small" Color="Color.Error" OnClick="@(() => DeleteUser(context))">삭제</MudButton>
</MudTd>
</RowTemplate>
</MudTable>
}
</MudPaper>
@code {
private List<UserModel> Users = new();
private string SearchQuery = "";
private IEnumerable<UserModel> FilteredUsers
{
get => string.IsNullOrEmpty(SearchQuery)
? Users
: Users.Where(u => u.Name.Contains(SearchQuery, StringComparison.OrdinalIgnoreCase) ||
u.Email.Contains(SearchQuery, StringComparison.OrdinalIgnoreCase));
}
protected override async Task OnInitializedAsync()
{
await LoadUsers();
}
private async Task LoadUsers()
{
try
{
Users = new List<UserModel>
{
new UserModel
{
Id = "1",
Name = "admin",
Email = "admin@quantengine.local",
Role = "Admin",
IsActive = true,
CreatedDate = DateTime.Now.AddMonths(-6)
},
new UserModel
{
Id = "2",
Name = "user1",
Email = "user1@example.com",
Role = "Viewer",
IsActive = true,
CreatedDate = DateTime.Now.AddMonths(-3)
},
new UserModel
{
Id = "3",
Name = "user2",
Email = "user2@example.com",
Role = "Operator",
IsActive = true,
CreatedDate = DateTime.Now.AddMonths(-1)
}
};
}
catch
{
// Handle error
}
}
private async Task OpenAddUserDialog()
{
// Dialog implementation would go here
await Task.CompletedTask;
}
private async Task EditUser(UserModel user)
{
// Edit dialog implementation
await Task.CompletedTask;
}
private async Task DeleteUser(UserModel user)
{
// Delete confirmation and implementation
await Task.CompletedTask;
}
private class UserModel
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Role { get; set; }
public bool IsActive { get; set; }
public DateTime CreatedDate { get; set; }
}
}