refactor environment explorer

pull/5510/head
filip mertens 1 month ago committed by Aniket
parent a98f8360e2
commit a85e268f09
  1. 252
      apps/remix-ide/src/app/providers/environment-explorer.tsx
  2. 4
      apps/remix-ide/src/blockchain/blockchain.tsx
  3. 2
      libs/remix-ui/environment-explorer/src/index.ts
  4. 111
      libs/remix-ui/environment-explorer/src/lib/components/environment-explorer-ui.tsx
  5. 45
      libs/remix-ui/environment-explorer/src/lib/types/index.ts
  6. 8
      libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx
  7. 3
      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> = () => { }
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,90 +61,12 @@ export class EnvironmentExplorer extends ViewPlugin {
)
}
renderComponent() {
this.dispatch({
...this
})
}
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) => {
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.`)
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)
@ -170,122 +76,18 @@ export class EnvironmentExplorer extends ViewPlugin {
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
renderComponent() {
this.dispatch({
...this.state
})
}
}}
>
<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() {

@ -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>
}
}

@ -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"

@ -184,6 +184,9 @@
],
"@remix-ui/git": [
"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