Merge pull request #2818 from ethereum/fix-fs

Maintain standard for root directory
pull/5370/head
bunsenstraat 2 years ago committed by GitHub
commit 21d58b69d7
  1. 2
      apps/remix-ide-e2e/src/tests/plugin_api.ts
  2. 9
      apps/remix-ide/src/app/files/fileProvider.js
  3. 13
      apps/remix-ide/src/app/files/workspaceFileProvider.js
  4. 5
      libs/remix-ui/workspace/src/lib/actions/events.ts
  5. 3
      libs/remix-ui/workspace/src/lib/actions/workspace.ts
  6. 27
      libs/remix-ui/workspace/src/lib/components/file-explorer.tsx
  7. 32
      libs/remix-ui/workspace/src/lib/reducers/workspace.ts
  8. 5
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  9. 1
      libs/remix-ui/workspace/src/lib/utils/constants.ts

@ -295,7 +295,7 @@ module.exports = {
scripts: { isDirectory: true },
tests: { isDirectory: true },
'README.txt': { isDirectory: false }
}, null, null)
}, null, '/')
},
'Should get all workspaces #group2': async function (browser: NightwatchBrowser) {
await clickAndCheckLog(browser, 'filePanel:getWorkspaces', [{name:"default_workspace",isGitRepo:false}, {name:"emptyworkspace",isGitRepo:false}, {name:"testspace",isGitRepo:false}], null, null)

@ -127,7 +127,13 @@ class FileProvider {
async createDir (path, cb) {
const unprefixedpath = this.removePrefix(path)
const paths = unprefixedpath.split('/')
await this.forceCreateDir(unprefixedpath)
if (cb) cb()
}
async forceCreateDir (path) {
const paths = path.split('/')
if (paths.length && paths[0] === '') paths.shift()
let currentCheck = ''
for (const value of paths) {
@ -141,7 +147,6 @@ class FileProvider {
}
}
}
if (cb) cb()
}
// this will not add a folder as readonly but keep the original url to be able to restore it later

@ -2,7 +2,6 @@
const EventManager = require('events')
const FileProvider = require('./fileProvider')
const pathModule = require('path')
class WorkspaceFileProvider extends FileProvider {
constructor () {
@ -31,16 +30,10 @@ class WorkspaceFileProvider extends FileProvider {
}
removePrefix (path) {
if (!path) path = '/'
path = path.replace(/^\/|\/$/g, '') // remove first and last slash
path = path.replace(/^\.\/+/, '') // remove ./ from start of string
if (path.startsWith(this.workspacesPath + '/' + this.workspace)) return path
const splitPath = path.split('/')
if (splitPath[0] === this.workspace) {
splitPath[0] = this.workspacesPath + '/' + this.workspace
path = splitPath.join('/')
return path
}
path = super.removePrefix(path)
let ret = this.workspacesPath + '/' + this.workspace + '/' + (path === '/' ? '' : path)
@ -80,8 +73,10 @@ class WorkspaceFileProvider extends FileProvider {
async createWorkspace (name) {
try {
if (!name) name = 'default_workspace'
const path = this.workspacesPath + '/' + name
await super.forceCreateDir(path)
this.setWorkspace(name)
await super.createDir(name)
this.event.emit('createWorkspace', name)
} catch (e) {
throw new Error(e)

@ -2,6 +2,7 @@ import { fileDecoration } from '@remix-ui/file-decorators'
import { extractParentFromKey } from '@remix-ui/helper'
import React from 'react'
import { action, WorkspaceTemplate } from '../types'
import { ROOT_PATH } from '../utils/constants'
import { displayNotification, displayPopUp, fileAddedSuccess, fileRemovedSuccess, fileRenamedSuccess, folderAddedSuccess, loadLocalhostError, loadLocalhostRequest, loadLocalhostSuccess, removeContextMenuItem, removeFocus, rootFolderChangedSuccess, setContextMenuItem, setMode, setReadOnlyMode, setFileDecorationSuccess } from './payload'
import { addInputField, createWorkspace, deleteWorkspace, fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile } from './workspace'
@ -164,7 +165,7 @@ const fileAdded = async (filePath: string) => {
const folderAdded = async (folderPath: string) => {
const provider = plugin.fileManager.currentFileProvider()
const path = extractParentFromKey(folderPath) || provider.workspace || provider.type || ''
const path = extractParentFromKey(folderPath) || ROOT_PATH
const promise = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree) => {
@ -188,7 +189,7 @@ const fileRemoved = async (removePath: string) => {
const fileRenamed = async (oldPath: string) => {
const provider = plugin.fileManager.currentFileProvider()
const path = extractParentFromKey(oldPath) || provider.workspace || provider.type || ''
const path = extractParentFromKey(oldPath) || ROOT_PATH
const promise = new Promise((resolve) => {
provider.resolveDirectory(path, (error, fileTree) => {
if (error) console.error(error)

@ -7,6 +7,7 @@ import { checkSlash, checkSpecialChars } from '@remix-ui/helper'
import { JSONStandardInput, WorkspaceTemplate } from '../types'
import { QueryParams } from '@remix-project/remix-lib'
import * as templateWithContent from '@remix-project/remix-ws-templates'
import { ROOT_PATH } from '../utils/constants'
const LOCALHOST = ' - connect to localhost - '
@ -346,7 +347,7 @@ export const cloneRepository = async (url: string) => {
const isActive = await plugin.call('manager', 'isActive', 'dgit')
if (!isActive) await plugin.call('manager', 'activatePlugin', 'dgit')
await fetchWorkspaceDirectory(repoName)
await fetchWorkspaceDirectory(ROOT_PATH)
dispatch(cloneRepositorySuccess())
}).catch(() => {
const cloneModal = {

@ -11,6 +11,7 @@ import { checkSpecialChars, extractNameFromKey, extractParentFromKey, joinPath }
// 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'
export const FileExplorer = (props: FileExplorerProps) => {
const { name, contextMenuItems, removedContextMenuItems, files, fileState } = props
@ -32,7 +33,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
},
mouseOverElement: null,
showContextMenu: false,
reservedKeywords: [name, 'gist-'],
reservedKeywords: [ROOT_PATH, 'gist-'],
copyElement: []
})
const [canPaste, setCanPaste] = useState(false)
@ -137,14 +138,14 @@ export const FileExplorer = (props: FileExplorerProps) => {
if (props.focusElement[0]) {
if (props.focusElement[0].type === 'folder' && props.focusElement[0].key) return props.focusElement[0].key
else if (props.focusElement[0].type === 'gist' && props.focusElement[0].key) return props.focusElement[0].key
else if (props.focusElement[0].type === 'file' && props.focusElement[0].key) return extractParentFromKey(props.focusElement[0].key) ? extractParentFromKey(props.focusElement[0].key) : name
else return name
else if (props.focusElement[0].type === 'file' && props.focusElement[0].key) return extractParentFromKey(props.focusElement[0].key) ? extractParentFromKey(props.focusElement[0].key) : ROOT_PATH
else return ROOT_PATH
}
}
const createNewFile = async (newFilePath: string) => {
try {
props.dispatchCreateNewFile(newFilePath, props.name)
props.dispatchCreateNewFile(newFilePath, ROOT_PATH)
} catch (error) {
return props.modal('File Creation Failed', typeof error === 'string' ? error : error.message, 'Close', async () => {})
}
@ -152,7 +153,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
const createNewFolder = async (newFolderPath: string) => {
try {
props.dispatchCreateNewFolder(newFolderPath, props.name)
props.dispatchCreateNewFolder(newFolderPath, ROOT_PATH)
} catch (e) {
return props.modal('Folder Creation Failed', typeof e === 'string' ? e : e.message, 'Close', async () => {})
}
@ -174,10 +175,9 @@ export const FileExplorer = (props: FileExplorerProps) => {
}
const uploadFile = (target) => {
let parentFolder = getFocusedFolder()
const parentFolder = getFocusedFolder()
const expandPath = [...new Set([...props.expandPath, parentFolder])]
parentFolder = parentFolder === name ? '/' : parentFolder
props.dispatchHandleExpandPath(expandPath)
props.dispatchUploadFile(target, parentFolder)
}
@ -235,7 +235,6 @@ export const FileExplorer = (props: FileExplorerProps) => {
}
const handleClickFile = (path: string, type: 'folder' | 'file' | 'gist') => {
path = path.indexOf(props.name + '/') === 0 ? path.replace(props.name + '/', '') : path
if (!state.ctrlKey) {
props.dispatchHandleClickFile(path, type)
} else {
@ -379,7 +378,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
}
const handlePasteClick = (dest: string, destType: string) => {
dest = destType === 'file' ? extractParentFromKey(dest) || props.name : dest
dest = destType === 'file' ? extractParentFromKey(dest) || ROOT_PATH : dest
state.copyElement.map(({ key, type }) => {
type === 'file' ? copyFile(key, dest) : copyFolder(key, dest)
})
@ -402,10 +401,10 @@ export const FileExplorer = (props: FileExplorerProps) => {
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(props.name)) {
expandPath = [props.name, ...new Set([...props.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') && !key.startsWith(props.name)))]
expandPath = [...new Set(props.expandPath.filter(key => key && (typeof key === 'string')))]
}
props.dispatchHandleExpandPath(expandPath)
}
@ -447,8 +446,8 @@ export const FileExplorer = (props: FileExplorerProps) => {
<div className='pb-2'>
<TreeView id='treeViewMenu'>
{
files[props.name] && Object.keys(files[props.name]).map((key, index) => <FileRender
file={files[props.name][key]}
files[ROOT_PATH] && Object.keys(files[ROOT_PATH]).map((key, index) => <FileRender
file={files[ROOT_PATH][key]}
fileDecorations={fileState}
index={index}
focusContext={state.focusContext}

@ -2,6 +2,7 @@ import { extractNameFromKey } from '@remix-ui/helper'
import { action, FileType } from '../types'
import * as _ from 'lodash'
import { fileDecoration } from '@remix-ui/file-decorators'
import { ROOT_PATH } from '../utils/constants'
interface Action {
type: string
payload: any
@ -693,7 +694,7 @@ const fileRemoved = (state: BrowserState, path: string): { [x: string]: Record<s
const removeInputField = (state: BrowserState, path: string): { [x: string]: Record<string, FileType> } => {
let files = state.mode === 'browser' ? state.browser.files : state.localhost.files
const root = state.mode === 'browser' ? state.browser.currentWorkspace : state.mode
const root = state.mode === 'browser' ? ROOT_PATH : state.mode
if (path === root) {
delete files[root][path + '/' + 'blank']
@ -720,11 +721,11 @@ const removeInputField = (state: BrowserState, path: string): { [x: string]: Rec
const fetchDirectoryContent = (state: BrowserState, payload: { fileTree, path: string, type?: 'file' | 'folder' }, deletePath?: string): { [x: string]: Record<string, FileType> } => {
if (!payload.fileTree) return state.mode === 'browser' ? state.browser.files : state[state.mode].files
if (state.mode === 'browser') {
if (payload.path === state.browser.currentWorkspace) {
let files = normalize(payload.fileTree, payload.path, payload.type)
files = _.merge(files, state.browser.files[state.browser.currentWorkspace])
if (payload.path === ROOT_PATH) {
let files = normalize(payload.fileTree, ROOT_PATH, payload.type)
files = _.merge(files, state.browser.files[ROOT_PATH])
if (deletePath) delete files[deletePath]
return { [state.browser.currentWorkspace]: files }
return { [ROOT_PATH]: files }
} else {
let files = state.browser.files
const _path = splitPath(state, payload.path)
@ -755,14 +756,11 @@ const fetchDirectoryContent = (state: BrowserState, payload: { fileTree, path: s
return files
}
} else {
if (payload.path === '/') {
const files = normalize(payload.fileTree, payload.path, payload.type)
return { [state.mode]: files }
} else if (payload.path === state.mode) {
let files = normalize(payload.fileTree, payload.path, payload.type)
files = _.merge(files, state[state.mode].files[state.mode])
if (payload.path === ROOT_PATH) {
let files = normalize(payload.fileTree, ROOT_PATH, payload.type)
files = _.merge(files, state.localhost.files[ROOT_PATH])
if (deletePath) delete files[deletePath]
return { [state.mode]: files }
return { [ROOT_PATH]: files }
} else {
let files = state.localhost.files
const _path = splitPath(state, payload.path)
@ -787,13 +785,9 @@ const fetchDirectoryContent = (state: BrowserState, payload: { fileTree, path: s
}
const fetchWorkspaceDirectoryContent = (state: BrowserState, payload: { fileTree, path: string }): { [x: string]: Record<string, FileType> } => {
if (state.mode === 'browser') {
const files = normalize(payload.fileTree, payload.path)
const files = normalize(payload.fileTree, ROOT_PATH)
return { [payload.path]: files }
} else {
return fetchDirectoryContent(state, payload)
}
return { [ROOT_PATH]: files }
}
const normalize = (filesList, directory?: string, newInputType?: 'folder' | 'file'): Record<string, FileType> => {
@ -846,7 +840,7 @@ const normalize = (filesList, directory?: string, newInputType?: 'folder' | 'fil
}
const splitPath = (state: BrowserState, path: string): string[] | string => {
const root = state.mode === 'browser' ? state.browser.currentWorkspace : 'localhost'
const root = ROOT_PATH
const pathArr: string[] = (path || '').split('/').filter(value => value)
if (pathArr[0] !== root) pathArr.unshift(root)

@ -4,6 +4,7 @@ import { CustomMenu, CustomToggle } from '@remix-ui/helper'
import { FileExplorer } from './components/file-explorer' // eslint-disable-line
import { FileSystemContext } from './contexts'
import './css/remix-ui-workspace.css'
import { ROOT_PATH } from './utils/constants'
const canUpload = window.File || window.FileReader || window.FileList || window.Blob
@ -28,9 +29,9 @@ export function Workspace () {
if (global.fs.mode === 'browser') {
if (global.fs.browser.currentWorkspace) setCurrentWorkspace(global.fs.browser.currentWorkspace)
else setCurrentWorkspace(NO_WORKSPACE)
global.dispatchFetchWorkspaceDirectory(global.fs.browser.currentWorkspace)
global.dispatchFetchWorkspaceDirectory(ROOT_PATH)
} else if (global.fs.mode === 'localhost') {
global.dispatchFetchWorkspaceDirectory('/')
global.dispatchFetchWorkspaceDirectory(ROOT_PATH)
setCurrentWorkspace(LOCALHOST)
}
}, [global.fs.browser.currentWorkspace, global.fs.localhost.sharedFolder, global.fs.mode])

Loading…
Cancel
Save