fix drag drop

flattentree
filip mertens 11 months ago
parent c3f30e5108
commit 85ece23f64
  1. 40
      apps/remixdesktop/src/utils/pluginEventDataBatcher.ts
  2. 111
      libs/remix-ui/workspace/src/lib/components/file-explorer.tsx
  3. 54
      libs/remix-ui/workspace/src/lib/components/flat-tree-drop.tsx
  4. 29
      libs/remix-ui/workspace/src/lib/components/flat-tree.tsx
  5. 6
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx

@ -1,54 +1,52 @@
import {EventEmitter} from 'events';
import {EventEmitter} from 'events'
// Max duration to batch session data before sending it to the renderer process.
const BATCH_DURATION_MS = 16;
const BATCH_DURATION_MS = 16
// Max number of events to batch before sending them to the renderer process.
const BATCH_MAX_SIZE = 50;
const BATCH_MAX_SIZE = 50
export class PluginEventDataBatcher extends EventEmitter {
uid: number;
uid: number
data!: any[]
timeout!: NodeJS.Timeout | null;
timeout!: NodeJS.Timeout | null
constructor(uid: number) {
super();
this.uid = uid;
super()
this.uid = uid
this.reset();
this.reset()
}
reset() {
this.data = [];
this.timeout = null;
this.data = []
this.timeout = null
}
write(key: string, ...payload: any): void {
if (this.data.length >= BATCH_MAX_SIZE) {
// We've reached the max batch size. Flush it and start another one
if (this.timeout) {
clearTimeout(this.timeout);
this.timeout = null;
clearTimeout(this.timeout)
this.timeout = null
}
this.flush();
this.flush()
}
this.data.push({
key,
payload,
});
console.log('data', this.data)
})
if (!this.timeout) {
this.timeout = setTimeout(() => this.flush(), BATCH_DURATION_MS);
this.timeout = setTimeout(() => this.flush(), BATCH_DURATION_MS)
}
}
flush() {
// Reset before emitting to allow for potential reentrancy
const data = this.data;
this.reset();
const data = this.data
this.reset()
this.emit('flush', data);
this.emit('flush', data)
}
}
}

