Commit 079cd362 authored by ioedeveloper's avatar ioedeveloper

finalize child components

parent 882251f6
......@@ -138,8 +138,11 @@ module.exports = class Filepanel extends ViewPlugin {
this.emit('displayNewFileInput', dir)
}
async uploadFile (event) {
return await this.request.uploadFile(event)
async uploadFile (target) {
const provider = this.fileManager.currentFileProvider()
const dir = provider.workspace || '/'
return this.emit('uploadFileEvent', dir, target)
}
async processCreateWorkspace (name) {
......
......@@ -484,6 +484,10 @@ const listenOnEvents = (provider) => {
plugin.on('filePanel', 'displayNewFileInput', (path) => {
addInputField('file', path)(dispatch)
})
plugin.on('filePanel', 'uploadFileEvent', (dir: string, target) => {
uploadFile(target, dir)(dispatch)
})
}
export const initWorkspace = (filePanelPlugin) => async (reducerDispatch: React.Dispatch<any>) => {
......
import React, { useRef, useEffect } from 'react' // eslint-disable-line
import { action, FileExplorerContextMenuProps } from '../types'
import './css/file-explorer-context-menu.css'
import '../css/file-explorer-context-menu.css'
import { customAction } from '@remixproject/plugin-api/lib/file-system/file-panel'
declare global {
......
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import React, { useEffect, useRef } from 'react'
import { FileType } from '../types'
export interface FileLabelProps {
file: FileType,
focusEdit: {
element: string
type: string
isNew: boolean
lastEdit: string
}
editModeOff: (content: string) => void
}
export const FileLabel = (props: FileLabelProps) => {
const { file, focusEdit, editModeOff } = props
const isEditable = focusEdit.element === file.path
const labelRef = useRef(null)
useEffect(() => {
if (isEditable) {
setTimeout(() => {
labelRef.current.focus()
}, 0)
}
}, [isEditable])
const handleEditInput = (event: React.KeyboardEvent<HTMLDivElement>) => {
if (event.which === 13) {
event.preventDefault()
editModeOff(labelRef.current.innerText)
}
}
const handleEditBlur = (event: React.SyntheticEvent) => {
event.stopPropagation()
editModeOff(labelRef.current.innerText)
}
return (
<div
className='remixui_items d-inline-block w-100'
ref={labelRef}
suppressContentEditableWarning={true}
contentEditable={isEditable}
onKeyDown={handleEditInput}
onBlur={handleEditBlur}
>
<span
title={file.path}
className={'remixui_label ' + (file.isDirectory ? 'folder' : 'remixui_leaf')}
data-path={file.path}
>
{ file.name }
</span>
</div>
)
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import React, { SyntheticEvent, useState } from 'react'
import { FileType } from '../types'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { TreeView, TreeViewItem } from '@remix-ui/tree-view'
import { getPathIcon } from '@remix-ui/helper'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { FileLabel } from './file-label'
export interface RenderFileProps {
file: FileType,
index: number,
focusEdit: { element: string, type: string, isNew: boolean, lastEdit: string },
focusElement: { key: string, type: 'file' | 'folder' | 'gist' }[],
focusContext: { element: string, x: number, y: number, type: string },
ctrlKey: boolean,
expandPath: string[],
editModeOff: (content: string) => void,
handleClickFolder: (path: string, type: string) => void,
handleClickFile: (path: string, type: string) => void,
handleContextMenu: (pageX: number, pageY: number, path: string, content: string, type: string) => void
}
export const FileRender = (props: RenderFileProps) => {
const { file } = props
if (!file || !file.path || typeof file === 'string' || typeof file === 'number' || typeof file === 'boolean') return
const [hover, setHover] = useState<boolean>(false)
const labelClass = props.focusEdit.element === file.path
? 'bg-light' : props.focusElement.findIndex(item => item.key === file.path) !== -1
? 'bg-secondary' : hover
? 'bg-light border' : (props.focusContext.element === file.path) && (props.focusEdit.element !== file.path)
? 'bg-light border' : ''
const icon = getPathIcon(file.path)
const spreadProps = {
onClick: (e) => e.stopPropagation()
}
const handleFolderClick = (event: SyntheticEvent) => {
event.stopPropagation()
if (props.focusEdit.element !== file.path) props.handleClickFolder(file.path, file.type)
}
const handleFileClick = (event: SyntheticEvent) => {
event.stopPropagation()
if (props.focusEdit.element !== file.path) props.handleClickFile(file.path, file.type)
}
const handleContextMenu = (event: PointerEvent) => {
event.preventDefault()
event.stopPropagation()
props.handleContextMenu(event.pageX, event.pageY, file.path, (event.target as HTMLElement).textContent, file.type)
}
const handleMouseOut = (event: SyntheticEvent) => {
event.stopPropagation()
setHover(false)
}
const handleMouseOver = (event: SyntheticEvent) => {
event.stopPropagation()
setHover(true)
}
if (file.isDirectory) {
return (
<TreeViewItem
id={`treeViewItem${file.path}`}
iconX='pr-3 fa fa-folder'
iconY='pr-3 fa fa-folder-open'
key={`${file.path + props.index}`}
label={<FileLabel file={file} focusEdit={props.focusEdit} editModeOff={props.editModeOff} />}
onClick={handleFolderClick}
onContextMenu={handleContextMenu}
labelClass={labelClass}
controlBehaviour={ props.ctrlKey }
expand={props.expandPath.includes(file.path)}
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
>
{
file.child ? <TreeView id={`treeView${file.path}`} key={`treeView${file.path}`} {...spreadProps }>{
Object.keys(file.child).map((key, index) => <FileRender
file={file.child[key]}
index={index}
focusContext={props.focusContext}
focusEdit={props.focusEdit}
focusElement={props.focusElement}
ctrlKey={props.ctrlKey}
editModeOff={props.editModeOff}
handleClickFile={props.handleClickFile}
handleClickFolder={props.handleClickFolder}
handleContextMenu={props.handleContextMenu}
expandPath={props.expandPath}
/>)
}
</TreeView> : <TreeView id={`treeView${file.path}`} key={`treeView${file.path}`} {...spreadProps }/>
}
</TreeViewItem>
)
} else {
return (
<TreeViewItem
id={`treeViewItem${file.path}`}
key={`treeView${file.path}`}
label={<FileLabel file={file} focusEdit={props.focusEdit} editModeOff={props.editModeOff} />}
onClick={handleFileClick}
onContextMenu={handleContextMenu}
icon={icon}
labelClass={labelClass}
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
/>
)
}
}
import { extractNameFromKey } from '@remix-ui/helper'
import { FileType } from '../types'
import * as _ from 'lodash'
interface Action {
type: string
......@@ -8,7 +9,7 @@ export interface BrowserState {
browser: {
currentWorkspace: string,
workspaces: string[],
files: { [x: string]: Record<string, File> },
files: { [x: string]: Record<string, FileType> },
expandPath: string[]
isRequesting: boolean,
isSuccessful: boolean,
......@@ -16,7 +17,7 @@ export interface BrowserState {
},
localhost: {
sharedFolder: string,
files: { [x: string]: Record<string, File> },
files: { [x: string]: Record<string, FileType> },
expandPath: string[],
isRequesting: boolean,
isSuccessful: boolean,
......@@ -469,7 +470,7 @@ export const browserReducer = (state = browserInitialState, action: Action) => {
}
}
const fileAdded = (state: BrowserState, path: string): { [x: string]: Record<string, File> } => {
const fileAdded = (state: BrowserState, path: string): { [x: string]: Record<string, FileType> } => {
let files = state.mode === 'browser' ? state.browser.files : state.localhost.files
const _path = splitPath(state, path)
......@@ -482,7 +483,7 @@ const fileAdded = (state: BrowserState, path: string): { [x: string]: Record<str
return files
}
const fileRemoved = (state: BrowserState, path: string): { [x: string]: Record<string, File> } => {
const fileRemoved = (state: BrowserState, path: string): { [x: string]: Record<string, FileType> } => {
const files = state.mode === 'browser' ? state.browser.files : state.localhost.files
const _path = splitPath(state, path)
......@@ -491,7 +492,7 @@ const fileRemoved = (state: BrowserState, path: string): { [x: string]: Record<s
}
// IDEA: Modify function to remove blank input field without fetching content
const fetchDirectoryContent = (state: BrowserState, payload: { fileTree, path: string, type?: 'file' | 'folder' }, deletePath?: string): { [x: string]: Record<string, File> } => {
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) {
......@@ -538,7 +539,7 @@ const fetchDirectoryContent = (state: BrowserState, payload: { fileTree, path: s
}
}
const fetchWorkspaceDirectoryContent = (state: BrowserState, payload: { fileTree, path: string }): { [x: string]: Record<string, File> } => {
const fetchWorkspaceDirectoryContent = (state: BrowserState, payload: { fileTree, path: string }): { [x: string]: Record<string, FileType> } => {
if (state.mode === 'browser') {
const files = normalize(payload.fileTree, payload.path)
......@@ -548,7 +549,7 @@ const fetchWorkspaceDirectoryContent = (state: BrowserState, payload: { fileTree
}
}
const normalize = (filesList, directory?: string, newInputType?: 'folder' | 'file'): Record<string, File> => {
const normalize = (filesList, directory?: string, newInputType?: 'folder' | 'file'): Record<string, FileType> => {
const folders = {}
const files = {}
......
.remixui_container {
display : flex;
flex-direction : row;
width : 100%;
height : 100%;
box-sizing : border-box;
}
.remixui_fileexplorer {
display : flex;
flex-direction : column;
position : relative;
width : 100%;
padding-left : 6px;
padding-right : 6px;
padding-top : 6px;
}
.remixui_fileExplorerTree {
cursor : default;
}
.remixui_gist {
padding : 10px;
}
.remixui_gist i {
cursor : pointer;
}
.remixui_gist i:hover {
color : orange;
}
.remixui_connectToLocalhost {
padding : 10px;
}
.remixui_connectToLocalhost i {
cursor : pointer;
}
.remixui_connectToLocalhost i:hover {
color : var(--secondary)
}
.remixui_uploadFile {
padding : 10px;
}
.remixui_uploadFile label:hover {
color : var(--secondary)
}
.remixui_uploadFile label {
cursor : pointer;
}
.remixui_treeview {
overflow-y : auto;
}
.remixui_dialog {
display: flex;
flex-direction: column;
}
.remixui_dialogParagraph {
margin-bottom: 2em;
word-break: break-word;
}
.remixui_menuicon {
padding-right : 10px;
}
\ No newline at end of file
import React, { useState, useEffect, useRef, useContext } from 'react' // eslint-disable-line
import { FileExplorer } from './components/file-explorer' // eslint-disable-line
import './remix-ui-workspace.css'
import './css/remix-ui-workspace.css'
import { WorkspaceProps, WorkspaceState } from './types'
import { FileSystemContext } from './contexts'
......@@ -9,12 +9,9 @@ const canUpload = window.File || window.FileReader || window.FileList || window.
export function Workspace (props: WorkspaceProps) {
const LOCALHOST = ' - connect to localhost - '
const NO_WORKSPACE = ' - none - '
const [state, setState] = useState<WorkspaceState>({
reset: false,
const [state] = useState<WorkspaceState>({
hideRemixdExplorer: true,
displayNewFile: false,
externalUploads: null,
uploadFileEvent: null,
loadingLocalhost: false
})
const [currentWorkspace, setCurrentWorkspace] = useState<string>(NO_WORKSPACE)
......@@ -50,19 +47,6 @@ export function Workspace (props: WorkspaceProps) {
return createWorkspace()
}
// props.plugin.request.createNewFile = async () => {
// if (!state.workspaces.length) await createNewWorkspace('default_workspace')
// props.plugin.resetNewFile()
// }
// props.plugin.request.uploadFile = async (target: EventTarget & HTMLInputElement) => {
// if (!state.workspaces.length) await createNewWorkspace('default_workspace')
// setState(prevState => {
// return { ...prevState, uploadFileEvent: target }
// })
// }
props.plugin.request.getCurrentWorkspace = () => {
return { name: currentWorkspace, isLocalhost: currentWorkspace === LOCALHOST, absolutePath: `${props.plugin.workspace.workspacesPath}/${currentWorkspace}` }
}
......@@ -120,10 +104,8 @@ export function Workspace (props: WorkspaceProps) {
}
/** ** ****/
const resetFocus = (reset) => {
setState(prevState => {
return { ...prevState, reset }
})
const resetFocus = () => {
global.dispatchSetFocusElement([{ key: '', type: 'folder' }])
}
const switchWorkspace = async (name: string) => {
......@@ -153,7 +135,7 @@ export function Workspace (props: WorkspaceProps) {
return (
<div className='remixui_container'>
<div className='remixui_fileexplorer' onClick={() => resetFocus(true)}>
<div className='remixui_fileexplorer' onClick={resetFocus}>
<div>
<header>
<div className="mb-2">
......@@ -214,14 +196,12 @@ export function Workspace (props: WorkspaceProps) {
<FileExplorer
name={currentWorkspace}
menuItems={['createNewFile', 'createNewFolder', 'publishToGist', canUpload ? 'uploadFile' : '']}
plugin={props.plugin}
focusRoot={state.reset}
contextMenuItems={props.plugin.registeredMenuItems}
removedContextMenuItems={props.plugin.removedMenuItems}
displayInput={state.displayNewFile}
externalUploads={state.uploadFileEvent}
resetFocus={resetFocus}
files={global.fs.browser.files}
expandPath={global.fs.browser.expandPath}
focusEdit={global.fs.focusEdit}
focusElement={global.fs.focusElement}
/>
}
</div>
......@@ -232,12 +212,12 @@ export function Workspace (props: WorkspaceProps) {
<FileExplorer
name='localhost'
menuItems={['createNewFile', 'createNewFolder']}
plugin={props.plugin}
focusRoot={state.reset}
contextMenuItems={props.plugin.registeredMenuItems}
removedContextMenuItems={props.plugin.removedMenuItems}
resetFocus={resetFocus}
files={global.fs.localhost.files}
expandPath={global.fs.localhost.expandPath}
focusEdit={global.fs.focusEdit}
focusElement={global.fs.focusElement}
/>
}
</div>
......
......@@ -28,11 +28,8 @@ export interface WorkspaceProps {
}
}
export interface WorkspaceState {
reset: boolean
hideRemixdExplorer: boolean
displayNewFile: boolean
externalUploads: EventTarget & HTMLInputElement
uploadFileEvent: EventTarget & HTMLInputElement
loadingLocalhost: boolean
}
......@@ -46,7 +43,7 @@ export interface Modal {
cancelFn: () => void
}
export interface File {
export interface FileType {
path: string,
name: string,
isDirectory: boolean,
......@@ -58,13 +55,14 @@ export interface File {
export interface FileExplorerProps {
name: string,
menuItems?: string[],
focusRoot: boolean,
contextMenuItems: MenuItems,
removedContextMenuItems: MenuItems,
displayInput?: boolean,
externalUploads?: EventTarget & HTMLInputElement,
resetFocus?: (value: boolean) => void,
files: { [x: string]: Record<string, File> }
files: { [x: string]: Record<string, FileType> },
expandPath: string[],
focusEdit: string,
focusElement: { key: string, type: 'file' | 'folder' | 'gist' }[]
}
export interface FileExplorerMenuProps {
......
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