115 lines
3.6 KiB
JavaScript
115 lines
3.6 KiB
JavaScript
import React, { useEffect, useState } from "react";
|
|
import { Link } from "react-router-dom";
|
|
import { apiFetch } from "../api";
|
|
import { useAuth } from "../state";
|
|
|
|
const emptyForm = {
|
|
name: "",
|
|
host: "",
|
|
port: 5432,
|
|
dbname: "",
|
|
username: "",
|
|
password: "",
|
|
sslmode: "prefer",
|
|
tags: {},
|
|
};
|
|
|
|
export function TargetsPage() {
|
|
const { tokens, refresh, me } = useAuth();
|
|
const [targets, setTargets] = useState([]);
|
|
const [form, setForm] = useState(emptyForm);
|
|
const [error, setError] = useState("");
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
const canManage = me?.role === "admin" || me?.role === "operator";
|
|
|
|
const load = async () => {
|
|
setLoading(true);
|
|
try {
|
|
setTargets(await apiFetch("/targets", {}, tokens, refresh));
|
|
setError("");
|
|
} catch (e) {
|
|
setError(String(e.message || e));
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
useEffect(() => {
|
|
load();
|
|
}, []);
|
|
|
|
const createTarget = async (e) => {
|
|
e.preventDefault();
|
|
try {
|
|
await apiFetch("/targets", { method: "POST", body: JSON.stringify(form) }, tokens, refresh);
|
|
setForm(emptyForm);
|
|
await load();
|
|
} catch (e) {
|
|
setError(String(e.message || e));
|
|
}
|
|
};
|
|
|
|
const deleteTarget = async (id) => {
|
|
if (!confirm("Target löschen?")) return;
|
|
try {
|
|
await apiFetch(`/targets/${id}`, { method: "DELETE" }, tokens, refresh);
|
|
await load();
|
|
} catch (e) {
|
|
setError(String(e.message || e));
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div>
|
|
<h2>Targets Management</h2>
|
|
{error && <div className="card error">{error}</div>}
|
|
{canManage && (
|
|
<form className="card grid two" onSubmit={createTarget}>
|
|
<input placeholder="Name" value={form.name} onChange={(e) => setForm({ ...form, name: e.target.value })} required />
|
|
<input placeholder="Host" value={form.host} onChange={(e) => setForm({ ...form, host: e.target.value })} required />
|
|
<input placeholder="Port" value={form.port} onChange={(e) => setForm({ ...form, port: Number(e.target.value) })} type="number" />
|
|
<input placeholder="DB Name" value={form.dbname} onChange={(e) => setForm({ ...form, dbname: e.target.value })} required />
|
|
<input placeholder="Username" value={form.username} onChange={(e) => setForm({ ...form, username: e.target.value })} required />
|
|
<input placeholder="Passwort" type="password" value={form.password} onChange={(e) => setForm({ ...form, password: e.target.value })} required />
|
|
<select value={form.sslmode} onChange={(e) => setForm({ ...form, sslmode: e.target.value })}>
|
|
<option value="disable">disable</option>
|
|
<option value="prefer">prefer</option>
|
|
<option value="require">require</option>
|
|
</select>
|
|
<button>Target anlegen</button>
|
|
</form>
|
|
)}
|
|
<div className="card">
|
|
{loading ? (
|
|
<p>Lade Targets...</p>
|
|
) : (
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Name</th>
|
|
<th>Host</th>
|
|
<th>DB</th>
|
|
<th>Aktionen</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{targets.map((t) => (
|
|
<tr key={t.id}>
|
|
<td>{t.name}</td>
|
|
<td>{t.host}:{t.port}</td>
|
|
<td>{t.dbname}</td>
|
|
<td>
|
|
<Link to={`/targets/${t.id}`}>Details</Link>{" "}
|
|
{canManage && <button onClick={() => deleteTarget(t.id)}>Delete</button>}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
)}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|