@ -187,7 +187,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
}
} else {
let expandPath = []
if (!props.expandPath.includes(path)) {
expandPath = [...new Set([...props.expandPath, path])]
props.dispatchFetchDirectory(path)
@ -333,7 +333,7 @@ export const FileExplorer = (props: FileExplorerProps) => {
)
}
}
const handleTreeClick = (event: SyntheticEvent) => {
let target = event.target as HTMLElement
while (target && target.getAttribute && !target.getAttribute('data-path')) {
@ -345,11 +345,11 @@ export const FileExplorer = (props: FileExplorerProps) => {
if (path && type === 'file') {
event.stopPropagation()
if (state.focusEdit.element !== path) handleClickFile(path, type)
} else if (path && type === 'folder') {
event.stopPropagation()
if (state.focusEdit.element !== path) handleClickFolder(path, type)
}
if (props.showIconsMenu === true) props.hideIconsMenu(!props.showIconsMenu)
}
@ -359,59 +359,60 @@ export const FileExplorer = (props: FileExplorerProps) => {
return (
<div ref={treeRef} tabIndex={0} style={{ outline: 'none',
display: 'flex',
flexDirection: 'column',
height: '100%',
}}>
<TreeView id="treeView">
<li key={`treeViewLiMenu`} data-id={`treeViewLiMenu`} className="li_tv">
<div
key={`treeViewDivMenu`}
data-id={`treeViewDivMenu`}
className={`d-flex flex-row align-items-center`}
>
<span className="w-100 pl-2 mt-1">
<div onClick={handleFileExplorerMenuClick}>
<FileExplorerMenu
title={''}
menuItems={props.menuItems}
createNewFile={handleNewFileInput}
createNewFolder={handleNewFolderInput}
publishToGist={publishToGist}
uploadFile={uploadFile}
uploadFolder={uploadFolder}
/>
</div>
</span>
</div>
</li>
<div style={{flexGrow: 2}}>
<div>
<FlatTree
treeRef={treeRef}
handleTreeClick={handleTreeClick}
focusEdit={state.focusEdit}
focusElement={props.focusElement}
focusContext={state.focusContext}
editModeOff={editModeOff}
files={files}
flatTree={flatTree}
fileState={fileState}
expandPath={props.expandPath}
handleContextMenu={handleContextMenu}
moveFile={handleFileMove}
moveFolder={handleFolderMove}
/>
<div className="h-100 remixui_treeview" data-id="filePanelFileExplorerTree">
<div ref={treeRef} tabIndex={0} style={{
outline: 'none',
display: 'flex',
flexDirection: 'column'
}}
className="h-100"
>
<TreeView id="treeView">
<li key={`treeViewLiMenu`} data-id={`treeViewLiMenu`} className="li_tv">
<div
key={`treeViewDivMenu`}
data-id={`treeViewDivMenu`}
className={`d-flex flex-row align-items-center`}
>
<span className="w-100 pl-2 mt-1">
<div onClick={handleFileExplorerMenuClick}>
<FileExplorerMenu
title={''}
menuItems={props.menuItems}
createNewFile={handleNewFileInput}
createNewFolder={handleNewFolderInput}
publishToGist={publishToGist}
uploadFile={uploadFile}
uploadFolder={uploadFolder}
/>
</div>
</span>
</div>
</li>
<div style={{ flexGrow: 2 }}>
<div>
<FlatTree
treeRef={treeRef}
handleTreeClick={handleTreeClick}
focusEdit={state.focusEdit}
focusElement={props.focusElement}
focusContext={state.focusContext}
editModeOff={editModeOff}
files={files}
flatTree={flatTree}
fileState={fileState}
expandPath={props.expandPath}
handleContextMenu={handleContextMenu}
moveFile={handleFileMove}
moveFolder={handleFolderMove}
handleClickFolder={handleClickFolder}
/>
</div>
</div>
</div>
<div className='d-block w-100 pb-4 mb-4'></div>
</TreeView>
</TreeView>
</div>
</div>
)
}

@ -3,19 +3,49 @@ import { FileType } from '../types'
import { getEventTarget } from '../utils/getEventTarget'
import { extractParentFromKey } from '@remix-ui/helper'
interface FlatTreeDropProps {
moveFile: (dest: string, src: string) => void
moveFolder: (dest: string, src: string) => void
getFlatTreeItem: (path: string) => FileType
dragSource: FileType
children: React.ReactNode
moveFile: (dest: string, src: string) => void
moveFolder: (dest: string, src: string) => void
getFlatTreeItem: (path: string) => FileType
handleClickFolder: (path: string, type: string) => void
dragSource: FileType
children: React.ReactNode
expandPath: string[]
}
export const FlatTreeDrop = (props: FlatTreeDropProps) => {
const { getFlatTreeItem, dragSource, moveFile, moveFolder } = props
const { getFlatTreeItem, dragSource, moveFile, moveFolder, handleClickFolder, expandPath } = props
// delay timer
const [timer, setTimer] = useState<NodeJS.Timeout>()
// folder to open
const [folderToOpen, setFolderToOpen] = useState<string>()
const onDragOver = async (e: SyntheticEvent) => {
//setShowMouseOverTarget(false)
e.preventDefault()
const target = await getEventTarget(e)
if (!target || !target.path) {
clearTimeout(timer)
setFolderToOpen(null)
return
}
const dragDestination = getFlatTreeItem(target.path)
if (dragDestination && !dragDestination.isDirectory) {
clearTimeout(timer)
setFolderToOpen(null)
}
if (dragDestination && dragDestination.isDirectory && !expandPath.includes(dragDestination.path) && folderToOpen !== dragDestination.path && props.handleClickFolder) {
setFolderToOpen(dragDestination.path)
timer && clearTimeout(timer)
setTimer(
setTimeout(() => {
handleClickFolder(dragDestination.path, dragDestination.type)
setFolderToOpen(null)
}, 600)
)
}
}
const onDrop = async (event: SyntheticEvent) => {
@ -23,12 +53,12 @@ export const FlatTreeDrop = (props: FlatTreeDropProps) => {
const target = await getEventTarget(event)
let dragDestination: any
if(!target || !target.path) {
if (!target || !target.path) {
dragDestination = {
path: '/',
isDirectory: true
}
}else{
} else {
dragDestination = getFlatTreeItem(target.path)
}
@ -40,7 +70,7 @@ export const FlatTreeDrop = (props: FlatTreeDropProps) => {
}
} else {
const path = extractParentFromKey(dragDestination.path) || '/'
if (dragSource.isDirectory) {
moveFolder(path, dragSource.path)
} else {
@ -51,6 +81,6 @@ export const FlatTreeDrop = (props: FlatTreeDropProps) => {
return (<div
onDrop={onDrop} onDragOver={onDragOver}
onDrop={onDrop} onDragOver={onDragOver}
>{props.children}</div>)
}

@ -37,10 +37,12 @@ interface FlatTreeProps {
focusContext: { element: string; x: number; y: number; type: string }
handleContextMenu: (pageX: number, pageY: number, path: string, content: string, type: string) => void
handleTreeClick: (e: SyntheticEvent) => void
handleClickFolder: (path: string, type: string) => void
treeRef: React.MutableRefObject<HTMLDivElement>
moveFile: (dest: string, src: string) => void
moveFolder: (dest: string, src: string) => void
fileState: fileDecoration[]
}
let mouseTimer: any = {
@ -49,7 +51,7 @@ let mouseTimer: any = {
}
export const FlatTree = (props: FlatTreeProps) => {
const { files, flatTree, expandPath, focusEdit, editModeOff, handleTreeClick, moveFile, moveFolder, fileState, focusElement } = props
const { files, flatTree, expandPath, focusEdit, editModeOff, handleTreeClick, moveFile, moveFolder, fileState, focusElement, handleClickFolder } = props
//const [flatTree, setFlatTree] = useState<{ [x: string]: FileType }>({})
const [hover, setHover] = useState<string>('')
const [mouseOverTarget, setMouseOverTarget] = useState<{
@ -70,10 +72,10 @@ export const FlatTree = (props: FlatTreeProps) => {
const isOnScreen = useOnScreen(props.treeRef)
useEffect(() => {
if(isOnScreen) {
if (isOnScreen) {
setViewPortHeight()
}
},[isOnScreen])
}, [isOnScreen])
const labelClass = (file: FileType) =>
@ -191,7 +193,7 @@ export const FlatTree = (props: FlatTreeProps) => {
}, [props.treeRef.current])
const Row = (index) => {
const Row = (index: number) => {
const node = Object.keys(flatTree)[index]
const file = flatTree[node]
return (<li
@ -207,9 +209,20 @@ export const FlatTree = (props: FlatTreeProps) => {
<div className={`pr-2 pl-2 ${file.isDirectory ? expandPath && expandPath.includes(file.path) ? 'fa fa-folder-open' : 'fa fa-folder' : getPathIcon(file.path)} caret caret_tv`}></div>
{focusEdit && file.path && focusEdit.element === file.path ?
<FlatTreeItemInput editModeOff={editModeOff} file={file} /> :
<div draggable={true} onDragStart={onDragStart} onDragEnd={onDragEnd} className={`ml-1 pl-2 text-nowrap remixui_leaf ${getFileStateClasses(file)}`} data-label-type={file.isDirectory ? 'folder' : 'file'} data-label-path={`${file.path}`} key={index}>{file.name}
</div>}
<FlatTreeItemInput
editModeOff={editModeOff}
file={file} /> :
<div
draggable={true}
onDragStart={onDragStart}
onDragEnd={onDragEnd}
className={`ml-1 pl-2 text-nowrap remixui_leaf ${getFileStateClasses(file)}`}
data-label-type={file.isDirectory ? 'folder' : 'file'}
data-label-path={`${file.path}`}
key={index}>
{file.name}
</div>
}
</div>
</li>)
}
@ -220,6 +233,8 @@ export const FlatTree = (props: FlatTreeProps) => {
getFlatTreeItem={getFlatTreeItem}
moveFile={moveFile}
moveFolder={moveFolder}
handleClickFolder={handleClickFolder}
expandPath={expandPath}
>
<div data-id="treeViewUltreeViewMenu" onClick={handleTreeClick} onMouseLeave={onMouseLeave} onMouseMove={onMouseMove} onContextMenu={handleContextMenu}>
{showMouseOverTarget && mouseOverTarget && !isDragging &&

@ -1043,7 +1043,7 @@ export function Workspace() {
</div>
)}
{!(global.fs.browser.isRequestingWorkspace || global.fs.browser.isRequestingCloning) && global.fs.mode === 'browser' && currentWorkspace !== NO_WORKSPACE && (
<div className="h-100 remixui_treeview" data-id="filePanelFileExplorerTree">
<FileExplorer
fileState={global.fs.browser.fileState}
name={currentWorkspace}
@ -1095,7 +1095,7 @@ export function Workspace() {
handleNewFolderInput={handleNewFolderInput}
dragStatus={dragStatus}
/>
</div>
)}
{global.fs.localhost.isRequestingLocalhost && (
<div className="text-center py-5">
@ -1103,7 +1103,6 @@ export function Workspace() {
</div>
)}
{global.fs.mode === 'localhost' && global.fs.localhost.isSuccessfulLocalhost && (
<div className="h-100 filesystemexplorer remixui_treeview">
<FileExplorer
name="localhost"
menuItems={['createNewFile', 'createNewFolder']}
@ -1155,7 +1154,6 @@ export function Workspace() {
handleNewFolderInput={handleNewFolderInput}
dragStatus={dragStatus}
/>
</div>
)}
</div>
</div>

Loading…
Cancel
Save