Merge pull request #4526 from ethereum/vyperui-updates

Vyper plugin UI Updates
pull/4532/head
yann300 9 months ago committed by GitHub
commit 817089ab1f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 109
      apps/vyper/src/app/app.css
  2. 64
      apps/vyper/src/app/app.tsx
  3. 19
      apps/vyper/src/app/components/CompileErrorCard.tsx
  4. 37
      apps/vyper/src/app/components/VyperResult.tsx
  5. 24
      apps/vyper/src/app/utils/compiler.tsx
  6. BIN
      apps/vyper/src/assets/vyperLogo_v2.webp
  7. 2
      apps/vyper/src/profile.json

@ -113,3 +113,112 @@ html, body, #root, main {
height: 100%;
width: 100%;
}
.remixui_copyButton {
padding: 6px;
font-weight: bold;
font-size: 11px;
line-height: 15px;
}
.remixui_contractHelperButtons {
margin-top: 6px;
display: flex;
align-items: center;
justify-content: space-between;
float: right;
}
.remixui_copyToClipboard {
font-size: 1rem;
}
.remixui_copyIcon {
margin-right: 5px;
}
.remixui_log {
display: flex;
flex-direction: column;
margin-bottom: 0.5rem;
overflow: visible;
}
.remixui_key {
margin-right: 5px;
text-transform: uppercase;
width: 100%;
}
.remixui_value {
display: flex;
width: 100%;
margin-top: 1.5%;
}
.remixui_questionMark {
margin-left: 2%;
cursor: pointer;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@-webkit-keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@-moz-keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@-o-keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
@-ms-keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.remixui_bouncingIcon {
display: inline-block;
position: relative;
-moz-animation: bounce 2s infinite linear;
-o-animation: bounce 2s infinite linear;
-webkit-animation: bounce 2s infinite linear;
animation: bounce 2s infinite linear;
}
@-webkit-keyframes bounce {
0% { top: 0; }
50% { top: -0.2em; }
70% { top: -0.3em; }
100% { top: 0; }
}
@-moz-keyframes bounce {
0% { top: 0; }
50% { top: -0.2em; }
70% { top: -0.3em; }
100% { top: 0; }
}
@-o-keyframes bounce {
0% { top: 0; }
50% { top: -0.2em; }
70% { top: -0.3em; }
100% { top: 0; }
}
@-ms-keyframes bounce {
0% { top: 0; }
50% { top: -0.2em; }
70% { top: -0.3em; }
100% { top: 0; }
}
@keyframes bounce {
0% { top: 0; }
50% { top: -0.2em; }
70% { top: -0.3em; }
100% { top: 0; }
}
#compileDetails {
margin: 15px;
padding: 15px;
}

