[eric] disable Restart & Update button after click with loading state

This commit is contained in:
ciregenz
2026-04-07 23:25:55 -07:00
parent 4f50fc2236
commit f5dd6b0cf8
4 changed files with 33 additions and 7 deletions
@@ -29,6 +29,7 @@ import RestartAltIcon from '@mui/icons-material/RestartAlt';
import SystemUpdateAltIcon from '@mui/icons-material/SystemUpdateAlt';
import CloseIcon from '@mui/icons-material/Close';
import LinearProgress from '@mui/material/LinearProgress';
import CircularProgress from '@mui/material/CircularProgress';
import Settings from '@/app/pages/Settings/Settings';
import DynamicIsland from '@/app/components/DynamicIsland';
import Dashboard from '@/app/pages/Dashboard/Dashboard';
@@ -39,6 +40,7 @@ import { fetchDashboards, createDashboard, renameDashboard } from '@/shared/stat
import { addBrowserCard, addBrowserTab } from '@/shared/state/dashboardLayoutSlice';
import { setPendingBrowserUrl } from '@/shared/state/tempStateSlice';
import { fetchOutputs } from '@/shared/state/outputsSlice';
import { setInstalling } from '@/shared/state/updateSlice';
import { findBrowserByWebContentsId } from '@/shared/browserRegistry';
import { useClaudeTokens } from '@/shared/styles/ThemeContext';
@@ -84,6 +86,7 @@ const AppShell: React.FC = () => {
const updateStatus = useAppSelector((state) => state.update.status);
const availableVersion = useAppSelector((state) => state.update.availableVersion);
const downloadPercent = useAppSelector((state) => state.update.downloadPercent);
const installing = useAppSelector((state) => state.update.installing);
const [dismissedVersion, setDismissedVersion] = useState<string | null>(() => {
try { return localStorage.getItem(UPDATE_DISMISS_KEY); } catch { return null; }
@@ -109,8 +112,10 @@ const AppShell: React.FC = () => {
}, []);
const handleInstallUpdate = useCallback(() => {
if (installing) return;
dispatch(setInstalling());
(window as any).openswarm?.installUpdate();
}, []);
}, [installing, dispatch]);
const dashboardItems = useAppSelector((state) => state.dashboards.items);
const dashboardList = Object.values(dashboardItems).sort(
@@ -454,9 +459,12 @@ const AppShell: React.FC = () => {
size="small"
variant="contained"
onClick={handleInstallUpdate}
disabled={installing}
startIcon={installing ? <CircularProgress size={12} sx={{ color: '#fff' }} /> : undefined}
sx={{
bgcolor: c.accent.primary,
'&:hover': { bgcolor: c.accent.pressed },
'&.Mui-disabled': { bgcolor: c.accent.primary, color: '#fff', opacity: 0.7 },
textTransform: 'none',
fontSize: '0.75rem',
fontWeight: 600,
@@ -468,7 +476,7 @@ const AppShell: React.FC = () => {
flexShrink: 0,
}}
>
Restart & Update
{installing ? 'Restarting…' : 'Restart & Update'}
</Button>
)}
<IconButton
@@ -1002,16 +1010,19 @@ const AppShell: React.FC = () => {
size="small"
variant="contained"
onClick={handleInstallUpdate}
disabled={installing}
startIcon={installing ? <CircularProgress size={12} sx={{ color: '#fff' }} /> : undefined}
sx={{
bgcolor: c.accent.primary,
'&:hover': { bgcolor: c.accent.pressed },
'&.Mui-disabled': { bgcolor: c.accent.primary, color: '#fff', opacity: 0.7 },
textTransform: 'none',
fontSize: '0.8rem',
borderRadius: 1.5,
minWidth: 'auto',
}}
>
Restart & Update
{installing ? 'Restarting…' : 'Restart & Update'}
</Button>
)}
</Box>
+10 -3
View File
@@ -41,7 +41,7 @@ import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { useAppDispatch, useAppSelector } from '@/shared/hooks';
import { updateSettings, closeSettingsModal, resetSystemPrompt, AppSettings, DEFAULT_SYSTEM_PROMPT } from '@/shared/state/settingsSlice';
import { fetchModels } from '@/shared/state/modelsSlice';
import { setChecking, setUpdateError } from '@/shared/state/updateSlice';
import { setChecking, setUpdateError, setInstalling } from '@/shared/state/updateSlice';
import { fetchModes } from '@/shared/state/modesSlice';
import { useClaudeTokens, useThemeMode } from '@/shared/styles/ThemeContext';
import DirectoryBrowser from '@/app/components/DirectoryBrowser';
@@ -716,6 +716,7 @@ const Settings: React.FC = () => {
const availableVersion = useAppSelector((s) => s.update.availableVersion);
const downloadPercent = useAppSelector((s) => s.update.downloadPercent);
const updateError = useAppSelector((s) => s.update.error);
const installing = useAppSelector((s) => s.update.installing);
const [activeTab, setActiveTab] = useState<'general' | 'models' | 'usage' | 'commands'>('general');
const [form, setForm] = useState<AppSettings>({ ...settings });
@@ -763,6 +764,8 @@ const Settings: React.FC = () => {
};
const handleInstallUpdate = () => {
if (installing) return;
dispatch(setInstalling());
(window as any).openswarm?.installUpdate();
};
@@ -1358,17 +1361,21 @@ const Settings: React.FC = () => {
variant="contained"
size="small"
onClick={handleInstallUpdate}
startIcon={<RestartAltIcon sx={{ fontSize: 15 }} />}
disabled={installing}
startIcon={installing
? <CircularProgress size={14} sx={{ color: '#fff' }} />
: <RestartAltIcon sx={{ fontSize: 15 }} />}
sx={{
bgcolor: c.accent.primary,
'&:hover': { bgcolor: c.accent.pressed },
'&.Mui-disabled': { bgcolor: c.accent.primary, color: '#fff', opacity: 0.7 },
textTransform: 'none',
fontSize: '0.8rem',
whiteSpace: 'nowrap',
borderRadius: 1.5,
}}
>
Restart &amp; Update
{installing ? 'Restarting…' : 'Restart & Update'}
</Button>
)}
</Box>
+8
View File
@@ -15,6 +15,7 @@ interface UpdateState {
availableVersion: string | null;
downloadPercent: number;
error: string | null;
installing: boolean;
}
const initialState: UpdateState = {
@@ -23,6 +24,7 @@ const initialState: UpdateState = {
availableVersion: null,
downloadPercent: 0,
error: null,
installing: false,
};
const updateSlice = createSlice({
@@ -56,11 +58,16 @@ const updateSlice = createSlice({
setUpdateError(state, action: PayloadAction<string>) {
state.status = 'error';
state.error = action.payload;
state.installing = false;
},
setInstalling(state) {
state.installing = true;
},
resetUpdateStatus(state) {
state.status = 'idle';
state.error = null;
state.downloadPercent = 0;
state.installing = false;
},
},
});
@@ -73,6 +80,7 @@ export const {
setDownloading,
setUpdateDownloaded,
setUpdateError,
setInstalling,
resetUpdateStatus,
} = updateSlice.actions;
File diff suppressed because one or more lines are too long