Files
2026-07-21 14:14:44 +07:00

259 lines
11 KiB
Plaintext

@page "/appsettings/json"
@using Indotalent.Infrastructure.Authentication.Firebase
@using Indotalent.Infrastructure.Authentication.Keycloak
@using Microsoft.AspNetCore.Authorization
@using Indotalent.Infrastructure.Authorization.Identity
@attribute [Authorize(Roles = ApplicationRoles.Admin)]
@using Indotalent.Infrastructure.Authentication.Identity
@using Indotalent.Infrastructure.Database
@using Indotalent.Infrastructure.BackgroundJob
@using Indotalent.Infrastructure.Email
@using Indotalent.Infrastructure.File
@using Indotalent.Infrastructure.Logging
@using Indotalent.Infrastructure.Authentication
@using MudBlazor
@using System.Reflection
@inject IdentityService IdentitySvc
@inject DatabaseService DbSvc
@inject BackgroundJobService JobSvc
@inject EmailService EmailSvc
@inject FileStorageService StorageSvc
@inject LoggingService LogSvc
@inject FirebaseService FirebaseSvc
@inject KeycloakService KeycloakSvc
<style>
.clean-white-tabs .mud-tabs-toolbar {
background-color: white !important;
border-bottom: 2px solid #DCEBFA;
border-radius: 0px !important;
}
.clean-white-tabs .mud-tab {
color: #94a3b8 !important;
text-transform: none;
font-weight: 500;
min-width: 140px;
border-radius: 0px !important;
}
.clean-white-tabs .mud-tab-active {
color: var(--mud-palette-primary) !important;
font-weight: 800;
}
.clean-white-tabs .mud-tabs-slider {
background-color: var(--mud-palette-primary) !important;
height: 3px !important;
bottom: 0;
}
.soltemp-info-card {
border: 1px solid #DCEBFA !important;
border-radius: 0px !important;
background-color: #ffffff;
margin-bottom: 24px;
}
.soltemp-info-header {
padding: 12px 16px !important;
background-color: #F0F7FF;
border-bottom: 1px solid #DCEBFA;
}
.soltemp-row-compact {
display: flex;
padding: 10px 16px;
align-items: center;
border-bottom: 1px solid #F0F7FF;
}
.soltemp-label-text {
width: 30%;
font-weight: 800;
color: #1a1a1a;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.soltemp-value-text {
width: 70%;
color: #4A5D75;
font-size: 0.85rem;
font-weight: 500;
font-family: 'Consolas', monospace;
word-break: break-all;
}
.status-chip {
font-weight: 900;
font-size: 10px;
border-radius: 0px !important;
}
</style>
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="mt-2 mb-8">
<div class="clean-white-tabs">
<MudTabs Elevation="0" TabPanelsClass="pt-4" Rounded="false" ApplyEffectsToContainer="true">
<MudTabPanel Text="Identity" Icon="@Icons.Material.Outlined.AdminPanelSettings">
@RenderIdentityProperties(IdentitySvc.GetConfiguration(), "Security & Identity")
</MudTabPanel>
<MudTabPanel Text="Database" Icon="@Icons.Material.Outlined.Storage">
@RenderObjectProperties(DbSvc.GetConfiguration(), "Database Engine")
</MudTabPanel>
<MudTabPanel Text="Jobs" Icon="@Icons.Material.Outlined.Schedule">
@RenderObjectProperties(JobSvc.GetConfiguration(), "Background Job Services")
</MudTabPanel>
<MudTabPanel Text="Email" Icon="@Icons.Material.Outlined.Email">
@RenderObjectProperties(EmailSvc.GetConfiguration(), "Email Providers")
</MudTabPanel>
<MudTabPanel Text="Storage" Icon="@Icons.Material.Outlined.CloudUpload">
@RenderObjectProperties(StorageSvc.GetConfiguration(), "File Storage Systems")
</MudTabPanel>
<MudTabPanel Text="Logging" Icon="@Icons.Material.Outlined.ListAlt">
@RenderObjectProperties(LogSvc.GetConfiguration(), "Diagnostic Logging")
</MudTabPanel>
</MudTabs>
</div>
</MudContainer>
@code {
private RenderFragment RenderIdentityProperties(IdentitySettingsModel settings, string sectionTitle)
{
return __builder =>
{
<MudPaper Elevation="0" Square="true" Class="pa-6 mb-6 d-flex align-center justify-space-between" Style="border: 1px solid #DCEBFA;">
<div>
<MudText Typo="Typo.h5" Style="font-weight: 900; color: #1a1a1a;">@sectionTitle</MudText>
<MudText Typo="Typo.body2" Style="color: #64748b;">Security Policy & Default Credentials</MudText>
</div>
<div class="d-flex align-center gap-2">
<MudIcon Icon="@Icons.Material.Filled.Home" Size="Size.Small" Color="Color.Default" />
<MudText Typo="Typo.caption" Style="color: #94a3b8;">/</MudText>
<MudText Typo="Typo.caption" Style="color: #94a3b8;">System</MudText>
<MudText Typo="Typo.caption" Style="color: #94a3b8;">/</MudText>
<MudText Typo="Typo.caption" Style="font-weight: 600; color: #1a1a1a;">@sectionTitle</MudText>
</div>
</MudPaper>
if (settings != null)
{
@RenderSectionCard("Password Policy", settings.Password)
@RenderSectionCard("Cookie Settings", settings.Cookies)
@RenderSectionCard("Default Admin", settings.DefaultAdmin)
@RenderSectionCard("SignIn Policy", settings.SignIn)
@RenderSectionCard("SSO Firebase", settings.SsoFirebase)
@RenderSectionCard("SSO Keycloak", settings.SsoKeycloak)
}
};
}
private RenderFragment RenderSectionCard(string title, object sectionValue)
{
return __builder =>
{
if (sectionValue == null) return;
<MudCard Elevation="0" Class="soltemp-info-card">
<div class="soltemp-info-header d-flex align-center justify-space-between">
<MudText Typo="Typo.body1" Style="font-weight: 900; color: #1a1a1a;">@title</MudText>
<MudChip T="string" Color="Color.Primary" Size="Size.Small" Variant="Variant.Filled" Class="status-chip">CONFIGURED</MudChip>
</div>
<MudCardContent Style="padding: 0;">
@{
var props = sectionValue.GetType().GetProperties();
int i = 0;
}
@foreach (var p in props)
{
var val = p.GetValue(sectionValue);
<div class="soltemp-row-compact" style="background-color: @(i++ % 2 == 0 ? "#ffffff" : "#F9FCFF");">
<div class="soltemp-label-text">@p.Name</div>
<div class="soltemp-value-text">
@(MaskIfSensitive(p.Name, val?.ToString()))
</div>
</div>
}
</MudCardContent>
</MudCard>
};
}
private RenderFragment RenderObjectProperties(object settingsObj, string sectionTitle)
{
return __builder =>
{
<MudPaper Elevation="0" Square="true" Class="pa-6 mb-6 d-flex align-center justify-space-between" Style="border: 1px solid #DCEBFA;">
<div>
<MudText Typo="Typo.h5" Style="font-weight: 900; color: #1a1a1a;">@sectionTitle</MudText>
<MudText Typo="Typo.body2" Style="color: #64748b;">Configuration discovery (Full Inspection Mode)</MudText>
</div>
<div class="d-flex align-center gap-2">
<MudIcon Icon="@Icons.Material.Filled.Home" Size="Size.Small" Color="Color.Default" />
<MudText Typo="Typo.caption" Style="color: #94a3b8;">/</MudText>
<MudText Typo="Typo.caption" Style="color: #94a3b8;">System</MudText>
<MudText Typo="Typo.caption" Style="color: #94a3b8;">/</MudText>
<MudText Typo="Typo.caption" Style="font-weight: 600; color: #1a1a1a;">@sectionTitle</MudText>
</div>
</MudPaper>
if (settingsObj != null)
{
var providers = settingsObj.GetType().GetProperties();
foreach (var provider in providers)
{
var providerValue = provider.GetValue(settingsObj);
if (providerValue == null) continue;
<MudCard Elevation="0" Class="soltemp-info-card">
<div class="soltemp-info-header d-flex align-center justify-space-between">
<MudText Typo="Typo.body1" Style="font-weight: 900; color: #1a1a1a;">@provider.Name</MudText>
@{
var isUsedProp = providerValue.GetType().GetProperty("IsUsed");
bool isUsed = (bool)(isUsedProp?.GetValue(providerValue) ?? false);
}
<MudChip T="string" Color="@(isUsed? Color.Success: Color.Default)" Size="Size.Small" Variant="Variant.Filled" Class="status-chip">
@(isUsed ? "ACTIVE" : "DISABLED")
</MudChip>
</div>
<MudCardContent Style="padding: 0;">
@{
var props = providerValue.GetType().GetProperties();
int i = 0;
}
@foreach (var p in props)
{
if (p.Name == "IsUsed") continue;
<div class="soltemp-row-compact" style="background-color: @(i++ % 2 == 0 ? "#ffffff" : "#F9FCFF");">
<div class="soltemp-label-text">@p.Name</div>
<div class="soltemp-value-text">
@(MaskIfSensitive(p.Name, p.GetValue(providerValue)?.ToString()))
</div>
</div>
}
</MudCardContent>
</MudCard>
}
}
};
}
private string MaskIfSensitive(string propertyName, string value)
{
if (string.IsNullOrEmpty(value)) return "-";
var sensitiveKeys = new[] { "Password", "Secret", "Key", "Token", "ApiKey" };
if (sensitiveKeys.Any(k => propertyName.Contains(k, StringComparison.OrdinalIgnoreCase)))
{
return "•••••••••••••••• (Encrypted)";
}
return value;
}
}