PlanTempusAdmin/Pages/Azure/Container.cshtml
Janus C. H. Knudsen 08f8150064 Refactors page styles into separate CSS files
Extracts inline styles from Razor pages into modular CSS files
Adds new CSS files for components and specific page styles
Improves code organization and maintainability by separating styling concerns

Updates layout to include new CSS files and optional style sections
2026-02-03 15:55:44 +01:00

175 lines
6.4 KiB
Text

@page
@model PlanTempusAdmin.Pages.Azure.ContainerModel
@{
ViewData["Title"] = $"Container: {Model.Name}";
}
@section Styles {
<link rel="stylesheet" href="~/css/pages/azure.css" asp-append-version="true" />
}
<div class="page-header">
<div class="breadcrumb">
<a href="/Azure">Azure Storage</a>
<span class="separator">/</span>
@if (string.IsNullOrEmpty(Model.Prefix))
{
<span>@Model.Name</span>
}
else
{
<a href="/Azure/Container?name=@Model.Name">@Model.Name</a>
var parts = Model.Prefix.Split('/').Where(p => !string.IsNullOrEmpty(p)).ToList();
var currentPath = "";
foreach (var part in parts)
{
currentPath += part + "/";
<span class="separator">/</span>
if (currentPath == Model.Prefix + "/")
{
<span>@part</span>
}
else
{
<a href="/Azure/Container?name=@Model.Name&prefix=@currentPath">@part</a>
}
}
}
</div>
<h1 class="page-title">@Model.Name</h1>
<p class="page-subtitle">@Model.Details.BlobCount filer · @FormatBytes(Model.Details.TotalSize)</p>
</div>
@if (!Model.IsConnected)
{
<div class="card">
<div class="card-body">
<p class="text-danger">Kan ikke forbinde til Azure Storage</p>
</div>
</div>
}
else
{
<!-- Directories -->
@if (Model.Details.Prefixes.Count > 0)
{
<div class="card">
<div class="card-header">Mapper</div>
<div class="folder-grid">
@foreach (var prefix in Model.Details.Prefixes)
{
var folderName = prefix.Split('/').Last(p => !string.IsNullOrEmpty(p));
<a href="/Azure/Container?name=@Model.Name&prefix=@(prefix)/" class="folder-item">
<span class="folder-icon">📁</span>
<span class="folder-name">@folderName</span>
</a>
}
</div>
</div>
}
<!-- Files -->
<div class="card mt-2">
<div class="card-header">
Filer
<span class="header-meta">@Model.Details.Blobs.Count filer</span>
</div>
@if (Model.Details.Blobs.Count == 0)
{
<div class="card-body">
<p class="text-muted">Ingen filer i denne mappe</p>
</div>
}
else
{
<table class="table">
<thead>
<tr>
<th>Navn</th>
<th>Størrelse</th>
<th>Type</th>
<th>Tier</th>
<th>Ændret</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var blob in Model.Details.Blobs)
{
<tr>
<td>
<span class="file-icon">@GetFileIcon(blob.Name)</span>
<code class="blob-name" title="@blob.Name">@blob.FileName</code>
</td>
<td>@FormatBytes(blob.Size)</td>
<td><span class="badge">@(blob.ContentType ?? "-")</span></td>
<td>
@if (!string.IsNullOrEmpty(blob.AccessTier))
{
<span class="badge badge-tier @GetTierClass(blob.AccessTier)">@blob.AccessTier</span>
}
</td>
<td>@FormatTimeAgo(blob.LastModified)</td>
<td class="actions">
<a href="/Azure/Container?name=@Model.Name&blob=@blob.Name&handler=Download"
class="btn btn-sm" title="Download">⬇️</a>
<form method="post" asp-page-handler="Delete" style="display:inline;">
<input type="hidden" name="container" value="@Model.Name" />
<input type="hidden" name="blob" value="@blob.Name" />
<button type="submit" class="btn btn-sm btn-danger"
onclick="return confirm('Slet @blob.FileName?')" title="Slet">🗑️</button>
</form>
</td>
</tr>
}
</tbody>
</table>
}
</div>
<div class="mt-2">
<a href="/Azure" class="btn">← Tilbage til oversigt</a>
</div>
}
@functions {
string FormatBytes(long bytes)
{
if (bytes == 0) return "0 B";
var sizes = new[] { "B", "KB", "MB", "GB", "TB" };
var i = (int)Math.Floor(Math.Log(bytes) / Math.Log(1024));
return $"{Math.Round(bytes / Math.Pow(1024, i), 1)} {sizes[i]}";
}
string FormatTimeAgo(DateTimeOffset? time)
{
if (!time.HasValue) return "-";
var diff = DateTimeOffset.Now - time.Value;
if (diff.TotalMinutes < 1) return "lige nu";
if (diff.TotalMinutes < 60) return $"{(int)diff.TotalMinutes}m siden";
if (diff.TotalHours < 24) return $"{(int)diff.TotalHours}t siden";
if (diff.TotalDays < 7) return $"{(int)diff.TotalDays}d siden";
return time.Value.ToString("dd/MM HH:mm");
}
string GetFileIcon(string name)
{
if (name.EndsWith(".tar.gz")) return "📦";
if (name.EndsWith(".gz") || name.EndsWith(".zip") || name.EndsWith(".7z")) return "📦";
if (name.EndsWith(".sql")) return "🐘";
if (name.EndsWith(".bak")) return "💾";
if (name.EndsWith(".log")) return "📜";
if (name.EndsWith(".json")) return "📋";
if (name.EndsWith(".xml")) return "📄";
return "📄";
}
string GetTierClass(string tier)
{
var t = tier.ToLower();
if (t == "hot") return "hot";
if (t == "cool") return "cool";
if (t == "archive") return "archive";
return "";
}
}