Skip to content

Commit 817089a

Browse files
authored
Merge pull request #4526 from ethereum/vyperui-updates
Vyper plugin UI Updates
2 parents 64fdcca + 7b12932 commit 817089a

File tree

7 files changed

+207
-48
lines changed

7 files changed

+207
-48
lines changed

apps/vyper/src/app/app.css

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,3 +113,112 @@ html, body, #root, main {
113113
height: 100%;
114114
width: 100%;
115115
}
116+
117+
118+
119+
.remixui_copyButton {
120+
padding: 6px;
121+
font-weight: bold;
122+
font-size: 11px;
123+
line-height: 15px;
124+
}
125+
126+
.remixui_contractHelperButtons {
127+
margin-top: 6px;
128+
display: flex;
129+
align-items: center;
130+
justify-content: space-between;
131+
float: right;
132+
}
133+
.remixui_copyToClipboard {
134+
font-size: 1rem;
135+
}
136+
.remixui_copyIcon {
137+
margin-right: 5px;
138+
}
139+
.remixui_log {
140+
display: flex;
141+
flex-direction: column;
142+
margin-bottom: 0.5rem;
143+
overflow: visible;
144+
}
145+
.remixui_key {
146+
margin-right: 5px;
147+
text-transform: uppercase;
148+
width: 100%;
149+
}
150+
.remixui_value {
151+
display: flex;
152+
width: 100%;
153+
margin-top: 1.5%;
154+
}
155+
.remixui_questionMark {
156+
margin-left: 2%;
157+
cursor: pointer;
158+
}
159+
160+
@keyframes spin {
161+
0% { transform: rotate(0deg); }
162+
100% { transform: rotate(360deg); }
163+
}
164+
@-webkit-keyframes spin {
165+
0% { transform: rotate(0deg); }
166+
100% { transform: rotate(360deg); }
167+
}
168+
@-moz-keyframes spin {
169+
0% { transform: rotate(0deg); }
170+
100% { transform: rotate(360deg); }
171+
}
172+
@-o-keyframes spin {
173+
0% { transform: rotate(0deg); }
174+
100% { transform: rotate(360deg); }
175+
}
176+
@-ms-keyframes spin {
177+
0% { transform: rotate(0deg); }
178+
100% { transform: rotate(360deg); }
179+
}
180+
181+
.remixui_bouncingIcon {
182+
display: inline-block;
183+
position: relative;
184+
-moz-animation: bounce 2s infinite linear;
185+
-o-animation: bounce 2s infinite linear;
186+
-webkit-animation: bounce 2s infinite linear;
187+
animation: bounce 2s infinite linear;
188+
}
189+
190+
@-webkit-keyframes bounce {
191+
0% { top: 0; }
192+
50% { top: -0.2em; }
193+
70% { top: -0.3em; }
194+
100% { top: 0; }
195+
}
196+
@-moz-keyframes bounce {
197+
0% { top: 0; }
198+
50% { top: -0.2em; }
199+
70% { top: -0.3em; }
200+
100% { top: 0; }
201+
}
202+
@-o-keyframes bounce {
203+
0% { top: 0; }
204+
50% { top: -0.2em; }
205+
70% { top: -0.3em; }
206+
100% { top: 0; }
207+
}
208+
@-ms-keyframes bounce {
209+
0% { top: 0; }
210+
50% { top: -0.2em; }
211+
70% { top: -0.3em; }
212+
100% { top: 0; }
213+
}
214+
@keyframes bounce {
215+
0% { top: 0; }
216+
50% { top: -0.2em; }
217+
70% { top: -0.3em; }
218+
100% { top: 0; }
219+
}
220+
221+
#compileDetails {
222+
margin: 15px;
223+
padding: 15px;
224+
}

apps/vyper/src/app/app.tsx

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import ToggleButton from 'react-bootstrap/ToggleButton'
1313
import Button from 'react-bootstrap/Button'
1414

1515
import './app.css'
16-
import { CustomTooltip } from '@remix-ui/helper'
16+
import {CustomTooltip} from '@remix-ui/helper'
17+
import {Form} from 'react-bootstrap'
18+
import {CompileErrorCard} from './components/CompileErrorCard'
1719

