add sub menus

pull/5370/head
yann300 2 years ago
parent aa2f1b42e6
commit 6ad00bd246
  1. 4
      apps/remix-ide/src/app/tabs/locales/en/filePanel.json
  2. 1
      libs/remix-ui/helper/src/index.ts
  3. 92
      libs/remix-ui/helper/src/lib/components/dropdown-submenu.tsx
  4. 9
      libs/remix-ui/workspace/src/lib/actions/workspace.ts
  5. 66
      libs/remix-ui/workspace/src/lib/components/workspace-hamburger-item.tsx
  6. 41
      libs/remix-ui/workspace/src/lib/components/workspace-hamburger.tsx
  7. 2
      libs/remix-ui/workspace/src/lib/contexts/index.ts
  8. 4
      libs/remix-ui/workspace/src/lib/providers/FileSystemProvider.tsx
  9. 4
      libs/remix-ui/workspace/src/lib/remix-ui-workspace.tsx
  10. 29
      libs/remix-ui/workspace/src/lib/scripts/contract-deployer/basic-contract-deploy.ts
  11. 2
      libs/remix-ui/workspace/src/lib/scripts/contract-deployer/create2-factory-deploy.ts
  12. 5
      libs/remix-ui/workspace/src/lib/scripts/contract-deployer/index.ts
  13. 7
      libs/remix-ui/workspace/src/lib/scripts/index.ts

@ -27,6 +27,10 @@
"filePanel.solghaction": "Solidity Test Workflow", "filePanel.solghaction": "Solidity Test Workflow",
"filePanel.workspace.tssoltestghaction": "Adds a preset yml file to run mocha and chai tests for solidity on github actions CI", "filePanel.workspace.tssoltestghaction": "Adds a preset yml file to run mocha and chai tests for solidity on github actions CI",
"filePanel.tssoltestghaction": "Mocha Chai Test Workflow", "filePanel.tssoltestghaction": "Mocha Chai Test Workflow",
"filePanel.workspace.addscriptetherscan": "Adds a scripts which can be used to interact with the etherscan API.",
"filePanel.addscriptetherscan": "Add Etherscan script",
"filePanel.workspace.addscriptdeployer": "Adds a scripts which can be used to deploy contracts.",
"filePanel.addscriptdeployer": "Add Contract deployer script",
"filePanel.workspace.slitherghaction": "Adds a preset yml file to run slither analysis on github actions CI", "filePanel.workspace.slitherghaction": "Adds a preset yml file to run slither analysis on github actions CI",
"filePanel.slitherghaction": "Slither Workflow", "filePanel.slitherghaction": "Slither Workflow",
"filePanel.workspace.helperscripts": "Adds convenient scripts to the 'scripts' directory", "filePanel.workspace.helperscripts": "Adds convenient scripts to the 'scripts' directory",

@ -4,3 +4,4 @@ export * from './lib/helper-components'
export * from './lib/components/PluginViewWrapper' export * from './lib/components/PluginViewWrapper'
export * from './lib/components/custom-dropdown' export * from './lib/components/custom-dropdown'
export * from './lib/components/custom-tooltip' export * from './lib/components/custom-tooltip'
export * from './lib/components/dropdown-submenu'

