Fixed rename bug

pull/668/head
ioedeveloper 4 years ago
parent c81b5ea79d
commit 138208b9cf
  1. 2
      apps/remix-ide/src/app/panels/file-panel.js
  2. 7
      libs/remix-ui/file-explorer/src/lib/file-explorer-context-menu.tsx
  3. 86
      libs/remix-ui/file-explorer/src/lib/file-explorer.tsx
  4. 7
      libs/remix-ui/file-explorer/src/lib/types/index.ts
  5. 15
      libs/remix-ui/tree-view/src/lib/tree-view-item/tree-view-item.tsx
  6. 1
      libs/remix-ui/tree-view/src/types/index.ts

@ -95,7 +95,7 @@ module.exports = class Filepanel extends ViewPlugin {
<FileExplorer
name='browser'
registry={this._components.registry}
files={this._deps.fileProviders.browser}
filesProvider={this._deps.fileProviders.browser}
menuItems={['createNewFile', 'createNewFolder', 'publishToGist', canUpload ? 'uploadFile' : '']}
plugin={this}
/>

@ -4,7 +4,7 @@ import { FileExplorerContextMenuProps } from './types'
import './css/file-explorer-context-menu.css'
export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) => {
const { actions, createNewFile, createNewFolder, deletePath, renamePath, hideContextMenu, pageX, pageY, path, ...otherProps } = props
const { actions, createNewFile, createNewFolder, deletePath, renamePath, hideContextMenu, pageX, pageY, path, type, ...otherProps } = props
const contextMenuRef = useRef(null)
useEffect(() => {
@ -23,12 +23,13 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) =>
}, [pageX, pageY])
const menu = () => {
return actions.map((item, index) => {
return actions.filter(item => item.type.findIndex(name => name === type) !== -1).map((item, index) => {
return <li
id={`menuitem${item.name.toLowerCase()}`}
key={index}
className='remixui_liitem'
onClick={() => {
onClick={(e) => {
e.stopPropagation()
switch (item.name) {
case 'New File':
createNewFile(path)

@ -9,7 +9,7 @@ import * as helper from '../../../../../apps/remix-ide/src/lib/helper'
import './css/file-explorer.css'
export const FileExplorer = (props: FileExplorerProps) => {
const { files, name, registry, plugin } = props
const { filesProvider, name, registry, plugin } = props
const containerRef = useRef(null)
const [state, setState] = useState({
focusElement: [{
@ -80,7 +80,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
const fetchDirectoryContent = async (folderPath: string): Promise<File[]> => {
return new Promise((resolve) => {
files.resolveDirectory(folderPath, (error, fileTree) => {
filesProvider.resolveDirectory(folderPath, (error, fileTree) => {
if (error) console.error(error)
const files = normalize(folderPath, fileTree)
@ -137,7 +137,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
const fileManager = state.fileManager
const newFileName = parentFolder + '/' + 'unnamed' + Math.floor(Math.random() * 101) // get filename from state (state.newFileName)
helper.createNonClashingName(newFileName, props.files, async (error, newName) => {
helper.createNonClashingName(newFileName, filesProvider, async (error, newName) => {
// if (error) return tooltip('Failed to create file ' + newName + ' ' + error)
if (error) return
const createFile = await fileManager.writeFile(newName, '')
@ -179,7 +179,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
const deletePath = async (path: string) => {
// if (self.files.isReadOnly(key)) { return tooltip('cannot delete file. ' + self.files.type + ' is a read only explorer') }
if (files.isReadOnly(path)) return
if (filesProvider.isReadOnly(path)) return
// const currentFilename = extractNameFromKey(path)
// modalDialogCustom.confirm(
@ -204,10 +204,22 @@ export const FileExplorer = (props: FileExplorerProps) => {
// )
}
const renamePath = async (path: string) => {
// if (self.files.isReadOnly(key)) { return tooltip('cannot rename folder. ' + self.files.type + ' is a read only explorer') }
if (files.isReadOnly(path)) return
editModeOn(path)
const renamePath = async (oldPath: string, newPath: string) => {
try {
const fileManager = state.fileManager
const exists = fileManager.exists(newPath)
if (exists) return
// modalDialogCustom.alert(File already exists.)
await fileManager.rename(oldPath, newPath)
const files = await replacePath(oldPath, newPath, state.files)
setState(prevState => {
return { ...prevState, files }
})
} catch (error) {
// modalDialogCustom.alert('Unexpected error while renaming: ' + error)
}
}
const addFile = async (parentFolder: string, newFileName: string) => {
@ -272,6 +284,24 @@ export const FileExplorer = (props: FileExplorerProps) => {
})
}
const replacePath = (oldPath: string, newPath: string, files: File[]): File[] => {
return files.map(file => {
if (file.path === oldPath) {
return {
...file,
path: newPath,
name: extractNameFromKey(newPath)
}
} else if (file.child) {
file.child = replacePath(oldPath, newPath, file.child)
return file
} else {
return file
}
})
}
// self._components = {}
// self._components.registry = localRegistry || globalRegistry
// self._deps = {
@ -344,8 +374,6 @@ export const FileExplorer = (props: FileExplorerProps) => {
title={data.path}
className={'remixui_label ' + (data.isDirectory ? 'folder' : 'remixui_leaf')}
data-path={data.path}
// onkeydown=${editModeOff}
// onblur=${editModeOff}
>
{ data.path.split('/').pop() }
</span>
@ -353,18 +381,14 @@ export const FileExplorer = (props: FileExplorerProps) => {
)
}
const onDragEnd = result => {
}
const handleClickFile = (path) => {
const handleClickFile = (path: string) => {
state.fileManager.open(path)
setState(prevState => {
return { ...prevState, focusElement: [{ key: path, type: 'file' }] }
})
}
const handleClickFolder = async (path) => {
const handleClickFolder = async (path: string) => {
if (state.ctrlKey) {
if (state.focusElement.findIndex(item => item.key === path) !== -1) {
setState(prevState => {
@ -402,13 +426,23 @@ export const FileExplorer = (props: FileExplorerProps) => {
})
}
const editModeOn = (path) => {
const editModeOn = (path: string) => {
if (filesProvider.isReadOnly(path)) return
setState(prevState => {
return { ...prevState, focusEdit: { element: path } }
})
}
const editModeOff = (path) => {
const editModeOff = (content: string) => {
if (!content) return
if (helper.checkSpecialChars(content)) {
// modalDialogCustom.alert('Special characters are not allowed')
}
const oldPath = state.focusEdit.element
const oldName = extractNameFromKey(oldPath)
const newPath = oldPath.replace(oldName, content)
renamePath(oldPath, newPath)
setState(prevState => {
return { ...prevState, focusEdit: { element: null } }
})
@ -435,7 +469,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
}}
labelClass={ state.focusEdit.element === file.path ? 'bg-light' : state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' }
editable={state.focusEdit.element === file.path}
onBlur={() => editModeOff(file.path)}
onBlur={(value) => editModeOff(value)}
controlBehaviour={ state.ctrlKey }
>
{
@ -449,15 +483,16 @@ export const FileExplorer = (props: FileExplorerProps) => {
</TreeViewItem>
{ (state.focusContext.element === file.path) &&
<FileExplorerContextMenu
actions={ state.actions.filter(item => item.type.findIndex(name => name === 'folder') !== -1) }
actions={state.actions}
hideContextMenu={hideContextMenu}
createNewFile={createNewFile}
createNewFolder={createNewFolder}
deletePath={deletePath}
renamePath={renamePath}
renamePath={editModeOn}
pageX={state.focusContext.x}
pageY={state.focusContext.y}
path={file.path}
type='folder'
/>
}
</>
@ -481,19 +516,20 @@ export const FileExplorer = (props: FileExplorerProps) => {
icon='fa fa-file'
labelClass={ state.focusEdit.element === file.path ? 'bg-light' : state.focusElement.findIndex(item => item.key === file.path) !== -1 ? 'bg-secondary' : '' }
editable={state.focusEdit.element === file.path}
onBlur={() => editModeOff(file.path)}
onBlur={(value) => editModeOff(value)}
/>
{ (state.focusContext.element === file.path) &&
<FileExplorerContextMenu
actions={ state.actions.filter(item => item.type.findIndex(name => name === 'file') !== -1) }
actions={state.actions}
hideContextMenu={hideContextMenu}
createNewFile={createNewFile}
createNewFolder={createNewFolder}
deletePath={deletePath}
renamePath={renamePath}
renamePath={editModeOn}
pageX={state.focusContext.x}
pageY={state.focusContext.y}
path={file.path}
type='file'
/>
}
</>
@ -527,7 +563,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
addFile={addFile}
createNewFile={createNewFile}
createNewFolder={createNewFolder}
files={props.files}
files={filesProvider}
fileManager={state.fileManager}
accessToken={state.accessToken}
/>

@ -2,7 +2,7 @@
export interface FileExplorerProps {
name: string,
registry: any,
files: any,
filesProvider: any,
menuItems?: string[],
plugin: any
}
@ -30,9 +30,10 @@ export interface FileExplorerContextMenuProps {
createNewFile: (folder?: string) => void,
createNewFolder: (parentFolder?: string) => void,
deletePath: (path: string) => void,
renamePath: (path: string) => void
renamePath: (path: string) => void,
hideContextMenu: () => void,
pageX: number,
pageY: number,
path: string
path: string,
type: string
}

@ -4,7 +4,7 @@ import { TreeViewItemProps } from '../../types'
import './tree-view-item.css'
export const TreeViewItem = (props: TreeViewItemProps) => {
const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, innerRef, editable, ...otherProps } = props
const { id, children, label, labelClass, expand, iconX = 'fas fa-caret-right', iconY = 'fas fa-caret-down', icon, controlBehaviour = false, innerRef, editable, onBlur, ...otherProps } = props
const [isExpanded, setIsExpanded] = useState(false)
const contentRef = useRef(null)
@ -18,11 +18,20 @@ export const TreeViewItem = (props: TreeViewItemProps) => {
}
}, [editable])
const handleInput = (event) => {
if (editable) {
if (event.which === 13) {
event.preventDefault()
onBlur && onBlur(contentRef.current.innerText)
}
}
}
return (
<li ref={innerRef} key={`treeViewLi${id}`} data-id={`treeViewLi${id}`} className='li_tv' {...otherProps}>
<li ref={innerRef} key={`treeViewLi${id}`} data-id={`treeViewLi${id}`} className='li_tv' onBlur={() => editable && onBlur(contentRef.current.innerText)} {...otherProps}>
<div key={`treeViewDiv${id}`} data-id={`treeViewDiv${id}`} className={`d-flex flex-row align-items-center ${labelClass}`} onClick={() => !controlBehaviour && setIsExpanded(!isExpanded)}>
{ children ? <div className={isExpanded ? `px-1 ${iconY} caret caret_tv` : `px-1 ${iconX} caret caret_tv`} style={{ visibility: children ? 'visible' : 'hidden' }}></div> : icon ? <div className={`pr-3 pl-1 ${icon} caret caret_tv`}></div> : null }
<span className='w-100 pl-1' ref={contentRef} contentEditable={editable} tabIndex={editable ? -3 : null}>
<span className='w-100 pl-1' ref={contentRef} suppressContentEditableWarning={true} contentEditable={editable} tabIndex={editable ? -3 : null} onKeyDown={handleInput}>
{ label }
</span>
</div>

@ -9,6 +9,7 @@ export interface TreeViewItemProps {
label: string | number | React.ReactNode,
expand?: boolean,
onClick?: (...args: any) => void,
onInput?: (...args: any) => void,
className?: string,
iconX?: string,
iconY?: string,

Loading…
Cancel
Save