188 lines
11 KiB
Plaintext
188 lines
11 KiB
Plaintext
@model Watcher.ViewModels.ContainerOverviewViewModel
|
|
@{
|
|
ViewData["Title"] = "Containerübersicht";
|
|
}
|
|
|
|
<head>
|
|
<link rel="stylesheet" href="~/css/main.css" />
|
|
<link rel="stylesheet" href="~/css/services-overview.css" />
|
|
</head>
|
|
|
|
<div class="container-fluid mt-4">
|
|
<div class="d-flex justify-content-between align-items-center mb-4">
|
|
<h4><i class="bi bi-box-seam me-2"></i>Container & Services</h4>
|
|
<span class="badge bg-primary">@Model.Containers.Count Container</span>
|
|
</div>
|
|
|
|
@if (!Model.Containers.Any())
|
|
{
|
|
<div class="alert alert-info">
|
|
<i class="bi bi-info-circle me-2"></i>Keine Container gefunden. Container werden automatisch von den Agents erkannt.
|
|
</div>
|
|
}
|
|
else
|
|
{
|
|
var groupedContainers = Model.Containers.GroupBy(c => c.Server?.Name ?? "Unbekannt");
|
|
|
|
foreach (var serverGroup in groupedContainers.OrderBy(g => g.Key))
|
|
{
|
|
<div class="mb-4">
|
|
<h5 class="text-text mb-3">
|
|
<i class="bi bi-hdd-network me-2"></i>@serverGroup.Key
|
|
<span class="badge bg-secondary ms-2">@serverGroup.Count()</span>
|
|
</h5>
|
|
|
|
<div class="row g-3">
|
|
@foreach (var container in serverGroup)
|
|
{
|
|
<div class="col-12 col-lg-6 col-xl-4">
|
|
<div class="card container-card shadow-sm">
|
|
<div class="card-header d-flex justify-content-between align-items-center">
|
|
<div class="d-flex align-items-center">
|
|
<i class="bi bi-box me-2 text-primary"></i>
|
|
<strong>@container.Name</strong>
|
|
</div>
|
|
<span class="badge @(container.IsRunning ? "bg-success" : "bg-danger")">
|
|
<i class="bi @(container.IsRunning ? "bi-play-fill" : "bi-stop-fill")"></i>
|
|
@(container.IsRunning ? "Running" : "Stopped")
|
|
</span>
|
|
</div>
|
|
<div class="card-body">
|
|
<div class="container-info">
|
|
<div class="info-row">
|
|
<span class="info-label"><i class="bi bi-tag me-1"></i>ID:</span>
|
|
<span class="info-value">@(container.ContainerId != null && container.ContainerId.Length > 12 ? container.ContainerId.Substring(0, 12) : container.ContainerId)</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="info-label"><i class="bi bi-image me-1"></i>Image:</span>
|
|
<span class="info-value">@container.Image</span>
|
|
</div>
|
|
<div class="info-row">
|
|
<span class="info-label"><i class="bi bi-server me-1"></i>Host:</span>
|
|
<span class="info-value">
|
|
<a href="/Server/Details/@container.ServerId" class="text-decoration-none">
|
|
@container.Server?.Name
|
|
</a>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Action Buttons -->
|
|
<div class="action-buttons mt-3 d-flex gap-2">
|
|
<button class="btn btn-sm btn-outline-warning flex-fill" onclick="restartContainer('@container.ContainerId')">
|
|
<i class="bi bi-arrow-clockwise"></i> Restart
|
|
</button>
|
|
<button class="btn btn-sm btn-outline-danger flex-fill" onclick="stopContainer('@container.ContainerId')">
|
|
<i class="bi bi-stop-circle"></i> Stop
|
|
</button>
|
|
<button class="btn btn-sm btn-outline-info flex-fill" onclick="updateContainer('@container.ContainerId')">
|
|
<i class="bi bi-arrow-up-circle"></i> Update
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Expandable Metrics Section -->
|
|
<div class="mt-3">
|
|
<button class="btn btn-sm btn-outline-secondary w-100 toggle-metrics"
|
|
data-container-id="@container.Id"
|
|
onclick="toggleMetrics(this, @container.Id)">
|
|
<i class="bi bi-graph-up me-1"></i>
|
|
Metriken anzeigen
|
|
<i class="bi bi-chevron-down float-end"></i>
|
|
</button>
|
|
<div class="metrics-panel collapse" id="metrics-@container.Id">
|
|
<div class="metrics-content mt-3 p-3 rounded">
|
|
<div class="metric-item">
|
|
<div class="d-flex justify-content-between mb-1">
|
|
<small><i class="bi bi-cpu me-1"></i>CPU</small>
|
|
<small class="text-muted"><span class="metric-value">--</span>%</small>
|
|
</div>
|
|
<div class="progress" style="height: 8px;">
|
|
<div class="progress-bar bg-info" role="progressbar" style="width: 0%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="metric-item mt-3">
|
|
<div class="d-flex justify-content-between mb-1">
|
|
<small><i class="bi bi-memory me-1"></i>RAM</small>
|
|
<small class="text-muted"><span class="metric-value">--</span> MB</small>
|
|
</div>
|
|
<div class="progress" style="height: 8px;">
|
|
<div class="progress-bar bg-success" role="progressbar" style="width: 0%"></div>
|
|
</div>
|
|
</div>
|
|
<div class="metric-item mt-3">
|
|
<div class="d-flex justify-content-between mb-1">
|
|
<small><i class="bi bi-ethernet me-1"></i>Network</small>
|
|
<small class="text-muted">
|
|
<i class="bi bi-arrow-down text-success"></i> <span class="metric-value">--</span> MB/s
|
|
<i class="bi bi-arrow-up text-primary ms-2"></i> <span class="metric-value">--</span> MB/s
|
|
</small>
|
|
</div>
|
|
</div>
|
|
<div class="text-center mt-3">
|
|
<small class="text-muted">
|
|
<i class="bi bi-info-circle me-1"></i>
|
|
Metriken werden in Echtzeit aktualisiert
|
|
</small>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
}
|
|
</div>
|
|
|
|
@section Scripts {
|
|
<script>
|
|
function toggleMetrics(button, containerId) {
|
|
const panel = document.getElementById('metrics-' + containerId);
|
|
const icon = button.querySelector('.float-end');
|
|
|
|
if (panel.classList.contains('show')) {
|
|
panel.classList.remove('show');
|
|
button.innerHTML = '<i class="bi bi-graph-up me-1"></i>Metriken anzeigen<i class="bi bi-chevron-down float-end"></i>';
|
|
} else {
|
|
panel.classList.add('show');
|
|
button.innerHTML = '<i class="bi bi-graph-up me-1"></i>Metriken verbergen<i class="bi bi-chevron-up float-end"></i>';
|
|
// Hier könnten echte Metriken geladen werden
|
|
loadContainerMetrics(containerId);
|
|
}
|
|
}
|
|
|
|
function loadContainerMetrics(containerId) {
|
|
// Placeholder für zukünftige API-Calls
|
|
console.log('Loading metrics for container:', containerId);
|
|
// TODO: Echte Metriken vom Backend laden
|
|
}
|
|
|
|
function restartContainer(containerId) {
|
|
if (confirm('Container wirklich neu starten?')) {
|
|
console.log('Restarting container:', containerId);
|
|
// TODO: API Call zum Neustarten
|
|
alert('Restart-Funktion wird implementiert');
|
|
}
|
|
}
|
|
|
|
function stopContainer(containerId) {
|
|
if (confirm('Container wirklich stoppen?')) {
|
|
console.log('Stopping container:', containerId);
|
|
// TODO: API Call zum Stoppen
|
|
alert('Stop-Funktion wird implementiert');
|
|
}
|
|
}
|
|
|
|
function updateContainer(containerId) {
|
|
if (confirm('Container-Image aktualisieren?')) {
|
|
console.log('Updating container:', containerId);
|
|
// TODO: API Call zum Updaten
|
|
alert('Update-Funktion wird implementiert');
|
|
}
|
|
}
|
|
</script>
|
|
}
|