@@ -48,24 +56,25 @@ export default async function DomainDetailPage({ params }: { params: Promise<{ i
- Konfiguration
-
-
-
- {target ? (
-
- {target}
-
- ) : "—"}
-
- {group && {group.name}
}
-
- {domain.redirect_code}
- {domain.redirect_code === 301 && ⚠}
-
- {domain.preserve_path ? "ja" : "nein"}
- {domain.include_www ? "ja" : "nein"}
- {domain.verified_at ? new Date(domain.verified_at).toLocaleString("de-DE") : "—"}
+
+ Konfiguration
+
+ Status: • Verifiziert: {domain.verified_at ? new Date(domain.verified_at).toLocaleDateString("de-DE") : "—"}
+ {target && <> • Aktuell: {target}>}
+ {group && <> • Gruppe: {group.name}>}
+
+
+
+
@@ -73,15 +82,35 @@ export default async function DomainDetailPage({ params }: { params: Promise<{ i
Hits
{hits24h.toLocaleString("de-DE")}
- {hits30d.toLocaleString("de-DE")}
- {hitsTotal.toLocaleString("de-DE")}
+ {hits30d.toLocaleString("de-DE")} ({visitors30d.toLocaleString("de-DE")} Besucher)
+ {hitsTotal.toLocaleString("de-DE")} ({visitorsTotal.toLocaleString("de-DE")} Besucher)
Aktionen
-
+
+
+
+
+
+
+ DNS-Records
+ Alle aktuell für diese Domain veröffentlichten DNS-Einträge.
+
+
+
+
+
+
+
+
+ Abschaltungs-Hinweis
+ Optional Hinweisseite vor Redirect.
+
+
+
@@ -108,8 +137,8 @@ function Row({ k, children }: { k: string; children: React.ReactNode }) {
);
}
-function StatusBadge({ status }: { status: string }) {
- if (status === "active") return
aktiv;
- if (status === "pending") return
wartet;
- return
{status};
+function StatusInline({ status }: { status: string }) {
+ if (status === "active") return
aktiv;
+ if (status === "pending") return
wartet;
+ return
{status};
}
diff --git a/app/(app)/domains/page.tsx b/app/(app)/domains/page.tsx
index 6affd16..228aa8b 100644
--- a/app/(app)/domains/page.tsx
+++ b/app/(app)/domains/page.tsx
@@ -1,4 +1,5 @@
import Link from "next/link";
+import { FileDown } from "lucide-react";
import { PageHeader } from "@/components/PageHeader";
import { Button } from "@/components/ui/button";
import { getDb } from "@/lib/db";
@@ -29,9 +30,14 @@ export default function DomainsPage() {
title="Domains"
description="Alle verwalteten Redirect-Domains"
actions={
-
+
+
+
+
}
/>
diff --git a/app/(app)/groups/page.tsx b/app/(app)/groups/page.tsx
index ebf2a67..321caf0 100644
--- a/app/(app)/groups/page.tsx
+++ b/app/(app)/groups/page.tsx
@@ -1,6 +1,6 @@
"use client";
import { useEffect, useState } from "react";
-import { Loader2, Plus, Trash2 } from "lucide-react";
+import { Loader2, Plus, Trash2, Pencil } from "lucide-react";
import { PageHeader } from "@/components/PageHeader";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
@@ -20,6 +20,7 @@ export default function GroupsPage() {
const [code, setCode] = useState<301 | 302>(302);
const [creating, setCreating] = useState(false);
const [error, setError] = useState("");
+ const [editing, setEditing] = useState
(null);
async function load() {
setLoading(true);
@@ -63,6 +64,29 @@ export default function GroupsPage() {
load();
}
+ async function handleEditSave(e: React.FormEvent) {
+ e.preventDefault();
+ if (!editing) return;
+ setCreating(true);
+ setError("");
+ try {
+ const r = await fetch(`/api/groups/${editing.id}`, {
+ method: "PATCH",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ name: editing.name, target_url: editing.target_url, redirect_code: editing.redirect_code }),
+ });
+ if (!r.ok) {
+ const d = await r.json();
+ setError(d.error || "Fehler");
+ return;
+ }
+ setEditing(null);
+ load();
+ } finally {
+ setCreating(false);
+ }
+ }
+
return (
{g.name}
-
+
+
+
+
@@ -138,6 +167,40 @@ export default function GroupsPage() {
)}