import { useStore } from '@nanostores/react' import { Button } from '@/components/ui/button' import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from '@/components/ui/dropdown-menu' import { Tip } from '@/components/ui/tooltip' import { useI18n } from '@/i18n' import { ChevronDown, Download, Loader2, RefreshCw } from '@/lib/icons' import { useStoreSelector } from '@/lib/use-session-slice' import { cn } from '@/lib/utils' import { resolveVersionStatus } from '@/lib/version-status' import { $connection } from '@/store/session' import { $backendUpdateApply, $backendUpdateChecking, $backendUpdateStatus, $desktopVersion, $updateApply, $updateChecking, $updateStatus, openUpdateOverlayFor } from '@/store/updates' export interface SidebarVersionMenuProps { compact?: boolean } /** One entry for the existing desktop and remote-backend update flows. */ export function SidebarVersionMenu({ compact = false }: SidebarVersionMenuProps) { const { t } = useI18n() const copy = t.shell.statusbar const version = useStore($desktopVersion)?.appVersion const remote = useStoreSelector($connection, connection => connection?.mode === 'remote') const clientCheck = useStore($updateChecking) const clientApply = useStore($updateApply) const clientUpdate = useStore($updateStatus) const backendCheck = useStore($backendUpdateChecking) const backendApply = useStore($backendUpdateApply) const backendUpdate = useStore($backendUpdateStatus) const targets = [ { target: 'client' as const, version, checking: clientCheck, apply: clientApply, update: clientUpdate }, ...(remote ? [ { target: 'backend' as const, version: backendUpdate?.currentVersion, checking: backendCheck, apply: backendApply, update: backendUpdate } ] : []) ].map(entry => { const applying = entry.apply.applying || entry.apply.stage === 'restart' return { ...entry, applying, status: resolveVersionStatus({ applying, applyMessage: entry.apply.message, behind: entry.update?.behind ?? 0, branch: entry.update?.branch, copy, remote, restarting: entry.apply.stage === 'restart', sha: entry.update?.currentSha?.slice(0, 7), target: entry.target, updateAvailable: entry.update?.updateAvailable, version: entry.version }) } }) const busy = targets.some(entry => entry.applying || entry.checking) const available = targets.some(entry => entry.status.hasUpdate) return ( {targets.map((entry, index) => (
{index > 0 && } {entry.target === 'client' ? copy.desktopVersion(entry.version ?? copy.unknown) : copy.backendVersion(entry.version ?? copy.unknown)} {entry.target === 'client' && entry.status.detail && ( {copy.commit(entry.status.detail)} )} openUpdateOverlayFor(entry.target)}> {entry.applying || entry.checking ? ( ) : entry.status.hasUpdate ? ( ) : ( )} {entry.applying ? copy.updateInProgress : entry.checking ? t.updates.checking : entry.status.hasUpdate ? t.updates.updateNow : t.settings.about.checkNow}
))}
) }