| import { useCallback, useEffect, useState } from "react"; |
| import { useApi } from "@/contexts/ApiContext"; |
| import { isHostedSpace } from "@/lib/isHostedSpace"; |
|
|
| export interface UpdateStatus { |
| update_available: boolean; |
| current_commit: string | null; |
| latest_commit: string | null; |
| commits_behind: number | null; |
| compare_url: string | null; |
| update_command: string | null; |
| can_auto_update: boolean; |
| } |
|
|
| |
| |
| |
| const DISMISS_KEY = "lelab:update-dismissed-sha"; |
|
|
| interface UseUpdateCheckResult { |
| status: UpdateStatus | null; |
| open: boolean; |
| |
| dismiss: (dontAskAgain: boolean) => void; |
| } |
|
|
| |
| |
| |
| |
| |
| export function useUpdateCheck(): UseUpdateCheckResult { |
| const { baseUrl, fetchWithHeaders } = useApi(); |
| const [status, setStatus] = useState<UpdateStatus | null>(null); |
| const [open, setOpen] = useState(false); |
|
|
| useEffect(() => { |
| if (isHostedSpace()) return; |
| let cancelled = false; |
| fetchWithHeaders(`${baseUrl}/system/update-check`) |
| .then((r) => (r.ok ? r.json() : null)) |
| .then((data: UpdateStatus | null) => { |
| if (cancelled || !data || !data.update_available) return; |
| let dismissed: string | null = null; |
| try { |
| dismissed = localStorage.getItem(DISMISS_KEY); |
| } catch { |
| |
| } |
| if (dismissed && dismissed === data.latest_commit) return; |
| setStatus(data); |
| setOpen(true); |
| }) |
| .catch(() => { |
| |
| }); |
| return () => { |
| cancelled = true; |
| }; |
| }, [baseUrl, fetchWithHeaders]); |
|
|
| const dismiss = useCallback( |
| (dontAskAgain: boolean) => { |
| if (dontAskAgain && status?.latest_commit) { |
| try { |
| localStorage.setItem(DISMISS_KEY, status.latest_commit); |
| } catch { |
| |
| } |
| } |
| setOpen(false); |
| }, |
| [status] |
| ); |
|
|
| return { status, open, dismiss }; |
| } |
|
|