Show warnings and add new icon

noir
ioedeveloper 3 weeks ago
parent b6a69db0d7
commit 1f1ba79db9
  1. 26
      apps/circuit-compiler/src/app/components/container.tsx
  2. 72
      apps/circuit-compiler/src/app/components/feedback.tsx
  3. 32
      apps/circuit-compiler/src/app/components/feedbackAlert.tsx
  4. 4
      apps/circuit-compiler/src/app/services/circomPluginClient.ts
  5. 29
      apps/circuit-compiler/src/app/types/index.ts
  6. 14
      apps/noir-compiler/src/app/actions/index.ts
  7. 18
      apps/noir-compiler/src/app/app.tsx
  8. 95
      apps/noir-compiler/src/app/components/container.tsx
  9. 15
      apps/noir-compiler/src/app/reducers/state.ts
  10. 24
      apps/noir-compiler/src/app/services/noirPluginClient.ts
  11. 7
      apps/noir-compiler/src/app/types/index.ts
  12. 2
      apps/noir-compiler/src/profile.json
  13. BIN
      apps/remix-ide/src/assets/img/noir-icon.webp
  14. 4
      libs/remix-ui/helper/src/index.ts
  15. 20
      libs/remix-ui/helper/src/lib/components/feedback.tsx
  16. 8
      libs/remix-ui/helper/src/lib/components/feedbackAlert.tsx
  17. 28
      libs/remix-ui/helper/src/types/compilerTypes.ts

@ -2,13 +2,13 @@ import { useContext } from 'react'
import { CompileBtn, CustomTooltip, RenderIf } from '@remix-ui/helper'
import { FormattedMessage } from 'react-intl'
import { CircuitAppContext } from '../contexts'
import { CompileOptions } from '@remix-ui/helper'
import { CompileOptions, CompilerReport } from '@remix-ui/helper'
import { VersionList } from './versions'
import { Toggler } from './toggler'
import { Configurations } from './configurations'
import { WitnessSection } from './witness'
import { CompilerFeedback } from './feedback'
import { CompilerReport, PrimeValue } from '../types'
import { CompilerFeedback } from '@remix-ui/helper'
import { PrimeValue } from '../types'
import { SetupExports } from './setupExports'
import { GenerateProof } from './generateProof'
import { compileCircuit } from '../actions'
@ -34,15 +34,19 @@ export function Container () {
circuitApp.dispatch({ type: 'SET_COMPILER_VERSION', payload: version })
}
const handleOpenErrorLocation = async (location: string, startRange: string) => {
if (location) {
const fullPathLocation = await circuitApp.plugin.resolveReportPath(location)
const handleOpenErrorLocation = async (report: CompilerReport) => {
if (report.labels.length > 0) {
const location = circuitApp.appState.filePathToId[report.labels[0].file_id]
const startRange = report.labels[0].range.start
if (location) {
const fullPathLocation = await circuitApp.plugin.resolveReportPath(location)
await circuitApp.plugin.call('fileManager', 'open', fullPathLocation)
// @ts-ignore
const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange)
// @ts-ignore
await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column)
await circuitApp.plugin.call('fileManager', 'open', fullPathLocation)
// @ts-ignore
const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange)
// @ts-ignore
await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column)
}
}
}

