Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context Menu For Plugins #752

Merged
merged 9 commits into from
Jan 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions apps/remix-ide/src/app/panels/file-panel.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ module.exports = class Filepanel extends ViewPlugin {
}
}
this.reset = false
this.registeredMenuItems = []
this.el = yo`
<div id="fileExplorerView">
</div>
Expand Down Expand Up @@ -102,6 +103,20 @@ module.exports = class Filepanel extends ViewPlugin {
return this.el
}

/**
*
* @param item { id: string, name: string, type?: string[], path?: string[], extension?: string[], pattern?: string[] }
* @param callback (...args) => void
*/
registerContextMenuItem (item) {
if (!item) throw new Error('Invalid register context menu argument')
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')

this.registeredMenuItems = [...this.registeredMenuItems, item]
this.renderComponent()
}

renderComponent () {
ReactDOM.render(
<div className='remixui_container'>
Expand All @@ -116,6 +131,7 @@ module.exports = class Filepanel extends ViewPlugin {
menuItems={['createNewFile', 'createNewFolder', 'publishToGist', canUpload ? 'uploadFile' : '']}
plugin={this}
focusRoot={this.reset}
contextMenuItems={this.registeredMenuItems}
/>
</div>
<div className='pl-2 filesystemexplorer remixui_treeview'>
Expand All @@ -127,6 +143,7 @@ module.exports = class Filepanel extends ViewPlugin {
menuItems={['createNewFile', 'createNewFolder']}
plugin={this}
focusRoot={this.reset}
contextMenuItems={this.registeredMenuItems}
/>
}
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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, publishToGist, runScript, pageX, pageY, path, type, ...otherProps } = props
const { actions, createNewFile, createNewFolder, deletePath, renamePath, hideContextMenu, publishToGist, runScript, emit, pageX, pageY, path, type, ...otherProps } = props
const contextMenuRef = useRef(null)

useEffect(() => {
Expand All @@ -24,10 +24,10 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) =>

const menu = () => {
return actions.filter(item => {
if (item.type.findIndex(name => name === type) !== -1) return true
else if (item.path.findIndex(key => key === path) !== -1) return true
else if (item.extension.findIndex(ext => path.endsWith(ext)) !== -1) return true
else if (item.pattern.filter(value => path.match(new RegExp(value))).length > 0) return true
if (item.type && Array.isArray(item.type) && (item.type.findIndex(name => name === type) !== -1)) return true
else if (item.path && Array.isArray(item.path) && (item.path.findIndex(key => key === path) !== -1)) return true
else if (item.extension && Array.isArray(item.extension) && (item.extension.findIndex(ext => path.endsWith(ext)) !== -1)) return true
else if (item.pattern && Array.isArray(item.pattern) && (item.pattern.filter(value => path.match(new RegExp(value))).length > 0)) return true
else return false
}).map((item, index) => {
return <li
Expand Down Expand Up @@ -56,6 +56,7 @@ export const FileExplorerContextMenu = (props: FileExplorerContextMenuProps) =>
runScript(path)
break
default:
emit && emit(item.id, path)
break
}
hideContextMenu()
Expand Down
25 changes: 24 additions & 1 deletion libs/remix-ui/file-explorer/src/lib/file-explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import './css/file-explorer.css'
const queryParams = new QueryParams()

export const FileExplorer = (props: FileExplorerProps) => {
const { filesProvider, name, registry, plugin, focusRoot } = props
const { filesProvider, name, registry, plugin, focusRoot, contextMenuItems } = props
const [state, setState] = useState({
focusElement: [{
key: name,
Expand Down Expand Up @@ -76,36 +76,42 @@ export const FileExplorer = (props: FileExplorerProps) => {
const accessToken = config.get('settings/gist-access-token')
const files = await fetchDirectoryContent(name)
const actions = [{
id: 'newFile',
name: 'New File',
type: ['folder'],
path: [],
extension: [],
pattern: []
}, {
id: 'newFolder',
name: 'New Folder',
type: ['folder'],
path: [],
extension: [],
pattern: []
}, {
id: 'rename',
name: 'Rename',
type: ['file', 'folder'],
path: [],
extension: [],
pattern: []
}, {
id: 'delete',
name: 'Delete',
type: ['file', 'folder'],
path: [],
extension: [],
pattern: []
}, {
id: 'pushChangesToGist',
name: 'Push changes to gist',
type: [],
path: [],
extension: [],
pattern: ['^browser/gists/([0-9]|[a-z])*$']
}, {
id: 'run',
name: 'Run',
type: [],
path: [],
Expand Down Expand Up @@ -165,6 +171,17 @@ export const FileExplorer = (props: FileExplorerProps) => {
}
}, [focusRoot])

useEffect(() => {
if (contextMenuItems) {
setState(prevState => {
// filter duplicate items
const items = contextMenuItems.filter(({ name }) => prevState.actions.findIndex(action => action.name === name) === -1)

return { ...prevState, actions: [...prevState.actions, ...items] }
})
}
}, [contextMenuItems])

const resolveDirectory = async (folderPath, dir: File[], isChild = false): Promise<File[]> => {
if (!isChild && (state.focusEdit.element === 'browser/blank') && state.focusEdit.isNew && (dir.findIndex(({ path }) => path === 'browser/blank') === -1)) {
dir = state.focusEdit.type === 'file' ? [...dir, {
Expand Down Expand Up @@ -603,6 +620,10 @@ export const FileExplorer = (props: FileExplorerProps) => {
})
}

const emitContextMenuEvent = (id: string, path: string) => {
plugin.emit(id, path)
}

const handleHideModal = () => {
setState(prevState => {
return { ...prevState, modalOptions: { ...state.modalOptions, hide: true } }
Expand Down Expand Up @@ -839,6 +860,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
deletePath={deletePath}
renamePath={editModeOn}
publishToGist={publishToGist}
emit={emitContextMenuEvent}
pageX={state.focusContext.x}
pageY={state.focusContext.y}
path={file.path}
Expand Down Expand Up @@ -875,6 +897,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
deletePath={deletePath}
renamePath={editModeOn}
runScript={runScript}
emit={emitContextMenuEvent}
pageX={state.focusContext.x}
pageY={state.focusContext.y}
path={file.path}
Expand Down
7 changes: 4 additions & 3 deletions libs/remix-ui/file-explorer/src/lib/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ export interface FileExplorerProps {
filesProvider: any,
menuItems?: string[],
plugin: any,
focusRoot: boolean
focusRoot: boolean,
contextMenuItems: { name: string, type: string[], path: string[], extension: string[], pattern: string[] }[]
}

export interface File {
Expand All @@ -26,15 +27,15 @@ export interface FileExplorerMenuProps {
}

export interface FileExplorerContextMenuProps {
actions: { name: string, type: string[], path: string[], extension: string[], pattern: string[] }[],
actions: { name: string, type: string[], path: string[], extension: string[], pattern: string[], id: string }[],
createNewFile: (folder?: string) => void,
createNewFolder: (parentFolder?: string) => void,
deletePath: (path: string) => void,
renamePath: (path: string, type: string) => void,
hideContextMenu: () => void,
extractParentFromKey?: (key: string) => string,
publishToGist?: () => void,
runScript?: (path: string) => void,
emit?: (id: string, path: string) => void,
pageX: number,
pageY: number,
path: string,
Expand Down