From c08b6e503faa32da7695d764fabc54d879b68149 Mon Sep 17 00:00:00 2001 From: filip mertens Date: Tue, 17 Dec 2024 10:23:41 +0100 Subject: [PATCH] refactor environment explorer --- .../app/providers/environment-explorer.tsx | 278 +++--------------- apps/remix-ide/src/blockchain/blockchain.tsx | 4 + .../environment-explorer/src/index.ts | 2 + .../components/environment-explorer-ui.tsx | 111 +++++++ .../src/lib/types/index.ts | 45 +++ .../grid-view/src/lib/remix-ui-grid-cell.tsx | 8 +- tsconfig.paths.json | 5 +- 7 files changed, 213 insertions(+), 240 deletions(-) create mode 100644 libs/remix-ui/environment-explorer/src/index.ts create mode 100644 libs/remix-ui/environment-explorer/src/lib/components/environment-explorer-ui.tsx create mode 100644 libs/remix-ui/environment-explorer/src/lib/types/index.ts diff --git a/apps/remix-ide/src/app/providers/environment-explorer.tsx b/apps/remix-ide/src/app/providers/environment-explorer.tsx index facc93e4d8b..cbf57ec29cb 100644 --- a/apps/remix-ide/src/app/providers/environment-explorer.tsx +++ b/apps/remix-ide/src/app/providers/environment-explorer.tsx @@ -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 = () => {} - + dispatch: React.Dispatch = () => { } + 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 { - 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): void { @@ -77,215 +61,33 @@ 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 ( - - - {this.providers['Injected'].map(provider => { - return { - 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 - } - }} - > -
{provider.description}
-
- })} -
- {this.providers['Remix VMs'].map(provider => { - return { - 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 - } - }} - > -
{provider.description}
-
- })}
- {this.providers['Saved VM States'].map(provider => { - const { latestBlock, timestamp } = JSON.parse(provider.description) - return { - 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 - } - }} - > -
Latest Block: {parseInt(latestBlock)}
- -
Saved at: {(new Date(timestamp)).toDateString()}
-
-
- })}
- {this.providers['Remix forked VMs'].map(provider => { - return { - 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 - } - }} - > -
{provider.description}
-
- })}
- {this.providers['Externals'].map(provider => { - return { - 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 - } - }} - > -
{provider.description}
-
- })}
-
- ) + updateComponent(state: EnvironmentExplorerState) { + return (<> + + ) } } diff --git a/apps/remix-ide/src/blockchain/blockchain.tsx b/apps/remix-ide/src/blockchain/blockchain.tsx index d5832e9ff44..6d3958a0648 100644 --- a/apps/remix-ide/src/blockchain/blockchain.tsx +++ b/apps/remix-ide/src/blockchain/blockchain.tsx @@ -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() { diff --git a/libs/remix-ui/environment-explorer/src/index.ts b/libs/remix-ui/environment-explorer/src/index.ts new file mode 100644 index 00000000000..6b3a3132fa6 --- /dev/null +++ b/libs/remix-ui/environment-explorer/src/index.ts @@ -0,0 +1,2 @@ +export * from './lib/types' +export { EnvironmentExplorerUI } from './lib/components/environment-explorer-ui' \ No newline at end of file diff --git a/libs/remix-ui/environment-explorer/src/lib/components/environment-explorer-ui.tsx b/libs/remix-ui/environment-explorer/src/lib/components/environment-explorer-ui.tsx new file mode 100644 index 00000000000..be13e529823 --- /dev/null +++ b/libs/remix-ui/environment-explorer/src/lib/components/environment-explorer-ui.tsx @@ -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 ( + <> +
Latest Block: {parseInt(latestBlock)}
+ +
Saved at: {(new Date(timestamp)).toDateString()}
+
+ ) + } + }, + '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 ( + <> + { + Object.values(sections).length && Object.values(sections).map((section) => ( + + {section.providers.map(provider => { + return { + await pinStateCallback(provider, pinned) + }} + > +
{(section.descriptionFn && section.descriptionFn(provider)) || provider.description}
+
+ })} +
+ )) + } +
+ + ) +} \ No newline at end of file diff --git a/libs/remix-ui/environment-explorer/src/lib/types/index.ts b/libs/remix-ui/environment-explorer/src/lib/types/index.ts new file mode 100644 index 00000000000..61685a5f36b --- /dev/null +++ b/libs/remix-ui/environment-explorer/src/lib/types/index.ts @@ -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 + 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 + provider: { + sendAsync: (payload: any) => Promise + } +} \ No newline at end of file diff --git a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx index f215b9ab53b..3c66f9703df 100644 --- a/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx +++ b/libs/remix-ui/grid-view/src/lib/remix-ui-grid-cell.tsx @@ -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) => { : <> } - { props.logos && props.logos.map((logo) => )} + { props.logos && props.logos.map((logo, index) => )} { props.title &&