1820
interface AppState {
1921
status: 'idle' | 'inProgress'
@@ -32,10 +34,9 @@ const App = () => {
3234
const [state, setState] = useState<AppState>({
3335
status: 'idle',
3436
environment: 'remote',
35-
localUrl: 'http://localhost:8000/'
37+
localUrl: 'http://localhost:8000/',
3638
})
3739

38-
3940
useEffect(() => {
4041
async function start() {
4142
try {
@@ -67,6 +68,9 @@ const App = () => {
6768

6869
useEffect(() => {
6970
remixClient.eventEmitter.on('setOutput', (payload) => {
71+
if (payload.status === 'failed') {
72+
console.error('Error in the compiler', payload)
73+
}
7074
setOutput(payload)
7175
})
7276

@@ -96,43 +100,43 @@ const App = () => {
96100

97101
return (
98102
<main id="vyper-plugin">
103+
<header>
104+
<div className="title">
105+
<img src={'assets/vyperLogo_v2.webp'} alt="Vyper logo" />
106+
<h4 className="pl-1">yper Compiler</h4>
107+
</div>
108+
<a rel="noopener noreferrer" href="https://github.com/ethereum/remix-project/tree/master/apps/vyper" target="_blank">
109+
<i className="fab fa-github"></i>
110+
</a>
111+
</header>
99112
<section>
100113
<div className="px-3 pt-3 mb-3 w-100">
101-
<CustomTooltip
102-
placement="bottom"
103-
tooltipText="Clone Vyper examples. Switch to the File Explorer to see the examples."
104-
>
105-
<Button data-id="add-repository" className="w-100 text-dark bg-light btn-outline-primary " onClick={() => remixClient.cloneVyperRepo()}>
106-
Clone Vyper examples repository
114+
<CustomTooltip placement="bottom" tooltipText="Clone Vyper examples. Switch to the File Explorer to see the examples.">
115+
<Button data-id="add-repository" className="w-100 btn btn-secondary" onClick={() => remixClient.cloneVyperRepo()}>
116+
Clone Vyper examples repository
107117
</Button>
108118
</CustomTooltip>
109119
</div>
110-
<ToggleButtonGroup name="remote" className="mb-3" onChange={setEnvironment} type="radio" value={state.environment}>
111-
<ToggleButton data-id="remote-compiler" variant="secondary" name="remote" value="remote">
112-
Remote Compiler
113-
</ToggleButton>
114-
<ToggleButton id="local-compiler" data-id="local-compiler" variant="secondary" name="local" value="local">
115-
Local Compiler
116-
</ToggleButton>
117-
</ToggleButtonGroup>
120+
<Form>
121+
<div className="d-flex flex-row gap-5 mb-3 mt-2">
122+
<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" />
123+
<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'}} />
124+
</div>
125+
</Form>
126+
<span className="px-3 mt-1 mb-1 small text-warning">Specify the compiler version & EVM version in the .vy file</span>
118127
<LocalUrlInput url={state.localUrl} setUrl={setLocalUrl} environment={state.environment} />
119128
<div className="px-3 w-100 mb-3 mt-1" id="compile-btn">
120-
<CompilerButton
121-
compilerUrl={compilerUrl()}
122-
contract={contract}
123-
setOutput={(name, update) => setOutput({...output, [name]: update})}
124-
resetCompilerState={resetCompilerResultState}
125-
/>
129+
<CompilerButton compilerUrl={compilerUrl()} contract={contract} setOutput={(name, update) => setOutput({...output, [name]: update})} resetCompilerState={resetCompilerResultState} />
126130
</div>
127131

128132
<article id="result" className="px-2 mx-2 border-top mt-3">
129-
{
130-
output && Object.keys(output).length > 0 && output.status !== 'failed' ? (
131-
<>
132-
<VyperResult output={output} plugin={remixClient} />
133-
</>
134-
) : null
135-
}
133+
{output && Object.keys(output).length > 0 && output.status !== 'failed' ? (
134+
<>
135+
<VyperResult output={output} plugin={remixClient} />
136+
</>
137+
) : output.status === 'failed' ? (
138+
<CompileErrorCard output={output} />
139+
) : null}
136140
</article>
137141
</section>
138142
</main>
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import Reaact from 'react'
2+
3+
export function CompileErrorCard(props: any) {
4+
return (
5+
<div id="vyperErrorResult" className="px-2 mx-3 alert alert-danger error" title={props.output.message}>
6+
<i className="fas fa-exclamation-circle text-danger"></i>
7+
<span
8+
data-id="error-message"
9+
className="text-center"
10+
style={{
11+
overflowX: 'hidden',
12+
textOverflow: 'ellipsis',
13+
}}
14+
>
15+
{props.output.message.trim()}
16+
</span>
17+
</div>
18+
)
19+
}

apps/vyper/src/app/components/VyperResult.tsx

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
import React, {useState} from 'react'
2-
import {VyperCompilationOutput, isCompilationError} from '../utils'
3-
import Tabs from 'react-bootstrap/Tabs'
4-
import Tab from 'react-bootstrap/Tab'
5-
import Button from 'react-bootstrap/Button'
2+
import {isCompilationError} from '../utils'
63
import {CopyToClipboard} from '@remix-ui/clipboard'
7-
import { VyperCompilationResult } from '../utils/types'
84

95
interface VyperResultProps {
106
output?: any
117
plugin?: any
128
}
139

10+
export type OutputType = {
11+
contractName: string
12+
abi: any
13+
bytecode: any
14+
runtimeBytecode: any
15+
ir: string
16+
methodIdentifiers: any
17+
}
18+
1419
export type ExampleContract = {
1520
name: string
1621
address: string
@@ -24,7 +29,6 @@ type TabContentMembers = {
2429
}
2530

2631
function VyperResult({ output, plugin }: VyperResultProps) {
27-
// const [active, setActive] = useState<keyof VyperCompilationResult>('abi')
2832

2933
if (!output)
3034
return (
@@ -51,15 +55,34 @@ function VyperResult({ output, plugin }: VyperResultProps) {
5155
</div>
5256
)
5357
}
58+
5459
return (
5560
<>
5661
<div className="border border-top"></div>
57-
<div className="d-flex justify-content-center px-2 w-100">
62+
<div className="d-flex justify-content-center px-2 w-100 flex-column border border-bottom">
5863
<button data-id="compilation-details" className="btn btn-secondary w-100" onClick={async () => {
5964
await plugin?.call('vyperCompilationDetails', 'showDetails', output)
6065
}}>
6166
<span>Compilation Details</span>
6267
</button>
68+
<div className="mt-1">
69+
<div className="input-group input-group mt-3 d-flex flex-row-reverse">
70+
<div className="btn-group align-self-start" role="group" aria-label="Copy to Clipboard">
71+
<CopyToClipboard tip={'Copy ABI to clipboard'} getContent={() => (Object.values(output)[0] as OutputType).abi} direction="bottom" icon="far fa-copy">
72+
<button className="btn remixui_copyButton">
73+
<i className="remixui_copyIcon far fa-copy" aria-hidden="true"></i>
74+
<span>ABI</span>
75+
</button>
76+
</CopyToClipboard>
77+
<CopyToClipboard tip={'Copy Bytecode to clipboard'} getContent={() => (Object.values(output)[0] as OutputType).bytecode.object} direction="bottom" icon="far fa-copy">
78+
<button className="btn remixui_copyButton">
79+
<i className="remixui_copyIcon far fa-copy" aria-hidden="true"></i>
80+
<span>Bytecode</span>
81+
</button>
82+
</CopyToClipboard>
83+
</div>
84+
</div>
85+
</div>
6386
</div>
6487
</>
6588
)

apps/vyper/src/app/utils/compiler.tsx

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -181,16 +181,15 @@ export async function compileContract(contract: string, compilerUrl: string, set
181181
try {
182182
_contract = await remixClient.getContract()
183183
} catch (e: any) {
184-
if (setOutput === null || setOutput === undefined) {
185-
const compileResult = {
186-
status: 'failed',
187-
message: e.message
188-
}
189-
const compileResultKey = ''
190-
remixClient.eventEmitter.emit('setOutput', { compileResultKey, compileResult })
191-
} else {
192-
setOutput('', {status: 'failed', message: e.message})
184+
// if (setOutput === null || setOutput === undefined) {
185+
const compileResult = {
186+
status: 'failed',
187+
message: e.message
193188
}
189+
remixClient.eventEmitter.emit('setOutput', compileResult)
190+
// } else {
191+
// setOutput('', {status: 'failed', message: e.message})
192+
// }
194193
return
195194
}
196195
remixClient.changeStatus({
@@ -201,12 +200,16 @@ export async function compileContract(contract: string, compilerUrl: string, set
201200
let output
202201
try {
203202
output = await compile(compilerUrl, _contract)
203+
console.log('checking compile result', output)
204+
remixClient.eventEmitter.emit('setOutput', output)
204205
} catch (e: any) {
205206
remixClient.changeStatus({
206207
key: 'failed',
207208
type: 'error',
208-
title: e.message
209+
title: `${e.message} debugging`
209210
})
211+
// setOutput !== null || setOutput !== undefined && setOutput('', {status: 'failed', message: e.message})
212+
remixClient.eventEmitter.emit('setOutput', {status: 'failed', message: e.message})
210213
return
211214
}
212215
const compileReturnType = () => {
@@ -288,6 +291,7 @@ export async function compileContract(contract: string, compilerUrl: string, set
288291
type: 'error',
289292
title: err.message
290293
})
294+
remixClient.eventEmitter.emit('setOutput', {status: 'failed', message: err.message})
291295
}
292296
}
293297

2.5 KB
Loading

apps/vyper/src/profile.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vyper",
3-
"displayName": "Vyper Plugin",
3+
"displayName": "Vyper",
44
"methods": ["getCompilationResult", "compile", "vyperCompileCustomAction"],
55
"url": "https://ipfs-cluster.ethdevops.io/ipfs/QmbmPzUg7ghTKcF2eo64zm1k1LKdibYfqYmiqXkHKXks8r",
66
"documentation": "https://remix-ide.readthedocs.io/en/latest/plugin_list.html",

0 commit comments

Comments
 (0)