Commit 783e92d0 authored by ioedeveloper's avatar ioedeveloper

Move context menu operation to reducer and removed duplicate event registration

parent 7ad686d1
...@@ -9,7 +9,6 @@ const { GitHandle } = require('../files/git-handle.js') ...@@ -9,7 +9,6 @@ const { GitHandle } = require('../files/git-handle.js')
const { HardhatHandle } = require('../files/hardhat-handle.js') const { HardhatHandle } = require('../files/hardhat-handle.js')
const { SlitherHandle } = require('../files/slither-handle.js') const { SlitherHandle } = require('../files/slither-handle.js')
const globalRegistry = require('../../global/registry') const globalRegistry = require('../../global/registry')
const modalDialogCustom = require('../ui/modal-dialog-custom')
/* /*
Overview of APIs: Overview of APIs:
* fileManager: @args fileProviders (browser, shared-folder, swarm, github, etc ...) & config & editor * fileManager: @args fileProviders (browser, shared-folder, swarm, github, etc ...) & config & editor
...@@ -53,11 +52,7 @@ module.exports = class Filepanel extends ViewPlugin { ...@@ -53,11 +52,7 @@ module.exports = class Filepanel extends ViewPlugin {
this.gitHandle = new GitHandle() this.gitHandle = new GitHandle()
this.hardhatHandle = new HardhatHandle() this.hardhatHandle = new HardhatHandle()
this.slitherHandle = new SlitherHandle() this.slitherHandle = new SlitherHandle()
this.registeredMenuItems = []
this.removedMenuItems = []
this.request = {}
this.workspaces = [] this.workspaces = []
this.initialWorkspace = null
this.appManager = appManager this.appManager = appManager
this.workspaceStatus = {} this.workspaceStatus = {}
} }
...@@ -81,26 +76,11 @@ module.exports = class Filepanel extends ViewPlugin { ...@@ -81,26 +76,11 @@ module.exports = class Filepanel extends ViewPlugin {
* @param callback (...args) => void * @param callback (...args) => void
*/ */
registerContextMenuItem (item) { registerContextMenuItem (item) {
if (!item) throw new Error('Invalid register context menu argument') this.emit('registerContextMenuItem', item)
if (!item.name || !item.id) throw new Error('Item name and id is mandatory')
if (!item.type && !item.path && !item.extension && !item.pattern) throw new Error('Invalid file matching criteria provided')
if (this.registeredMenuItems.filter((o) => {
return o.id === item.id && o.name === item.name
}).length) throw new Error(`Action ${item.name} already exists on ${item.id}`)
this.registeredMenuItems = [...this.registeredMenuItems, item]
this.removedMenuItems = this.removedMenuItems.filter(menuItem => item.id !== menuItem.id)
this.renderComponent()
} }
removePluginActions (plugin) { removePluginActions (plugin) {
this.registeredMenuItems = this.registeredMenuItems.filter((item) => { this.emit('removePluginActions', plugin)
if (item.id !== plugin.name || item.sticky === true) return true
else {
this.removedMenuItems.push(item)
return false
}
})
this.renderComponent()
} }
getCurrentWorkspace () { getCurrentWorkspace () {
......
import { extractParentFromKey } from '@remix-ui/helper' import { extractParentFromKey } from '@remix-ui/helper'
import React from 'react' import React from 'react'
import { displayNotification, fileAddedSuccess, fileRemovedSuccess, fileRenamedSuccess, folderAddedSuccess, rootFolderChangedSuccess } from './payload' import { action } from '../types'
import { displayNotification, displayPopUp, fileAddedSuccess, fileRemovedSuccess, fileRenamedSuccess, folderAddedSuccess, removeContextMenuItem, rootFolderChangedSuccess, setContextMenuItem } from './payload'
import { addInputField, createWorkspace, fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile } from './workspace' import { addInputField, createWorkspace, fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile } from './workspace'
const queuedEvents = [] const queuedEvents = []
...@@ -8,8 +9,39 @@ const pendingEvents = {} ...@@ -8,8 +9,39 @@ const pendingEvents = {}
const LOCALHOST = ' - connect to localhost - ' const LOCALHOST = ' - connect to localhost - '
let plugin, dispatch: React.Dispatch<any> let plugin, dispatch: React.Dispatch<any>
export const listenOnEvents = (filePanelPlugin, provider) => async (reducerDispatch: React.Dispatch<any>) => { export const listenOnPluginEvents = (filePanelPlugin) => {
plugin = filePanelPlugin plugin = filePanelPlugin
plugin.on('filePanel', 'createWorkspace', (name: string) => {
createWorkspace(name)
})
plugin.on('filePanel', 'renameWorkspace', (oldName: string, workspaceName: string) => {
renameWorkspace(oldName, workspaceName)
})
plugin.on('filePanel', 'registerContextMenuItem', (item: action) => {
registerContextMenuItem(item)
})
plugin.on('filePanel', 'removePluginActions', (plugin) => {
removePluginActions(plugin)
})
plugin.on('filePanel', 'displayNewFileInput', (path) => {
addInputField('file', path)
})
plugin.on('filePanel', 'uploadFileEvent', (dir: string, target) => {
uploadFile(target, dir)
})
plugin.on('remixd', 'rootFolderChanged', async (path: string) => {
await executeEvent('rootFolderChanged', path)
})
}
export const listenOnProviderEvents = (provider) => async (reducerDispatch: React.Dispatch<any>) => {
dispatch = reducerDispatch dispatch = reducerDispatch
provider.event.on('fileAdded', async (filePath: string) => { provider.event.on('fileAdded', async (filePath: string) => {
...@@ -29,10 +61,6 @@ export const listenOnEvents = (filePanelPlugin, provider) => async (reducerDispa ...@@ -29,10 +61,6 @@ export const listenOnEvents = (filePanelPlugin, provider) => async (reducerDispa
await executeEvent('fileRenamed', oldPath, newPath) await executeEvent('fileRenamed', oldPath, newPath)
}) })
plugin.on('remixd', 'rootFolderChanged', async (path: string) => {
await executeEvent('rootFolderChanged', path)
})
// provider.event.on('disconnected', () => { // provider.event.on('disconnected', () => {
// dispatch(setMode('browser')) // dispatch(setMode('browser'))
// }) // })
...@@ -77,29 +105,21 @@ export const listenOnEvents = (filePanelPlugin, provider) => async (reducerDispa ...@@ -77,29 +105,21 @@ export const listenOnEvents = (filePanelPlugin, provider) => async (reducerDispa
provider.event.on('fileRenamedError', async () => { provider.event.on('fileRenamedError', async () => {
dispatch(displayNotification('File Renamed Failed', '', 'Ok', 'Cancel')) dispatch(displayNotification('File Renamed Failed', '', 'Ok', 'Cancel'))
}) })
}
plugin.on('filePanel', 'displayNewFileInput', (path) => { const registerContextMenuItem = (item: action) => {
addInputField('file', path) if (!item) return dispatch(displayPopUp('Invalid register context menu argument'))
}) if (!item.name || !item.id) return dispatch(displayPopUp('Item name and id is mandatory'))
if (!item.type && !item.path && !item.extension && !item.pattern) return dispatch(displayPopUp('Invalid file matching criteria provided'))
plugin.on('filePanel', 'uploadFileEvent', (dir: string, target) => { dispatch(setContextMenuItem(item))
uploadFile(target, dir) }
})
provider.event.on('createWorkspace', (name: string) => {
createWorkspace(name)
})
plugin.on('filePanel', 'createWorkspace', (name: string) => {
createWorkspace(name)
})
plugin.on('filePanel', 'renameWorkspace', (oldName: string, workspaceName: string) => { const removePluginActions = (plugin) => {
renameWorkspace(oldName, workspaceName) dispatch(removeContextMenuItem(plugin))
})
} }
const fileAdded = async (filePath: string) => { const fileAdded = async (filePath: string) => {
console.log('fileAdded: ', filePath)
await dispatch(fileAddedSuccess(filePath)) await dispatch(fileAddedSuccess(filePath))
if (filePath.includes('_test.sol')) { if (filePath.includes('_test.sol')) {
plugin.emit('newTestFileCreated', filePath) plugin.emit('newTestFileCreated', filePath)
...@@ -107,6 +127,7 @@ const fileAdded = async (filePath: string) => { ...@@ -107,6 +127,7 @@ const fileAdded = async (filePath: string) => {
} }
const folderAdded = async (folderPath: string) => { const folderAdded = async (folderPath: string) => {
console.log('folderAdded: ', folderPath)
const provider = plugin.fileManager.currentFileProvider() const provider = plugin.fileManager.currentFileProvider()
const path = extractParentFromKey(folderPath) || provider.workspace || provider.type || '' const path = extractParentFromKey(folderPath) || provider.workspace || provider.type || ''
......
import { action } from '../types'
export const setCurrentWorkspace = (workspace: string) => { export const setCurrentWorkspace = (workspace: string) => {
return { return {
type: 'SET_CURRENT_WORKSPACE', type: 'SET_CURRENT_WORKSPACE',
...@@ -184,3 +186,17 @@ export const focusElement = (elements: { key: string, type: 'file' | 'folder' | ...@@ -184,3 +186,17 @@ export const focusElement = (elements: { key: string, type: 'file' | 'folder' |
payload: elements payload: elements
} }
} }
export const setContextMenuItem = (item: action) => {
return {
type: 'SET_CONTEXT_MENU_ITEM',
payload: item
}
}
export const removeContextMenuItem = (plugin) => {
return {
type: 'REMOVE_CONTEXT_MENU_ITEM',
payload: plugin
}
}
...@@ -5,7 +5,7 @@ import { checkSpecialChars, checkSlash, extractNameFromKey, createNonClashingNam ...@@ -5,7 +5,7 @@ import { checkSpecialChars, checkSlash, extractNameFromKey, createNonClashingNam
import Gists from 'gists' import Gists from 'gists'
import { customAction } from '@remixproject/plugin-api/lib/file-system/file-panel/type' import { customAction } from '@remixproject/plugin-api/lib/file-system/file-panel/type'
import { addInputFieldSuccess, createWorkspaceError, createWorkspaceRequest, createWorkspaceSuccess, displayNotification, displayPopUp, fetchDirectoryError, fetchDirectoryRequest, fetchDirectorySuccess, fetchWorkspaceDirectoryError, fetchWorkspaceDirectoryRequest, fetchWorkspaceDirectorySuccess, focusElement, hideNotification, hidePopUp, removeInputFieldSuccess, setCurrentWorkspace, setDeleteWorkspace, setMode, setRenameWorkspace, setWorkspaces } from './payload' import { addInputFieldSuccess, createWorkspaceError, createWorkspaceRequest, createWorkspaceSuccess, displayNotification, displayPopUp, fetchDirectoryError, fetchDirectoryRequest, fetchDirectorySuccess, fetchWorkspaceDirectoryError, fetchWorkspaceDirectoryRequest, fetchWorkspaceDirectorySuccess, focusElement, hideNotification, hidePopUp, removeInputFieldSuccess, setCurrentWorkspace, setDeleteWorkspace, setMode, setRenameWorkspace, setWorkspaces } from './payload'
import { listenOnEvents } from './events' import { listenOnPluginEvents, listenOnProviderEvents } from './events'
const QueryParams = require('../../../../../../apps/remix-ide/src/lib/query-params') const QueryParams = require('../../../../../../apps/remix-ide/src/lib/query-params')
const examples = require('../../../../../../apps/remix-ide/src/app/editor/examples') const examples = require('../../../../../../apps/remix-ide/src/app/editor/examples')
...@@ -43,9 +43,9 @@ export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React. ...@@ -43,9 +43,9 @@ export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React.
} }
} }
listenOnEvents(plugin, workspaceProvider)(dispatch) listenOnPluginEvents(plugin)
listenOnEvents(plugin, localhostProvider)(dispatch) listenOnProviderEvents(workspaceProvider)(dispatch)
// dispatch(setWorkspaces(workspaces)) listenOnProviderEvents(localhostProvider)(dispatch)
dispatch(setMode('browser')) dispatch(setMode('browser'))
} }
} }
...@@ -106,6 +106,7 @@ export const removeInputField = async (path: string) => { ...@@ -106,6 +106,7 @@ export const removeInputField = async (path: string) => {
} }
export const createWorkspace = async (workspaceName: string) => { export const createWorkspace = async (workspaceName: string) => {
console.log('workspaceName: ', workspaceName)
const promise = createWorkspaceTemplate(workspaceName, true, 'default-template') const promise = createWorkspaceTemplate(workspaceName, true, 'default-template')
dispatch(createWorkspaceRequest(promise)) dispatch(createWorkspaceRequest(promise))
......
...@@ -209,7 +209,7 @@ export const FileSystemProvider = (props: WorkspaceProps) => { ...@@ -209,7 +209,7 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
} }
return ( return (
<FileSystemContext.Provider value={value}> <FileSystemContext.Provider value={value}>
<Workspace plugin={plugin} /> <Workspace />
<ModalDialog id='fileSystem' { ...focusModal } handleHide={ handleHideModal } /> <ModalDialog id='fileSystem' { ...focusModal } handleHide={ handleHideModal } />
<Toaster message={focusToaster} handleHide={handleToaster} /> <Toaster message={focusToaster} handleHide={handleToaster} />
</FileSystemContext.Provider> </FileSystemContext.Provider>
......
import { extractNameFromKey } from '@remix-ui/helper' import { extractNameFromKey } from '@remix-ui/helper'
import { FileType } from '../types' import { action, FileType } from '../types'
import * as _ from 'lodash' import * as _ from 'lodash'
interface Action { interface Action {
type: string type: string
...@@ -13,7 +13,12 @@ export interface BrowserState { ...@@ -13,7 +13,12 @@ export interface BrowserState {
expandPath: string[] expandPath: string[]
isRequesting: boolean, isRequesting: boolean,
isSuccessful: boolean, isSuccessful: boolean,
error: string,
contextMenu: {
registeredMenuItems: action[],
removedMenuItems: action[],
error: string error: string
}
}, },
localhost: { localhost: {
sharedFolder: string, sharedFolder: string,
...@@ -21,7 +26,12 @@ export interface BrowserState { ...@@ -21,7 +26,12 @@ export interface BrowserState {
expandPath: string[], expandPath: string[],
isRequesting: boolean, isRequesting: boolean,
isSuccessful: boolean, isSuccessful: boolean,
error: string,
contextMenu: {
registeredMenuItems: action[],
removedMenuItems: action[],
error: string error: string
}
}, },
mode: 'browser' | 'localhost', mode: 'browser' | 'localhost',
notification: { notification: {
...@@ -46,7 +56,12 @@ export const browserInitialState: BrowserState = { ...@@ -46,7 +56,12 @@ export const browserInitialState: BrowserState = {
expandPath: [], expandPath: [],
isRequesting: false, isRequesting: false,
isSuccessful: false, isSuccessful: false,
error: null,
contextMenu: {
registeredMenuItems: [],
removedMenuItems: [],
error: null error: null
}
}, },
localhost: { localhost: {
sharedFolder: '', sharedFolder: '',
...@@ -54,7 +69,12 @@ export const browserInitialState: BrowserState = { ...@@ -54,7 +69,12 @@ export const browserInitialState: BrowserState = {
expandPath: [], expandPath: [],
isRequesting: false, isRequesting: false,
isSuccessful: false, isSuccessful: false,
error: null,
contextMenu: {
registeredMenuItems: [],
removedMenuItems: [],
error: null error: null
}
}, },
mode: 'browser', mode: 'browser',
notification: { notification: {
...@@ -465,6 +485,38 @@ export const browserReducer = (state = browserInitialState, action: Action) => { ...@@ -465,6 +485,38 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
} }
} }
case 'SET_CONTEXT_MENU_ITEM': {
const payload = action.payload as action
return {
...state,
browser: {
...state.browser,
contextMenu: state.mode === 'browser' ? addContextMenuItem(state, payload) : state.browser.contextMenu
},
localhost: {
...state.localhost,
contextMenu: state.mode === 'localhost' ? addContextMenuItem(state, payload) : state.localhost.contextMenu
}
}
}
case 'REMOVE_CONTEXT_MENU_ITEM': {
const payload = action.payload
return {
...state,
browser: {
...state.browser,
contextMenu: state.mode === 'browser' ? removeContextMenuItem(state, payload) : state.browser.contextMenu
},
localhost: {
...state.localhost,
contextMenu: state.mode === 'localhost' ? removeContextMenuItem(state, payload) : state.localhost.contextMenu
}
}
}
default: default:
throw new Error() throw new Error()
} }
...@@ -609,3 +661,46 @@ const splitPath = (state: BrowserState, path: string): string[] | string => { ...@@ -609,3 +661,46 @@ const splitPath = (state: BrowserState, path: string): string[] | string => {
return _path return _path
} }
const addContextMenuItem = (state: BrowserState, item: action): { registeredMenuItems: action[], removedMenuItems: action[], error: string } => {
let registeredItems = state[state.mode].contextMenu.registeredMenuItems
let removedItems = state[state.mode].contextMenu.removedMenuItems
let error = null
if (registeredItems.filter((o) => {
return o.id === item.id && o.name === item.name
}).length) {
error = `Action ${item.name} already exists on ${item.id}`
return {
registeredMenuItems: registeredItems,
removedMenuItems: removedItems,
error
}
}
registeredItems = [...registeredItems, item]
removedItems = removedItems.filter(menuItem => item.id !== menuItem.id)
return {
registeredMenuItems: registeredItems,
removedMenuItems: removedItems,
error
}
}
const removeContextMenuItem = (state: BrowserState, plugin): { registeredMenuItems: action[], removedMenuItems: action[], error: string } => {
let registeredItems = state[state.mode].contextMenu.registeredMenuItems
const removedItems = state[state.mode].contextMenu.removedMenuItems
const error = null
registeredItems = registeredItems.filter((item) => {
if (item.id !== plugin.name || item.sticky === true) return true
else {
removedItems.push(item)
return false
}
})
return {
registeredMenuItems: registeredItems,
removedMenuItems: removedItems,
error
}
}
import React, { useState, useEffect, useRef, useContext } from 'react' // eslint-disable-line import React, { useState, useEffect, useRef, useContext } from 'react' // eslint-disable-line
import { FileExplorer } from './components/file-explorer' // eslint-disable-line import { FileExplorer } from './components/file-explorer' // eslint-disable-line
import './css/remix-ui-workspace.css' import './css/remix-ui-workspace.css'
import { WorkspaceProps, WorkspaceState } from './types' import { WorkspaceState } from './types'
import { FileSystemContext } from './contexts' import { FileSystemContext } from './contexts'
const canUpload = window.File || window.FileReader || window.FileList || window.Blob const canUpload = window.File || window.FileReader || window.FileList || window.Blob
export function Workspace (props: WorkspaceProps) { export function Workspace () {
const LOCALHOST = ' - connect to localhost - ' const LOCALHOST = ' - connect to localhost - '
const NO_WORKSPACE = ' - none - ' const NO_WORKSPACE = ' - none - '
const [state] = useState<WorkspaceState>({ const [state] = useState<WorkspaceState>({
...@@ -16,6 +16,8 @@ export function Workspace (props: WorkspaceProps) { ...@@ -16,6 +16,8 @@ export function Workspace (props: WorkspaceProps) {
}) })
const [currentWorkspace, setCurrentWorkspace] = useState<string>(NO_WORKSPACE) const [currentWorkspace, setCurrentWorkspace] = useState<string>(NO_WORKSPACE)
const global = useContext(FileSystemContext) const global = useContext(FileSystemContext)
const workspaceRenameInput = useRef()
const workspaceCreateInput = useRef()
useEffect(() => { useEffect(() => {
global.dispatchInitWorkspace() global.dispatchInitWorkspace()
...@@ -54,9 +56,6 @@ export function Workspace (props: WorkspaceProps) { ...@@ -54,9 +56,6 @@ export function Workspace (props: WorkspaceProps) {
global.modal('Delete Current Workspace', 'Are you sure to delete the current workspace?', 'OK', onFinishDeleteWorkspace, '') global.modal('Delete Current Workspace', 'Are you sure to delete the current workspace?', 'OK', onFinishDeleteWorkspace, '')
} }
const workspaceRenameInput = useRef()
const workspaceCreateInput = useRef()
const onFinishRenameWorkspace = async () => { const onFinishRenameWorkspace = async () => {
if (workspaceRenameInput.current === undefined) return if (workspaceRenameInput.current === undefined) return
// @ts-ignore: Object is possibly 'null'. // @ts-ignore: Object is possibly 'null'.
...@@ -185,8 +184,8 @@ export function Workspace (props: WorkspaceProps) { ...@@ -185,8 +184,8 @@ export function Workspace (props: WorkspaceProps) {
<FileExplorer <FileExplorer
name={currentWorkspace} name={currentWorkspace}
menuItems={['createNewFile', 'createNewFolder', 'publishToGist', canUpload ? 'uploadFile' : '']} menuItems={['createNewFile', 'createNewFolder', 'publishToGist', canUpload ? 'uploadFile' : '']}
contextMenuItems={props.plugin.registeredMenuItems} contextMenuItems={global.fs.browser.contextMenu.registeredMenuItems}
removedContextMenuItems={props.plugin.removedMenuItems} removedContextMenuItems={global.fs.browser.contextMenu.removedMenuItems}
files={global.fs.browser.files} files={global.fs.browser.files}
expandPath={global.fs.browser.expandPath} expandPath={global.fs.browser.expandPath}
focusEdit={global.fs.focusEdit} focusEdit={global.fs.focusEdit}
...@@ -219,8 +218,8 @@ export function Workspace (props: WorkspaceProps) { ...@@ -219,8 +218,8 @@ export function Workspace (props: WorkspaceProps) {
<FileExplorer <FileExplorer
name='localhost' name='localhost'
menuItems={['createNewFile', 'createNewFolder']} menuItems={['createNewFile', 'createNewFolder']}
contextMenuItems={props.plugin.registeredMenuItems} contextMenuItems={global.fs.localhost.contextMenu.registeredMenuItems}
removedContextMenuItems={props.plugin.removedMenuItems} removedContextMenuItems={global.fs.localhost.contextMenu.removedMenuItems}
files={global.fs.localhost.files} files={global.fs.localhost.files}
expandPath={global.fs.localhost.expandPath} expandPath={global.fs.localhost.expandPath}
focusEdit={global.fs.focusEdit} focusEdit={global.fs.focusEdit}
......
...@@ -90,7 +90,7 @@ export interface FileExplorerMenuProps { ...@@ -90,7 +90,7 @@ export interface FileExplorerMenuProps {
uploadFile: (target: EventTarget & HTMLInputElement) => void uploadFile: (target: EventTarget & HTMLInputElement) => void
} }
export type action = { name: string, type?: Array<'folder' | 'gist' | 'file'>, path?: string[], extension?: string[], pattern?: string[], id: string, multiselect: boolean, label: string } export type action = { name: string, type?: Array<'folder' | 'gist' | 'file'>, path?: string[], extension?: string[], pattern?: string[], id: string, multiselect: boolean, label: string, sticky?: boolean }
export type MenuItems = action[] export type MenuItems = action[]
export interface FileExplorerContextMenuProps { export interface FileExplorerContextMenuProps {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment