mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
LiveFile: Reload: 👍
This commit is contained in:
+2
-2
@@ -4,7 +4,7 @@ import type { SxProps } from '@mui/joy/styles/types';
|
||||
import { Box, Button, ColorPaletteProp } from '@mui/joy';
|
||||
import AbcIcon from '@mui/icons-material/Abc';
|
||||
import CodeIcon from '@mui/icons-material/Code';
|
||||
import ExpandLessIcon from '@mui/icons-material/ExpandLess';
|
||||
import ExpandCircleDownIcon from '@mui/icons-material/ExpandCircleDown';
|
||||
import ImageOutlinedIcon from '@mui/icons-material/ImageOutlined';
|
||||
import PictureAsPdfIcon from '@mui/icons-material/PictureAsPdf';
|
||||
import TelegramIcon from '@mui/icons-material/Telegram';
|
||||
@@ -94,7 +94,7 @@ export function DocAttachmentFragmentButton(props: {
|
||||
|
||||
const buttonText = ellipsizeMiddle(fragment.part.l1Title || fragment.title || 'Document', 28 /* totally arbitrary length */);
|
||||
|
||||
const Icon = isSelected ? ExpandLessIcon : buttonIconForFragment(fragment);
|
||||
const Icon = isSelected ? ExpandCircleDownIcon : buttonIconForFragment(fragment);
|
||||
|
||||
return (
|
||||
<Button
|
||||
|
||||
+25
-17
@@ -11,6 +11,7 @@ import { AutoBlocksRenderer } from '~/modules/blocks/AutoBlocksRenderer';
|
||||
import type { ContentScaling } from '~/common/app.theme';
|
||||
import type { DMessageRole } from '~/common/stores/chat/chat.message';
|
||||
import { LiveFileIcon } from '~/common/livefile/LiveFileIcon';
|
||||
import { addSnackbar } from '~/common/components/useSnackbarsStore';
|
||||
import { createDMessageDataInlineText, createDocAttachmentFragment, DMessageAttachmentFragment, DMessageFragmentId, isDocPart } from '~/common/stores/chat/chat.fragments';
|
||||
import { liveFileInAttachmentFragment } from '~/common/livefile/liveFile';
|
||||
import { marshallWrapText } from '~/common/stores/chat/chat.tokens';
|
||||
@@ -74,15 +75,9 @@ export function DocAttachmentFragmentEditor(props: {
|
||||
if (editedText === undefined)
|
||||
return;
|
||||
|
||||
// only edit DOCs
|
||||
if (!isDocPart(fragment.part)) {
|
||||
console.warn('handleEditApply: unexpected part type:', fragment.part.pt);
|
||||
return;
|
||||
}
|
||||
|
||||
if (editedText.length > 0) {
|
||||
const newData = createDMessageDataInlineText(editedText, fragment.part.data.mimeType);
|
||||
const newAttachment = createDocAttachmentFragment(fragmentTitle, fragment.caption, fragment.part.type, newData, fragment.part.ref, fragment.part.meta, fragment._liveFile);
|
||||
const newData = createDMessageDataInlineText(editedText, docPart.data.mimeType);
|
||||
const newAttachment = createDocAttachmentFragment(fragmentTitle, fragment.caption, docPart.type, newData, docPart.ref, docPart.meta, fragment._liveFile);
|
||||
// reuse the same fragment ID, which makes the screen not flash (otherwise the whole editor would disappear as the ID does not exist anymore)
|
||||
newAttachment.fId = fragmentId;
|
||||
onFragmentReplace(fragmentId, newAttachment);
|
||||
@@ -91,7 +86,7 @@ export function DocAttachmentFragmentEditor(props: {
|
||||
// if the user deleted all text, let's remove the part
|
||||
handleFragmentDelete();
|
||||
}
|
||||
}, [editedText, fragment._liveFile, fragment.caption, fragment.part, fragmentId, fragmentTitle, handleFragmentDelete, onFragmentReplace]);
|
||||
}, [docPart, editedText, fragment._liveFile, fragment.caption, fragmentId, fragmentTitle, handleFragmentDelete, onFragmentReplace]);
|
||||
|
||||
const handleToggleEdit = React.useCallback(() => {
|
||||
// reset other states when entering Edit
|
||||
@@ -110,20 +105,33 @@ export function DocAttachmentFragmentEditor(props: {
|
||||
const handleLiveFileReload = React.useCallback(async () => {
|
||||
if (!fileSystemFileHandle)
|
||||
return;
|
||||
console.log('handleLiveFileReload', fileSystemFileHandle);
|
||||
// TODO: ...reload the content of the file from disk and edit the current fragment (replace) - if we are here we don't need confimation
|
||||
|
||||
setIsLiveFileReloadArmed(false);
|
||||
setIsLiveFileReloading(true);
|
||||
|
||||
try {
|
||||
// ... (rest of the implementation)
|
||||
|
||||
setIsLiveFileReloading(false);
|
||||
// Read the file content
|
||||
const file = await fileSystemFileHandle.getFile();
|
||||
const reloadedText = await file.text();
|
||||
|
||||
} catch (error) {
|
||||
setIsLiveFileReloading(false);
|
||||
// Update the fragment
|
||||
const newData = createDMessageDataInlineText(reloadedText, docPart.data.mimeType);
|
||||
const newAttachment = createDocAttachmentFragment(fragmentTitle, fragment.caption, docPart.type, newData, docPart.ref, docPart.meta, fragment._liveFile);
|
||||
// reuse the same fragment ID, which makes the screen not flash (otherwise the whole editor would disappear as the ID does not exist anymore)
|
||||
newAttachment.fId = fragmentId;
|
||||
onFragmentReplace(fragmentId, newAttachment);
|
||||
|
||||
// signal the success
|
||||
addSnackbar({ key: 'chat-attachment-doc-reload-ok', message: 'Reloaded from the file system.', type: 'success', overrides: { autoHideDuration: 2000 } });
|
||||
|
||||
} catch (error: any) {
|
||||
addSnackbar({ key: 'chat-attachment-doc-reload-fail', message: `Error reloading the file: ${error?.message || error || 'error unknown.'}`, type: 'issue' });
|
||||
}
|
||||
|
||||
}, [fileSystemFileHandle]);
|
||||
setIsLiveFileReloading(false);
|
||||
|
||||
}, [docPart, fileSystemFileHandle, fragment._liveFile, fragment.caption, fragmentId, fragmentTitle, onFragmentReplace]);
|
||||
|
||||
const handleToggleLiveFileReloadArmed = React.useCallback((event: React.MouseEvent) => {
|
||||
// reset other states when entering LiveFileReload
|
||||
@@ -195,7 +203,7 @@ console.log('handleLiveFileReload', fileSystemFileHandle);
|
||||
{hasLiveFile && (
|
||||
<Box sx={{ display: 'flex', gap: 1 }}>
|
||||
<Button disabled={isEditing || isLiveFileReloading} variant={isLiveFileReloadArmed ? 'soft' : 'outlined'} color={DocSelColor} size='sm' onClick={handleToggleLiveFileReloadArmed} startDecorator={isLiveFileReloadArmed ? <CloseRoundedIcon /> : <LiveFileIcon />}>
|
||||
{isLiveFileReloadArmed ? 'Cancel' : 'Reload File'}
|
||||
{isLiveFileReloadArmed ? 'Cancel' : 'Sync File'}
|
||||
</Button>
|
||||
{isLiveFileReloadArmed && (
|
||||
<Button disabled={isLiveFileReloading} variant='solid' color='success' size='sm' onClick={handleLiveFileReload} startDecorator={<LiveFileIcon />}>
|
||||
|
||||
@@ -10,8 +10,8 @@ import type { DMessageId } from '~/common/stores/chat/chat.message';
|
||||
export type AttachmentDraft = {
|
||||
readonly id: AttachmentDraftId;
|
||||
readonly source: AttachmentDraftSource,
|
||||
label: string;
|
||||
ref: string; // will be used in ```ref\n...``` for instance - TODO: remove?
|
||||
label: string; // what's written in the button, such as a web page `title`
|
||||
ref: string; // will be used in ```ref\n...``` for instance the web page `url`
|
||||
|
||||
inputLoading: boolean;
|
||||
inputError: string | null;
|
||||
|
||||
@@ -45,9 +45,9 @@ export type DMessageAttachmentFragment = _DMessageFragmentWrapper<'attachment',
|
||||
title: string; // label of the attachment (filename, named id, content overview, title..)
|
||||
caption: string; // additional information, such as provenance, content preview, etc.
|
||||
created: number;
|
||||
_liveFile?: {
|
||||
_liveFile?: { // [LiveFile] Store the handle to mem, remove when restoring from disk
|
||||
lft: 'fs';
|
||||
_fsFileHandle?: FileSystemFileHandle; // [LiveFile] Store the handle to mem/DB - TODO: check if it works across sessions
|
||||
_fsFileHandle?: FileSystemFileHandle; // file handle to read back the raw data in the future (if available)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user