Skip to content

Commit e86b90c

Browse files
authored
Merge pull request #6123 from ethereum/aichat-ui-update
AiChat UI/UX Update
2 parents 73e1dce + e5f9092 commit e86b90c

File tree

15 files changed

+450
-224
lines changed

15 files changed

+450
-224
lines changed

.env.local

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ WALLET_CONNECT_PROJECT_ID=<project_id>
66
NOIR_COMPILER_BASE_URL_DEV=<dev_base_endpoint>
77
NOIR_COMPILER_BASE_URL_PROD=<prod_base_endpoint>
88
NOIR_COMPILER_WS_URL_DEV=<dev_websocket_url>
9-
NOIR_COMPILER_WS_URL_PROD=<prod_websocket_url>
9+
NOIR_COMPILER_WS_URL_PROD=<prod_websocket_url>

apps/remix-ide-e2e/src/commands/assistantClearChat.ts

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,24 @@ import { NightwatchBrowser } from 'nightwatch'
22
import EventEmitter from 'events'
33

44
class AssistantClearChat extends EventEmitter {
5-
command(this: NightwatchBrowser): NightwatchBrowser {
6-
this.api.perform((done) => {
7-
clearChat(this.api, () => {
8-
done()
9-
this.emit('complete')
10-
})
11-
})
12-
return this
13-
}
5+
command(this: NightwatchBrowser): NightwatchBrowser {
6+
this.api.perform((done) => {
7+
clearChat(this.api, () => {
8+
done()
9+
this.emit('complete')
10+
})
11+
})
12+
return this
13+
}
1414
}
1515

1616
function clearChat(browser: NightwatchBrowser, done: VoidFunction) {
17-
browser
18-
.execute(function () {
19-
(window as any).remixAIChat.current.clearChat();
20-
}, [])
17+
browser
18+
.execute(function () {
19+
(window as any).remixAIChat.current.clearChat();
20+
}, [])
2121

22-
done()
22+
done()
2323
}
2424

2525
module.exports = AssistantClearChat;

apps/remix-ide-e2e/src/commands/assistantSetProvider.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function setAssistant(browser: NightwatchBrowser, provider: string, done: VoidFu
3030
selector: "//*[@data-id='remix-ai-streaming' and @data-streaming='false']",
3131
})
3232
//.pause()
33-
.perform(() => done())
33+
.perform(() => done())
3434
}
3535

3636
module.exports = SetAssistantProvider

apps/remix-ide-e2e/src/helpers/init.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ type LoadPlugin = {
88
url: string
99
}
1010

11-
1211
// eslint-disable-next-line @typescript-eslint/no-unused-vars
1312
export default function (browser: NightwatchBrowser, callback: VoidFunction, url?: string, preloadPlugins = true, loadPlugin?: LoadPlugin, hideToolTips: boolean = true): void {
1413
browser

apps/remix-ide-e2e/src/tests/ai_panel.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ module.exports = {
8181
locateStrategy: 'xpath',
8282
timeout: 120000
8383
})
84-
.waitForElementPresent('*[data-id="remix-ai-assistant-ready"]')
84+
// .waitForElementPresent('*[data-id="remix-ai-assistant-ready"]')
8585
.assistantAddContext('currentFile')
8686
.waitForElementVisible({
8787
locateStrategy: 'xpath',
@@ -171,8 +171,8 @@ module.exports = {
171171
locateStrategy: 'xpath',
172172
timeout: 120000
173173
})
174-
.waitForElementVisible('*[data-id="composer-ai-workspace-generate"]')
175-
.click('*[data-id="composer-ai-workspace-generate"]')
174+
.waitForElementVisible('*[data-id="remix-ai-workspace-generate"]')
175+
.click('*[data-id="remix-ai-workspace-generate"]')
176176
.waitForElementVisible('*[data-id="generate-workspaceModalDialogModalBody-react"]')
177177
.click('*[data-id="modalDialogCustomPromp"]')
178178
.setValue('*[data-id="modalDialogCustomPromp"]', 'a simple ERC20 contract')
@@ -268,4 +268,4 @@ module.exports = {
268268
.clickLaunchIcon('filePanel')
269269
.waitForElementNotVisible('*[data-id="remix-ai-assistant"]', 5000)
270270
},
271-
}
271+
}

apps/remix-ide/src/assets/css/themes/remix-dark_tvx1s2.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
--danger: #b84040;
2222
--light: #2a2c3f;
2323
--dark: #222336;
24+
--dim: #47485c;
2425
--text: #babbcc;
2526
--text-background: #222336;
2627
--text-bg-mark: #8388b2;

libs/remix-ui/remix-ai-assistant/src/components/chat.tsx

Lines changed: 30 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import remarkGfm from "remark-gfm"
33
import copy from "copy-to-clipboard"
44
import { ChatMessage, assistantAvatar } from "../lib/types"
55
import React from 'react'
6+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
7+
import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism'
68

