commit
3a20e015d7
@ -1,4 +0,0 @@ |
|||||||
# Add files here to ignore them from prettier formatting |
|
||||||
|
|
||||||
/dist |
|
||||||
/coverage |
|
@ -1,3 +0,0 @@ |
|||||||
{ |
|
||||||
"singleQuote": true |
|
||||||
} |
|
@ -0,0 +1,18 @@ |
|||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
import EventEmitter from 'events' |
||||||
|
|
||||||
|
class switchEnvironment extends EventEmitter { |
||||||
|
command (this: NightwatchBrowser, provider: string): NightwatchBrowser { |
||||||
|
this.api.waitForElementVisible('[data-id="settingsSelectEnvOptions"]') |
||||||
|
.click('[data-id="settingsSelectEnvOptions"] button') |
||||||
|
.waitForElementVisible(`[data-id="dropdown-item-${provider}"]`) |
||||||
|
.click(`[data-id="dropdown-item-${provider}"]`) |
||||||
|
.perform((done) => { |
||||||
|
done() |
||||||
|
this.emit('complete') |
||||||
|
}) |
||||||
|
return this |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = switchEnvironment |
@ -0,0 +1,18 @@ |
|||||||
|
import { NightwatchBrowser } from 'nightwatch' |
||||||
|
import EventEmitter from 'events' |
||||||
|
|
||||||
|
class switchWorkspace extends EventEmitter { |
||||||
|
command (this: NightwatchBrowser, workspaceName: string): NightwatchBrowser { |
||||||
|
this.api.waitForElementVisible('[data-id="workspacesSelect"]') |
||||||
|
.click('[data-id="workspacesSelect"]') |
||||||
|
.waitForElementVisible(`[data-id="dropdown-item-${workspaceName}"]`) |
||||||
|
.click(`[data-id="dropdown-item-${workspaceName}"]`) |
||||||
|
.perform((done) => { |
||||||
|
done() |
||||||
|
this.emit('complete') |
||||||
|
}) |
||||||
|
return this |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = switchWorkspace |
@ -1,21 +0,0 @@ |
|||||||
#!/usr/bin/env node |
|
||||||
var path = require('path') |
|
||||||
var httpServer = require('http-server') |
|
||||||
var remixd = require('remixd') |
|
||||||
|
|
||||||
var server = httpServer.createServer({ |
|
||||||
root: path.join(__dirname, '/../') |
|
||||||
}) |
|
||||||
|
|
||||||
var folder = process.argv.length > 2 ? process.argv[2] : process.cwd() |
|
||||||
|
|
||||||
server.listen(8080, '127.0.0.1', function () {}) |
|
||||||
var router = new remixd.Router(65520, remixd.services.sharedFolder, { remixIdeUrl: 'http://localhost:8080' }, (webSocket) => { |
|
||||||
remixd.services.sharedFolder.setWebSocket(webSocket) |
|
||||||
remixd.services.sharedFolder.setupNotifications(folder) |
|
||||||
remixd.services.sharedFolder.sharedFolder(folder, false) |
|
||||||
}) |
|
||||||
|
|
||||||
router.start() |
|
||||||
|
|
||||||
console.log('\x1b[33m%s\x1b[0m', 'Starting Remix IDE at http://localhost:8080 and sharing ' + folder) |
|
@ -0,0 +1,41 @@ |
|||||||
|
import * as packageJson from '../../../../../package.json' |
||||||
|
import React from 'react' // eslint-disable-line
|
||||||
|
import { AbstractProvider } from './abstract-provider' |
||||||
|
|
||||||
|
const profile = { |
||||||
|
name: 'basic-http-provider', |
||||||
|
displayName: 'External Http Provider', |
||||||
|
kind: 'provider', |
||||||
|
description: '', |
||||||
|
methods: ['sendAsync'], |
||||||
|
version: packageJson.version |
||||||
|
} |
||||||
|
|
||||||
|
export class ExternalHttpProvider extends AbstractProvider { |
||||||
|
constructor (blockchain) { |
||||||
|
super(profile, blockchain, 'http://127.0.0.1:8545') |
||||||
|
} |
||||||
|
|
||||||
|
body (): JSX.Element { |
||||||
|
const thePath = '<path/to/local/folder/for/test/chain>' |
||||||
|
return ( |
||||||
|
<> |
||||||
|
<div className=""> |
||||||
|
Note: To use Geth & https://remix.ethereum.org, configure it to allow requests from Remix:(see <a href="https://geth.ethereum.org/docs/rpc/server" target="_blank" rel="noreferrer">Geth Docs on rpc server</a>)
|
||||||
|
<div className="border p-1">geth --http --http.corsdomain https://remix.ethereum.org</div>
|
||||||
|
<br /> |
||||||
|
To run Remix & a local Geth test node, use this command: (see <a href="https://geth.ethereum.org/getting-started/dev-mode" target="_blank" rel="noreferrer">Geth Docs on Dev mode</a>) |
||||||
|
<div className="border p-1">geth --http --http.corsdomain="{window.origin}" --http.api web3,eth,debug,personal,net --vmdebug --datadir {thePath} --dev console</div> |
||||||
|
<br /> |
||||||
|
<br /> |
||||||
|
<b>WARNING:</b> It is not safe to use the --http.corsdomain flag with a wildcard: <b>--http.corsdomain *</b> |
||||||
|
<br /> |
||||||
|
<br />For more info: <a href="https://remix-ide.readthedocs.io/en/latest/run.html#more-about-web3-provider" target="_blank" rel="noreferrer">Remix Docs on Web3 Provider</a> |
||||||
|
<br /> |
||||||
|
<br /> |
||||||
|
External HTTP Provider Endpoint |
||||||
|
</div> |
||||||
|
</> |
||||||
|
) |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
import * as packageJson from '../../../../../package.json' |
||||||
|
import { InjectedProvider } from './injected-provider' |
||||||
|
|
||||||
|
const profile = { |
||||||
|
name: 'injected-arbitrum-one-provider', |
||||||
|
displayName: 'Injected Arbitrum One Provider', |
||||||
|
kind: 'provider', |
||||||
|
description: 'injected Arbitrum One Provider', |
||||||
|
methods: ['sendAsync'], |
||||||
|
version: packageJson.version |
||||||
|
} |
||||||
|
|
||||||
|
export class InjectedArbitrumOneProvider extends InjectedProvider { |
||||||
|
|
||||||
|
constructor () { |
||||||
|
super(profile) |
||||||
|
this.chainName = 'Arbitrum One' |
||||||
|
this.chainId = '0xa4b1' |
||||||
|
this.rpcUrls = ['https://arb1.arbitrum.io/rpc'] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,21 @@ |
|||||||
|
import * as packageJson from '../../../../../package.json' |
||||||
|
import { InjectedProvider } from './injected-provider' |
||||||
|
|
||||||
|
const profile = { |
||||||
|
name: 'injected-optimism-provider', |
||||||
|
displayName: 'Injected Optimism Provider', |
||||||
|
kind: 'provider', |
||||||
|
description: 'injected Optimism Provider', |
||||||
|
methods: ['sendAsync'], |
||||||
|
version: packageJson.version |
||||||
|
} |
||||||
|
|
||||||
|
export class Injected0ptimismProvider extends InjectedProvider { |
||||||
|
|
||||||
|
constructor () { |
||||||
|
super(profile) |
||||||
|
this.chainName = 'Optimism' |
||||||
|
this.chainId = '0xa' |
||||||
|
this.rpcUrls = ['https://mainnet.optimism.io'] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,75 @@ |
|||||||
|
import { Plugin } from '@remixproject/engine' |
||||||
|
import { JsonDataRequest, RejectRequest, SuccessRequest } from './abstract-provider' |
||||||
|
import { ethers } from 'ethers' |
||||||
|
import Web3 from 'web3' |
||||||
|
|
||||||
|
export class InjectedProvider extends Plugin { |
||||||
|
provider: any |
||||||
|
chainName: string |
||||||
|
chainId: string |
||||||
|
rpcUrls: Array<string> |
||||||
|
|
||||||
|
constructor (profile) { |
||||||
|
super(profile) |
||||||
|
if ((window as any).ethereum) { |
||||||
|
this.provider = new Web3((window as any).ethereum) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sendAsync (data: JsonDataRequest): Promise<any> { |
||||||
|
return new Promise((resolve, reject) => { |
||||||
|
this.sendAsyncInternal(data, resolve, reject)
|
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
private async sendAsyncInternal (data: JsonDataRequest, resolve: SuccessRequest, reject: RejectRequest): Promise<void> { |
||||||
|
// Check the case where current environment is VM on UI and it still sends RPC requests
|
||||||
|
// This will be displayed on UI tooltip as 'cannot get account list: Environment Updated !!'
|
||||||
|
if (!this.provider) { |
||||||
|
this.call('notification', 'toast', 'No injected provider (e.g Metamask) has been found.') |
||||||
|
return reject(new Error('no injected provider found.')) |
||||||
|
} |
||||||
|
try { |
||||||
|
if ((window as any) && typeof (window as any).ethereum.enable === 'function') (window as any).ethereum.enable() |
||||||
|
if (!await (window as any).ethereum._metamask.isUnlocked()) this.call('notification', 'toast', 'Please make sure the injected provider is unlocked (e.g Metamask).') |
||||||
|
await addL2Network(this.chainName, this.chainId, this.rpcUrls) |
||||||
|
const resultData = await this.provider.currentProvider.send(data.method, data.params) |
||||||
|
resolve({ jsonrpc: '2.0', result: resultData.result, id: data.id }) |
||||||
|
} catch (error) { |
||||||
|
reject(error) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
export const addL2Network = async (chainName: string, chainId: string, rpcUrls: Array<string>) => { |
||||||
|
try { |
||||||
|
await (window as any).ethereum.request({ |
||||||
|
method: 'wallet_switchEthereumChain', |
||||||
|
params: [{ chainId: chainId }], |
||||||
|
}); |
||||||
|
} catch (switchError) { |
||||||
|
// This error code indicates that the chain has not been added to MetaMask.
|
||||||
|
if (switchError.code === 4902) { |
||||||
|
try { |
||||||
|
await (window as any).ethereum.request({ |
||||||
|
method: 'wallet_addEthereumChain', |
||||||
|
params: [ |
||||||
|
{ |
||||||
|
chainId: chainId, |
||||||
|
chainName: chainName, |
||||||
|
rpcUrls: rpcUrls, |
||||||
|
}, |
||||||
|
], |
||||||
|
}); |
||||||
|
|
||||||
|
await (window as any).ethereum.request({ |
||||||
|
method: 'wallet_switchEthereumChain', |
||||||
|
params: [{ chainId: chainId }], |
||||||
|
}); |
||||||
|
} catch (addError) { |
||||||
|
// handle "add" error
|
||||||
|
} |
||||||
|
} |
||||||
|
// handle other "switch" errors
|
||||||
|
}
|
||||||
|
} |
@ -1,3 +1,4 @@ |
|||||||
export * from './lib/remix-ui-helper' |
export * from './lib/remix-ui-helper' |
||||||
export * from './lib/helper-components' |
export * from './lib/helper-components' |
||||||
export * from './lib/components/PluginViewWrapper' |
export * from './lib/components/PluginViewWrapper' |
||||||
|
export * from './lib/components/custom-dropdown' |
@ -0,0 +1,42 @@ |
|||||||
|
// The forwardRef is important!!
|
||||||
|
|
||||||
|
import React, { Ref } from "react" |
||||||
|
|
||||||
|
// Dropdown needs access to the DOM node in order to position the Menu
|
||||||
|
export const CustomToggle = React.forwardRef(({ children, onClick, icon, className = '' }: { children: React.ReactNode, onClick: (e) => void, icon: string, className: string }, ref: Ref<HTMLButtonElement>) => ( |
||||||
|
<button |
||||||
|
ref={ref} |
||||||
|
onClick={(e) => { |
||||||
|
e.preventDefault() |
||||||
|
onClick(e) |
||||||
|
}} |
||||||
|
className={className.replace('dropdown-toggle', '')} |
||||||
|
> |
||||||
|
<div className="d-flex"> |
||||||
|
<div className="mr-auto">{ children }</div> |
||||||
|
{ icon && <div className="pr-1"><i className={`${icon} pr-1`}></i></div> } |
||||||
|
<div><i className="fad fa-sort-circle"></i></div> |
||||||
|
</div> |
||||||
|
</button> |
||||||
|
)) |
||||||
|
|
||||||
|
// forwardRef again here!
|
||||||
|
// Dropdown needs access to the DOM of the Menu to measure it
|
||||||
|
export const CustomMenu = React.forwardRef( |
||||||
|
({ children, style, className, 'aria-labelledby': labeledBy }: { children: React.ReactNode, style?: React.CSSProperties, className: string, 'aria-labelledby'?: string }, ref: Ref<HTMLDivElement>) => { |
||||||
|
return ( |
||||||
|
<div |
||||||
|
ref={ref} |
||||||
|
style={style} |
||||||
|
className={className} |
||||||
|
aria-labelledby={labeledBy} |
||||||
|
> |
||||||
|
<ul className="list-unstyled mb-0"> |
||||||
|
{ |
||||||
|
children |
||||||
|
} |
||||||
|
</ul> |
||||||
|
</div> |
||||||
|
) |
||||||
|
}, |
||||||
|
) |
@ -0,0 +1,81 @@ |
|||||||
|
import { CopyToClipboard } from '@remix-ui/clipboard' |
||||||
|
import React, { useEffect, useState } from 'react' |
||||||
|
import { GithubSettingsProps } from '../types' |
||||||
|
|
||||||
|
export function GithubSettings (props: GithubSettingsProps) { |
||||||
|
const [githubToken, setGithubToken] = useState<string>("") |
||||||
|
const [githubUserName, setGithubUsername] = useState<string>("") |
||||||
|
const [githubEmail, setGithubEmail] = useState<string>("") |
||||||
|
|
||||||
|
useEffect(() => { |
||||||
|
if (props.config) { |
||||||
|
const githubToken = props.config.get('settings/gist-access-token') |
||||||
|
const githubUserName = props.config.get('settings/github-user-name') |
||||||
|
const githubEmail = props.config.get('settings/github-email') |
||||||
|
|
||||||
|
setGithubToken(githubToken) |
||||||
|
setGithubUsername(githubUserName) |
||||||
|
setGithubEmail(githubEmail) |
||||||
|
} |
||||||
|
}, [props.config]) |
||||||
|
|
||||||
|
const handleChangeTokenState = (event) => { |
||||||
|
setGithubToken(event.target.value) |
||||||
|
} |
||||||
|
|
||||||
|
const handleChangeUserNameState = (event) => { |
||||||
|
setGithubUsername(event.target.value) |
||||||
|
} |
||||||
|
|
||||||
|
const handleChangeEmailState = (event) => { |
||||||
|
setGithubEmail(event.target.value) |
||||||
|
} |
||||||
|
|
||||||
|
// api key settings
|
||||||
|
const saveGithubToken = () => { |
||||||
|
props.saveTokenToast(githubToken, githubUserName, githubEmail) |
||||||
|
} |
||||||
|
|
||||||
|
const removeToken = () => { |
||||||
|
setGithubToken('') |
||||||
|
setGithubUsername('') |
||||||
|
setGithubEmail('') |
||||||
|
props.removeTokenToast() |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<div className="border-top"> |
||||||
|
<div className="card-body pt-3 pb-2"> |
||||||
|
<h6 className="card-title">GitHub Credentials</h6> |
||||||
|
<p className="mb-1">Manage your GitHub credentials used to publish to Gist and retrieve GitHub contents.</p> |
||||||
|
<p className="">Go to github token page (link below) to create a new token and save it in Remix. Make sure this token has only \'create gist\' permission.</p> |
||||||
|
<p className="mb-1"><a className="text-primary" target="_blank" href="https://github.com/settings/tokens">https://github.com/settings/tokens</a></p>
|
||||||
|
<div> |
||||||
|
<label>TOKEN:</label> |
||||||
|
<div className="input-group text-secondary mb-0 h6"> |
||||||
|
<input id="gistaccesstoken" data-id="settingsTabGistAccessToken" type="password" className="form-control" onChange={(e) => handleChangeTokenState(e)} value={ githubToken } /> |
||||||
|
<div className="input-group-append"> |
||||||
|
<CopyToClipboard content={githubToken} data-id='copyToClipboardCopyIcon' className='far fa-copy ml-1 p-2 mt-1' direction={"top"} /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div> |
||||||
|
<label>USERNAME:</label> |
||||||
|
<div className="text-secondary mb-0 h6"> |
||||||
|
<input id="githubusername" data-id="settingsTabGithubUsername" type="text" className="form-control" onChange={(e) => handleChangeUserNameState(e)} value={ githubUserName } /> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div> |
||||||
|
<label>EMAIL:</label> |
||||||
|
<div className="text-secondary mb-0 h6"> |
||||||
|
<input id="githubemail" data-id="settingsTabGithubEmail" type="text" className="form-control" onChange={(e) => handleChangeEmailState(e)} value={ githubEmail } /> |
||||||
|
<div className="d-flex justify-content-end pt-2"> |
||||||
|
<input className="btn btn-sm btn-primary ml-2" id="savegisttoken" data-id="settingsTabSaveGistToken" onClick={saveGithubToken} value="Save" type="button" disabled={githubToken === ''}></input> |
||||||
|
<button className="btn btn-sm btn-secondary ml-2" id="removegisttoken" data-id="settingsTabRemoveGistToken" title="Delete GitHub Credentials" onClick={removeToken}>Remove</button> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
) |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
export interface GithubSettingsProps { |
||||||
|
saveTokenToast: (githubToken: string, githubUserName: string, githubEmail: string) => void, |
||||||
|
removeTokenToast: () => void, |
||||||
|
config: { |
||||||
|
exists: (key: string) => boolean, |
||||||
|
get: (key: string) => string, |
||||||
|
set: (key: string, content: string) => void, |
||||||
|
clear: () => void, |
||||||
|
getUnpersistedProperty: (key: string) => void, |
||||||
|
setUnpersistedProperty: (key: string, value: string) => void |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
{ |
||||||
|
"presets": [ |
||||||
|
[ |
||||||
|
"@nrwl/react/babel", |
||||||
|
{ |
||||||
|
"runtime": "automatic", |
||||||
|
"useBuiltIns": "usage" |
||||||
|
} |
||||||
|
] |
||||||
|
], |
||||||
|
"plugins": [] |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
{ |
||||||
|
"extends": ["plugin:@nrwl/nx/react", "../../../.eslintrc.json"], |
||||||
|
"ignorePatterns": ["!**/*"], |
||||||
|
"overrides": [ |
||||||
|
{ |
||||||
|
"files": ["*.ts", "*.tsx", "*.js", "*.jsx"], |
||||||
|
"rules": {} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"files": ["*.ts", "*.tsx"], |
||||||
|
"rules": {} |
||||||
|
}, |
||||||
|
{ |
||||||
|
"files": ["*.js", "*.jsx"], |
||||||
|
"rules": {} |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
# remix-ui-tooltip-popup |
||||||
|
|
||||||
|
This library was generated with [Nx](https://nx.dev). |
||||||
|
|
||||||
|
## Running unit tests |
||||||
|
|
||||||
|
Run `nx test remix-ui-tooltip-popup` to execute the unit tests via [Jest](https://jestjs.io). |
@ -0,0 +1 @@ |
|||||||
|
export * from './lib/tooltip-popup' |
@ -0,0 +1,27 @@ |
|||||||
|
import React, { useState } from 'react' |
||||||
|
import { OverlayTrigger, Popover } from 'react-bootstrap' |
||||||
|
import { TooltipPopupProps } from '../types' |
||||||
|
import './tooltip-popup.module.css' |
||||||
|
|
||||||
|
const popover = (title?: string, content?: string | React.ReactNode) => ( |
||||||
|
<Popover id="popover-basic" className='bg-light border-secondary'> |
||||||
|
<Popover.Title as="h3" className='bg-dark border-0'>{ title || 'Tooltip' }</Popover.Title> |
||||||
|
<Popover.Content> |
||||||
|
{ content } |
||||||
|
</Popover.Content> |
||||||
|
</Popover> |
||||||
|
) |
||||||
|
|
||||||
|
export function TooltipPopup(props: TooltipPopupProps) { |
||||||
|
const [show, setShow] = useState<boolean>(false) |
||||||
|
|
||||||
|
return ( |
||||||
|
<OverlayTrigger trigger="click" placement={"bottom"} overlay={popover(props.title, props.children || props.content)} show={show} onToggle={(nextShow) => { |
||||||
|
setShow(nextShow) |
||||||
|
}}> |
||||||
|
<i className={`${props.icon} remixui_menuicon pr-0 mr-2`}></i> |
||||||
|
</OverlayTrigger> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default TooltipPopup |
@ -0,0 +1,6 @@ |
|||||||
|
export interface TooltipPopupProps { |
||||||
|
children?: React.ReactNode, |
||||||
|
title?: string, |
||||||
|
content?: string, |
||||||
|
icon: string |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
{ |
||||||
|
"extends": "../../../tsconfig.base.json", |
||||||
|
"compilerOptions": { |
||||||
|
"jsx": "react-jsx", |
||||||
|
"allowJs": true, |
||||||
|
"esModuleInterop": true, |
||||||
|
"allowSyntheticDefaultImports": true, |
||||||
|
"forceConsistentCasingInFileNames": true, |
||||||
|
"strict": true, |
||||||
|
"noImplicitReturns": true, |
||||||
|
"noFallthroughCasesInSwitch": true |
||||||
|
}, |
||||||
|
"files": [], |
||||||
|
"include": [], |
||||||
|
"references": [ |
||||||
|
{ |
||||||
|
"path": "./tsconfig.lib.json" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
{ |
||||||
|
"extends": "./tsconfig.json", |
||||||
|
"compilerOptions": { |
||||||
|
"outDir": "../../../dist/out-tsc", |
||||||
|
"types": ["node"] |
||||||
|
}, |
||||||
|
"files": [ |
||||||
|
"../../../node_modules/@nrwl/react/typings/cssmodule.d.ts", |
||||||
|
"../../../node_modules/@nrwl/react/typings/image.d.ts" |
||||||
|
], |
||||||
|
"exclude": ["**/*.spec.ts", "**/*.spec.tsx"], |
||||||
|
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"] |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue