feat: implement update management system with new update store and UI components

This commit is contained in:
Bohdan Triapitsyn
2025-12-20 01:04:32 +02:00
parent 5982767bdf
commit 79ed6abab7
8 changed files with 317 additions and 288 deletions
+10 -2
View File
@@ -7,6 +7,7 @@ import {
import { RiChat4Line, RiCodeLine, RiCommandLine, RiGitBranchLine, RiLayoutLeftLine, RiPlayListAddLine, RiQuestionLine, RiSettings3Line, RiTerminalBoxLine, type RemixiconComponentType } from '@remixicon/react';
import { useUIStore, type MainTab } from '@/stores/useUIStore';
import { useUpdateStore } from '@/stores/useUpdateStore';
import { useConfigStore } from '@/stores/useConfigStore';
import { useSessionStore } from '@/stores/useSessionStore';
import { ContextUsageDisplay } from '@/components/ui/ContextUsageDisplay';
@@ -95,6 +96,7 @@ export const Header: React.FC = () => {
const getContextUsage = useSessionStore((state) => state.getContextUsage);
const { isMobile } = useDeviceInfo();
const diffFileCount = useDiffFileCount();
const updateAvailable = useUpdateStore((state) => state.available);
const headerRef = React.useRef<HTMLElement | null>(null);
@@ -491,13 +493,19 @@ export const Header: React.FC = () => {
type="button"
onClick={handleOpenSettings}
aria-label="Open settings"
className={headerIconButtonClass}
className={cn(headerIconButtonClass, 'relative')}
>
<RiSettings3Line className="h-5 w-5" />
{updateAvailable && (
<span
className="absolute top-1.5 right-1.5 h-2 w-2 rounded-full bg-primary"
aria-label="Update available"
/>
)}
</button>
</TooltipTrigger>
<TooltipContent>
<p>Settings</p>
<p>{updateAvailable ? 'Settings (Update available)' : 'Settings'}</p>
</TooltipContent>
</Tooltip>
</div>
@@ -11,6 +11,7 @@ import { MobileOverlayPanel } from '@/components/ui/MobileOverlayPanel';
import { DiffWorkerProvider } from '@/contexts/DiffWorkerProvider';
import { useUIStore } from '@/stores/useUIStore';
import { useUpdateStore } from '@/stores/useUpdateStore';
import { useDeviceInfo } from '@/lib/device';
import { useEdgeSwipe } from '@/hooks/useEdgeSwipe';
import { cn } from '@/lib/utils';
@@ -44,6 +45,15 @@ export const MainLayout: React.FC = () => {
useEdgeSwipe({ enabled: true });
// Trigger update check 3 seconds after mount (for both mobile and desktop)
const checkForUpdates = useUpdateStore((state) => state.checkForUpdates);
React.useEffect(() => {
const timer = setTimeout(() => {
checkForUpdates();
}, 3000);
return () => clearTimeout(timer);
}, [checkForUpdates]);
React.useEffect(() => {
const previous = useUIStore.getState().isMobile;
if (previous !== isMobile) {
+12 -12
View File
@@ -4,7 +4,7 @@ import { toast } from 'sonner';
import { cn } from '@/lib/utils';
import { ErrorBoundary } from '../ui/ErrorBoundary';
import { useUIStore } from '@/stores/useUIStore';
import { useUpdateCheck } from '@/hooks/useUpdateCheck';
import { useUpdateStore } from '@/stores/useUpdateStore';
import { UpdateDialog } from '../ui/UpdateDialog';
import { Tooltip, TooltipContent, TooltipTrigger } from '../ui/tooltip';
@@ -27,11 +27,11 @@ export const Sidebar: React.FC<SidebarProps> = ({ isOpen, isMobile, children })
const startWidthRef = React.useRef(sidebarWidth || SIDEBAR_CONTENT_WIDTH);
const [updateDialogOpen, setUpdateDialogOpen] = React.useState(false);
const update = useUpdateCheck();
const updateStore = useUpdateStore();
const pendingMenuUpdateCheckRef = React.useRef(false);
const checkForUpdates = update.checkForUpdates;
const { available, downloaded, checking } = update;
const checkForUpdates = updateStore.checkForUpdates;
const { available, downloaded, checking } = updateStore;
const [isDesktopApp, setIsDesktopApp] = React.useState<boolean>(() => {
if (typeof window === 'undefined') {
@@ -267,14 +267,14 @@ export const Sidebar: React.FC<SidebarProps> = ({ isOpen, isMobile, children })
<UpdateDialog
open={updateDialogOpen}
onOpenChange={setUpdateDialogOpen}
info={update.info}
downloading={update.downloading}
downloaded={update.downloaded}
progress={update.progress}
error={update.error}
onDownload={update.downloadUpdate}
onRestart={update.restartToUpdate}
runtimeType={update.runtimeType}
info={updateStore.info}
downloading={updateStore.downloading}
downloaded={updateStore.downloaded}
progress={updateStore.progress}
error={updateStore.error}
onDownload={updateStore.downloadUpdate}
onRestart={updateStore.restartToUpdate}
runtimeType={updateStore.runtimeType}
/>
</div>
</aside>