|
|
import { Alert, CssBaseline, Snackbar, ThemeProvider } from "@mui/material"; |
|
|
import { useCallback, useEffect, useState } from "react"; |
|
|
|
|
|
|
|
|
import { DemoView } from "./components/DemoView"; |
|
|
import { InitialForm } from "./components/InitialForm"; |
|
|
import { CustomThemeProvider, useThemeMode } from "./contexts/ThemeContext"; |
|
|
import { FormData, SnackbarState, UserInfo } from "./types"; |
|
|
import { preloadDefaultMcp } from "./utils/api"; |
|
|
import { useStartDemo } from "./hooks/useStartDemo"; |
|
|
|
|
|
const AppContent = () => { |
|
|
const { theme } = useThemeMode(); |
|
|
|
|
|
|
|
|
const [userInfo, setUserInfo] = useState<UserInfo | null>(null); |
|
|
const [accessToken, setAccessToken] = useState<string | null>(null); |
|
|
const [loginLabel, setLoginLabel] = useState<string>( |
|
|
"Login with Hugging Face", |
|
|
); |
|
|
|
|
|
|
|
|
const [formData, setFormData] = useState<FormData>({ |
|
|
model: "", |
|
|
provider: "", |
|
|
mcpFile: null, |
|
|
}); |
|
|
|
|
|
|
|
|
const [snackbar, setSnackbar] = useState<SnackbarState>({ |
|
|
open: false, |
|
|
message: "", |
|
|
severity: "info", |
|
|
}); |
|
|
const [defaultMcpFile, setDefaultMcpFile] = useState<File | null>(null); |
|
|
|
|
|
|
|
|
const { |
|
|
isStarting, |
|
|
iframeUrl, |
|
|
iframeLoading, |
|
|
healthCheckProgress, |
|
|
startDemoSession, |
|
|
resetDemo, |
|
|
setIframeLoaded, |
|
|
} = useStartDemo(); |
|
|
|
|
|
|
|
|
const isDemoActive = Boolean(iframeUrl); |
|
|
|
|
|
|
|
|
const showSnackbar = useCallback( |
|
|
(message: string, severity: "success" | "error" | "info" = "info") => { |
|
|
setSnackbar({ open: true, message, severity }); |
|
|
}, |
|
|
[], |
|
|
); |
|
|
|
|
|
const handleSnackbarClose = () => { |
|
|
setSnackbar((prev: SnackbarState) => ({ ...prev, open: false })); |
|
|
}; |
|
|
|
|
|
const handleIframeLoad = () => { |
|
|
setIframeLoaded(); |
|
|
}; |
|
|
|
|
|
|
|
|
const handleLoginStateChange = useCallback( |
|
|
( |
|
|
newUserInfo: UserInfo | null, |
|
|
newAccessToken: string | null, |
|
|
newLoginLabel: string, |
|
|
) => { |
|
|
setUserInfo(newUserInfo); |
|
|
setAccessToken(newAccessToken); |
|
|
setLoginLabel(newLoginLabel); |
|
|
}, |
|
|
[], |
|
|
); |
|
|
|
|
|
|
|
|
const handleFormChange = (newFormData: FormData) => { |
|
|
setFormData(newFormData); |
|
|
}; |
|
|
|
|
|
const handleFormSubmit = async () => { |
|
|
await startDemoSession(formData, loginLabel, accessToken, { |
|
|
logPrefix: "Initial startup", |
|
|
onError: (error) => { |
|
|
showSnackbar(error.message, "error"); |
|
|
}, |
|
|
}); |
|
|
}; |
|
|
|
|
|
const handleRestart = () => { |
|
|
resetDemo(); |
|
|
}; |
|
|
|
|
|
const handleSettingsRestart = async () => { |
|
|
await startDemoSession(formData, loginLabel, accessToken, { |
|
|
logPrefix: "Settings restart", |
|
|
onError: (error) => { |
|
|
showSnackbar(error.message, "error"); |
|
|
}, |
|
|
}); |
|
|
}; |
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
const loadDefaultMcp = async () => { |
|
|
const mcpFile = await preloadDefaultMcp(); |
|
|
if (mcpFile) { |
|
|
setFormData((prev: FormData) => ({ ...prev, mcpFile: mcpFile })); |
|
|
setDefaultMcpFile(mcpFile); |
|
|
} |
|
|
}; |
|
|
loadDefaultMcp(); |
|
|
}, []); |
|
|
|
|
|
return ( |
|
|
<ThemeProvider theme={theme}> |
|
|
<CssBaseline /> |
|
|
|
|
|
{/* Conditional rendering based on demo state */} |
|
|
{isDemoActive ? ( |
|
|
<DemoView |
|
|
iframeUrl={iframeUrl} |
|
|
iframeLoading={iframeLoading} |
|
|
healthCheckProgress={healthCheckProgress} |
|
|
formData={formData} |
|
|
onIframeLoad={handleIframeLoad} |
|
|
onRestart={handleRestart} |
|
|
onFormChange={handleFormChange} |
|
|
onSettingsRestart={handleSettingsRestart} |
|
|
defaultMcpFile={defaultMcpFile} |
|
|
/> |
|
|
) : ( |
|
|
<InitialForm |
|
|
formData={formData} |
|
|
userInfo={userInfo} |
|
|
accessToken={accessToken} |
|
|
loginLabel={loginLabel} |
|
|
isStarting={isStarting} |
|
|
onFormChange={handleFormChange} |
|
|
onSubmit={handleFormSubmit} |
|
|
onLoginStateChange={handleLoginStateChange} |
|
|
defaultMcpFile={defaultMcpFile} |
|
|
/> |
|
|
)} |
|
|
|
|
|
{/* Snackbar for notifications */} |
|
|
<Snackbar |
|
|
open={snackbar.open} |
|
|
autoHideDuration={4000} |
|
|
onClose={handleSnackbarClose} |
|
|
anchorOrigin={{ vertical: "bottom", horizontal: "center" }} |
|
|
> |
|
|
<Alert |
|
|
onClose={handleSnackbarClose} |
|
|
severity={snackbar.severity} |
|
|
sx={{ width: "100%" }} |
|
|
> |
|
|
{snackbar.message} |
|
|
</Alert> |
|
|
</Snackbar> |
|
|
</ThemeProvider> |
|
|
); |
|
|
}; |
|
|
|
|
|
function App() { |
|
|
return ( |
|
|
<CustomThemeProvider> |
|
|
<AppContent /> |
|
|
</CustomThemeProvider> |
|
|
); |
|
|
} |
|
|
|
|
|
export default App; |
|
|
|