mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
Flash: enable saving images too
This commit is contained in:
@@ -8,7 +8,7 @@ import ClearAllIcon from '@mui/icons-material/ClearAll';
|
||||
import ErrorIcon from '@mui/icons-material/Error';
|
||||
import InfoIcon from '@mui/icons-material/Info';
|
||||
import NotificationsActiveIcon from '@mui/icons-material/NotificationsActive';
|
||||
import WarningIcon from '@mui/icons-material/Warning';
|
||||
import WarningRoundedIcon from '@mui/icons-material/WarningRounded';
|
||||
|
||||
import { GoodModal } from '~/common/components/modals/GoodModal';
|
||||
|
||||
@@ -25,7 +25,7 @@ function _getLogLevelIcon(level: LogLevel) {
|
||||
case 'info':
|
||||
return <InfoIcon fontSize='small' color='info' />;
|
||||
case 'warn':
|
||||
return <WarningIcon fontSize='small' color='warning' />;
|
||||
return <WarningRoundedIcon fontSize='small' color='warning' />;
|
||||
case 'error':
|
||||
return <ErrorIcon fontSize='small' color='error' />;
|
||||
case 'critical':
|
||||
|
||||
@@ -3,11 +3,12 @@
|
||||
import * as React from 'react';
|
||||
import { fileOpen, fileSave, FileWithHandle } from 'browser-fs-access';
|
||||
|
||||
import { Box, Button, Divider, Sheet, Typography } from '@mui/joy';
|
||||
import { Box, Button, Divider, FormControl, FormLabel, Sheet, Switch, Typography } from '@mui/joy';
|
||||
import DownloadIcon from '@mui/icons-material/Download';
|
||||
import DoneIcon from '@mui/icons-material/Done';
|
||||
import ErrorIcon from '@mui/icons-material/Error';
|
||||
import RestoreIcon from '@mui/icons-material/Restore';
|
||||
import WarningRoundedIcon from '@mui/icons-material/WarningRounded';
|
||||
|
||||
import { GoodModal } from '~/common/components/modals/GoodModal';
|
||||
import { Is } from '~/common/util/pwaUtils';
|
||||
@@ -444,6 +445,7 @@ async function saveFlashObjectOrThrow(backupType: 'full' | 'auto-before-restore'
|
||||
.then((flashString) => {
|
||||
logger.info(`Expected flash file size: ${flashString.length.toLocaleString()} bytes`);
|
||||
downloadBlob(new Blob([flashString], { type: 'application/json' }), saveToFileName);
|
||||
return undefined;
|
||||
});
|
||||
|
||||
// for mobile, try a different implementation, with streaming creation, to hopefully avoid truncation
|
||||
@@ -464,7 +466,7 @@ async function saveFlashObjectOrThrow(backupType: 'full' | 'auto-before-restore'
|
||||
resolve(new Blob([flashString], { type: 'application/json' }));
|
||||
});
|
||||
|
||||
await fileSave(flashBlobPromise, {
|
||||
return await fileSave(flashBlobPromise, {
|
||||
description: BACKUP_FILE_FORMAT,
|
||||
extensions: ['.agi.json', '.json'],
|
||||
fileName: saveToFileName,
|
||||
@@ -774,6 +776,7 @@ export function FlashBackup(props: {
|
||||
}) {
|
||||
|
||||
// state
|
||||
const [includeImages, setIncludeImages] = React.useState(false);
|
||||
const [backupState, setBackupState] = React.useState<'idle' | 'processing' | 'success' | 'error'>('idle');
|
||||
const [errorMessage, setErrorMessage] = React.useState<string | null>(null);
|
||||
|
||||
@@ -789,13 +792,13 @@ export function FlashBackup(props: {
|
||||
try {
|
||||
onStartedBackup?.();
|
||||
const dateStr = new Date().toISOString().split('.')[0].replace('T', '-');
|
||||
await saveFlashObjectOrThrow(
|
||||
const success = await saveFlashObjectOrThrow(
|
||||
'full',
|
||||
event.ctrlKey, // control forces a traditional browser download - default: fileSave
|
||||
event.shiftKey, // shift adds images - default: no images
|
||||
`Big-AGI-flash${event.shiftKey ? '+images' : ''}${event.ctrlKey ? '-download' : ''}-${dateStr}.json`,
|
||||
includeImages,
|
||||
`Big-AGI-flash${includeImages ? '+images' : ''}${event.ctrlKey ? '-download' : ''}-${dateStr}.json`,
|
||||
);
|
||||
setBackupState('success');
|
||||
setBackupState(success ? 'success' : 'idle');
|
||||
} catch (error: any) {
|
||||
if (error?.name === 'AbortError') {
|
||||
// the user has closed the file picker, most likely - do nothing
|
||||
@@ -806,12 +809,12 @@ export function FlashBackup(props: {
|
||||
setErrorMessage(`Backup failed: ${_getErrorText(error)}`);
|
||||
}
|
||||
}
|
||||
}, [onStartedBackup]);
|
||||
}, [includeImages, onStartedBackup]);
|
||||
|
||||
|
||||
return <>
|
||||
|
||||
<Typography level='body-sm' mt={{ xs: 3, md: 5 }}>
|
||||
<Typography level='body-sm' mt={3}>
|
||||
Save <strong>all settings and chats</strong>:
|
||||
</Typography>
|
||||
<Button
|
||||
@@ -831,14 +834,15 @@ export function FlashBackup(props: {
|
||||
>
|
||||
{backupState === 'success' ? 'Backup Saved' : backupState === 'error' ? 'Backup Failed' : isProcessing ? 'Backing Up...' : 'Export All'}
|
||||
</Button>
|
||||
{!errorMessage && <Typography level='body-xs'>
|
||||
<Box component='span' sx={{ display: { xs: 'none', md: 'block' } }}>
|
||||
Shift + Click to include images
|
||||
</Box>
|
||||
<Box component='span' sx={{ display: { xs: 'block', md: 'none' } }}>
|
||||
Excludes image binary data
|
||||
</Box>
|
||||
</Typography>}
|
||||
{!errorMessage && <>
|
||||
<FormControl orientation='horizontal' sx={{ justifyContent: 'space-between', alignItems: 'center', ml: 2, mr: 1.25, mt: 0.25 }}>
|
||||
<FormLabel sx={{ fontWeight: 'md' }}>Include Binary Images</FormLabel>
|
||||
<Switch size='sm' color={includeImages ? 'danger' : undefined} checked={includeImages} onChange={(event) => setIncludeImages(event.target.checked)} />
|
||||
</FormControl>
|
||||
{includeImages && <Typography level='body-xs' color='danger' ml={2} endDecorator={<WarningRoundedIcon />}>
|
||||
Files too large may get corrupted.
|
||||
</Typography>}
|
||||
</>}
|
||||
|
||||
{errorMessage && (
|
||||
<Sheet variant='soft' color='danger' sx={{ px: 1.5, py: 1, borderRadius: 'sm', display: 'grid', gap: 1 }}>
|
||||
|
||||
Reference in New Issue
Block a user