mirror of
https://github.com/enricoros/big-AGI.git
synced 2026-05-10 21:50:14 -07:00
EnhancedRenderCode x LiveFileSync: extract WorkspaceLiveFilePicker
This commit is contained in:
@@ -0,0 +1,106 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Box, Dropdown, IconButton, ListDivider, ListItemDecorator, Menu, MenuButton, MenuItem } from '@mui/joy';
|
||||
import CodeIcon from '@mui/icons-material/Code';
|
||||
|
||||
import type { LiveFileId, LiveFileMetadata } from '~/common/livefile/liveFile.types';
|
||||
import { LiveFilePatchIcon } from '~/common/components/icons/LiveFilePatchIcon';
|
||||
import { useContextWorkspaceId } from '~/common/stores/workspace/WorkspaceIdProvider';
|
||||
import { useWorkspaceContentsMetadata } from '~/common/stores/workspace/useWorkspaceContentsMetadata';
|
||||
import { TooltipOutlined } from '~/common/components/TooltipOutlined';
|
||||
|
||||
|
||||
/**
|
||||
* Allows selection of LiveFiles in the current Workspace
|
||||
*/
|
||||
export function WorkspaceLiveFilePicker(props: {
|
||||
enabled: boolean;
|
||||
autoSelectName: string | null;
|
||||
liveFileId: LiveFileId | null;
|
||||
onSelectLiveFile: (id: LiveFileId | null) => void;
|
||||
}) {
|
||||
|
||||
|
||||
// external state
|
||||
const workspaceId = useContextWorkspaceId();
|
||||
const { liveFilesMetadata: wLiveFiles } = useWorkspaceContentsMetadata(props.enabled ? workspaceId : null);
|
||||
|
||||
// set as disabled when empty
|
||||
const enabled = wLiveFiles.length > 0;
|
||||
const { autoSelectName, liveFileId, onSelectLiveFile } = props;
|
||||
|
||||
|
||||
// [effect] auto-select a LiveFileId
|
||||
React.useEffect(() => {
|
||||
if (!enabled || !wLiveFiles.length)
|
||||
return;
|
||||
|
||||
if (wLiveFiles.length === 1) {
|
||||
// auto-select the only LiveFile
|
||||
onSelectLiveFile(wLiveFiles[0].id);
|
||||
} else {
|
||||
// auto-select by name
|
||||
const lfm = wLiveFiles.find(lfm => lfm.name === autoSelectName);
|
||||
if (lfm)
|
||||
onSelectLiveFile(lfm.id);
|
||||
}
|
||||
}, [enabled, wLiveFiles, autoSelectName, onSelectLiveFile]);
|
||||
|
||||
|
||||
return (
|
||||
<Dropdown>
|
||||
|
||||
{/* Activation button */}
|
||||
<TooltipOutlined color='success' title='Select a LiveFile to patch' placement='top-end'>
|
||||
<MenuButton
|
||||
aria-label='Pair File'
|
||||
slots={{ root: IconButton }}
|
||||
slotProps={{
|
||||
root: {
|
||||
color: liveFileId ? 'success' : undefined,
|
||||
// variant: liveFileId ? undefined : undefined,
|
||||
size: 'sm',
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
ml: 'auto',
|
||||
}}
|
||||
>
|
||||
<LiveFilePatchIcon />
|
||||
</MenuButton>
|
||||
</TooltipOutlined>
|
||||
|
||||
{/* List of the Workspace LiveFiles to pair */}
|
||||
<Menu
|
||||
placement='bottom-start'
|
||||
sx={{
|
||||
minWidth: 200,
|
||||
zIndex: 'var(--joy-zIndex-modal)', /* on top of its own modal in FS */
|
||||
}}
|
||||
>
|
||||
{/*<ListItem>*/}
|
||||
{/* <Typography level='body-sm'>Recent Workspace Files</Typography>*/}
|
||||
{/*</ListItem>*/}
|
||||
|
||||
{wLiveFiles.map((lfm: LiveFileMetadata) => (
|
||||
<MenuItem key={lfm.id} onClick={() => onSelectLiveFile(lfm.id)}>
|
||||
<ListItemDecorator><CodeIcon sx={{ fontSize: 'lg' }} /></ListItemDecorator>
|
||||
<Box sx={{ mr: 1 }}>
|
||||
{lfm.name}
|
||||
<Box component='span' sx={{ fontSize: 'xs', display: 'block' }}>
|
||||
{lfm.size?.toLocaleString() || '(unknown)'} bytes {lfm.type ? `· ${lfm.type}` : ''}
|
||||
</Box>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
))}
|
||||
|
||||
<ListDivider />
|
||||
|
||||
<MenuItem disabled={!liveFileId} onClick={() => onSelectLiveFile(null)}>
|
||||
<ListItemDecorator />
|
||||
Remove Pairing
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Box, Dropdown, IconButton, ListDivider, ListItemDecorator, Menu, MenuButton, MenuItem, Typography } from '@mui/joy';
|
||||
import CodeIcon from '@mui/icons-material/Code';
|
||||
import { Typography } from '@mui/joy';
|
||||
|
||||
import { useContextWorkspaceId } from '~/common/stores/workspace/WorkspaceIdProvider';
|
||||
import { useWorkspaceContentsMetadata } from '~/common/stores/workspace/useWorkspaceContentsMetadata';
|
||||
|
||||
import type { LiveFileId, LiveFileMetadata } from '~/common/livefile/liveFile.types';
|
||||
import { LiveFilePatchIcon } from '~/common/components/icons/LiveFilePatchIcon';
|
||||
import type { LiveFileId } from '~/common/livefile/liveFile.types';
|
||||
import { isLiveFileSupported } from '~/common/livefile/store-live-file';
|
||||
import { useUXLabsStore } from '~/common/state/store-ux-labs';
|
||||
|
||||
import { WorkspaceLiveFilePicker } from './WorkspaceLiveFilePicker';
|
||||
|
||||
|
||||
export function useLiveFilePatch(title: string, code: string, isPartial: boolean, isMobile: boolean) {
|
||||
|
||||
@@ -25,19 +25,6 @@ export function useLiveFilePatch(title: string, code: string, isPartial: boolean
|
||||
const workspaceId = useContextWorkspaceId();
|
||||
const { liveFilesMetadata } = useWorkspaceContentsMetadata(isEnabled ? workspaceId : null);
|
||||
|
||||
// [effect] auto-select a LiveFileId
|
||||
React.useEffect(() => {
|
||||
if (liveFilesMetadata.length === 1) {
|
||||
// auto-select the only LiveFile
|
||||
setLiveFileId(liveFilesMetadata[0].id);
|
||||
} else {
|
||||
// auto-select matching the title
|
||||
const lfm = liveFilesMetadata.find(lfm => lfm.name === title);
|
||||
if (lfm)
|
||||
setLiveFileId(lfm.id);
|
||||
}
|
||||
}, [isEnabled, liveFilesMetadata, title]);
|
||||
|
||||
|
||||
// reset enablement if no live files
|
||||
if (!liveFilesMetadata?.length)
|
||||
@@ -51,60 +38,14 @@ export function useLiveFilePatch(title: string, code: string, isPartial: boolean
|
||||
|
||||
const button = React.useMemo(() => !isEnabled ? null : <>
|
||||
|
||||
<WorkspaceLiveFilePicker
|
||||
autoSelectName={title}
|
||||
enabled={isEnabled}
|
||||
liveFileId={liveFileId}
|
||||
onSelectLiveFile={setLiveFileId}
|
||||
/>
|
||||
|
||||
{/* LiveFile selector */}
|
||||
<Dropdown>
|
||||
|
||||
{/*<TooltipOutlined color='success' title='Select a LiveFile to patch'>*/}
|
||||
<MenuButton
|
||||
aria-label='Pair File'
|
||||
slots={{ root: IconButton }}
|
||||
slotProps={{
|
||||
root: {
|
||||
color: liveFileId ? 'success' : undefined,
|
||||
variant: liveFileId ? undefined : undefined,
|
||||
size: 'sm',
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
ml: 'auto',
|
||||
}}
|
||||
>
|
||||
<LiveFilePatchIcon />
|
||||
</MenuButton>
|
||||
{/*</TooltipOutlined>*/}
|
||||
|
||||
<Menu
|
||||
placement='bottom-start'
|
||||
sx={{
|
||||
minWidth: 200,
|
||||
zIndex: 'var(--joy-zIndex-modal)', /* on top of its own modal in FS */
|
||||
}}
|
||||
>
|
||||
{/*<ListItem>*/}
|
||||
{/* <Typography level='body-sm'>Recent Workspace Files</Typography>*/}
|
||||
{/*</ListItem>*/}
|
||||
|
||||
{liveFilesMetadata.map((lfm: LiveFileMetadata) => (
|
||||
<MenuItem key={lfm.id} onClick={() => setLiveFileId(lfm.id)}>
|
||||
<ListItemDecorator><CodeIcon sx={{ fontSize: 'lg' }} /></ListItemDecorator>
|
||||
<Box>
|
||||
{lfm.name}
|
||||
<Typography level='body-xs'>{lfm.size?.toLocaleString() || '(unknown)'} bytes {lfm.type ? `· ${lfm.type}` : ''}</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
))}
|
||||
|
||||
<ListDivider />
|
||||
|
||||
<MenuItem disabled={!liveFileId} onClick={() => setLiveFileId(null)}>
|
||||
<ListItemDecorator />
|
||||
Remove Pairing
|
||||
</MenuItem>
|
||||
</Menu>
|
||||
</Dropdown>
|
||||
|
||||
</>, [isEnabled, liveFileId, liveFilesMetadata]);
|
||||
</>, [isEnabled, liveFileId, title]);
|
||||
|
||||
|
||||
const actionBar = React.useMemo(() => (!isEnabled || !liveFilesMetadata || true) ? null : (
|
||||
|
||||
Reference in New Issue
Block a user