fixes and improvements

This commit is contained in:
2026-05-07 13:48:10 +02:00
parent bba23165ab
commit efc9b247c7
8 changed files with 344 additions and 245 deletions
+46 -43
View File
@@ -13,6 +13,7 @@ import {
FormControlLabel,
Grid,
Stack,
MenuItem,
Tab,
TextField,
Typography,
@@ -33,7 +34,6 @@ import { HoverEditButton } from "../components/HoverEditButton";
import { SectionCard } from "../components/SectionCard";
import { SelectionRailCard } from "../components/SelectionRailCard";
import { TabbedCard } from "../components/TabbedCard";
const SERVICE_OPTIONS = [
{ value: "monitoring", label: "Monitoring" },
{ value: "files", label: "Files" },
@@ -41,9 +41,7 @@ const SERVICE_OPTIONS = [
{ value: "jellyseerr", label: "Jellyseerr" },
{ value: "nextcloud", label: "Nextcloud" },
];
type SettingsTab = "machines" | "ssh-keys" | "danger";
function emptyMachine(
mode: MonitoringMachineInput["mode"] = "local",
): MonitoringMachineInput {
@@ -72,7 +70,6 @@ function emptyMachine(
notes: "",
};
}
function MachineEditor({
title,
hint,
@@ -97,7 +94,6 @@ function MachineEditor({
const enabledServices = draft.services.length;
const hasJellyfin = draft.services.includes("jellyfin");
const hasJellyseerr = draft.services.includes("jellyseerr");
return (
<Card variant="outlined">
<CardContent sx={{ p: 1.5 }}>
@@ -139,7 +135,6 @@ function MachineEditor({
/>
</Stack>
</Stack>
<Grid container spacing={1.25}>
<Grid size={{ xs: 12, md: 6 }}>
<TextField
@@ -239,11 +234,12 @@ function MachineEditor({
}
/>
</Grid>
<Grid size={{ xs: 12, md: 3 }}>
<Grid size={{ xs: 12, md: 4 }}>
<TextField
select
fullWidth
size="small"
label="SSH key id"
label="SSH key"
value={draft.ssh_key_id}
onChange={(e) =>
setDraft((current) => ({
@@ -251,7 +247,19 @@ function MachineEditor({
ssh_key_id: e.target.value,
}))
}
/>
helperText={
sshKeys.length > 0
? "Select a saved SSH key."
: "No SSH keys are saved yet. Add one in the SSH Keys tab."
}
>
<MenuItem value="">No key selected</MenuItem>
{sshKeys.map((key) => (
<MenuItem key={key.id} value={key.id}>
{key.name}
</MenuItem>
))}
</TextField>
</Grid>
<Grid size={{ xs: 12, md: 6 }}>
<TextField
@@ -387,15 +395,23 @@ function MachineEditor({
/>
</Grid>{" "}
</Grid>
{selectedSSHKey && (
{selectedSSHKey ? (
<Alert severity="info">
Selected key: {selectedSSHKey.name}
{selectedSSHKey.fingerprint
? ` · ${selectedSSHKey.fingerprint}`
: ""}
</Alert>
)}
) : !isLocal && sshKeys.length === 0 ? (
<Alert severity="warning">
No SSH keys have been saved yet. Add one before configuring SSH
machines.
</Alert>
) : draft.ssh_key_id ? (
<Alert severity="warning">
The selected SSH key was not found.
</Alert>
) : null}
{!isLocal && !hasJellyfin && (
<Alert severity="warning">
SSH machines usually need monitoring or files enabled.
@@ -411,7 +427,6 @@ function MachineEditor({
</Card>
);
}
function SSHKeyManager({ sshKeys }: { sshKeys: SSHKey[] }) {
const saveKey = useSaveSSHKey();
const generateKey = useGenerateSSHKey();
@@ -420,20 +435,22 @@ function SSHKeyManager({ sshKeys }: { sshKeys: SSHKey[] }) {
id: null,
name: "",
private_key: "",
public_key: "",
fingerprint: "",
passphrase: "",
notes: "",
});
const editing = Boolean(draft.id);
const clear = () =>
setDraft({
id: null,
name: "",
private_key: "",
passphrase: "",
public_key: "",
fingerprint: "",
notes: "",
});
return (
<Card variant="outlined">
<CardContent sx={{ p: 1.5 }}>
@@ -461,7 +478,6 @@ function SSHKeyManager({ sshKeys }: { sshKeys: SSHKey[] }) {
label={`${sshKeys.length} saved`}
/>
</Stack>
<Grid container spacing={1.25}>
<Grid size={{ xs: 12, md: 4 }}>
<TextField
@@ -524,7 +540,6 @@ function SSHKeyManager({ sshKeys }: { sshKeys: SSHKey[] }) {
/>
</Grid>
</Grid>
<Stack direction="row" spacing={1} sx={{ flexWrap: "wrap" }}>
<Button
variant="contained"
@@ -552,6 +567,8 @@ function SSHKeyManager({ sshKeys }: { sshKeys: SSHKey[] }) {
name: generated.name || current.name,
private_key: generated.private_key,
passphrase: generated.passphrase,
public_key: generated.public_key,
fingerprint: generated.fingerprint,
notes: generated.notes,
}));
}}
@@ -562,11 +579,9 @@ function SSHKeyManager({ sshKeys }: { sshKeys: SSHKey[] }) {
Clear
</Button>
</Stack>
{saveKey.error && (
<Alert severity="error">{String(saveKey.error)}</Alert>
)}
{sshKeys.length > 0 ? (
<Grid container spacing={1.25}>
{sshKeys.map((key) => (
@@ -658,6 +673,8 @@ function SSHKeyManager({ sshKeys }: { sshKeys: SSHKey[] }) {
name: key.name,
private_key: "",
passphrase: "",
public_key: key.public_key,
fingerprint: key.fingerprint,
notes: key.notes,
})
}
@@ -686,7 +703,6 @@ function SSHKeyManager({ sshKeys }: { sshKeys: SSHKey[] }) {
</Card>
);
}
function ResetLocalDatabaseCard() {
const resetDatabase = useResetLocalDatabase();
const [open, setOpen] = useState(false);
@@ -699,7 +715,6 @@ function ResetLocalDatabaseCard() {
ackSettings &&
ackIndex &&
ackIrreversible;
const close = () => {
setOpen(false);
setPhrase("");
@@ -707,7 +722,6 @@ function ResetLocalDatabaseCard() {
setAckIndex(false);
setAckIrreversible(false);
};
return (
<>
<Card variant="outlined">
@@ -745,7 +759,6 @@ function ResetLocalDatabaseCard() {
</Stack>
</CardContent>
</Card>
<Dialog open={open} onClose={close} fullWidth maxWidth="sm">
<DialogTitle>Reset local database</DialogTitle>
<DialogContent>
@@ -810,7 +823,6 @@ function ResetLocalDatabaseCard() {
</>
);
}
export function Settings() {
const { data: machines, error } = useMonitoringSettings();
const { data: sshKeys = [] } = useSSHKeys();
@@ -822,7 +834,6 @@ export function Settings() {
emptyMachine(),
);
const [selectedMachineId, setSelectedMachineId] = useState("");
const orderedMachines = useMemo(() => machines ?? [], [machines]);
const selectedMachine = useMemo(
() =>
@@ -837,7 +848,6 @@ export function Settings() {
const sshMachines = orderedMachines.filter(
(machine) => machine.mode === "ssh",
);
const beginLocal = () => {
setMachineDraft(emptyMachine("local"));
setMachineDialogOpen(true);
@@ -858,7 +868,6 @@ export function Settings() {
setMachineDialogOpen(false);
setMachineDraft(emptyMachine(draft.mode));
};
return (
<Stack spacing={2.25}>
<Stack spacing={0.5}>
@@ -870,7 +879,6 @@ export function Settings() {
tabbed admin workspace.
</Typography>
</Stack>
{error && <Alert severity="error">{String(error)}</Alert>}
{saveMachine.error && (
<Alert severity="error">{String(saveMachine.error)}</Alert>
@@ -878,7 +886,6 @@ export function Settings() {
{deleteMachine.error && (
<Alert severity="error">{String(deleteMachine.error)}</Alert>
)}
<TabbedCard
value={tab}
onChange={(value) => setTab(value as SettingsTab)}
@@ -951,7 +958,6 @@ export function Settings() {
</Stack>
</CardContent>
</Card>
{orderedMachines.length > 0 ? (
<Box
sx={{
@@ -1014,15 +1020,15 @@ export function Settings() {
host: machine.host,
port: machine.port,
username: machine.username,
key_directory: "",
key_name: "",
path_prefix: "",
ssh_key_id: machine.ssh_key_id,
key_directory: "",
key_name: "",
path_prefix: "",
ssh_key_id: machine.ssh_key_id,
ssh_private_key: "",
ssh_private_key_passphrase: "",
password: "",
media_root: machine.media_root,
jellyfin_url: machine.jellyfin_url,
jellyfin_url: machine.jellyfin_url,
jellyfin_user_id: machine.jellyfin_user_id,
jellyfin_api_key: "",
jellyseerr_url: machine.jellyseerr_url,
@@ -1036,7 +1042,6 @@ export function Settings() {
})}
</Box>
</SelectionRailCard>
<SectionCard
title={selectedMachine?.name || "No machine selected"}
description={
@@ -1140,15 +1145,15 @@ export function Settings() {
host: selectedMachine.host,
port: selectedMachine.port,
username: selectedMachine.username,
key_directory: "",
key_name: "",
path_prefix: "",
ssh_key_id: selectedMachine.ssh_key_id,
key_directory: "",
key_name: "",
path_prefix: "",
ssh_key_id: selectedMachine.ssh_key_id,
ssh_private_key: "",
ssh_private_key_passphrase: "",
password: "",
media_root: selectedMachine.media_root,
jellyfin_url: selectedMachine.jellyfin_url,
jellyfin_url: selectedMachine.jellyfin_url,
jellyfin_user_id:
selectedMachine.jellyfin_user_id,
jellyfin_api_key: "",
@@ -1179,11 +1184,9 @@ export function Settings() {
) : null}
</Stack>
)}
{tab === "ssh-keys" && <SSHKeyManager sshKeys={sshKeys} />}
{tab === "danger" && <ResetLocalDatabaseCard />}
</TabbedCard>
<Dialog
open={machineDialogOpen}
onClose={closeMachineDialog}