diff --git a/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx b/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx index 8a0a218e9b..60589b5552 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-explorer-menu.tsx @@ -1,9 +1,9 @@ -import { CustomTooltip } from '@remix-ui/helper' -import React, { useState, useEffect, } from 'react' //eslint-disable-line -import { FormattedMessage } from 'react-intl' -import { Placement } from 'react-bootstrap/esm/Overlay' -import { FileExplorerMenuProps } from '../types' -const _paq = window._paq = window._paq || [] +import {CustomTooltip} from '@remix-ui/helper' +import React, {useState, useEffect} from 'react' //eslint-disable-line +import {FormattedMessage} from 'react-intl' +import {Placement} from 'react-bootstrap/esm/Overlay' +import {FileExplorerMenuProps} from '../types' +const _paq = (window._paq = window._paq || []) export const FileExplorerMenu = (props: FileExplorerMenuProps) => { const [state, setState] = useState({ @@ -44,18 +44,24 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { icon: 'fab fa-github', placement: 'bottom-start' } - ].filter(item => props.menuItems && props.menuItems.find((name) => { return name === item.action })), + ].filter( + (item) => + props.menuItems && + props.menuItems.find((name) => { + return name === item.action + }) + ), actions: {} }) - const enableDirUpload = { directory: "", webkitdirectory: "" } + const enableDirUpload = {directory: '', webkitdirectory: ''} useEffect(() => { const actions = { updateGist: () => {} } - setState(prevState => { - return { ...prevState, actions } + setState((prevState) => { + return {...prevState, actions} }) }, []) @@ -67,32 +73,53 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { tooltipClasses="text-nowrap" tooltipText={props.title} > - { props.title } + + {props.title} + - { - state.menuItems.map(({ action, title, icon, placement }, index) => { + + {state.menuItems.map(({action, title, icon, placement}, index) => { if (action === 'uploadFile') { return ( } + tooltipText={ + + } key={`index-${action}-${placement}-${icon}`} > - { - e.stopPropagation() - _paq.push(['trackEvent', 'fileExplorer', 'fileAction', action]) - props.uploadFile(e.target) - e.target.value = null - }} - multiple /> + { + e.stopPropagation() + _paq.push([ + 'trackEvent', + 'fileExplorer', + 'fileAction', + action + ]) + props.uploadFile(e.target) + e.target.value = null + }} + multiple + /> ) @@ -102,22 +129,38 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { placement={placement as Placement} tooltipId="uploadFolderTooltip" tooltipClasses="text-nowrap" - tooltipText={} + tooltipText={ + + } key={`index-${action}-${placement}-${icon}`} > - { - e.stopPropagation() - _paq.push(['trackEvent', 'fileExplorer', 'fileAction', action]) - props.uploadFolder(e.target) - e.target.value = null - }} - {...enableDirUpload} multiple /> + { + e.stopPropagation() + _paq.push([ + 'trackEvent', + 'fileExplorer', + 'fileAction', + action + ]) + props.uploadFolder(e.target) + e.target.value = null + }} + {...enableDirUpload} + multiple + /> ) @@ -127,7 +170,12 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { placement={placement as Placement} tooltipId={`${action}-${title}-${icon}-${index}`} tooltipClasses="text-nowrap" - tooltipText={} + tooltipText={ + + } key={`${action}-${title}-${index}`} > { data-id={'fileExplorerNewFile' + action} onClick={(e) => { e.stopPropagation() - _paq.push(['trackEvent', 'fileExplorer', 'fileAction', action]) + _paq.push([ + 'trackEvent', + 'fileExplorer', + 'fileAction', + action + ]) if (action === 'createNewFile') { props.createNewFile() } else if (action === 'createNewFolder') { @@ -148,8 +201,7 @@ export const FileExplorerMenu = (props: FileExplorerMenuProps) => { }} className={'newFile ' + icon + ' px-1 remixui_newFile'} key={`${action}-${title}-${index}`} - > - + > ) } diff --git a/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx b/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx index ae17e2af9a..b015e04f2f 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx @@ -1,22 +1,41 @@ -import React, { useEffect, useState, useRef, SyntheticEvent } from 'react' // eslint-disable-line -import { TreeView, TreeViewItem } from '@remix-ui/tree-view' // eslint-disable-line -import { FileExplorerMenu } from './file-explorer-menu' // eslint-disable-line -import { FileExplorerContextMenu } from './file-explorer-context-menu' // eslint-disable-line -import { FileExplorerProps, WorkSpaceState } from '../types' +import React, {useEffect, useState, useRef, SyntheticEvent} from 'react' // eslint-disable-line +import {TreeView, TreeViewItem} from '@remix-ui/tree-view' // eslint-disable-line +import {FileExplorerMenu} from './file-explorer-menu' // eslint-disable-line +import {FileExplorerContextMenu} from './file-explorer-context-menu' // eslint-disable-line +import {FileExplorerProps, WorkSpaceState} from '../types' import '../css/file-explorer.css' -import { checkSpecialChars, extractNameFromKey, extractParentFromKey, joinPath } from '@remix-ui/helper' +import { + checkSpecialChars, + extractNameFromKey, + extractParentFromKey, + joinPath +} from '@remix-ui/helper' // eslint-disable-next-line @typescript-eslint/no-unused-vars -import { FileRender } from './file-render' -import { Drag } from "@remix-ui/drag-n-drop" -import { ROOT_PATH } from '../utils/constants' +import {FileRender} from './file-render' +import {Drag} from '@remix-ui/drag-n-drop' +import {ROOT_PATH} from '../utils/constants' export const FileExplorer = (props: FileExplorerProps) => { - const { name, contextMenuItems, removedContextMenuItems, files, workspaceState, toGist, addMenuItems, - removeMenuItems, handleContextMenu, handleNewFileInput, handleNewFolderInput, uploadFile, uploadFolder, fileState } = props - const [state, setState] = useState( workspaceState) + const { + name, + contextMenuItems, + removedContextMenuItems, + files, + workspaceState, + toGist, + addMenuItems, + removeMenuItems, + handleContextMenu, + handleNewFileInput, + handleNewFolderInput, + uploadFile, + uploadFolder, + fileState + } = props + const [state, setState] = useState(workspaceState) const treeRef = useRef(null) - + useEffect(() => { if (contextMenuItems) { addMenuItems(contextMenuItems) @@ -31,8 +50,16 @@ export const FileExplorer = (props: FileExplorerProps) => { useEffect(() => { if (props.focusEdit) { - setState(prevState => { - return { ...prevState, focusEdit: { element: props.focusEdit, type: 'file', isNew: true, lastEdit: null } } + setState((prevState) => { + return { + ...prevState, + focusEdit: { + element: props.focusEdit, + type: 'file', + isNew: true, + lastEdit: null + } + } }) } }, [props.focusEdit]) @@ -45,21 +72,21 @@ export const FileExplorer = (props: FileExplorerProps) => { if (treeRef.current) { const keyPressHandler = (e: KeyboardEvent) => { if (e.shiftKey) { - setState(prevState => { - return { ...prevState, ctrlKey: true } + setState((prevState) => { + return {...prevState, ctrlKey: true} }) } } - + const keyUpHandler = (e: KeyboardEvent) => { if (!e.shiftKey) { - setState(prevState => { - return { ...prevState, ctrlKey: false } + setState((prevState) => { + return {...prevState, ctrlKey: false} }) } } const targetDocument = treeRef.current - + targetDocument.addEventListener('keydown', keyPressHandler) targetDocument.addEventListener('keyup', keyUpHandler) return () => { @@ -70,7 +97,11 @@ export const FileExplorer = (props: FileExplorerProps) => { }, [treeRef.current]) const hasReservedKeyword = (content: string): boolean => { - if (state.reservedKeywords.findIndex(value => content.startsWith(value)) !== -1) return true + if ( + state.reservedKeywords.findIndex((value) => content.startsWith(value)) !== + -1 + ) + return true else return false } @@ -78,7 +109,12 @@ export const FileExplorer = (props: FileExplorerProps) => { try { props.dispatchCreateNewFile(newFilePath, ROOT_PATH) } catch (error) { - return props.modal('File Creation Failed', typeof error === 'string' ? error : error.message, 'Close', async () => {}) + return props.modal( + 'File Creation Failed', + typeof error === 'string' ? error : error.message, + 'Close', + async () => {} + ) } } @@ -86,7 +122,12 @@ export const FileExplorer = (props: FileExplorerProps) => { try { props.dispatchCreateNewFolder(newFolderPath, ROOT_PATH) } catch (e) { - return props.modal('Folder Creation Failed', typeof e === 'string' ? e : e.message, 'Close', async () => {}) + return props.modal( + 'Folder Creation Failed', + typeof e === 'string' ? e : e.message, + 'Close', + async () => {} + ) } } @@ -94,42 +135,66 @@ export const FileExplorer = (props: FileExplorerProps) => { try { props.dispatchRenamePath(oldPath, newPath) } catch (error) { - props.modal('Rename File Failed', 'Unexpected error while renaming: ' + typeof error === 'string' ? error : error.message, 'Close', async () => {}) + props.modal( + 'Rename File Failed', + 'Unexpected error while renaming: ' + typeof error === 'string' + ? error + : error.message, + 'Close', + async () => {} + ) } } const publishToGist = (path?: string, type?: string) => { - props.modal('Create a public gist', `Are you sure you want to anonymously publish all your files in the ${name} workspace as a public gist on github.com?`, 'OK', () => toGist(path, type), 'Cancel', () => {}) + props.modal( + 'Create a public gist', + `Are you sure you want to anonymously publish all your files in the ${name} workspace as a public gist on github.com?`, + 'OK', + () => toGist(path, type), + 'Cancel', + () => {} + ) } - const handleClickFile = (path: string, type: 'folder' | 'file' | 'gist') => { if (!state.ctrlKey) { props.dispatchHandleClickFile(path, type) } else { - if (props.focusElement.findIndex(item => item.key === path) !== -1) { - const focusElement = props.focusElement.filter(item => item.key !== path) + if (props.focusElement.findIndex((item) => item.key === path) !== -1) { + const focusElement = props.focusElement.filter( + (item) => item.key !== path + ) props.dispatchSetFocusElement(focusElement) } else { - const nonRootFocus = props.focusElement.filter((el) => { return !(el.key === '' && el.type === 'folder') }) + const nonRootFocus = props.focusElement.filter((el) => { + return !(el.key === '' && el.type === 'folder') + }) - nonRootFocus.push({ key: path, type }) + nonRootFocus.push({key: path, type}) props.dispatchSetFocusElement(nonRootFocus) } } } - const handleClickFolder = async (path: string, type: 'folder' | 'file' | 'gist') => { + const handleClickFolder = async ( + path: string, + type: 'folder' | 'file' | 'gist' + ) => { if (state.ctrlKey) { - if (props.focusElement.findIndex(item => item.key === path) !== -1) { - const focusElement = props.focusElement.filter(item => item.key !== path) + if (props.focusElement.findIndex((item) => item.key === path) !== -1) { + const focusElement = props.focusElement.filter( + (item) => item.key !== path + ) props.dispatchSetFocusElement(focusElement) } else { - const nonRootFocus = props.focusElement.filter((el) => { return !(el.key === '' && el.type === 'folder') }) + const nonRootFocus = props.focusElement.filter((el) => { + return !(el.key === '' && el.type === 'folder') + }) - nonRootFocus.push({ key: path, type }) + nonRootFocus.push({key: path, type}) props.dispatchSetFocusElement(nonRootFocus) } } else { @@ -139,10 +204,16 @@ export const FileExplorer = (props: FileExplorerProps) => { expandPath = [...new Set([...props.expandPath, path])] props.dispatchFetchDirectory(path) } else { - expandPath = [...new Set(props.expandPath.filter(key => key && (typeof key === 'string') && !key.startsWith(path)))] + expandPath = [ + ...new Set( + props.expandPath.filter( + (key) => key && typeof key === 'string' && !key.startsWith(path) + ) + ) + ] } - props.dispatchSetFocusElement([{ key: path, type }]) + props.dispatchSetFocusElement([{key: path, type}]) props.dispatchHandleExpandPath(expandPath) } } @@ -151,37 +222,63 @@ export const FileExplorer = (props: FileExplorerProps) => { if (typeof content === 'string') content = content.trim() const parentFolder = extractParentFromKey(state.focusEdit.element) - if (!content || (content.trim() === '')) { + if (!content || content.trim() === '') { if (state.focusEdit.isNew) { props.dispatchRemoveInputField(parentFolder) - setState(prevState => { - return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } + setState((prevState) => { + return { + ...prevState, + focusEdit: {element: null, isNew: false, type: '', lastEdit: ''} + } }) } else { - setState(prevState => { - return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } + setState((prevState) => { + return { + ...prevState, + focusEdit: {element: null, isNew: false, type: '', lastEdit: ''} + } }) } } else { if (state.focusEdit.lastEdit === content) { - return setState(prevState => { - return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } + return setState((prevState) => { + return { + ...prevState, + focusEdit: {element: null, isNew: false, type: '', lastEdit: ''} + } }) } if (checkSpecialChars(content)) { - props.modal('Validation Error', 'Special characters are not allowed', 'OK', () => {}) + props.modal( + 'Validation Error', + 'Special characters are not allowed', + 'OK', + () => {} + ) } else { if (state.focusEdit.isNew) { if (hasReservedKeyword(content)) { props.dispatchRemoveInputField(parentFolder) - props.modal('Reserved Keyword', `File name contains Remix reserved keywords. '${content}'`, 'Close', () => {}) + props.modal( + 'Reserved Keyword', + `File name contains Remix reserved keywords. '${content}'`, + 'Close', + () => {} + ) } else { - state.focusEdit.type === 'file' ? createNewFile(joinPath(parentFolder, content)) : createNewFolder(joinPath(parentFolder, content)) + state.focusEdit.type === 'file' + ? createNewFile(joinPath(parentFolder, content)) + : createNewFolder(joinPath(parentFolder, content)) props.dispatchRemoveInputField(parentFolder) } } else { if (hasReservedKeyword(content)) { - props.modal('Reserved Keyword', `File name contains Remix reserved keywords. '${content}'`, 'Close', () => {}) + props.modal( + 'Reserved Keyword', + `File name contains Remix reserved keywords. '${content}'`, + 'Close', + () => {} + ) } else { if (state.focusEdit.element) { const oldPath: string = state.focusEdit.element @@ -192,24 +289,39 @@ export const FileExplorer = (props: FileExplorerProps) => { } } } - setState(prevState => { - return { ...prevState, focusEdit: { element: null, isNew: false, type: '', lastEdit: '' } } + setState((prevState) => { + return { + ...prevState, + focusEdit: {element: null, isNew: false, type: '', lastEdit: ''} + } }) } } } - const handleFileExplorerMenuClick = (e: SyntheticEvent) => { e.stopPropagation() - if (e && (e.target as any).getAttribute('data-id') === 'fileExplorerUploadFileuploadFile') return // we don't want to let propagate the input of type file - if (e && (e.target as any).getAttribute('data-id') === 'fileExplorerFileUpload') return // we don't want to let propagate the input of type file + if ( + e && + (e.target as any).getAttribute('data-id') === + 'fileExplorerUploadFileuploadFile' + ) + return // we don't want to let propagate the input of type file + if ( + e && + (e.target as any).getAttribute('data-id') === 'fileExplorerFileUpload' + ) + return // we don't want to let propagate the input of type file let expandPath = [] if (!props.expandPath.includes(ROOT_PATH)) { expandPath = [ROOT_PATH, ...new Set([...props.expandPath])] } else { - expandPath = [...new Set(props.expandPath.filter(key => key && (typeof key === 'string')))] + expandPath = [ + ...new Set( + props.expandPath.filter((key) => key && typeof key === 'string') + ) + ] } props.dispatchHandleExpandPath(expandPath) } @@ -218,23 +330,34 @@ export const FileExplorer = (props: FileExplorerProps) => { try { props.dispatchMoveFile(src, dest) } catch (error) { - props.modal('Moving File Failed', 'Unexpected error while moving file: ' + src, 'Close', async () => {}) - } + props.modal( + 'Moving File Failed', + 'Unexpected error while moving file: ' + src, + 'Close', + async () => {} + ) + } } const handleFolderMove = (dest: string, src: string) => { try { props.dispatchMoveFolder(src, dest) } catch (error) { - props.modal('Moving Folder Failed', 'Unexpected error while moving folder: ' + src, 'Close', async () => {}) - } + props.modal( + 'Moving Folder Failed', + 'Unexpected error while moving folder: ' + src, + 'Close', + async () => {} + ) + } } return ( - - - + + @@ -249,28 +372,30 @@ export const FileExplorer = (props: FileExplorerProps) => { /> } - expand={true}> - - - { - files[ROOT_PATH] && Object.keys(files[ROOT_PATH]).map((key, index) => ) - } + expand={true} + > + + + {files[ROOT_PATH] && + Object.keys(files[ROOT_PATH]).map((key, index) => ( + + ))}