@ -1,72 +0,0 @@
import { useState } from 'react'
import { CompilerFeedbackProps, CompilerReport } from '../types'
import { RenderIf } from '@remix-ui/helper'
import { CopyToClipboard } from '@remix-ui/clipboard'
import { FeedbackAlert } from './feedbackAlert'
export function CompilerFeedback ({ feedback, filePathToId, hideWarnings, openErrorLocation, askGPT }: CompilerFeedbackProps) {
const [showException, setShowException] = useState<boolean>(true)
const handleCloseException = () => {
setShowException(false)
}
const handleOpenError = (report: CompilerReport) => {
if (report.labels.length > 0) {
openErrorLocation(filePathToId[report.labels[0].file_id], report.labels[0].range.start)
}
}
const handleAskGPT = (report: CompilerReport) => {
askGPT(report)
}
return (
<div>
{
(feedback && typeof feedback === 'string') || (Array.isArray(feedback) && feedback.length > 0) ? (
<div className="circuit_errors_box">
<RenderIf condition={ (typeof feedback === "string") && showException }>
<div className="circuit_feedback error alert alert-danger" data-id="circuit_feedback">
<span> <>{ feedback }</> </span>
<div className="close" data-id="renderer" onClick={handleCloseException}>
<i className="fas fa-times"></i>
</div>
<div className="d-flex pt-1 flex-row-reverse">
<span className="ml-3 pt-1 py-1" >
<CopyToClipboard content={feedback} className="p-0 m-0 far fa-copy error" direction={'top'} />
</span>
</div>
</div>
</RenderIf>
<RenderIf condition={ Array.isArray(feedback) }>
<>
{
Array.isArray(feedback) && feedback.map((response, index) => (
<div key={index} onClick={() => handleOpenError(response)}>
<RenderIf condition={response.type === 'Error'}>
<div className={`circuit_feedback ${response.type.toLowerCase()} alert alert-danger`} data-id="circuit_feedback">
<FeedbackAlert
message={response.message + (response.labels[0] ? ": " + response.labels[0].message + ` ${filePathToId[response.labels[0].file_id]}:${response.labels[0].range.start}:${response.labels[0].range.end}` : '')}
askGPT={ () => handleAskGPT(response) } />
</div>
</RenderIf>
<RenderIf condition={(response.type === 'Warning') && !hideWarnings}>
<div className={`circuit_feedback ${response.type.toLowerCase()} alert alert-warning`} data-id="circuit_feedback">
<FeedbackAlert
message={response.message}
askGPT={() => { handleAskGPT(response) }} />
</div>
</RenderIf>
</div>
)
)
}
</>
</RenderIf>
</div>
) : <></>
}
</div>
)
}

@ -1,32 +0,0 @@
import { useState } from 'react'
import { FeedbackAlertProps } from '../types'
import { RenderIf } from '@remix-ui/helper'
import {CopyToClipboard} from '@remix-ui/clipboard'
export function FeedbackAlert ({ message, askGPT }: FeedbackAlertProps) {
const [ showAlert, setShowAlert] = useState<boolean>(true)
const handleCloseAlert = () => {
setShowAlert(false)
}
return (
<RenderIf condition={showAlert}>
<>
<span> { message } </span>
<div className="close" data-id="renderer" onClick={handleCloseAlert}>
<i className="fas fa-times"></i>
</div>
<div className="d-flex pt-1 flex-row-reverse">
<span className="ml-3 pt-1 py-1" >
<CopyToClipboard content={message} className="p-0 m-0 far fa-copy error" direction={'top'} />
</span>
<span className="border border-success text-success btn-sm" onClick={(e) => {
e.stopPropagation()
askGPT()
}}>Ask RemixAI</span>
</div>
</>
</RenderIf>
)
}

