Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ celerybeat-schedule
.spyderproject
.spyproject

# vscode project settings
.vscode

# Rope project settings
.ropeproject

Expand Down
6 changes: 3 additions & 3 deletions packages/jupyter-chat/src/components/attachments.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

import CloseIcon from '@mui/icons-material/Close';
import { Box } from '@mui/material';
import React, { useContext } from 'react';
import React from 'react';
import { PathExt } from '@jupyterlab/coreutils';
import { UUID } from '@lumino/coreutils';

import { TooltippedButton } from './mui-extras/tooltipped-button';
import { useChatContext } from '../context';
import { IAttachment } from '../types';
import { AttachmentOpenerContext } from '../context';

const ATTACHMENTS_CLASS = 'jp-chat-attachments';
const ATTACHMENT_CLASS = 'jp-chat-attachment';
Expand Down Expand Up @@ -81,7 +81,7 @@ export type AttachmentProps = AttachmentsProps & {
*/
export function AttachmentPreview(props: AttachmentProps): JSX.Element {
const remove_tooltip = 'Remove attachment';
const attachmentOpenerRegistry = useContext(AttachmentOpenerContext);
const { attachmentOpenerRegistry } = useChatContext();

return (
<Box className={ATTACHMENT_CLASS}>
Expand Down
34 changes: 13 additions & 21 deletions packages/jupyter-chat/src/components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,31 +18,29 @@ import {
} from './input';
import { JlThemeProvider } from './jl-theme-provider';
import { ChatMessages } from './messages';
import { AttachmentOpenerContext } from '../context';
import { ChatReactContext } from '../context';
import { IChatModel } from '../model';
import {
IAttachmentOpenerRegistry,
IChatCommandRegistry,
IMessageFooterRegistry
} from '../registers';

export function ChatBody(props: Chat.IChatBodyProps): JSX.Element {
export function ChatBody(props: Chat.IChatProps): JSX.Element {
const { model } = props;
let { inputToolbarRegistry } = props;
if (!inputToolbarRegistry) {
inputToolbarRegistry = InputToolbarRegistry.defaultToolbarRegistry();
}

const contextValue: Chat.IChatProps = {
...props,
inputToolbarRegistry
};

return (
<AttachmentOpenerContext.Provider value={props.attachmentOpenerRegistry}>
<ChatMessages
rmRegistry={props.rmRegistry}
model={model}
chatCommandRegistry={props.chatCommandRegistry}
inputToolbarRegistry={inputToolbarRegistry}
messageFooterRegistry={props.messageFooterRegistry}
welcomeMessage={props.welcomeMessage}
/>
<ChatReactContext.Provider value={contextValue}>
<ChatMessages />
<ChatInput
sx={{
paddingLeft: 4,
Expand All @@ -52,15 +50,13 @@ export function ChatBody(props: Chat.IChatBodyProps): JSX.Element {
borderTop: '1px solid var(--jp-border-color1)'
}}
model={model.input}
chatCommandRegistry={props.chatCommandRegistry}
toolbarRegistry={inputToolbarRegistry}
/>
</AttachmentOpenerContext.Provider>
</ChatReactContext.Provider>
);
}

export function Chat(props: Chat.IOptions): JSX.Element {
const [view, setView] = useState<Chat.View>(props.chatView || Chat.View.chat);
const [view, setView] = useState<Chat.View>(Chat.View.chat);
return (
<JlThemeProvider themeManager={props.themeManager ?? null}>
<Box
Expand Down Expand Up @@ -112,7 +108,7 @@ export namespace Chat {
/**
* The props for the chat body component.
*/
export interface IChatBodyProps {
export interface IChatProps {
/**
* The chat model.
*/
Expand Down Expand Up @@ -146,15 +142,11 @@ export namespace Chat {
/**
* The options to build the Chat UI.
*/
export interface IOptions extends IChatBodyProps {
export interface IOptions extends IChatProps {
/**
* The theme manager.
*/
themeManager?: IThemeManager | null;
/**
* The view to render.
*/
chatView?: View;
/**
* A settings panel that can be used for dedicated settings (e.g. jupyter-ai)
*/
Expand Down
35 changes: 13 additions & 22 deletions packages/jupyter-chat/src/components/input/chat-input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,11 @@ import {
import clsx from 'clsx';
import React, { useEffect, useRef, useState } from 'react';

import { InputToolbarRegistry } from './toolbar-registry';
import { useChatCommands } from './use-chat-commands';
import { AttachmentPreviewList } from '../attachments';
import {
IInputToolbarRegistry,
InputToolbarRegistry,
useChatCommands
} from '.';
import { useChatContext } from '../../context';
import { IInputModel, InputModel } from '../../input-model';
import { IChatCommandRegistry } from '../../registers';
import { IAttachment } from '../../types';

const INPUT_BOX_CLASS = 'jp-chat-input-container';
Expand All @@ -31,11 +28,13 @@ const INPUT_COMPONENT_CLASS = 'jp-chat-input-component';
const INPUT_TOOLBAR_CLASS = 'jp-chat-input-toolbar';

export function ChatInput(props: ChatInput.IProps): JSX.Element {
const { model, toolbarRegistry } = props;
const { model } = props;
const { chatCommandRegistry, inputToolbarRegistry } = useChatContext();

const [input, setInput] = useState<string>(model.value);
const inputRef = useRef<HTMLInputElement>();

const chatCommands = useChatCommands(model, props.chatCommandRegistry);
const chatCommands = useChatCommands(model, chatCommandRegistry);

const [sendWithShiftEnter, setSendWithShiftEnter] = useState<boolean>(
model.config.sendWithShiftEnter ?? false
Expand Down Expand Up @@ -88,16 +87,16 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
*/
useEffect(() => {
const updateToolbar = () => {
setToolbarElements(toolbarRegistry.getItems());
setToolbarElements(inputToolbarRegistry?.getItems() || []);
};

toolbarRegistry.itemsChanged.connect(updateToolbar);
inputToolbarRegistry?.itemsChanged.connect(updateToolbar);
updateToolbar();

return () => {
toolbarRegistry.itemsChanged.disconnect(updateToolbar);
inputToolbarRegistry?.itemsChanged.disconnect(updateToolbar);
};
}, [toolbarRegistry]);
}, [inputToolbarRegistry]);

const inputExists = !!input.trim();

Expand Down Expand Up @@ -160,7 +159,7 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
(!sendWithShiftEnter && !event.shiftKey)
) {
// Run all command providers
await props.chatCommandRegistry?.onSubmit(model);
await chatCommandRegistry?.onSubmit(model);
model.send(model.value);
event.stopPropagation();
event.preventDefault();
Expand Down Expand Up @@ -245,7 +244,7 @@ export function ChatInput(props: ChatInput.IProps): JSX.Element {
{toolbarElements.map(item => (
<item.element
model={model}
chatCommandRegistry={props.chatCommandRegistry}
chatCommandRegistry={chatCommandRegistry}
/>
))}
</Toolbar>
Expand All @@ -265,10 +264,6 @@ export namespace ChatInput {
* The input model.
*/
model: IInputModel;
/**
* The toolbar registry.
*/
toolbarRegistry: IInputToolbarRegistry;
/**
* The function to be called to cancel editing.
*/
Expand All @@ -277,9 +272,5 @@ export namespace ChatInput {
* Custom mui/material styles.
*/
sx?: SxProps<Theme>;
/**
* Chat command registry.
*/
chatCommandRegistry?: IChatCommandRegistry;
}
}
22 changes: 12 additions & 10 deletions packages/jupyter-chat/src/components/messages/footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,17 @@
import { Box } from '@mui/material';
import React from 'react';

import {
IMessageFooterRegistry,
MessageFooterSectionProps
} from '../../registers';
import { useChatContext } from '../../context';
import { IChatMessage } from '../../types';

/**
* The chat footer component properties.
*/
export interface IMessageFootersProps extends MessageFooterSectionProps {
export interface IMessageFootersProps {
/**
* The chat footer registry.
* The chat model.
*/
registry: IMessageFooterRegistry;
message: IChatMessage;
}

/**
Expand All @@ -27,9 +25,13 @@ export interface IMessageFootersProps extends MessageFooterSectionProps {
*/
export function MessageFooterComponent(
props: IMessageFootersProps
): JSX.Element {
const { message, model, registry } = props;
const footer = registry.getFooter();
): JSX.Element | null {
const { message } = props;
const { model, messageFooterRegistry } = useChatContext();
if (!messageFooterRegistry) {
return null;
}
const footer = messageFooterRegistry.getFooter();

return (
<Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
Expand Down
18 changes: 5 additions & 13 deletions packages/jupyter-chat/src/components/messages/message-renderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
* Distributed under the terms of the Modified BSD License.
*/

import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
import { PromiseDelegate } from '@lumino/coreutils';
import React, { useState, useEffect } from 'react';
import { createPortal } from 'react-dom';

import { CodeToolbar, CodeToolbarProps } from '../code-blocks/code-toolbar';
import { MessageToolbar } from './toolbar';
import { CodeToolbar, CodeToolbarProps } from '../code-blocks/code-toolbar';
import { useChatContext } from '../../context';
import { MarkdownRenderer, MD_RENDERED_CLASS } from '../../markdown-renderer';
import { IChatModel } from '../../model';

/**
* The type of the props for the MessageRenderer component.
Expand All @@ -21,14 +20,6 @@ type MessageRendererProps = {
* The string to render.
*/
markdownStr: string;
/**
* The rendermime registry.
*/
rmRegistry: IRenderMimeRegistry;
/**
* The model of the chat.
*/
model: IChatModel;
/**
* The promise to resolve when the message is rendered.
*/
Expand All @@ -51,7 +42,8 @@ type MessageRendererProps = {
* The message renderer base component.
*/
function MessageRendererBase(props: MessageRendererProps): JSX.Element {
const { markdownStr, rmRegistry } = props;
const { markdownStr } = props;
const { model, rmRegistry } = useChatContext();
const appendContent = props.appendContent || false;
const [renderedContent, setRenderedContent] = useState<HTMLElement | null>(
null
Expand Down Expand Up @@ -81,7 +73,7 @@ function MessageRendererBase(props: MessageRendererProps): JSX.Element {
);
newCodeToolbarDefns.push([
codeToolbarRoot,
{ model: props.model, content: preBlock.textContent || '' }
{ model: model, content: preBlock.textContent || '' }
]);
});

Expand Down
11 changes: 4 additions & 7 deletions packages/jupyter-chat/src/components/messages/message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ import { PromiseDelegate } from '@lumino/coreutils';
import React, { forwardRef, useEffect, useState } from 'react';

import { MessageRenderer } from './message-renderer';
import { BaseMessageProps } from './messages';
import { AttachmentPreviewList } from '../attachments';
import { ChatInput } from '../input';
import { useChatContext } from '../../context';
import { IInputModel, InputModel } from '../../input-model';
import { IChatMessage } from '../../types';
import { replaceSpanToMention } from '../../utils';

/**
* The message component props.
*/
type ChatMessageProps = BaseMessageProps & {
type ChatMessageProps = {
/**
* The message to display.
*/
Expand All @@ -37,7 +37,8 @@ type ChatMessageProps = BaseMessageProps & {
*/
export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
(props, ref): JSX.Element => {
const { message, model, rmRegistry } = props;
const { message } = props;
const { model } = useChatContext();
const [edit, setEdit] = useState<boolean>(false);
const [deleted, setDeleted] = useState<boolean>(false);
const [canEdit, setCanEdit] = useState<boolean>(false);
Expand Down Expand Up @@ -132,14 +133,10 @@ export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
<ChatInput
onCancel={() => cancelEdition()}
model={model.getEditionModel(message.id)!}
chatCommandRegistry={props.chatCommandRegistry}
toolbarRegistry={props.inputToolbarRegistry}
/>
) : (
<MessageRenderer
rmRegistry={rmRegistry}
markdownStr={message.body}
model={model}
edit={canEdit ? startEdition : undefined}
delete={canDelete ? () => deleteMessage(message.id) : undefined}
rendered={props.renderedPromise}
Expand Down
Loading
Loading