diff --git a/apps/remix-ide-e2e/src/commands/hidePopupPanel.ts b/apps/remix-ide-e2e/src/commands/hidePopupPanel.ts new file mode 100644 index 0000000000..dd646722a5 --- /dev/null +++ b/apps/remix-ide-e2e/src/commands/hidePopupPanel.ts @@ -0,0 +1,25 @@ +import { NightwatchBrowser } from 'nightwatch' +import EventEmitter from 'events' + +class HidePopupPanel extends EventEmitter { + command(this: NightwatchBrowser) { + browser + .perform((done) => { + browser.execute(function () { + return localStorage.getItem('did_show_popup_panel') + }, [], function (result) { + if (!result.value) { + browser.waitForElementVisible('*[data-id="popupPanelToggle"]') + .click('*[data-id="popupPanelToggle"]') + } + done() + }) + }) + .perform((done) => { + done() + this.emit('complete') + }) + } +} + +module.exports = HidePopupPanel diff --git a/apps/remix-ide-e2e/src/commands/hideToolTips.ts b/apps/remix-ide-e2e/src/commands/hideToolTips.ts index 00a05e26c3..87d7e10b64 100644 --- a/apps/remix-ide-e2e/src/commands/hideToolTips.ts +++ b/apps/remix-ide-e2e/src/commands/hideToolTips.ts @@ -1,4 +1,4 @@ -import {NightwatchBrowser} from 'nightwatch' +import { NightwatchBrowser } from 'nightwatch' import EventEmitter from 'events' class HideToolTips extends EventEmitter { @@ -16,6 +16,9 @@ class HideToolTips extends EventEmitter { .popover { display:none !important; } + #scamDetails { + display:none !important; + } `) }, [], done()) }) diff --git a/apps/remix-ide-e2e/src/commands/refreshPage.ts b/apps/remix-ide-e2e/src/commands/refreshPage.ts index 5147ceb839..309892536f 100644 --- a/apps/remix-ide-e2e/src/commands/refreshPage.ts +++ b/apps/remix-ide-e2e/src/commands/refreshPage.ts @@ -20,6 +20,9 @@ class RefreshPage extends EventEmitter { .popover { display:none !important; } + #scamDetails { + display:none !important; + } `) }, [], done()) }) diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index f30ce3dd62..9b8351f06b 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -14,6 +14,7 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url .url(url || 'http://127.0.0.1:8080') .pause(5000) .switchBrowserTab(0) + .hidePopupPanel() .perform((done) => { if (!loadPlugin) return done() browser @@ -39,6 +40,9 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url .popover { display:none !important; } + #scamDetails { + display:none !important; + } `); }, [], done()) }) diff --git a/apps/remix-ide-e2e/src/tests/circom.test.ts b/apps/remix-ide-e2e/src/tests/circom.test.ts index 9ef2661f82..6228cda5ca 100644 --- a/apps/remix-ide-e2e/src/tests/circom.test.ts +++ b/apps/remix-ide-e2e/src/tests/circom.test.ts @@ -5,6 +5,7 @@ import init from '../helpers/init' module.exports = { '@disabled': true, before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.globals.asyncHookTimeout = 30000000; init(browser, done) }, @@ -195,7 +196,7 @@ module.exports = { .waitForElementPresent('[data-id="verticalIconsKindcircuit-compiler"]') .waitForElementVisible('[data-id="verticalIconsKindcircuit-compiler"]') .click('[data-id="play-editor"]') - .pause(7000) + .pause(10000) .journalLastChildIncludes('newZkey') .pause(25000) .journalLastChildIncludes('setup done.') diff --git a/apps/remix-ide-e2e/src/tests/matomo.test.ts b/apps/remix-ide-e2e/src/tests/matomo.test.ts index 74db9e8253..52d26f0fad 100644 --- a/apps/remix-ide-e2e/src/tests/matomo.test.ts +++ b/apps/remix-ide-e2e/src/tests/matomo.test.ts @@ -439,7 +439,7 @@ module.exports = { return (window as any)._paq }, [], (res) => { const expectedEvents = [ - ["trackEvent", "Preload", "start"], + ["trackEvent", "App", "Preload", "start"], ["trackEvent", "Storage", "activate", "indexedDB"], ["trackEvent", "App", "load"], ]; diff --git a/apps/remix-ide-e2e/src/tests/url.test.ts b/apps/remix-ide-e2e/src/tests/url.test.ts index 8a77f2e60c..9db1b69bac 100644 --- a/apps/remix-ide-e2e/src/tests/url.test.ts +++ b/apps/remix-ide-e2e/src/tests/url.test.ts @@ -91,23 +91,14 @@ module.exports = { }) }, - 'Should load Etherscan verified contracts from URL "address" param) #group1': function (browser: NightwatchBrowser) { + 'Should load Etherscan verified contracts from URL "address" param) #flaky #group1': function (browser: NightwatchBrowser) { browser .url('http://127.0.0.1:8080/#address=0xdac17f958d2ee523a2206206994597c13d831ec7') .refreshPage() - .pause(7000) + .pause(2000) .currentWorkspaceIs('code-sample') - .waitForElementVisible('*[data-id=treeViewLitreeViewItemsepolia]') - .waitForElementVisible('*[data-id="treeViewLitreeViewItemsepolia/0xdac17f958d2ee523a2206206994597c13d831ec7/contracts/MetaMultiSigWallet.sol"]') - .getEditorValue((content) => { - browser.assert.ok(content && content.indexOf( - 'contract MetaMultiSigWallet {') !== -1) - - }) .waitForElementVisible('*[data-id=treeViewLitreeViewItemmainnet]') - .click('*[data-id=treeViewLitreeViewItemmainnet]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7"]') - .click('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7"]') .waitForElementVisible('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7/TetherToken.sol"]') .click('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7/TetherToken.sol"]') .getEditorValue((content) => { diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index 4a5b1831ee..5c6d3bd262 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -74,6 +74,7 @@ declare module 'nightwatch' { connectToExternalHttpProvider: (url: string, identifier: string) => NightwatchBrowser waitForElementNotContainsText: (id: string, value: string, timeout: number = 10000) => NightwatchBrowser hideToolTips: (this: NightwatchBrowser) => NightwatchBrowser + hidePopupPanel: (this: NightwatchBrowser) => NightwatchBrowser enableClipBoard: () => NightwatchBrowser addFileSnekmate: (name: string, content: NightwatchContractContent) => NightwatchBrowser selectFiles: (selelectedElements: any[]) => NightwatchBrowser diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index a936cc5e33..23addcdf90 100644 --- a/apps/remix-ide/src/app.js +++ b/apps/remix-ide/src/app.js @@ -12,6 +12,7 @@ import { SidePanel } from './app/components/side-panel' import { StatusBar } from './app/components/status-bar' import { HiddenPanel } from './app/components/hidden-panel' import { PinnedPanel } from './app/components/pinned-panel' +import { PopupPanel } from './app/components/popup-panel' import { VerticalIcons } from './app/components/vertical-icons' import { LandingPage } from './app/ui/landing-page/landing-page' import { MainPanel } from './app/components/main-panel' @@ -450,6 +451,7 @@ class AppComponent { this.sidePanel = new SidePanel() this.hiddenPanel = new HiddenPanel() this.pinnedPanel = new PinnedPanel() + this.popupPanel = new PopupPanel() const pluginManagerComponent = new PluginManagerComponent(appManager, this.engine) const filePanel = new FilePanel(appManager, contentImport) @@ -457,7 +459,7 @@ class AppComponent { const landingPage = new LandingPage(appManager, this.menuicons, fileManager, filePanel, contentImport) this.settings = new SettingsTab(Registry.getInstance().get('config').api, editor, appManager) - this.engine.register([this.menuicons, landingPage, this.hiddenPanel, this.sidePanel, this.statusBar, filePanel, pluginManagerComponent, this.settings, this.pinnedPanel]) + this.engine.register([this.menuicons, landingPage, this.hiddenPanel, this.sidePanel, this.statusBar, filePanel, pluginManagerComponent, this.settings, this.pinnedPanel, this.popupPanel]) // CONTENT VIEWS & DEFAULT PLUGINS const openZeppelinProxy = new OpenZeppelinProxy(blockchain) @@ -540,6 +542,7 @@ class AppComponent { await this.appManager.activatePlugin(['statusBar']) await this.appManager.activatePlugin(['sidePanel']) // activating host plugin separately await this.appManager.activatePlugin(['pinnedPanel']) + await this.appManager.activatePlugin(['popupPanel']) await this.appManager.activatePlugin(['home']) await this.appManager.activatePlugin(['settings', 'config']) await this.appManager.activatePlugin([ diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx new file mode 100644 index 0000000000..4352394aae --- /dev/null +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -0,0 +1,123 @@ +import React from 'react' // eslint-disable-line +import { AbstractPanel } from './panel' +import { PluginRecord, RemixPluginPanel } from '@remix-ui/panel' +import packageJson from '../../../../../package.json' +import { PluginViewWrapper } from '@remix-ui/helper' +import { EventEmitter } from 'events' + +import { AppAction, appActionTypes, AppState } from '@remix-ui/app' + +const profile = { + name: 'popupPanel', + displayName: 'Popup Panel', + description: 'Remix IDE popup panel', + version: packageJson.version, + events: [], + methods: ['addView', 'removeView', 'showContent', 'showPopupPanel'] +} +type popupPanelState = { + plugins: Record +} + +export class PopupPanel extends AbstractPanel { + element: HTMLDivElement + dispatch: React.Dispatch = () => { } + appStateDispatch: React.Dispatch = () => { } + + constructor(config) { + super(profile) + this.event = new EventEmitter() + } + + setDispatch(dispatch: React.Dispatch) { + this.dispatch = dispatch + } + + setAppStateDispatch(appStateDispatch: React.Dispatch) { + this.appStateDispatch = appStateDispatch + } + + onActivation() { + this.renderComponent() + } + + focus(name) { + this.emit('focusChanged', name) + super.focus(name) + this.renderComponent() + } + + addView(profile, view) { + super.addView(profile, view) + this.renderComponent() + this.showContent(profile.name) // should be handled by some click + } + + removeView(profile) { + super.removeView(profile) + this.renderComponent() + } + + async showContent(name) { + super.showContent(name) + this.renderComponent() + } + + async showPopupPanel(show) { + + this.appStateDispatch({ + type: appActionTypes.setShowPopupPanel, + payload: show + }) + this.renderComponent() + } + + renderComponent() { + this.dispatch({ + plugins: this.plugins + }) + } + + render() { + return ( + + ) + } + + updateComponent(state: popupPanelState, appState: Partial) { + return ( +
+
+ + + + } + plugins={state.plugins} /> +
+
+ ) + } +} diff --git a/apps/remix-ide/src/app/components/preload.tsx b/apps/remix-ide/src/app/components/preload.tsx index 18e7665e0a..2a05a283e5 100644 --- a/apps/remix-ide/src/app/components/preload.tsx +++ b/apps/remix-ide/src/app/components/preload.tsx @@ -10,7 +10,7 @@ import './styles/preload.css' import isElectron from 'is-electron' const _paq = (window._paq = window._paq || []) -_paq.push(['trackEvent', 'Preload', 'start']) +_paq.push(['trackEvent', 'App', 'Preload', 'start']) export const Preload = (props: any) => { const [tip, setTip] = useState('') @@ -40,7 +40,7 @@ export const Preload = (props: any) => { }) }) .catch((err) => { - _paq.push(['trackEvent', 'Preload', 'error', err && err.message]) + _paq.push(['trackEvent', 'App', 'PreloadError', err && err.message]) console.error('Error loading Remix:', err) setError(true) }) diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index d6d3c78a48..6004c20c56 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -5,6 +5,7 @@ import { RemixAITab, ChatApi } from '@remix-ui/remix-ai' import React, { useCallback } from 'react'; import { ICompletions, IModel, RemoteInferencer, IRemoteModel, IParams, GenerationParams, CodeExplainAgent } from '@remix/remix-ai-core'; import { CustomRemixApi } from '@remix-api' +import { PluginViewWrapper } from '@remix-ui/helper' type chatRequestBufferT = { [key in keyof T]: T[key] @@ -16,12 +17,13 @@ const profile = { methods: ['code_generation', 'code_completion', "solidity_answer", "code_explaining", "code_insertion", "error_explaining", - "initialize", 'chatPipe', 'ProcessChatRequestBuffer', 'isChatRequestPending'], + "initialize", 'chatPipe', 'ProcessChatRequestBuffer', + 'isChatRequestPending'], events: [], icon: 'assets/img/remix-logo-blue.png', description: 'RemixAI provides AI services to Remix IDE.', kind: '', - location: 'sidePanel', + location: 'popupPanel', documentation: 'https://remix-ide.readthedocs.io/en/latest/remixai.html', version: packageJson.version, maintainedBy: 'Remix' @@ -37,6 +39,7 @@ export class RemixAIPlugin extends ViewPlugin { chatRequestBuffer: chatRequestBufferT = null agent: CodeExplainAgent useRemoteInferencer:boolean = false + dispatch: any constructor(inDesktop:boolean) { super(profile) @@ -46,6 +49,7 @@ export class RemixAIPlugin extends ViewPlugin { } onActivation(): void { + if (this.isOnDesktop) { console.log('Activating RemixAIPlugin on desktop') // this.on(this.remixDesktopPluginName, 'activated', () => { @@ -201,13 +205,40 @@ export class RemixAIPlugin extends ViewPlugin { return "" } } + isChatRequestPending(){ return this.chatRequestBuffer != null } + setDispatch(dispatch) { + this.dispatch = dispatch + this.renderComponent() + } + + renderComponent () { + this.dispatch({ + plugin: this, + }) + } + render() { + return
+ +
+ } + + updateComponent(state) { return ( - + ) } } diff --git a/apps/remix-ide/src/app/tabs/compile-tab.js b/apps/remix-ide/src/app/tabs/compile-tab.js index 1fb7dea231..70f0d498a7 100644 --- a/apps/remix-ide/src/app/tabs/compile-tab.js +++ b/apps/remix-ide/src/app/tabs/compile-tab.js @@ -99,13 +99,17 @@ class CompileTab extends CompilerApiMixin(ViewPlugin) { // implements ICompilerA * This function is used by remix-plugin compiler API. * @param {object} settings {evmVersion, optimize, runs, version, language} */ - setCompilerConfig (settings) { + async setCompilerConfig (settings) { super.setCompilerConfig(settings) this.renderComponent() // @todo(#2875) should use loading compiler return value to check whether the compiler is loaded instead of "setInterval" const value = JSON.stringify(settings, null, '\t') + let pluginInfo + pluginInfo = await this.call('udapp', 'showPluginDetails') - this.call('notification', 'toast', compilerConfigChangedToastMsg(this.currentRequest.from, value)) + if (this.currentRequest.from === 'udapp') { + this.call('notification', 'toast', compilerConfigChangedToastMsg((pluginInfo ? pluginInfo.displayName : this.currentRequest.from ), value)) + } } compile (fileName) { diff --git a/apps/remix-ide/src/app/tabs/locales/ru/home.json b/apps/remix-ide/src/app/tabs/locales/ru/home.json index 48044db76d..894148bb5a 100644 --- a/apps/remix-ide/src/app/tabs/locales/ru/home.json +++ b/apps/remix-ide/src/app/tabs/locales/ru/home.json @@ -1,4 +1,5 @@ { + "home.home": "Главная", "home.scamAlert": "Предупреждение о мошенничестве", "home.scamAlertText": "Единственный URL, который использует Remix, - это remix.ethereum.org", "home.scamAlertText2": "Остерегайтесь видеороликов, рекламирующих \"ботов-передовиков ликвидности\"", @@ -6,6 +7,9 @@ "home.learnMore": "Узнать больше", "home.here": "здесь", "home.featured": "Рекомендуемые", + "home.learnEthPromoTitle": "LearnEth: Учебники внутри Remix", + "home.learnEthPromoButton": "Начать обучение", + "home.learnEthPromoText": "Ознакомьтесь с уроками по Remix, Solidity и другим проектам Web3. Отлично подходит для всех уровней навыков.", "home.jumpIntoWeb3": "Перейти в WEB3", "home.jumpIntoWeb3More": "Подробнее", "home.jumpIntoWeb3Text": "Remix IDE является частью проекта Remix, широкий выбор инструментов которого, может быть использован для всего путешествия по разработке контракта пользователями любого уровня знаний. Узнайте больше на сайте проекта Remix.", @@ -36,6 +40,7 @@ "home.ozerc1155TemplateDesc": "Создайте ERC1155 токен, импортируя библиотеку OpenZeppelin.", "home.gnosisSafeMultisigTemplateDesc": "Создайте кошельки с мульти-подписью с использованием этого шаблона.", "home.zeroxErc20TemplateDesc": "Создайте токен ERC20, импортируя контракт с 0xProject.", + "home.learnEthPluginDesc": "Узнайте о Remix, Solidity и других проектах Web3.", "home.learn": "Обучение", "home.learnEth1": "Основы Remix", "home.learnEth1Desc": "Введение в интерфейс Remix-а и основные операции.", @@ -65,5 +70,8 @@ "home.resources": "Источники", "home.connectToLocalhost": "Подключиться к локальному хосту", "home.seeAllTutorials": "Посмотреть все уроки", - "home.maintainedByRemix": "Поддерживается Remix" + "home.maintainedByRemix": "Поддерживается Remix", + "home.gitCloneTooltip": "Клонировать репозиторий Github в новую рабочую область", + "home.gistTooltip": "Открыть репозиторий Gist", + "home.newFileTooltip": "Добавить новый файл в рабочую область" } diff --git a/apps/remix-ide/src/app/udapp/run-tab.tsx b/apps/remix-ide/src/app/udapp/run-tab.tsx index bc811f8aff..b17d95b9c6 100644 --- a/apps/remix-ide/src/app/udapp/run-tab.tsx +++ b/apps/remix-ide/src/app/udapp/run-tab.tsx @@ -35,7 +35,8 @@ const profile = { 'setEnvironmentMode', 'clearAllInstances', 'addInstance', - 'resolveContractAndAddInstance' + 'resolveContractAndAddInstance', + 'showPluginDetails' ] } @@ -87,6 +88,10 @@ export class RunTab extends ViewPlugin { }) } + showPluginDetails() { + return profile + } + async setEnvironmentMode(env) { const canCall = await this.askUserPermission('setEnvironmentMode', 'change the environment used') if (canCall) { diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css index a4aa80cea9..6dee3ce457 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-cerulean.min.css @@ -36,6 +36,7 @@ --body-bg: #fff; --text-bg-mark: #fcf8e3; --custom-select: #fff; + --brand-dark-blue: #222496; --breakpoint-xs:0; --breakpoint-sm:576px; --breakpoint-md:768px; diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css index dd75e7682f..d4842f1d12 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-cyborg.min.css @@ -37,6 +37,7 @@ --body-bg: #060606; --text-bg-mark: #fcf8e3; --custom-select: #fff; + --brand-dark-blue: #222496; --breakpoint-xs:0; --breakpoint-sm:576px; --breakpoint-md:768px; diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css index 54bed17144..9d764e4f83 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-flatly.min.css @@ -36,6 +36,7 @@ --body-bg: #fff; --text-bg-mark: #fcf8e3; --custom-select: #fff; + --brand-dark-blue: #222496; --breakpoint-xs:0; --breakpoint-sm:576px; --breakpoint-md:768px; diff --git a/apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css b/apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css index 5856861ba6..35bf23f3c1 100644 --- a/apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css +++ b/apps/remix-ide/src/assets/css/themes/bootstrap-spacelab.min.css @@ -39,6 +39,7 @@ --body-bg:#fff; --text-bg-mark: #fcf8e3; --custom-select: #fff; + --brand-dark-blue: #222496; --breakpoint-xs:0; --breakpoint-sm:576px; --breakpoint-md:768px; diff --git a/apps/remix-ide/src/assets/css/themes/remix-black_undtds.css b/apps/remix-ide/src/assets/css/themes/remix-black_undtds.css index a9ca2de081..2ff8c005fb 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-black_undtds.css +++ b/apps/remix-ide/src/assets/css/themes/remix-black_undtds.css @@ -25,6 +25,7 @@ --text: #babbcc; --body-bg: #1a1a1a; --custom-select: #252525; + --brand-dark-blue: #222496; --text-bg-mark: #a5a5a5; --breakpoint-xs: 0; --breakpoint-sm: 576px; diff --git a/apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css b/apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css index d291d9665d..b4552f4703 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css +++ b/apps/remix-ide/src/assets/css/themes/remix-candy_ikhg4m.css @@ -25,6 +25,7 @@ --body-bg: #d5efff; --text-bg-mark: #fcf8e3; --custom-select: #ffffff; + --brand-dark-blue: #222496; --breakpoint-xs: 0; --breakpoint-sm: 576px; --breakpoint-md: 768px; diff --git a/apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css b/apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css index 0e57ee6fca..c131351a55 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css +++ b/apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css @@ -25,6 +25,7 @@ --text-background: #222336; --text-bg-mark: #8388b2; --custom-select: #35384c; + --brand-dark-blue: #222496; --runtab: #8A93B0; --body-bg: #222336; --breakpoint-xs: 0; diff --git a/apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css b/apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css index bf4d7268fd..ac79dade67 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css +++ b/apps/remix-ide/src/assets/css/themes/remix-hacker_owl.css @@ -27,7 +27,7 @@ --body-bg: #011628; --custom-select: #252525; --text-bg-mark: #a5a5a5; - --custom-select: #011627; + --brand-dark-blue: #222496; --text-background: #011626; --breakpoint-xs: 0; --breakpoint-sm: 576px; diff --git a/apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css b/apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css index 1740f44c17..11dd9e544e 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css +++ b/apps/remix-ide/src/assets/css/themes/remix-light_powaqg.css @@ -25,6 +25,7 @@ --body-bg: #eef1f6; --text-bg-mark: #fcf8e3; --custom-select: #fff; + --brand-dark-blue: #222496; --breakpoint-xs: 0; --breakpoint-sm: 576px; --breakpoint-md: 768px; diff --git a/apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css b/apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css index 5eebada8ee..0b678a1272 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css +++ b/apps/remix-ide/src/assets/css/themes/remix-midcentury_hrzph3.css @@ -25,6 +25,7 @@ --body-bg: #DBE2E0; --text-bg-mark: #fcf8e3; --custom-select: #eeede9; + --brand-dark-blue: #222496; --breakpoint-xs: 0; --breakpoint-sm: 576px; --breakpoint-md: 768px; diff --git a/apps/remix-ide/src/assets/css/themes/remix-unicorn.css b/apps/remix-ide/src/assets/css/themes/remix-unicorn.css index afa9a5b270..ac3fe7175f 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-unicorn.css +++ b/apps/remix-ide/src/assets/css/themes/remix-unicorn.css @@ -25,6 +25,7 @@ --body-bg: #f1eef6; --text-bg-mark: #fcf8e3; --custom-select: #fff; + --brand-dark-blue: #222496; --breakpoint-xs: 0; --breakpoint-sm: 576px; --breakpoint-md: 768px; diff --git a/apps/remix-ide/src/assets/css/themes/remix-violet.css b/apps/remix-ide/src/assets/css/themes/remix-violet.css index 61c372a95f..740ef0dd68 100644 --- a/apps/remix-ide/src/assets/css/themes/remix-violet.css +++ b/apps/remix-ide/src/assets/css/themes/remix-violet.css @@ -25,6 +25,7 @@ --body-bg: #f1eef6; --text-bg-mark: #fcf8e3; --custom-select: #fff; + --brand-dark-blue: #222496; --breakpoint-xs: 0; --breakpoint-sm: 576px; --breakpoint-md: 768px; diff --git a/apps/remix-ide/src/assets/img/aiLogo.svg b/apps/remix-ide/src/assets/img/aiLogo.svg new file mode 100644 index 0000000000..f6dc2a50b2 --- /dev/null +++ b/apps/remix-ide/src/assets/img/aiLogo.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/remix-ide/src/assets/img/aiLogoHead.webp b/apps/remix-ide/src/assets/img/aiLogoHead.webp new file mode 100644 index 0000000000..d026f81bbf Binary files /dev/null and b/apps/remix-ide/src/assets/img/aiLogoHead.webp differ diff --git a/apps/remixdesktop/test/types/index.d.ts b/apps/remixdesktop/test/types/index.d.ts index faf3a89d54..2a67630e60 100644 --- a/apps/remixdesktop/test/types/index.d.ts +++ b/apps/remixdesktop/test/types/index.d.ts @@ -71,6 +71,7 @@ declare module 'nightwatch' { connectToExternalHttpProvider: (url: string, identifier: string) => NightwatchBrowser waitForElementNotContainsText: (id: string, value: string, timeout: number = 10000) => NightwatchBrowser hideToolTips: (this: NightwatchBrowser) => NightwatchBrowser + hidePopupPanel: (this: NightwatchBrowser) => NightwatchBrowser enableClipBoard: () => NightwatchBrowser } diff --git a/libs/remix-api/src/lib/plugins/popuppanel-api.ts b/libs/remix-api/src/lib/plugins/popuppanel-api.ts new file mode 100644 index 0000000000..040a70bc0a --- /dev/null +++ b/libs/remix-api/src/lib/plugins/popuppanel-api.ts @@ -0,0 +1,10 @@ +import { IFilePanel } from '@remixproject/plugin-api' +import { StatusEvents } from '@remixproject/plugin-utils' + +export interface IPopupPanelAPI { + events:{ + } & StatusEvents + methods: { + showPopupPanel(state: boolean): void + } +} diff --git a/libs/remix-api/src/lib/plugins/remixaiDesktop-api.ts b/libs/remix-api/src/lib/plugins/remixaiDesktop-api.ts deleted file mode 100644 index dc9deb7e82..0000000000 --- a/libs/remix-api/src/lib/plugins/remixaiDesktop-api.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { IParams } from "@remix/remix-ai-core"; -import { StatusEvents } from "@remixproject/plugin-utils"; - -export interface IRemixAID { - events: { - activated():void, - onInference():void, - onInferenceDone():void, - onStreamResult(streamText: string):void, - - } & StatusEvents, - methods: { - code_completion(context: string): Promise - code_insertion(msg_pfx: string, msg_sfx: string): Promise, - code_generation(prompt: string): Promise, - code_explaining(code: string, context?: string): Promise, - error_explaining(prompt: string): Promise, - solidity_answer(prompt: string): Promise, - initializeModelBackend(local: boolean, generalModel?, completionModel?): Promise, - chatPipe(pipeMessage: string): Promise, - ProcessChatRequestBuffer(params:IParams): Promise, - } -} \ No newline at end of file diff --git a/libs/remix-api/src/lib/remix-api.ts b/libs/remix-api/src/lib/remix-api.ts index e8dad3b599..36d7fbf6a0 100644 --- a/libs/remix-api/src/lib/remix-api.ts +++ b/libs/remix-api/src/lib/remix-api.ts @@ -17,8 +17,10 @@ import { IRemixAI } from "./plugins/remixai-api" import { IRemixAID } from "./plugins/remixAIDesktop-api" import { IMenuIconsApi } from "./plugins/menuicons-api" import { IDgitPlugin } from "./plugins/dgitplugin-api" +import { IPopupPanelAPI } from "./plugins/popuppanel-api" export interface ICustomRemixApi extends IRemixApi { + popupPanel: IPopupPanelAPI dgitApi: IGitApi dgit: IDgitPlugin config: IConfigApi @@ -39,4 +41,5 @@ export interface ICustomRemixApi extends IRemixApi { remixAID: IRemixAID } + export declare type CustomRemixApi = Readonly \ No newline at end of file diff --git a/libs/remix-ui/app/src/index.ts b/libs/remix-ui/app/src/index.ts index 31dea89385..4602431686 100644 --- a/libs/remix-ui/app/src/index.ts +++ b/libs/remix-ui/app/src/index.ts @@ -2,6 +2,6 @@ export { default as RemixApp } from './lib/remix-app/remix-app' export { dispatchModalContext, dispatchModalInterface, AppContext, appProviderContextType, appPlatformTypes, platformContext, onLineContext } from './lib/remix-app/context/context' export { ModalProvider, useDialogDispatchers } from './lib/remix-app/context/provider' export { AppModal } from './lib/remix-app/interface/index' -export { AlertModal } from './lib/remix-app/interface/index' +export { AlertModal, AppState } from './lib/remix-app/interface/index' export { ModalTypes, AppModalCancelTypes } from './lib/remix-app/types/index' export { AppAction, appActionTypes } from './lib/remix-app/actions/app' diff --git a/libs/remix-ui/app/src/lib/remix-app/actions/app.ts b/libs/remix-ui/app/src/lib/remix-app/actions/app.ts index 716d351e94..246b10cad0 100644 --- a/libs/remix-ui/app/src/lib/remix-app/actions/app.ts +++ b/libs/remix-ui/app/src/lib/remix-app/actions/app.ts @@ -17,6 +17,7 @@ export const enum appActionTypes { setCurrentBranch = 'SET_CURRENT_BRANCH', setNeedsGitInit = 'SET_NEEDS_GIT_INIT', setCanUseGit = 'SET_CAN_USE_GIT', + setShowPopupPanel = 'SET_SHOW_POPUP_PANEL', } type AppPayload = { @@ -24,6 +25,7 @@ type AppPayload = { [appActionTypes.setCurrentBranch]: branch, [appActionTypes.setNeedsGitInit]: boolean, [appActionTypes.setCanUseGit]: boolean, + [appActionTypes.setShowPopupPanel]: boolean, } export type AppAction = ActionMap[keyof ActionMap< diff --git a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts index 0c146c98f7..531c2764d0 100644 --- a/libs/remix-ui/app/src/lib/remix-app/interface/index.ts +++ b/libs/remix-ui/app/src/lib/remix-app/interface/index.ts @@ -52,5 +52,6 @@ export interface AppState { currentBranch: branch needsGitInit: boolean canUseGit: boolean + showPopupPanel: boolean } diff --git a/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts b/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts index 6dd37603bc..39d61cab75 100644 --- a/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts +++ b/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts @@ -27,5 +27,12 @@ export const appReducer = (state: AppState, action: AppAction): AppState => { canUseGit: action.payload } } + + case appActionTypes.setShowPopupPanel: { + return { + ...state, + showPopupPanel: action.payload + } + } } } \ No newline at end of file diff --git a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx index f343310096..f3c0bf43d0 100644 --- a/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx +++ b/libs/remix-ui/app/src/lib/remix-app/remix-app.tsx @@ -9,12 +9,11 @@ import { AppProvider } from './context/provider' import AppDialogs from './components/modals/dialogs' import DialogViewPlugin from './components/modals/dialogViewPlugin' import { appProviderContextType, onLineContext, platformContext } from './context/context' -import { FormattedMessage, IntlProvider } from 'react-intl' -import { CustomTooltip } from '@remix-ui/helper' +import { IntlProvider } from 'react-intl' import { UsageTypes } from './types' -import { AppState } from './interface' import { appReducer } from './reducer/app' import { appInitialState } from './state/app' +import isElectron from 'is-electron' declare global { interface Window { @@ -45,7 +44,10 @@ const RemixApp = (props: IRemixAppUi) => { const sidePanelRef = useRef(null) const pinnedPanelRef = useRef(null) - const [appState, appStateDispatch] = useReducer(appReducer, appInitialState) + const [appState, appStateDispatch] = useReducer(appReducer, { + ...appInitialState, + showPopupPanel: !window.localStorage.getItem('did_show_popup_panel') && !isElectron() + }) useEffect(() => { async function activateApp() { @@ -77,6 +79,12 @@ const RemixApp = (props: IRemixAppUi) => { } }, []) + useEffect(() => { + if (!appState.showPopupPanel) { + window.localStorage.setItem('did_show_popup_panel', 'true') + } + },[appState.showPopupPanel]) + function setListeners() { props.app.sidePanel.events.on('toggle', () => { setHideSidePanel((prev) => { @@ -244,6 +252,7 @@ const RemixApp = (props: IRemixAppUi) => { }
{props.app.hiddenPanel.render()}
+
{props.app.popupPanel.render()}
{props.app.statusBar.render()}
diff --git a/libs/remix-ui/app/src/lib/remix-app/state/app.ts b/libs/remix-ui/app/src/lib/remix-app/state/app.ts index 8086b75c9c..708b22301a 100644 --- a/libs/remix-ui/app/src/lib/remix-app/state/app.ts +++ b/libs/remix-ui/app/src/lib/remix-app/state/app.ts @@ -5,5 +5,6 @@ export const appInitialState: AppState = { gitHubUser: {} as GitHubUser, currentBranch: null, needsGitInit: true, - canUseGit: false + canUseGit: false, + showPopupPanel: false } \ No newline at end of file diff --git a/libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx b/libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx index c88f985ef6..e5e7700eac 100644 --- a/libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx +++ b/libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx @@ -1,18 +1,35 @@ -import React from 'react' -import { useEffect, useState } from 'react' +import { AppContext } from '@remix-ui/app' +import React, { useContext, useEffect, useState } from 'react' interface IPluginViewWrapperProps { plugin: any + useAppContext?: boolean // Optional flag to decide whether to use AppContext } -export const PluginViewWrapper = (props: IPluginViewWrapperProps) => { +export const PluginViewWrapper = ({ plugin, useAppContext = false }: IPluginViewWrapperProps) => { const [state, setState] = useState(null) + const appContext = useAppContext ? useContext(AppContext) : null useEffect(() => { - if (props.plugin.setDispatch) { - props.plugin.setDispatch(setState) + if (plugin.setDispatch) { + plugin.setDispatch(setState) } - }, []) + if (useAppContext && appContext.appStateDispatch && plugin.setAppStateDispatch) { + plugin.setAppStateDispatch(appContext.appStateDispatch) + } + }, [plugin]) + + if (useAppContext && appContext && appContext.appState) { + return ( + <> + {state ? <>{plugin.updateComponent(state, appContext.appState)} : <>} + + ) + } - return <>{state ? <>{props.plugin.updateComponent(state)} : <>} + return ( + <> + {state ? <>{plugin.updateComponent(state)} : <>} + + ) } diff --git a/libs/remix-ui/helper/src/lib/components/custom-tooltip.tsx b/libs/remix-ui/helper/src/lib/components/custom-tooltip.tsx index b199c1d8a9..9d3a2d31a7 100644 --- a/libs/remix-ui/helper/src/lib/components/custom-tooltip.tsx +++ b/libs/remix-ui/helper/src/lib/components/custom-tooltip.tsx @@ -4,7 +4,7 @@ import { Fragment } from 'react' import { OverlayTrigger, Popover, Tooltip } from 'react-bootstrap' import { CustomTooltipType } from '../../types/customtooltip' -export function CustomTooltip({ children, placement, tooltipId, tooltipClasses, tooltipText, tooltipTextClasses, delay, hide }: CustomTooltipType) { +export function CustomTooltip({ children, placement, tooltipId, tooltipClasses, tooltipText, tooltipTextClasses, delay, hide, show }: CustomTooltipType) { if (typeof tooltipText !== 'string') { const newTooltipText = React.cloneElement(tooltipText, { className: ' bg-secondary text-wrap p-1 px-2 ' @@ -16,6 +16,7 @@ export function CustomTooltip({ children, placement, tooltipId, tooltipClasses, (!hide ? ( diff --git a/libs/remix-ui/helper/src/types/customtooltip.ts b/libs/remix-ui/helper/src/types/customtooltip.ts index 7afb63f091..a7b1383089 100644 --- a/libs/remix-ui/helper/src/types/customtooltip.ts +++ b/libs/remix-ui/helper/src/types/customtooltip.ts @@ -10,4 +10,5 @@ export type CustomTooltipType = { tooltipTextClasses?: string delay?: OverlayDelay hide?: boolean + show?: boolean } \ No newline at end of file diff --git a/libs/remix-ui/home-tab/src/lib/components/homeTabGetStarted.tsx b/libs/remix-ui/home-tab/src/lib/components/homeTabGetStarted.tsx index 1671bf26ff..ce83ef76e2 100644 --- a/libs/remix-ui/home-tab/src/lib/components/homeTabGetStarted.tsx +++ b/libs/remix-ui/home-tab/src/lib/components/homeTabGetStarted.tsx @@ -171,7 +171,7 @@ function HomeTabGetStarted({ plugin }: HomeTabGetStartedProps) { : ( + + } - + ) } diff --git a/libs/remix-ui/statusbar/src/lib/components/scamAlertStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/scamAlertStatus.tsx index d3cbce68fd..98a8b1fc4c 100644 --- a/libs/remix-ui/statusbar/src/lib/components/scamAlertStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/scamAlertStatus.tsx @@ -15,7 +15,7 @@ export default function ScamAlertStatus ({ refs, getReferenceProps }: ScamAlertS -
+
diff --git a/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx b/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx index e72bfe62b5..062424e2b2 100644 --- a/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx @@ -18,13 +18,22 @@ export default function ScamDetails ({ refs, floatStyle, scamAlerts }: ScamDetai return (
-
+
{scamAlerts && scamAlerts.map((alert, index) => ( {alert.url.length < 1 ? diff --git a/libs/remix-ui/statusbar/src/lib/remixui-statusbar-panel.tsx b/libs/remix-ui/statusbar/src/lib/remixui-statusbar-panel.tsx index 5099d31286..22b1dac390 100644 --- a/libs/remix-ui/statusbar/src/lib/remixui-statusbar-panel.tsx +++ b/libs/remix-ui/statusbar/src/lib/remixui-statusbar-panel.tsx @@ -72,25 +72,37 @@ export function RemixUIStatusBar({ statusBarPlugin }: RemixUIStatusBarProps) { {(platform !== appPlatformTypes.desktop) && showScamDetails && ( - + )}
-
- + { (platform !== appPlatformTypes.desktop) &&
+ +
} +
+
+ +
-
-
+
-
-
+
- { (platform !== appPlatformTypes.desktop) &&
- -
}