@ -1,8 +1,10 @@
import React , { useState , useEffect , useRef , useContext } from 'react' // eslint-disable-line
import { FormattedMessage , useIntl } from 'react-intl'
import { Dropdown } from 'react-bootstrap'
import { CustomMenu , CustomToggle } from './components/custom-dropdown'
import { FileExplorer } from './components/file-explorer' // eslint-disable-line
import './css/remix-ui-workspace.css'
import { FileSystemContext } from './contexts'
import './css/remix-ui-workspace.css'
const canUpload = window . File || window . FileReader || window . FileList || window . Blob
@ -10,11 +12,13 @@ export function Workspace () {
const LOCALHOST = ' - connect to localhost - '
const NO_WORKSPACE = ' - none - '
const [ currentWorkspace , setCurrentWorkspace ] = useState < string > ( NO_WORKSPACE )
const [ selectedWorkspace , setSelectedWorkspace ] = useState < { name : string , isGitRepo : boolean } > ( null )
const global = useContext ( FileSystemContext )
const workspaceRenameInput = useRef ( )
const workspaceCreateInput = useRef ( )
const workspaceCreateTemplateInput = useRef ( )
const intl = useIntl ( )
const cloneUrlRef = useRef < HTMLInputElement > ( )
useEffect ( ( ) = > {
resetFocus ( )
@ -32,15 +36,21 @@ export function Workspace () {
} , [ global . fs . browser . currentWorkspace , global . fs . localhost . sharedFolder , global . fs . mode ] )
useEffect ( ( ) = > {
if ( global . fs . browser . currentWorkspace && ! global . fs . browser . workspaces . includes ( global . fs . browser . currentWorkspace ) ) {
if ( global . fs . browser . currentWorkspace && ! global . fs . browser . workspaces . find ( ( { name } ) = > name === global . fs . browser . currentWorkspace ) ) {
if ( global . fs . browser . workspaces . length > 0 ) {
switchWorkspace ( global . fs . browser . workspaces [ global . fs . browser . workspaces . length - 1 ] )
switchWorkspace ( global . fs . browser . workspaces [ global . fs . browser . workspaces . length - 1 ] . name )
} else {
switchWorkspace ( NO_WORKSPACE )
}
}
} , [ global . fs . browser . workspaces ] )
useEffect ( ( ) = > {
const workspace = global . fs . browser . workspaces . find ( workspace = > workspace . name === currentWorkspace )
setSelectedWorkspace ( workspace )
} , [ currentWorkspace ] )
const renameCurrentWorkspace = ( ) = > {
global . modal ( intl . formatMessage ( { id : 'filePanel.workspace.rename' , defaultMessage : 'Rename Current Workspace' } ) , renameModalMessage ( ) , 'OK' , onFinishRenameWorkspace , '' )
}
@ -59,6 +69,10 @@ export function Workspace () {
)
}
const cloneGitRepository = ( ) = > {
global . modal ( 'Clone Git Repository' , cloneModalMessage ( ) , 'OK' , handleTypingUrl , '' )
}
const downloadWorkspaces = async ( ) = > {
try {
await global . dispatchHandleDownloadFiles ( )
@ -132,6 +146,16 @@ export function Workspace () {
workspaceCreateInput . current . value = ` ${ workspaceCreateTemplateInput . current . value || 'remixDefault' } _ ${ Date . now ( ) } `
}
const handleTypingUrl = ( ) = > {
const url = cloneUrlRef . current . value
if ( url ) {
global . dispatchCloneRepository ( url )
} else {
global . modal ( 'Clone Git Repository' , 'Please provide a valid git repository url.' , 'OK' , ( ) = > { } , '' )
}
}
const createModalMessage = ( ) = > {
return (
< >
@ -157,6 +181,14 @@ export function Workspace () {
)
}
const cloneModalMessage = ( ) = > {
return (
< >
< input type = "text" data - id = "modalDialogCustomPromptTextClone" placeholder = 'Enter git repository url' ref = { cloneUrlRef } className = "form-control" / >
< / >
)
}
return (
< div className = 'remixui_container' >
< div className = 'remixui_fileexplorer' data - id = "remixUIWorkspaceExplorer" onClick = { resetFocus } >
@ -166,111 +198,142 @@ export function Workspace () {
< label className = "form-check-label" htmlFor = "workspacesSelect" >
< FormattedMessage id = 'filePanel.workspace' defaultMessage = 'Workspaces' / >
< / label >
< span className = "remixui_menu" >
< span
hidden = { currentWorkspace === LOCALHOST }
id = 'workspaceCreate'
data - id = 'workspaceCreate'
onClick = { ( e ) = > {
e . stopPropagation ( )
createWorkspace ( )
} }
className = 'far fa-plus-square remixui_menuicon'
title = { intl . formatMessage ( { id : 'filePanel.create' , defaultMessage : 'Create' } ) } >
< / span >
< span
hidden = { currentWorkspace === LOCALHOST || currentWorkspace === NO_WORKSPACE }
id = 'workspaceRename'
data - id = 'workspaceRename'
onClick = { ( e ) = > {
e . stopPropagation ( )
renameCurrentWorkspace ( )
} }
className = 'far fa-edit remixui_menuicon'
title = { intl . formatMessage ( { id : 'filePanel.rename' , defaultMessage : 'Rename' } ) } >
< / span >
< span
hidden = { currentWorkspace === LOCALHOST || currentWorkspace === NO_WORKSPACE }
id = 'workspaceDelete'
data - id = 'workspaceDelete'
onClick = { ( e ) = > {
e . stopPropagation ( )
deleteCurrentWorkspace ( )
} }
className = 'fas fa-trash remixui_menuicon'
title = { intl . formatMessage ( { id : 'filePanel.delete' , defaultMessage : 'Delete' } ) } >
< / span >
< span
hidden = { currentWorkspace === LOCALHOST || currentWorkspace === NO_WORKSPACE }
id = 'workspacesDownload'
data - id = 'workspacesDownload'
onClick = { ( e ) = > {
e . stopPropagation ( )
downloadWorkspaces ( )
} }
className = 'far fa-download remixui_menuicon'
title = { intl . formatMessage ( { id : 'filePanel.workspace.download' , defaultMessage : 'Download Workspaces' } ) } >
< span className = "remixui_menu" >
< span
hidden = { currentWorkspace === LOCALHOST }
id = 'workspaceCreate'
data - id = 'workspaceCreate'
onClick = { ( e ) = > {
e . stopPropagation ( )
createWorkspace ( )
} }
className = 'far fa-plus-square remixui_menuicon'
title = { intl . formatMessage ( { id : 'filePanel.create' , defaultMessage : 'Create' } ) } >
< / span >
< span
hidden = { currentWorkspace === LOCALHOST || currentWorkspace === NO_WORKSPACE }
id = 'workspaceRename'
data - id = 'workspaceRename'
onClick = { ( e ) = > {
e . stopPropagation ( )
renameCurrentWorkspace ( )
} }
className = 'far fa-edit remixui_menuicon'
title = { intl . formatMessage ( { id : 'filePanel.rename' , defaultMessage : 'Rename' } ) } >
< / span >
< span
hidden = { currentWorkspace === LOCALHOST || currentWorkspace === NO_WORKSPACE }
id = 'workspaceDelete'
data - id = 'workspaceDelete'
onClick = { ( e ) = > {
e . stopPropagation ( )
deleteCurrentWorkspace ( )
} }
className = 'fas fa-trash remixui_menuicon'
title = { intl . formatMessage ( { id : 'filePanel.delete' , defaultMessage : 'Delete' } ) } >
< / span >
< span
hidden = { currentWorkspace === LOCALHOST || currentWorkspace === NO_WORKSPACE }
id = 'workspacesDownload'
data - id = 'workspacesDownload'
onClick = { ( e ) = > {
e . stopPropagation ( )
downloadWorkspaces ( )
} }
className = 'far fa-download remixui_menuicon'
title = { intl . formatMessage ( { id : 'filePanel.workspace.download' , defaultMessage : 'Download Workspaces' } ) } >
< / span >
< span
hidden = { currentWorkspace === LOCALHOST }
id = 'workspacesRestore'
data - id = 'workspacesRestore'
onClick = { ( e ) = > {
e . stopPropagation ( )
restoreBackup ( )
} }
className = 'far fa-upload remixui_menuicon'
title = { intl . formatMessage ( { id : 'filePanel.workspace.restore' , defaultMessage : 'Restore Workspaces Backup' } ) } >
< / span >
< span
id = 'cloneGitRepository'
data - id = 'cloneGitRepository'
onClick = { ( e ) = > {
e . stopPropagation ( )
cloneGitRepository ( )
} }
className = 'far fa-clone remixui_menuicon'
title = 'Clone Git Repository' >
< / span >
< / span >
< span
hidden = { currentWorkspace === LOCALHOST }
id = 'workspacesRestore'
data - id = 'workspacesRestore'
onClick = { ( e ) = > {
e . stopPropagation ( )
restoreBackup ( )
} }
className = 'far fa-upload remixui_menuicon'
title = { intl . formatMessage ( { id : 'filePanel.workspace.restore' , defaultMessage : 'Restore Workspaces Backup' } ) } >
< / span >
< / span >
< select id = "workspacesSelect" value = { currentWorkspace } data - id = "workspacesSelect" onChange = { ( e ) = > switchWorkspace ( e . target . value ) } className = "form-control custom-select" >
{
global . fs . browser . workspaces
. map ( ( folder , index ) = > {
return < option key = { index } value = { folder } > { folder } < / option >
} )
}
< option value = { LOCALHOST } > { currentWorkspace === LOCALHOST ? 'localhost' : LOCALHOST } < / option >
{ global . fs . browser . workspaces . length <= 0 && < option value = { NO_WORKSPACE } > { NO_WORKSPACE } < / option > }
< / select >
< Dropdown id = "workspacesSelect" data - id = "workspacesSelect" >
< Dropdown.Toggle as = { CustomToggle } id = "dropdown-custom-components" className = "btn btn-light btn-block w-100 d-inline-block border border-dark form-control" icon = { selectedWorkspace && selectedWorkspace . isGitRepo ? 'far fa-code-branch' : null } >
{ selectedWorkspace ? selectedWorkspace.name : currentWorkspace === LOCALHOST ? 'localhost' : NO_WORKSPACE }
< / Dropdown.Toggle >
< Dropdown.Menu as = { CustomMenu } className = 'w-100 custom-dropdown-items' data - id = "custom-dropdown-items" >
{
global . fs . browser . workspaces . map ( ( { name , isGitRepo } , index ) = > (
< Dropdown.Item
key = { index }
onClick = { ( ) = > {
switchWorkspace ( name )
} }
data - id = { ` dropdown-item- ${ name } ` }
>
{ isGitRepo ?
< div className = 'd-flex justify-content-between' >
< span > { currentWorkspace === name ? < span > & # 10003 ; { name } < / span > : < span className = "pl-3" > { name } < / span > } < / span >
< i className = 'fas fa-code-branch pt-1' > < / i >
< / div > :
< span > { currentWorkspace === name ? < span > & # 10003 ; { name } < / span > : < span className = "pl-3" > { name } < / span > } < / span >
}
< / Dropdown.Item >
) )
}
< Dropdown.Item onClick = { ( ) = > { switchWorkspace ( LOCALHOST ) } } > { currentWorkspace === LOCALHOST ? < span > & # 10003 ; localhost < / span > : < span className = "pl-3" > { LOCALHOST } < / span > } < / Dropdown.Item >
{ ( ( global . fs . browser . workspaces . length <= 0 ) || currentWorkspace === NO_WORKSPACE ) && < Dropdown.Item onClick = { ( ) = > { switchWorkspace ( NO_WORKSPACE ) } } > { < span className = "pl-3" > NO_WORKSPACE < / span > } < / Dropdown.Item > }
< / Dropdown.Menu >
< / Dropdown >
< / div >
< / header >
< / div >
< div className = 'h-100 remixui_fileExplorerTree' >
< div className = 'h-100' >
< div className = 'pl-2 remixui_treeview' data - id = 'filePanelFileExplorerTree' >
{ ( global . fs . mode === 'browser' ) && ( currentWorkspace !== NO_WORKSPACE ) &&
< FileExplorer
name = { currentWorkspace }
menuItems = { [ 'createNewFile' , 'createNewFolder' , 'publishToGist' , canUpload ? 'uploadFile' : '' ] }
contextMenuItems = { global . fs . browser . contextMenu . registeredMenuItems }
removedContextMenuItems = { global . fs . browser . contextMenu . removedMenuItems }
files = { global . fs . browser . files }
expandPath = { global . fs . browser . expandPath }
focusEdit = { global . fs . focusEdit }
focusElement = { global . fs . focusElement }
dispatchCreateNewFile = { global . dispatchCreateNewFile }
modal = { global . modal }
dispatchCreateNewFolder = { global . dispatchCreateNewFolder }
readonly = { global . fs . readonly }
toast = { global . toast }
dispatchDeletePath = { global . dispatchDeletePath }
dispatchRenamePath = { global . dispatchRenamePath }
dispatchUploadFile = { global . dispatchUploadFile }
dispatchCopyFile = { global . dispatchCopyFile }
dispatchCopyFolder = { global . dispatchCopyFolder }
dispatchPublishToGist = { global . dispatchPublishToGist }
dispatchRunScript = { global . dispatchRunScript }
dispatchEmitContextMenuEvent = { global . dispatchEmitContextMenuEvent }
dispatchHandleClickFile = { global . dispatchHandleClickFile }
dispatchSetFocusElement = { global . dispatchSetFocusElement }
dispatchFetchDirectory = { global . dispatchFetchDirectory }
dispatchRemoveInputField = { global . dispatchRemoveInputField }
dispatchAddInputField = { global . dispatchAddInputField }
dispatchHandleExpandPath = { global . dispatchHandleExpandPath }
/ >
}
< / div >
{ global . fs . browser . isRequestingWorkspace || global . fs . browser . isRequestingCloning ? < div className = "text-center py-5" > < i className = "fas fa-spinner fa-pulse fa-2x" > < / i > < / div >
: < div className = 'pl-2 remixui_treeview' data - id = 'filePanelFileExplorerTree' >
{ ( global . fs . mode === 'browser' ) && ( currentWorkspace !== NO_WORKSPACE ) &&
< FileExplorer
name = { currentWorkspace }
menuItems = { [ 'createNewFile' , 'createNewFolder' , 'publishToGist' , canUpload ? 'uploadFile' : '' ] }
contextMenuItems = { global . fs . browser . contextMenu . registeredMenuItems }
removedContextMenuItems = { global . fs . browser . contextMenu . removedMenuItems }
files = { global . fs . browser . files }
expandPath = { global . fs . browser . expandPath }
focusEdit = { global . fs . focusEdit }
focusElement = { global . fs . focusElement }
dispatchCreateNewFile = { global . dispatchCreateNewFile }
modal = { global . modal }
dispatchCreateNewFolder = { global . dispatchCreateNewFolder }
readonly = { global . fs . readonly }
toast = { global . toast }
dispatchDeletePath = { global . dispatchDeletePath }
dispatchRenamePath = { global . dispatchRenamePath }
dispatchUploadFile = { global . dispatchUploadFile }
dispatchCopyFile = { global . dispatchCopyFile }
dispatchCopyFolder = { global . dispatchCopyFolder }
dispatchPublishToGist = { global . dispatchPublishToGist }
dispatchRunScript = { global . dispatchRunScript }
dispatchEmitContextMenuEvent = { global . dispatchEmitContextMenuEvent }
dispatchHandleClickFile = { global . dispatchHandleClickFile }
dispatchSetFocusElement = { global . dispatchSetFocusElement }
dispatchFetchDirectory = { global . dispatchFetchDirectory }
dispatchRemoveInputField = { global . dispatchRemoveInputField }
dispatchAddInputField = { global . dispatchAddInputField }
dispatchHandleExpandPath = { global . dispatchHandleExpandPath }
/ >
}
< / div >
}
{
global . fs . localhost . isRequestingLocalhost ? < div className = "text-center py-5" > < i className = "fas fa-spinner fa-pulse fa-2x" > < / i > < / div >
: < div className = 'pl-2 filesystemexplorer remixui_treeview' >