commit
4224f21dfa
@ -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/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