fixes and improvements

This commit is contained in:
2026-05-07 22:24:08 +02:00
parent a85c9a0df4
commit 26a30a5572
3 changed files with 131 additions and 6 deletions
+47
View File
@@ -0,0 +1,47 @@
import {
Dialog,
DialogContent,
DialogTitle,
Stack,
Typography,
} from "@mui/material";
import { DialogFooter } from "./DialogFooter";
export function ConfirmDialog({
open,
title,
message,
confirmLabel = "Delete",
onCancel,
onConfirm,
busy,
}: {
open: boolean;
title: string;
message: string;
confirmLabel?: string;
onCancel: () => void;
onConfirm: () => void;
busy?: boolean;
}) {
return (
<Dialog open={open} onClose={onCancel} fullWidth maxWidth="xs">
<DialogTitle>{title}</DialogTitle>
<DialogContent>
<Stack spacing={1}>
<Typography variant="body2" color="text.secondary">
{message}
</Typography>
</Stack>
</DialogContent>
<DialogFooter
onCancel={onCancel}
onConfirm={onConfirm}
confirmLabel={confirmLabel}
confirmColor="error"
confirmBusyLabel={confirmLabel}
confirmDisabled={busy}
/>
</Dialog>
);
}
+65 -3
View File
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useMemo, useState } from "react";
import {
Alert,
Box,
@@ -29,6 +29,7 @@ import {
useMonitoringOverview,
useSaveDashboardShortcut,
} from "../hooks/useDashboard";
import { useMonitoringSettings } from "../hooks/useSettings";
import type { DashboardShortcut, DashboardShortcutInput } from "../types";
import { NowPlaying } from "../components/NowPlaying";
import { MonitoringOverviewTable } from "../components/MonitoringOverviewTable";
@@ -310,7 +311,19 @@ function ShortcutCard({
export function Dashboard() {
const navigate = useNavigate();
const { data: activity } = useActivity();
const { data: machines = [] } = useMonitoringSettings();
const jellyfinMachines = useMemo(
() =>
machines.filter(
(machine) => machine.enabled && machine.services.includes("jellyfin"),
),
[machines],
);
const [activeJellyfinMachineId, setActiveJellyfinMachineId] =
useState<string>("");
const selectedJellyfinId =
activeJellyfinMachineId || jellyfinMachines[0]?.id || "";
const { data: activity } = useActivity(selectedJellyfinId || undefined);
const { data: monitoringOverview } = useMonitoringOverview();
const { data: shortcuts = [] } = useDashboardShortcuts();
const saveShortcut = useSaveDashboardShortcut();
@@ -319,6 +332,7 @@ export function Dashboard() {
const [shortcutDraft, setShortcutDraft] = useState<DashboardShortcutInput>(
emptyShortcut(),
);
const [deleteShortcutId, setDeleteShortcutId] = useState<string | null>(null);
const openCreateShortcut = () => {
setShortcutDraft(emptyShortcut());
@@ -373,7 +387,7 @@ export function Dashboard() {
}
}}
onEdit={() => openEditShortcut(shortcut)}
onDelete={() => deleteShortcut.mutate(shortcut.id)}
onDelete={() => setDeleteShortcutId(shortcut.id)}
/>
</Grid>
))}
@@ -389,6 +403,29 @@ export function Dashboard() {
<SectionCard
title="Jellyfin activity"
description="Live sessions and idle users from Jellyfin."
action={
jellyfinMachines.length > 1 ? (
<FormControl size="small" sx={{ minWidth: 180 }}>
<Select
value={selectedJellyfinId}
onChange={(e) => setActiveJellyfinMachineId(e.target.value)}
sx={{ fontSize: "0.8rem" }}
>
{jellyfinMachines.map((m) => (
<MenuItem key={m.id} value={m.id}>
{m.name}
</MenuItem>
))}
</Select>
</FormControl>
) : jellyfinMachines.length === 1 ? (
<Chip
label={jellyfinMachines[0].name}
size="small"
variant="outlined"
/>
) : null
}
>
{activity ? (
<NowPlaying
@@ -414,6 +451,31 @@ export function Dashboard() {
onClose={() => setShortcutDialogOpen(false)}
onSave={saveShortcutDraft}
/>
<Dialog
open={Boolean(deleteShortcutId)}
onClose={() => setDeleteShortcutId(null)}
fullWidth
maxWidth="xs"
>
<DialogTitle>Delete shortcut?</DialogTitle>
<DialogContent>
<Typography variant="body2" color="text.secondary">
This cannot be undone. The shortcut will be removed from the
dashboard.
</Typography>
</DialogContent>
<DialogFooter
onCancel={() => setDeleteShortcutId(null)}
onConfirm={() => {
if (deleteShortcutId) {
deleteShortcut.mutate(deleteShortcutId);
}
setDeleteShortcutId(null);
}}
confirmLabel="Delete"
confirmColor="error"
/>
</Dialog>
</Stack>
);
}
+19 -3
View File
@@ -36,6 +36,7 @@ import { HoverEditButton } from "../components/HoverEditButton";
import { SectionCard } from "../components/SectionCard";
import { SelectionRailCard } from "../components/SelectionRailCard";
import { TabbedCard } from "../components/TabbedCard";
import { ConfirmDialog } from "../components/ConfirmDialog";
const SERVICE_OPTIONS = [
{ value: "monitoring", label: "Monitoring" },
{ value: "files", label: "Files" },
@@ -996,6 +997,7 @@ export function Settings() {
const deleteMachine = useDeleteMonitoringMachine();
const testMachineSSH = useTestMonitoringMachineSSH();
const [tab, setTab] = useState<SettingsTab>("machines");
const [deleteMachineId, setDeleteMachineId] = useState<string | null>(null);
const [sshValidationMessage, setSSHValidationMessage] = useState("");
const [sshValidationError, setSSHValidationError] = useState("");
const [sshValidationStatus, setSSHValidationStatus] = useState("");
@@ -1384,7 +1386,7 @@ export function Settings() {
variant="outlined"
color="error"
onClick={() =>
deleteMachine.mutate(selectedMachine.id)
setDeleteMachineId(selectedMachine.id)
}
>
Delete
@@ -1448,8 +1450,8 @@ export function Settings() {
variant="outlined"
color="error"
onClick={() => {
deleteMachine.mutate(machineDraft.id as string);
closeMachineDialog();
setDeleteMachineId(machineDraft.id as string);
}}
>
Delete
@@ -1457,6 +1459,20 @@ export function Settings() {
) : undefined
}
/>
<ConfirmDialog
open={Boolean(deleteMachineId)}
title="Delete machine?"
message="The machine will be removed. Action history will be deleted."
onCancel={() => setDeleteMachineId(null)}
onConfirm={() => {
if (deleteMachineId) {
deleteMachine.mutate(deleteMachineId);
closeMachineDialog();
}
setDeleteMachineId(null);
}}
/>
</Dialog>
</Stack>
);