@ -7,8 +7,8 @@ import * as compilerV218 from 'circom_wasm/v2.1.8'
import * as compilerV217 from 'circom_wasm/v2.1.7'
import * as compilerV216 from 'circom_wasm/v2.1.6'
import * as compilerV215 from 'circom_wasm/v2.1.5'
import { extractNameFromKey, extractParentFromKey } from '@remix-ui/helper'
import { CompilationConfig, CompilerReport, PrimeValue } from '../types'
import { extractNameFromKey, extractParentFromKey, CompilerReport } from '@remix-ui/helper'
import { CompilationConfig, PrimeValue } from '../types'
import isElectron from 'is-electron'
export class CircomPluginClient extends PluginClient {

@ -1,6 +1,7 @@
import { compiler_list } from 'circom_wasm'
import { Dispatch } from 'react'
import type { CircomPluginClient } from '../services/circomPluginClient'
import { CompilerReport } from '@remix-ui/helper'
export type CompilerStatus = "compiling" | "computing" | "idle" | "errored" | "warning" | "exporting" | "proving"
@ -87,34 +88,6 @@ export type CompilationConfig = {
export type PrimeValue = "bn128" | "bls12381" | "goldilocks" | "grumpkin" | "pallas" | "vesta"
export type CompilerFeedbackProps = {
feedback: string | CompilerReport[],
filePathToId: Record<string, string>,
openErrorLocation: (location: string, startRange: string) => void,
hideWarnings: boolean,
askGPT: (report: CompilerReport) => void
}
export type CompilerReport = {
type: "Error" | "Bug" | "Help" | "Note" | "Warning" | "Unknown",
message: string,
labels: {
style: "Primary" | "Secondary" | "Unknown",
file_id: string,
range: {
start: string,
end: string
},
message: string
}[],
notes: string[]
}
export type FeedbackAlertProps = {
message: string,
askGPT: () => void
}
export type ConfigurationsProps = {
setPrimeValue: (prime: PrimeValue) => void,
primeValue: PrimeValue,

@ -2,15 +2,9 @@ import { NoirPluginClient } from "../services/noirPluginClient"
import { AppState } from "../types"
export const compileNoirCircuit = async (plugin: NoirPluginClient, appState: AppState) => {
try {
if (appState.status !== "compiling") {
await plugin.compile(appState.filePath)
} else {
console.log('Existing noir compilation in progress')
}
} catch (e) {
plugin.emit('statusChanged', { key: 'error', title: e.message, type: 'error' })
plugin.internalEvents.emit('noir_compiling_errored', e)
console.error(e)
if (appState.status !== "compiling") {
await plugin.compile(appState.filePath)
} else {
console.log('Existing noir compilation in progress')
}
}

@ -37,6 +37,13 @@ function App() {
// plugin.parse(path, content)
// }
})
// noir compiling events
plugin.internalEvents.on('noir_compiling_start', () => dispatch({ type: 'SET_COMPILER_STATUS', payload: 'compiling' }))
plugin.internalEvents.on('noir_compiling_done', () => {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'idle' })
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: null })
})
plugin.internalEvents.on('noir_compiling_errored', noirCompilerErrored)
setIsPluginActivated(true)
})
}, [])
@ -47,6 +54,17 @@ function App() {
}
}, [isPluginActivated])
const noirCompilerErrored = (err: ErrorEvent) => {
dispatch({ type: 'SET_COMPILER_STATUS', payload: 'errored' })
try {
const report = JSON.parse(err.message)
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: report })
} catch (e) {
dispatch({ type: 'SET_COMPILER_FEEDBACK', payload: err.message })
}
}
const setCurrentLocale = async () => {
// @ts-ignore
const currentLocale = await plugin.call('locale', 'currentLocale')

@ -1,5 +1,5 @@
import { useContext } from 'react'
import { CompileBtn, CustomTooltip, RenderIf } from '@remix-ui/helper'
import { CompileBtn, CompilerFeedback, CompilerReport, CustomTooltip, RenderIf } from '@remix-ui/helper'
import { FormattedMessage } from 'react-intl'
import { NoirAppContext } from '../contexts'
import { CompileOptions } from '@remix-ui/helper'
@ -21,15 +21,20 @@ export function Container () {
}
}
const handleOpenErrorLocation = async (location: string, startRange: string) => {
if (location) {
const fullPathLocation = await circuitApp.plugin.resolveReportPath(location)
const handleOpenErrorLocation = async (report: CompilerReport) => {
if (report.labels.length > 0) {
// const location = noirApp.appState.filePathToId[report.labels[0].file_id]
// const startRange = report.labels[0].range.start
await circuitApp.plugin.call('fileManager', 'open', fullPathLocation)
// @ts-ignore
const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange)
// @ts-ignore
await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column)
// if (location) {
// const fullPathLocation = await circuitApp.plugin.resolveReportPath(location)
// await circuitApp.plugin.call('fileManager', 'open', fullPathLocation)
// // @ts-ignore
// const startPosition: { lineNumber: number; column: number } = await circuitApp.plugin.call('editor', 'getPositionAt', startRange)
// // @ts-ignore
// await circuitApp.plugin.call('editor', 'gotoLine', startPosition.lineNumber - 1, startPosition.column)
// }
}
}
@ -43,44 +48,44 @@ export function Container () {
const askGPT = async (report: CompilerReport) => {
if (report.labels.length > 0) {
const location = circuitApp.appState.filePathToId[report.labels[0].file_id]
const error = report.labels[0].message
// const location = circuitApp.appState.filePathToId[report.labels[0].file_id]
// const error = report.labels[0].message
if (location) {
const fullPathLocation = await circuitApp.plugin.resolveReportPath(location)
const content = await circuitApp.plugin.call('fileManager', 'readFile', fullPathLocation)
const message = `
circom code: ${content}
error message: ${error}
full circom error: ${JSON.stringify(report, null, 2)}
explain why the error occurred and how to fix it.
`
await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true)
setTimeout(async () => {
await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message)
}, 500)
} else {
const message = `
error message: ${error}
full circom error: ${JSON.stringify(report, null, 2)}
explain why the error occurred and how to fix it.
`
await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true)
setTimeout(async () => {
await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message)
}, 500)
}
// if (location) {
// const fullPathLocation = await circuitApp.plugin.resolveReportPath(location)
// const content = await circuitApp.plugin.call('fileManager', 'readFile', fullPathLocation)
// const message = `
// circom code: ${content}
// error message: ${error}
// full circom error: ${JSON.stringify(report, null, 2)}
// explain why the error occurred and how to fix it.
// `
// await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true)
// setTimeout(async () => {
// await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message)
// }, 500)
// } else {
// const message = `
// error message: ${error}
// full circom error: ${JSON.stringify(report, null, 2)}
// explain why the error occurred and how to fix it.
// `
// await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true)
// setTimeout(async () => {
// await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message)
// }, 500)
// }
} else {
const error = report.message
const message = `
error message: ${error}
full circom error: ${JSON.stringify(report, null, 2)}
explain why the error occurred and how to fix it.
`
await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true)
setTimeout(async () => {
await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message)
}, 500)
// const error = report.message
// const message = `
// error message: ${error}
// full circom error: ${JSON.stringify(report, null, 2)}
// explain why the error occurred and how to fix it.
// `
// await circuitApp.plugin.call('popupPanel' as any, 'showPopupPanel', true)
// setTimeout(async () => {
// await circuitApp.plugin.call('remixAI' as any, 'chatPipe', 'error_explaining', message)
// }, 500)
}
}

