From 83f1338d18900440fc5ba58fdfae73dd4c7472e5 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 29 Oct 2024 09:46:28 +0100 Subject: [PATCH 01/82] popup panel --- apps/remix-ide/src/app.js | 5 +- .../src/app/components/popup-panel.tsx | 69 +++++++++++++++++++ .../src/app/plugins/remixAIPlugin.tsx | 2 +- .../app/src/lib/remix-app/remix-app.tsx | 1 + 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 apps/remix-ide/src/app/components/popup-panel.tsx diff --git a/apps/remix-ide/src/app.js b/apps/remix-ide/src/app.js index 796d354c5c..d9a4cf6f13 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' @@ -445,6 +446,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) @@ -452,7 +454,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) @@ -535,6 +537,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..c91ab9644c --- /dev/null +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -0,0 +1,69 @@ +import React from 'react' // eslint-disable-line +import { AbstractPanel } from './panel' +import { RemixPluginPanel } from '@remix-ui/panel' +import packageJson from '../../../../../package.json' +import { PluginViewWrapper } from '@remix-ui/helper' + +const profile = { + name: 'popupPanel', + displayName: 'Popup Panel', + description: 'Remix IDE popup panel', + version: packageJson.version, + methods: ['addView', 'removeView', 'showContent'] +} + +export class PopupPanel extends AbstractPanel { + element: HTMLDivElement + dispatch: React.Dispatch = () => {} + constructor(config) { + super(profile) + } + + setDispatch(dispatch: React.Dispatch) { + this.dispatch = dispatch + } + + 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() + } + + renderComponent() { + this.dispatch({ + plugins: this.plugins + }) + } + + render() { + return ( +
+ +
+ ) + } + + updateComponent(state: any) { + return } plugins={state.plugins} /> + } +} diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index d6d3c78a48..e307433c69 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -21,7 +21,7 @@ const profile = { 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' 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..dd8a672525 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 @@ -244,6 +244,7 @@ const RemixApp = (props: IRemixAppUi) => { }
{props.app.hiddenPanel.render()}
+
{props.app.popupPanel.render()}
{props.app.statusBar.render()}
From 6ffdb154f64fb34eb59b9b36d7c34b24ccfa6df2 Mon Sep 17 00:00:00 2001 From: lianahus Date: Mon, 4 Nov 2024 09:30:14 +0100 Subject: [PATCH 02/82] popup for ai --- .../src/app/components/popup-panel.tsx | 54 +++++++++++++++++-- .../plugins/electron/remixAIDesktopPlugin.tsx | 2 +- .../src/app/plugins/remixAIPlugin.tsx | 44 ++++++++++++++- .../remixdesktop/src/plugins/remixAIDektop.ts | 2 +- libs/remix-api/src/lib/plugins/remixai-api.ts | 1 + libs/remix-api/src/lib/remix-api.ts | 8 +++ .../panel/src/lib/plugins/remix-ui-panel.tsx | 15 ++++-- .../remix-ai/src/lib/components/Default.tsx | 4 +- .../remix-ai/src/lib/components/RemixAI.tsx | 18 +++++-- .../remix-ai/src/lib/components/color.css | 36 ++++++++++--- libs/remix-ui/statusbar/src/css/statusbar.css | 5 ++ .../statusbar/src/lib/components/aiStatus.tsx | 53 +++++++++++++++--- .../src/lib/components/scamDetails.tsx | 14 +++-- .../src/lib/remixui-statusbar-panel.tsx | 22 +++++--- libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx | 2 +- 15 files changed, 236 insertions(+), 44 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index c91ab9644c..2f0f5ef049 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -3,20 +3,26 @@ import { AbstractPanel } from './panel' import { RemixPluginPanel } from '@remix-ui/panel' import packageJson from '../../../../../package.json' import { PluginViewWrapper } from '@remix-ui/helper' +import {EventEmitter} from 'events' const profile = { name: 'popupPanel', displayName: 'Popup Panel', description: 'Remix IDE popup panel', version: packageJson.version, - methods: ['addView', 'removeView', 'showContent'] + events: ['popupPanelShown'], + methods: ['addView', 'removeView', 'showContent', 'showPopupPanel'] } export class PopupPanel extends AbstractPanel { element: HTMLDivElement dispatch: React.Dispatch = () => {} + showPanel: boolean + constructor(config) { super(profile) + this.event = new EventEmitter() + this.showPanel = true } setDispatch(dispatch: React.Dispatch) { @@ -49,21 +55,59 @@ export class PopupPanel extends AbstractPanel { this.renderComponent() } + async showPopupPanel(show) { + console.log("hide in popup-panel =", show) + this.showPanel = show + this.event.emit('popupPanelShown', show) + this.renderComponent() + } + renderComponent() { this.dispatch({ - plugins: this.plugins + plugins: this.plugins, + showPpPanel: this.showPanel }) } render() { return ( -
- +
+ {this.showPanel && }
) } updateComponent(state: any) { - return } plugins={state.plugins} /> + return ( +
+ + + + } + plugins={state.plugins} /> +
) } } diff --git a/apps/remix-ide/src/app/plugins/electron/remixAIDesktopPlugin.tsx b/apps/remix-ide/src/app/plugins/electron/remixAIDesktopPlugin.tsx index e9909ebc1f..1ead4faafd 100644 --- a/apps/remix-ide/src/app/plugins/electron/remixAIDesktopPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/electron/remixAIDesktopPlugin.tsx @@ -10,7 +10,7 @@ const desktop_profile = { description: 'RemixAI provides AI services to Remix IDE Desktop.', documentation: 'https://remix-ide.readthedocs.io/en/latest/remixai.html', icon: 'assets/img/remix-logo-blue.png', - methods: ['initializeModelBackend', 'code_completion', 'code_insertion', 'code_generation', 'code_explaining', 'error_explaining', 'solidity_answer'], + methods: ['initializeModelBackend', 'code_completion', 'code_insertion', 'code_generation', 'code_explaining', 'error_explaining', 'solidity_answer', 'toggle'], } export class remixAIDesktopPlugin extends ElectronPlugin { diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index e307433c69..eb5ef592a4 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -5,10 +5,15 @@ 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] } +enum AIChatViewState { + minimized = 0, + open = 1 +} const profile = { name: 'remixAI', @@ -16,7 +21,8 @@ const profile = { methods: ['code_generation', 'code_completion', "solidity_answer", "code_explaining", "code_insertion", "error_explaining", - "initialize", 'chatPipe', 'ProcessChatRequestBuffer', 'isChatRequestPending'], + "initialize", 'chatPipe', 'ProcessChatRequestBuffer', + 'isChatRequestPending', 'toggle'], events: [], icon: 'assets/img/remix-logo-blue.png', description: 'RemixAI provides AI services to Remix IDE.', @@ -37,6 +43,7 @@ export class RemixAIPlugin extends ViewPlugin { chatRequestBuffer: chatRequestBufferT = null agent: CodeExplainAgent useRemoteInferencer:boolean = false + dispatch: any constructor(inDesktop:boolean) { super(profile) @@ -46,6 +53,7 @@ export class RemixAIPlugin extends ViewPlugin { } onActivation(): void { + //this.renderComponent(AIChatViewState.open) if (this.isOnDesktop) { console.log('Activating RemixAIPlugin on desktop') // this.on(this.remixDesktopPluginName, 'activated', () => { @@ -59,6 +67,10 @@ export class RemixAIPlugin extends ViewPlugin { } } + toggle (open: AIChatViewState) { + this.renderComponent(open) + } + async initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean){ if (this.isOnDesktop && !this.useRemoteInferencer) { // on desktop use remote inferencer -> false @@ -201,13 +213,41 @@ export class RemixAIPlugin extends ViewPlugin { return "" } } + isChatRequestPending(){ return this.chatRequestBuffer != null } + setDispatch(dispatch) { + this.dispatch = dispatch + this.renderComponent(AIChatViewState.open) + } + + renderComponent (open: AIChatViewState) { + this.dispatch({ + plugin: this, + openState: open + }) + } + render() { + return
+ +
+ } + + updateComponent(state) { return ( - + ) } } diff --git a/apps/remixdesktop/src/plugins/remixAIDektop.ts b/apps/remixdesktop/src/plugins/remixAIDektop.ts index 6382e28bba..75cf39612c 100644 --- a/apps/remixdesktop/src/plugins/remixAIDektop.ts +++ b/apps/remixdesktop/src/plugins/remixAIDektop.ts @@ -32,7 +32,7 @@ const clientProfile: Profile = { description: 'RemixAI provides AI services to Remix IDE Desktop.', kind: '', documentation: 'https://remix-ide.readthedocs.io/en/latest/remixai.html', - methods: ['initializeModelBackend', 'code_completion', 'code_insertion', 'code_generation', 'code_explaining', 'error_explaining', 'solidity_answer'] + methods: ['initializeModelBackend', 'code_completion', 'code_insertion', 'code_generation', 'code_explaining', 'error_explaining', 'solidity_answer', 'toggle'] } class RemixAIDesktopPluginClient extends ElectronBasePluginClient { diff --git a/libs/remix-api/src/lib/plugins/remixai-api.ts b/libs/remix-api/src/lib/plugins/remixai-api.ts index 0ea1498151..799b180662 100644 --- a/libs/remix-api/src/lib/plugins/remixai-api.ts +++ b/libs/remix-api/src/lib/plugins/remixai-api.ts @@ -19,5 +19,6 @@ export interface IRemixAI { chatPipe(pipeMessage: string): Promise, ProcessChatRequestBuffer(params:IParams): Promise, initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean): Promise, + toggle(boolean) } } \ 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 75e9e6476d..0d7a8f4634 100644 --- a/libs/remix-api/src/lib/remix-api.ts +++ b/libs/remix-api/src/lib/remix-api.ts @@ -16,8 +16,15 @@ import { IMatomoApi } from "./plugins/matomo-api" import { IRemixAI } from "./plugins/remixai-api" import { IRemixAID } from "./plugins/remixAIDesktop-api" import { IDgitPlugin } from "./plugins/dgitplugin-api" +import { Api } from "@remixproject/plugin-utils"; + export interface ICustomRemixApi extends IRemixApi { + popupPanel: { + methods: ['showPopupPanel'] + events: ['popupPanelShown'] + showPopupPanel(): void + } & Api dgitApi: IGitApi dgit: IDgitPlugin config: IConfigApi @@ -37,4 +44,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/panel/src/lib/plugins/remix-ui-panel.tsx b/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx index 4e1fa59a2e..71aa3db8b0 100644 --- a/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx +++ b/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx @@ -14,16 +14,21 @@ export interface RemixPanelProps { export function RemixPluginPanel(props: RemixPanelProps) { return ( - <> +
{props.header}
- {Object.values(props.plugins).map((pluginRecord) => { - return - })} + { Object.values(props.plugins).map((pluginRecord) => { + return + }) }
- +
) } diff --git a/libs/remix-ui/remix-ai/src/lib/components/Default.tsx b/libs/remix-ui/remix-ai/src/lib/components/Default.tsx index 459797294c..1f1ce48323 100644 --- a/libs/remix-ui/remix-ai/src/lib/components/Default.tsx +++ b/libs/remix-ui/remix-ai/src/lib/components/Default.tsx @@ -42,8 +42,8 @@ export const Default = (props) => { }; ChatApi = useAiChatApi(); const conversationStarters: ConversationStarter[] = [ - { prompt: 'Explain briefly the current file in Editor', icon: ⭐️ }, - { prompt: 'Explain what is a solidity contract!' }] + { prompt: 'Explain what is a solidity contract!'}, + { prompt: 'Explain briefly the current file in Editor'}] // Define initial messages const initialMessages: ChatItem[] = [ diff --git a/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx b/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx index d55a3a9256..61b5910913 100644 --- a/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx +++ b/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx @@ -1,14 +1,22 @@ import React, { useContext } from 'react' import '../remix-ai.css' import { Default, ChatApi } from './Default' +enum AIChatViewState { + minimized = 0, + open = 1 +} +interface IRemixAITab { + plugin: any, + openState: AIChatViewState +} +export const RemixAITab = (props: IRemixAITab) => { -export const RemixAITab = (props) => { - - const plugin = props.plugin return ( <> -
- +
+
+ +
) diff --git a/libs/remix-ui/remix-ai/src/lib/components/color.css b/libs/remix-ui/remix-ai/src/lib/components/color.css index 836a05f103..40e54d438b 100644 --- a/libs/remix-ui/remix-ai/src/lib/components/color.css +++ b/libs/remix-ui/remix-ai/src/lib/components/color.css @@ -1,11 +1,32 @@ .nlux-theme-remix_ai_theme[data-color-scheme='light'] { --nlux-ChatRoom--BackgroundColor: var(--text-background); + padding-bottom: 0.1rem; } .nlux-theme-remix_ai_theme[data-color-scheme='dark'] { --nlux-ChatRoom--BackgroundColor: var(--text-background); + padding-bottom: 0.1rem; } +.nlux-launchPad-container { + padding-bottom: 2rem; +} + +.nlux-conversationStarters-container { + overflow-y: hidden; +} + +.nlux-comp-conversationStarters { + width: auto !important; + padding: 0px !important +} + +.nlux-conversationStarters-container>.nlux-comp-conversationStarters>.nlux-comp-conversationStarter { + border-width: 1px !important; + border-color: var(--text-background) !important; +} + + .nlux-theme-remix_ai_theme { /* Override top-level chat room colors */ @@ -35,9 +56,13 @@ --nlux-PromptInput-Focus-Outline--Width: 10px; --nlux-PromptInput-Max-Height: 50px; --nlux-PromptInput--BorderWidth: 0; - .nlux-comp-composer > textarea {padding: 8px;} --nlux-PromptInput--BorderRadius: 10px 0 0 10px; - --nlux-PromptInput-Height: 50px; + --nlux-PromptInput-Height: 30px; + --nlux-cvStrt--brdrWd: 0; + --nlux-cvStrt--brdClr: var(--light); + --nlux-cvStrt--brdrWd: 'hidden'; + --nlux-comp-composer > textarea {padding: 8px;} + /* Override input colors */ @@ -49,10 +74,10 @@ --nlux-Composer--Gap: 0; /* Override submit button colors */ - --nlux-SubmitButton--BackgroundColor: var(--primary); - --nlux-SubmitButton-Active--BackgroundColor:var(--primary); + --nlux-SubmitButton--BackgroundColor: var(--light); + --nlux-SubmitButton-Active--BackgroundColor:var(--light); --nlux-SubmitButton-Disabled--BackgroundColor: var(--dark); - --nlux-SubmitButton-Active--TextColor: var(--text); + --nlux-SubmitButton-Active--TextColor: var(--primary); --nlux-SubmitButton-Disabled--TextColor: var(--text); /** Inline code in markdown */ @@ -61,7 +86,6 @@ --nlux-InlineCode--Padding: 0 2px; --nlux-InlineCode--FontSize: 14px; - /*code block */ --nlux-CodeBlock-CopyButton--BackgroundColor: var(--bg-text); --nlux-CodeBlock-CopyButton--TextColor: var(--text); diff --git a/libs/remix-ui/statusbar/src/css/statusbar.css b/libs/remix-ui/statusbar/src/css/statusbar.css index 4792ca77f3..30a5712f89 100644 --- a/libs/remix-ui/statusbar/src/css/statusbar.css +++ b/libs/remix-ui/statusbar/src/css/statusbar.css @@ -1,4 +1,9 @@ +.remixui_statusbar_gitstatus { + position: relative; + left: 20rem; +} + .remixui_statusbar_gitstatus .remixui_statusbar_gitstatus:hover { cursor: pointer; diff --git a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx index fc6d774ce4..d476fba092 100644 --- a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx @@ -12,12 +12,24 @@ interface AIStatusProps { export default function AIStatus(props: AIStatusProps) { const [copilotActive, setCopilotActive] = useState(false) + const [expandAIChat, setExpandAIChat] = useState(true) + useEffect(() => { + const popupPanelListener = async (show) => { + setTimeout(() => setExpandAIChat(show), 0); + }; + + props.plugin.on('popupPanel', 'popupPanelShown', popupPanelListener) + const run = async () => { const aiActivate = await props.plugin.call('settings', 'get', 'settings/copilot/suggest/activate') setCopilotActive(aiActivate) } run() + + return () => { + props.plugin.off('popupPanel', 'popupPanelShown') + } }, []) useEffect(() => { @@ -29,15 +41,42 @@ export default function AIStatus(props: AIStatusProps) { } run() }, [props.plugin.isAiActive, props.plugin.isAiActive]) + return ( - -
- +
+ + { + await props.plugin.call('settings' as any, 'updateCopilotChoice', !copilotActive) + }} + > {copilotActive === false ? 'RemixAI Copilot (disabled)' : 'RemixAI Copilot (enabled)'} + +
+
- +
) -} +} \ No newline at end of file diff --git a/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx b/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx index e72bfe62b5..9c9193b933 100644 --- a/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx @@ -18,13 +18,21 @@ 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..cfd5caf99c 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,35 @@ export function RemixUIStatusBar({ statusBarPlugin }: RemixUIStatusBarProps) { {(platform !== appPlatformTypes.desktop) && showScamDetails && ( - + )}
+ { (platform !== appPlatformTypes.desktop) &&
+ +
}
-
-
- { (platform !== appPlatformTypes.desktop) &&
- -
}
diff --git a/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx b/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx index bfa136f185..05596f3ee6 100644 --- a/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx +++ b/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx @@ -261,7 +261,7 @@ export const TabsUI = (props: TabsUIProps) => { methods: ['code_generation', 'code_completion', "solidity_answer", "code_explaining", "code_insertion", "error_explaining", - "initialize", 'chatPipe', 'ProcessChatRequestBuffer', 'isChatRequestPending'], + "initialize", 'chatPipe', 'ProcessChatRequestBuffer', 'isChatRequestPending', 'toggle'], events: [], icon: 'assets/img/remix-logo-blue.png', description: 'RemixAI provides AI services to Remix IDE.', From 0dfc70e7a1a820cde282d22a342fa2e1f989fb15 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 12:50:55 +0100 Subject: [PATCH 03/82] first fixes --- .../src/app/components/popup-panel.tsx | 49 +++++++++++-------- .../app/src/lib/remix-app/actions/app.ts | 2 + .../app/src/lib/remix-app/interface/index.ts | 1 + .../app/src/lib/remix-app/reducer/app.ts | 47 ++++++++++-------- .../app/src/lib/remix-app/state/app.ts | 3 +- .../src/lib/components/PluginViewWrapper.tsx | 14 +++++- .../panel/src/lib/plugins/remix-ui-panel.tsx | 4 +- .../statusbar/src/lib/components/aiStatus.tsx | 10 +--- 8 files changed, 77 insertions(+), 53 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index 2f0f5ef049..8388e8a83f 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -1,9 +1,11 @@ import React from 'react' // eslint-disable-line import { AbstractPanel } from './panel' -import { RemixPluginPanel } from '@remix-ui/panel' +import { PluginRecord, RemixPluginPanel } from '@remix-ui/panel' import packageJson from '../../../../../package.json' import { PluginViewWrapper } from '@remix-ui/helper' -import {EventEmitter} from 'events' +import { EventEmitter } from 'events' +import { AppState } from 'libs/remix-ui/app/src/lib/remix-app/interface' +import { AppAction, appActionTypes } from '@remix-ui/app' const profile = { name: 'popupPanel', @@ -13,22 +15,28 @@ const profile = { events: ['popupPanelShown'], methods: ['addView', 'removeView', 'showContent', 'showPopupPanel'] } +type popupPanelState = { + plugins: Record +} export class PopupPanel extends AbstractPanel { element: HTMLDivElement - dispatch: React.Dispatch = () => {} - showPanel: boolean + dispatch: React.Dispatch = () => { } + appStateDispatch: React.Dispatch = () => { } constructor(config) { super(profile) this.event = new EventEmitter() - this.showPanel = true } setDispatch(dispatch: React.Dispatch) { this.dispatch = dispatch } + setAppStateDispatch(appStateDispatch: React.Dispatch) { + this.appStateDispatch = appStateDispatch + } + onActivation() { this.renderComponent() } @@ -56,23 +64,31 @@ export class PopupPanel extends AbstractPanel { } async showPopupPanel(show) { - console.log("hide in popup-panel =", show) - this.showPanel = show - this.event.emit('popupPanelShown', show) + + this.appStateDispatch({ + type: appActionTypes.setShowPopupPanel, + payload: show + }) this.renderComponent() } renderComponent() { this.dispatch({ - plugins: this.plugins, - showPpPanel: this.showPanel + plugins: this.plugins }) } render() { + return ( + + ) + } + + updateComponent(state: popupPanelState & Partial) { + console.log("state in updateComponent =", state) return (
- {this.showPanel && } -
- ) - } - - updateComponent(state: any) { - return ( -
@@ -108,6 +116,7 @@ export class PopupPanel extends AbstractPanel { } plugins={state.plugins} /> -
) +
+ ) } } 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..5abe07626c 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 @@ -3,29 +3,36 @@ import { AppState } from "../interface"; export const appReducer = (state: AppState, action: AppAction): AppState => { switch (action.type) { - case appActionTypes.setGitHubUser: { - return { - ...state, - gitHubUser: action.payload + case appActionTypes.setGitHubUser: { + return { + ...state, + gitHubUser: action.payload + } } - } - case appActionTypes.setCurrentBranch: { - return { - ...state, - currentBranch: action.payload + case appActionTypes.setCurrentBranch: { + return { + ...state, + currentBranch: action.payload + } } - } - case appActionTypes.setNeedsGitInit: { - return { - ...state, - needsGitInit: action.payload + case appActionTypes.setNeedsGitInit: { + return { + ...state, + needsGitInit: action.payload + } } - } - case appActionTypes.setCanUseGit: { - return { - ...state, - canUseGit: action.payload + case appActionTypes.setCanUseGit: { + return { + ...state, + 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/state/app.ts b/libs/remix-ui/app/src/lib/remix-app/state/app.ts index 8086b75c9c..2778233a09 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: true } \ 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..168f1095f2 100644 --- a/libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx +++ b/libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx @@ -1,4 +1,5 @@ -import React from 'react' +import { AppContext } from '@remix-ui/app' +import React, { useContext } from 'react' import { useEffect, useState } from 'react' interface IPluginViewWrapperProps { @@ -7,12 +8,21 @@ interface IPluginViewWrapperProps { export const PluginViewWrapper = (props: IPluginViewWrapperProps) => { const [state, setState] = useState(null) + const appContext = useContext(AppContext) useEffect(() => { if (props.plugin.setDispatch) { props.plugin.setDispatch(setState) } + if(props.plugin.setAppStateDispatch) { + props.plugin.setAppStateDispatch(appContext.appStateDispatch) + } }, []) - return <>{state ? <>{props.plugin.updateComponent(state)} : <>} + return <>{state ? <>{props.plugin.updateComponent( + { + ...state, + ...appContext['appState'] + })} + : <>} } diff --git a/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx b/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx index 71aa3db8b0..ba6c494a04 100644 --- a/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx +++ b/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx @@ -14,7 +14,7 @@ export interface RemixPanelProps { export function RemixPluginPanel(props: RemixPanelProps) { return ( -
+ <> {props.header}
@@ -28,7 +28,7 @@ export function RemixPluginPanel(props: RemixPanelProps) { }) }
-
+ ) } diff --git a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx index d476fba092..55b4fbf43d 100644 --- a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx @@ -12,14 +12,8 @@ interface AIStatusProps { export default function AIStatus(props: AIStatusProps) { const [copilotActive, setCopilotActive] = useState(false) - const [expandAIChat, setExpandAIChat] = useState(true) useEffect(() => { - const popupPanelListener = async (show) => { - setTimeout(() => setExpandAIChat(show), 0); - }; - - props.plugin.on('popupPanel', 'popupPanelShown', popupPanelListener) const run = async () => { const aiActivate = await props.plugin.call('settings', 'get', 'settings/copilot/suggest/activate') @@ -71,10 +65,10 @@ export default function AIStatus(props: AIStatusProps) { }} className='p-1 alert alert-info border border-info fa-solid fa-message-bot' onClick={async () => { - await props.plugin.call('popupPanel', 'showPopupPanel', !expandAIChat) + await props.plugin.call('popupPanel', 'showPopupPanel', true) }} > - {expandAIChat ? '1' : '0'} +
From f866b4d9cbfce98ebfc7239b0dc83dd0541cb879 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 13:06:24 +0100 Subject: [PATCH 04/82] lianas css --- apps/remix-ide/src/app/components/popup-panel.tsx | 2 +- libs/remix-ui/statusbar/src/css/statusbar.css | 7 ++----- .../statusbar/src/lib/remixui-statusbar-panel.tsx | 10 ++++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index 8388e8a83f..2712b0725d 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -97,7 +97,7 @@ export class PopupPanel extends AbstractPanel { position: 'fixed', bottom: '2rem', right: '3.5rem', - zIndex: 2000, + zIndex: 200, boxShadow: '3px 3px var(--secondary), -0.1em 0 1.4em var(--secondary)' }} data-id="popupPanelPluginsContainer" diff --git a/libs/remix-ui/statusbar/src/css/statusbar.css b/libs/remix-ui/statusbar/src/css/statusbar.css index 30a5712f89..11ee870603 100644 --- a/libs/remix-ui/statusbar/src/css/statusbar.css +++ b/libs/remix-ui/statusbar/src/css/statusbar.css @@ -1,9 +1,6 @@ - -.remixui_statusbar_gitstatus { - position: relative; - left: 20rem; +.remixui_statusbar { + white-space: nowrap; } - .remixui_statusbar_gitstatus .remixui_statusbar_gitstatus:hover { cursor: pointer; 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 cfd5caf99c..a295239a10 100644 --- a/libs/remix-ui/statusbar/src/lib/remixui-statusbar-panel.tsx +++ b/libs/remix-ui/statusbar/src/lib/remixui-statusbar-panel.tsx @@ -91,13 +91,15 @@ export function RemixUIStatusBar({ statusBarPlugin }: RemixUIStatusBarProps) { { (platform !== appPlatformTypes.desktop) &&
} -
- +
+
+ +
-
+
-
+
From a1ed9fd1660cccf50b1a1236e9c36184c7306b45 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 13:36:36 +0100 Subject: [PATCH 05/82] fix state --- .../src/app/components/popup-panel.tsx | 2 +- .../src/app/plugins/remixAIPlugin.tsx | 17 ++++---------- .../src/lib/plugins/popuppanel-api.ts | 10 ++++++++ libs/remix-api/src/lib/plugins/remixai-api.ts | 1 - .../src/lib/plugins/remixaiDesktop-api.ts | 23 ------------------- libs/remix-api/src/lib/remix-api.ts | 7 ++---- .../remix-ai/src/lib/components/RemixAI.tsx | 6 +---- .../statusbar/src/lib/components/aiStatus.tsx | 13 ++++++----- 8 files changed, 25 insertions(+), 54 deletions(-) create mode 100644 libs/remix-api/src/lib/plugins/popuppanel-api.ts delete mode 100644 libs/remix-api/src/lib/plugins/remixaiDesktop-api.ts diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index 2712b0725d..3b9af9ff23 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -12,7 +12,7 @@ const profile = { displayName: 'Popup Panel', description: 'Remix IDE popup panel', version: packageJson.version, - events: ['popupPanelShown'], + events: [], methods: ['addView', 'removeView', 'showContent', 'showPopupPanel'] } type popupPanelState = { diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index eb5ef592a4..5bb7ac7e93 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -10,10 +10,6 @@ import { PluginViewWrapper } from '@remix-ui/helper' type chatRequestBufferT = { [key in keyof T]: T[key] } -enum AIChatViewState { - minimized = 0, - open = 1 -} const profile = { name: 'remixAI', @@ -53,7 +49,7 @@ export class RemixAIPlugin extends ViewPlugin { } onActivation(): void { - //this.renderComponent(AIChatViewState.open) + if (this.isOnDesktop) { console.log('Activating RemixAIPlugin on desktop') // this.on(this.remixDesktopPluginName, 'activated', () => { @@ -66,10 +62,6 @@ export class RemixAIPlugin extends ViewPlugin { this.initialize() } } - - toggle (open: AIChatViewState) { - this.renderComponent(open) - } async initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean){ if (this.isOnDesktop && !this.useRemoteInferencer) { @@ -220,13 +212,12 @@ export class RemixAIPlugin extends ViewPlugin { setDispatch(dispatch) { this.dispatch = dispatch - this.renderComponent(AIChatViewState.open) + this.renderComponent() } - renderComponent (open: AIChatViewState) { + renderComponent () { this.dispatch({ plugin: this, - openState: open }) } @@ -247,7 +238,7 @@ export class RemixAIPlugin extends ViewPlugin { updateComponent(state) { return ( - + ) } } 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/remixai-api.ts b/libs/remix-api/src/lib/plugins/remixai-api.ts index 799b180662..0ea1498151 100644 --- a/libs/remix-api/src/lib/plugins/remixai-api.ts +++ b/libs/remix-api/src/lib/plugins/remixai-api.ts @@ -19,6 +19,5 @@ export interface IRemixAI { chatPipe(pipeMessage: string): Promise, ProcessChatRequestBuffer(params:IParams): Promise, initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean): Promise, - toggle(boolean) } } \ No newline at end of file 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 0d7a8f4634..5b400d445f 100644 --- a/libs/remix-api/src/lib/remix-api.ts +++ b/libs/remix-api/src/lib/remix-api.ts @@ -17,14 +17,11 @@ import { IRemixAI } from "./plugins/remixai-api" import { IRemixAID } from "./plugins/remixAIDesktop-api" import { IDgitPlugin } from "./plugins/dgitplugin-api" import { Api } from "@remixproject/plugin-utils"; +import { IPopupPanelAPI } from "./plugins/popuppanel-api" export interface ICustomRemixApi extends IRemixApi { - popupPanel: { - methods: ['showPopupPanel'] - events: ['popupPanelShown'] - showPopupPanel(): void - } & Api + popupPanel: IPopupPanelAPI dgitApi: IGitApi dgit: IDgitPlugin config: IConfigApi diff --git a/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx b/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx index 61b5910913..a5aaba4a7d 100644 --- a/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx +++ b/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx @@ -1,13 +1,9 @@ import React, { useContext } from 'react' import '../remix-ai.css' import { Default, ChatApi } from './Default' -enum AIChatViewState { - minimized = 0, - open = 1 -} + interface IRemixAITab { plugin: any, - openState: AIChatViewState } export const RemixAITab = (props: IRemixAITab) => { diff --git a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx index 55b4fbf43d..48864811a2 100644 --- a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx @@ -1,7 +1,8 @@ // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries import { StatusBar } from 'apps/remix-ide/src/app/components/status-bar' import { CustomTooltip } from '@remix-ui/helper' -import React, { useEffect, useState } from 'react' +import React, { useContext, useEffect, useState } from 'react' +import { appActionTypes, AppContext } from '@remix-ui/app' interface AIStatusProps { plugin: StatusBar @@ -12,7 +13,7 @@ interface AIStatusProps { export default function AIStatus(props: AIStatusProps) { const [copilotActive, setCopilotActive] = useState(false) - + const appContext = useContext(AppContext) useEffect(() => { const run = async () => { @@ -21,9 +22,6 @@ export default function AIStatus(props: AIStatusProps) { } run() - return () => { - props.plugin.off('popupPanel', 'popupPanelShown') - } }, []) useEffect(() => { @@ -65,7 +63,10 @@ export default function AIStatus(props: AIStatusProps) { }} className='p-1 alert alert-info border border-info fa-solid fa-message-bot' onClick={async () => { - await props.plugin.call('popupPanel', 'showPopupPanel', true) + appContext.appStateDispatch({ + type: appActionTypes.setShowPopupPanel, + payload: !appContext.appState.showPopupPanel + }) }} > From 452ae03b88a25e9aed255c29f5bf72c66e35f8e3 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 13:46:01 +0100 Subject: [PATCH 06/82] clean up --- .../src/app/components/popup-panel.tsx | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index 3b9af9ff23..f45a9f3d3f 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -23,7 +23,7 @@ export class PopupPanel extends AbstractPanel { element: HTMLDivElement dispatch: React.Dispatch = () => { } appStateDispatch: React.Dispatch = () => { } - + constructor(config) { super(profile) this.event = new EventEmitter() @@ -64,7 +64,7 @@ export class PopupPanel extends AbstractPanel { } async showPopupPanel(show) { - + this.appStateDispatch({ type: appActionTypes.setShowPopupPanel, payload: show @@ -85,7 +85,6 @@ export class PopupPanel extends AbstractPanel { } updateComponent(state: popupPanelState & Partial) { - console.log("state in updateComponent =", state) return (
- - - - } - plugins={state.plugins} /> +
+ + + + } + plugins={state.plugins} /> +
) } From 78d4ce895c4b8fef4ede89430c1ae5af8f875d1f Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 13:49:45 +0100 Subject: [PATCH 07/82] linting --- .../src/app/components/popup-panel.tsx | 4 +- .../src/app/plugins/remixAIPlugin.tsx | 2 +- libs/remix-ui/app/src/index.ts | 2 +- .../app/src/lib/remix-app/reducer/app.ts | 50 +++++++++---------- .../src/lib/components/PluginViewWrapper.tsx | 2 +- .../remix-ai/src/lib/components/Default.tsx | 4 +- .../statusbar/src/lib/components/aiStatus.tsx | 6 +-- .../src/lib/remixui-statusbar-panel.tsx | 4 +- 8 files changed, 37 insertions(+), 37 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index f45a9f3d3f..363d89d2cf 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -4,8 +4,8 @@ import { PluginRecord, RemixPluginPanel } from '@remix-ui/panel' import packageJson from '../../../../../package.json' import { PluginViewWrapper } from '@remix-ui/helper' import { EventEmitter } from 'events' -import { AppState } from 'libs/remix-ui/app/src/lib/remix-app/interface' -import { AppAction, appActionTypes } from '@remix-ui/app' + +import { AppAction, appActionTypes, AppState } from '@remix-ui/app' const profile = { name: 'popupPanel', diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index 5bb7ac7e93..34a3a15298 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -62,7 +62,7 @@ export class RemixAIPlugin extends ViewPlugin { this.initialize() } } - + async initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean){ if (this.isOnDesktop && !this.useRemoteInferencer) { // on desktop use remote inferencer -> false 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/reducer/app.ts b/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts index 5abe07626c..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 @@ -3,36 +3,36 @@ import { AppState } from "../interface"; export const appReducer = (state: AppState, action: AppAction): AppState => { switch (action.type) { - case appActionTypes.setGitHubUser: { - return { - ...state, - gitHubUser: action.payload - } + case appActionTypes.setGitHubUser: { + return { + ...state, + gitHubUser: action.payload } - case appActionTypes.setCurrentBranch: { - return { - ...state, - currentBranch: action.payload - } + } + case appActionTypes.setCurrentBranch: { + return { + ...state, + currentBranch: action.payload } - case appActionTypes.setNeedsGitInit: { - return { - ...state, - needsGitInit: action.payload - } + } + case appActionTypes.setNeedsGitInit: { + return { + ...state, + needsGitInit: action.payload } - case appActionTypes.setCanUseGit: { - return { - ...state, - canUseGit: action.payload - } + } + case appActionTypes.setCanUseGit: { + return { + ...state, + canUseGit: action.payload } + } - case appActionTypes.setShowPopupPanel: { - return { - ...state, - showPopupPanel: action.payload - } + case appActionTypes.setShowPopupPanel: { + return { + ...state, + showPopupPanel: action.payload } } + } } \ 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 168f1095f2..c29f58d4dc 100644 --- a/libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx +++ b/libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx @@ -14,7 +14,7 @@ export const PluginViewWrapper = (props: IPluginViewWrapperProps) => { if (props.plugin.setDispatch) { props.plugin.setDispatch(setState) } - if(props.plugin.setAppStateDispatch) { + if (props.plugin.setAppStateDispatch) { props.plugin.setAppStateDispatch(appContext.appStateDispatch) } }, []) diff --git a/libs/remix-ui/remix-ai/src/lib/components/Default.tsx b/libs/remix-ui/remix-ai/src/lib/components/Default.tsx index 1f1ce48323..bdeaacbea7 100644 --- a/libs/remix-ui/remix-ai/src/lib/components/Default.tsx +++ b/libs/remix-ui/remix-ai/src/lib/components/Default.tsx @@ -42,8 +42,8 @@ export const Default = (props) => { }; ChatApi = useAiChatApi(); const conversationStarters: ConversationStarter[] = [ - { prompt: 'Explain what is a solidity contract!'}, - { prompt: 'Explain briefly the current file in Editor'}] + { prompt: 'Explain what is a solidity contract!' }, + { prompt: 'Explain briefly the current file in Editor' }] // Define initial messages const initialMessages: ChatItem[] = [ diff --git a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx index 48864811a2..53f3de6325 100644 --- a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx @@ -15,13 +15,13 @@ export default function AIStatus(props: AIStatusProps) { const [copilotActive, setCopilotActive] = useState(false) const appContext = useContext(AppContext) useEffect(() => { - + const run = async () => { const aiActivate = await props.plugin.call('settings', 'get', 'settings/copilot/suggest/activate') setCopilotActive(aiActivate) } run() - + }, []) useEffect(() => { @@ -40,7 +40,7 @@ export default function AIStatus(props: AIStatusProps) { tooltipText={copilotActive ? "Disable RemixAI Copilot" : "Enable RemixAI Copilot. Switch to .sol file to try it."} > { await props.plugin.call('settings' as any, 'updateCopilotChoice', !copilotActive) 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 a295239a10..22b1dac390 100644 --- a/libs/remix-ui/statusbar/src/lib/remixui-statusbar-panel.tsx +++ b/libs/remix-ui/statusbar/src/lib/remixui-statusbar-panel.tsx @@ -89,8 +89,8 @@ export function RemixUIStatusBar({ statusBarPlugin }: RemixUIStatusBarProps) { )}
{ (platform !== appPlatformTypes.desktop) &&
- -
} + +
}
From 87f2a7926310427a080a4e8a374ee28f2b3b26ad Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 14:07:23 +0100 Subject: [PATCH 08/82] hide popup --- libs/remix-ui/app/src/lib/remix-app/state/app.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2778233a09..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 @@ -6,5 +6,5 @@ export const appInitialState: AppState = { currentBranch: null, needsGitInit: true, canUseGit: false, - showPopupPanel: true + showPopupPanel: false } \ No newline at end of file From 45025f0e6f84b46dacf81632175d06a96be77483 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 14:32:47 +0100 Subject: [PATCH 09/82] hidescam button --- apps/remix-ide-e2e/src/helpers/init.ts | 3 +++ libs/remix-ui/statusbar/src/lib/components/scamAlertStatus.tsx | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index f30ce3dd62..cd6bdb86af 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -27,6 +27,8 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url }) .verifyLoad() .enableClipBoard() + .waitForElementVisible('*[data-id="hTScamAlertButton"]') + .click('*[data-id="hTScamAlertButton"]') .perform((done) => { browser.execute(function () { // hide tooltips function addStyle(styleString) { @@ -76,6 +78,7 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url function initModules(browser: NightwatchBrowser, callback: VoidFunction) { browser + .pause() .click('[data-id="verticalIconsKindpluginManager"]') .scrollAndClick('[data-id="pluginManagerComponentActivateButtonsolidityStaticAnalysis"]') .scrollAndClick('[data-id="pluginManagerComponentActivateButtondebugger"]') 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 -
+
From 624ac09b6ba633040fd5852c61b6734fb7c6f31d Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 15:16:14 +0100 Subject: [PATCH 10/82] fix bugs --- .../src/app/components/popup-panel.tsx | 6 +-- .../src/lib/components/PluginViewWrapper.tsx | 37 +++++++++++-------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index 363d89d2cf..b85c3eb8a8 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -80,14 +80,14 @@ export class PopupPanel extends AbstractPanel { render() { return ( - + ) } - updateComponent(state: popupPanelState & Partial) { + updateComponent(state: popupPanelState, appState: Partial) { return (
{ +export const PluginViewWrapper = ({ plugin, useAppContext = false }: IPluginViewWrapperProps) => { const [state, setState] = useState(null) - const appContext = useContext(AppContext) + const appContext = useAppContext ? useContext(AppContext) : null useEffect(() => { - if (props.plugin.setDispatch) { - props.plugin.setDispatch(setState) + if (plugin.setDispatch) { + plugin.setDispatch(setState) } - if (props.plugin.setAppStateDispatch) { - props.plugin.setAppStateDispatch(appContext.appStateDispatch) + if (useAppContext && appContext.appStateDispatch && plugin.setAppStateDispatch) { + plugin.setAppStateDispatch(appContext.appStateDispatch) } - }, []) + }, [plugin]) - return <>{state ? <>{props.plugin.updateComponent( - { - ...state, - ...appContext['appState'] - })} - : <>} + if (useAppContext && appContext && appContext.appState) { + return ( + <> + {state ? <>{plugin.updateComponent(state, appContext.appState)} : <>} + + ) + } + + return ( + <> + {state ? <>{plugin.updateComponent(state)} : <>} + + ) } From 5ed722e0ff6c99c0b41abe38ff55d569572df12a Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 15:31:20 +0100 Subject: [PATCH 11/82] init --- apps/remix-ide-e2e/src/helpers/init.ts | 3 ++- libs/remix-ui/app/src/lib/remix-app/state/app.ts | 2 +- libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index cd6bdb86af..a6c303f32d 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -29,6 +29,8 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url .enableClipBoard() .waitForElementVisible('*[data-id="hTScamAlertButton"]') .click('*[data-id="hTScamAlertButton"]') + .waitForElementVisible('*[data-id="aiStatusButton"]') + .click('*[data-id="aiStatusButton"]') .perform((done) => { browser.execute(function () { // hide tooltips function addStyle(styleString) { @@ -78,7 +80,6 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url function initModules(browser: NightwatchBrowser, callback: VoidFunction) { browser - .pause() .click('[data-id="verticalIconsKindpluginManager"]') .scrollAndClick('[data-id="pluginManagerComponentActivateButtonsolidityStaticAnalysis"]') .scrollAndClick('[data-id="pluginManagerComponentActivateButtondebugger"]') 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 708b22301a..2778233a09 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 @@ -6,5 +6,5 @@ export const appInitialState: AppState = { currentBranch: null, needsGitInit: true, canUseGit: false, - showPopupPanel: false + showPopupPanel: true } \ No newline at end of file diff --git a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx index 53f3de6325..bfdf3f96bb 100644 --- a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx @@ -61,6 +61,7 @@ export default function AIStatus(props: AIStatusProps) { color: 'var(--ai)', boxShadow: '3px 3px var(--secondary), -0.1em 0 1.4em var(--secondary)' }} + data-id="aiStatusButton" className='p-1 alert alert-info border border-info fa-solid fa-message-bot' onClick={async () => { appContext.appStateDispatch({ From 925bfa4e6e31db3bcdefb80e9bee1eda4ae978e4 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 15:58:48 +0100 Subject: [PATCH 12/82] hidescamdetails --- apps/remix-ide-e2e/src/commands/hideToolTips.ts | 5 ++++- apps/remix-ide-e2e/src/helpers/init.ts | 5 +++-- libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) 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/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index a6c303f32d..5954ce7b38 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -27,8 +27,6 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url }) .verifyLoad() .enableClipBoard() - .waitForElementVisible('*[data-id="hTScamAlertButton"]') - .click('*[data-id="hTScamAlertButton"]') .waitForElementVisible('*[data-id="aiStatusButton"]') .click('*[data-id="aiStatusButton"]') .perform((done) => { @@ -43,6 +41,9 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url .popover { display:none !important; } + #scamDetails { + display:none !important; + } `); }, [], done()) }) diff --git a/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx b/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx index 9c9193b933..6a3108b313 100644 --- a/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx @@ -18,6 +18,7 @@ export default function ScamDetails ({ refs, floatStyle, scamAlerts }: ScamDetai return (
Date: Mon, 4 Nov 2024 16:49:58 +0100 Subject: [PATCH 13/82] hide popup panel --- apps/remix-ide-e2e/src/helpers/init.ts | 2 -- libs/remix-ui/app/src/lib/remix-app/state/app.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index 5954ce7b38..67e8f1a8fc 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -27,8 +27,6 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url }) .verifyLoad() .enableClipBoard() - .waitForElementVisible('*[data-id="aiStatusButton"]') - .click('*[data-id="aiStatusButton"]') .perform((done) => { browser.execute(function () { // hide tooltips function addStyle(styleString) { 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 2778233a09..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 @@ -6,5 +6,5 @@ export const appInitialState: AppState = { currentBranch: null, needsGitInit: true, canUseGit: false, - showPopupPanel: true + showPopupPanel: false } \ No newline at end of file From da9549b35e0d6d34417633c1ea0e2e2bac0ac2f5 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 16:59:59 +0100 Subject: [PATCH 14/82] hide scam --- apps/remix-ide-e2e/src/commands/refreshPage.ts | 3 +++ 1 file changed, 3 insertions(+) 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()) }) From 73adade3383b1fa5c873e1eb43233efee5f4e6bb Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 29 Oct 2024 09:46:28 +0100 Subject: [PATCH 15/82] popup panel --- apps/remix-ide/src/app.js | 5 +- .../src/app/components/popup-panel.tsx | 69 +++++++++++++++++++ .../src/app/plugins/remixAIPlugin.tsx | 2 +- .../app/src/lib/remix-app/remix-app.tsx | 1 + 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 apps/remix-ide/src/app/components/popup-panel.tsx 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..c91ab9644c --- /dev/null +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -0,0 +1,69 @@ +import React from 'react' // eslint-disable-line +import { AbstractPanel } from './panel' +import { RemixPluginPanel } from '@remix-ui/panel' +import packageJson from '../../../../../package.json' +import { PluginViewWrapper } from '@remix-ui/helper' + +const profile = { + name: 'popupPanel', + displayName: 'Popup Panel', + description: 'Remix IDE popup panel', + version: packageJson.version, + methods: ['addView', 'removeView', 'showContent'] +} + +export class PopupPanel extends AbstractPanel { + element: HTMLDivElement + dispatch: React.Dispatch = () => {} + constructor(config) { + super(profile) + } + + setDispatch(dispatch: React.Dispatch) { + this.dispatch = dispatch + } + + 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() + } + + renderComponent() { + this.dispatch({ + plugins: this.plugins + }) + } + + render() { + return ( +
+ +
+ ) + } + + updateComponent(state: any) { + return } plugins={state.plugins} /> + } +} diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index d6d3c78a48..e307433c69 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -21,7 +21,7 @@ const profile = { 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' 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..dd8a672525 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 @@ -244,6 +244,7 @@ const RemixApp = (props: IRemixAppUi) => { }
{props.app.hiddenPanel.render()}
+
{props.app.popupPanel.render()}
{props.app.statusBar.render()}
From 13ef8733823c203b9e0a1ea26faaca2494108984 Mon Sep 17 00:00:00 2001 From: lianahus Date: Mon, 4 Nov 2024 09:30:14 +0100 Subject: [PATCH 16/82] popup for ai --- .../src/app/components/popup-panel.tsx | 54 +++++++++++++++++-- .../plugins/electron/remixAIDesktopPlugin.tsx | 2 +- .../src/app/plugins/remixAIPlugin.tsx | 44 ++++++++++++++- .../remixdesktop/src/plugins/remixAIDektop.ts | 2 +- libs/remix-api/src/lib/plugins/remixai-api.ts | 1 + libs/remix-api/src/lib/remix-api.ts | 8 +++ .../panel/src/lib/plugins/remix-ui-panel.tsx | 15 ++++-- .../remix-ai/src/lib/components/Default.tsx | 4 +- .../remix-ai/src/lib/components/RemixAI.tsx | 18 +++++-- .../remix-ai/src/lib/components/color.css | 36 ++++++++++--- libs/remix-ui/statusbar/src/css/statusbar.css | 5 ++ .../statusbar/src/lib/components/aiStatus.tsx | 53 +++++++++++++++--- .../src/lib/components/scamDetails.tsx | 14 +++-- .../src/lib/remixui-statusbar-panel.tsx | 22 +++++--- libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx | 2 +- 15 files changed, 236 insertions(+), 44 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index c91ab9644c..2f0f5ef049 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -3,20 +3,26 @@ import { AbstractPanel } from './panel' import { RemixPluginPanel } from '@remix-ui/panel' import packageJson from '../../../../../package.json' import { PluginViewWrapper } from '@remix-ui/helper' +import {EventEmitter} from 'events' const profile = { name: 'popupPanel', displayName: 'Popup Panel', description: 'Remix IDE popup panel', version: packageJson.version, - methods: ['addView', 'removeView', 'showContent'] + events: ['popupPanelShown'], + methods: ['addView', 'removeView', 'showContent', 'showPopupPanel'] } export class PopupPanel extends AbstractPanel { element: HTMLDivElement dispatch: React.Dispatch = () => {} + showPanel: boolean + constructor(config) { super(profile) + this.event = new EventEmitter() + this.showPanel = true } setDispatch(dispatch: React.Dispatch) { @@ -49,21 +55,59 @@ export class PopupPanel extends AbstractPanel { this.renderComponent() } + async showPopupPanel(show) { + console.log("hide in popup-panel =", show) + this.showPanel = show + this.event.emit('popupPanelShown', show) + this.renderComponent() + } + renderComponent() { this.dispatch({ - plugins: this.plugins + plugins: this.plugins, + showPpPanel: this.showPanel }) } render() { return ( -
- +
+ {this.showPanel && }
) } updateComponent(state: any) { - return } plugins={state.plugins} /> + return ( +
+ + + + } + plugins={state.plugins} /> +
) } } diff --git a/apps/remix-ide/src/app/plugins/electron/remixAIDesktopPlugin.tsx b/apps/remix-ide/src/app/plugins/electron/remixAIDesktopPlugin.tsx index e9909ebc1f..1ead4faafd 100644 --- a/apps/remix-ide/src/app/plugins/electron/remixAIDesktopPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/electron/remixAIDesktopPlugin.tsx @@ -10,7 +10,7 @@ const desktop_profile = { description: 'RemixAI provides AI services to Remix IDE Desktop.', documentation: 'https://remix-ide.readthedocs.io/en/latest/remixai.html', icon: 'assets/img/remix-logo-blue.png', - methods: ['initializeModelBackend', 'code_completion', 'code_insertion', 'code_generation', 'code_explaining', 'error_explaining', 'solidity_answer'], + methods: ['initializeModelBackend', 'code_completion', 'code_insertion', 'code_generation', 'code_explaining', 'error_explaining', 'solidity_answer', 'toggle'], } export class remixAIDesktopPlugin extends ElectronPlugin { diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index e307433c69..eb5ef592a4 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -5,10 +5,15 @@ 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] } +enum AIChatViewState { + minimized = 0, + open = 1 +} const profile = { name: 'remixAI', @@ -16,7 +21,8 @@ const profile = { methods: ['code_generation', 'code_completion', "solidity_answer", "code_explaining", "code_insertion", "error_explaining", - "initialize", 'chatPipe', 'ProcessChatRequestBuffer', 'isChatRequestPending'], + "initialize", 'chatPipe', 'ProcessChatRequestBuffer', + 'isChatRequestPending', 'toggle'], events: [], icon: 'assets/img/remix-logo-blue.png', description: 'RemixAI provides AI services to Remix IDE.', @@ -37,6 +43,7 @@ export class RemixAIPlugin extends ViewPlugin { chatRequestBuffer: chatRequestBufferT = null agent: CodeExplainAgent useRemoteInferencer:boolean = false + dispatch: any constructor(inDesktop:boolean) { super(profile) @@ -46,6 +53,7 @@ export class RemixAIPlugin extends ViewPlugin { } onActivation(): void { + //this.renderComponent(AIChatViewState.open) if (this.isOnDesktop) { console.log('Activating RemixAIPlugin on desktop') // this.on(this.remixDesktopPluginName, 'activated', () => { @@ -59,6 +67,10 @@ export class RemixAIPlugin extends ViewPlugin { } } + toggle (open: AIChatViewState) { + this.renderComponent(open) + } + async initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean){ if (this.isOnDesktop && !this.useRemoteInferencer) { // on desktop use remote inferencer -> false @@ -201,13 +213,41 @@ export class RemixAIPlugin extends ViewPlugin { return "" } } + isChatRequestPending(){ return this.chatRequestBuffer != null } + setDispatch(dispatch) { + this.dispatch = dispatch + this.renderComponent(AIChatViewState.open) + } + + renderComponent (open: AIChatViewState) { + this.dispatch({ + plugin: this, + openState: open + }) + } + render() { + return
+ +
+ } + + updateComponent(state) { return ( - + ) } } diff --git a/apps/remixdesktop/src/plugins/remixAIDektop.ts b/apps/remixdesktop/src/plugins/remixAIDektop.ts index 6382e28bba..75cf39612c 100644 --- a/apps/remixdesktop/src/plugins/remixAIDektop.ts +++ b/apps/remixdesktop/src/plugins/remixAIDektop.ts @@ -32,7 +32,7 @@ const clientProfile: Profile = { description: 'RemixAI provides AI services to Remix IDE Desktop.', kind: '', documentation: 'https://remix-ide.readthedocs.io/en/latest/remixai.html', - methods: ['initializeModelBackend', 'code_completion', 'code_insertion', 'code_generation', 'code_explaining', 'error_explaining', 'solidity_answer'] + methods: ['initializeModelBackend', 'code_completion', 'code_insertion', 'code_generation', 'code_explaining', 'error_explaining', 'solidity_answer', 'toggle'] } class RemixAIDesktopPluginClient extends ElectronBasePluginClient { diff --git a/libs/remix-api/src/lib/plugins/remixai-api.ts b/libs/remix-api/src/lib/plugins/remixai-api.ts index 0ea1498151..799b180662 100644 --- a/libs/remix-api/src/lib/plugins/remixai-api.ts +++ b/libs/remix-api/src/lib/plugins/remixai-api.ts @@ -19,5 +19,6 @@ export interface IRemixAI { chatPipe(pipeMessage: string): Promise, ProcessChatRequestBuffer(params:IParams): Promise, initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean): Promise, + toggle(boolean) } } \ 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..da580b7026 100644 --- a/libs/remix-api/src/lib/remix-api.ts +++ b/libs/remix-api/src/lib/remix-api.ts @@ -17,8 +17,15 @@ 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 { Api } from "@remixproject/plugin-utils"; + export interface ICustomRemixApi extends IRemixApi { + popupPanel: { + methods: ['showPopupPanel'] + events: ['popupPanelShown'] + showPopupPanel(): void + } & Api dgitApi: IGitApi dgit: IDgitPlugin config: IConfigApi @@ -39,4 +46,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/panel/src/lib/plugins/remix-ui-panel.tsx b/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx index 4e1fa59a2e..71aa3db8b0 100644 --- a/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx +++ b/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx @@ -14,16 +14,21 @@ export interface RemixPanelProps { export function RemixPluginPanel(props: RemixPanelProps) { return ( - <> +
{props.header}
- {Object.values(props.plugins).map((pluginRecord) => { - return - })} + { Object.values(props.plugins).map((pluginRecord) => { + return + }) }
- +
) } diff --git a/libs/remix-ui/remix-ai/src/lib/components/Default.tsx b/libs/remix-ui/remix-ai/src/lib/components/Default.tsx index 459797294c..1f1ce48323 100644 --- a/libs/remix-ui/remix-ai/src/lib/components/Default.tsx +++ b/libs/remix-ui/remix-ai/src/lib/components/Default.tsx @@ -42,8 +42,8 @@ export const Default = (props) => { }; ChatApi = useAiChatApi(); const conversationStarters: ConversationStarter[] = [ - { prompt: 'Explain briefly the current file in Editor', icon: ⭐️ }, - { prompt: 'Explain what is a solidity contract!' }] + { prompt: 'Explain what is a solidity contract!'}, + { prompt: 'Explain briefly the current file in Editor'}] // Define initial messages const initialMessages: ChatItem[] = [ diff --git a/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx b/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx index d55a3a9256..61b5910913 100644 --- a/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx +++ b/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx @@ -1,14 +1,22 @@ import React, { useContext } from 'react' import '../remix-ai.css' import { Default, ChatApi } from './Default' +enum AIChatViewState { + minimized = 0, + open = 1 +} +interface IRemixAITab { + plugin: any, + openState: AIChatViewState +} +export const RemixAITab = (props: IRemixAITab) => { -export const RemixAITab = (props) => { - - const plugin = props.plugin return ( <> -
- +
+
+ +
) diff --git a/libs/remix-ui/remix-ai/src/lib/components/color.css b/libs/remix-ui/remix-ai/src/lib/components/color.css index 836a05f103..40e54d438b 100644 --- a/libs/remix-ui/remix-ai/src/lib/components/color.css +++ b/libs/remix-ui/remix-ai/src/lib/components/color.css @@ -1,11 +1,32 @@ .nlux-theme-remix_ai_theme[data-color-scheme='light'] { --nlux-ChatRoom--BackgroundColor: var(--text-background); + padding-bottom: 0.1rem; } .nlux-theme-remix_ai_theme[data-color-scheme='dark'] { --nlux-ChatRoom--BackgroundColor: var(--text-background); + padding-bottom: 0.1rem; } +.nlux-launchPad-container { + padding-bottom: 2rem; +} + +.nlux-conversationStarters-container { + overflow-y: hidden; +} + +.nlux-comp-conversationStarters { + width: auto !important; + padding: 0px !important +} + +.nlux-conversationStarters-container>.nlux-comp-conversationStarters>.nlux-comp-conversationStarter { + border-width: 1px !important; + border-color: var(--text-background) !important; +} + + .nlux-theme-remix_ai_theme { /* Override top-level chat room colors */ @@ -35,9 +56,13 @@ --nlux-PromptInput-Focus-Outline--Width: 10px; --nlux-PromptInput-Max-Height: 50px; --nlux-PromptInput--BorderWidth: 0; - .nlux-comp-composer > textarea {padding: 8px;} --nlux-PromptInput--BorderRadius: 10px 0 0 10px; - --nlux-PromptInput-Height: 50px; + --nlux-PromptInput-Height: 30px; + --nlux-cvStrt--brdrWd: 0; + --nlux-cvStrt--brdClr: var(--light); + --nlux-cvStrt--brdrWd: 'hidden'; + --nlux-comp-composer > textarea {padding: 8px;} + /* Override input colors */ @@ -49,10 +74,10 @@ --nlux-Composer--Gap: 0; /* Override submit button colors */ - --nlux-SubmitButton--BackgroundColor: var(--primary); - --nlux-SubmitButton-Active--BackgroundColor:var(--primary); + --nlux-SubmitButton--BackgroundColor: var(--light); + --nlux-SubmitButton-Active--BackgroundColor:var(--light); --nlux-SubmitButton-Disabled--BackgroundColor: var(--dark); - --nlux-SubmitButton-Active--TextColor: var(--text); + --nlux-SubmitButton-Active--TextColor: var(--primary); --nlux-SubmitButton-Disabled--TextColor: var(--text); /** Inline code in markdown */ @@ -61,7 +86,6 @@ --nlux-InlineCode--Padding: 0 2px; --nlux-InlineCode--FontSize: 14px; - /*code block */ --nlux-CodeBlock-CopyButton--BackgroundColor: var(--bg-text); --nlux-CodeBlock-CopyButton--TextColor: var(--text); diff --git a/libs/remix-ui/statusbar/src/css/statusbar.css b/libs/remix-ui/statusbar/src/css/statusbar.css index 4792ca77f3..30a5712f89 100644 --- a/libs/remix-ui/statusbar/src/css/statusbar.css +++ b/libs/remix-ui/statusbar/src/css/statusbar.css @@ -1,4 +1,9 @@ +.remixui_statusbar_gitstatus { + position: relative; + left: 20rem; +} + .remixui_statusbar_gitstatus .remixui_statusbar_gitstatus:hover { cursor: pointer; diff --git a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx index fc6d774ce4..d476fba092 100644 --- a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx @@ -12,12 +12,24 @@ interface AIStatusProps { export default function AIStatus(props: AIStatusProps) { const [copilotActive, setCopilotActive] = useState(false) + const [expandAIChat, setExpandAIChat] = useState(true) + useEffect(() => { + const popupPanelListener = async (show) => { + setTimeout(() => setExpandAIChat(show), 0); + }; + + props.plugin.on('popupPanel', 'popupPanelShown', popupPanelListener) + const run = async () => { const aiActivate = await props.plugin.call('settings', 'get', 'settings/copilot/suggest/activate') setCopilotActive(aiActivate) } run() + + return () => { + props.plugin.off('popupPanel', 'popupPanelShown') + } }, []) useEffect(() => { @@ -29,15 +41,42 @@ export default function AIStatus(props: AIStatusProps) { } run() }, [props.plugin.isAiActive, props.plugin.isAiActive]) + return ( - -
- +
+ + { + await props.plugin.call('settings' as any, 'updateCopilotChoice', !copilotActive) + }} + > {copilotActive === false ? 'RemixAI Copilot (disabled)' : 'RemixAI Copilot (enabled)'} + +
+
- +
) -} +} \ No newline at end of file diff --git a/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx b/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx index e72bfe62b5..9c9193b933 100644 --- a/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx @@ -18,13 +18,21 @@ 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..cfd5caf99c 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,35 @@ export function RemixUIStatusBar({ statusBarPlugin }: RemixUIStatusBarProps) { {(platform !== appPlatformTypes.desktop) && showScamDetails && ( - + )}
+ { (platform !== appPlatformTypes.desktop) &&
+ +
}
-
-
- { (platform !== appPlatformTypes.desktop) &&
- -
}
diff --git a/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx b/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx index eaaffcad15..bae6a258c2 100644 --- a/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx +++ b/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx @@ -279,7 +279,7 @@ export const TabsUI = (props: TabsUIProps) => { methods: ['code_generation', 'code_completion', "solidity_answer", "code_explaining", "code_insertion", "error_explaining", - "initialize", 'chatPipe', 'ProcessChatRequestBuffer', 'isChatRequestPending'], + "initialize", 'chatPipe', 'ProcessChatRequestBuffer', 'isChatRequestPending', 'toggle'], events: [], icon: 'assets/img/remix-logo-blue.png', description: 'RemixAI provides AI services to Remix IDE.', From 14c15bd902d1b534acd6179b9eaaac5f1ee5545d Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 12:50:55 +0100 Subject: [PATCH 17/82] first fixes --- .../src/app/components/popup-panel.tsx | 49 +++++++++++-------- .../app/src/lib/remix-app/actions/app.ts | 2 + .../app/src/lib/remix-app/interface/index.ts | 1 + .../app/src/lib/remix-app/reducer/app.ts | 47 ++++++++++-------- .../app/src/lib/remix-app/state/app.ts | 3 +- .../src/lib/components/PluginViewWrapper.tsx | 14 +++++- .../panel/src/lib/plugins/remix-ui-panel.tsx | 4 +- .../statusbar/src/lib/components/aiStatus.tsx | 10 +--- 8 files changed, 77 insertions(+), 53 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index 2f0f5ef049..8388e8a83f 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -1,9 +1,11 @@ import React from 'react' // eslint-disable-line import { AbstractPanel } from './panel' -import { RemixPluginPanel } from '@remix-ui/panel' +import { PluginRecord, RemixPluginPanel } from '@remix-ui/panel' import packageJson from '../../../../../package.json' import { PluginViewWrapper } from '@remix-ui/helper' -import {EventEmitter} from 'events' +import { EventEmitter } from 'events' +import { AppState } from 'libs/remix-ui/app/src/lib/remix-app/interface' +import { AppAction, appActionTypes } from '@remix-ui/app' const profile = { name: 'popupPanel', @@ -13,22 +15,28 @@ const profile = { events: ['popupPanelShown'], methods: ['addView', 'removeView', 'showContent', 'showPopupPanel'] } +type popupPanelState = { + plugins: Record +} export class PopupPanel extends AbstractPanel { element: HTMLDivElement - dispatch: React.Dispatch = () => {} - showPanel: boolean + dispatch: React.Dispatch = () => { } + appStateDispatch: React.Dispatch = () => { } constructor(config) { super(profile) this.event = new EventEmitter() - this.showPanel = true } setDispatch(dispatch: React.Dispatch) { this.dispatch = dispatch } + setAppStateDispatch(appStateDispatch: React.Dispatch) { + this.appStateDispatch = appStateDispatch + } + onActivation() { this.renderComponent() } @@ -56,23 +64,31 @@ export class PopupPanel extends AbstractPanel { } async showPopupPanel(show) { - console.log("hide in popup-panel =", show) - this.showPanel = show - this.event.emit('popupPanelShown', show) + + this.appStateDispatch({ + type: appActionTypes.setShowPopupPanel, + payload: show + }) this.renderComponent() } renderComponent() { this.dispatch({ - plugins: this.plugins, - showPpPanel: this.showPanel + plugins: this.plugins }) } render() { + return ( + + ) + } + + updateComponent(state: popupPanelState & Partial) { + console.log("state in updateComponent =", state) return (
- {this.showPanel && } -
- ) - } - - updateComponent(state: any) { - return ( -
@@ -108,6 +116,7 @@ export class PopupPanel extends AbstractPanel { } plugins={state.plugins} /> -
) +
+ ) } } 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..5abe07626c 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 @@ -3,29 +3,36 @@ import { AppState } from "../interface"; export const appReducer = (state: AppState, action: AppAction): AppState => { switch (action.type) { - case appActionTypes.setGitHubUser: { - return { - ...state, - gitHubUser: action.payload + case appActionTypes.setGitHubUser: { + return { + ...state, + gitHubUser: action.payload + } } - } - case appActionTypes.setCurrentBranch: { - return { - ...state, - currentBranch: action.payload + case appActionTypes.setCurrentBranch: { + return { + ...state, + currentBranch: action.payload + } } - } - case appActionTypes.setNeedsGitInit: { - return { - ...state, - needsGitInit: action.payload + case appActionTypes.setNeedsGitInit: { + return { + ...state, + needsGitInit: action.payload + } } - } - case appActionTypes.setCanUseGit: { - return { - ...state, - canUseGit: action.payload + case appActionTypes.setCanUseGit: { + return { + ...state, + 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/state/app.ts b/libs/remix-ui/app/src/lib/remix-app/state/app.ts index 8086b75c9c..2778233a09 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: true } \ 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..168f1095f2 100644 --- a/libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx +++ b/libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx @@ -1,4 +1,5 @@ -import React from 'react' +import { AppContext } from '@remix-ui/app' +import React, { useContext } from 'react' import { useEffect, useState } from 'react' interface IPluginViewWrapperProps { @@ -7,12 +8,21 @@ interface IPluginViewWrapperProps { export const PluginViewWrapper = (props: IPluginViewWrapperProps) => { const [state, setState] = useState(null) + const appContext = useContext(AppContext) useEffect(() => { if (props.plugin.setDispatch) { props.plugin.setDispatch(setState) } + if(props.plugin.setAppStateDispatch) { + props.plugin.setAppStateDispatch(appContext.appStateDispatch) + } }, []) - return <>{state ? <>{props.plugin.updateComponent(state)} : <>} + return <>{state ? <>{props.plugin.updateComponent( + { + ...state, + ...appContext['appState'] + })} + : <>} } diff --git a/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx b/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx index 71aa3db8b0..ba6c494a04 100644 --- a/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx +++ b/libs/remix-ui/panel/src/lib/plugins/remix-ui-panel.tsx @@ -14,7 +14,7 @@ export interface RemixPanelProps { export function RemixPluginPanel(props: RemixPanelProps) { return ( -
+ <> {props.header}
@@ -28,7 +28,7 @@ export function RemixPluginPanel(props: RemixPanelProps) { }) }
-
+ ) } diff --git a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx index d476fba092..55b4fbf43d 100644 --- a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx @@ -12,14 +12,8 @@ interface AIStatusProps { export default function AIStatus(props: AIStatusProps) { const [copilotActive, setCopilotActive] = useState(false) - const [expandAIChat, setExpandAIChat] = useState(true) useEffect(() => { - const popupPanelListener = async (show) => { - setTimeout(() => setExpandAIChat(show), 0); - }; - - props.plugin.on('popupPanel', 'popupPanelShown', popupPanelListener) const run = async () => { const aiActivate = await props.plugin.call('settings', 'get', 'settings/copilot/suggest/activate') @@ -71,10 +65,10 @@ export default function AIStatus(props: AIStatusProps) { }} className='p-1 alert alert-info border border-info fa-solid fa-message-bot' onClick={async () => { - await props.plugin.call('popupPanel', 'showPopupPanel', !expandAIChat) + await props.plugin.call('popupPanel', 'showPopupPanel', true) }} > - {expandAIChat ? '1' : '0'} +
From f8667db195e0dd0b969550079ea68e2c9b6e9904 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 13:06:24 +0100 Subject: [PATCH 18/82] lianas css --- apps/remix-ide/src/app/components/popup-panel.tsx | 2 +- libs/remix-ui/statusbar/src/css/statusbar.css | 7 ++----- .../statusbar/src/lib/remixui-statusbar-panel.tsx | 10 ++++++---- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index 8388e8a83f..2712b0725d 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -97,7 +97,7 @@ export class PopupPanel extends AbstractPanel { position: 'fixed', bottom: '2rem', right: '3.5rem', - zIndex: 2000, + zIndex: 200, boxShadow: '3px 3px var(--secondary), -0.1em 0 1.4em var(--secondary)' }} data-id="popupPanelPluginsContainer" diff --git a/libs/remix-ui/statusbar/src/css/statusbar.css b/libs/remix-ui/statusbar/src/css/statusbar.css index 30a5712f89..11ee870603 100644 --- a/libs/remix-ui/statusbar/src/css/statusbar.css +++ b/libs/remix-ui/statusbar/src/css/statusbar.css @@ -1,9 +1,6 @@ - -.remixui_statusbar_gitstatus { - position: relative; - left: 20rem; +.remixui_statusbar { + white-space: nowrap; } - .remixui_statusbar_gitstatus .remixui_statusbar_gitstatus:hover { cursor: pointer; 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 cfd5caf99c..a295239a10 100644 --- a/libs/remix-ui/statusbar/src/lib/remixui-statusbar-panel.tsx +++ b/libs/remix-ui/statusbar/src/lib/remixui-statusbar-panel.tsx @@ -91,13 +91,15 @@ export function RemixUIStatusBar({ statusBarPlugin }: RemixUIStatusBarProps) { { (platform !== appPlatformTypes.desktop) &&
} -
- +
+
+ +
-
+
-
+
From fac93dc375ae5244d8e04edc16c49fed0f1414c8 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 13:36:36 +0100 Subject: [PATCH 19/82] fix state --- .../src/app/components/popup-panel.tsx | 2 +- .../src/app/plugins/remixAIPlugin.tsx | 17 ++++---------- .../src/lib/plugins/popuppanel-api.ts | 10 ++++++++ libs/remix-api/src/lib/plugins/remixai-api.ts | 1 - .../src/lib/plugins/remixaiDesktop-api.ts | 23 ------------------- libs/remix-api/src/lib/remix-api.ts | 7 ++---- .../remix-ai/src/lib/components/RemixAI.tsx | 6 +---- .../statusbar/src/lib/components/aiStatus.tsx | 13 ++++++----- 8 files changed, 25 insertions(+), 54 deletions(-) create mode 100644 libs/remix-api/src/lib/plugins/popuppanel-api.ts delete mode 100644 libs/remix-api/src/lib/plugins/remixaiDesktop-api.ts diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index 2712b0725d..3b9af9ff23 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -12,7 +12,7 @@ const profile = { displayName: 'Popup Panel', description: 'Remix IDE popup panel', version: packageJson.version, - events: ['popupPanelShown'], + events: [], methods: ['addView', 'removeView', 'showContent', 'showPopupPanel'] } type popupPanelState = { diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index eb5ef592a4..5bb7ac7e93 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -10,10 +10,6 @@ import { PluginViewWrapper } from '@remix-ui/helper' type chatRequestBufferT = { [key in keyof T]: T[key] } -enum AIChatViewState { - minimized = 0, - open = 1 -} const profile = { name: 'remixAI', @@ -53,7 +49,7 @@ export class RemixAIPlugin extends ViewPlugin { } onActivation(): void { - //this.renderComponent(AIChatViewState.open) + if (this.isOnDesktop) { console.log('Activating RemixAIPlugin on desktop') // this.on(this.remixDesktopPluginName, 'activated', () => { @@ -66,10 +62,6 @@ export class RemixAIPlugin extends ViewPlugin { this.initialize() } } - - toggle (open: AIChatViewState) { - this.renderComponent(open) - } async initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean){ if (this.isOnDesktop && !this.useRemoteInferencer) { @@ -220,13 +212,12 @@ export class RemixAIPlugin extends ViewPlugin { setDispatch(dispatch) { this.dispatch = dispatch - this.renderComponent(AIChatViewState.open) + this.renderComponent() } - renderComponent (open: AIChatViewState) { + renderComponent () { this.dispatch({ plugin: this, - openState: open }) } @@ -247,7 +238,7 @@ export class RemixAIPlugin extends ViewPlugin { updateComponent(state) { return ( - + ) } } 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/remixai-api.ts b/libs/remix-api/src/lib/plugins/remixai-api.ts index 799b180662..0ea1498151 100644 --- a/libs/remix-api/src/lib/plugins/remixai-api.ts +++ b/libs/remix-api/src/lib/plugins/remixai-api.ts @@ -19,6 +19,5 @@ export interface IRemixAI { chatPipe(pipeMessage: string): Promise, ProcessChatRequestBuffer(params:IParams): Promise, initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean): Promise, - toggle(boolean) } } \ No newline at end of file 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 da580b7026..7df4dc7104 100644 --- a/libs/remix-api/src/lib/remix-api.ts +++ b/libs/remix-api/src/lib/remix-api.ts @@ -18,14 +18,11 @@ import { IRemixAID } from "./plugins/remixAIDesktop-api" import { IMenuIconsApi } from "./plugins/menuicons-api" import { IDgitPlugin } from "./plugins/dgitplugin-api" import { Api } from "@remixproject/plugin-utils"; +import { IPopupPanelAPI } from "./plugins/popuppanel-api" export interface ICustomRemixApi extends IRemixApi { - popupPanel: { - methods: ['showPopupPanel'] - events: ['popupPanelShown'] - showPopupPanel(): void - } & Api + popupPanel: IPopupPanelAPI dgitApi: IGitApi dgit: IDgitPlugin config: IConfigApi diff --git a/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx b/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx index 61b5910913..a5aaba4a7d 100644 --- a/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx +++ b/libs/remix-ui/remix-ai/src/lib/components/RemixAI.tsx @@ -1,13 +1,9 @@ import React, { useContext } from 'react' import '../remix-ai.css' import { Default, ChatApi } from './Default' -enum AIChatViewState { - minimized = 0, - open = 1 -} + interface IRemixAITab { plugin: any, - openState: AIChatViewState } export const RemixAITab = (props: IRemixAITab) => { diff --git a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx index 55b4fbf43d..48864811a2 100644 --- a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx @@ -1,7 +1,8 @@ // eslint-disable-next-line @nrwl/nx/enforce-module-boundaries import { StatusBar } from 'apps/remix-ide/src/app/components/status-bar' import { CustomTooltip } from '@remix-ui/helper' -import React, { useEffect, useState } from 'react' +import React, { useContext, useEffect, useState } from 'react' +import { appActionTypes, AppContext } from '@remix-ui/app' interface AIStatusProps { plugin: StatusBar @@ -12,7 +13,7 @@ interface AIStatusProps { export default function AIStatus(props: AIStatusProps) { const [copilotActive, setCopilotActive] = useState(false) - + const appContext = useContext(AppContext) useEffect(() => { const run = async () => { @@ -21,9 +22,6 @@ export default function AIStatus(props: AIStatusProps) { } run() - return () => { - props.plugin.off('popupPanel', 'popupPanelShown') - } }, []) useEffect(() => { @@ -65,7 +63,10 @@ export default function AIStatus(props: AIStatusProps) { }} className='p-1 alert alert-info border border-info fa-solid fa-message-bot' onClick={async () => { - await props.plugin.call('popupPanel', 'showPopupPanel', true) + appContext.appStateDispatch({ + type: appActionTypes.setShowPopupPanel, + payload: !appContext.appState.showPopupPanel + }) }} > From cbab1a11fb730502a24b052146a8a576b13717ba Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 13:46:01 +0100 Subject: [PATCH 20/82] clean up --- .../src/app/components/popup-panel.tsx | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index 3b9af9ff23..f45a9f3d3f 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -23,7 +23,7 @@ export class PopupPanel extends AbstractPanel { element: HTMLDivElement dispatch: React.Dispatch = () => { } appStateDispatch: React.Dispatch = () => { } - + constructor(config) { super(profile) this.event = new EventEmitter() @@ -64,7 +64,7 @@ export class PopupPanel extends AbstractPanel { } async showPopupPanel(show) { - + this.appStateDispatch({ type: appActionTypes.setShowPopupPanel, payload: show @@ -85,7 +85,6 @@ export class PopupPanel extends AbstractPanel { } updateComponent(state: popupPanelState & Partial) { - console.log("state in updateComponent =", state) return (
- - - - } - plugins={state.plugins} /> +
+ + + + } + plugins={state.plugins} /> +
) } From ed896ee6fc5c081b98939615e34b6b43a869c451 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 13:49:45 +0100 Subject: [PATCH 21/82] linting --- .../src/app/components/popup-panel.tsx | 4 +- .../src/app/plugins/remixAIPlugin.tsx | 2 +- libs/remix-ui/app/src/index.ts | 2 +- .../app/src/lib/remix-app/reducer/app.ts | 50 +++++++++---------- .../src/lib/components/PluginViewWrapper.tsx | 2 +- .../remix-ai/src/lib/components/Default.tsx | 4 +- .../statusbar/src/lib/components/aiStatus.tsx | 6 +-- .../src/lib/remixui-statusbar-panel.tsx | 4 +- 8 files changed, 37 insertions(+), 37 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index f45a9f3d3f..363d89d2cf 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -4,8 +4,8 @@ import { PluginRecord, RemixPluginPanel } from '@remix-ui/panel' import packageJson from '../../../../../package.json' import { PluginViewWrapper } from '@remix-ui/helper' import { EventEmitter } from 'events' -import { AppState } from 'libs/remix-ui/app/src/lib/remix-app/interface' -import { AppAction, appActionTypes } from '@remix-ui/app' + +import { AppAction, appActionTypes, AppState } from '@remix-ui/app' const profile = { name: 'popupPanel', diff --git a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx index 5bb7ac7e93..34a3a15298 100644 --- a/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx +++ b/apps/remix-ide/src/app/plugins/remixAIPlugin.tsx @@ -62,7 +62,7 @@ export class RemixAIPlugin extends ViewPlugin { this.initialize() } } - + async initialize(model1?:IModel, model2?:IModel, remoteModel?:IRemoteModel, useRemote?:boolean){ if (this.isOnDesktop && !this.useRemoteInferencer) { // on desktop use remote inferencer -> false 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/reducer/app.ts b/libs/remix-ui/app/src/lib/remix-app/reducer/app.ts index 5abe07626c..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 @@ -3,36 +3,36 @@ import { AppState } from "../interface"; export const appReducer = (state: AppState, action: AppAction): AppState => { switch (action.type) { - case appActionTypes.setGitHubUser: { - return { - ...state, - gitHubUser: action.payload - } + case appActionTypes.setGitHubUser: { + return { + ...state, + gitHubUser: action.payload } - case appActionTypes.setCurrentBranch: { - return { - ...state, - currentBranch: action.payload - } + } + case appActionTypes.setCurrentBranch: { + return { + ...state, + currentBranch: action.payload } - case appActionTypes.setNeedsGitInit: { - return { - ...state, - needsGitInit: action.payload - } + } + case appActionTypes.setNeedsGitInit: { + return { + ...state, + needsGitInit: action.payload } - case appActionTypes.setCanUseGit: { - return { - ...state, - canUseGit: action.payload - } + } + case appActionTypes.setCanUseGit: { + return { + ...state, + canUseGit: action.payload } + } - case appActionTypes.setShowPopupPanel: { - return { - ...state, - showPopupPanel: action.payload - } + case appActionTypes.setShowPopupPanel: { + return { + ...state, + showPopupPanel: action.payload } } + } } \ 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 168f1095f2..c29f58d4dc 100644 --- a/libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx +++ b/libs/remix-ui/helper/src/lib/components/PluginViewWrapper.tsx @@ -14,7 +14,7 @@ export const PluginViewWrapper = (props: IPluginViewWrapperProps) => { if (props.plugin.setDispatch) { props.plugin.setDispatch(setState) } - if(props.plugin.setAppStateDispatch) { + if (props.plugin.setAppStateDispatch) { props.plugin.setAppStateDispatch(appContext.appStateDispatch) } }, []) diff --git a/libs/remix-ui/remix-ai/src/lib/components/Default.tsx b/libs/remix-ui/remix-ai/src/lib/components/Default.tsx index 1f1ce48323..bdeaacbea7 100644 --- a/libs/remix-ui/remix-ai/src/lib/components/Default.tsx +++ b/libs/remix-ui/remix-ai/src/lib/components/Default.tsx @@ -42,8 +42,8 @@ export const Default = (props) => { }; ChatApi = useAiChatApi(); const conversationStarters: ConversationStarter[] = [ - { prompt: 'Explain what is a solidity contract!'}, - { prompt: 'Explain briefly the current file in Editor'}] + { prompt: 'Explain what is a solidity contract!' }, + { prompt: 'Explain briefly the current file in Editor' }] // Define initial messages const initialMessages: ChatItem[] = [ diff --git a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx index 48864811a2..53f3de6325 100644 --- a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx @@ -15,13 +15,13 @@ export default function AIStatus(props: AIStatusProps) { const [copilotActive, setCopilotActive] = useState(false) const appContext = useContext(AppContext) useEffect(() => { - + const run = async () => { const aiActivate = await props.plugin.call('settings', 'get', 'settings/copilot/suggest/activate') setCopilotActive(aiActivate) } run() - + }, []) useEffect(() => { @@ -40,7 +40,7 @@ export default function AIStatus(props: AIStatusProps) { tooltipText={copilotActive ? "Disable RemixAI Copilot" : "Enable RemixAI Copilot. Switch to .sol file to try it."} > { await props.plugin.call('settings' as any, 'updateCopilotChoice', !copilotActive) 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 a295239a10..22b1dac390 100644 --- a/libs/remix-ui/statusbar/src/lib/remixui-statusbar-panel.tsx +++ b/libs/remix-ui/statusbar/src/lib/remixui-statusbar-panel.tsx @@ -89,8 +89,8 @@ export function RemixUIStatusBar({ statusBarPlugin }: RemixUIStatusBarProps) { )}
{ (platform !== appPlatformTypes.desktop) &&
- -
} + +
}
From 8af1f52dbe32e4724fcbdd4975161155e5c96b3a Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 14:07:23 +0100 Subject: [PATCH 22/82] hide popup --- libs/remix-ui/app/src/lib/remix-app/state/app.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 2778233a09..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 @@ -6,5 +6,5 @@ export const appInitialState: AppState = { currentBranch: null, needsGitInit: true, canUseGit: false, - showPopupPanel: true + showPopupPanel: false } \ No newline at end of file From 9734f542d6c40eea315a4931e3dea76b5f5042dc Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 14:32:47 +0100 Subject: [PATCH 23/82] hidescam button --- apps/remix-ide-e2e/src/helpers/init.ts | 3 +++ libs/remix-ui/statusbar/src/lib/components/scamAlertStatus.tsx | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index f30ce3dd62..cd6bdb86af 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -27,6 +27,8 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url }) .verifyLoad() .enableClipBoard() + .waitForElementVisible('*[data-id="hTScamAlertButton"]') + .click('*[data-id="hTScamAlertButton"]') .perform((done) => { browser.execute(function () { // hide tooltips function addStyle(styleString) { @@ -76,6 +78,7 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url function initModules(browser: NightwatchBrowser, callback: VoidFunction) { browser + .pause() .click('[data-id="verticalIconsKindpluginManager"]') .scrollAndClick('[data-id="pluginManagerComponentActivateButtonsolidityStaticAnalysis"]') .scrollAndClick('[data-id="pluginManagerComponentActivateButtondebugger"]') 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 -
+
From d244c909be59381867d4ae89c56dc68e90a9bc69 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 15:16:14 +0100 Subject: [PATCH 24/82] fix bugs --- .../src/app/components/popup-panel.tsx | 6 +-- .../src/lib/components/PluginViewWrapper.tsx | 37 +++++++++++-------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index 363d89d2cf..b85c3eb8a8 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -80,14 +80,14 @@ export class PopupPanel extends AbstractPanel { render() { return ( - + ) } - updateComponent(state: popupPanelState & Partial) { + updateComponent(state: popupPanelState, appState: Partial) { return (
{ +export const PluginViewWrapper = ({ plugin, useAppContext = false }: IPluginViewWrapperProps) => { const [state, setState] = useState(null) - const appContext = useContext(AppContext) + const appContext = useAppContext ? useContext(AppContext) : null useEffect(() => { - if (props.plugin.setDispatch) { - props.plugin.setDispatch(setState) + if (plugin.setDispatch) { + plugin.setDispatch(setState) } - if (props.plugin.setAppStateDispatch) { - props.plugin.setAppStateDispatch(appContext.appStateDispatch) + if (useAppContext && appContext.appStateDispatch && plugin.setAppStateDispatch) { + plugin.setAppStateDispatch(appContext.appStateDispatch) } - }, []) + }, [plugin]) - return <>{state ? <>{props.plugin.updateComponent( - { - ...state, - ...appContext['appState'] - })} - : <>} + if (useAppContext && appContext && appContext.appState) { + return ( + <> + {state ? <>{plugin.updateComponent(state, appContext.appState)} : <>} + + ) + } + + return ( + <> + {state ? <>{plugin.updateComponent(state)} : <>} + + ) } From d3c71d16413d23d8cbb61bde0ca38f40592c1853 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 15:31:20 +0100 Subject: [PATCH 25/82] init --- apps/remix-ide-e2e/src/helpers/init.ts | 3 ++- libs/remix-ui/app/src/lib/remix-app/state/app.ts | 2 +- libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx | 1 + 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index cd6bdb86af..a6c303f32d 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -29,6 +29,8 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url .enableClipBoard() .waitForElementVisible('*[data-id="hTScamAlertButton"]') .click('*[data-id="hTScamAlertButton"]') + .waitForElementVisible('*[data-id="aiStatusButton"]') + .click('*[data-id="aiStatusButton"]') .perform((done) => { browser.execute(function () { // hide tooltips function addStyle(styleString) { @@ -78,7 +80,6 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url function initModules(browser: NightwatchBrowser, callback: VoidFunction) { browser - .pause() .click('[data-id="verticalIconsKindpluginManager"]') .scrollAndClick('[data-id="pluginManagerComponentActivateButtonsolidityStaticAnalysis"]') .scrollAndClick('[data-id="pluginManagerComponentActivateButtondebugger"]') 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 708b22301a..2778233a09 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 @@ -6,5 +6,5 @@ export const appInitialState: AppState = { currentBranch: null, needsGitInit: true, canUseGit: false, - showPopupPanel: false + showPopupPanel: true } \ No newline at end of file diff --git a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx index 53f3de6325..bfdf3f96bb 100644 --- a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx @@ -61,6 +61,7 @@ export default function AIStatus(props: AIStatusProps) { color: 'var(--ai)', boxShadow: '3px 3px var(--secondary), -0.1em 0 1.4em var(--secondary)' }} + data-id="aiStatusButton" className='p-1 alert alert-info border border-info fa-solid fa-message-bot' onClick={async () => { appContext.appStateDispatch({ From 29fca2194639594a09688ad38f7fff8c6b07fe1a Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 15:58:48 +0100 Subject: [PATCH 26/82] hidescamdetails --- apps/remix-ide-e2e/src/commands/hideToolTips.ts | 5 ++++- apps/remix-ide-e2e/src/helpers/init.ts | 5 +++-- libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) 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/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index a6c303f32d..5954ce7b38 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -27,8 +27,6 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url }) .verifyLoad() .enableClipBoard() - .waitForElementVisible('*[data-id="hTScamAlertButton"]') - .click('*[data-id="hTScamAlertButton"]') .waitForElementVisible('*[data-id="aiStatusButton"]') .click('*[data-id="aiStatusButton"]') .perform((done) => { @@ -43,6 +41,9 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url .popover { display:none !important; } + #scamDetails { + display:none !important; + } `); }, [], done()) }) diff --git a/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx b/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx index 9c9193b933..6a3108b313 100644 --- a/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx @@ -18,6 +18,7 @@ export default function ScamDetails ({ refs, floatStyle, scamAlerts }: ScamDetai return (
Date: Mon, 4 Nov 2024 16:49:58 +0100 Subject: [PATCH 27/82] hide popup panel --- apps/remix-ide-e2e/src/helpers/init.ts | 2 -- libs/remix-ui/app/src/lib/remix-app/state/app.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index 5954ce7b38..67e8f1a8fc 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -27,8 +27,6 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url }) .verifyLoad() .enableClipBoard() - .waitForElementVisible('*[data-id="aiStatusButton"]') - .click('*[data-id="aiStatusButton"]') .perform((done) => { browser.execute(function () { // hide tooltips function addStyle(styleString) { 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 2778233a09..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 @@ -6,5 +6,5 @@ export const appInitialState: AppState = { currentBranch: null, needsGitInit: true, canUseGit: false, - showPopupPanel: true + showPopupPanel: false } \ No newline at end of file From e958836133c825e23e1a2c9fa1eae914d53d968c Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 16:59:59 +0100 Subject: [PATCH 28/82] hide scam --- apps/remix-ide-e2e/src/commands/refreshPage.ts | 3 +++ 1 file changed, 3 insertions(+) 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()) }) From 8cba5e05a1207a1574cab1400ea24734ac1c2248 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 17:21:08 +0100 Subject: [PATCH 29/82] timeout --- apps/remix-ide-e2e/nightwatch-chrome.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/nightwatch-chrome.ts b/apps/remix-ide-e2e/nightwatch-chrome.ts index f1b95992eb..864b5f9f4f 100644 --- a/apps/remix-ide-e2e/nightwatch-chrome.ts +++ b/apps/remix-ide-e2e/nightwatch-chrome.ts @@ -21,7 +21,7 @@ module.exports = { 'default': { globals: { waitForConditionTimeout: 10000, - asyncHookTimeout: 10000000 + asyncHookTimeout: 30000000 }, screenshots: { enabled: true, From e4d64a8b756e6cb8a7d35d74dbdb18f59d24a7e8 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Mon, 4 Nov 2024 17:25:22 +0100 Subject: [PATCH 30/82] increase timeouts --- apps/remix-ide-e2e/nightwatch-chrome.ts | 2 +- apps/remix-ide-e2e/src/tests/circom.test.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/remix-ide-e2e/nightwatch-chrome.ts b/apps/remix-ide-e2e/nightwatch-chrome.ts index 864b5f9f4f..f1b95992eb 100644 --- a/apps/remix-ide-e2e/nightwatch-chrome.ts +++ b/apps/remix-ide-e2e/nightwatch-chrome.ts @@ -21,7 +21,7 @@ module.exports = { 'default': { globals: { waitForConditionTimeout: 10000, - asyncHookTimeout: 30000000 + asyncHookTimeout: 10000000 }, screenshots: { enabled: true, diff --git a/apps/remix-ide-e2e/src/tests/circom.test.ts b/apps/remix-ide-e2e/src/tests/circom.test.ts index 9ef2661f82..3c62015ad8 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) }, From 4d047091ba75176e297d5d5487de1511a28a7b37 Mon Sep 17 00:00:00 2001 From: lianahus Date: Mon, 4 Nov 2024 22:59:40 +0100 Subject: [PATCH 31/82] style --- .../src/app/components/popup-panel.tsx | 4 +- .../plugins/electron/remixAIDesktopPlugin.tsx | 2 +- .../src/app/plugins/remixAIPlugin.tsx | 4 +- .../remixdesktop/src/plugins/remixAIDektop.ts | 2 +- .../remix-ai/src/lib/components/RemixAI.tsx | 2 +- .../remix-ai/src/lib/components/color.css | 22 ++++--- .../remix-ai/src/lib/components/personas.tsx | 4 +- .../statusbar/src/lib/components/aiStatus.tsx | 60 +++++++++++-------- .../src/lib/components/scamDetails.tsx | 2 +- 9 files changed, 60 insertions(+), 42 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index b85c3eb8a8..3e5155d181 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -97,14 +97,14 @@ export class PopupPanel extends AbstractPanel { bottom: '2rem', right: '3.5rem', zIndex: 200, - boxShadow: '3px 3px var(--secondary), -0.1em 0 1.4em var(--secondary)' + boxShadow: "0 1px 7px var(--secondary)" }} data-id="popupPanelPluginsContainer" >
+ -
+ +
+ + +
+
) } \ No newline at end of file diff --git a/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx b/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx index 6a3108b313..062424e2b2 100644 --- a/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/scamDetails.tsx @@ -26,7 +26,7 @@ export default function ScamDetails ({ refs, floatStyle, scamAlerts }: ScamDetai height: '6rem', transform: 'translate(88.5px, -80px)', willChange: 'transform', - boxShadow: '3px 3px var(--secondary), -0.1em 0 1.4em var(--secondary)' + boxShadow: "0 1px 7px var(--secondary)" } } className="p-1 pb-0 mb-1 d-flex alert alert-warning border border-warning" > From cf6b7bfe478a1cd6730e729fd4de0e63b2b23329 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 07:30:39 +0100 Subject: [PATCH 32/82] show and hide panel --- apps/remix-ide-e2e/src/helpers/init.ts | 9 +++++++++ libs/remix-api/src/lib/remix-api.ts | 2 -- libs/remix-ui/app/src/lib/remix-app/remix-app.tsx | 15 +++++++++++---- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index 67e8f1a8fc..a98c0b6ac6 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -14,6 +14,15 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url .url(url || 'http://127.0.0.1:8080') .pause(5000) .switchBrowserTab(0) + // get value from local storage + .execute(function () { + return localStorage.getItem('did_show_popup_panel') + }, [], function (result) { + if (!result.value) { + browser.waitForElementVisible('*[data-id="aiStatusButton"]') + .click('*[data-id="aiStatusButton"]') + } + }) .perform((done) => { if (!loadPlugin) return done() browser diff --git a/libs/remix-api/src/lib/remix-api.ts b/libs/remix-api/src/lib/remix-api.ts index 7df4dc7104..36d7fbf6a0 100644 --- a/libs/remix-api/src/lib/remix-api.ts +++ b/libs/remix-api/src/lib/remix-api.ts @@ -17,10 +17,8 @@ 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 { Api } from "@remixproject/plugin-utils"; import { IPopupPanelAPI } from "./plugins/popuppanel-api" - export interface ICustomRemixApi extends IRemixApi { popupPanel: IPopupPanelAPI dgitApi: IGitApi 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 dd8a672525..5ab14a7811 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,10 +9,8 @@ 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' @@ -45,7 +43,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') + }) useEffect(() => { async function activateApp() { @@ -77,6 +78,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) => { From b3d5a42c1004aaa7f34631ad5e044ec6ccdb3678 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 07:38:57 +0100 Subject: [PATCH 33/82] lint --- libs/remix-ui/app/src/lib/remix-app/remix-app.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 5ab14a7811..f3738ee5b8 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 @@ -79,7 +79,7 @@ const RemixApp = (props: IRemixAppUi) => { }, []) useEffect(() => { - if(!appState.showPopupPanel) { + if (!appState.showPopupPanel) { window.localStorage.setItem('did_show_popup_panel', 'true') } },[appState.showPopupPanel]) From 51f6a52c913f32e574d3d7776bb25870f514d409 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 07:57:23 +0100 Subject: [PATCH 34/82] helpers --- .../src/commands/hidePopUpPanel.ts | 32 +++++++++++++++++++ apps/remix-ide-e2e/src/helpers/init.ts | 11 ++----- apps/remix-ide-e2e/src/types/index.d.ts | 1 + 3 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 apps/remix-ide-e2e/src/commands/hidePopUpPanel.ts 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..196f7b4476 --- /dev/null +++ b/apps/remix-ide-e2e/src/commands/hidePopUpPanel.ts @@ -0,0 +1,32 @@ +import { NightwatchBrowser } from 'nightwatch' +import EventEmitter from 'events' + +class HidePopUpPanel extends EventEmitter { + command(this: NightwatchBrowser) { + browser + .perform((done) => { + browser.execute(function () { + // hide tooltips + function addStyle(styleString) { + const style = document.createElement('style') + style.textContent = styleString + document.head.append(style) + } + addStyle(` + .popover { + display:none !important; + } + #scamDetails { + display:none !important; + } + `) + }, [], done()) + }) + .perform((done) => { + done() + this.emit('complete') + }) + } +} + +module.exports = HidePopUpPanel diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index a98c0b6ac6..2bf8244c31 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -14,15 +14,8 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url .url(url || 'http://127.0.0.1:8080') .pause(5000) .switchBrowserTab(0) - // get value from local storage - .execute(function () { - return localStorage.getItem('did_show_popup_panel') - }, [], function (result) { - if (!result.value) { - browser.waitForElementVisible('*[data-id="aiStatusButton"]') - .click('*[data-id="aiStatusButton"]') - } - }) + .hidePopUpPanel() + .pause() .perform((done) => { if (!loadPlugin) return done() browser diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index 4a5b1831ee..d031b6c992 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -77,6 +77,7 @@ declare module 'nightwatch' { enableClipBoard: () => NightwatchBrowser addFileSnekmate: (name: string, content: NightwatchContractContent) => NightwatchBrowser selectFiles: (selelectedElements: any[]) => NightwatchBrowser + hidePopUpPanel: (this: NightwatchBrowser) => NightwatchBrowser } export interface NightwatchBrowser { From 578036f5765f30f57792bad28902f44346a0bbea Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 08:10:16 +0100 Subject: [PATCH 35/82] hide panel command --- .../src/commands/hidePopUpPanel.ts | 32 ------------------- .../src/commands/hidePopupPanel.ts | 25 +++++++++++++++ apps/remix-ide-e2e/src/helpers/init.ts | 2 +- apps/remix-ide-e2e/src/types/index.d.ts | 2 +- .../test/tests/app/compiler.test.ts | 1 + .../test/tests/app/externaleditor.test.ts | 1 + .../test/tests/app/foundry.test.ts | 1 + apps/remixdesktop/test/tests/app/gist.test.ts | 1 + .../test/tests/app/git-ui.test.ts | 2 +- .../test/tests/app/git-ui_2.test.ts | 2 +- .../test/tests/app/git-ui_3.test.ts | 2 +- .../test/tests/app/git-ui_4.test.ts | 2 +- apps/remixdesktop/test/tests/app/git.test.ts | 1 + .../test/tests/app/github.test.ts | 2 +- .../test/tests/app/github_2.test.ts | 2 +- .../test/tests/app/github_3.test.ts | 2 +- .../test/tests/app/hardhat.test.ts | 1 + .../test/tests/app/offline.test.ts | 1 + .../test/tests/app/search.test.ts | 1 + .../test/tests/app/slitherlinux.test.ts | 1 + .../test/tests/app/templates.test.ts | 1 + .../remixdesktop/test/tests/app/xterm.test.ts | 1 + .../test/tests/app/xtermwin.test.ts | 1 + apps/remixdesktop/test/types/index.d.ts | 1 + 24 files changed, 47 insertions(+), 41 deletions(-) delete mode 100644 apps/remix-ide-e2e/src/commands/hidePopUpPanel.ts create mode 100644 apps/remix-ide-e2e/src/commands/hidePopupPanel.ts diff --git a/apps/remix-ide-e2e/src/commands/hidePopUpPanel.ts b/apps/remix-ide-e2e/src/commands/hidePopUpPanel.ts deleted file mode 100644 index 196f7b4476..0000000000 --- a/apps/remix-ide-e2e/src/commands/hidePopUpPanel.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { NightwatchBrowser } from 'nightwatch' -import EventEmitter from 'events' - -class HidePopUpPanel extends EventEmitter { - command(this: NightwatchBrowser) { - browser - .perform((done) => { - browser.execute(function () { - // hide tooltips - function addStyle(styleString) { - const style = document.createElement('style') - style.textContent = styleString - document.head.append(style) - } - addStyle(` - .popover { - display:none !important; - } - #scamDetails { - display:none !important; - } - `) - }, [], done()) - }) - .perform((done) => { - done() - this.emit('complete') - }) - } -} - -module.exports = HidePopUpPanel 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..29baee5523 --- /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="aiStatusButton"]') + .click('*[data-id="aiStatusButton"]') + } + done() + }) + }) + .perform((done) => { + done() + this.emit('complete') + }) + } +} + +module.exports = HidePopupPanel diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index 2bf8244c31..1caa647862 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -14,7 +14,7 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url .url(url || 'http://127.0.0.1:8080') .pause(5000) .switchBrowserTab(0) - .hidePopUpPanel() + .hidePopupPanel() .pause() .perform((done) => { if (!loadPlugin) return done() diff --git a/apps/remix-ide-e2e/src/types/index.d.ts b/apps/remix-ide-e2e/src/types/index.d.ts index d031b6c992..5c6d3bd262 100644 --- a/apps/remix-ide-e2e/src/types/index.d.ts +++ b/apps/remix-ide-e2e/src/types/index.d.ts @@ -74,10 +74,10 @@ 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 - hidePopUpPanel: (this: NightwatchBrowser) => NightwatchBrowser } export interface NightwatchBrowser { diff --git a/apps/remixdesktop/test/tests/app/compiler.test.ts b/apps/remixdesktop/test/tests/app/compiler.test.ts index 2fce46320c..7da49f2685 100644 --- a/apps/remixdesktop/test/tests/app/compiler.test.ts +++ b/apps/remixdesktop/test/tests/app/compiler.test.ts @@ -3,6 +3,7 @@ import { NightwatchBrowser } from 'nightwatch' module.exports = { before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hidePopupPanel() done() }, 'download compiler': function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/externaleditor.test.ts b/apps/remixdesktop/test/tests/app/externaleditor.test.ts index 89e991fdcd..75d074bb00 100644 --- a/apps/remixdesktop/test/tests/app/externaleditor.test.ts +++ b/apps/remixdesktop/test/tests/app/externaleditor.test.ts @@ -2,6 +2,7 @@ import {NightwatchBrowser} from 'nightwatch' const testsBash = { before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hidePopupPanel() done() }, open: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/foundry.test.ts b/apps/remixdesktop/test/tests/app/foundry.test.ts index 3aa370882a..a0457f6ee9 100644 --- a/apps/remixdesktop/test/tests/app/foundry.test.ts +++ b/apps/remixdesktop/test/tests/app/foundry.test.ts @@ -9,6 +9,7 @@ const dir = '/tmp/' + projectDir const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hidePopupPanel() done() }, installFoundry: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/gist.test.ts b/apps/remixdesktop/test/tests/app/gist.test.ts index b53c741910..443581eb0f 100644 --- a/apps/remixdesktop/test/tests/app/gist.test.ts +++ b/apps/remixdesktop/test/tests/app/gist.test.ts @@ -3,6 +3,7 @@ import { NightwatchBrowser } from 'nightwatch' const gist_id = '02a847917a6a7ecaf4a7e0d4e68715bf' const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hidePopupPanel() done() }, 'start gist': function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/git-ui.test.ts b/apps/remixdesktop/test/tests/app/git-ui.test.ts index 813c31da44..ba954da076 100644 --- a/apps/remixdesktop/test/tests/app/git-ui.test.ts +++ b/apps/remixdesktop/test/tests/app/git-ui.test.ts @@ -13,7 +13,7 @@ let gitserver: ChildProcess const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips() + browser.hideToolTips().hidePopupPanel() done() }, after: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/git-ui_2.test.ts b/apps/remixdesktop/test/tests/app/git-ui_2.test.ts index 6a1f3b598b..cd1679a732 100644 --- a/apps/remixdesktop/test/tests/app/git-ui_2.test.ts +++ b/apps/remixdesktop/test/tests/app/git-ui_2.test.ts @@ -13,7 +13,7 @@ let gitserver: ChildProcess const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips() + browser.hideToolTips().hidePopupPanel() done() }, after: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/git-ui_3.test.ts b/apps/remixdesktop/test/tests/app/git-ui_3.test.ts index 6fb96951ff..83906f9285 100644 --- a/apps/remixdesktop/test/tests/app/git-ui_3.test.ts +++ b/apps/remixdesktop/test/tests/app/git-ui_3.test.ts @@ -13,7 +13,7 @@ let gitserver: ChildProcess const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips() + browser.hideToolTips().hidePopupPanel() done() }, after: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/git-ui_4.test.ts b/apps/remixdesktop/test/tests/app/git-ui_4.test.ts index 521462122d..a82a0ad8b9 100644 --- a/apps/remixdesktop/test/tests/app/git-ui_4.test.ts +++ b/apps/remixdesktop/test/tests/app/git-ui_4.test.ts @@ -13,7 +13,7 @@ let gitserver: ChildProcess const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips() + browser.hideToolTips().hidePopupPanel() done() }, after: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/git.test.ts b/apps/remixdesktop/test/tests/app/git.test.ts index 9cc26be3d0..a4f92f4bab 100644 --- a/apps/remixdesktop/test/tests/app/git.test.ts +++ b/apps/remixdesktop/test/tests/app/git.test.ts @@ -4,6 +4,7 @@ import { NightwatchBrowser } from 'nightwatch' module.exports = { '@isogit': true, before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hidePopupPanel() done() }, 'clone a repo': function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/github.test.ts b/apps/remixdesktop/test/tests/app/github.test.ts index 612be7e02f..7e3f83265a 100644 --- a/apps/remixdesktop/test/tests/app/github.test.ts +++ b/apps/remixdesktop/test/tests/app/github.test.ts @@ -3,7 +3,7 @@ import { NightwatchBrowser } from "nightwatch" const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips() + browser.hideToolTips().hidePopupPanel() done() }, diff --git a/apps/remixdesktop/test/tests/app/github_2.test.ts b/apps/remixdesktop/test/tests/app/github_2.test.ts index 3b02b3746c..55f011dee2 100644 --- a/apps/remixdesktop/test/tests/app/github_2.test.ts +++ b/apps/remixdesktop/test/tests/app/github_2.test.ts @@ -3,7 +3,7 @@ import { NightwatchBrowser } from "nightwatch" const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips() + browser.hideToolTips().hidePopupPanel() done() }, diff --git a/apps/remixdesktop/test/tests/app/github_3.test.ts b/apps/remixdesktop/test/tests/app/github_3.test.ts index 12542bb86f..3bcc366964 100644 --- a/apps/remixdesktop/test/tests/app/github_3.test.ts +++ b/apps/remixdesktop/test/tests/app/github_3.test.ts @@ -5,7 +5,7 @@ let commitCount = 0 let branchCount = 0 const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips() + browser.hideToolTips().hidePopupPanel() done() }, diff --git a/apps/remixdesktop/test/tests/app/hardhat.test.ts b/apps/remixdesktop/test/tests/app/hardhat.test.ts index f8c093102e..a9ca651595 100644 --- a/apps/remixdesktop/test/tests/app/hardhat.test.ts +++ b/apps/remixdesktop/test/tests/app/hardhat.test.ts @@ -8,6 +8,7 @@ const dir = path.join('remix-desktop-test-' + Date.now().toString()) const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hidePopupPanel() done() }, setuphardhat: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/offline.test.ts b/apps/remixdesktop/test/tests/app/offline.test.ts index 284d44991a..48f308b7eb 100644 --- a/apps/remixdesktop/test/tests/app/offline.test.ts +++ b/apps/remixdesktop/test/tests/app/offline.test.ts @@ -4,6 +4,7 @@ import { NightwatchBrowser } from 'nightwatch' module.exports = { '@offline': true, before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hidePopupPanel() done() }, 'open default template': function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/search.test.ts b/apps/remixdesktop/test/tests/app/search.test.ts index 8f3ba0a9e7..7b5824d800 100644 --- a/apps/remixdesktop/test/tests/app/search.test.ts +++ b/apps/remixdesktop/test/tests/app/search.test.ts @@ -3,6 +3,7 @@ import { NightwatchBrowser } from 'nightwatch' module.exports = { before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hidePopupPanel() done() }, 'open default template': function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/slitherlinux.test.ts b/apps/remixdesktop/test/tests/app/slitherlinux.test.ts index 21b3f38ea5..8af6d2ea6d 100644 --- a/apps/remixdesktop/test/tests/app/slitherlinux.test.ts +++ b/apps/remixdesktop/test/tests/app/slitherlinux.test.ts @@ -3,6 +3,7 @@ import { ChildProcess, spawn, execSync } from 'child_process' import { homedir } from 'os' const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hidePopupPanel() done() }, open: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/templates.test.ts b/apps/remixdesktop/test/tests/app/templates.test.ts index 86528458e9..78d36507e9 100644 --- a/apps/remixdesktop/test/tests/app/templates.test.ts +++ b/apps/remixdesktop/test/tests/app/templates.test.ts @@ -3,6 +3,7 @@ import { NightwatchBrowser } from 'nightwatch' module.exports = { before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hidePopupPanel() done() }, 'open default template': function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/xterm.test.ts b/apps/remixdesktop/test/tests/app/xterm.test.ts index df238fbcc9..c7c32c0303 100644 --- a/apps/remixdesktop/test/tests/app/xterm.test.ts +++ b/apps/remixdesktop/test/tests/app/xterm.test.ts @@ -5,6 +5,7 @@ import {NightwatchBrowser} from 'nightwatch' const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hidePopupPanel() done() }, open: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/xtermwin.test.ts b/apps/remixdesktop/test/tests/app/xtermwin.test.ts index cf7b1e5be4..f714d736cf 100644 --- a/apps/remixdesktop/test/tests/app/xtermwin.test.ts +++ b/apps/remixdesktop/test/tests/app/xtermwin.test.ts @@ -2,6 +2,7 @@ import {NightwatchBrowser} from 'nightwatch' const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { + browser.hidePopupPanel() done() }, open: function (browser: NightwatchBrowser) { 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 } From 504ea40ef9119aea78a4a0e3e8b27d767fd03dee Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 08:10:58 +0100 Subject: [PATCH 36/82] rm pause --- apps/remix-ide-e2e/src/helpers/init.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/remix-ide-e2e/src/helpers/init.ts b/apps/remix-ide-e2e/src/helpers/init.ts index 1caa647862..9b8351f06b 100644 --- a/apps/remix-ide-e2e/src/helpers/init.ts +++ b/apps/remix-ide-e2e/src/helpers/init.ts @@ -15,7 +15,6 @@ export default function (browser: NightwatchBrowser, callback: VoidFunction, url .pause(5000) .switchBrowserTab(0) .hidePopupPanel() - .pause() .perform((done) => { if (!loadPlugin) return done() browser From 493110dac2d3527e17be407257f254bf523fc802 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 08:28:01 +0100 Subject: [PATCH 37/82] hide on desktop --- apps/remixdesktop/test/tests/app/compiler.test.ts | 1 - apps/remixdesktop/test/tests/app/externaleditor.test.ts | 1 - apps/remixdesktop/test/tests/app/foundry.test.ts | 1 - apps/remixdesktop/test/tests/app/gist.test.ts | 1 - apps/remixdesktop/test/tests/app/git-ui.test.ts | 2 +- apps/remixdesktop/test/tests/app/git-ui_2.test.ts | 2 +- apps/remixdesktop/test/tests/app/git-ui_3.test.ts | 2 +- apps/remixdesktop/test/tests/app/git-ui_4.test.ts | 2 +- apps/remixdesktop/test/tests/app/git.test.ts | 1 - apps/remixdesktop/test/tests/app/github.test.ts | 2 +- apps/remixdesktop/test/tests/app/github_2.test.ts | 2 +- apps/remixdesktop/test/tests/app/github_3.test.ts | 2 +- apps/remixdesktop/test/tests/app/hardhat.test.ts | 1 - apps/remixdesktop/test/tests/app/offline.test.ts | 1 - apps/remixdesktop/test/tests/app/search.test.ts | 1 - apps/remixdesktop/test/tests/app/slitherlinux.test.ts | 1 - apps/remixdesktop/test/tests/app/templates.test.ts | 1 - apps/remixdesktop/test/tests/app/xterm.test.ts | 1 - apps/remixdesktop/test/tests/app/xtermwin.test.ts | 1 - libs/remix-ui/app/src/lib/remix-app/remix-app.tsx | 3 ++- 20 files changed, 9 insertions(+), 20 deletions(-) diff --git a/apps/remixdesktop/test/tests/app/compiler.test.ts b/apps/remixdesktop/test/tests/app/compiler.test.ts index 7da49f2685..2fce46320c 100644 --- a/apps/remixdesktop/test/tests/app/compiler.test.ts +++ b/apps/remixdesktop/test/tests/app/compiler.test.ts @@ -3,7 +3,6 @@ import { NightwatchBrowser } from 'nightwatch' module.exports = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hidePopupPanel() done() }, 'download compiler': function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/externaleditor.test.ts b/apps/remixdesktop/test/tests/app/externaleditor.test.ts index 75d074bb00..89e991fdcd 100644 --- a/apps/remixdesktop/test/tests/app/externaleditor.test.ts +++ b/apps/remixdesktop/test/tests/app/externaleditor.test.ts @@ -2,7 +2,6 @@ import {NightwatchBrowser} from 'nightwatch' const testsBash = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hidePopupPanel() done() }, open: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/foundry.test.ts b/apps/remixdesktop/test/tests/app/foundry.test.ts index a0457f6ee9..3aa370882a 100644 --- a/apps/remixdesktop/test/tests/app/foundry.test.ts +++ b/apps/remixdesktop/test/tests/app/foundry.test.ts @@ -9,7 +9,6 @@ const dir = '/tmp/' + projectDir const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hidePopupPanel() done() }, installFoundry: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/gist.test.ts b/apps/remixdesktop/test/tests/app/gist.test.ts index 443581eb0f..b53c741910 100644 --- a/apps/remixdesktop/test/tests/app/gist.test.ts +++ b/apps/remixdesktop/test/tests/app/gist.test.ts @@ -3,7 +3,6 @@ import { NightwatchBrowser } from 'nightwatch' const gist_id = '02a847917a6a7ecaf4a7e0d4e68715bf' const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hidePopupPanel() done() }, 'start gist': function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/git-ui.test.ts b/apps/remixdesktop/test/tests/app/git-ui.test.ts index ba954da076..813c31da44 100644 --- a/apps/remixdesktop/test/tests/app/git-ui.test.ts +++ b/apps/remixdesktop/test/tests/app/git-ui.test.ts @@ -13,7 +13,7 @@ let gitserver: ChildProcess const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips().hidePopupPanel() + browser.hideToolTips() done() }, after: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/git-ui_2.test.ts b/apps/remixdesktop/test/tests/app/git-ui_2.test.ts index cd1679a732..6a1f3b598b 100644 --- a/apps/remixdesktop/test/tests/app/git-ui_2.test.ts +++ b/apps/remixdesktop/test/tests/app/git-ui_2.test.ts @@ -13,7 +13,7 @@ let gitserver: ChildProcess const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips().hidePopupPanel() + browser.hideToolTips() done() }, after: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/git-ui_3.test.ts b/apps/remixdesktop/test/tests/app/git-ui_3.test.ts index 83906f9285..6fb96951ff 100644 --- a/apps/remixdesktop/test/tests/app/git-ui_3.test.ts +++ b/apps/remixdesktop/test/tests/app/git-ui_3.test.ts @@ -13,7 +13,7 @@ let gitserver: ChildProcess const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips().hidePopupPanel() + browser.hideToolTips() done() }, after: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/git-ui_4.test.ts b/apps/remixdesktop/test/tests/app/git-ui_4.test.ts index a82a0ad8b9..521462122d 100644 --- a/apps/remixdesktop/test/tests/app/git-ui_4.test.ts +++ b/apps/remixdesktop/test/tests/app/git-ui_4.test.ts @@ -13,7 +13,7 @@ let gitserver: ChildProcess const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips().hidePopupPanel() + browser.hideToolTips() done() }, after: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/git.test.ts b/apps/remixdesktop/test/tests/app/git.test.ts index a4f92f4bab..9cc26be3d0 100644 --- a/apps/remixdesktop/test/tests/app/git.test.ts +++ b/apps/remixdesktop/test/tests/app/git.test.ts @@ -4,7 +4,6 @@ import { NightwatchBrowser } from 'nightwatch' module.exports = { '@isogit': true, before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hidePopupPanel() done() }, 'clone a repo': function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/github.test.ts b/apps/remixdesktop/test/tests/app/github.test.ts index 7e3f83265a..612be7e02f 100644 --- a/apps/remixdesktop/test/tests/app/github.test.ts +++ b/apps/remixdesktop/test/tests/app/github.test.ts @@ -3,7 +3,7 @@ import { NightwatchBrowser } from "nightwatch" const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips().hidePopupPanel() + browser.hideToolTips() done() }, diff --git a/apps/remixdesktop/test/tests/app/github_2.test.ts b/apps/remixdesktop/test/tests/app/github_2.test.ts index 55f011dee2..3b02b3746c 100644 --- a/apps/remixdesktop/test/tests/app/github_2.test.ts +++ b/apps/remixdesktop/test/tests/app/github_2.test.ts @@ -3,7 +3,7 @@ import { NightwatchBrowser } from "nightwatch" const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips().hidePopupPanel() + browser.hideToolTips() done() }, diff --git a/apps/remixdesktop/test/tests/app/github_3.test.ts b/apps/remixdesktop/test/tests/app/github_3.test.ts index 3bcc366964..12542bb86f 100644 --- a/apps/remixdesktop/test/tests/app/github_3.test.ts +++ b/apps/remixdesktop/test/tests/app/github_3.test.ts @@ -5,7 +5,7 @@ let commitCount = 0 let branchCount = 0 const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hideToolTips().hidePopupPanel() + browser.hideToolTips() done() }, diff --git a/apps/remixdesktop/test/tests/app/hardhat.test.ts b/apps/remixdesktop/test/tests/app/hardhat.test.ts index a9ca651595..f8c093102e 100644 --- a/apps/remixdesktop/test/tests/app/hardhat.test.ts +++ b/apps/remixdesktop/test/tests/app/hardhat.test.ts @@ -8,7 +8,6 @@ const dir = path.join('remix-desktop-test-' + Date.now().toString()) const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hidePopupPanel() done() }, setuphardhat: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/offline.test.ts b/apps/remixdesktop/test/tests/app/offline.test.ts index 48f308b7eb..284d44991a 100644 --- a/apps/remixdesktop/test/tests/app/offline.test.ts +++ b/apps/remixdesktop/test/tests/app/offline.test.ts @@ -4,7 +4,6 @@ import { NightwatchBrowser } from 'nightwatch' module.exports = { '@offline': true, before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hidePopupPanel() done() }, 'open default template': function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/search.test.ts b/apps/remixdesktop/test/tests/app/search.test.ts index 7b5824d800..8f3ba0a9e7 100644 --- a/apps/remixdesktop/test/tests/app/search.test.ts +++ b/apps/remixdesktop/test/tests/app/search.test.ts @@ -3,7 +3,6 @@ import { NightwatchBrowser } from 'nightwatch' module.exports = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hidePopupPanel() done() }, 'open default template': function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/slitherlinux.test.ts b/apps/remixdesktop/test/tests/app/slitherlinux.test.ts index 8af6d2ea6d..21b3f38ea5 100644 --- a/apps/remixdesktop/test/tests/app/slitherlinux.test.ts +++ b/apps/remixdesktop/test/tests/app/slitherlinux.test.ts @@ -3,7 +3,6 @@ import { ChildProcess, spawn, execSync } from 'child_process' import { homedir } from 'os' const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hidePopupPanel() done() }, open: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/templates.test.ts b/apps/remixdesktop/test/tests/app/templates.test.ts index 78d36507e9..86528458e9 100644 --- a/apps/remixdesktop/test/tests/app/templates.test.ts +++ b/apps/remixdesktop/test/tests/app/templates.test.ts @@ -3,7 +3,6 @@ import { NightwatchBrowser } from 'nightwatch' module.exports = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hidePopupPanel() done() }, 'open default template': function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/xterm.test.ts b/apps/remixdesktop/test/tests/app/xterm.test.ts index c7c32c0303..df238fbcc9 100644 --- a/apps/remixdesktop/test/tests/app/xterm.test.ts +++ b/apps/remixdesktop/test/tests/app/xterm.test.ts @@ -5,7 +5,6 @@ import {NightwatchBrowser} from 'nightwatch' const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hidePopupPanel() done() }, open: function (browser: NightwatchBrowser) { diff --git a/apps/remixdesktop/test/tests/app/xtermwin.test.ts b/apps/remixdesktop/test/tests/app/xtermwin.test.ts index f714d736cf..cf7b1e5be4 100644 --- a/apps/remixdesktop/test/tests/app/xtermwin.test.ts +++ b/apps/remixdesktop/test/tests/app/xtermwin.test.ts @@ -2,7 +2,6 @@ import {NightwatchBrowser} from 'nightwatch' const tests = { before: function (browser: NightwatchBrowser, done: VoidFunction) { - browser.hidePopupPanel() done() }, open: function (browser: NightwatchBrowser) { 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 f3738ee5b8..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 @@ -13,6 +13,7 @@ import { IntlProvider } from 'react-intl' import { UsageTypes } from './types' import { appReducer } from './reducer/app' import { appInitialState } from './state/app' +import isElectron from 'is-electron' declare global { interface Window { @@ -45,7 +46,7 @@ const RemixApp = (props: IRemixAppUi) => { const [appState, appStateDispatch] = useReducer(appReducer, { ...appInitialState, - showPopupPanel: !window.localStorage.getItem('did_show_popup_panel') + showPopupPanel: !window.localStorage.getItem('did_show_popup_panel') && !isElectron() }) useEffect(() => { From 8bce86f2de9378b128787a464cc93e722f20088a Mon Sep 17 00:00:00 2001 From: lianahus Date: Tue, 5 Nov 2024 09:53:44 +0100 Subject: [PATCH 38/82] adding the avatar for ai --- apps/remix-ide/src/assets/img/aiLogo.svg | 77 ++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 apps/remix-ide/src/assets/img/aiLogo.svg 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From a36d473a88e1d584436a4211ea83a4fe2fb73b97 Mon Sep 17 00:00:00 2001 From: lianahus Date: Tue, 5 Nov 2024 15:13:44 +0100 Subject: [PATCH 39/82] icon for chat got new style --- .../src/app/components/popup-panel.tsx | 2 +- .../css/themes/bootstrap-cerulean.min.css | 1 + .../css/themes/bootstrap-cyborg.min.css | 1 + .../css/themes/bootstrap-flatly.min.css | 1 + .../css/themes/bootstrap-spacelab.min.css | 1 + .../assets/css/themes/remix-black_undtds.css | 1 + .../assets/css/themes/remix-candy_ikhg4m.css | 1 + .../assets/css/themes/remix-dark_tvx1s2.css | 1 + .../assets/css/themes/remix-hacker_owl.css | 2 +- .../assets/css/themes/remix-light_powaqg.css | 1 + .../css/themes/remix-midcentury_hrzph3.css | 1 + .../src/assets/css/themes/remix-unicorn.css | 1 + .../src/assets/css/themes/remix-violet.css | 1 + .../src/lib/components/custom-tooltip.tsx | 3 +- .../helper/src/types/customtooltip.ts | 1 + .../src/lib/components/homeTabGetStarted.tsx | 2 +- .../statusbar/src/lib/components/aiStatus.tsx | 83 +++++++++++-------- libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx | 2 +- 18 files changed, 65 insertions(+), 41 deletions(-) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index 3e5155d181..4ebc8a77bd 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -95,7 +95,7 @@ export class PopupPanel extends AbstractPanel { height: '40rem', position: 'fixed', bottom: '2rem', - right: '3.5rem', + right: '1.5rem', zIndex: 200, boxShadow: "0 1px 7px var(--secondary)" }} 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/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) { -
- +
+ + { !appContext.appState.showPopupPanel &&
+ + 👋 I'm here to help you! + + +
+ } +
) } \ No newline at end of file diff --git a/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx b/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx index bae6a258c2..eaaffcad15 100644 --- a/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx +++ b/libs/remix-ui/tabs/src/lib/remix-ui-tabs.tsx @@ -279,7 +279,7 @@ export const TabsUI = (props: TabsUIProps) => { methods: ['code_generation', 'code_completion', "solidity_answer", "code_explaining", "code_insertion", "error_explaining", - "initialize", 'chatPipe', 'ProcessChatRequestBuffer', 'isChatRequestPending', 'toggle'], + "initialize", 'chatPipe', 'ProcessChatRequestBuffer', 'isChatRequestPending'], events: [], icon: 'assets/img/remix-logo-blue.png', description: 'RemixAI provides AI services to Remix IDE.', From 2de6d2880d507cbbac50fb06e6d0c82c16ce86c3 Mon Sep 17 00:00:00 2001 From: lianahus Date: Tue, 5 Nov 2024 15:20:36 +0100 Subject: [PATCH 40/82] color fix --- libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx index 67d60045a9..1a2a157a9a 100644 --- a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx @@ -66,7 +66,7 @@ export default function AIStatus(props: AIStatusProps) { color: 'var(--ai)', alignItems: 'self-end', }}> - Date: Tue, 5 Nov 2024 15:32:59 +0100 Subject: [PATCH 41/82] linter --- apps/remix-ide/src/assets/img/aiLogoHead.webp | Bin 0 -> 66260 bytes .../statusbar/src/lib/components/aiStatus.tsx | 66 +++++++++--------- 2 files changed, 33 insertions(+), 33 deletions(-) create mode 100644 apps/remix-ide/src/assets/img/aiLogoHead.webp 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 0000000000000000000000000000000000000000..d026f81bbf60f9cdf6ab24ad4f7b09ac099106af GIT binary patch literal 66260 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 z

G2uOu)?mt>yo4dsLKKJEghEm>Y7KQ!Z61CUp(uajRwmfdcviMm zO1#CqaE~7 z7Bhv+sO!z~$%`x4=r#pv`6Rvs2rNvklRp>U&YY!X8cyeP$W2vVHL70ZbinH#i;BN>gkGnN{%ak=2gpyObse|$hG#z<)_TVnHYm;q9sox zsEk{un*b}~A|FG4N5ojvpEPpcD$%^YIUw0MAS_K*xiE~cPb~lGEnJG5CBz}{NroMM z#gNK+^N3~oyP|+d_ucVsSV3-7sXBDy51`fI2P)CU@E89b#jS}wQv&#@$|C7@C5SutC4f!_+k z3-1U*{WgT8-PV!D*kq*e8HmVZ%ow?Y1QfC%-66=ND)I4Md`)L%Xj80)R6AaLuqo{_ zeQg5vA{NsdncI1DO#ESx<_&rLL#6|=^WhP3n*ORr36+7A# z8xe$MV0;yRv5*@(Mg5Ni%KhY1G2VW-4U&*VdtoofgZ%(CQFR*Q_$ZEcuagu3y37cC z7nnqwLjZ-$mB2%0V|`u4OrIf7G0Em#!UMaK@>j-VqwgSJX|epyn8ww$g(D6Dyf^P( zh0F>mnD%Cc3BE+der3CMIJkMgN%VagJ$QyiZ3`)S#s}p2v-B3ps4#vh3rmT_KBhx7 z)OcKNfoc^E*{~aj=Mt>h2G#O{Svx+7?%=QgXtA>-K#7W<3RVcQi*+v2vF+cZjoWgi zl}7c6u)0;Jr9-U@H@gv|uVi&!;~!L|%zCg*Um}fF#>nT_`QQq<1b4sKj8gf4dgKV1 znV*{74=dRdwVEm9;8#5RB#)f^5yNv?eir%Ch;WrH;?!=!HT%>3k>YnHq+L9|<@#1{ z{Lg?j1w#-O5rsu1ek^LX>gUY9<}-n5xeZV9+1LBjxe_Ocjxv!taAbU6B1mcgB7(yu z2~Lc2oPp5Q);VOt$U0CUBcZT{?h|47{5jUi6z&3DEp-045ya7TJF)pSTK$ZJ8nVa_ zgkOFXZanqo!1N z*rk=y;EvF~=S>n;sHsG=X|Q30Z`uH+CN|c!Eu1rMMFw8@xpp941%x$yc$?7H|Evwo+v1Z5G< zHY;>S6sY-7G96qMCClWe@BDDeS4UtuZFKbbxK+x26nD|l-w+4v-29KtNfPtn^gvb- zTigO&k1(HRee&JasAOLYdx{@9X^lju(;qP0e)L`-u;&FYsx46&43(X4Cwnu&5$9}z zU>WzBoLtO$&&K2toRPB*d59Crf}H%;!Z}CKn=%Lzox06K5JiBVAb&FB2Ep5>4;m7_ z?2BG929Lh*E&q40$AQ+(St#3TjW4vNbSg|f!5TBz;qI?x(@9)8LC4a^RP&W7_Rmw~ zF?s5E(63o3UMVt(xmDGNXe0~jwAOCwpNdGYVX?p%N^=>BTcXEBnWjBlBU;vRkFAS~ z9^v_ z3CL$Ic-UcJi3Mf$ZuHMhrAgfU;52d){#pENLAO;0he9?t=4THBuW9zRP*<#S-Q3wzp_S+-@cAY*}paWeJrwfuzCwg%>x1P{x%pHnX{3iU}q>T z(rtE=gQ(OXt$oDtZ+dMS(Ea6U!)7mYWk<~-UCE+1v;zOzmMYfvAn$~N^|RfQ!)-_6 zw|RwVxpgbE?4KzvbqbnP*n|gfw*@ah7BjPr5P@Ez`atxsQi48-W+kj^PLY%&uI@d7 zrhT|602iGkxEG`(VAJ!I+bwXg``L%;%PpoM)rnS?^C0ik*{2*P8(@s%Ad?D4^~zT; zV(gyw_c6BV=EiRHJw|1xzjd5NM1?!Y*Anby)djq#nIt{_^X2QajqV8ik(j+uqy<@@ z+3cW|6^o)ZRm#Idf59Z<*cjJRG8=P@92);VeYU`rZ zK*d{rLL1@*@1V{TX=sFxMM%qT!I_XM;+Ywo+GR{t@QoYxM|N?tQZ!~yPQ=!X^!n!Ihx+vN+2U%<~Jq%VF$@lNh3q`&maLhk2<5HcJ;dS8ZI9*BL1H4_bCX_!c!-5#6 zf0M-wfo21r@am3L)cCCM5uFqBZ9#pk!B!$HSuS&c*Hv#h&6d_yesYoOC;>T5cr2&J zshjts@3t+iKF(Xc7mrRQG32I1Pajh_R|_2e&z#n4D{WL3(tkZM-L`svAJ5D2@dr6z zEz%gGc81vq)02HMZcH|4*xdTU^6FTa)j5(G0}C3ec-57mhwrEwOxujJnu@1Pw7axy zB;wQ|RB*A=PL=?Nl;oXPe|4+a{e~?u96`KH6PGsyBcF~6>4(XJXfPKde|P^^LGh@j-M%ywVklGz!dh%*fQ#{twIv0lwt^ z!ibRV9P+Hs#3(@$2yuo=w0;}~;VPJ+{Xvv7HpRYio;pU}0)I?Tl|vr}+sSqLM-x%+ zn&NpARm%!u;|lVJTBL%iL8Fd$Y7nx)rByGGBvSX4C$5yu zPzAv!mv)H#!6vJ_$twT4c0*g;&f$hn|HhGbv#*=aBYgw%3>BM2_v_4w<&5R#0E55K zK7rp-|0;>-6}Jxw2A5TDK}4rBayZkfVMqQ{h}j#CFyg*mJ@#B?zANC*a4pso?op?w zW#yNPIx@xx6$ivJ{Pn`AT^l|nj{MNE122vr!QZ$8Wqn0!t*01aQewF+JupX1jxTmr zP_YJmCFDeje~N!Zm-8c02a;L7Cb6uC@Pz0b+fS}aO5wTxj;Niw0xU4E~H)!JW2m| zZnLnsl^U1ccOln>*LMa_508WJnzp&2rka{R?!0IhtyAb7QkeSny}zPfr+}*>q3zcb zEU=3f!8J4`2xeQ=)ZYA@y@K^u^r4$xiMU)R^POH*kB`M7sJjG)qR(lRQASwsT6FkS zj5rqANiKCQf+tkUn6gTR;x9o&+)dp=fV23rU(Z7`uN-Dk3K=>c;4h zp^F98$G%(Kf*H>QK!(8u(v$9QH(^7QM-2W^f)6R7zLYAOt=Rjf31^cf$vR&l9n+;zHump@@Z8K85>ro(8ID0h-Z6f5X*`brg6h`1p=Brp3vj7pd_~@E0NQ1kyCvgF}6DD z@o1k4l8qRMJ>Z&)L2O2bM=1$&>q|-D=*^-)LG>-jl?d%u4q0O&!=OAxm7ezcgkzpR zyy0E;+u4RLRa&(~^B2fv4UZL%^s~?_IJ{Zj+88z~@)W0(PrVqY${XZdz>76IGk7A9 z3+_f^1fVGY{i8QXq9)t0y5gY4;Nkx)`aDx~*~(2Q>(J29XUTVrv%11Dm2(x4e`2>4 z08Mz{UzIx<<~~2iaT=0 z+nq4Bf-FFhEMl&I0ca4L)X%;}}xSI@%9e8$PuGC3q# z{sA4=Y&7CTqQ%hkn$t)mcal9y|36w*4PfxlVeA43T_Q+ApLKOT`P$Y?$pZQ9ShjZq zOZ6M4P_6qEQB7Z75EM1HzMRNp{JW2}GVqAutF?|z&M4zRP)*^WV^2&yw6|4tb0d|} zX!+zMA3K(XG%S*9KFk5EUv*gje)YR1+sb=Ske}apwJnOIsXY_dy=2Xux2SR?PJ&|% zGDL}`CAwU~RBb@Hpv0o@eULf7Bc5?g^TsK2KvaIN4a#`%6igSV-Ns z%V#(iiJAUr1gvyxpz67>2pesNdn- z8<2_bckF| zus*=c!_ZIU?qPlV(ZDb%fyohxEZ+zh$Mn!pp7;4n%vYBx@JowiflhWAz-AZ*vrJQB z#}oeQSU23}$w4#~93KtL3nYn*i?d#uc`4;tZP(7ODc$9rrOP#A%K**EQYK8T^GK7x zQzcHFry)yX*@eaL*)1O9WH}gv%Pjc|W9TC#bZ?i=ES%mmTcd%TI;}($TCp^Z6Cta_NijFU=3j>8J9Cd`0hFDb+dd;)U^U=Y-%%o|Sbte;ZZOyBO;NdXyl!Df zPDYl*4W&G`YYs*VeY-2WaWXAAE2Du$ibDCFOwEO{B!K$6lz3J<#ELFt=-OuX^N%$D zG;d%_@<%Q?DiOgvH0p91`c)^EZDV%EOXPYbw^AeS5;1!BV_ zkPRMLU2v_k^IV`(om8dd1*97pHy1^sGRr548f(Q0ZO^4e&~cy~@#p=X;?mxAM%9Ss zAm0d^{tqgX#>3F;s`6oXkCI9qKJWFeq|?)s2`mzLPKHIIcB&re)4>;x>Q!S^PwRP4 zQD*t(3Y`g)B*kUs_5f;-_LUflf#vTSKEapP+K(o$v>Hon+C|VN4b(Y;%ozGlK zDs=W(F@f0FS{ngMNN1VJrn|FiT#k&^g#ZK=VCj6lL4DY$J>Dk=t z4lKsRDEb}V@(C>9DuKN-Yh4GD83z#`0{hGB_Yv0B&iUNVDuOJ2DIO+&pKXhTt1VbE z|EIT)iwd`i6H_tvn4zImF^1(VbWZZaN315R6U?cr)Vvq=cyQWf(#+Ku+ux$ItasZh zpYEpf1ZbhD*rv&)&y~9Gy5lmtiKibkdt=Y`j-oI0=f{&t<3-2)mW;ALxZ~W^klo~d zSSP1wo$p~QN39^b$9FJZd1)@WZQ3qJth|A zywY?nj&xPU1w1W(Ha2l`T-W0_7T7EGYHObp?l2mcrFxy9aOKP8k3_Ez@BTH(n-P6sxYy6OB1<_3+F(dnu?LYtAn1EHti=f81#5yl7vgSN@1| zI%n=>c*hNa@o0t$B%GCPJkDsZYt=zzJs%w(ArF>LD|t0OIuC27I|mQ!j^R3!WhD&n zitl+p0-la)*Lshno@6{9oqAqI-n}B^jv~mGYRGh*$nZ>}H$5eO-MtBEu>@C=Fs$Mw z4#Jz6{c2jctta2h45oF2JJtE(FnHUl{_%2C>9rccQ_FR+xs2FT3VmPp?)fjOv-{yS zr)L6!FPul^s33OL`P{bIc7$zVF?c_4_b@s!a&~e0)cf9eUt14$OamFGyY5**a;!Zp zo7;DkxFaMyP6YRWu>1`d_Z6$gQ@@Mm_>T)0kH=q+yz9^QmS#fcB%)7H!dw9e3{)EK% zs@6!?N^hC}l8pcHj3gAIvq`rMx$pUsnSJ)CcF}YFFnUk(+v7chu(e_REd)9x{<<|@ zBJlh?o9m%j?Oo*krMr-grKIu<)~!f$zhcCaJNsw<#hS<2eGYiYm~hD<)vS!OqR#un*nKxZAO%{r;Hv(8yw>pKc< zcT9MUyYlsUd%WuMJGuzD=e@uG^{CVS<2v3L>Lb#X0MYY<sXaOrsnlVa8s{3xu}%~0IBY0j(>8ZxE6K#~ z7_{fh)l_w2Y0Itr!Z*_m-GaVd-8kjHPC%?fK38=9X4}{meJU{KeJ}c9v3Gyz3!Qwp zBkQ0kJK||VRb*aj?VYcrtHJ!wsDb?|r|##Bz^i!;O@t<|2Cd0$BT8sdj^xJlY22XTZ~|V_{qxbbSj_j@JhP@sB zfB(}{sbkKO+LaN36-mY7{nqZxUNcWc<$d0C6Iq;~g(@WW=Qt4jpK;j=aH!3O%#W=8 zY4|JtG1Ji78#3xCeDlxw?1x|Hl5ySWlwi%BS@-=|@AX0##c>V!wa7R&s|n&uiNm_qm9fsTE(b<@Xvf z?t#Wz3dcgv3Dfou80bn6(wa^)&Q68np1D;Pz;{WtdH=Q?{5t1q?&>hLDdLO}sd(mj zDI5&##2+61<$erpK3v?_cPByqi?Ln;qpo?e&lE(Xf1mn$Gn^N2H$>)-@3go zzkl_f=)OAbJN2Bc@3&+;&7syw`>w&*(e)z);tB^-@ai^1nAknN7VKliXe;0bWRCkQxWsG+9qexF5)P(4cU^yy=S>{I)EOoI~s;9 zN4922wS6299sk`kJmg`xN%0;wG!(s8&4>p;ndGx8b6Y;2_b%Jye10?PeOwg(7?Kzf zo2y>wS{+I?F7{StA?bKwetXX&LSIxH68m-};$$!ixl^sh^wN>i2v-uufJG>{UXgpp z(!oP8!?JQQV?+Zn#Xt~6C ztOsDITvwIHyeTM%O60z)_X%t5uNInIAt5c+QdP7-IKfNmalI5Pb0YWH%Xf-e{<_t= zRdN;*en-a|*F98o)gqy^0#1H!o6B?xYqIG}(1*YK{ZaKfG|IT*eCryzPXT?La55EY zvesbTQ0^T(a9%g>h#;*GM)eXE@~RpJ*K|M-;^u&w1y%*W5UaCfkSsjxS=B-&O@AR) zM8hr#yNd5-wYip${V(09j zm{^*l&DPOH-e2>DU?p!WzAcHfp(-Z{7>@;|X>sHLS>k_(Nf;so5e>RE_PASKPaK_6 zpZ(a&OufKSo|(v^Ilo&sIt@{-W_e?CUn(^2G+FlV;}V1Bbp;^boS7`M#o1IE_!#pc zVH(%XkyglO%k}t6=@N+=&uyZ>F8&R0Mw8V097`a@NO;D z^D=1ec43ZuZMHp3lui@?dJC2&4p6eyCZyM}wY3M4=$gG+hSZ8 zhGW1EZV$W8HUXm>)%nUJw_n#9pI@S|j@hEm^8$t6Pe&j5TppIs&6I{~N99*i;Q$L?Xz0*o^fKnI}IgJxPg7-OW zy(MeO;de!7n!kGd=x#5Z7_k;{+6MAFb{x;U!RgO9a1gR!{hiX}kDzRIo&bZl&e?nY zZmgijAB5Hm^*4|Xf$W8VO7U4Y126vSF{#;OQt`PTHSM#-wu7V$yQ^l2Vn`j776QYz zwQ#UWg`vb~BR75qUr<>lSzq3(t&VTzDg~#J=?uNe2V7g$^Kb>sy6xAWwh8xzFP}!Y zE49x`L*Z8PiyPX5`FjD;nyh&Wx!Y~ESoJTY?O30SVnQWh!Q}B&eTC@1e#R&Z ziihq95TT)kKUeODZa+lR^PSKVN_A%K6dloem!09+6IjBq{v$Kk{lYWgWkp^-i9QyZ ziStcN8RmPXX1J-)if_Xt_CE&<%+j)b~? z@R+6T%eo^!I(O;KDP6Xg3&OH$GLLfS&Hk0`kLfc)e7M(!WWTJrMl4YZ;o9L4`$k8PVIMaA#jHMZ?fV)|ZiVNOb@Zvy3hrc5YMEr1II(@oYLmyo; zoYOwHm`d`^XEtne$7SPSl#Gw`oYtx3TKX4s&Ge|+*z4y)xATi?ZOzQ^0jNSYAeTa3 zjbOs=$i@$U=E0>_OvFnH-?e~o#HDS8SuLVMIc$z}Ex%L%rCz^s$*ywQ)!LYK{479D zGPzesK%n?CK_Yu)pCvHIML(D8D^FNYZS_bg@Z=o`p?3cB7Sx_qD&WtQ#4Ji4^7d!h=5#2Gj|LCPi7;dGTgHoK5NGAX<{~Mo+?{$L6In~j+H2F

z1hL5wipCp@AA*)^56_L~9)nW@-h}JI{g6Z%#i!f_U$AN)?{AAqb4>k}f+x}ag1+DG zin7mq2U1O2o7o^qHZAly69Wx$;<iRKn4< z4+J_bVg_XTO|a1uZKgn zGM9$AlEoN_KTGz04CJ<8e6j7j0(Aq!>2ngWe~^8UU6wDndUus(sUNy_B)o}1=W1-T zg-$}YZ*SJ;)&#M3C_OJQ (arNj_QeJS~s8x!0nj&*;TTB!Q% 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 literal 0 HcmV?d00001 diff --git a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx index 1a2a157a9a..5ba0c390ff 100644 --- a/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx +++ b/libs/remix-ui/statusbar/src/lib/components/aiStatus.tsx @@ -60,40 +60,40 @@ export default function AIStatus(props: AIStatusProps) { } `} { !appContext.appState.showPopupPanel &&

+
+ +
}
From 420575bae6f46e2334567bb1295fbb5f3b122b91 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 15:53:59 +0100 Subject: [PATCH 42/82] CI fix --- apps/remix-ide-e2e/src/commands/hidePopupPanel.ts | 4 ++-- apps/remix-ide/src/app/components/popup-panel.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/remix-ide-e2e/src/commands/hidePopupPanel.ts b/apps/remix-ide-e2e/src/commands/hidePopupPanel.ts index 29baee5523..dd646722a5 100644 --- a/apps/remix-ide-e2e/src/commands/hidePopupPanel.ts +++ b/apps/remix-ide-e2e/src/commands/hidePopupPanel.ts @@ -9,8 +9,8 @@ class HidePopupPanel extends EventEmitter { return localStorage.getItem('did_show_popup_panel') }, [], function (result) { if (!result.value) { - browser.waitForElementVisible('*[data-id="aiStatusButton"]') - .click('*[data-id="aiStatusButton"]') + browser.waitForElementVisible('*[data-id="popupPanelToggle"]') + .click('*[data-id="popupPanelToggle"]') } done() }) diff --git a/apps/remix-ide/src/app/components/popup-panel.tsx b/apps/remix-ide/src/app/components/popup-panel.tsx index 4ebc8a77bd..5d27c38828 100644 --- a/apps/remix-ide/src/app/components/popup-panel.tsx +++ b/apps/remix-ide/src/app/components/popup-panel.tsx @@ -104,7 +104,7 @@ export class PopupPanel extends AbstractPanel {
+
) -} \ No newline at end of file +} From 2c7a6e20c308e670ddf855f938a3677ebd4c1ce4 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Tue, 5 Nov 2024 22:14:59 +0100 Subject: [PATCH 47/82] Update url.test.ts --- apps/remix-ide-e2e/src/tests/url.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/url.test.ts b/apps/remix-ide-e2e/src/tests/url.test.ts index 8a77f2e60c..43ee8e48f3 100644 --- a/apps/remix-ide-e2e/src/tests/url.test.ts +++ b/apps/remix-ide-e2e/src/tests/url.test.ts @@ -97,8 +97,8 @@ module.exports = { .refreshPage() .pause(7000) .currentWorkspaceIs('code-sample') - .waitForElementVisible('*[data-id=treeViewLitreeViewItemsepolia]') - .waitForElementVisible('*[data-id="treeViewLitreeViewItemsepolia/0xdac17f958d2ee523a2206206994597c13d831ec7/contracts/MetaMultiSigWallet.sol"]') + .waitForElementVisible('*[data-id=treeViewLitreeViewItemsepolia]', 20000) + .waitForElementVisible('*[data-id="treeViewLitreeViewItemsepolia/0xdac17f958d2ee523a2206206994597c13d831ec7/contracts/MetaMultiSigWallet.sol"]', 20000) .getEditorValue((content) => { browser.assert.ok(content && content.indexOf( 'contract MetaMultiSigWallet {') !== -1) From b8893fd5f0185c09991682fcfbd8f1b1d89f0522 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 22:34:57 +0100 Subject: [PATCH 48/82] flaky run --- .circleci/config.yml | 2 +- apps/remix-ide-e2e/src/tests/url.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 67b99229f6..73a4af3952 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2.1 parameters: run_flaky_tests: type: boolean - default: false + default: true orbs: browser-tools: circleci/browser-tools@1.4.4 win: circleci/windows@5.0 diff --git a/apps/remix-ide-e2e/src/tests/url.test.ts b/apps/remix-ide-e2e/src/tests/url.test.ts index 8a77f2e60c..b4ba938d59 100644 --- a/apps/remix-ide-e2e/src/tests/url.test.ts +++ b/apps/remix-ide-e2e/src/tests/url.test.ts @@ -91,7 +91,7 @@ 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() From cc4703d9cd6afdd6c7b3136da8a8c000a143b013 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 22:37:29 +0100 Subject: [PATCH 49/82] undo --- .circleci/config.yml | 2 +- apps/remix-ide-e2e/src/tests/url.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 73a4af3952..67b99229f6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2.1 parameters: run_flaky_tests: type: boolean - default: true + default: false orbs: browser-tools: circleci/browser-tools@1.4.4 win: circleci/windows@5.0 diff --git a/apps/remix-ide-e2e/src/tests/url.test.ts b/apps/remix-ide-e2e/src/tests/url.test.ts index b4ba938d59..8a77f2e60c 100644 --- a/apps/remix-ide-e2e/src/tests/url.test.ts +++ b/apps/remix-ide-e2e/src/tests/url.test.ts @@ -91,7 +91,7 @@ module.exports = { }) }, - 'Should load Etherscan verified contracts from URL "address" param) #flaky #group1': function (browser: NightwatchBrowser) { + 'Should load Etherscan verified contracts from URL "address" param) #group1': function (browser: NightwatchBrowser) { browser .url('http://127.0.0.1:8080/#address=0xdac17f958d2ee523a2206206994597c13d831ec7') .refreshPage() From 99289a4bca9598c03a278c79c7ee98a3c294a019 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 22:38:13 +0100 Subject: [PATCH 50/82] flaky test --- .circleci/config.yml | 2 +- apps/remix-ide-e2e/src/tests/url.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 67b99229f6..73a4af3952 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2.1 parameters: run_flaky_tests: type: boolean - default: false + default: true orbs: browser-tools: circleci/browser-tools@1.4.4 win: circleci/windows@5.0 diff --git a/apps/remix-ide-e2e/src/tests/url.test.ts b/apps/remix-ide-e2e/src/tests/url.test.ts index 8a77f2e60c..b4ba938d59 100644 --- a/apps/remix-ide-e2e/src/tests/url.test.ts +++ b/apps/remix-ide-e2e/src/tests/url.test.ts @@ -91,7 +91,7 @@ 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() From a6ba619ce31e953fa8d312cddf514973f062bd86 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 23:04:04 +0100 Subject: [PATCH 51/82] fix url test --- apps/remix-ide-e2e/src/tests/url.test.ts | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/url.test.ts b/apps/remix-ide-e2e/src/tests/url.test.ts index b4ba938d59..15d64def03 100644 --- a/apps/remix-ide-e2e/src/tests/url.test.ts +++ b/apps/remix-ide-e2e/src/tests/url.test.ts @@ -95,15 +95,8 @@ module.exports = { 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"]') From 12b3f27b31a5526e6232ec432dfcf3a68e586154 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 23:10:59 +0100 Subject: [PATCH 52/82] don't click --- apps/remix-ide-e2e/src/tests/url.test.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/remix-ide-e2e/src/tests/url.test.ts b/apps/remix-ide-e2e/src/tests/url.test.ts index 15d64def03..538a1ae95d 100644 --- a/apps/remix-ide-e2e/src/tests/url.test.ts +++ b/apps/remix-ide-e2e/src/tests/url.test.ts @@ -92,6 +92,22 @@ module.exports = { }, '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(2000) + .currentWorkspaceIs('code-sample') + .waitForElementVisible('*[data-id=treeViewLitreeViewItemmainnet]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7"]') + .waitForElementVisible('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7/TetherToken.sol"]') + .click('*[data-id="treeViewLitreeViewItemmainnet/0xdac17f958d2ee523a2206206994597c13d831ec7/TetherToken.sol"]') + .getEditorValue((content) => { + browser.assert.ok(content && content.indexOf( + 'contract TetherToken is Pausable, StandardToken, BlackList {') !== -1) + + }) + }, + 'Should load Etherscan sepolia verified contracts from URL "address" param) #flaky #group1': function (browser: NightwatchBrowser) { browser .url('http://127.0.0.1:8080/#address=0xdac17f958d2ee523a2206206994597c13d831ec7') .refreshPage() From 1982977ce3c2d54d7b26eb995be2b39451d6fd40 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 23:12:34 +0100 Subject: [PATCH 53/82] no sepolia --- apps/remix-ide-e2e/src/tests/url.test.ts | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/apps/remix-ide-e2e/src/tests/url.test.ts b/apps/remix-ide-e2e/src/tests/url.test.ts index 538a1ae95d..9db1b69bac 100644 --- a/apps/remix-ide-e2e/src/tests/url.test.ts +++ b/apps/remix-ide-e2e/src/tests/url.test.ts @@ -107,24 +107,6 @@ module.exports = { }) }, - 'Should load Etherscan sepolia verified contracts from URL "address" param) #flaky #group1': function (browser: NightwatchBrowser) { - browser - .url('http://127.0.0.1:8080/#address=0xdac17f958d2ee523a2206206994597c13d831ec7') - .refreshPage() - .pause(2000) - .currentWorkspaceIs('code-sample') - .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) => { - browser.assert.ok(content && content.indexOf( - 'contract TetherToken is Pausable, StandardToken, BlackList {') !== -1) - - }) - }, 'Should load Blockscout verified contracts from URL "address" and "blockscout" params (single source)': ''+function (browser: NightwatchBrowser) { browser From a1be3eca928586b6f7f6f633e74ea58f038cac71 Mon Sep 17 00:00:00 2001 From: bunsenstraat Date: Tue, 5 Nov 2024 23:19:18 +0100 Subject: [PATCH 54/82] turn off flaky --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 73a4af3952..67b99229f6 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,7 @@ version: 2.1 parameters: run_flaky_tests: type: boolean - default: true + default: false orbs: browser-tools: circleci/browser-tools@1.4.4 win: circleci/windows@5.0 From 302eb8edee1783d0215fd5550364eb21f3da0c00 Mon Sep 17 00:00:00 2001 From: ryestew Date: Mon, 4 Nov 2024 14:50:37 -0500 Subject: [PATCH 55/82] update qdapp logo in udapp and change size of logo --- libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx b/libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx index 37ba859f5f..601147f5d1 100644 --- a/libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx +++ b/libs/remix-ui/run-tab/src/lib/components/universalDappUI.tsx @@ -287,12 +287,12 @@ export function UniversalDappUI(props: UdappProps) { : {instanceBalance} ETH
-
+
{props.exEnvironment && props.exEnvironment.startsWith('injected') && ( }> { props.editInstance(props.instance) }} From f5d6fa0ca383fdad9cde9ac68911652bbb045a05 Mon Sep 17 00:00:00 2001 From: lianahus Date: Tue, 29 Oct 2024 10:20:52 +0100 Subject: [PATCH 56/82] matomo updates --- apps/remix-ide/src/app/components/preload.tsx | 4 ++-- .../plugin-manager/src/lib/components/ActivePluginCard.tsx | 3 +++ .../plugin-manager/src/lib/components/InactivePluginCard.tsx | 3 +++ libs/remix-ui/settings/src/lib/remix-ui-settings.tsx | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) 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/libs/remix-ui/plugin-manager/src/lib/components/ActivePluginCard.tsx b/libs/remix-ui/plugin-manager/src/lib/components/ActivePluginCard.tsx index 6241150a2e..36ee6b743c 100644 --- a/libs/remix-ui/plugin-manager/src/lib/components/ActivePluginCard.tsx +++ b/libs/remix-ui/plugin-manager/src/lib/components/ActivePluginCard.tsx @@ -3,6 +3,8 @@ import React from 'react' import { FormattedMessage } from 'react-intl' import '../remix-ui-plugin-manager.css' import { CustomTooltip } from '@remix-ui/helper' +const _paq = (window._paq = window._paq || []) + interface PluginCardProps { profile: any buttonText: string @@ -85,6 +87,7 @@ function ActivePluginCard({ profile, buttonText, deactivatePlugin }: PluginCardP > : ( : (