import React, { ReactElement } from 'react'; import { useAppDispatch, useAppSelector } from '../store/hooks'; import { isDev } from '../shared/utils'; import { cleanupAsync, isDesynced, updateWindowsAsync } from '../store/windowsSlice'; import { useLiveQuery } from 'dexie-react-hooks'; import { getBackupEveryNSeconds, getIsBackupOverdue, getLatestBackup, getTabvanaWindowId } from '../db/prefs'; import { requestBackupPermission, setBackupDir, maybeBackup } from '../db/backup'; import { faArrowsRotate, faBroom, faGear, faPlugCircleBolt } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { openOptionsPageInWindow } from '../chrome/chromeActions'; import IconButton from '@mui/joy/IconButton'; import { Button, CircularProgress, Tooltip } from '@mui/joy'; import { useActiveProgress, clearAllProgress, useCompletedProgress } from '../db/progress'; import { clearQueue } from '../db/queue'; const GlobalButtons = React.memo((): ReactElement => { const tabvanaWindowId = useLiveQuery(getTabvanaWindowId); const isBackupOverdue = useLiveQuery(getIsBackupOverdue); const { totalWork, completedWork, activeTasks, operations } = useActiveProgress(); const completedProgressTasks = useCompletedProgress(); const dispatch = useAppDispatch(); const desynced = useAppSelector(isDesynced); const working = activeTasks > 0; const handleCancelTasks = async () => { await clearQueue(); await clearAllProgress(); }; const tooltipContent = (
{operations.length > 0 ? ( <>
Total: {completedWork} / {totalWork}
{Object.entries( operations.reduce((acc, op) => { if (!acc[op.type]) acc[op.type] = { current: 0, total: 0 }; acc[op.type].current += op.current; acc[op.type].total += op.total; return acc; }, {} as Record) ).map(([type, stats]) => { const label = type === 'generateEmbedding' ? 'Generating embeddings' : type === 'backup' ? 'Backup in progress' : type === 'renormalize' ? 'Renormalizing database' : type === 'similarity' ? 'Calculating similarities' : type.charAt(0).toUpperCase() + type.slice(1); return (
{label}: {stats.current} / {stats.total}
); })} ) : (
No active background tasks
)} {completedProgressTasks.length > 0 && ( <>
Completed Tasks ({completedProgressTasks.length})
{completedProgressTasks.map((op, i) => { const label = op.type === 'generateEmbedding' ? 'Generated embeddings' : op.type === 'backup' ? 'Backup completed' : op.type === 'renormalize' ? 'Renormalized database' : op.type === 'similarity' ? 'Calculated similarities' : op.type.charAt(0).toUpperCase() + op.type.slice(1) + ' completed'; return (
{label} ({op.total})
); })} )}
); return (
0} value={activeTasks === 0 ? 0 : (totalWork > 0 ? (completedWork / totalWork) * 100 : undefined)} color={activeTasks > 0 ? 'primary' : 'neutral'} sx={{ verticalAlign: 'middle', margin: '0.2rem', ...(activeTasks > 0 && { animation: 'pulse 1.5s ease-in-out infinite', '@keyframes pulse': { '0%': { opacity: 0.6 }, '50%': { opacity: 1 }, '100%': { opacity: 0.6 }, }, }), }} > {/* totalWork > 0 && {Math.round((completedWork / totalWork) * 100)}% */} {isBackupOverdue && ( )} {desynced && ( )} {isDev && ( chrome.runtime.reload()} title="Reload Extension"> )} { dispatch(cleanupAsync(tabvanaWindowId)); }} title="Clean Up" /> openOptionsPageInWindow()} title="Settings" />
); }); export default GlobalButtons;