diff --git a/apps/remix-ide-e2e/src/tests/generalSettings.test.ts b/apps/remix-ide-e2e/src/tests/generalSettings.test.ts index 30346994bc..f36d042950 100644 --- a/apps/remix-ide-e2e/src/tests/generalSettings.test.ts +++ b/apps/remix-ide-e2e/src/tests/generalSettings.test.ts @@ -19,7 +19,7 @@ module.exports = { browser.waitForElementVisible('*[data-id="remixIdeSidePanel"]', 5000) .waitForElementVisible('*[data-id="settingsTabGenerateContractMetadataLabel"]', 5000) .verify.elementPresent('[data-id="settingsTabGenerateContractMetadata"]:checked') - .click('*[data-id="verticalIconsFileExplorerIcons"]') + .click('*[data-id="verticalIconsKindfilePanel"]') .click('[data-id="treeViewLitreeViewItemcontracts"]') .openFile('contracts/3_Ballot.sol') .click('*[data-id="verticalIconsKindsolidity"]') diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index d327647549..71360c1e9d 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -225,8 +225,8 @@ class AppComponent { self.engine.register([appPanel, tabProxy]) // those views depend on app_manager - self.menuicons = new VerticalIcons(appManager) - self.sidePanel = new SidePanel(appManager, self.menuicons) + self.menuicons = new VerticalIcons() + self.sidePanel = new SidePanel() self.hiddenPanel = new HiddenPanel() const pluginManagerComponent = new PluginManagerComponent( diff --git a/apps/remix-ide/src/app/components/panel.ts b/apps/remix-ide/src/app/components/panel.ts index a5747188af..3b3bd6d33b 100644 --- a/apps/remix-ide/src/app/components/panel.ts +++ b/apps/remix-ide/src/app/components/panel.ts @@ -49,8 +49,7 @@ export class AbstractPanel extends HostPlugin { * @param {String} name The name of the plugin to display the content */ showContent (name) { - if (!this.plugins[name]) throw new Error(`Plugin ${name} is not yet activated`) - + if (!this.plugins[name]) throw new Error(`Plugin ${name} is not yet activated`) Object.values(this.plugins).forEach(plugin => { plugin.active = false }) diff --git a/apps/remix-ide/src/app/components/side-panel.tsx b/apps/remix-ide/src/app/components/side-panel.tsx index 8b64d64e45..b5e9dcd3df 100644 --- a/apps/remix-ide/src/app/components/side-panel.tsx +++ b/apps/remix-ide/src/app/components/side-panel.tsx @@ -4,8 +4,6 @@ import ReactDOM from 'react-dom' import { AbstractPanel } from './panel' import { RemixPluginPanel } from '@remix-ui/panel' import packageJson from '../../../../../package.json' -import { RemixAppManager } from '../../remixAppManager' -import { VerticalIcons } from 'libs/remix-ui/vertical-icons-panel/types/vertical-icons-panel' import RemixUIPanelHeader from 'libs/remix-ui/panel/src/lib/plugins/panel-header' // const csjs = require('csjs-inject') @@ -17,20 +15,18 @@ const sidePanel = { methods: ['addView', 'removeView'] } -// TODO merge with vertical-icons.js export class SidePanel extends AbstractPanel { - appManager: RemixAppManager sideelement: any - verticalIcons: VerticalIcons; - constructor (appManager: RemixAppManager, verticalIcons: VerticalIcons) { + constructor() { super(sidePanel) - this.appManager = appManager this.sideelement = document.createElement('section') this.sideelement.setAttribute('class', 'panel plugin-manager') - this.verticalIcons = verticalIcons + } + onActivation() { + this.renderComponent() // Toggle content - verticalIcons.events.on('toggleContent', (name) => { + this.on('menuicons', 'toggleContent', (name) => { if (!this.plugins[name]) return if (this.plugins[name].active) { // TODO: Only keep `this.emit` (issue#2210) @@ -44,7 +40,7 @@ export class SidePanel extends AbstractPanel { this.events.emit('showing', name) }) // Force opening - verticalIcons.events.on('showContent', (name) => { + this.on('menuicons', 'showContent', (name) => { if (!this.plugins[name]) return this.showContent(name) // TODO: Only keep `this.emit` (issue#2210) @@ -53,25 +49,22 @@ export class SidePanel extends AbstractPanel { }) } - onActivation () { - this.renderComponent() - } - - focus (name) { + focus(name) { this.emit('focusChanged', name) super.focus(name) } - removeView (profile) { + removeView(profile) { + if (this.plugins[profile.name].active) this.call('menuicons', 'select', 'filePanel') super.removeView(profile) this.emit('pluginDisabled', profile.name) this.call('menuicons', 'unlinkContent', profile) this.renderComponent() } - addView (profile, view) { + addView(profile, view) { super.addView(profile, view) - this.verticalIcons.linkContent(profile) + this.call('menuicons', 'linkContent', profile) this.renderComponent() } @@ -79,17 +72,17 @@ export class SidePanel extends AbstractPanel { * Display content and update the header * @param {String} name The name of the plugin to display */ - async showContent (name) { + async showContent(name) { super.showContent(name) this.emit('focusChanged', name) this.renderComponent() } - render () { + render() { return this.sideelement } - renderComponent () { - ReactDOM.render(} plugins={this.plugins}/>, this.sideelement) + renderComponent() { + ReactDOM.render(} plugins={this.plugins} />, this.sideelement) } } diff --git a/apps/remix-ide/src/app/components/vertical-icons.js b/apps/remix-ide/src/app/components/vertical-icons.js deleted file mode 100644 index c458e9e5ef..0000000000 --- a/apps/remix-ide/src/app/components/vertical-icons.js +++ /dev/null @@ -1,110 +0,0 @@ -import * as packageJson from '../../../../../package.json' -import ReactDOM from 'react-dom' -import React from 'react' // eslint-disable-line -// eslint-disable-next-line no-unused-vars -import { RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel' -import Registry from '../state/registry' -const { Plugin } = require('@remixproject/engine') -const EventEmitter = require('events') - -const profile = { - name: 'menuicons', - displayName: 'Vertical Icons', - description: '', - version: packageJson.version, - methods: ['select', 'unlinkContent'] -} - -// TODO merge with side-panel.js. VerticalIcons should not be a plugin -export class VerticalIcons extends Plugin { - constructor (appManager) { - super(profile) - this.events = new EventEmitter() - this.appManager = appManager - this.htmlElement = document.createElement('div') - this.htmlElement.setAttribute('id', 'icon-panel') - this.icons = {} - this.iconKind = {} - this.iconStatus = {} - this.defaultProfile = profile - this.targetProfileForChange = {} - this.targetProfileForRemoval = {} - this.registry = Registry.getInstance() - this.keys = ['succeed', 'edited', 'none', 'loading', 'failed'] - this.types = ['error', 'warning', 'success', 'info', ''] - } - - renderComponent () { - ReactDOM.render( - , - this.htmlElement) - } - - onActivation () { - this.renderComponent() - } - - linkContent (profile) { - if (!profile.icon) return - if (!profile.kind) profile.kind = 'none' - this.targetProfileForChange[profile.name] = profile - this.listenOnStatus(profile) - this.renderComponent() - } - - unlinkContent (profile) { - this.targetProfileForRemoval = profile - this.removeIcon(profile) - this.renderComponent() - } - - listenOnStatus (profile) { - - } - - /** - * Remove an icon from the map - * @param {ModuleProfile} profile The profile of the module - */ - removeIcon ({ name }) { - if (this.targetProfileForChange[name]) delete this.targetProfileForChange[name] - setTimeout(() => { - this.renderComponent() - }, 150) - } - - /** - * Set an icon as active - * @param {string} name Name of profile of the module to activate - */ - select (name) { - // TODO: Only keep `this.emit` (issue#2210) - this.emit('showContent', name) - this.events.emit('showContent', name) - } - - onThemeChanged (themeType) { - const invert = themeType === 'dark' ? 1 : 0 - const active = this.view.querySelector('.active') - if (active) { - const image = active.querySelector('.image') - image.style.setProperty('filter', `invert(${invert})`) - } - } - - /** - * Toggles the side panel for plugin - * @param {string} name Name of profile of the module to activate - */ - toggle (name) { - // TODO: Only keep `this.emit` (issue#2210) - this.emit('toggleContent', name) - this.events.emit('toggleContent', name) - } - - render () { - return this.htmlElement - } -} diff --git a/apps/remix-ide/src/app/components/vertical-icons.tsx b/apps/remix-ide/src/app/components/vertical-icons.tsx new file mode 100644 index 0000000000..2e8deaa182 --- /dev/null +++ b/apps/remix-ide/src/app/components/vertical-icons.tsx @@ -0,0 +1,116 @@ +// eslint-disable-next-line no-use-before-define +import React from 'react' +import ReactDOM from 'react-dom' +import Registry from '../state/registry' +import packageJson from '../../../../../package.json' +import { Plugin } from '@remixproject/engine' +import { EventEmitter } from 'events' +import { IconRecord, RemixUiVerticalIconsPanel } from '@remix-ui/vertical-icons-panel' +import { Profile } from '@remixproject/plugin-utils' +import { timeStamp } from 'console' + +const profile = { + name: 'menuicons', + displayName: 'Vertical Icons', + description: '', + version: packageJson.version, + methods: ['select', 'unlinkContent', 'linkContent'], + events: ['toggleContent', 'showContent'] +} + +export class VerticalIcons extends Plugin { + events: EventEmitter + htmlElement: HTMLDivElement + icons: Record = {} + constructor () { + super(profile) + this.events = new EventEmitter() + this.htmlElement = document.createElement('div') + this.htmlElement.setAttribute('id', 'icon-panel') + } + + renderComponent () { + const fixedOrder = ['filePanel', 'solidity','udapp', 'debugger', 'solidityStaticAnalysis', 'solidityUnitTesting', 'pluginManager'] + + const divived = Object.values(this.icons).map((value) => { return { + ...value, + isRequired: fixedOrder.indexOf(value.profile.name) > -1 + }}).sort((a,b) => { + return a.timestamp - b.timestamp + }) + + const required = divived.filter((value) => value.isRequired).sort((a,b) => { + return fixedOrder.indexOf(a.profile.name) - fixedOrder.indexOf(b.profile.name) + }) + + const sorted: IconRecord[] = [ + ...required, + ...divived.filter((value) => { return !value.isRequired }) + ] + + ReactDOM.render( + , + this.htmlElement) + } + + onActivation () { + this.renderComponent() + this.on('sidePanel', 'focusChanged', (name: string) => { + Object.keys(this.icons).map((o) => { + this.icons[o].active = false + }) + this.icons[name].active = true + this.renderComponent() + }) + } + + async linkContent (profile: Profile) { + if (!profile.icon) return + if (!profile.kind) profile.kind = 'none' + this.icons[profile.name] = { + profile: profile, + active: false, + canbeDeactivated: await this.call('manager', 'canDeactivate', this.profile, profile), + timestamp: Date.now() + } + this.renderComponent() + } + + unlinkContent (profile: Profile) { + delete this.icons[profile.name] + this.renderComponent() + } + + async activateHome() { + await this.call('manager', 'activatePlugin', 'home') + await this.call('tabs', 'focus', 'home') + } + + /** + * Set an icon as active + * @param {string} name Name of profile of the module to activate + */ + select (name: string) { + // TODO: Only keep `this.emit` (issue#2210) + console.log(name, this) + this.emit('showContent', name) + this.events.emit('showContent', name) + } + + /** + * Toggles the side panel for plugin + * @param {string} name Name of profile of the module to activate + */ + toggle (name: string) { + // TODO: Only keep `this.emit` (issue#2210) + this.emit('toggleContent', name) + this.events.emit('toggleContent', name) + } + + render () { + return this.htmlElement + } +} diff --git a/apps/remix-ide/src/remixAppManager.js b/apps/remix-ide/src/remixAppManager.js index d3cc735b3f..7967336579 100644 --- a/apps/remix-ide/src/remixAppManager.js +++ b/apps/remix-ide/src/remixAppManager.js @@ -50,6 +50,10 @@ export class RemixAppManager extends PluginManager { return isNative(from.name) } + async canDeactivate(from,to) { + return this.canDeactivatePlugin(from, to) + } + async deactivatePlugin (name) { const [to, from] = [ await this.getProfile(name), diff --git a/apps/remix-ide/src/walkthroughService.js b/apps/remix-ide/src/walkthroughService.js index e68da1b421..b9ffab4416 100644 --- a/apps/remix-ide/src/walkthroughService.js +++ b/apps/remix-ide/src/walkthroughService.js @@ -31,7 +31,7 @@ export class WalkthroughService extends Plugin { position: 'right' }, { - element: document.querySelector('#compileIcons'), + element: document.querySelector('#verticalIconsKindsolidity'), title: 'Solidity Compiler', intro: 'Having selected a .sol file in the File Explorers (the icon above), compile it with the Solidity Compiler.', tooltipClass: 'bg-light text-dark', diff --git a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.css b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.css index 54c71b16c5..4464c8d2fa 100644 --- a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.css +++ b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.css @@ -36,7 +36,7 @@ .remixui_home_rightPanel { right: 0; position: absolute; - z-index: 3; + z-index: 3000; } .remixui_home_remixHomeMedia { overflow-y: auto; diff --git a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx index ecbca46eb7..73bd4f0357 100644 --- a/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx +++ b/libs/remix-ui/home-tab/src/lib/remix-ui-home-tab.tsx @@ -80,6 +80,7 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => { const remiAudioEl = useRef(null) const inputValue = useRef(null) + const rightPanel = useRef(null) useEffect(() => { plugin.call('theme', 'currentTheme').then((theme) => { @@ -97,7 +98,7 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => { window.addEventListener('click', (event) => { const target = event.target as Element const id = target.id - if (id !== 'remixIDEHomeTwitterbtn' && id !== 'remixIDEHomeMediumbtn') { + if (id !== 'remixIDEHomeTwitterbtn' && id !== 'remixIDEHomeMediumbtn' && !rightPanel.current.contains(event.target)) { // todo check event.target setState(prevState => { return { ...prevState, showMediaPanel: 'none' } }) } @@ -266,7 +267,7 @@ export const RemixUiHomeTab = (props: RemixUiHomeTabProps) => {

-

+
-