diff --git a/ui/src/ide/sidebar/FileBrowser.tsx b/ui/src/ide/sidebar/FileBrowser.tsx index ab6ca4a..2097296 100644 --- a/ui/src/ide/sidebar/FileBrowser.tsx +++ b/ui/src/ide/sidebar/FileBrowser.tsx @@ -1,276 +1,208 @@ -import React, { useEffect, useState } from 'react' -import { BaseApiUrl } from '../config' -import ContextMenu from './ContextMenu' -import getFileExtension from '../utils' +import React, { useEffect, useState } from 'react'; +import { BaseApiUrl } from '../config'; +import ContextMenu from './ContextMenu'; +import getFileExtension from '../utils'; interface IContent { - type: string - path: string - name: string - content: IContent[] + type: string; + path: string; + name: string; + content: IContent[]; } -export default function FileBrowser ({ sendDataToParent, display }) { - const [menuPosition, setMenuPosition] = useState<{ xPos: number, yPos: number } | null>(null) - const [isMenuVisible, setIsMenuVisible] = useState(false) - const [contextPath, setContextPath] = useState('') - - // const handleRightClick = (event: React.MouseEvent, path:string) => { - // event.preventDefault(); - // setMenuPosition({ xPos: event.pageX, yPos: event.pageY }); - // setContextPath(path) - // setIsMenuVisible(true); - // }; - - const handleCloseMenu = () => { - setIsMenuVisible(false) - } - - const [contents, setContents] = useState([]) - - const [cwd, setCwd] = useState('') - - const directoryRightClickHandler = (e, path: string) => { - e.preventDefault() // prevent the default behaviour when right clicked - console.log('Right Click') - - setMenuPosition({ xPos: e.pageX, yPos: e.pageY }) - setContextPath(path) - setIsMenuVisible(true) - } +interface FileBrowserProps { + sendDataToParent: (name: string, path: string, type: string) => void; + display: string; +} - const menuItems = [ - { label: 'Rename', action: (contextPath: string) => alert('Rename' + contextPath) }, - { label: 'Delete', action: async (contextPath: string) => await deleteFile(contextPath) } - ] +export default function FileBrowser({ sendDataToParent, display }: FileBrowserProps) { + const [contents, setContents] = useState([]); + const [cwd, setCwd] = useState(''); const FetchData = async () => { const res = await fetch(BaseApiUrl + '/api/contents?type=notebook&hash=0', { method: 'POST', + body: JSON.stringify({ path: cwd }), + }); + const resJson = await res.json(); + setContents(resJson.content); + }; - body: JSON.stringify({ - path: cwd - }) - }) - const resJson = await res.json() - console.log(resJson) - setContents(resJson.content) - } - - const handleFileClick = async (name: string, path: string, type: string) => { - sendDataToParent(name, path, type) - } - - const showNewFileDialog = () => { - console.log('New file') - } + const handleFileClick = (name: string, path: string, type: string) => { + sendDataToParent(name, path, type); + }; const createNewFile = async () => { - const path = 'abc.py' - const res = await fetch(BaseApiUrl + '/api/contents/create', { + await fetch(BaseApiUrl + '/api/contents/create', { method: 'POST', - - body: JSON.stringify({ - ext: '.py', - type: 'file' - }) - }) - FetchData() - } + body: JSON.stringify({ ext: '.py', type: 'file' }), + }); + FetchData(); + }; const createNewDirectory = async () => { - const path = 'abc.py' - const res = await fetch(BaseApiUrl + '/api/contents/create' + path, { + await fetch(BaseApiUrl + '/api/contents/create', { method: 'POST', - body: JSON.stringify({ - type: 'directory' - }) - }) - FetchData() - } - - const renameFile = async (oldPath: string, newPath: string) => { - const res = await fetch(BaseApiUrl + '/api/contents/untitled', { - method: 'PATCH', - body: JSON.stringify({ - old_path: oldPath, - new_path: newPath - }) - }) - } - - const deleteFile = async (path: string) => { - console.log('Deleting file') - - const res = await fetch(BaseApiUrl + '/api/contents', { - method: 'DELETE', - body: JSON.stringify({ - path - }) - }) - } + body: JSON.stringify({ type: 'directory' }), + }); + FetchData(); + }; useEffect(() => { - FetchData() - }, [cwd]) + FetchData(); + }, [cwd]); return ( -
{cwd}
Files
- - + +
    - {contents.map((content, index) => { - if (content.type === 'directory') { - return ( - - ) - } else { - return ( - - ) - } - } - )} + {contents.map((content, index) => ( + content.type === 'directory' ? ( + + ) : ( + + ) + ))}
-
- {isMenuVisible && (menuPosition != null) && ( - - )} -
- ) + ); } -function FileItem ({ directoryRightClickHandler, handleFileClick, content }) { +const FileItem = ({ content, handleFileClick }: { content: IContent; handleFileClick: (name: string, path: string, type: string) => void }) => { + const [isEditing, setIsEditing] = useState(false); + const [text, setText] = useState(content.name); + const getIconToLoad = () => { - const extension = getFileExtension(content.name) - switch (extension) { - case 'go': - case 'mod': - return "./images/editor/go-icon.svg" - case 'py': - case 'ipynb': - return "./images/editor/py-icon.svg" - case 'js': - return "./images/editor/js-icon.svg" - case 'json': - return "./images/editor/json-icon.svg" - case 'ts': - return "./images/editor/ts-icon.svg" - case 'tsx': - case 'jsx': - return "./images/editor/react-icon.svg" - case 'html': - return "./images/editor/html-icon.svg" - case 'css': - return "./images/editor/go-icon.svg" - case 'sass': - case 'scss': - return "./images/editor/go-icon.svg" - case 'md': - case 'markdown': - return "./images/editor/md-icon.svg" - case 'gitignore': - return "./images/editor/git-icon.svg" - } - return "./images/editor/go-icon.svg" - } + const extension = getFileExtension(content.name); + const iconMap: { [key: string]: string } = { + go: './images/editor/go-icon.svg', + mod: './images/editor/go-icon.svg', + py: './images/editor/py-icon.svg', + ipynb: './images/editor/py-icon.svg', + js: './images/editor/js-icon.svg', + json: './images/editor/json-icon.svg', + ts: './images/editor/ts-icon.svg', + tsx: './images/editor/react-icon.svg', + jsx: './images/editor/react-icon.svg', + html: './images/editor/html-icon.svg', + css: './images/editor/go-icon.svg', + sass: './images/editor/go-icon.svg', + scss: './images/editor/go-icon.svg', + md: './images/editor/md-icon.svg', + markdown: './images/editor/md-icon.svg', + gitignore: './images/editor/git-icon.svg', + }; + return extension != null ? iconMap[extension] : './images/editor/go-icon.svg'; + }; return (
  • - directoryRightClickHandler(e, content.path)} onClick={() => handleFileClick(content.name, content.path, content.type)}> + handleFileClick(content.name, content.path, content.type)} + onContextMenu={(e) => e.preventDefault()} + > - {content.name} + {isEditing ? ( + setText(e.target.value)} + onBlur={() => setIsEditing(false)} + onKeyDown={(e) => e.key === 'Enter' && setIsEditing(false)} + autoFocus + /> + ) : ( + setIsEditing(true)}>{text} + )}
  • - ) -} + ); +}; -function DirectoryItem ({ directoryRightClickHandler, data, sendDataToParent }) { - const [content, setContent] = useState(data) +const DirectoryItem = ({ data, sendDataToParent }: { data: IContent; sendDataToParent: (name: string, path: string, type: string) => void }) => { + const [isEditing, setIsEditing] = useState(false); + const [text, setText] = useState(data.name); + const [menuPosition, setMenuPosition] = useState<{ xPos: number; yPos: number } | null>(null); + const [isMenuVisible, setIsMenuVisible] = useState(false); - const handleFileClick = async (name: string, path: string, type: string) => { - sendDataToParent(name, path, type) - } - - const FetchData = async (path) => { + const handleDirectoryClick = async (path: string) => { const res = await fetch(BaseApiUrl + '/api/contents?type=notebook&hash=0', { method: 'POST', + body: JSON.stringify({ path }), + }); + const resJson = await res.json(); + sendDataToParent(resJson.name, resJson.path, resJson.type); + }; - body: JSON.stringify({ - path - }) - }) - const resJson = await res.json() - console.log('important =>', resJson) - setContent(resJson) - } + const menuItems = [ + { label: 'Rename', action: () => setIsEditing(true) }, + // { label: 'Delete', action: async () => await deleteFile(data.path) } + ]; - const handleDirectoryClick = async (path: string, type: string) => { - FetchData(path) - } - useEffect(() => { - }, []) + const handleRightClick = (e: React.MouseEvent, path: string) => { + e.preventDefault(); + setMenuPosition({ xPos: e.pageX, yPos: e.pageY }); + setIsMenuVisible(true); + }; return (
  • - directoryRightClickHandler(e, content.path)} onClick={async () => await handleDirectoryClick(content.path, content.type)}> + handleRightClick(e, data.path)} onClick={() => handleDirectoryClick(data.path)}> - {content.name} + {isEditing ? ( + setText(e.target.value)} + onBlur={() => setIsEditing(false)} + onKeyDown={(e) => e.key === 'Enter' && setIsEditing(false)} + autoFocus + /> + ) : ( + setIsEditing(true)}>{text} + )} -
      -
        - {content.content !== null && content.content.map((content, index) => { - if (content.type === 'directory') { - return ( - - ) - } else { - return ( - - ) - } - } - )} -
      + {isMenuVisible && menuPosition && ( + setIsMenuVisible(false)} + /> + )} +
        + {data.content?.map((content, index) => ( + content.type === 'directory' ? ( + + ) : ( + + ) + ))}
      - ) -} + ); +};