210 lines
7.3 KiB
JavaScript
210 lines
7.3 KiB
JavaScript
import React, { PureComponent } from 'react';
|
|
import Box from '@mui/material/Box';
|
|
import Typography from '@mui/material/Typography';
|
|
import IconButton from '@mui/material/IconButton';
|
|
import FolderOpenRoundedIcon from '@mui/icons-material/FolderOpenRounded';
|
|
import CloseRoundedIcon from '@mui/icons-material/CloseRounded';
|
|
|
|
import vfsAutomat from '../../automats/vfsAutomat';
|
|
import VfsFileExplorer from './VfsFileExplorer';
|
|
import VfsTextEditor from './VfsTextEditor';
|
|
import VfsFilePreview from './VfsFilePreview';
|
|
import VfsNewFileDialog from './VfsNewFileDialog';
|
|
|
|
export default class VfsEditorPanel extends PureComponent {
|
|
constructor(props) {
|
|
super(props);
|
|
const s = vfsAutomat.state;
|
|
this.state = {
|
|
files: s.files,
|
|
loadingFiles: s.loadingFiles,
|
|
loadError: s.loadError,
|
|
selectedFileName: s.selectedFileName,
|
|
selectedFile: s.selectedFile,
|
|
fileContent: s.fileContent,
|
|
originalContent: s.originalContent,
|
|
isDirty: s.isDirty,
|
|
loadingContent: s.loadingContent,
|
|
isSaving: s.isSaving,
|
|
saveError: s.saveError,
|
|
isUploading: s.isUploading,
|
|
searchQuery: s.searchQuery,
|
|
newFileDialogOpen: s.newFileDialogOpen,
|
|
newFileDefaultFolder: s.newFileDefaultFolder,
|
|
};
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.unsub = vfsAutomat.subscribe(this, (state) => ({
|
|
files: state.files,
|
|
loadingFiles: state.loadingFiles,
|
|
loadError: state.loadError,
|
|
selectedFileName: state.selectedFileName,
|
|
selectedFile: state.selectedFile,
|
|
fileContent: state.fileContent,
|
|
originalContent: state.originalContent,
|
|
isDirty: state.isDirty,
|
|
loadingContent: state.loadingContent,
|
|
isSaving: state.isSaving,
|
|
saveError: state.saveError,
|
|
isUploading: state.isUploading,
|
|
searchQuery: state.searchQuery,
|
|
newFileDialogOpen: state.newFileDialogOpen,
|
|
newFileDefaultFolder: state.newFileDefaultFolder,
|
|
}));
|
|
|
|
if (this.state.files.length === 0 && !this.state.loadingFiles) {
|
|
void vfsAutomat.actions.loadFiles();
|
|
}
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
this.unsub?.();
|
|
}
|
|
|
|
handleMentionInChat = (file, lineInfo = null) => {
|
|
if (!file) return;
|
|
if (this.props.onMentionReference) {
|
|
this.props.onMentionReference({
|
|
fileName: file.name,
|
|
path: file.name,
|
|
startLine: lineInfo?.startLine || null,
|
|
endLine: lineInfo?.endLine || null,
|
|
selectedText: lineInfo?.selectedText || '',
|
|
isImage: file.isImage || false,
|
|
});
|
|
return;
|
|
}
|
|
if (this.props.onInsertToChat) {
|
|
const isImg = file.isImage;
|
|
const tag = lineInfo?.startLine
|
|
? `[${file.name}#${lineInfo.startLine === lineInfo.endLine ? `L${lineInfo.startLine}` : `L${lineInfo.startLine}-L${lineInfo.endLine}`}](${file.name}#${lineInfo.startLine === lineInfo.endLine ? `L${lineInfo.startLine}` : `L${lineInfo.startLine}-L${lineInfo.endLine}`})`
|
|
: isImg
|
|
? ``
|
|
: `[${file.name}](${file.name})`;
|
|
this.props.onInsertToChat(tag);
|
|
}
|
|
};
|
|
|
|
render() {
|
|
const {
|
|
files,
|
|
loadingFiles,
|
|
selectedFileName,
|
|
selectedFile,
|
|
fileContent,
|
|
originalContent,
|
|
isDirty,
|
|
loadingContent,
|
|
isSaving,
|
|
saveError,
|
|
searchQuery,
|
|
newFileDialogOpen,
|
|
} = this.state;
|
|
|
|
return (
|
|
<Box
|
|
sx={{
|
|
display: 'flex',
|
|
flexDirection: 'column',
|
|
height: '100%',
|
|
width: '100%',
|
|
overflow: 'hidden',
|
|
bgcolor: 'background.paper',
|
|
borderRight: 1,
|
|
borderColor: 'divider',
|
|
}}
|
|
>
|
|
{selectedFileName && selectedFile?.isText ? (
|
|
/* Single Column Mode: Text Editor */
|
|
<VfsTextEditor
|
|
fileName={selectedFileName}
|
|
file={selectedFile}
|
|
content={fileContent}
|
|
originalContent={originalContent}
|
|
isDirty={isDirty}
|
|
isSaving={isSaving}
|
|
saveError={saveError}
|
|
loadingContent={loadingContent}
|
|
onChange={(c) => vfsAutomat.actions.updateContent(c)}
|
|
onSave={() => vfsAutomat.actions.saveCurrentFile()}
|
|
onClose={() => vfsAutomat.actions.selectFile(null)}
|
|
onDownload={() => vfsAutomat.actions.downloadFile(selectedFileName)}
|
|
onMentionInChat={(lineInfo) => this.handleMentionInChat(selectedFile, lineInfo)}
|
|
/>
|
|
) : selectedFileName && !selectedFile?.isText ? (
|
|
/* Single Column Mode: Preview (Image, PDF, Binary) */
|
|
<VfsFilePreview
|
|
fileName={selectedFileName}
|
|
file={selectedFile}
|
|
onClose={() => vfsAutomat.actions.selectFile(null)}
|
|
onDownload={() => vfsAutomat.actions.downloadFile(selectedFileName)}
|
|
onMentionInChat={() => this.handleMentionInChat(selectedFile)}
|
|
/>
|
|
) : (
|
|
/* Single Column Mode: File Explorer */
|
|
<>
|
|
<Box
|
|
sx={{
|
|
p: 1.5,
|
|
px: 2,
|
|
borderBottom: 1,
|
|
borderColor: 'divider',
|
|
display: 'flex',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
bgcolor: 'background.paper',
|
|
minHeight: 52,
|
|
flexShrink: 0,
|
|
}}
|
|
>
|
|
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
|
|
<FolderOpenRoundedIcon color="primary" sx={{ fontSize: 22 }} />
|
|
<Typography variant="subtitle1" fontWeight={700}>
|
|
Dateien
|
|
</Typography>
|
|
</Box>
|
|
|
|
<IconButton
|
|
size="small"
|
|
onClick={() => vfsAutomat.actions.closeVfs()}
|
|
aria-label="VFS schließen"
|
|
>
|
|
<CloseRoundedIcon fontSize="small" />
|
|
</IconButton>
|
|
</Box>
|
|
|
|
<Box sx={{ flexGrow: 1, minHeight: 0, overflow: 'hidden' }}>
|
|
<VfsFileExplorer
|
|
files={files}
|
|
loading={loadingFiles}
|
|
selectedFileName={selectedFileName}
|
|
searchQuery={searchQuery}
|
|
onSelectFile={(name) => vfsAutomat.actions.selectFile(name)}
|
|
onRefresh={() => vfsAutomat.actions.loadFiles()}
|
|
onOpenNewDialog={(parentDir) => vfsAutomat.actions.setNewFileDialogOpen(true, parentDir)}
|
|
onSearchChange={(q) => vfsAutomat.actions.setSearchQuery(q)}
|
|
onDownload={(name) => vfsAutomat.actions.downloadFile(name)}
|
|
onDelete={(name) => vfsAutomat.actions.deletePath(name)}
|
|
onRename={(oldPath, newPath) => vfsAutomat.actions.renameFile(oldPath, newPath)}
|
|
onMkdir={(dirPath) => vfsAutomat.actions.mkdir(dirPath)}
|
|
onUpload={(filesToUpload) => vfsAutomat.actions.uploadFiles(filesToUpload)}
|
|
onMentionInChat={this.handleMentionInChat}
|
|
/>
|
|
</Box>
|
|
</>
|
|
)}
|
|
|
|
{/* New File Dialog */}
|
|
<VfsNewFileDialog
|
|
open={newFileDialogOpen}
|
|
defaultFolder={this.state.newFileDefaultFolder}
|
|
onClose={() => vfsAutomat.actions.setNewFileDialogOpen(false)}
|
|
onCreate={(name) => vfsAutomat.actions.createFile(name)}
|
|
isCreating={isSaving}
|
|
/>
|
|
</Box>
|
|
);
|
|
}
|
|
}
|