From 86b16e7d79aa02e2403b103767298419ffa4de79 Mon Sep 17 00:00:00 2001 From: Lim Jet <57783762+daoauth@users.noreply.github.com> Date: Fri, 13 Dec 2024 14:33:43 +0900 Subject: [PATCH] fix history --- src/utilities/aptosAssistant.ts | 10 ++- src/webview/panel/src/App.css | 19 ++++-- src/webview/panel/src/App.tsx | 67 ++++++++++++------- src/webview/panel/src/components/Bot.tsx | 3 - src/webview/panel/src/components/Skeleton.tsx | 21 ++++++ src/webview/panel/src/utilities/commends.ts | 5 ++ src/webview/panelProvider.ts | 6 +- 7 files changed, 90 insertions(+), 41 deletions(-) create mode 100644 src/webview/panel/src/components/Skeleton.tsx diff --git a/src/utilities/aptosAssistant.ts b/src/utilities/aptosAssistant.ts index be490e5..4a4f926 100644 --- a/src/utilities/aptosAssistant.ts +++ b/src/utilities/aptosAssistant.ts @@ -1,4 +1,5 @@ import * as vscode from 'vscode'; +import { RequestData } from '../webview/panel/src/utilities/commends'; const getContent = (str: string) => { const { choices } = JSON.parse(str); @@ -7,14 +8,14 @@ const getContent = (str: string) => { let isLoading: boolean = false; const history: { - user: string; + user: RequestData; bot: string; }[] = []; export const getHistory = () => history; export const aptosAssistant = async ( - request: string, + request: RequestData, onData: (data: string) => void, onEnd: () => void, ): Promise => { @@ -38,7 +39,10 @@ export const aptosAssistant = async ( top: 3, suggest_followup_questions: false, }, - history, + history: history.map((item) => ({ + user: item.user.content, + bot: item.bot, + })), }), }, ); diff --git a/src/webview/panel/src/App.css b/src/webview/panel/src/App.css index c8b9268..2127df7 100644 --- a/src/webview/panel/src/App.css +++ b/src/webview/panel/src/App.css @@ -1,12 +1,17 @@ -#loading-spinner { - animation: loading-spinner 1s linear infinite; +.skeleton { + background-color: var(--vscode-editorWidget-background); + border-radius: 4px; + animation: pulse 1.5s infinite; } -@keyframes loading-spinner { - from { - transform: rotate(0deg); +@keyframes pulse { + 0% { + opacity: 1; } - to { - transform: rotate(360deg); + 50% { + opacity: 0.5; + } + 100% { + opacity: 1; } } diff --git a/src/webview/panel/src/App.tsx b/src/webview/panel/src/App.tsx index 77282f5..5ef35e5 100644 --- a/src/webview/panel/src/App.tsx +++ b/src/webview/panel/src/App.tsx @@ -3,22 +3,24 @@ import { VSCodeTextField } from '@vscode/webview-ui-toolkit/react'; import './App.css'; -import { COMMENDS } from './utilities/commends'; +import { COMMENDS, RequestData } from './utilities/commends'; import { vscode } from './utilities/vscode'; import { User } from './components/User'; import { Bot } from './components/Bot'; +import { Skeleton } from './components/Skeleton'; function App() { const initialized = useRef(false); const [isLoading, setIsLoading] = useState(false); const [input, setInput] = useState(''); - const [htmlHistory, setHtmlHistory] = useState< - { isBot: boolean; content: string }[] - >([]); - const messagesEndRef = useRef(null); + const [htmlHistory, setHtmlHistory] = useState<(string | RequestData)[]>([]); + const scrollContainerRef = useRef(null); useEffect(() => { - messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }); + if (scrollContainerRef.current) { + scrollContainerRef.current.scrollTop = + scrollContainerRef.current.scrollHeight; + } }, [htmlHistory]); useEffect(() => { @@ -30,23 +32,26 @@ function App() { setIsLoading(() => true); setHtmlHistory((old) => [ ...old, - { isBot: false, content: message.data }, - { isBot: true, content: '' }, + { code: true, content: message.data }, + '', ]); break; case COMMENDS.AiHistory: - const temp: { isBot: boolean; content: string }[] = []; - message.data.forEach((item: { user: string; bot: string }) => { - temp.push({ isBot: false, content: item.user }); - item.bot && temp.push({ isBot: true, content: item.bot }); + const temp: (string | RequestData)[] = []; + message.data.forEach((item: { user: RequestData; bot: string }) => { + temp.push(item.user, item.bot); }); setHtmlHistory(() => temp); + if (scrollContainerRef.current) { + setTimeout(() => { + scrollContainerRef.current!.scrollTop = + scrollContainerRef.current!.scrollHeight; + }, 5); + } + initialized.current = true; break; case COMMENDS.AiStream: - setHtmlHistory((old) => [ - ...old.slice(0, -1), - { isBot: true, content: message.data }, - ]); + setHtmlHistory((old) => [...old.slice(0, -1), message.data]); break; case COMMENDS.AiStreamEnd: setIsLoading(() => false); @@ -57,19 +62,25 @@ function App() { }; if (!initialized.current) { - initialized.current = true; vscode.postMessage({ command: COMMENDS.Env }); } window.addEventListener('message', handleMessage); + + return () => { + window.removeEventListener('message', handleMessage); + }; }, []); return (
{htmlHistory.length === 0 ? ( @@ -85,18 +96,24 @@ function App() { height: '100%', }} > - No messages yet. Start a conversation! + 👋 Hello, Aptos! Start a conversation. 💬
) : ( htmlHistory.map((item, key) => - item.isBot ? ( - + typeof item === 'string' ? ( + isLoading && key === htmlHistory.length - 1 && !item ? ( + + ) : ( + + ) ) : ( - + ), ) )} -
{ @@ -127,8 +144,8 @@ function App() { setIsLoading(() => true); setHtmlHistory((old) => [ ...old, - { isBot: false, content: value }, - { isBot: true, content: '' }, + { code: false, content: value }, + '', ]); } }} diff --git a/src/webview/panel/src/components/Bot.tsx b/src/webview/panel/src/components/Bot.tsx index 86a837c..a218be5 100644 --- a/src/webview/panel/src/components/Bot.tsx +++ b/src/webview/panel/src/components/Bot.tsx @@ -5,7 +5,6 @@ import 'highlight.js/styles/github-dark.css'; export const Bot = ({ data }: { data: string }) => { const [html, setHtml] = useState(''); - useEffect(() => { const renderer = { code: ({ text, lang }: { text: string; lang?: string }) => { @@ -18,13 +17,11 @@ export const Bot = ({ data }: { data: string }) => { const renderedHtml = marked.parse(data, { async: false, gfm: true }); setHtml(() => renderedHtml); }, [data]); - return (
diff --git a/src/webview/panel/src/components/Skeleton.tsx b/src/webview/panel/src/components/Skeleton.tsx new file mode 100644 index 0000000..56dacef --- /dev/null +++ b/src/webview/panel/src/components/Skeleton.tsx @@ -0,0 +1,21 @@ +import React from 'react'; + +export const Skeleton = () => { + const lineCount = Math.floor(Math.random() * (2 - 1 + 1)) + 1; + return ( +
+ {Array.from({ length: lineCount }).map((_, index) => ( +
+ ))} +
+ ); +}; diff --git a/src/webview/panel/src/utilities/commends.ts b/src/webview/panel/src/utilities/commends.ts index 55fb0b5..b3cc805 100644 --- a/src/webview/panel/src/utilities/commends.ts +++ b/src/webview/panel/src/utilities/commends.ts @@ -9,3 +9,8 @@ export enum COMMENDS { OutputInfo = 'output:info', OutputError = 'output:error', } + +export interface RequestData { + code: boolean; + content: string; +} diff --git a/src/webview/panelProvider.ts b/src/webview/panelProvider.ts index 0f2add9..c400f3b 100644 --- a/src/webview/panelProvider.ts +++ b/src/webview/panelProvider.ts @@ -50,7 +50,7 @@ class PanelProvider implements vscode.WebviewViewProvider { break; case COMMENDS.AiQuestion: aptosAssistant( - data, + { code: false, content: data }, (stream) => { this._view?.webview.postMessage({ command: COMMENDS.AiStream, @@ -92,10 +92,10 @@ class PanelProvider implements vscode.WebviewViewProvider { case 'aptos-extension.assistant.folder': this._view?.webview.postMessage({ command: message.command, - data: 'Code Analysis...', + data: { code: true, content: '' }, }); aptosAssistant( - message.data, + { code: true, content: message.data }, (stream) => { this._view?.webview.postMessage({ command: COMMENDS.AiStream,