Merge branch 'master' into contrib1

pull/5507/head
Joseph Izang 1 month ago committed by GitHub
commit c7cf7b6dde
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 277
      apps/remix-ide/src/app/providers/environment-explorer.tsx
  2. 4
      apps/remix-ide/src/blockchain/blockchain.tsx
  3. 8
      apps/remix-ide/team-best-practices.md
  4. 2
      libs/remix-ui/environment-explorer/src/index.ts
  5. 111
      libs/remix-ui/environment-explorer/src/lib/components/environment-explorer-ui.tsx
  6. 45
      libs/remix-ui/environment-explorer/src/lib/types/index.ts
  7. 1
      libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.css
  8. 8
      libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx
  9. 2
      release-process.md
  10. 5
      tsconfig.paths.json

@ -1,11 +1,8 @@
import React from 'react' // eslint-disable-line
import { ViewPlugin } from '@remixproject/engine-web'
import { CustomTooltip, PluginViewWrapper } from '@remix-ui/helper'
import { RemixUIGridView } from '@remix-ui/remix-ui-grid-view'
import { RemixUIGridSection } from '@remix-ui/remix-ui-grid-section'
import { RemixUIGridCell } from '@remix-ui/remix-ui-grid-cell'
import { PluginViewWrapper } from '@remix-ui/helper'
import './style/environment-explorer.css'
import type { Provider } from '../../blockchain/blockchain'
import { EnvironmentExplorerUI, Provider } from '@remix-ui/environment-explorer'
import * as packageJson from '../../../../../package.json'
@ -25,44 +22,31 @@ const profile = {
methods: []
}
type ProvidersSection = `Injected` | 'Remix VMs' | 'Externals' | 'Remix forked VMs' | 'Saved VM States'
type EnvironmentExplorerState = {
providersFlat: { [key: string]: Provider },
pinnedProviders: string[],
}
export class EnvironmentExplorer extends ViewPlugin {
providers: { [key in ProvidersSection]: Provider[] }
providersFlat: { [key: string]: Provider }
pinnedProviders: string[]
dispatch: React.Dispatch<any> = () => {}
dispatch: React.Dispatch<any> = () => { }
state: EnvironmentExplorerState
constructor() {
super(profile)
this.providersFlat = {}
this.providers = {
'Injected': [],
'Remix VMs': [],
'Saved VM States': [],
'Remix forked VMs': [],
'Externals': []
this.state = {
providersFlat: {},
pinnedProviders: [],
}
}
async onActivation(): Promise<void> {
this.providersFlat = await this.call('blockchain', 'getAllProviders')
this.pinnedProviders = await this.call('blockchain', 'getPinnedProviders')
this.renderComponent()
this.on('blockchain', 'providersChanged', this.updateProviders.bind(this))
await this.updateProviders()
}
addProvider (provider: Provider) {
if (provider.isInjected) {
this.providers['Injected'].push(provider)
} else if (provider.isForkedVM) {
this.providers['Remix forked VMs'].push(provider)
} else if (provider.isVM) {
this.providers['Remix VMs'].push(provider)
} else if (provider.isSavedState) {
this.providers['Saved VM States'].push(provider)
} else {
this.providers['Externals'].push(provider)
}
async updateProviders() {
this.state.providersFlat = await this.call('blockchain', 'getAllProviders')
this.state.pinnedProviders = await this.call('blockchain', 'getPinnedProviders')
this.renderComponent()
}
setDispatch(dispatch: React.Dispatch<any>): void {
@ -77,215 +61,32 @@ export class EnvironmentExplorer extends ViewPlugin {
)
}
async pinStateCallback(provider: Provider, pinned: boolean) {
if (pinned) {
this.emit('providerPinned', provider.name, provider)
this.call('notification', 'toast', `"${provider.displayName}" has been added to the Environment list of the Deploy & Run Transactions plugin.`)
} else {
const providerName = await this.call('blockchain', 'getProvider')
if (providerName !== provider.name) {
this.emit('providerUnpinned', provider.name, provider)
this.call('notification', 'toast', `"${provider.displayName}" has been removed from the Environment list of the Deploy & Run Transactions plugin.`)
return true
} else {
this.call('notification', 'toast', 'Cannot unpin the current selected provider')
return false
}
}
}
renderComponent() {
this.dispatch({
...this
...this.state
})
}
updateComponent(state: any) {
this.providers = {
'Injected': [],
'Remix VMs': [],
'Saved VM States': [],
'Externals': [],
'Remix forked VMs': []
}
for (const [key, provider] of Object.entries(this.providersFlat)) {
this.addProvider(provider)
}
return (
<RemixUIGridView
plugin={this}
styleList={""}
logo={profile.icon}
enableFilter={true}
showUntagged={true}
showPin={true}
title={profile.description}
description="Select the providers and chains to include them in the ENVIRONMENT select box of the Deploy & Run Transactions plugin."
>
<RemixUIGridSection
plugin={this}
title='Deploy using a Browser Extension.'
hScrollable={false}
>
{this.providers['Injected'].map(provider => {
return <RemixUIGridCell
plugin={this}
title={provider.displayName}
logos={provider.logos}
classList='EECellStyle'
searchKeywords={['Injected', provider.name, provider.displayName, provider.title, provider.description]}
pinned={this.pinnedProviders.includes(provider.name)}
key={provider.name}
id={provider.name}
pinStateCallback={async (pinned: boolean) => {
if (pinned) {
this.emit('providerPinned', provider.name, provider)
this.call('notification', 'toast', `"${provider.displayName}" has been added to the Environment list of the Deploy & Run Transactions plugin.`)
return true
}
const providerName = await this.call('blockchain', 'getProvider')
if (providerName !== provider.name) {
this.emit('providerUnpinned', provider.name, provider)
this.call('notification', 'toast', `"${provider.displayName}" has been removed from the Environment list of the Deploy & Run Transactions plugin.`)
return true
} else {
this.call('notification', 'toast', 'Cannot unpin the current selected provider')
return false
}
}}
>
<div>{provider.description}</div>
</RemixUIGridCell>
})}
</RemixUIGridSection>
<RemixUIGridSection
plugin={this}
title='Deploy to an In-browser Virtual Machine.'
hScrollable={false}
>{this.providers['Remix VMs'].map(provider => {
return <RemixUIGridCell
plugin={this}
title={provider.displayName}
logos={provider.logos}
classList='EECellStyle'
searchKeywords={['Remix VMs', provider.name, provider.displayName, provider.title, provider.description]}
pinned={this.pinnedProviders.includes(provider.name)}
key={provider.name}
id={provider.name}
pinStateCallback={async (pinned: boolean) => {
if (pinned) {
this.emit('providerPinned', provider.name, provider)
this.call('notification', 'toast', `"${provider.displayName}" has been added to the Environment list of the Deploy & Run Transactions plugin.`)
return true
}
const providerName = await this.call('blockchain', 'getProvider')
if (providerName !== provider.name) {
this.emit('providerUnpinned', provider.name, provider)
this.call('notification', 'toast', `"${provider.displayName}" has been removed from the Environment list of the Deploy & Run Transactions plugin.`)
return true
} else {
this.call('notification', 'toast', 'Cannot unpin the current selected provider')
return false
}
}}
>
<div>{provider.description}</div>
</RemixUIGridCell>
})}</RemixUIGridSection>
<RemixUIGridSection
plugin={this}
title='Deploy to an In-browser Saved VM State.'
hScrollable={false}
>{this.providers['Saved VM States'].map(provider => {
const { latestBlock, timestamp } = JSON.parse(provider.description)
return <RemixUIGridCell
plugin={this}
title={provider.displayName}
logos={provider.logos}
classList='EECellStyle'
searchKeywords={['Saved VM States', provider.name, provider.displayName, provider.title, provider.description]}
pinned={this.pinnedProviders.includes(provider.name)}
key={provider.name}
id={provider.name}
pinStateCallback={async (pinned: boolean) => {
if (pinned) {
this.emit('providerPinned', provider.name, provider)
this.call('notification', 'toast', `"${provider.displayName}" has been added to the Environment list of the Deploy & Run Transactions plugin.`)
return true
}
const providerName = await this.call('blockchain', 'getProvider')
if (providerName !== provider.name) {
this.emit('providerUnpinned', provider.name, provider)
this.call('notification', 'toast', `"${provider.displayName}" has been removed from the Environment list of the Deploy & Run Transactions plugin.`)
return true
} else {
this.call('notification', 'toast', 'Cannot unpin the current selected provider')
return false
}
}}
>
<div><b>Latest Block: </b>{parseInt(latestBlock)}</div>
<CustomTooltip
placement="auto"
tooltipId="overlay-tooltip-compile"
tooltipText={`Saved at: ${(new Date(timestamp)).toLocaleString()}`}
>
<div><b>Saved at: </b>{(new Date(timestamp)).toDateString()}</div>
</CustomTooltip>
</RemixUIGridCell>
})}</RemixUIGridSection>
<RemixUIGridSection
plugin={this}
title='Deploy to an In-browser forked Virtual Machine.'
hScrollable={false}
>{this.providers['Remix forked VMs'].map(provider => {
return <RemixUIGridCell
plugin={this}
title={provider.displayName}
logos={provider.logos}
classList='EECellStyle'
searchKeywords={['Remix VMs', provider.name, provider.displayName, provider.title, provider.description]}
pinned={this.pinnedProviders.includes(provider.name)}
key={provider.name}
id={provider.name}
pinStateCallback={async (pinned: boolean) => {
if (pinned) {
this.emit('providerPinned', provider.name, provider)
this.call('notification', 'toast', `"${provider.displayName}" has been added to the Environment list of the Deploy & Run Transactions plugin.`)
return true
}
const providerName = await this.call('blockchain', 'getProvider')
if (providerName !== provider.name) {
this.emit('providerUnpinned', provider.name, provider)
this.call('notification', 'toast', `"${provider.displayName}" has been removed from the Environment list of the Deploy & Run Transactions plugin.`)
return true
} else {
this.call('notification', 'toast', 'Cannot unpin the current selected provider')
return false
}
}}
>
<div>{provider.description}</div>
</RemixUIGridCell>
})}</RemixUIGridSection>
<RemixUIGridSection
plugin={this}
title='Deploy to an external Provider.'
hScrollable={false}
>{this.providers['Externals'].map(provider => {
return <RemixUIGridCell
plugin={this}
title={provider.displayName}
logos={provider.logos}
classList='EECellStyle'
searchKeywords={['Externals', provider.name, provider.displayName, provider.title, provider.description]}
pinned={this.pinnedProviders.includes(provider.name)}
key={provider.name}
id={provider.name}
pinStateCallback={async (pinned: boolean) => {
if (pinned) {
this.emit('providerPinned', provider.name, provider)
this.call('notification', 'toast', `"${provider.displayName}" has been added to the Environment list of the Deploy & Run Transactions plugin.`)
return true
}
const providerName = await this.call('blockchain', 'getProvider')
if (providerName !== provider.name) {
this.emit('providerUnpinned', provider.name, provider)
this.call('notification', 'toast', `"${provider.displayName}" has been removed from the Environment list of the Deploy & Run Transactions plugin.`)
return true
} else {
this.call('notification', 'toast', 'Cannot unpin the current selected provider')
return false
}
}}
>
<div>{provider.description}</div>
</RemixUIGridCell>
})}</RemixUIGridSection>
</RemixUIGridView>
)
updateComponent(state: EnvironmentExplorerState) {
return (<>
<EnvironmentExplorerUI pinStateCallback={this.pinStateCallback.bind(this)} profile={profile} state={state} />
</>)
}
}

@ -146,6 +146,7 @@ export class Blockchain extends Plugin {
this.pinnedProviders.push(name)
this.call('config', 'setAppParameter', 'settings/pinned-providers', JSON.stringify(this.pinnedProviders))
_paq.push(['trackEvent', 'blockchain', 'providerPinned', name])
this.emit('providersChanged')
})
this.on('environmentExplorer', 'providerUnpinned', (name, provider) => {
@ -154,6 +155,7 @@ export class Blockchain extends Plugin {
this.pinnedProviders.splice(index, 1)
this.call('config', 'setAppParameter', 'settings/pinned-providers', JSON.stringify(this.pinnedProviders))
_paq.push(['trackEvent', 'blockchain', 'providerUnpinned', name])
this.emit('providersChanged')
})
this.call('config', 'getAppParameter', 'settings/pinned-providers').then((providers) => {
@ -665,10 +667,12 @@ export class Blockchain extends Plugin {
addProvider(provider: Provider) {
if (this.pinnedProviders.includes(provider.name)) this.emit('shouldAddProvidertoUdapp', provider.name, provider)
this.executionContext.addProvider(provider)
this.emit('providersChanged')
}
removeProvider(name) {
this.executionContext.removeProvider(name)
this.emit('providersChanged')
}
getAllProviders() {

@ -5,7 +5,7 @@ This document aims to address contributors best practices of the following repos
- remix-ide https://github.com/ethereum/remix-project
- remix-plugin https://github.com/ethereum/remix-plugin
This document is not in its final version, **a team meeting which aims to address new/old best practices, feedback, workflows, all kind of issues related to how the team work together occurs every 2 weeks.**
This document is not in its final version, **a team meeting which aims to address new/old best practices, feedback, workflows, all kind of issues related to how the team works together occurs every 2 weeks.**
This document link to other specialised best practices (like coding best practices).
Related links:
@ -122,9 +122,9 @@ Before starting to coding, we should ensure all devs / contributors are aware of
- A milestone should **only** contain items we are sure to finish.
- The end of a milestone trigger a new release.
- Milestone items and duration should take in account time spent in bugs fixing and support.
- Milestone items and duration should take into account time spent in bugs fixing and support.
- The team should commit to the milestone duration.
- If a dev finish early he/she can help other to push remaining tasks.
- If a dev finish early he/she can help others to push remaining tasks.
- If a dev finish early he/she can work on specifying / integrating the next milestone.
- A milestone duration is fixed at the start of the milestone (but should better not exceed 1 month).
- Progress and issues regarding a milestone are discussed on regular standups.
@ -146,7 +146,7 @@ Before starting to coding, we should ensure all devs / contributors are aware of
- After a new release we should stay in alert for possible regression and better not release on Friday at 5pm :)
### 2) Community:
- Before the official release, we should select a group of power users and invite them to test and give feedbacks.
- Before the official release, we should select a group of power users and invite them to test and give feedback.
- Users need to know upfront a new release is coming and we should prepare them for it by showcasing some new features they can expect and when it will happen (fixed date, published at least 1 week in advance).
- Whenever we have a new release we have to communicate this efficiently (twitter, reddit, ...).

@ -0,0 +1,2 @@
export * from './lib/types'
export { EnvironmentExplorerUI } from './lib/components/environment-explorer-ui'

@ -0,0 +1,111 @@
// eslint-disable-next-line no-use-before-define
import React, { useEffect, useState } from 'react'
import { environmentExplorerUIGridSections, environmentExplorerUIProps } from '../types'
import { RemixUIGridCell, RemixUIGridSection, RemixUIGridView } from '@remix-ui/remix-ui-grid-view'
import { CustomTooltip } from '@remix-ui/helper'
const defaultSections: environmentExplorerUIGridSections = {
Injected: {
title: 'Deploy using a Browser Extension.',
keywords: ['Injected'],
providers: [],
filterFn: (provider) => provider.isInjected
},
'Remix VMs': {
title: 'Deploy to an In-browser Virtual Machine.',
keywords: ['Remix VMs'],
providers: [],
filterFn: (provider) => provider.isVM
},
'Saved VM States': {
title: 'Deploy to an In-browser Saved VM State.',
keywords: ['Saved VM States'],
providers: [],
filterFn: (provider) => provider.isSavedState,
descriptionFn: (provider) => {
const { latestBlock, timestamp } = JSON.parse(provider.description)
return (
<>
<div><b>Latest Block: </b>{parseInt(latestBlock)}</div>
<CustomTooltip
placement="auto"
tooltipId="overlay-tooltip-compile"
tooltipText={`Saved at: ${(new Date(timestamp)).toLocaleString()}`}
>
<div><b>Saved at: </b>{(new Date(timestamp)).toDateString()}</div>
</CustomTooltip>
</>)
}
},
'Remix forked VMs': {
title: 'Deploy to a Remix forked Virtual Machine.',
keywords: ['Remix forked VMs'],
providers: [],
filterFn: (provider) => provider.isForkedVM
},
'Externals': {
title: 'Deploy to an external Provider.',
keywords: ['Externals'],
providers: [],
filterFn: (provider) => (!provider.isInjected && !provider.isVM && !provider.isSavedState && !provider.isForkedVM)
},
}
export const EnvironmentExplorerUI = (props: environmentExplorerUIProps) => {
const [sections, setSections] = useState(defaultSections)
const { state, pinStateCallback, profile } = props
useEffect(() => {
setSections((prevSections) => {
const newSections = { ...prevSections }
Object.keys(newSections).forEach((section) => {
newSections[section].providers = Object.values(state.providersFlat).filter(newSections[section].filterFn)
})
return newSections
})
}, [state])
return (
<>
<RemixUIGridView
plugin={null}
styleList={""}
logo={profile.icon}
enableFilter={true}
showUntagged={true}
showPin={true}
title={profile.description}
description="Select the providers and chains to include them in the ENVIRONMENT select box of the Deploy & Run Transactions plugin."
>{
Object.values(sections).length && Object.values(sections).map((section) => (
<RemixUIGridSection
plugin={this}
title={section.title}
hScrollable={false}
key={section.title}
>
{section.providers.map(provider => {
return <RemixUIGridCell
plugin={this}
title={provider.displayName}
logos={provider.logos}
classList='EECellStyle'
searchKeywords={['Injected', provider.name, provider.displayName, provider.title, provider.description]}
pinned={state.pinnedProviders.includes(provider.name)}
key={provider.name}
id={provider.name}
pinStateCallback={async (pinned: boolean) => {
await pinStateCallback(provider, pinned)
}}
>
<div>{(section.descriptionFn && section.descriptionFn(provider)) || provider.description}</div>
</RemixUIGridCell>
})}
</RemixUIGridSection>
))
}
</RemixUIGridView>
</>
)
}

@ -0,0 +1,45 @@
import { Plugin } from '@remixproject/engine'
import { Profile } from '@remixproject/plugin-utils'
export type ProvidersSection = `Injected` | 'Remix VMs' | 'Externals' | 'Remix forked VMs' | 'Saved VM States'
export type environmentExplorerUIProps = {
state: {
providersFlat: { [key: string]: Provider }
pinnedProviders: string[]
}
pinStateCallback (provider: Provider, pinned: boolean): Promise<void>
profile: Profile
}
export type environmentExplorerUIGridSection = {
title: string
keywords: string[],
providers: Provider[]
filterFn: (provider: Provider) => boolean
descriptionFn?: (provider: Provider) => string | JSX.Element | null
}
export type environmentExplorerUIGridSections = {
[key in ProvidersSection]: environmentExplorerUIGridSection
}
export type Provider = {
options: { [key: string]: string }
dataId: string
name: string
displayName: string
logo?: string,
logos?: string[],
fork: string
description?: string
isInjected: boolean
isVM: boolean
isSavedState: boolean
isForkedVM: boolean
title: string
init: () => Promise<void>
provider: {
sendAsync: (payload: any) => Promise<void>
}
}

@ -31,6 +31,7 @@
right: 0.9rem;
top: -0.7rem;
background: transparent;
z-index: 1000;
}
.remixui_grid_cell_tags {

@ -54,6 +54,12 @@ export const RemixUIGridCell = (props: RemixUIGridCellProps) => {
setAnyEnabled(enabled)
}, [filterCon, props.tagList])
useEffect(() => {
if (props.pinned!== pinned) {
setPinned(props.pinned)
}
},[props.pinned])
/*const listenOnExpand = (key) => {
if (key === props.key) setExpand(props.toggleExpandView)
console.log('expand ----> ', key)
@ -86,7 +92,7 @@ export const RemixUIGridCell = (props: RemixUIGridCellProps) => {
<img className='remixui_grid_view_logo mr-1' src={props.logo} style={{ width: '1rem', height: '1rem' }}/> :
<></>
}
{ props.logos && props.logos.map((logo) => <img className='remixui_grid_view_logo mr-1' src={logo} style={{ width: '1rem', height: '1rem' }}/>)}
{ props.logos && props.logos.map((logo, index) => <img key={index} className='remixui_grid_view_logo mr-1' src={logo} style={{ width: '1rem', height: '1rem' }}/>)}
{ props.title &&
<CustomTooltip
placement="top"

@ -49,7 +49,7 @@ This command will ask for a new version.
This command uses `lerna` and is solely responsible for publishing all the remix libraries. It will ask for a new version of each library. Make sure you are logged in to NPM.
Once these commands run successfully, the version for each remix library will be updated to latest in the libs' package.json file.
Once these commands run successfully, the version for each remix library will be updated to the latest in the libs' package.json file.
- Create and merge bump PR to master

@ -183,8 +183,11 @@
"libs/remix-ai-core/src/index.ts"
],
"@remix-ui/git": [
"libs/remix-ui/git/src/index.ts"
"libs/remix-ui/git/src/index.ts"
],
"@remix-ui/environment-explorer": [
"libs/remix-ui/environment-explorer/src/index.ts"
],
"@remix-api": [
"libs/remix-api/src/index.ts"
],

Loading…
Cancel
Save