@ -0,0 +1,92 @@
import * as React from 'react';
import {DropdownProps} from 'react-bootstrap/Dropdown';
import {useRef} from "react";
interface Props extends DropdownProps {
id?: string;
className?: string;
href?: string;
title: string
}
export const DropdownSubmenu: React.FC<Props> = (props:Props) => {
let refSubMenuContent = useRef(null as HTMLDivElement | null);
let className = 'dropdown-submenu-container';
className = props.className
? className + ' ' + props.className
: className;
const onClick = (event: React.SyntheticEvent<any>) => {
event.preventDefault();
event.stopPropagation();
if (refSubMenuContent.current) {
let show = false;
if (refSubMenuContent.current.classList.contains('show')) {
hideChildren(refSubMenuContent.current);
} else {
show = true;
hideSiblings();
}
refSubMenuContent.current.classList.toggle('show');
if (typeof props.onToggle === 'function') {
props.onToggle(show, event, { source: 'select'});
}
}
};
const hideSiblings = () => {
if (refSubMenuContent.current) {
const parents = getParents(
refSubMenuContent.current,
'.dropdown-menu.show'
);
if (parents.length > 1) {
hideChildren(parents[1]);
}
}
};
const hideChildren = (parent: any) => {
const children = parent.querySelectorAll('.dropdown-menu.show') as any;
for (const child of children) {
child.classList.remove('show');
}
}
const getParents = (elem: any, selector: string) => {
const nodes = [];
let element = elem;
nodes.push(element);
while (element.parentNode) {
if (
typeof element.parentNode.matches === 'function' &&
element.parentNode.matches(selector)
) {
nodes.push(element.parentNode);
}
element = element.parentNode;
}
return nodes;
}
return (
<div className={className} id={props.id}>
<a
href={props.href}
className="dropdown-item dropdown-submenu dropdown-toggle"
onClick={onClick}
>
{props.title}
</a>
<div
className="dropdown-menu"
ref={refSubMenuContent}
>
{props.children}
</div>
</div>
);
}

@ -13,8 +13,7 @@ import { ROOT_PATH, slitherYml, solTestYml, tsSolTestYml } from '../utils/consta
import { IndexedDBStorage } from '../../../../../../apps/remix-ide/src/app/files/filesystems/indexedDB' import { IndexedDBStorage } from '../../../../../../apps/remix-ide/src/app/files/filesystems/indexedDB'
import { getUncommittedFiles } from '../utils/gitStatusFilter' import { getUncommittedFiles } from '../utils/gitStatusFilter'
import { AppModal, ModalTypes } from '@remix-ui/app' import { AppModal, ModalTypes } from '@remix-ui/app'
import { contractDeployerScripts } from '../scripts/contract-deployer' import { scripts } from '../scripts'
import { etherscanScripts } from '../scripts/etherscan'
declare global { declare global {
interface Window { remixFileSystemCallback: IndexedDBStorage; } interface Window { remixFileSystemCallback: IndexedDBStorage; }
@ -679,9 +678,9 @@ export const createSlitherGithubAction = async () => {
plugin.call('fileManager', 'open', path) plugin.call('fileManager', 'open', path)
} }
export const createHelperScripts = async () => { export const createHelperScripts = async (script: string) => {
await contractDeployerScripts(plugin) if (!scripts[script]) return
await etherscanScripts(plugin) await scripts[script](plugin)
plugin.call('notification', 'toast', 'scripts added in the "scripts" folder') plugin.call('notification', 'toast', 'scripts added in the "scripts" folder')
} }

@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import { CustomTooltip } from '@remix-ui/helper' import { CustomTooltip, CustomMenu, CustomIconsToggle } from '@remix-ui/helper'
import { Dropdown } from 'react-bootstrap' import { Dropdown, NavDropdown} from 'react-bootstrap'
import { FormattedMessage } from 'react-intl' import { FormattedMessage } from 'react-intl'
const _paq = window._paq = window._paq || [] const _paq = window._paq = window._paq || []
@ -49,3 +49,65 @@ export function HamburgerMenuItem (props: HamburgerMenuItemProps) {
</> </>
) )
} }
// keeping the following for a later use:
export function NavHamburgerMenuItem (props: HamburgerMenuItemProps) {
const { hideOption } = props
const uid = 'workspace' + props.kind
return (
<>
<NavDropdown.Item>
<CustomTooltip
placement="right"
tooltipId={uid + "Tooltip"}
tooltipClasses="text-nowrap"
tooltipText={<FormattedMessage id={'filePanel.workspace.' + props.kind} />}
>
<div
data-id={uid}
key={uid + '-fe-ws'}
onClick={() => {
props.actionOnClick()
_paq.push(['trackEvent', 'fileExplorer', 'workspaceMenu', uid])
}}
>
<span
hidden={hideOption}
id={uid}
data-id={uid}
className={props.fa + ' pl-2'}
style={{width: '1.4rem'}}
>
</span>
<span className="px-2">
<FormattedMessage id={'filePanel.' + props.kind } />
</span>
</div>
</CustomTooltip>
</NavDropdown.Item>
</>
)
}
export interface HamburgerSubMenuItemProps {
id: string
title: string
subMenus: Array<HamburgerMenuItemProps>
}
export function HamburgerSubMenuItem (props: HamburgerSubMenuItemProps) {
return (
<>
<NavDropdown
title={props.title}
as={CustomMenu}
key={props.id}
id={props.id}
drop='right'
>
{props.subMenus.map(item => <NavHamburgerMenuItem kind={item.kind} fa={item.fa} hideOption={item.hideOption} actionOnClick={item.actionOnClick} />)}
</NavDropdown>
</>
)
}

