mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
LFS: pairing 1
This commit is contained in:
@@ -4,6 +4,7 @@ import { Box, Button, SvgIcon } from '@mui/joy';
|
||||
import UploadFileRoundedIcon from '@mui/icons-material/UploadFileRounded';
|
||||
|
||||
import { TooltipOutlined } from '~/common/components/TooltipOutlined';
|
||||
import { getDataTransferFilesOrPromises } from '~/common/util/fileSystemUtils';
|
||||
import { useDragDropDataTransfer } from '~/common/components/useDragDropDataTransfer';
|
||||
|
||||
import { LiveFileChooseIcon, LiveFileIcon } from './liveFile.icons';
|
||||
@@ -11,16 +12,30 @@ import { LiveFileChooseIcon, LiveFileIcon } from './liveFile.icons';
|
||||
|
||||
export function LiveFileSyncButton(props: {
|
||||
disabled: boolean;
|
||||
hasContent: boolean;
|
||||
isPaired: boolean;
|
||||
isRead: boolean;
|
||||
handleSyncButtonClicked: () => void;
|
||||
onPairWithFSFHandle: (fsHandle: FileSystemFileHandle) => Promise<any>;
|
||||
onPairWithPicker: () => Promise<void>;
|
||||
upUpdateFileContent: () => void;
|
||||
}) {
|
||||
|
||||
const { onPairWithFSFHandle } = props;
|
||||
|
||||
const handleDataTransfer = React.useCallback(async (dataTransfer: DataTransfer) => {
|
||||
// get FileSystemFileHandle objects from the DataTransfer
|
||||
const fileOrFSHandlePromises = getDataTransferFilesOrPromises(dataTransfer.items, false);
|
||||
if (!fileOrFSHandlePromises.length)
|
||||
return;
|
||||
|
||||
|
||||
console.log('LiveFileSyncButton: handleDataTransfer', dataTransfer);
|
||||
}, []);
|
||||
// resolve the promises to get the actual files/handles
|
||||
const filesOrHandles = await Promise.all(fileOrFSHandlePromises);
|
||||
for (let filesOrHandle of filesOrHandles) {
|
||||
if (!(filesOrHandle instanceof File) && filesOrHandle?.kind === 'file' && filesOrHandle) {
|
||||
await onPairWithFSFHandle(filesOrHandle);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}, [onPairWithFSFHandle]);
|
||||
|
||||
const {
|
||||
dragContainerSx,
|
||||
@@ -38,27 +53,27 @@ export function LiveFileSyncButton(props: {
|
||||
|
||||
<TooltipOutlined
|
||||
title={
|
||||
props.isRead ? 'Click to reload the File and compare.'
|
||||
props.hasContent ? 'Click to reload the File and compare.'
|
||||
: props.isPaired ? 'Click to compare with the File contents.'
|
||||
: 'Setup LiveFile pairing.'
|
||||
}
|
||||
color={props.isRead ? 'primary' : 'success'}
|
||||
variant={props.isRead ? undefined : 'solid'}
|
||||
color={props.hasContent ? 'primary' : 'success'}
|
||||
variant={props.hasContent ? undefined : 'solid'}
|
||||
>
|
||||
<Button
|
||||
variant='soft'
|
||||
color={props.isRead ? 'primary' : 'success'}
|
||||
color={props.hasContent ? 'primary' : 'success'}
|
||||
size='sm'
|
||||
disabled={props.disabled}
|
||||
onClick={props.handleSyncButtonClicked}
|
||||
onClick={props.isPaired ? props.upUpdateFileContent : props.onPairWithPicker}
|
||||
startDecorator={
|
||||
props.isRead ? <LiveFileIcon />
|
||||
props.hasContent ? <LiveFileIcon />
|
||||
: (props.isPaired ? <LiveFileIcon />
|
||||
: <LiveFileChooseIcon />)
|
||||
}
|
||||
aria-label={props.isPaired ? 'Sync File' : 'Choose File'}
|
||||
>
|
||||
{props.isRead ? 'Refresh'
|
||||
{props.hasContent ? 'Refresh'
|
||||
: props.isPaired ? 'Sync File'
|
||||
: 'Pair File'}
|
||||
</Button>
|
||||
|
||||
@@ -16,7 +16,6 @@ import { useLiveFile } from './liveFile.hooks';
|
||||
import { LiveFileSyncButton } from '~/common/livefile/LiveFileSyncButton';
|
||||
|
||||
|
||||
|
||||
interface DiffSummary {
|
||||
insertions: number;
|
||||
deletions: number;
|
||||
@@ -130,33 +129,28 @@ export function useLiveFileComparison(
|
||||
}
|
||||
}, [fileHasContent, isLoadingFile, reloadFileContent]);
|
||||
|
||||
const handlePairNewFileWithPicker = React.useCallback(async () => {
|
||||
// Open the file picker
|
||||
const fileWithHandle = await fileOpen({ description: 'Select a File to pair to this document' }).catch(() => null /* The User closed the files picker */);
|
||||
if (!fileWithHandle)
|
||||
return;
|
||||
if (!fileWithHandle.handle) {
|
||||
setStatus({ message: 'Browser does not support LiveFile operations.', mtype: 'error' });
|
||||
return;
|
||||
}
|
||||
|
||||
const handlePairNewFSFHandle = React.useCallback(async (fsfHandle: FileSystemFileHandle) => {
|
||||
// Pair the file: create a LiveFile, replace it in the Fragment, and load the preview
|
||||
try {
|
||||
const liveFileId = await liveFileCreateOrThrow(fileWithHandle.handle);
|
||||
const liveFileId = await liveFileCreateOrThrow(fsfHandle);
|
||||
replaceLiveFileId(liveFileId);
|
||||
// Immediately load the preview on this ID
|
||||
await handleUpdateFileContent(liveFileId);
|
||||
} catch (error: any) {
|
||||
setStatus({ message: `Error pairing the file: ${error?.message || typeof error === 'string' ? error : 'Unknown error'}`, mtype: 'error' });
|
||||
}
|
||||
}, [replaceLiveFileId, handleUpdateFileContent]);
|
||||
}, [handleUpdateFileContent, replaceLiveFileId]);
|
||||
|
||||
const handleSyncButtonClicked = React.useCallback(async () => {
|
||||
if (isPairingValid)
|
||||
await handleUpdateFileContent();
|
||||
const handlePairNewFileWithPicker = React.useCallback(async () => {
|
||||
// Open the file picker
|
||||
const fileWithHandle = await fileOpen({ description: 'Select a File to pair to this document' }).catch(() => null /* The User closed the files picker */);
|
||||
if (!fileWithHandle)
|
||||
return;
|
||||
if (fileWithHandle.handle)
|
||||
await handlePairNewFSFHandle(fileWithHandle.handle);
|
||||
else
|
||||
await handlePairNewFileWithPicker();
|
||||
}, [handlePairNewFileWithPicker, handleUpdateFileContent, isPairingValid]);
|
||||
setStatus({ message: 'Browser does not support LiveFile operations.', mtype: 'error' });
|
||||
}, [handlePairNewFSFHandle]);
|
||||
|
||||
|
||||
// Save and Load from Disk
|
||||
@@ -188,10 +182,12 @@ export function useLiveFileComparison(
|
||||
<LiveFileSyncButton
|
||||
disabled={isSavingFile}
|
||||
isPaired={isPairingValid}
|
||||
isRead={fileHasContent}
|
||||
handleSyncButtonClicked={handleSyncButtonClicked}
|
||||
hasContent={fileHasContent}
|
||||
onPairWithFSFHandle={handlePairNewFSFHandle}
|
||||
onPairWithPicker={handlePairNewFileWithPicker}
|
||||
upUpdateFileContent={handleUpdateFileContent}
|
||||
/>
|
||||
), [fileHasContent, handleSyncButtonClicked, isPairingValid, isSavingFile]);
|
||||
), [fileHasContent, handlePairNewFSFHandle, handlePairNewFileWithPicker, handleUpdateFileContent, isPairingValid, isSavingFile]);
|
||||
|
||||
const liveFileActionBox = React.useMemo(() => {
|
||||
if (!status && !fileHasContent) return null;
|
||||
|
||||
Reference in New Issue
Block a user