@ -13,7 +13,9 @@ import ToggleButton from 'react-bootstrap/ToggleButton'
import Button from 'react-bootstrap/Button'
import './app.css'
import { CustomTooltip } from '@remix-ui/helper'
import {CustomTooltip} from '@remix-ui/helper'
import {Form} from 'react-bootstrap'
import {CompileErrorCard} from './components/CompileErrorCard'
interface AppState {
status: 'idle' | 'inProgress'
@ -32,10 +34,9 @@ const App = () => {
const [state, setState] = useState<AppState>({
status: 'idle',
environment: 'remote',
localUrl: 'http://localhost:8000/'
localUrl: 'http://localhost:8000/',
})
useEffect(() => {
async function start() {
try {
@ -67,6 +68,9 @@ const App = () => {
useEffect(() => {
remixClient.eventEmitter.on('setOutput', (payload) => {
if (payload.status === 'failed') {
console.error('Error in the compiler', payload)
}
setOutput(payload)
})
@ -96,43 +100,43 @@ const App = () => {
return (
<main id="vyper-plugin">
<header>
<div className="title">
<img src={'assets/vyperLogo_v2.webp'} alt="Vyper logo" />
<h4 className="pl-1">yper Compiler</h4>
</div>
<a rel="noopener noreferrer" href="https://github.com/ethereum/remix-project/tree/master/apps/vyper" target="_blank">
<i className="fab fa-github"></i>
</a>
</header>
<section>
<div className="px-3 pt-3 mb-3 w-100">
<CustomTooltip
placement="bottom"
tooltipText="Clone Vyper examples. Switch to the File Explorer to see the examples."
>
<Button data-id="add-repository" className="w-100 text-dark bg-light btn-outline-primary " onClick={() => remixClient.cloneVyperRepo()}>
Clone Vyper examples repository
<CustomTooltip placement="bottom" tooltipText="Clone Vyper examples. Switch to the File Explorer to see the examples.">
<Button data-id="add-repository" className="w-100 btn btn-secondary" onClick={() => remixClient.cloneVyperRepo()}>
Clone Vyper examples repository
</Button>
</CustomTooltip>
</div>
<ToggleButtonGroup name="remote" className="mb-3" onChange={setEnvironment} type="radio" value={state.environment}>
<ToggleButton data-id="remote-compiler" variant="secondary" name="remote" value="remote">
Remote Compiler
</ToggleButton>
<ToggleButton id="local-compiler" data-id="local-compiler" variant="secondary" name="local" value="local">
Local Compiler
</ToggleButton>
</ToggleButtonGroup>
<Form>
<div className="d-flex flex-row gap-5 mb-3 mt-2">
<Form.Check inline data-id="remote-compiler" type="radio" value={state.environment} checked={state.environment === 'remote'} onChange={() => setEnvironment('remote')} label="Remote Compiler" style={{cursor: state.environment === 'remote' ? 'default' : 'pointer'}} className="d-flex mr-4" />
<Form.Check inline id="local-compiler" data-id="local-compiler" checked={state.environment === 'local'} type="radio" name="local" value={state.environment} onChange={() => setEnvironment('local')} label="Local Compiler" style={{cursor: state.environment === 'local' ? 'default' : 'pointer'}} />
</div>
</Form>
<span className="px-3 mt-1 mb-1 small text-warning">Specify the compiler version & EVM version in the .vy file</span>
<LocalUrlInput url={state.localUrl} setUrl={setLocalUrl} environment={state.environment} />
<div className="px-3 w-100 mb-3 mt-1" id="compile-btn">
<CompilerButton
compilerUrl={compilerUrl()}
contract={contract}
setOutput={(name, update) => setOutput({...output, [name]: update})}
resetCompilerState={resetCompilerResultState}
/>
<CompilerButton compilerUrl={compilerUrl()} contract={contract} setOutput={(name, update) => setOutput({...output, [name]: update})} resetCompilerState={resetCompilerResultState} />
</div>
<article id="result" className="px-2 mx-2 border-top mt-3">
{
output && Object.keys(output).length > 0 && output.status !== 'failed' ? (
<>
<VyperResult output={output} plugin={remixClient} />
</>
) : null
}
{output && Object.keys(output).length > 0 && output.status !== 'failed' ? (
<>
<VyperResult output={output} plugin={remixClient} />
</>
) : output.status === 'failed' ? (
<CompileErrorCard output={output} />
) : null}
</article>
</section>
</main>

@ -0,0 +1,19 @@
import Reaact from 'react'
export function CompileErrorCard(props: any) {
return (
<div id="vyperErrorResult" className="px-2 mx-3 alert alert-danger error" title={props.output.message}>
<i className="fas fa-exclamation-circle text-danger"></i>
<span
data-id="error-message"
className="text-center"
style={{
overflowX: 'hidden',
textOverflow: 'ellipsis',
}}
>
{props.output.message.trim()}
</span>
</div>
)
}

@ -1,16 +1,21 @@
import React, {useState} from 'react'
import {VyperCompilationOutput, isCompilationError} from '../utils'
import Tabs from 'react-bootstrap/Tabs'
import Tab from 'react-bootstrap/Tab'
import Button from 'react-bootstrap/Button'
import {isCompilationError} from '../utils'
import {CopyToClipboard} from '@remix-ui/clipboard'
import { VyperCompilationResult } from '../utils/types'
interface VyperResultProps {
output?: any
plugin?: any
}
export type OutputType = {
contractName: string
abi: any
bytecode: any
runtimeBytecode: any
ir: string
methodIdentifiers: any
}
export type ExampleContract = {
name: string
address: string
@ -24,7 +29,6 @@ type TabContentMembers = {
}
function VyperResult({ output, plugin }: VyperResultProps) {
// const [active, setActive] = useState<keyof VyperCompilationResult>('abi')
if (!output)
return (
@ -51,15 +55,34 @@ function VyperResult({ output, plugin }: VyperResultProps) {
</div>
)
}
return (
<>
<div className="border border-top"></div>
<div className="d-flex justify-content-center px-2 w-100">
<div className="d-flex justify-content-center px-2 w-100 flex-column border border-bottom">
<button data-id="compilation-details" className="btn btn-secondary w-100" onClick={async () => {
await plugin?.call('vyperCompilationDetails', 'showDetails', output)
}}>
<span>Compilation Details</span>
</button>
<div className="mt-1">
<div className="input-group input-group mt-3 d-flex flex-row-reverse">
<div className="btn-group align-self-start" role="group" aria-label="Copy to Clipboard">
<CopyToClipboard tip={'Copy ABI to clipboard'} getContent={() => (Object.values(output)[0] as OutputType).abi} direction="bottom" icon="far fa-copy">
<button className="btn remixui_copyButton">
<i className="remixui_copyIcon far fa-copy" aria-hidden="true"></i>
<span>ABI</span>
</button>
</CopyToClipboard>
<CopyToClipboard tip={'Copy Bytecode to clipboard'} getContent={() => (Object.values(output)[0] as OutputType).bytecode.object} direction="bottom" icon="far fa-copy">
<button className="btn remixui_copyButton">
<i className="remixui_copyIcon far fa-copy" aria-hidden="true"></i>
<span>Bytecode</span>
</button>
</CopyToClipboard>
</div>
</div>
</div>
</div>
</>
)

@ -181,16 +181,15 @@ export async function compileContract(contract: string, compilerUrl: string, set
try {
_contract = await remixClient.getContract()
} catch (e: any) {
if (setOutput === null || setOutput === undefined) {
const compileResult = {
status: 'failed',
message: e.message
}
const compileResultKey = ''
remixClient.eventEmitter.emit('setOutput', { compileResultKey, compileResult })
} else {
setOutput('', {status: 'failed', message: e.message})
// if (setOutput === null || setOutput === undefined) {
const compileResult = {
status: 'failed',
message: e.message
}
remixClient.eventEmitter.emit('setOutput', compileResult)
// } else {
// setOutput('', {status: 'failed', message: e.message})
// }
return
}
remixClient.changeStatus({
@ -201,12 +200,16 @@ export async function compileContract(contract: string, compilerUrl: string, set
let output
try {
output = await compile(compilerUrl, _contract)
console.log('checking compile result', output)
remixClient.eventEmitter.emit('setOutput', output)
} catch (e: any) {
remixClient.changeStatus({
key: 'failed',
type: 'error',
title: e.message
title: `${e.message} debugging`
})
// setOutput !== null || setOutput !== undefined && setOutput('', {status: 'failed', message: e.message})
remixClient.eventEmitter.emit('setOutput', {status: 'failed', message: e.message})
return
}
const compileReturnType = () => {
@ -288,6 +291,7 @@ export async function compileContract(contract: string, compilerUrl: string, set
type: 'error',
title: err.message
})
remixClient.eventEmitter.emit('setOutput', {status: 'failed', message: err.message})
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

@ -1,6 +1,6 @@
{
"name": "vyper",
"displayName": "Vyper Plugin",
"displayName": "Vyper",
"methods": ["getCompilationResult", "compile", "vyperCompileCustomAction"],
"url": "https://ipfs-cluster.ethdevops.io/ipfs/QmbmPzUg7ghTKcF2eo64zm1k1LKdibYfqYmiqXkHKXks8r",
"documentation": "https://remix-ide.readthedocs.io/en/latest/plugin_list.html",

Loading…
Cancel
Save