diff --git a/apps/remix-ide/src/app/panels/file-panel.js b/apps/remix-ide/src/app/panels/file-panel.js index f2a423264b..9bd770b813 100644 --- a/apps/remix-ide/src/app/panels/file-panel.js +++ b/apps/remix-ide/src/app/panels/file-panel.js @@ -30,7 +30,7 @@ const { SlitherHandle } = require('../files/slither-handle.js') const profile = { name: 'filePanel', displayName: 'File explorers', - methods: ['createNewFile', 'uploadFile', 'getCurrentWorkspace', 'getWorkspaces', 'createWorkspace', 'setWorkspace', 'registerContextMenuItem', 'renameWorkspace', 'deleteWorkspace'], + methods: ['createNewFile', 'uploadFile', 'getCurrentWorkspace', 'getWorkspaces', 'createWorkspace', 'setWorkspace', 'registerContextMenuItem', 'renameWorkspace', 'deleteWorkspace', 'setFileState'], events: ['setWorkspace', 'workspaceRenamed', 'workspaceDeleted', 'workspaceCreated'], icon: 'assets/img/fileManager.webp', description: ' - ', @@ -85,6 +85,11 @@ module.exports = class Filepanel extends ViewPlugin { }) } + async setFileState (items) { + console.log(items) + this.emit('setFileState', items) + } + getCurrentWorkspace () { return this.currentWorkspaceMetadata } diff --git a/libs/remix-core-plugin/src/lib/code-parser.ts b/libs/remix-core-plugin/src/lib/code-parser.tsx similarity index 91% rename from libs/remix-core-plugin/src/lib/code-parser.ts rename to libs/remix-core-plugin/src/lib/code-parser.tsx index c0dfc3496b..010568e32d 100644 --- a/libs/remix-core-plugin/src/lib/code-parser.ts +++ b/libs/remix-core-plugin/src/lib/code-parser.tsx @@ -6,6 +6,10 @@ import { Compiler } from '@remix-project/remix-solidity' import { AstNode, CompilationError, CompilationResult, CompilationSource } from '@remix-project/remix-solidity' import { helper } from '@remix-project/remix-solidity' + +import React from 'react' +// eslint-disable-next-line +import { fileState, fileStateType } from '@remix-ui/workspace' const SolidityParser = (window as any).SolidityParser = (window as any).SolidityParser || [] const profile = { @@ -107,7 +111,48 @@ export class CodeParser extends Plugin { } console.log('allErrors', allErrors) await this.call('editor', 'addErrorMarker', allErrors) + try { + + let fileState:fileState = { + path: this.currentFile, + isDirectory: false, + fileStateType: [fileStateType.Custom], + fileStateLabelClass: 'text-success', + fileStateIconClass: '', + fileStateIcon: , + comment: '', + owner: 'code-parser', + bubble: true + } + await this.call('filePanel', 'setFileState', [fileState]) + fileState = { + ...fileState, + path: 'contracts/1_Storage.sol', + fileStateLabelClass: 'text-danger', + fileStateIcon: , + } + await this.call('filePanel', 'setFileState', [fileState]) + fileState = { + ...fileState, + path: 'scripts/ethers-lib.ts', + fileStateLabelClass: 'text-danger', + fileStateIcon:
  • call rob now!
    , + } + await this.call('filePanel', 'setFileState', [fileState]) + + } catch (e) { + console.log('error calling filePanel', e) + } } else { + await this.call('filePanel', 'setFileState', [{ + path: this.currentFile, + isDirectory: false, + fileStateType: [], + fileStateClass: '', + comment: '', + owner: 'code-parser', + bubble: true + }]) await this.call('editor', 'clearErrorMarkers', result.getSourceCode().sources) } @@ -605,7 +650,7 @@ export class CodeParser extends Plugin { } else { if (node.typeName && node.typeName.name) { return `${node.typeName.name} ${node.visibility}${node.name && node.name.length ? ` ${node.name}` : ''}` - } + } else if (node.typeName && node.typeName.namePath) { return `${node.typeName.namePath} ${node.visibility}${node.name && node.name.length ? ` ${node.name}` : ''}` } diff --git a/libs/remix-core-plugin/tsconfig.json b/libs/remix-core-plugin/tsconfig.json index 7f163468b2..2845e6dae0 100644 --- a/libs/remix-core-plugin/tsconfig.json +++ b/libs/remix-core-plugin/tsconfig.json @@ -1,8 +1,9 @@ { "extends": "../../tsconfig.base.json", "compilerOptions": { + "jsx": "react", "types": ["node"], "esModuleInterop": true }, - "include": ["**/*.ts"] + "include": ["**/*.ts", "src/lib/code-parser.tsx"] } \ No newline at end of file diff --git a/libs/remix-ui/editor/src/lib/providers/completionProvider.ts b/libs/remix-ui/editor/src/lib/providers/completionProvider.ts index 18c4fd3797..69e7d4f178 100644 --- a/libs/remix-ui/editor/src/lib/providers/completionProvider.ts +++ b/libs/remix-ui/editor/src/lib/providers/completionProvider.ts @@ -2,7 +2,7 @@ import { isArray } from "lodash" import { editor, languages, Position } from "monaco-editor" import monaco from "../../types/monaco" import { EditorUIProps } from "../remix-ui-editor" -import { GeCompletionUnits, getBlockCompletionItems, GetCompletionKeywords, getCompletionSnippets, GetCompletionTypes, getContextualAutoCompleteByGlobalVariable, GetGlobalFunctions, GetGlobalVariable, getMsgCompletionItems, getTxCompletionItems } from "./completion/completionGlobals" +import { GeCompletionUnits, GetCompletionKeywords, getCompletionSnippets, GetCompletionTypes, getContextualAutoCompleteByGlobalVariable, GetGlobalFunctions, GetGlobalVariable } from "./completion/completionGlobals" export class RemixCompletionProvider implements languages.CompletionItemProvider { diff --git a/libs/remix-ui/workspace/src/index.ts b/libs/remix-ui/workspace/src/index.ts index 166467d115..660e0b217b 100644 --- a/libs/remix-ui/workspace/src/index.ts +++ b/libs/remix-ui/workspace/src/index.ts @@ -1,2 +1,3 @@ export * from './lib/providers/FileSystemProvider' export * from './lib/contexts' +export { fileState, fileStateType } from './lib/types/index' \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/actions/events.ts b/libs/remix-ui/workspace/src/lib/actions/events.ts index a8bde65fd5..f9e76f1715 100644 --- a/libs/remix-ui/workspace/src/lib/actions/events.ts +++ b/libs/remix-ui/workspace/src/lib/actions/events.ts @@ -1,7 +1,7 @@ import { extractParentFromKey } from '@remix-ui/helper' import React from 'react' -import { action, WorkspaceTemplate } from '../types' -import { displayNotification, displayPopUp, fileAddedSuccess, fileRemovedSuccess, fileRenamedSuccess, folderAddedSuccess, loadLocalhostError, loadLocalhostRequest, loadLocalhostSuccess, removeContextMenuItem, removeFocus, rootFolderChangedSuccess, setContextMenuItem, setMode, setReadOnlyMode } from './payload' +import { action, WorkspaceTemplate, fileState } from '../types' +import { displayNotification, displayPopUp, fileAddedSuccess, fileRemovedSuccess, fileRenamedSuccess, folderAddedSuccess, loadLocalhostError, loadLocalhostRequest, loadLocalhostSuccess, removeContextMenuItem, removeFocus, rootFolderChangedSuccess, setContextMenuItem, setMode, setReadOnlyMode, setFileStateSuccess } from './payload' import { addInputField, createWorkspace, deleteWorkspace, fetchWorkspaceDirectory, renameWorkspace, switchToWorkspace, uploadFile } from './workspace' const LOCALHOST = ' - connect to localhost - ' @@ -38,6 +38,10 @@ export const listenOnPluginEvents = (filePanelPlugin) => { uploadFile(target, dir, cb) }) + plugin.on('filePanel', 'setFileState', async (items: fileState[]) => { + setFileState(items) + }) + plugin.on('remixd', 'rootFolderChanged', async (path: string) => { rootFolderChanged(path) }) @@ -202,3 +206,8 @@ const fileRenamed = async (oldPath: string) => { const rootFolderChanged = async (path) => { await dispatch(rootFolderChangedSuccess(path)) } + +const setFileState = async (items: fileState[], cb?: (err: Error, result?: string | number | boolean | Record) => void) => { + await dispatch(setFileStateSuccess(items)) + cb && cb(null, true) +} diff --git a/libs/remix-ui/workspace/src/lib/actions/payload.ts b/libs/remix-ui/workspace/src/lib/actions/payload.ts index a0ed0850cb..338caffd45 100644 --- a/libs/remix-ui/workspace/src/lib/actions/payload.ts +++ b/libs/remix-ui/workspace/src/lib/actions/payload.ts @@ -1,4 +1,4 @@ -import { action } from '../types' +import { action, fileState } from '../types' export const setCurrentWorkspace = (workspace: string) => { return { @@ -239,3 +239,10 @@ export const fsInitializationCompleted = () => { type: 'FS_INITIALIZATION_COMPLETED' } } + +export const setFileStateSuccess = (items: fileState[]) => { + return { + type: 'SET_FILE_STATE_SUCCESS', + payload: items + } +} diff --git a/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx b/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx index a0351ea3a1..adbad94a36 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-explorer.tsx @@ -12,7 +12,7 @@ import { checkSpecialChars, extractNameFromKey, extractParentFromKey, joinPath } import { FileRender } from './file-render' export const FileExplorer = (props: FileExplorerProps) => { - const { name, contextMenuItems, removedContextMenuItems, files } = props + const { name, contextMenuItems, removedContextMenuItems, files, fileState } = props const [state, setState] = useState({ ctrlKey: false, newFileName: '', @@ -432,6 +432,7 @@ export const FileExplorer = (props: FileExplorerProps) => { { files[props.name] && Object.keys(files[props.name]).map((key, index) => void } export const FileLabel = (props: FileLabelProps) => { - const { file, focusEdit, editModeOff } = props + const { file, focusEdit, editModeOff, fileState } = props const [isEditable, setIsEditable] = useState(false) + const [fileStateClasses, setFileStateClasses] = useState('') const labelRef = useRef(null) useEffect(() => { @@ -24,6 +26,17 @@ export const FileLabel = (props: FileLabelProps) => { } }, [file.path, focusEdit]) + useEffect(() => { + const state = props.fileState.find((state: fileState) => { + if(state.path === props.file.path) return true + if(state.bubble && props.file.isDirectory && state.path.startsWith(props.file.path)) return true + }) + console.log(props) + if (state && state.fileStateLabelClass) { + setFileStateClasses(state.fileStateLabelClass) + } + }, [fileState]) + useEffect(() => { if (labelRef.current) { setTimeout(() => { @@ -57,10 +70,10 @@ export const FileLabel = (props: FileLabelProps) => { > - { file.name } + {file.name} ) diff --git a/libs/remix-ui/workspace/src/lib/components/file-render.tsx b/libs/remix-ui/workspace/src/lib/components/file-render.tsx index ac0054e96b..398a75f4ae 100644 --- a/libs/remix-ui/workspace/src/lib/components/file-render.tsx +++ b/libs/remix-ui/workspace/src/lib/components/file-render.tsx @@ -1,11 +1,12 @@ // eslint-disable-next-line no-use-before-define import React, { SyntheticEvent, useEffect, useState } from 'react' -import { FileType } from '../types' +import { fileState, 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' +import FileState from './file-state' export interface RenderFileProps { file: FileType, @@ -19,6 +20,7 @@ export interface RenderFileProps { handleClickFolder: (path: string, type: string) => void, handleClickFile: (path: string, type: string) => void, handleContextMenu: (pageX: number, pageY: number, path: string, content: string, type: string) => void + fileState: fileState[] } export const FileRender = (props: RenderFileProps) => { @@ -76,7 +78,7 @@ export const FileRender = (props: RenderFileProps) => { iconX='pr-3 fa fa-folder' iconY='pr-3 fa fa-folder-open' key={`${file.path + props.index}`} - label={} + label={} onClick={handleFolderClick} onContextMenu={handleContextMenu} labelClass={labelClass} @@ -89,6 +91,7 @@ export const FileRender = (props: RenderFileProps) => { file.child ? { Object.keys(file.child).map((key, index) => { } + label={ + <> +
    + + +
    + + } onClick={handleFileClick} onContextMenu={handleContextMenu} icon={icon} diff --git a/libs/remix-ui/workspace/src/lib/components/file-state.tsx b/libs/remix-ui/workspace/src/lib/components/file-state.tsx new file mode 100644 index 0000000000..fbf660777a --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/components/file-state.tsx @@ -0,0 +1,56 @@ +// eslint-disable-next-line no-use-before-define +import React, { useEffect, useState } from 'react' +import { FileType, fileState, fileStateType } from '../types' +import FileStateCustom from './filestates/file-state-custom' +import FileStateError from './filestates/file-state-error' +import FileStateWarning from './filestates/file-state-warning' +// import FileStateModified from './filestates/file-state-modified' +// import FileStateUntracked from './filestates/file-state-untracked' + +export type fileStateProps = { + file: FileType, + fileState: fileState[] +} + +export const FileState = (props: fileStateProps) => { + const [state, setState] = useState(undefined) + useEffect(() => { + console.log(props.file) + console.log(props.fileState) + setState(props.fileState.find((st) => st.path === props.file.path)) + }, [props.fileState]) + + const getTags = function () { + if (state) { + const types = state.fileStateType + const elements: any[] = [] + + for (const type of types) { + switch (type) { + case fileStateType.Modified: + //elements.push() + break + case fileStateType.Untracked: + //elements.push() + break + case fileStateType.Error: + elements.push() + break + case fileStateType.Warning: + elements.push() + break + case fileStateType.Custom: + elements.push() + break + } + } + return elements + } + } + + return <> + {getTags()} + +} + +export default FileState \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/components/filestates/file-state-custom.tsx b/libs/remix-ui/workspace/src/lib/components/filestates/file-state-custom.tsx new file mode 100644 index 0000000000..ef56538480 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/components/filestates/file-state-custom.tsx @@ -0,0 +1,13 @@ +// eslint-disable-next-line no-use-before-define +import React from 'react' +import { fileState } from '../../types' + +const FileStateError = (props: { + fileState: fileState +}) => { + return <> + {props.fileState.fileStateIcon} + +} + +export default FileStateError \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/components/filestates/file-state-error.tsx b/libs/remix-ui/workspace/src/lib/components/filestates/file-state-error.tsx new file mode 100644 index 0000000000..1e8a950218 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/components/filestates/file-state-error.tsx @@ -0,0 +1,11 @@ +// eslint-disable-next-line no-use-before-define +import React from 'react' +import { fileState } from '../../types' + +const FileStateError = (props: { + fileState: fileState +}) => { + return <> +} + +export default FileStateError \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/components/filestates/file-state-icon-properties.tsx b/libs/remix-ui/workspace/src/lib/components/filestates/file-state-icon-properties.tsx new file mode 100644 index 0000000000..e69de29bb2 diff --git a/libs/remix-ui/workspace/src/lib/components/filestates/file-state-warning.tsx b/libs/remix-ui/workspace/src/lib/components/filestates/file-state-warning.tsx new file mode 100644 index 0000000000..81912cfbd2 --- /dev/null +++ b/libs/remix-ui/workspace/src/lib/components/filestates/file-state-warning.tsx @@ -0,0 +1,11 @@ +// eslint-disable-next-line no-use-before-define +import React from 'react' +import { fileState } from '../../types' + +const FileStateWarning = (props: { + fileState: fileState +}) => { + return <> +} + +export default FileStateWarning \ No newline at end of file diff --git a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts index 8d33cb226d..a6951c50cc 100644 --- a/libs/remix-ui/workspace/src/lib/reducers/workspace.ts +++ b/libs/remix-ui/workspace/src/lib/reducers/workspace.ts @@ -1,5 +1,5 @@ import { extractNameFromKey } from '@remix-ui/helper' -import { action, FileType } from '../types' +import { action, fileState, FileType } from '../types' import * as _ from 'lodash' interface Action { type: string @@ -20,7 +20,8 @@ export interface BrowserState { registeredMenuItems: action[], removedMenuItems: action[], error: string - } + }, + fileState: fileState[] }, localhost: { sharedFolder: string, @@ -35,7 +36,8 @@ export interface BrowserState { registeredMenuItems: action[], removedMenuItems: action[], error: string - } + }, + fileState: [] }, mode: 'browser' | 'localhost', notification: { @@ -68,7 +70,8 @@ export const browserInitialState: BrowserState = { registeredMenuItems: [], removedMenuItems: [], error: null - } + }, + fileState: [] }, localhost: { sharedFolder: '', @@ -83,7 +86,8 @@ export const browserInitialState: BrowserState = { registeredMenuItems: [], removedMenuItems: [], error: null - } + }, + fileState: [] }, mode: 'browser', notification: { @@ -599,6 +603,34 @@ export const browserReducer = (state = browserInitialState, action: Action) => { } } + case 'SET_FILE_STATE_SUCCESS': { + const payload = action.payload as fileState[] + console.log('SET_FILE_STATE_SUCCESS', payload) + const a = state.browser.fileState + const b = payload + const merge = _.merge({}, _.keyBy(a, 'path'), _.keyBy(b, 'path')) + const vals = _.values(merge) + console.log(a) + console.log(vals) + vals.map(function (x) { + const c = a.find(function (el) { + return el.path === x.path + }) + if (c && c.fileStateType) { + x.fileStateType = _.uniq([...c.fileStateType, ...x.fileStateType]) + } + return x + }) + console.log(vals) + return { + ...state, + browser: { + ...state.browser, + fileState: vals + } + } + } + default: throw new Error() } diff --git a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx index 98a80306bd..24538c4d9d 100644 --- a/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx +++ b/libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx @@ -238,6 +238,7 @@ export function Workspace () { contextMenuItems={global.fs.browser.contextMenu.registeredMenuItems} removedContextMenuItems={global.fs.browser.contextMenu.removedMenuItems} files={global.fs.browser.files} + fileState={global.fs.browser.fileState} expandPath={global.fs.browser.expandPath} focusEdit={global.fs.focusEdit} focusElement={global.fs.focusElement} @@ -273,6 +274,7 @@ export function Workspace () { contextMenuItems={global.fs.localhost.contextMenu.registeredMenuItems} removedContextMenuItems={global.fs.localhost.contextMenu.removedMenuItems} files={global.fs.localhost.files} + fileState={[]} expandPath={global.fs.localhost.expandPath} focusEdit={global.fs.focusEdit} focusElement={global.fs.focusElement} diff --git a/libs/remix-ui/workspace/src/lib/types/index.ts b/libs/remix-ui/workspace/src/lib/types/index.ts index fb169db5e8..9605894846 100644 --- a/libs/remix-ui/workspace/src/lib/types/index.ts +++ b/libs/remix-ui/workspace/src/lib/types/index.ts @@ -66,6 +66,35 @@ export interface FileType { child?: File[] } +export enum fileStateType { + Error = 'ERROR', + Warning = 'WARNING', + Success = 'SUCCESS', + Loading = 'LOADING', + Unsaved = 'UNSAVED', + Untracked = 'UNTRACKED', + Modified = 'MODIFIED', + Staged = 'STAGED', + Committed = 'COMMITTED', + Deleted = 'DELETED', + Added = 'ADDED', + New = 'NEW', + Compiled = 'COMPILED', + Custom = 'CUSTOM', +} + +export type fileState = { + path: string, + isDirectory: boolean, + fileStateType: fileStateType[], + fileStateLabelClass: string, + fileStateIconClass: string, + fileStateIcon: string | HTMLDivElement | JSX.Element, + bubble: boolean, + comment: string, + owner: string, +} + /* eslint-disable-next-line */ export interface FileExplorerProps { name: string, @@ -73,6 +102,7 @@ export interface FileExplorerProps { contextMenuItems: MenuItems, removedContextMenuItems: MenuItems, files: { [x: string]: Record }, + fileState: fileState[], expandPath: string[], focusEdit: string, focusElement: { key: string, type: 'file' | 'folder' | 'gist' }[],