feat(dotnet): migrate core formulas, deploy tools, and blazor admin web app to .NET 10
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (push) Has been cancelled
Quant Engine CI/CD Pipeline / validate-core (pull_request) Has been cancelled
Quant Engine CI/CD Pipeline / validate-ui-and-storage (pull_request) Has been cancelled
WBS-9.3 - NULL Policy CI Gate / NULL Policy Validation (pull_request) Has been cancelled

This commit is contained in:
2026-06-25 15:52:10 +09:00
parent 9abb8d3bc3
commit 2ba8def9bb
232 changed files with 10825 additions and 65 deletions
@@ -0,0 +1,19 @@
@page "/counter"
@rendermode InteractiveServer
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
@@ -0,0 +1,227 @@
@page "/"
@using QuantEngine.Core.Models
@using QuantEngine.Core.Interfaces
@inject IWorkspaceRepository WorkspaceRepo
@inject NavigationManager NavManager
<PageTitle>Quant Engine - Administration Dashboard</PageTitle>
<div class="dashboard-container">
<!-- Header -->
<header class="db-header">
<div class="logo-area">
<span class="icon">📈</span>
<h1>Quant Engine</h1>
<span class="badge">Active Workspace</span>
</div>
<div class="system-status">
<span class="status-dot green"></span>
<span>PostgreSQL: Connected</span>
</div>
</header>
<!-- Main Content Grid -->
<div class="db-grid">
<!-- Sidebar Summary Cards -->
<aside class="summary-panel">
<!-- Locks Card -->
<div class="card status-card">
<h3>🔒 Active Locks</h3>
@if (locks.Any())
{
<ul class="status-list">
@foreach (var l in locks)
{
<li>
<strong>@l.Domain</strong> / <span>@l.TargetRef</span>
<span class="meta">by @l.LockedBy - @l.Reason (@l.LockedAt)</span>
</li>
}
</ul>
}
else
{
<p class="empty-state">No active locks in workspace.</p>
}
</div>
<!-- Approvals Card -->
<div class="card status-card">
<h3>✅ Approvals v2</h3>
@if (approvals.Any())
{
<ul class="status-list">
@foreach (var a in approvals)
{
<li class="approval-item">
<div class="approval-meta">
<strong>@a.Domain</strong> <span class="badge @(a.Status.ToLower())">@a.Status</span>
</div>
<span class="meta">by @a.ApprovedBy @@ @a.ApprovedAt</span>
</li>
}
</ul>
}
else
{
<p class="empty-state">No approvals pending.</p>
}
</div>
</aside>
<!-- Main Settings / Configuration Grid -->
<main class="main-panel">
<div class="card table-card">
<div class="table-header">
<h2>⚙️ System Config (Settings)</h2>
<button class="btn btn-primary" @onclick="ShowAddSettingModal">Add Configuration</button>
</div>
<div class="table-container">
<table>
<thead>
<tr>
<th>Ordinal</th>
<th>Key</th>
<th>Value (JSON)</th>
<th>Note</th>
<th>Updated At</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@if (settings != null && settings.Any())
{
@foreach (var s in settings)
{
<tr>
<td>@s.Ordinal</td>
<td class="font-mono"><strong>@s.Key</strong></td>
<td class="font-mono value-cell">@s.ValueJson</td>
<td>@s.Note</td>
<td class="meta">@s.UpdatedAt</td>
<td>
<div class="action-buttons">
<button class="btn btn-sm btn-secondary" @onclick="() => EditSetting(s)">Edit</button>
<button class="btn btn-sm btn-danger" @onclick="() => DeleteSetting(s.Key)">Delete</button>
</div>
</td>
</tr>
}
}
else
{
<tr>
<td colspan="6" class="empty-row">No configuration settings found.</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</main>
</div>
<!-- Add/Edit Modal -->
@if (showModal)
{
<div class="modal-backdrop" @onclick="CloseModal">
<div class="modal-content" @onclick:stopPropagation="true">
<div class="modal-header">
<h3>@(isEditMode ? "Edit Setting" : "Add Setting")</h3>
<button class="close-btn" @onclick="CloseModal">&times;</button>
</div>
<div class="modal-body">
<div class="form-group">
<label>Key</label>
<input type="text" class="form-control" @bind="modalSetting.Key" disabled="@isEditMode" />
</div>
<div class="form-group">
<label>Value (JSON)</label>
<textarea class="form-control font-mono" rows="4" @bind="modalSetting.ValueJson"></textarea>
</div>
<div class="form-group">
<label>Note</label>
<input type="text" class="form-control" @bind="modalSetting.Note" />
</div>
<div class="form-group">
<label>Ordinal</label>
<input type="number" class="form-control" @bind="modalSetting.Ordinal" />
</div>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" @onclick="CloseModal">Cancel</button>
<button class="btn btn-primary" @onclick="SaveSetting">Save Changes</button>
</div>
</div>
</div>
}
</div>
@code {
private List<Setting> settings = new();
private List<WorkspaceLock> locks = new();
private List<WorkspaceApproval> approvals = new();
private bool showModal = false;
private bool isEditMode = false;
private Setting modalSetting = new();
protected override async Task OnInitializedAsync()
{
await LoadData();
}
private async Task LoadData()
{
settings = (await WorkspaceRepo.GetSettingsAsync()).ToList();
locks = (await WorkspaceRepo.GetLocksAsync()).ToList();
approvals = (await WorkspaceRepo.GetApprovalsAsync()).ToList();
}
private void ShowAddSettingModal()
{
isEditMode = false;
modalSetting = new Setting
{
Ordinal = settings.Count + 1,
UpdatedAt = DateTime.UtcNow.AddHours(9).ToString("o")
};
showModal = true;
}
private void EditSetting(Setting s)
{
isEditMode = true;
modalSetting = new Setting
{
Ordinal = s.Ordinal,
Key = s.Key,
ValueJson = s.ValueJson,
Note = s.Note,
UpdatedAt = DateTime.UtcNow.AddHours(9).ToString("o")
};
showModal = true;
}
private async Task SaveSetting()
{
if (string.IsNullOrWhiteSpace(modalSetting.Key)) return;
modalSetting.UpdatedAt = DateTime.UtcNow.AddHours(9).ToString("o");
await WorkspaceRepo.UpsertSettingAsync(modalSetting);
showModal = false;
await LoadData();
}
private async Task DeleteSetting(string key)
{
await WorkspaceRepo.DeleteSettingAsync(key);
await LoadData();
}
private void CloseModal()
{
showModal = false;
}
}
@@ -0,0 +1,36 @@
@page "/Error"
@using System.Diagnostics
<PageTitle>Error</PageTitle>
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
@if (ShowRequestId)
{
<p>
<strong>Request ID:</strong> <code>@RequestId</code>
</p>
}
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
@code{
[CascadingParameter]
private HttpContext? HttpContext { get; set; }
private string? RequestId { get; set; }
private bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
protected override void OnInitialized() =>
RequestId = Activity.Current?.Id ?? HttpContext?.TraceIdentifier;
}
@@ -0,0 +1,7 @@
@page "/"
<PageTitle>Home</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
@@ -0,0 +1,5 @@
@page "/not-found"
@layout MainLayout
<h3>Not Found</h3>
<p>Sorry, the content you are looking for does not exist.</p>
@@ -0,0 +1,64 @@
@page "/weather"
@attribute [StreamRendering]
<PageTitle>Weather</PageTitle>
<h1>Weather</h1>
<p>This component demonstrates showing data.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th aria-label="Temperature in Celsius">Temp. (C)</th>
<th aria-label="Temperature in Fahrenheit">Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[]? forecasts;
protected override async Task OnInitializedAsync()
{
// Simulate asynchronous loading to demonstrate streaming rendering
await Task.Delay(500);
var startDate = DateOnly.FromDateTime(DateTime.Now);
var summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" };
forecasts = Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = summaries[Random.Shared.Next(summaries.Length)]
}).ToArray();
}
private class WeatherForecast
{
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public string? Summary { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
}