Server und Container Overview+Add Seite erstellt und an Datenbank angeschlossen
This commit is contained in:
60
Watcher/Controllers/ContainerController.cs
Normal file
60
Watcher/Controllers/ContainerController.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Watcher.Data;
|
||||
using Watcher.Models;
|
||||
using Watcher.ViewModels;
|
||||
|
||||
namespace Watcher.Controllers;
|
||||
|
||||
|
||||
public class ContainerController : Controller
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public ContainerController(AppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Overview()
|
||||
{
|
||||
var containers = await _context.Containers.ToListAsync();
|
||||
|
||||
var viewModel = new ContainerOverviewViewModel
|
||||
{
|
||||
Containers = containers
|
||||
};
|
||||
|
||||
return View(viewModel);
|
||||
}
|
||||
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult AddContainer()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> AddContainer(AddContainerViewModel vm)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return View(vm);
|
||||
|
||||
var container = new Container
|
||||
{
|
||||
Name = vm.Name,
|
||||
Image = vm.Image,
|
||||
Status = vm.Status,
|
||||
Hostname = vm.Hostname,
|
||||
IsRunning = vm.IsRunning,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
_context.Containers.Add(container);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return RedirectToAction("Index");
|
||||
}
|
||||
}
|
56
Watcher/Controllers/ServerController.cs
Normal file
56
Watcher/Controllers/ServerController.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Watcher.Data;
|
||||
using Watcher.Models;
|
||||
using Watcher.ViewModels;
|
||||
|
||||
[Authorize]
|
||||
public class ServerController : Controller
|
||||
{
|
||||
private readonly AppDbContext _context;
|
||||
|
||||
public ServerController(AppDbContext context)
|
||||
{
|
||||
_context = context;
|
||||
}
|
||||
|
||||
public async Task<IActionResult> Overview()
|
||||
{
|
||||
var vm = new ServerOverviewViewModel
|
||||
{
|
||||
Servers = await _context.Servers.OrderBy(s => s.Id).ToListAsync()
|
||||
};
|
||||
|
||||
return View(vm);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult AddServer()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public async Task<IActionResult> AddServer(AddServerViewModel vm)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
return View(vm);
|
||||
|
||||
var server = new Server
|
||||
{
|
||||
Name = vm.Name,
|
||||
IPAddress = vm.IPAddress,
|
||||
Hostname = vm.Hostname,
|
||||
Status = vm.Status,
|
||||
Type = vm.Type,
|
||||
IsOnline = vm.IsOnline,
|
||||
CreatedAt = DateTime.UtcNow
|
||||
};
|
||||
|
||||
_context.Servers.Add(server);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
return RedirectToAction("Overview");
|
||||
}
|
||||
}
|
290
Watcher/Migrations/20250614224113_Container-Server-Update.Designer.cs
generated
Normal file
290
Watcher/Migrations/20250614224113_Container-Server-Update.Designer.cs
generated
Normal file
@@ -0,0 +1,290 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Watcher.Data;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Watcher.Migrations
|
||||
{
|
||||
[DbContext(typeof(AppDbContext))]
|
||||
[Migration("20250614224113_Container-Server-Update")]
|
||||
partial class ContainerServerUpdate
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.HasAnnotation("ProductVersion", "8.0.6")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 64);
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Container", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Hostname")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int?>("ImageId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<bool>("IsRunning")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int?>("TagId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ImageId");
|
||||
|
||||
b.HasIndex("TagId");
|
||||
|
||||
b.ToTable("Containers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Image", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Tag")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Images");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.LogEvent", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("ContainerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Level")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Message")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int?>("ServerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("Timestamp")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ContainerId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("LogEvents");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Metric", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("ContainerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<int?>("ServerId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("Timestamp")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<double>("Value")
|
||||
.HasColumnType("double");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ContainerId");
|
||||
|
||||
b.HasIndex("ServerId");
|
||||
|
||||
b.ToTable("Metrics");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Server", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("Hostname")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("IPAddress")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("IsOnline")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("Status")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<int?>("TagId")
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Type")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("TagId");
|
||||
|
||||
b.ToTable("Servers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Tag", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Tags");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("int");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<DateTime>("LastLogin")
|
||||
.HasColumnType("datetime(6)");
|
||||
|
||||
b.Property<string>("PocketId")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("PreferredUsername")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Container", b =>
|
||||
{
|
||||
b.HasOne("Watcher.Models.Image", "Image")
|
||||
.WithMany("Containers")
|
||||
.HasForeignKey("ImageId");
|
||||
|
||||
b.HasOne("Watcher.Models.Tag", null)
|
||||
.WithMany("Containers")
|
||||
.HasForeignKey("TagId");
|
||||
|
||||
b.Navigation("Image");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.LogEvent", b =>
|
||||
{
|
||||
b.HasOne("Watcher.Models.Container", "Container")
|
||||
.WithMany()
|
||||
.HasForeignKey("ContainerId");
|
||||
|
||||
b.HasOne("Watcher.Models.Server", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServerId");
|
||||
|
||||
b.Navigation("Container");
|
||||
|
||||
b.Navigation("Server");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Metric", b =>
|
||||
{
|
||||
b.HasOne("Watcher.Models.Container", "Container")
|
||||
.WithMany()
|
||||
.HasForeignKey("ContainerId");
|
||||
|
||||
b.HasOne("Watcher.Models.Server", "Server")
|
||||
.WithMany()
|
||||
.HasForeignKey("ServerId");
|
||||
|
||||
b.Navigation("Container");
|
||||
|
||||
b.Navigation("Server");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Server", b =>
|
||||
{
|
||||
b.HasOne("Watcher.Models.Tag", null)
|
||||
.WithMany("Servers")
|
||||
.HasForeignKey("TagId");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Image", b =>
|
||||
{
|
||||
b.Navigation("Containers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Tag", b =>
|
||||
{
|
||||
b.Navigation("Containers");
|
||||
|
||||
b.Navigation("Servers");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
29
Watcher/Migrations/20250614224113_Container-Server-Update.cs
Normal file
29
Watcher/Migrations/20250614224113_Container-Server-Update.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Watcher.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class ContainerServerUpdate : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "IPAddress",
|
||||
table: "Servers",
|
||||
type: "longtext",
|
||||
nullable: false)
|
||||
.Annotation("MySql:CharSet", "utf8mb4");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropColumn(
|
||||
name: "IPAddress",
|
||||
table: "Servers");
|
||||
}
|
||||
}
|
||||
}
|
@@ -152,6 +152,10 @@ namespace Watcher.Migrations
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<string>("IPAddress")
|
||||
.IsRequired()
|
||||
.HasColumnType("longtext");
|
||||
|
||||
b.Property<bool>("IsOnline")
|
||||
.HasColumnType("tinyint(1)");
|
||||
|
||||
@@ -218,13 +222,15 @@ namespace Watcher.Migrations
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.Container", b =>
|
||||
{
|
||||
b.HasOne("Watcher.Models.Image", null)
|
||||
b.HasOne("Watcher.Models.Image", "Image")
|
||||
.WithMany("Containers")
|
||||
.HasForeignKey("ImageId");
|
||||
|
||||
b.HasOne("Watcher.Models.Tag", null)
|
||||
.WithMany("Containers")
|
||||
.HasForeignKey("TagId");
|
||||
|
||||
b.Navigation("Image");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Watcher.Models.LogEvent", b =>
|
||||
|
@@ -8,6 +8,8 @@ public class Container
|
||||
|
||||
public string Status { get; set; } = string.Empty;
|
||||
|
||||
public Image? Image { get; set; }
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
public string Hostname { get; set; } = string.Empty;
|
||||
|
@@ -6,6 +6,8 @@ public class Server
|
||||
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
public string IPAddress { get; set; } = string.Empty;
|
||||
|
||||
public string Status { get; set; } = string.Empty;
|
||||
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
13
Watcher/ViewModels/AddContainerViewModel.cs
Normal file
13
Watcher/ViewModels/AddContainerViewModel.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Watcher.Models;
|
||||
|
||||
namespace Watcher.ViewModels;
|
||||
public class AddContainerViewModel
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public Image? Image { get; set; }
|
||||
public string Status { get; set; } = string.Empty;
|
||||
public string Hostname { get; set; } = string.Empty;
|
||||
public string IPAddress { get; set; } = string.Empty;
|
||||
public string ServerName { get; set; } = string.Empty; // oder ID, je nach Relation
|
||||
public bool IsRunning { get; set; } = false;
|
||||
}
|
12
Watcher/ViewModels/AddServerViewModel.cs
Normal file
12
Watcher/ViewModels/AddServerViewModel.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
namespace Watcher.ViewModels;
|
||||
|
||||
public class AddServerViewModel
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string IPAddress { get; set; } = string.Empty;
|
||||
public string Status { get; set; } = string.Empty;
|
||||
public string Hostname { get; set; } = string.Empty;
|
||||
public string Type { get; set; } = "VPS";
|
||||
public bool IsOnline { get; set; } = false;
|
||||
}
|
10
Watcher/ViewModels/ContainerOverviewViewModel.cs
Normal file
10
Watcher/ViewModels/ContainerOverviewViewModel.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Watcher.Models;
|
||||
|
||||
namespace Watcher.ViewModels
|
||||
{
|
||||
public class ContainerOverviewViewModel
|
||||
{
|
||||
public List<Container> Containers { get; set; } = new();
|
||||
}
|
||||
}
|
||||
|
10
Watcher/ViewModels/ServerOverviewViewModel.cs
Normal file
10
Watcher/ViewModels/ServerOverviewViewModel.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Watcher.Models;
|
||||
|
||||
namespace Watcher.ViewModels
|
||||
|
||||
{
|
||||
public class ServerOverviewViewModel
|
||||
{
|
||||
public List<Server> Servers { get; set; } = new();
|
||||
}
|
||||
}
|
22
Watcher/Views/Container/AddContainer.cshtml
Normal file
22
Watcher/Views/Container/AddContainer.cshtml
Normal file
@@ -0,0 +1,22 @@
|
||||
@model Watcher.ViewModels.AddContainerViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Neuen Container hinzufügen";
|
||||
}
|
||||
|
||||
<h1 class="text-2xl font-bold mb-4">Neuen Container hinzufügen</h1>
|
||||
|
||||
<form asp-action="Add" method="post" class="space-y-4 max-w-xl">
|
||||
<div>
|
||||
<label asp-for="Name" class="block font-medium">Name</label>
|
||||
<input asp-for="Name" class="w-full border rounded px-3 py-2" />
|
||||
</div>
|
||||
<div>
|
||||
<label asp-for="Image" class="block font-medium">Image</label>
|
||||
<input asp-for="Image" class="w-full border rounded px-3 py-2" />
|
||||
</div>
|
||||
<div>
|
||||
<label asp-for="ServerName" class="block font-medium">Server</label>
|
||||
<input asp-for="ServerName" class="w-full border rounded px-3 py-2" />
|
||||
</div>
|
||||
<button type="submit" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">Speichern</button>
|
||||
</form>
|
36
Watcher/Views/Container/Overview.cshtml
Normal file
36
Watcher/Views/Container/Overview.cshtml
Normal file
@@ -0,0 +1,36 @@
|
||||
@model Watcher.ViewModels.ContainerOverviewViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Containerübersicht";
|
||||
}
|
||||
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-3xl font-bold">Containerübersicht</h1>
|
||||
<a asp-action="AddContainer" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
|
||||
+ Container hinzufügen
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
@foreach (var container in Model.Containers)
|
||||
{
|
||||
<div class="bg-white shadow-md rounded-xl p-5 border border-gray-200 hover:shadow-lg transition duration-200">
|
||||
<h2 class="text-xl font-semibold mb-1">@container.Name</h2>
|
||||
<p class="text-sm text-gray-600 mb-2"><strong>Image:</strong> @container.Image</p>
|
||||
<p class="text-sm text-gray-600"><strong>Hostname:</strong> @container.Hostname</p>
|
||||
<p class="text-sm text-gray-600"><strong>Status:</strong> @container.Status</p>
|
||||
<p class="text-sm text-gray-600 mb-3">
|
||||
<strong>Läuft:</strong>
|
||||
<span class="@(container.IsRunning ? "text-green-600" : "text-red-600")">
|
||||
@(container.IsRunning ? "Ja" : "Nein")
|
||||
</span>
|
||||
</p>
|
||||
<div class="flex justify-end gap-2">
|
||||
<a asp-action="Edit" asp-route-id="@container.Id"
|
||||
class="text-blue-600 hover:underline text-sm">Bearbeiten</a>
|
||||
<a asp-action="Delete" asp-route-id="@container.Id"
|
||||
class="text-red-600 hover:underline text-sm">Löschen</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
@@ -10,14 +10,14 @@
|
||||
<h2 class="text-xl font-semibold mb-2">Server</h2>
|
||||
<p>🟢 Online: <strong>@Model.ActiveServers</strong></p>
|
||||
<p>🔴 Offline: <strong>@Model.OfflineServers</strong></p>
|
||||
<a href="/Servers" class="text-blue-500 hover:underline mt-2 inline-block">→ Zu den Servern</a>
|
||||
<a href="/Server/Overview" class="text-blue-500 hover:underline mt-2 inline-block">→ Zu den Servern</a>
|
||||
</div>
|
||||
|
||||
<div class="bg-white shadow rounded-2xl p-4">
|
||||
<h2 class="text-xl font-semibold mb-2">Container</h2>
|
||||
<p>🟢 Laufend: <strong>@Model.RunningContainers</strong></p>
|
||||
<p>🔴 Fehlerhaft: <strong>@Model.FailedContainers</strong></p>
|
||||
<a href="/Containers" class="text-blue-500 hover:underline mt-2 inline-block">→ Zu den Containern</a>
|
||||
<a href="/Container/Overview" class="text-blue-500 hover:underline mt-2 inline-block">→ Zu den Containern</a>
|
||||
</div>
|
||||
|
||||
<div class="col-span-2 bg-white shadow rounded-2xl p-4">
|
||||
|
42
Watcher/Views/Server/AddServer.cshtml
Normal file
42
Watcher/Views/Server/AddServer.cshtml
Normal file
@@ -0,0 +1,42 @@
|
||||
@using Watcher.ViewModels
|
||||
|
||||
@model AddServerViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Neuen Server hinzufügen";
|
||||
}
|
||||
|
||||
<h1 class="text-2xl font-bold mb-4">Neuen Server hinzufügen</h1>
|
||||
|
||||
<form asp-action="Add" method="post" class="space-y-4 max-w-xl">
|
||||
<div>
|
||||
<label asp-for="Name" class="block font-medium">Name</label>
|
||||
<input asp-for="Name" class="w-full border rounded px-3 py-2" />
|
||||
<span asp-validation-for="Name" class="text-red-600 text-sm"></span>
|
||||
</div>
|
||||
<div>
|
||||
<label asp-for="Hostname" class="block font-medium">Hostname</label>
|
||||
<input asp-for="Hostname" class="w-full border rounded px-3 py-2" />
|
||||
</div>
|
||||
<div>
|
||||
<label asp-for="IPAddress" class="block font-medium">IP-Adresse</label>
|
||||
<input asp-for="IPAddress" class="w-full border rounded px-3 py-2" />
|
||||
</div>
|
||||
<div>
|
||||
<label asp-for="Status" class="block font-medium">Status</label>
|
||||
<input asp-for="Status" class="w-full border rounded px-3 py-2" />
|
||||
</div>
|
||||
<div>
|
||||
<label asp-for="Type" class="block font-medium">Typ</label>
|
||||
<select asp-for="Type" class="w-full border rounded px-3 py-2">
|
||||
<option>VPS</option>
|
||||
<option>VM</option>
|
||||
<option>Container</option>
|
||||
<option>Physisch</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<input asp-for="IsOnline" class="mr-2" type="checkbox" />
|
||||
<label asp-for="IsOnline">Online?</label>
|
||||
</div>
|
||||
<button type="submit" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">Speichern</button>
|
||||
</form>
|
43
Watcher/Views/Server/overview.cshtml
Normal file
43
Watcher/Views/Server/overview.cshtml
Normal file
@@ -0,0 +1,43 @@
|
||||
@model Watcher.ViewModels.ServerOverviewViewModel
|
||||
@{
|
||||
ViewData["Title"] = "Serverübersicht";
|
||||
}
|
||||
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-2xl font-bold">Serverübersicht</h1>
|
||||
<a asp-action="AddServer" class="bg-blue-600 text-white px-4 py-2 rounded hover:bg-blue-700">
|
||||
+ Server hinzufügen
|
||||
</a>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
@foreach (var s in Model.Servers)
|
||||
{
|
||||
<div class="bg-white rounded-xl shadow p-4 border border-gray-200">
|
||||
<div class="flex justify-between items-start">
|
||||
<div>
|
||||
<h2 class="text-lg font-semibold">@s.Name</h2>
|
||||
<p class="text-sm text-gray-500">@s.Hostname</p>
|
||||
</div>
|
||||
<span class="text-sm px-2 py-1 rounded
|
||||
@(s.IsOnline ? "bg-green-100 text-green-700" : "bg-red-100 text-red-700")">
|
||||
@(s.IsOnline ? "Online" : "Offline")
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 text-sm space-y-1 text-gray-700">
|
||||
<div><strong>IP:</strong> Ip</div>
|
||||
<div><strong>Typ:</strong> @s.Type</div>
|
||||
<div><strong>Status:</strong> @(string.IsNullOrEmpty(s.Status) ? "-" : s.Status)</div>
|
||||
<div><strong>Erstellt:</strong> @s.CreatedAt.ToLocalTime().ToString("dd.MM.yyyy HH:mm")</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex justify-end gap-2">
|
||||
<a asp-action="Edit" asp-route-id="@s.Id" class="text-blue-600 hover:underline text-sm">Bearbeiten</a>
|
||||
<a asp-action="Delete" asp-route-id="@s.Id" class="text-red-600 hover:underline text-sm">Löschen</a>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
</div>
|
Reference in New Issue
Block a user