Fehlende Kanäle und Rollen aus dem Panel anlegen
Deploy / check (push) Has been cancelled
Deploy / deploy (push) Has been cancelled

Die Status-Seite listet Module, denen ein Kanal oder eine Rolle fehlt.
Bisher hieß das: rüber zu Discord, Kanal anlegen, Rechte setzen, zurück ins
Panel, auswählen, speichern. Jetzt steht daneben ein Knopf, der genau das
in einem Schritt macht — inklusive Eintragen der Einstellung.

Die Vorlagen hängen bei den Modulen (modules.js): Name, Thema und ob der
Kanal privat sein soll. Private Kanäle bekommen @everyone entzogen und
Bot plus alle Rollen mit Moderationsrecht eingetragen — sonst legt man
einen Modmail-Kanal an, den das Team nicht sieht.

Gibt es Kanal oder Rolle schon (bei Rollen unabhängig von Groß- und
Kleinschreibung), werden sie verknüpft statt doppelt angelegt. Beim
Temp-Voice-Hub entsteht ein Sprachkanal statt eines Textkanals.

Fehlen dem Bot die Rechte, steht das im Panel im Klartext („Dem Bot fehlt
das Recht Kanäle verwalten") statt einer Discord-Fehlernummer.

Bewusst nur Anlegen: kein Löschen, kein Umbenennen. Ein Fehlklick beim
Anlegen kostet einen überflüssigen Kanal, einer beim Löschen dessen
Verlauf. Umbenennen wäre zusätzlich eine Falle, weil Discord es auf zwei
Änderungen pro zehn Minuten und Kanal begrenzt.

moduleMissing liefert dafür Objekte statt Beschriftungen, damit das Panel
weiß, was sich anlegen lässt.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-31 18:29:54 +02:00
co-authored by Claude Fable 5
parent 0240225165
commit 684573b88c
6 changed files with 197 additions and 23 deletions
+37 -2
View File
@@ -304,6 +304,7 @@ export default function Settings({ me }) {
const [modules, setModules] = useState([]);
const [moduleGroups, setModuleGroups] = useState([]);
const [modFilter, setModFilter] = useState('alle');
const [creating, setCreating] = useState(null); // Einstellung, die gerade angelegt wird
// Text-Vorlagen (was der Bot nach außen schreibt)
const [templates, setTemplates] = useState([]);
const [templateGroups, setTemplateGroups] = useState([]);
@@ -501,6 +502,26 @@ export default function Settings({ me }) {
}
}
/** Fehlenden Kanal / fehlende Rolle vom Bot anlegen lassen */
async function createMissing(entry) {
setCreating(entry.setting);
try {
const res = await apiPost('/api/setup/create', { setting: entry.setting });
setModules(res.modules);
// Die neue Auswahl steht sofort im Formular — und zählt nicht als
// ungespeicherte Änderung, weil der Vergleichsstand mitwandert.
setForm(res.settings);
setData((d) => (d ? { ...d, settings: res.settings } : d));
flash(res.wiederverwendet
? `✓ Vorhandenen ${res.art === 'rolle' ? 'Rolle' : 'Kanal'}${res.name}" verknüpft`
: `${res.art === 'rolle' ? 'Rolle' : 'Kanal'}${res.name}" angelegt`);
} catch (error) {
flash(`${error.body?.error ?? 'Anlegen fehlgeschlagen'}`);
} finally {
setCreating(null);
}
}
/** Alle geänderten Stellwerte auf einmal speichern */
async function saveTuning() {
const changed = Object.fromEntries(
@@ -1023,8 +1044,22 @@ export default function Settings({ me }) {
<div className="key-row" key={m.id}>
<span className="key-name">{m.name}</span>
<span className="todo-missing with-icon">
<IconWarning size={13} /> {m.missing.join(', ')}
<IconWarning size={13} /> {m.missing.map((x) => x.label).join(', ')}
</span>
{/* Was der Bot selbst anlegen kann, bekommt einen Knopf dafür */}
{m.missing.filter((x) => x.create).map((x) => (
<button
key={x.setting}
className="btn-mini btn-create"
disabled={creating === x.setting}
title={`#${x.create.name} anlegen und eintragen`}
onClick={() => createMissing(x)}
>
{creating === x.setting
? '…'
: `${x.create.rolle ? 'Rolle' : 'Kanal'} anlegen`}
</button>
))}
{m.tab && (
<button className="btn-mini" onClick={() => setTab(m.tab)}>
Einrichten
@@ -2262,7 +2297,7 @@ export default function Settings({ me }) {
<div className="mod-foot">
{m.enabled && m.missing.length > 0 && (
<span className="mod-missing with-icon">
<IconWarning size={13} /> Fehlt: {m.missing.join(', ')}
<IconWarning size={13} /> Fehlt: {m.missing.map((x) => x.label).join(', ')}
</span>
)}
{m.enabled && m.missing.length === 0 && (