mirror of
https://github.com/nicotsx/ironmount.git
synced 2025-12-10 12:10:51 +01:00
feat: sse for volume status change
This commit is contained in:
@@ -15,7 +15,6 @@ interface FileEntry {
|
|||||||
type VolumeFileBrowserProps = {
|
type VolumeFileBrowserProps = {
|
||||||
volumeName: string;
|
volumeName: string;
|
||||||
enabled?: boolean;
|
enabled?: boolean;
|
||||||
refetchInterval?: number | false;
|
|
||||||
withCheckboxes?: boolean;
|
withCheckboxes?: boolean;
|
||||||
selectedPaths?: Set<string>;
|
selectedPaths?: Set<string>;
|
||||||
onSelectionChange?: (paths: Set<string>) => void;
|
onSelectionChange?: (paths: Set<string>) => void;
|
||||||
@@ -28,7 +27,6 @@ type VolumeFileBrowserProps = {
|
|||||||
export const VolumeFileBrowser = ({
|
export const VolumeFileBrowser = ({
|
||||||
volumeName,
|
volumeName,
|
||||||
enabled = true,
|
enabled = true,
|
||||||
refetchInterval,
|
|
||||||
withCheckboxes = false,
|
withCheckboxes = false,
|
||||||
selectedPaths,
|
selectedPaths,
|
||||||
onSelectionChange,
|
onSelectionChange,
|
||||||
@@ -46,7 +44,6 @@ export const VolumeFileBrowser = ({
|
|||||||
const { data, isLoading, error } = useQuery({
|
const { data, isLoading, error } = useQuery({
|
||||||
...listFilesOptions({ path: { name: volumeName } }),
|
...listFilesOptions({ path: { name: volumeName } }),
|
||||||
enabled,
|
enabled,
|
||||||
refetchInterval,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
useMemo(() => {
|
useMemo(() => {
|
||||||
|
|||||||
@@ -92,6 +92,17 @@ export function useServerEvents() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
eventSource.addEventListener("volume:status_updated", (e) => {
|
||||||
|
const data = JSON.parse(e.data) as VolumeEvent;
|
||||||
|
console.log("[SSE] Volume status updated:", data);
|
||||||
|
|
||||||
|
queryClient.invalidateQueries();
|
||||||
|
|
||||||
|
handlersRef.current.get("volume:updated")?.forEach((handler) => {
|
||||||
|
handler(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
eventSource.onerror = (error) => {
|
eventSource.onerror = (error) => {
|
||||||
console.error("[SSE] Connection error:", error);
|
console.error("[SSE] Connection error:", error);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -30,7 +30,6 @@ export const FilesTabContent = ({ volume }: Props) => {
|
|||||||
<VolumeFileBrowser
|
<VolumeFileBrowser
|
||||||
volumeName={volume.name}
|
volumeName={volume.name}
|
||||||
enabled={volume.status === "mounted"}
|
enabled={volume.status === "mounted"}
|
||||||
refetchInterval={10000}
|
|
||||||
className="overflow-auto flex-1 border rounded-md bg-card p-2"
|
className="overflow-auto flex-1 border rounded-md bg-card p-2"
|
||||||
emptyMessage="This volume is empty."
|
emptyMessage="This volume is empty."
|
||||||
emptyDescription="Files and folders will appear here once you add them."
|
emptyDescription="Files and folders will appear here once you add them."
|
||||||
|
|||||||
@@ -6,10 +6,16 @@ import type { TypedEmitter } from "tiny-typed-emitter";
|
|||||||
*/
|
*/
|
||||||
interface ServerEvents {
|
interface ServerEvents {
|
||||||
"backup:started": (data: { scheduleId: number; volumeName: string; repositoryName: string }) => void;
|
"backup:started": (data: { scheduleId: number; volumeName: string; repositoryName: string }) => void;
|
||||||
"backup:completed": (data: { scheduleId: number; volumeName: string; repositoryName: string; status: "success" | "error" }) => void;
|
"backup:completed": (data: {
|
||||||
|
scheduleId: number;
|
||||||
|
volumeName: string;
|
||||||
|
repositoryName: string;
|
||||||
|
status: "success" | "error";
|
||||||
|
}) => void;
|
||||||
"volume:mounted": (data: { volumeName: string }) => void;
|
"volume:mounted": (data: { volumeName: string }) => void;
|
||||||
"volume:unmounted": (data: { volumeName: string }) => void;
|
"volume:unmounted": (data: { volumeName: string }) => void;
|
||||||
"volume:updated": (data: { volumeName: string }) => void;
|
"volume:updated": (data: { volumeName: string }) => void;
|
||||||
|
"volume:status_changed": (data: { volumeName: string; status: string }) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export const eventsController = new Hono().get("/", (c) => {
|
|||||||
data: JSON.stringify({ timestamp: Date.now() }),
|
data: JSON.stringify({ timestamp: Date.now() }),
|
||||||
event: "heartbeat",
|
event: "heartbeat",
|
||||||
});
|
});
|
||||||
await stream.sleep(30000);
|
await stream.sleep(5000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -224,6 +224,10 @@ const checkHealth = async (name: string) => {
|
|||||||
const backend = createVolumeBackend(volume);
|
const backend = createVolumeBackend(volume);
|
||||||
const { error, status } = await backend.checkHealth();
|
const { error, status } = await backend.checkHealth();
|
||||||
|
|
||||||
|
if (status !== volume.status) {
|
||||||
|
serverEvents.emit("volume:status_changed", { volumeName: name, status });
|
||||||
|
}
|
||||||
|
|
||||||
await db
|
await db
|
||||||
.update(volumesTable)
|
.update(volumesTable)
|
||||||
.set({ lastHealthCheck: Date.now(), status, lastError: error ?? null })
|
.set({ lastHealthCheck: Date.now(), status, lastError: error ?? null })
|
||||||
|
|||||||
Reference in New Issue
Block a user