Werte für mehrere Funktionen, und Anlegen frischt die Auswahl auf
Zwei Nachzügler zu den Modul-Seiten. Die Thread-Archivdauer gilt für Tickets und Modmail, hing aber nur an Tickets — auf der Modmail-Seite fehlte sie also. `module` darf jetzt eine Liste sein; nach außen kommt immer eine, damit niemand zwischen einem und mehreren unterscheiden muss. Und beim Anlegen aus dem Panel wurde nur die Einstellung gesetzt, nicht die Kanalliste nachgeladen. Der frische Kanal stand damit zwar in der Einstellung, fehlte aber in der Auswahl — das Feld sah leer aus, obwohl es gesetzt war. Aufgefallen im Browser-Test: „Einsatzbereit" stand da, die Auswahl daneben war leer. Jetzt holt reloadSettings Kanäle, Rollen und Einstellungen frisch; das gilt für den Einzelknopf, den Assistenten und die Modul-Seiten gleichermaßen. Nachgeprüft: Kanal über die Status-Liste anlegen, dann ohne Neuladen nach Feeds wechseln — dort steht #dev-log. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -59,12 +59,12 @@ function Feld({ feld, value, onChange, PickSelect, channelItems, roleItems }) {
|
|||||||
* form: object, setForm: (f: object) => void,
|
* form: object, setForm: (f: object) => void,
|
||||||
* PickSelect: Function, channelItems: Array, roleItems: Array,
|
* PickSelect: Function, channelItems: Array, roleItems: Array,
|
||||||
* welcomePreviewUrl: string, flash: (msg: string) => void,
|
* welcomePreviewUrl: string, flash: (msg: string) => void,
|
||||||
* goTab: (tab: string) => void,
|
* goTab: (tab: string) => void, reloadSettings: () => Promise<void>,
|
||||||
* }} props
|
* }} props
|
||||||
*/
|
*/
|
||||||
export default function ModulePage(props) {
|
export default function ModulePage(props) {
|
||||||
const { id, onBack, onToggle, form, setForm, PickSelect, channelItems, roleItems,
|
const { id, onBack, onToggle, form, setForm, PickSelect, channelItems, roleItems,
|
||||||
welcomePreviewUrl, flash, goTab } = props;
|
welcomePreviewUrl, flash, goTab, reloadSettings } = props;
|
||||||
|
|
||||||
const [detail, setDetail] = useState(null);
|
const [detail, setDetail] = useState(null);
|
||||||
const [fehler, setFehler] = useState(false);
|
const [fehler, setFehler] = useState(false);
|
||||||
@@ -104,7 +104,7 @@ export default function ModulePage(props) {
|
|||||||
if (Object.keys(geaendert).length === 0) return;
|
if (Object.keys(geaendert).length === 0) return;
|
||||||
try {
|
try {
|
||||||
const res = await apiPut('/api/tuning', geaendert);
|
const res = await apiPut('/api/tuning', geaendert);
|
||||||
setDetail((d) => ({ ...d, werte: res.values.filter((w) => w.module === d.id) }));
|
setDetail((d) => ({ ...d, werte: res.values.filter((w) => w.modules.includes(d.id)) }));
|
||||||
setWerteEntwurf({});
|
setWerteEntwurf({});
|
||||||
flash('✓ Werte gespeichert');
|
flash('✓ Werte gespeichert');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -115,7 +115,9 @@ export default function ModulePage(props) {
|
|||||||
async function anlegen(setting) {
|
async function anlegen(setting) {
|
||||||
try {
|
try {
|
||||||
const res = await apiPost('/api/setup/create', { setting });
|
const res = await apiPost('/api/setup/create', { setting });
|
||||||
setForm(res.settings);
|
// Auffrischen statt nur setzen: der neue Kanal muss auch in der
|
||||||
|
// Auswahlliste stehen, sonst wirkt das Feld leer.
|
||||||
|
await reloadSettings();
|
||||||
laden();
|
laden();
|
||||||
flash(res.wiederverwendet ? `✓ „${res.name}" verknüpft` : `✓ „${res.name}" angelegt`);
|
flash(res.wiederverwendet ? `✓ „${res.name}" verknüpft` : `✓ „${res.name}" angelegt`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -542,8 +542,7 @@ export default function Settings({ me }) {
|
|||||||
try {
|
try {
|
||||||
const res = await apiPost('/api/setup/run', { kategorie: plan.kategorie });
|
const res = await apiPost('/api/setup/run', { kategorie: plan.kategorie });
|
||||||
setModules(res.modules);
|
setModules(res.modules);
|
||||||
setForm(res.settings);
|
await reloadSettings();
|
||||||
setData((d) => (d ? { ...d, settings: res.settings } : d));
|
|
||||||
setSetupResult(res.ergebnisse);
|
setSetupResult(res.ergebnisse);
|
||||||
setPlan(null);
|
setPlan(null);
|
||||||
const neu = res.ergebnisse.filter((r) => r.ok && !r.wiederverwendet).length;
|
const neu = res.ergebnisse.filter((r) => r.ok && !r.wiederverwendet).length;
|
||||||
@@ -555,16 +554,25 @@ export default function Settings({ me }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Kanäle, Rollen und Einstellungen neu holen. Nötig nach dem Anlegen: der
|
||||||
|
* frische Kanal steht sonst zwar in der Einstellung, fehlt aber in der
|
||||||
|
* Auswahlliste — das Feld sähe leer aus, obwohl es gesetzt ist.
|
||||||
|
*/
|
||||||
|
async function reloadSettings() {
|
||||||
|
const frisch = await apiGet('/api/settings').catch(() => null);
|
||||||
|
if (!frisch) return;
|
||||||
|
setData(frisch);
|
||||||
|
setForm(frisch.settings);
|
||||||
|
}
|
||||||
|
|
||||||
/** Fehlenden Kanal / fehlende Rolle vom Bot anlegen lassen */
|
/** Fehlenden Kanal / fehlende Rolle vom Bot anlegen lassen */
|
||||||
async function createMissing(entry) {
|
async function createMissing(entry) {
|
||||||
setCreating(entry.setting);
|
setCreating(entry.setting);
|
||||||
try {
|
try {
|
||||||
const res = await apiPost('/api/setup/create', { setting: entry.setting });
|
const res = await apiPost('/api/setup/create', { setting: entry.setting });
|
||||||
setModules(res.modules);
|
setModules(res.modules);
|
||||||
// Die neue Auswahl steht sofort im Formular — und zählt nicht als
|
await reloadSettings();
|
||||||
// ungespeicherte Änderung, weil der Vergleichsstand mitwandert.
|
|
||||||
setForm(res.settings);
|
|
||||||
setData((d) => (d ? { ...d, settings: res.settings } : d));
|
|
||||||
flash(res.wiederverwendet
|
flash(res.wiederverwendet
|
||||||
? `✓ Vorhandenen ${res.art === 'rolle' ? 'Rolle' : 'Kanal'} „${res.name}" verknüpft`
|
? `✓ Vorhandenen ${res.art === 'rolle' ? 'Rolle' : 'Kanal'} „${res.name}" verknüpft`
|
||||||
: `✓ ${res.art === 'rolle' ? 'Rolle' : 'Kanal'} „${res.name}" angelegt`);
|
: `✓ ${res.art === 'rolle' ? 'Rolle' : 'Kanal'} „${res.name}" angelegt`);
|
||||||
@@ -2378,6 +2386,7 @@ export default function Settings({ me }) {
|
|||||||
welcomePreviewUrl={welcomePreviewUrl}
|
welcomePreviewUrl={welcomePreviewUrl}
|
||||||
flash={flash}
|
flash={flash}
|
||||||
goTab={setTab}
|
goTab={setTab}
|
||||||
|
reloadSettings={reloadSettings}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="settings-section">
|
<div className="settings-section">
|
||||||
|
|||||||
+8
-3
@@ -2,7 +2,9 @@
|
|||||||
// Wartezeiten, Prüf-Intervalle, Obergrenzen.
|
// Wartezeiten, Prüf-Intervalle, Obergrenzen.
|
||||||
//
|
//
|
||||||
// `module` verbindet einen Wert mit seiner Funktion — die Modul-Seite zeigt ihn
|
// `module` verbindet einen Wert mit seiner Funktion — die Modul-Seite zeigt ihn
|
||||||
// dann dort, wo er hingehört, statt nur in der flachen Werte-Liste.
|
// dann dort, wo er hingehört, statt nur in der flachen Werte-Liste. Ein Wert
|
||||||
|
// darf zu mehreren gehören (die Thread-Archivdauer gilt für Tickets UND
|
||||||
|
// Modmail); dann steht dort eine Liste.
|
||||||
//
|
//
|
||||||
// Wie bei den Modulen und Vorlagen lebt der Standard im Code und die
|
// Wie bei den Modulen und Vorlagen lebt der Standard im Code und die
|
||||||
// Datenbank enthält nur Abweichungen. `min`/`max` sind keine Kosmetik: sie
|
// Datenbank enthält nur Abweichungen. `min`/`max` sind keine Kosmetik: sie
|
||||||
@@ -107,7 +109,7 @@ export const TUNING = [
|
|||||||
unit: 'Commits', default: 10, min: 1, max: 20,
|
unit: 'Commits', default: 10, min: 1, max: 20,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'thread_archive_days', module: 'tickets', group: 'grenzen', label: 'Threads archivieren nach',
|
id: 'thread_archive_days', module: ['tickets', 'modmail'], group: 'grenzen', label: 'Threads archivieren nach',
|
||||||
hint: 'Für Ticket- und Modmail-Threads. Discord erlaubt 1, 3 oder 7 Tage.',
|
hint: 'Für Ticket- und Modmail-Threads. Discord erlaubt 1, 3 oder 7 Tage.',
|
||||||
unit: 'Tagen', default: 7, min: 1, max: 7, choices: [1, 3, 7],
|
unit: 'Tagen', default: 7, min: 1, max: 7, choices: [1, 3, 7],
|
||||||
},
|
},
|
||||||
@@ -171,7 +173,10 @@ export function tuningStates() {
|
|||||||
const custom = getSetting(`tune_${t.id}`);
|
const custom = getSetting(`tune_${t.id}`);
|
||||||
return {
|
return {
|
||||||
id: t.id, label: t.label, hint: t.hint ?? null,
|
id: t.id, label: t.label, hint: t.hint ?? null,
|
||||||
group: t.group, module: t.module ?? null,
|
group: t.group,
|
||||||
|
// Immer als Liste nach außen — der Aufrufer muss dann nicht
|
||||||
|
// zwischen einem Wert und mehreren unterscheiden
|
||||||
|
modules: t.module ? [t.module].flat() : [],
|
||||||
unit: t.unit, min: t.min, max: t.max,
|
unit: t.unit, min: t.min, max: t.max,
|
||||||
choices: t.choices ?? null,
|
choices: t.choices ?? null,
|
||||||
default: t.default,
|
default: t.default,
|
||||||
|
|||||||
+1
-1
@@ -202,7 +202,7 @@ export function registerApiRoutes(app, client) {
|
|||||||
return {
|
return {
|
||||||
...detail,
|
...detail,
|
||||||
texte: templateStates().filter((t) => t.module === detail.id),
|
texte: templateStates().filter((t) => t.module === detail.id),
|
||||||
werte: tuningStates().filter((w) => w.module === detail.id),
|
werte: tuningStates().filter((w) => w.modules.includes(detail.id)),
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user