@ -1,6 +1,6 @@
import React from 'react' import React from 'react'
import { Dropdown } from 'react-bootstrap' import { Dropdown } from 'react-bootstrap'
import { HamburgerMenuItem } from './workspace-hamburger-item' import { HamburgerMenuItem, HamburgerSubMenuItem } from './workspace-hamburger-item'
export interface HamburgerMenuProps { export interface HamburgerMenuProps {
createWorkspace: () => void, createWorkspace: () => void,
@ -15,7 +15,7 @@ export interface HamburgerMenuProps {
addGithubAction: () => void, addGithubAction: () => void,
addTsSolTestGithubAction: () => void, addTsSolTestGithubAction: () => void,
addSlitherGithubAction: () => void, addSlitherGithubAction: () => void,
addHelperScripts: () => void, addHelperScripts: (script: string) => void,
showIconsMenu: boolean, showIconsMenu: boolean,
hideWorkspaceOptions: boolean, hideWorkspaceOptions: boolean,
hideLocalhostOptions: boolean hideLocalhostOptions: boolean
@ -72,10 +72,43 @@ export function HamburgerMenu (props: HamburgerMenuProps) {
props.hideIconsMenu(!showIconsMenu) props.hideIconsMenu(!showIconsMenu)
}}></HamburgerMenuItem> }}></HamburgerMenuItem>
<Dropdown.Divider className="border mb-0 mt-0 remixui_menuhr" style={{ pointerEvents: 'none' }} /> <Dropdown.Divider className="border mb-0 mt-0 remixui_menuhr" style={{ pointerEvents: 'none' }} />
<HamburgerMenuItem kind='helperscripts' fa='fak fa-ts-logo' hideOption={hideWorkspaceOptions} actionOnClick={() => { <HamburgerMenuItem kind='addscriptetherscan' fa='fak fa-ts-logo' hideOption={hideWorkspaceOptions} actionOnClick={() => {
props.addHelperScripts() props.addHelperScripts('etherscan')
props.hideIconsMenu(!showIconsMenu)
}}></HamburgerMenuItem>
<HamburgerMenuItem kind='addscriptdeployer' fa='fak fa-ts-logo' hideOption={hideWorkspaceOptions} actionOnClick={() => {
props.addHelperScripts('deployer')
props.hideIconsMenu(!showIconsMenu) props.hideIconsMenu(!showIconsMenu)
}}></HamburgerMenuItem> }}></HamburgerMenuItem>
</> </>
) )
} }
// keep for later use
/*<HamburgerSubMenuItem
id="web3-script-menu"
title="Web3 Scripts"
subMenus={[
{
kind:'etherscan-script',
fa: 'fak fa-ts-logo',
hideOption: hideWorkspaceOptions,
actionOnClick: () => {
alert('etherscan')
props.addHelperScripts()
props.hideIconsMenu(!showIconsMenu)
}
},
{
kind:'contract-deployer-factory-script',
fa: 'fak fa-ts-logo',
hideOption: hideWorkspaceOptions,
actionOnClick: () => {
alert('deloyer')
props.addHelperScripts()
props.hideIconsMenu(!showIconsMenu)
}
}
]}
></HamburgerSubMenuItem>
*/