79
const DEFAULT_SUGGESTIONS = [
810
'Explain what a modifier is',
@@ -19,6 +21,29 @@ export interface ChatHistoryComponentProps {
1921
historyRef: React.RefObject<HTMLDivElement>
2022
}
2123

24+
const AiChatIntro = (props) => {
25+
return (
26+
<div className="assistant-landing d-flex flex-column align-items-center justify-content-center text-center px-3 h-100">
27+
<img src={assistantAvatar} alt="RemixAI logo" style={{ width: '120px' }} className="mb-3" />
28+
<h5 className="mb-2">RemixAI</h5>
29+
<p className="mb-4" style={{ fontSize: '1.1rem' }}>
30+
RemixAI provides you personalized guidance as you build. It can break down concepts,
31+
answer questions about blockchain technology and assist you with your smart contracts.
32+
</p>
33+
{DEFAULT_SUGGESTIONS.map((s, index) => (
34+
<button
35+
key={s}
36+
data-id={`remix-ai-assistant-starter-${index}`}
37+
className="btn btn-secondary mb-2 w-100 text-left"
38+
onClick={() => props.sendPrompt(s)}
39+
>
40+
<i className="fa-kit fa-remixai mr-2"></i>{s}
41+
</button>
42+
))}
43+
</div>
44+
)
45+
}
46+
2247
export const ChatHistoryComponent: React.FC<ChatHistoryComponentProps> = ({
2348
messages,
2449
isStreaming,
@@ -29,34 +54,17 @@ export const ChatHistoryComponent: React.FC<ChatHistoryComponentProps> = ({
2954
return (
3055
<div
3156
ref={historyRef}
32-
className="d-flex flex-column flex-grow-1 overflow-y-auto"
57+
className="d-flex flex-column overflow-y-auto border-box-sizing preserve-wrap w-100"
3358
>
3459
{messages.length === 0 ? (
35-
<div className="assistant-landing d-flex flex-column align-items-center justify-content-center text-center px-3 h-100">
36-
<img src={assistantAvatar} alt="RemixAI logo" style={{ width: '120px' }} className="mb-3" />
37-
<h5 className="mb-2">RemixAI</h5>
38-
<p className="mb-4" style={{ fontSize: '1.1rem' }}>
39-
RemixAI provides you personalized guidance as you build. It can break down concepts,
40-
answer questions about blockchain technology and assist you with your smart contracts.
41-
</p>
42-
{DEFAULT_SUGGESTIONS.map((s, index) => (
43-
<button
44-
key={s}
45-
data-id={`remix-ai-assistant-starter-${index}`}
46-
className="btn btn-secondary mb-2 w-100 text-left"
47-
onClick={() => sendPrompt(s)}
48-
>
49-
<i className="fa-kit fa-remixai mr-2"></i>{s}
50-
</button>
51-
))}
52-
</div>
60+
<AiChatIntro sendPrompt={sendPrompt} />
5361
) : (
5462
messages.map(msg => {
5563
const bubbleClass =
5664
msg.role === 'user' ? 'bubble-user bg-light' : 'bubble-assistant bg-light'
5765

5866
return (
59-
<div key={msg.id} className="chat-row d-flex mb-2">
67+
<div key={msg.id} className="chat-row d-flex mb-2 w-100">
6068
{/* Avatar for assistant */}
6169
{msg.role === 'assistant' && (
6270
<img
@@ -67,7 +75,7 @@ export const ChatHistoryComponent: React.FC<ChatHistoryComponentProps> = ({
6775
)}
6876

6977
{/* Bubble */}
70-
<div data-id="ai-response-chat-bubble-section" className="flex-grow-1 w-25 mr-1">
78+
<div data-id="ai-response-chat-bubble-section" className="overflow-y-scroll w-100 mr-1">
7179
<div className={`chat-bubble p-2 rounded ${bubbleClass}`}>
7280
{msg.role === 'user' && (
7381
<small className="text-uppercase fw-bold text-secondary d-block mb-1">
@@ -154,7 +162,7 @@ export const ChatHistoryComponent: React.FC<ChatHistoryComponentProps> = ({
154162
</div>
155163
</div>
156164
)
157-
})
165+
}) //end of messages render
158166
)}
159167
{isStreaming && (
160168
<div className="text-center my-2">
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import React, { Dispatch } from 'react'
2+
import { AiAssistantType, AiContextType, groupListType } from '../types/componentTypes'
3+
4+
export interface GroupListMenuProps {
5+
setChoice: Dispatch<React.SetStateAction<AiContextType | AiAssistantType | any>>
6+
choice: AiContextType | AiAssistantType | any
7+
setShowOptions: Dispatch<React.SetStateAction<boolean>>
8+
groupList: groupListType[]
9+
}
10+
11+
export default function GroupListMenu(props: GroupListMenuProps) {
12+
13+
return (
14+
<div className="btn-group-vertical">
15+
{props.groupList.map((item, index) => (
16+
<button
17+
key={`${item.label}-${index}`}
18+
className="btn btn-light"
19+
data-id={item.dataId}
20+
onClick={() => {
21+
props.setChoice(item.stateValue)
22+
props.setShowOptions(false)
23+
}}
24+
>
25+
<div className="d-flex flex-column small text-left">
26+
<span className="font-semibold text-white mb-1">{item.label}</span>
27+
<div className="d-flex justify-content-between">
28+
<span className="text-light mr-2 text-wrap">{item.bodyText}</span>{ props.choice === item.stateValue && <span className={item.icon}></span> }
29+
</div>
30+
</div>
31+
</button>
32+
))}
33+
</div>
34+
)
35+
}

0 commit comments

Comments
 (0)