From a8ac61d1fa0296c4fa2fc2217c8e43d91426ac8c Mon Sep 17 00:00:00 2001 From: Nakul Date: Wed, 23 Jul 2025 17:08:45 +0530 Subject: [PATCH 1/2] Adding New chat button --- src/components/chat-header.tsx | 45 ++++++++++++++++++++ src/components/new-chat-button.tsx | 68 ++++++++++++++++++++++++++++++ src/index.ts | 56 ++++++++++++++++++++---- 3 files changed, 160 insertions(+), 9 deletions(-) create mode 100644 src/components/chat-header.tsx create mode 100644 src/components/new-chat-button.tsx diff --git a/src/components/chat-header.tsx b/src/components/chat-header.tsx new file mode 100644 index 0000000..7492c1c --- /dev/null +++ b/src/components/chat-header.tsx @@ -0,0 +1,45 @@ +import React, { useEffect, useRef } from 'react'; +import { ReactWidget } from '@jupyterlab/apputils'; +import { buildChatSidebar, IChatModel } from '@jupyter/chat'; +import { NewChatButton } from './new-chat-button'; +import { jupyternautLiteIcon } from '../icons'; + +export function buildSidebarWithHeader( + options: Parameters[0], + newChat: () => void, + model: IChatModel +): ReactWidget { + const sidebar = buildChatSidebar(options); + + const ChatSidebarWithHeader = () => { + const containerRef = useRef(null); + + useEffect(() => { + if (containerRef.current) { + containerRef.current.innerHTML = ''; + containerRef.current.appendChild(sidebar.node); + sidebar.node.style.flex = '1'; + sidebar.node.style.height = '100%'; + sidebar.update(); + } + }, []); + + return ( +
+
+ +
+
+
+ ); + }; + + const widget = ReactWidget.create(); + widget.title.icon = jupyternautLiteIcon; + return widget; +} diff --git a/src/components/new-chat-button.tsx b/src/components/new-chat-button.tsx new file mode 100644 index 0000000..e09a9ba --- /dev/null +++ b/src/components/new-chat-button.tsx @@ -0,0 +1,68 @@ +import AddIcon from '@mui/icons-material/Add'; +import React from 'react'; + +import { InputToolbarRegistry, TooltippedButton } from '@jupyter/chat'; + +/** + * Props for the New Chat button. + */ +export interface INewChatButtonProps + extends InputToolbarRegistry.IToolbarItemProps { + newChat: () => void; +} + +/** + * The new chat button component. + */ +export function NewChatButton(props: INewChatButtonProps): JSX.Element { + const tooltip = 'Start a new chat'; + return ( + + + + Chat + + + ); +} + +/** + * Factory to create the toolbar item for new chat. + */ +export function newChatItem( + newChat: () => void +): InputToolbarRegistry.IToolbarItem { + return { + element: (props: InputToolbarRegistry.IToolbarItemProps) => { + const newProps: INewChatButtonProps = { ...props, newChat }; + return NewChatButton(newProps); + }, + position: 2000, + hidden: false + }; +} diff --git a/src/index.ts b/src/index.ts index 06e870d..afd19bd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,7 +12,11 @@ import { JupyterFrontEndPlugin, ILayoutRestorer } from '@jupyterlab/application'; -import { ReactWidget, IThemeManager } from '@jupyterlab/apputils'; +import { + ReactWidget, + IThemeManager, + MainAreaWidget +} from '@jupyterlab/apputils'; import { ICompletionProviderManager } from '@jupyterlab/completer'; import { INotebookTracker } from '@jupyterlab/notebook'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; @@ -28,6 +32,12 @@ import { AIProviderRegistry } from './provider'; import { aiSettingsRenderer, textArea } from './settings'; import { IAIProviderRegistry, PLUGIN_IDS } from './tokens'; import { stopItem } from './components/stop-button'; +import { buildSidebarWithHeader } from './components/chat-header'; + +namespace Private { + // eslint-disable-next-line prefer-const + export let id = 0; +} const chatCommandRegistryPlugin: JupyterFrontEndPlugin = { id: PLUGIN_IDS.chatCommandRegistry, @@ -127,15 +137,43 @@ const chatPlugin: JupyterFrontEndPlugin = { } }); + let chatCount = 0; + try { - chatWidget = buildChatSidebar({ - model: chatHandler, - themeManager, - rmRegistry, - chatCommandRegistry, - inputToolbarRegistry, - welcomeMessage: welcomeMessage(providerRegistry.providers) - }); + chatWidget = buildSidebarWithHeader( + { + model: chatHandler, + themeManager, + rmRegistry, + chatCommandRegistry, + inputToolbarRegistry, + welcomeMessage: welcomeMessage(providerRegistry.providers) + }, + () => { + const handler = new ChatHandler({ providerRegistry }); + const content = buildChatSidebar({ + model: handler, + themeManager, + rmRegistry, + chatCommandRegistry, + inputToolbarRegistry, + welcomeMessage: welcomeMessage(providerRegistry.providers) + }); + + const label = chatCount === 0 ? 'New Chat' : `New Chat-${chatCount}`; + chatCount++; + + content.title.label = label; + content.title.closable = true; + + const widget = new MainAreaWidget({ content }); + widget.id = `chat-panel-${Private.id++}`; + + app.shell.add(widget, 'main'); + app.shell.activateById(widget.id); + }, + chatHandler + ); } catch (e) { chatWidget = buildErrorWidget(themeManager); } From 8b7fb9c50b29b72947e35fd003a0bb61fe81f19e Mon Sep 17 00:00:00 2001 From: Nakul Date: Tue, 23 Sep 2025 15:14:59 +0530 Subject: [PATCH 2/2] .. --- src/components/chat-header.tsx | 45 -------------------- src/components/new-chat-button.tsx | 68 ------------------------------ src/index.ts | 59 +++++--------------------- 3 files changed, 10 insertions(+), 162 deletions(-) delete mode 100644 src/components/chat-header.tsx delete mode 100644 src/components/new-chat-button.tsx diff --git a/src/components/chat-header.tsx b/src/components/chat-header.tsx deleted file mode 100644 index 7492c1c..0000000 --- a/src/components/chat-header.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import React, { useEffect, useRef } from 'react'; -import { ReactWidget } from '@jupyterlab/apputils'; -import { buildChatSidebar, IChatModel } from '@jupyter/chat'; -import { NewChatButton } from './new-chat-button'; -import { jupyternautLiteIcon } from '../icons'; - -export function buildSidebarWithHeader( - options: Parameters[0], - newChat: () => void, - model: IChatModel -): ReactWidget { - const sidebar = buildChatSidebar(options); - - const ChatSidebarWithHeader = () => { - const containerRef = useRef(null); - - useEffect(() => { - if (containerRef.current) { - containerRef.current.innerHTML = ''; - containerRef.current.appendChild(sidebar.node); - sidebar.node.style.flex = '1'; - sidebar.node.style.height = '100%'; - sidebar.update(); - } - }, []); - - return ( -
-
- -
-
-
- ); - }; - - const widget = ReactWidget.create(); - widget.title.icon = jupyternautLiteIcon; - return widget; -} diff --git a/src/components/new-chat-button.tsx b/src/components/new-chat-button.tsx deleted file mode 100644 index e09a9ba..0000000 --- a/src/components/new-chat-button.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import AddIcon from '@mui/icons-material/Add'; -import React from 'react'; - -import { InputToolbarRegistry, TooltippedButton } from '@jupyter/chat'; - -/** - * Props for the New Chat button. - */ -export interface INewChatButtonProps - extends InputToolbarRegistry.IToolbarItemProps { - newChat: () => void; -} - -/** - * The new chat button component. - */ -export function NewChatButton(props: INewChatButtonProps): JSX.Element { - const tooltip = 'Start a new chat'; - return ( - - - - Chat - - - ); -} - -/** - * Factory to create the toolbar item for new chat. - */ -export function newChatItem( - newChat: () => void -): InputToolbarRegistry.IToolbarItem { - return { - element: (props: InputToolbarRegistry.IToolbarItemProps) => { - const newProps: INewChatButtonProps = { ...props, newChat }; - return NewChatButton(newProps); - }, - position: 2000, - hidden: false - }; -} diff --git a/src/index.ts b/src/index.ts index afd19bd..adb8bda 100644 --- a/src/index.ts +++ b/src/index.ts @@ -12,11 +12,7 @@ import { JupyterFrontEndPlugin, ILayoutRestorer } from '@jupyterlab/application'; -import { - ReactWidget, - IThemeManager, - MainAreaWidget -} from '@jupyterlab/apputils'; +import { ReactWidget, IThemeManager } from '@jupyterlab/apputils'; import { ICompletionProviderManager } from '@jupyterlab/completer'; import { INotebookTracker } from '@jupyterlab/notebook'; import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; @@ -32,12 +28,6 @@ import { AIProviderRegistry } from './provider'; import { aiSettingsRenderer, textArea } from './settings'; import { IAIProviderRegistry, PLUGIN_IDS } from './tokens'; import { stopItem } from './components/stop-button'; -import { buildSidebarWithHeader } from './components/chat-header'; - -namespace Private { - // eslint-disable-next-line prefer-const - export let id = 0; -} const chatCommandRegistryPlugin: JupyterFrontEndPlugin = { id: PLUGIN_IDS.chatCommandRegistry, @@ -113,7 +103,7 @@ const chatPlugin: JupyterFrontEndPlugin = { }) .catch(reason => { console.error( - `Something went wrong when reading the settings.\n${reason}` + `Something went wrong when reading the settings.\n${reason} ` ); }); @@ -136,44 +126,15 @@ const chatPlugin: JupyterFrontEndPlugin = { inputToolbarRegistry.show('send'); } }); - - let chatCount = 0; - try { - chatWidget = buildSidebarWithHeader( - { - model: chatHandler, - themeManager, - rmRegistry, - chatCommandRegistry, - inputToolbarRegistry, - welcomeMessage: welcomeMessage(providerRegistry.providers) - }, - () => { - const handler = new ChatHandler({ providerRegistry }); - const content = buildChatSidebar({ - model: handler, - themeManager, - rmRegistry, - chatCommandRegistry, - inputToolbarRegistry, - welcomeMessage: welcomeMessage(providerRegistry.providers) - }); - - const label = chatCount === 0 ? 'New Chat' : `New Chat-${chatCount}`; - chatCount++; - - content.title.label = label; - content.title.closable = true; - - const widget = new MainAreaWidget({ content }); - widget.id = `chat-panel-${Private.id++}`; - - app.shell.add(widget, 'main'); - app.shell.activateById(widget.id); - }, - chatHandler - ); + chatWidget = buildChatSidebar({ + model: chatHandler, + themeManager, + rmRegistry, + chatCommandRegistry, + inputToolbarRegistry, + welcomeMessage: welcomeMessage(providerRegistry.providers) + }); } catch (e) { chatWidget = buildErrorWidget(themeManager); }