import { Eye, EyeOff, Save } from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';
import { api, errorMessage, setApiToken } from '../api.js';
export function Settings({ onChanged }) {
const [fields, setFields] = useState([]);
const [values, setValues] = useState({});
const [visibleSecrets, setVisibleSecrets] = useState({});
const [saving, setSaving] = useState(false);
const [message, setMessage] = useState('');
const [error, setError] = useState('');
const requiredMissing = useMemo(
() => fields.filter((field) => field.required && !String(values[field.key] || '').trim()),
[fields, values],
);
async function loadSettings() {
setError('');
try {
const result = await api.get('/settings');
setFields(result.data.fields || []);
setValues(Object.fromEntries((result.data.fields || []).map((field) => [field.key, field.value || ''])));
} catch (requestError) {
setError(errorMessage(requestError));
}
}
useEffect(() => {
loadSettings();
}, []);
async function saveSettings(event) {
event.preventDefault();
setSaving(true);
setMessage('');
setError('');
try {
setApiToken(values.API_TOKEN);
const result = await api.put('/settings', { values });
setFields(result.data.fields || []);
setValues(Object.fromEntries((result.data.fields || []).map((field) => [field.key, field.value || ''])));
setMessage('Settings saved. Running jobs use the updated values; a changed PORT still needs a backend restart.');
await onChanged?.();
} catch (requestError) {
setError(errorMessage(requestError));
} finally {
setSaving(false);
}
}
return (
Values are written to backend/.env. Keep access to this UI restricted because secrets are editable here.
Settings