Skip to content

Commit

Permalink
feat: introduce regacy folder explorer for calling explorer at anywhere
Browse files Browse the repository at this point in the history
  • Loading branch information
ironAiken2 committed Aug 5, 2024
1 parent e7563c6 commit a4313d5
Show file tree
Hide file tree
Showing 31 changed files with 2,479 additions and 2,212 deletions.
9 changes: 7 additions & 2 deletions react/src/components/BAIModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,13 @@ export const DEFAULT_BAI_MODAL_Z_INDEX = 1001;
export interface BAIModalProps extends ModalProps {
okText?: string; // customize text of ok button with adequate content
draggable?: boolean; // modal can be draggle
className?: string;
}
const BAIModal: React.FC<BAIModalProps> = ({ styles, ...modalProps }) => {
const BAIModal: React.FC<BAIModalProps> = ({
className,
styles,
...modalProps
}) => {
const { token } = theme.useToken();
const [disabled, setDisabled] = useState(true);
const [bounds, setBounds] = useState({
Expand Down Expand Up @@ -46,7 +51,7 @@ const BAIModal: React.FC<BAIModalProps> = ({ styles, ...modalProps }) => {
keyboard={false}
{...modalProps}
centered={modalProps.centered ?? true}
className="bai-modal"
className={`bai-modal ${className ?? ''}`}
wrapClassName={modalProps.draggable ? 'draggable' : ''}
styles={{
...styles,
Expand Down
26 changes: 15 additions & 11 deletions react/src/components/FolderExplorerOpener.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { useBaiSignedRequestWithPromise } from '../helper';
import { useCurrentProjectValue } from '../hooks/useCurrentProject';
import { jotaiStore } from './DefaultProviders';
import LegacyFolderExplorer from './LegacyFolderExplorer';
import { VFolder } from './VFolderSelect';
import { atom, useAtomValue } from 'jotai';
import { useEffect } from 'react';
import { useEffect, useState } from 'react';
import { StringParam, useQueryParam } from 'use-query-params';

// TODO: Separate Folder Explorer from `backend-ai-data-view` and make it opened directly on all pages.

const isDataViewReadyAtom = atom(false);
document.addEventListener('backend-ai-data-view:connected', () => {
jotaiStore.set(isDataViewReadyAtom, true);
Expand All @@ -18,6 +17,8 @@ document.addEventListener('backend-ai-data-view:disconnected', () => {

const FolderExplorerOpener = () => {
const [folderId] = useQueryParam('folder', StringParam) || '';
const [vfolderName, setVFolderName] = useState<string>('');
const [open, setOpen] = useState(false);
const normalizedFolderId = folderId?.replaceAll('-', '');
const currentProject = useCurrentProjectValue();
const baiRequestWithPromise = useBaiSignedRequestWithPromise();
Expand All @@ -38,22 +39,25 @@ const FolderExplorerOpener = () => {
// `id` of `/folders` API is not UUID, but UUID without `-`
(vFolder) => vFolder.id === normalizedFolderId,
);
document.dispatchEvent(
new CustomEvent('folderExplorer:open', {
detail: {
vFolder,
},
}),
);
setVFolderName(vFolder?.name || '');
})
.catch(() => {
// do nothing
});
setOpen(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isDataViewReady, folderId]); // don't need to watch `folderId` because this used only once right after the backend-ai-data-view is ready

return null;
return (
<LegacyFolderExplorer
vfolderName={vfolderName}
vfolderID={normalizedFolderId || ''}
open={open}
onRequestClose={() => setOpen(false)}
destroyOnClose
/>
);
};

export default FolderExplorerOpener;
206 changes: 206 additions & 0 deletions react/src/components/LegacyFolderExplorer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,206 @@
import BAIModal, { BAIModalProps } from './BAIModal';
import Flex from './Flex';
import {
DeleteOutlined,
FileAddOutlined,
FolderAddOutlined,
UploadOutlined,
} from '@ant-design/icons';
import {
Button,
Dropdown,
Grid,
Image,
Tooltip,
Typography,
theme,
} from 'antd';
import { createStyles } from 'antd-style';
import { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';

const useStyles = createStyles(({ token, css }) => ({
baiModalHeader: css`
.ant-modal-title {
width: 100%;
margin-right: ${token.marginXXL}px;
}
`,
}));

interface LegacyFolderExplorerProps extends BAIModalProps {
vfolderName: string;
vfolderID: string;
onRequestClose: () => void;
}

const LegacyFolderExplorer: React.FC<LegacyFolderExplorerProps> = ({
vfolderName,
vfolderID,
onRequestClose,
...modalProps
}) => {
const { t } = useTranslation();
const { token } = theme.useToken();
const { styles } = useStyles();
const { lg } = Grid.useBreakpoint();
const [isWritable, setIsWritable] = useState<boolean>(false);
const [isSelected, setIsSelected] = useState<boolean>(false);
// TODO: Events are sent and received as normal,
// but the Lit Element is not rendered and the values inside are not available but ref is available.
const folderExplorerRef = useRef<HTMLDivElement>(null);
const navigate = useNavigate();

useEffect(() => {
const handleConnected = (e: any) => {
setIsWritable(e.detail || false);
};

const handleColumnSelected = (e: any) => {
setIsSelected(e.detail || false);
};

document.addEventListener('folderExplorer:connected', handleConnected);
document.addEventListener(
'folderExplorer:columnSelected',
handleColumnSelected,
);
return () => {
document.removeEventListener('folderExplorer:connected', handleConnected);
document.removeEventListener(
'folderExplorer:columnSelected',
handleColumnSelected,
);
};
}, []);

return (
<BAIModal
className={styles.baiModalHeader}
centered
width={1200}
destroyOnClose
footer={null}
title={
<Flex justify="between" gap={token.marginMD} style={{ width: '100%' }}>
<Flex gap={token.marginMD} style={{ flex: 1 }}>
<Tooltip title={vfolderName}>
<Typography.Title
level={3}
style={{ marginTop: token.marginSM }}
ellipsis
>
{vfolderName}
</Typography.Title>
</Tooltip>
</Flex>
<Flex justify="end" gap={token.marginSM} style={{ flex: lg ? 2 : 1 }}>
<Button
danger
disabled={!isSelected || !isWritable}
icon={<DeleteOutlined />}
onClick={() => {
// @ts-ignore
folderExplorerRef.current?._openDeleteMultipleFileDialog();
}}
>
{lg && t('button.Delete')}
</Button>
<Button
disabled={!isWritable}
icon={<FolderAddOutlined />}
onClick={() => {
//@ts-ignore
folderExplorerRef.current?.openMkdirDialog();
}}
>
{lg && t('button.Create')}
</Button>
<Dropdown
disabled={!isWritable}
menu={{
items: [
{
key: 'upload files',
label: t('data.explorer.UploadFiles'),
icon: <FileAddOutlined />,
onClick: () => {
// @ts-ignore
folderExplorerRef.current?.handleUpload('file');
},
},
{
key: 'upload folder',
label: t('data.explorer.UploadFolder'),
icon: <FolderAddOutlined />,
onClick: () => {
// @ts-ignore
folderExplorerRef.current?.handleUpload('folder');
},
},
],
}}
>
<Button icon={<UploadOutlined />}>{lg && 'Upload'}</Button>
</Dropdown>
<Button
icon={
<Image
width="18px"
src="/resources/icons/filebrowser.svg"
alt="File Browser"
preview={false}
/>
}
onClick={() =>
// @ts-ignore
folderExplorerRef.current?._executeFileBrowser()
}
>
{lg && t('data.explorer.ExecuteFileBrowser')}
</Button>
<Button
icon={
<Image
width="18px"
src="/resources/icons/sftp.png"
alt="SSH / SFTP"
preview={false}
/>
}
onClick={() => {
// @ts-ignore
folderExplorerRef.current?._executeSSHProxyAgent();
}}
>
{lg && t('data.explorer.RunSSH/SFTPserver')}
</Button>
</Flex>
</Flex>
}
onCancel={() => {
onRequestClose();
const queryParams = new URLSearchParams(window.location.search).get(
'tab',
);
if (queryParams) {
navigate(`?tab=${queryParams}`);
} else {
navigate('/data');
}
}}
{...modalProps}
>
{/* @ts-ignore */}
<backend-ai-folder-explorer
ref={folderExplorerRef}
active
vfolderID={vfolderID}
style={{ width: '100%' }}
/>
</BAIModal>
);
};

export default LegacyFolderExplorer;
7 changes: 4 additions & 3 deletions resources/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,6 @@
"Delete": "Löschen",
"FolderOptionUpdate": "Ordneroption aktualisieren",
"Leave": "Verlassen",
"RenameAFolder": "Einen Ordner umbenennen",
"TypeNewFolderName": "Geben Sie einen neuen Ordnernamen ein",
"FolderCreated": "Ordner erstellt",
"FolderCloned": "Ordner geklont",
Expand Down Expand Up @@ -709,7 +708,6 @@
"FileExtensionChanged": "Möchten Sie die Dateierweiterung ändern?",
"KeepFileExtension": "Behalten",
"UseNewFileExtension": "Benutzen",
"RemoveFileExtension": "Dateierweiterung entfernen",
"ExecutingFileBrowser": "Dateibrowser wird ausgeführt...",
"ExecuteFileBrowser": "Dateibrowser ausführen",
"NotEnoughResourceForFileBrowserSession": "Nicht genügend Ressourcen (CPU: 1 Core, Speicher: 0,5 GB), um die Sitzung für den Dateibrowser zu erstellen. Bitte überprüfen Sie die verfügbaren Ressourcen.",
Expand All @@ -725,7 +723,10 @@
"StartingSSH/SFTPSession": "SFTP-Sitzung starten...",
"NumberOfSFTPSessionsExceededTitle": "Limit der laufenden Upload-Session erreicht",
"NumberOfSFTPSessionsExceededBody": "Sie führen alle verfügbaren Upload-Sitzungen aus, die Sie erstellen können. Bitte beenden Sie ungenutzte Upload-Sitzungen, bevor Sie eine neue Sitzung starten.",
"DownloadNotAllowed": "Das Herunterladen von Dateien/Ordnern ist in diesem Ordner nicht gestattet."
"DownloadNotAllowed": "Das Herunterladen von Dateien/Ordnern ist in diesem Ordner nicht gestattet.",
"RenameAFolder": "Ordner umbenennen",
"Filename": "Dateiname",
"RemoveFileExtension": "Entfernen "
},
"invitation": {
"NoValidEmails": "Es wurden keine gültigen E-Mails eingegeben",
Expand Down
7 changes: 4 additions & 3 deletions resources/i18n/el.json
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,6 @@
"Delete": "Διαγράφω",
"FolderOptionUpdate": "Ενημέρωση επιλογής φακέλου",
"Leave": "Αδεια",
"RenameAFolder": "Μετονομάστε ένα φάκελο",
"TypeNewFolderName": "Πληκτρολογήστε νέο όνομα φακέλου",
"FolderCreated": "Δημιουργήθηκε φάκελος",
"FolderCloned": "Ο φάκελος κλωνοποιήθηκε",
Expand Down Expand Up @@ -709,7 +708,6 @@
"FileExtensionChanged": "Θέλετε να αλλάξετε την επέκταση αρχείου;",
"KeepFileExtension": "Διατήρηση",
"UseNewFileExtension": "Χρήση",
"RemoveFileExtension": "αφαιρέστε την επέκταση αρχείου",
"ExecutingFileBrowser": "Εκτέλεση προγράμματος περιήγησης ...",
"ExecuteFileBrowser": "Εκτελέστε πρόγραμμα περιήγησης αρχείων",
"NotEnoughResourceForFileBrowserSession": "Δεν υπάρχουν αρκετοί πόροι (cpu: 1 Core, mem: 0,5 GB) για τη δημιουργία της περιόδου λειτουργίας για το πρόγραμμα περιήγησης αρχείων παρακαλούμε ελέγξτε τους διαθέσιμους πόρους.",
Expand All @@ -725,7 +723,10 @@
"StartingSSH/SFTPSession": "Έναρξη συνεδρίας SFTP...",
"NumberOfSFTPSessionsExceededTitle": "Έφθασε το όριο του αριθμού των τρεχουσών συνόδων μεταφόρτωσης",
"NumberOfSFTPSessionsExceededBody": "Εκτελείτε όλες τις διαθέσιμες συνεδρίες μεταφόρτωσης που επιτρέπεται να δημιουργήσετε. Παρακαλούμε τερματίστε τις αχρησιμοποίητες συνεδρίες μεταφόρτωσης πριν ξεκινήσετε μια νέα συνεδρία.",
"DownloadNotAllowed": "Η λήψη αρχείου/φακέλου δεν επιτρέπεται σε αυτόν τον φάκελο."
"DownloadNotAllowed": "Η λήψη αρχείου/φακέλου δεν επιτρέπεται σε αυτόν τον φάκελο.",
"RenameAFolder": "Μετονομασία φακέλου",
"Filename": "Ονομα αρχείου",
"RemoveFileExtension": "Αφαιρώ "
},
"invitation": {
"NoValidEmails": "Δεν καταχωρήθηκαν έγκυρα μηνύματα ηλεκτρονικού ταχυδρομείου",
Expand Down
7 changes: 4 additions & 3 deletions resources/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,6 @@
"Delete": "Delete",
"FolderOptionUpdate": "Update folder option",
"Leave": "Leave",
"RenameAFolder": "Rename a folder",
"TypeNewFolderName": "Type new folder name",
"FolderCreated": "Folder created",
"FolderCloned": "Folder cloned",
Expand Down Expand Up @@ -844,7 +843,6 @@
"FileExtensionChanged": "Would you like to change the file extension?",
"KeepFileExtension": "Keep ",
"UseNewFileExtension": "Use ",
"RemoveFileExtension": "remove file extension",
"ExecutingFileBrowser": "Executing filebrowser...",
"ExecuteFileBrowser": "Execute filebrowser",
"NotEnoughResourceForFileBrowserSession": "No enough resources(cpu: 1 Core, mem: 0.5GB) to create the session for filebrowser. please check the available resources.",
Expand All @@ -858,7 +856,10 @@
"EmptyFilesAndFoldersAreNotUploaded": "Empty files and empty folders are not uploaded",
"NumberOfSFTPSessionsExceededTitle": "Reached limit of running upload session count",
"NumberOfSFTPSessionsExceededBody": "You are running all available upload sessions you are allowed to create. Please terminated unused upload sessions before starting a new session.",
"DownloadNotAllowed": "Downloading file/folder is not allowed in this folder."
"DownloadNotAllowed": "Downloading file/folder is not allowed in this folder.",
"RenameAFolder": "Rename Folder",
"Filename": "File name",
"RemoveFileExtension": "Remove "
},
"invitation": {
"NoValidEmails": "No valid emails were entered",
Expand Down
Loading

0 comments on commit a4313d5

Please sign in to comment.