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.',