@ -5,7 +5,8 @@ export const appInitialState: AppState = {
filePathToId: {},
autoCompile: false,
hideWarnings: false,
status: 'idle'
status: 'idle',
compilerFeedback: ''
}
export const appReducer = (state = appInitialState, action: Actions): AppState => {
@ -29,6 +30,18 @@ export const appReducer = (state = appInitialState, action: Actions): AppState =
filePath: action.payload
}
case 'SET_COMPILER_FEEDBACK':
return {
...state,
compilerFeedback: action.payload
}
case 'SET_COMPILER_STATUS':
return {
...state,
status: action.payload
}
default:
throw new Error()
}

@ -38,14 +38,26 @@ export class NoirPluginClient extends PluginClient {
}
async compile(path: string): Promise<void> {
// @ts-ignore
const fileContent = await this.call('fileManager', 'readFile', path)
const fileBytes = new TextEncoder().encode(fileContent)
try {
this.internalEvents.emit('noir_compiling_start')
this.emit('statusChanged', { key: 'loading', title: 'Compiling Noir Circuit...', type: 'info' })
// @ts-ignore
this.call('terminal', 'log', { type: 'log', value: 'Compiling ' + path })
// @ts-ignore
const fileContent = await this.call('fileManager', 'readFile', path)
const fileBytes = new TextEncoder().encode(fileContent)
this.fm.writeFile(`src/${path}`, new Blob([fileBytes]).stream())
const program = await compile_program(this.fm)
this.fm.writeFile(`src/${path}`, new Blob([fileBytes]).stream())
const program = await compile_program(this.fm)
console.log('program: ', program)
console.log('program: ', program)
this.internalEvents.emit('noir_compiling_done')
this.emit('statusChanged', { key: 'succeed', title: 'Noir circuit compiled successfully', type: 'success' })
} catch (e) {
this.emit('statusChanged', { key: 'error', title: e.message, type: 'error' })
this.internalEvents.emit('noir_compiling_errored', e)
console.error(e)
}
}
async parse(path: string): Promise<void> {

@ -14,13 +14,16 @@ export interface AppState {
filePathToId: Record<string, string>,
autoCompile: boolean,
hideWarnings: boolean,
status: CompilerStatus
status: CompilerStatus,
compilerFeedback: string
}
export interface ActionPayloadTypes {
SET_AUTO_COMPILE: boolean,
SET_HIDE_WARNINGS: boolean,
SET_FILE_PATH: string
SET_FILE_PATH: string,
SET_COMPILER_FEEDBACK: string,
SET_COMPILER_STATUS: CompilerStatus
}
export interface Action<T extends keyof ActionPayloadTypes> {
type: T

@ -8,7 +8,7 @@
"canActivate": [],
"url": "",
"description": "Enables support for noir circuit compilation",
"icon": "assets/img/noir-icon-bw-800b.webp",
"icon": "assets/img/noir-icon.webp",
"location": "sidePanel",
"documentation": "",
"repo": "https://github.com/ethereum/remix-project/tree/master/apps/noir-compiler",

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

@ -3,4 +3,6 @@ export * from './lib/bleach'
export * from './lib/helper-components'
export * from './lib/components/PluginViewWrapper'
export * from './lib/components/custom-dropdown'
export * from './lib/components/custom-tooltip'
export * from './lib/components/custom-tooltip'
export * from './lib/components/feedback'
export type { CompilerReport } from './types/compilerTypes'

@ -1,5 +1,5 @@
import { useState } from 'react'
import { CompilerFeedbackProps, CompilerReport } from '../types'
import React, { useState } from 'react'
import { CompilerFeedbackProps, CompilerReport } from '../../types/compilerTypes'
import { RenderIf } from '@remix-ui/helper'
import { CopyToClipboard } from '@remix-ui/clipboard'
import { FeedbackAlert } from './feedbackAlert'
@ -11,16 +11,6 @@ export function CompilerFeedback ({ feedback, filePathToId, hideWarnings, openEr
setShowException(false)
}
const handleOpenError = (report: CompilerReport) => {
if (report.labels.length > 0) {
openErrorLocation(filePathToId[report.labels[0].file_id], report.labels[0].range.start)
}
}
const handleAskGPT = (report: CompilerReport) => {
askGPT(report)
}
return (
<div>
{
@ -43,19 +33,19 @@ export function CompilerFeedback ({ feedback, filePathToId, hideWarnings, openEr
<>
{
Array.isArray(feedback) && feedback.map((response, index) => (
<div key={index} onClick={() => handleOpenError(response)}>
<div key={index} onClick={() => openErrorLocation(response)}>
<RenderIf condition={response.type === 'Error'}>
<div className={`circuit_feedback ${response.type.toLowerCase()} alert alert-danger`} data-id="circuit_feedback">
<FeedbackAlert
message={response.message + (response.labels[0] ? ": " + response.labels[0].message + ` ${filePathToId[response.labels[0].file_id]}:${response.labels[0].range.start}:${response.labels[0].range.end}` : '')}
askGPT={ () => handleAskGPT(response) } />
askGPT={ () => askGPT(response) } />
</div>
</RenderIf>
<RenderIf condition={(response.type === 'Warning') && !hideWarnings}>
<div className={`circuit_feedback ${response.type.toLowerCase()} alert alert-warning`} data-id="circuit_feedback">
<FeedbackAlert
message={response.message}
askGPT={() => { handleAskGPT(response) }} />
askGPT={() => { askGPT(response) }} />
</div>
</RenderIf>
</div>

@ -1,10 +1,10 @@
import { useState } from 'react'
import { FeedbackAlertProps } from '../types'
import React, { useState } from 'react'
import { FeedbackAlertProps } from '../../types/compilerTypes'
import { RenderIf } from '@remix-ui/helper'
import {CopyToClipboard} from '@remix-ui/clipboard'
import { CopyToClipboard } from '@remix-ui/clipboard'
export function FeedbackAlert ({ message, askGPT }: FeedbackAlertProps) {
const [ showAlert, setShowAlert] = useState<boolean>(true)
const [showAlert, setShowAlert] = useState<boolean>(true)
const handleCloseAlert = () => {
setShowAlert(false)

@ -3,4 +3,32 @@ export type CompileOptionsProps = {
setCircuitHideWarnings: (value: boolean) => void,
autoCompile: boolean,
hideWarnings: boolean
}
export type FeedbackAlertProps = {
message: string,
askGPT: () => void
}
export type CompilerFeedbackProps = {
feedback: string | CompilerReport[],
filePathToId: Record<string, string>,
openErrorLocation: (report: CompilerReport) => void,
hideWarnings: boolean,
askGPT: (report: CompilerReport) => void
}
export type CompilerReport = {
type: "Error" | "Bug" | "Help" | "Note" | "Warning" | "Unknown",
message: string,
labels: {
style: "Primary" | "Secondary" | "Unknown",
file_id: string,
range: {
start: string,
end: string
},
message: string
}[],
notes: string[]
}
Loading…
Cancel
Save