mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-11 04:07:44 +02:00
[eric] disable Restart & Update button after click with loading state
This commit is contained in:
@@ -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>
|
||||
|
||||
@@ -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 & Update
|
||||
{installing ? 'Restarting…' : 'Restart & Update'}
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user