@ -45,7 +45,7 @@ export const FileSystemContext = createContext<{
dispatchCreateSolidityGithubAction: () => Promise<void>, dispatchCreateSolidityGithubAction: () => Promise<void>,
dispatchCreateTsSolGithubAction: () => Promise<void>, dispatchCreateTsSolGithubAction: () => Promise<void>,
dispatchCreateSlitherGithubAction: () => Promise<void> dispatchCreateSlitherGithubAction: () => Promise<void>
dispatchCreateHelperScripts: () => Promise<void> dispatchCreateHelperScripts: (script: string) => Promise<void>
}>(null) }>(null)

@ -183,8 +183,8 @@ export const FileSystemProvider = (props: WorkspaceProps) => {
await createSlitherGithubAction() await createSlitherGithubAction()
} }
const dispatchCreateHelperScripts = async () => { const dispatchCreateHelperScripts = async (script: string) => {
await createHelperScripts() await createHelperScripts(script)
} }
useEffect(() => { useEffect(() => {

@ -209,8 +209,8 @@ export function Workspace () {
global.dispatchCreateSlitherGithubAction() global.dispatchCreateSlitherGithubAction()
} }
const addHelperScripts = () => { const addHelperScripts = (script: string) => {
global.dispatchCreateHelperScripts() global.dispatchCreateHelperScripts(script)
} }
const downloadWorkspaces = async () => { const downloadWorkspaces = async () => {

@ -0,0 +1,29 @@
import { ethers } from 'ethers'
/**
* Deploy the given contract
* @param {string} contractName name of the contract to deploy
* @param {Array<any>} args list of constructor' parameters
* @param {Number} accountIndex account index from the exposed account
* @return {Contract} deployed contract
*/
export const deploy = async (contractName: string, args: Array<any>, accountIndex?: number): Promise<ethers.Contract> => {
console.log(`deploying ${contractName}`)
// Note that the script needs the ABI which is generated from the compilation artifact.
// Make sure contract is compiled and artifacts are generated
const artifactsPath = `browser/contracts/artifacts/${contractName}.json` // Change this for different path
const metadata = JSON.parse(await remix.call('fileManager', 'getFile', artifactsPath))
// 'web3Provider' is a remix global variable object
const signer = (new ethers.providers.Web3Provider(web3Provider)).getSigner(accountIndex)
const factory = new ethers.ContractFactory(metadata.abi, metadata.data.bytecode.object, signer)
const contract = await factory.deploy(...args)
// The contract is NOT deployed yet; we must wait until it is mined
await contract.deployed()
return contract
}

@ -5,7 +5,7 @@ export const CREATE2_DEPLOYER_ADDRESS =
"0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2"; "0x13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2";
/** /**
* Deploy the given contract * Deploy the given contract using a factory
* @param {string} address of the factory contract * @param {string} address of the factory contract
* @param {string} contractName name of the contract to deploy * @param {string} contractName name of the contract to deploy
* @param {Array<any>} args list of constructor' parameters * @param {Array<any>} args list of constructor' parameters

@ -3,4 +3,9 @@ export const contractDeployerScripts = async (plugin) => {
'scripts/contract-deployer/create2-factory-deploy.ts' , 'scripts/contract-deployer/create2-factory-deploy.ts' ,
// @ts-ignore // @ts-ignore
(await import('!!raw-loader!./create2-factory-deploy.ts')).default) (await import('!!raw-loader!./create2-factory-deploy.ts')).default)
await plugin.call('fileManager', 'writeFile',
'scripts/contract-deployer/basic-contract-deploy.ts' ,
// @ts-ignore
(await import('!!raw-loader!./basic-contract-deploy.ts')).default)
} }

@ -0,0 +1,7 @@
import { contractDeployerScripts } from '../scripts/contract-deployer'
import { etherscanScripts } from '../scripts/etherscan'
export const scripts = {
'etherscan': etherscanScripts,
'deployer': contractDeployerScripts
}
Loading…
Cancel
Save