@jupyter/chat 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,6 +3,7 @@ import { PromiseDelegate } from '@lumino/coreutils';
3
3
  import React from 'react';
4
4
  import { IInputToolbarRegistry } from './input';
5
5
  import { IChatCommandRegistry } from '../chat-commands';
6
+ import { IMessageFooterRegistry } from '../footers';
6
7
  import { IChatModel } from '../model';
7
8
  import { IChatMessage, IUser } from '../types';
8
9
  /**
@@ -25,6 +26,10 @@ type BaseMessageProps = {
25
26
  * The input toolbar registry.
26
27
  */
27
28
  inputToolbarRegistry: IInputToolbarRegistry;
29
+ /**
30
+ * The footer registry.
31
+ */
32
+ messageFooterRegistry?: IMessageFooterRegistry;
28
33
  };
29
34
  /**
30
35
  * The messages list component.
@@ -11,6 +11,7 @@ import React, { useEffect, useState, useRef, forwardRef } from 'react';
11
11
  import { AttachmentPreviewList } from './attachments';
12
12
  import { ChatInput } from './chat-input';
13
13
  import { MarkdownRenderer } from './markdown-renderer';
14
+ import { MessageFooter } from './messages/footer';
14
15
  import { ScrollContainer } from './scroll-container';
15
16
  import { InputModel } from '../input-model';
16
17
  import { replaceSpanToMention } from '../utils';
@@ -138,7 +139,8 @@ export function ChatMessages(props) {
138
139
  // extra div needed to ensure each bubble is on a new line
139
140
  React.createElement(Box, { key: i, className: clsx(MESSAGE_CLASS, message.stacked ? MESSAGE_STACKED_CLASS : '') },
140
141
  React.createElement(ChatMessageHeader, { message: message }),
141
- React.createElement(ChatMessage, { ...props, message: message, index: i, renderedPromise: renderedPromise.current[i], ref: el => (listRef.current[i] = el) })));
142
+ React.createElement(ChatMessage, { ...props, message: message, index: i, renderedPromise: renderedPromise.current[i], ref: el => (listRef.current[i] = el) }),
143
+ props.messageFooterRegistry && (React.createElement(MessageFooter, { registry: props.messageFooterRegistry, message: message, model: model }))));
142
144
  })),
143
145
  React.createElement(Writers, { writers: currentWriters })),
144
146
  React.createElement(Navigation, { ...props, refMsgBox: refMsgBox, allRendered: allRendered })));
@@ -237,6 +239,10 @@ export const ChatMessage = forwardRef((props, ref) => {
237
239
  if (model.user.username === message.sender.username) {
238
240
  setCanEdit(model.updateMessage !== undefined);
239
241
  setCanDelete(model.deleteMessage !== undefined);
242
+ return;
243
+ }
244
+ if (message.sender.bot) {
245
+ setCanDelete(model.deleteMessage !== undefined);
240
246
  }
241
247
  }
242
248
  else {
@@ -3,6 +3,7 @@ import { IThemeManager } from '@jupyterlab/apputils';
3
3
  import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
4
4
  import { IChatCommandRegistry } from '../chat-commands';
5
5
  import { IInputToolbarRegistry } from './input';
6
+ import { IMessageFooterRegistry } from '../footers';
6
7
  import { IChatModel } from '../model';
7
8
  import { IAttachmentOpenerRegistry } from '../registry';
8
9
  export declare function ChatBody(props: Chat.IChatBodyProps): JSX.Element;
@@ -35,6 +36,10 @@ export declare namespace Chat {
35
36
  * The input toolbar registry
36
37
  */
37
38
  inputToolbarRegistry?: IInputToolbarRegistry;
39
+ /**
40
+ * The footer registry.
41
+ */
42
+ messageFooterRegistry?: IMessageFooterRegistry;
38
43
  }
39
44
  /**
40
45
  * The options to build the Chat UI.
@@ -19,7 +19,7 @@ export function ChatBody(props) {
19
19
  inputToolbarRegistry = InputToolbarRegistry.defaultToolbarRegistry();
20
20
  }
21
21
  return (React.createElement(AttachmentOpenerContext.Provider, { value: props.attachmentOpenerRegistry },
22
- React.createElement(ChatMessages, { rmRegistry: props.rmRegistry, model: model, chatCommandRegistry: props.chatCommandRegistry, inputToolbarRegistry: inputToolbarRegistry }),
22
+ React.createElement(ChatMessages, { rmRegistry: props.rmRegistry, model: model, chatCommandRegistry: props.chatCommandRegistry, inputToolbarRegistry: inputToolbarRegistry, messageFooterRegistry: props.messageFooterRegistry }),
23
23
  React.createElement(ChatInput, { sx: {
24
24
  paddingLeft: 4,
25
25
  paddingRight: 4,
@@ -0,0 +1,16 @@
1
+ /// <reference types="react" />
2
+ import { IMessageFooterRegistry, MessageFooterSectionProps } from '../../footers';
3
+ /**
4
+ * The chat footer component properties.
5
+ */
6
+ export interface IMessageFootersProps extends MessageFooterSectionProps {
7
+ /**
8
+ * The chat footer registry.
9
+ */
10
+ registry: IMessageFooterRegistry;
11
+ }
12
+ /**
13
+ * The chat footer component, which displays footer components on a row according to
14
+ * their respective positions.
15
+ */
16
+ export declare function MessageFooter(props: IMessageFootersProps): JSX.Element;
@@ -0,0 +1,19 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { Box } from '@mui/material';
6
+ import React from 'react';
7
+ /**
8
+ * The chat footer component, which displays footer components on a row according to
9
+ * their respective positions.
10
+ */
11
+ export function MessageFooter(props) {
12
+ var _a, _b, _c;
13
+ const { message, model, registry } = props;
14
+ const footer = registry.getFooter();
15
+ return (React.createElement(Box, { sx: { display: 'flex', justifyContent: 'space-between' } },
16
+ ((_a = footer.left) === null || _a === void 0 ? void 0 : _a.component) ? (React.createElement(footer.left.component, { message: message, model: model })) : (React.createElement("div", null)),
17
+ ((_b = footer.center) === null || _b === void 0 ? void 0 : _b.component) ? (React.createElement(footer.center.component, { message: message, model: model })) : (React.createElement("div", null)),
18
+ ((_c = footer.right) === null || _c === void 0 ? void 0 : _c.component) ? (React.createElement(footer.right.component, { message: message, model: model })) : (React.createElement("div", null))));
19
+ }
@@ -0,0 +1,2 @@
1
+ export * from './registry';
2
+ export * from './types';
@@ -0,0 +1,6 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ export * from './registry';
6
+ export * from './types';
@@ -0,0 +1,36 @@
1
+ import { Token } from '@lumino/coreutils';
2
+ import { MessageFooter, MessageFooterSection } from './types';
3
+ /**
4
+ * The interface of a registry to provide chat footer.
5
+ */
6
+ export interface IMessageFooterRegistry {
7
+ /**
8
+ * Get the message footer.
9
+ */
10
+ getFooter(): MessageFooter;
11
+ /**
12
+ * Add a message footer section.
13
+ * If multiple labextensions add a section in the same region, only
14
+ * the last one will be displayed.
15
+ */
16
+ addSection(section: MessageFooterSection): void;
17
+ }
18
+ /**
19
+ * The default implementation of the message footer registry.
20
+ */
21
+ export declare class MessageFooterRegistry implements IMessageFooterRegistry {
22
+ /**
23
+ * Get the footer from the registry.
24
+ */
25
+ getFooter(): MessageFooter;
26
+ /**
27
+ * Add a message footer.
28
+ * If several extension add footers, only the last one will be displayed.
29
+ */
30
+ addSection(footer: MessageFooterSection): void;
31
+ private _footers;
32
+ }
33
+ /**
34
+ * The token providing the chat footer registry.
35
+ */
36
+ export declare const IMessageFooterRegistry: Token<IMessageFooterRegistry>;
@@ -0,0 +1,30 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ import { Token } from '@lumino/coreutils';
6
+ /**
7
+ * The default implementation of the message footer registry.
8
+ */
9
+ export class MessageFooterRegistry {
10
+ constructor() {
11
+ this._footers = {};
12
+ }
13
+ /**
14
+ * Get the footer from the registry.
15
+ */
16
+ getFooter() {
17
+ return this._footers;
18
+ }
19
+ /**
20
+ * Add a message footer.
21
+ * If several extension add footers, only the last one will be displayed.
22
+ */
23
+ addSection(footer) {
24
+ this._footers[footer.position] = footer;
25
+ }
26
+ }
27
+ /**
28
+ * The token providing the chat footer registry.
29
+ */
30
+ export const IMessageFooterRegistry = new Token('@jupyter/chat:ChatFooterRegistry');
@@ -0,0 +1,26 @@
1
+ /// <reference types="react" />
2
+ import { IChatModel } from '../model';
3
+ import { IChatMessage } from '../types';
4
+ /**
5
+ * The props sent passed to each `MessageFooterSection` React component.
6
+ */
7
+ export type MessageFooterSectionProps = {
8
+ model: IChatModel;
9
+ message: IChatMessage;
10
+ };
11
+ /**
12
+ * A message footer section which can be added to the footer registry.
13
+ */
14
+ export type MessageFooterSection = {
15
+ component: React.FC<MessageFooterSectionProps>;
16
+ position: 'left' | 'center' | 'right';
17
+ };
18
+ /**
19
+ * The message footer returned by the registry, composed of 'left', 'center',
20
+ * and 'right' sections.
21
+ */
22
+ export type MessageFooter = {
23
+ left?: MessageFooterSection;
24
+ center?: MessageFooterSection;
25
+ right?: MessageFooterSection;
26
+ };
@@ -0,0 +1,5 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+ export {};
package/lib/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  export * from './active-cell-manager';
2
2
  export * from './chat-commands';
3
3
  export * from './components';
4
+ export * from './footers';
4
5
  export * from './icons';
5
6
  export * from './input-model';
6
7
  export * from './model';
package/lib/index.js CHANGED
@@ -5,6 +5,7 @@
5
5
  export * from './active-cell-manager';
6
6
  export * from './chat-commands';
7
7
  export * from './components';
8
+ export * from './footers';
8
9
  export * from './icons';
9
10
  export * from './input-model';
10
11
  export * from './model';
package/lib/types.d.ts CHANGED
@@ -12,6 +12,10 @@ export interface IUser {
12
12
  * The string to use to mention a user in the chat.
13
13
  */
14
14
  mention_name?: string;
15
+ /**
16
+ * Boolean identifying if user is a bot.
17
+ */
18
+ bot?: boolean;
15
19
  }
16
20
  /**
17
21
  * The configuration interface.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jupyter/chat",
3
- "version": "0.10.1",
3
+ "version": "0.11.0",
4
4
  "description": "A package that provides UI components that can be used to create a chat in a Jupyterlab extension.",
5
5
  "keywords": [
6
6
  "jupyter",
@@ -20,8 +20,10 @@ import { AttachmentPreviewList } from './attachments';
20
20
  import { ChatInput } from './chat-input';
21
21
  import { IInputToolbarRegistry } from './input';
22
22
  import { MarkdownRenderer } from './markdown-renderer';
23
+ import { MessageFooter } from './messages/footer';
23
24
  import { ScrollContainer } from './scroll-container';
24
25
  import { IChatCommandRegistry } from '../chat-commands';
26
+ import { IMessageFooterRegistry } from '../footers';
25
27
  import { IInputModel, InputModel } from '../input-model';
26
28
  import { IChatModel } from '../model';
27
29
  import { IChatMessage, IUser } from '../types';
@@ -58,6 +60,10 @@ type BaseMessageProps = {
58
60
  * The input toolbar registry.
59
61
  */
60
62
  inputToolbarRegistry: IInputToolbarRegistry;
63
+ /**
64
+ * The footer registry.
65
+ */
66
+ messageFooterRegistry?: IMessageFooterRegistry;
61
67
  };
62
68
 
63
69
  /**
@@ -198,6 +204,13 @@ export function ChatMessages(props: BaseMessageProps): JSX.Element {
198
204
  renderedPromise={renderedPromise.current[i]}
199
205
  ref={el => (listRef.current[i] = el)}
200
206
  />
207
+ {props.messageFooterRegistry && (
208
+ <MessageFooter
209
+ registry={props.messageFooterRegistry}
210
+ message={message}
211
+ model={model}
212
+ />
213
+ )}
201
214
  </Box>
202
215
  );
203
216
  })}
@@ -366,6 +379,10 @@ export const ChatMessage = forwardRef<HTMLDivElement, ChatMessageProps>(
366
379
  if (model.user.username === message.sender.username) {
367
380
  setCanEdit(model.updateMessage !== undefined);
368
381
  setCanDelete(model.deleteMessage !== undefined);
382
+ return;
383
+ }
384
+ if (message.sender.bot) {
385
+ setCanDelete(model.deleteMessage !== undefined);
369
386
  }
370
387
  } else {
371
388
  setCanEdit(false);
@@ -17,6 +17,7 @@ import { ChatMessages } from './chat-messages';
17
17
  import { ChatInput } from './chat-input';
18
18
  import { IInputToolbarRegistry, InputToolbarRegistry } from './input';
19
19
  import { AttachmentOpenerContext } from '../context';
20
+ import { IMessageFooterRegistry } from '../footers';
20
21
  import { IChatModel } from '../model';
21
22
  import { IAttachmentOpenerRegistry } from '../registry';
22
23
 
@@ -34,6 +35,7 @@ export function ChatBody(props: Chat.IChatBodyProps): JSX.Element {
34
35
  model={model}
35
36
  chatCommandRegistry={props.chatCommandRegistry}
36
37
  inputToolbarRegistry={inputToolbarRegistry}
38
+ messageFooterRegistry={props.messageFooterRegistry}
37
39
  />
38
40
  <ChatInput
39
41
  sx={{
@@ -125,6 +127,10 @@ export namespace Chat {
125
127
  * The input toolbar registry
126
128
  */
127
129
  inputToolbarRegistry?: IInputToolbarRegistry;
130
+ /**
131
+ * The footer registry.
132
+ */
133
+ messageFooterRegistry?: IMessageFooterRegistry;
128
134
  }
129
135
 
130
136
  /**
@@ -0,0 +1,50 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+
6
+ import { Box } from '@mui/material';
7
+ import React from 'react';
8
+ import {
9
+ IMessageFooterRegistry,
10
+ MessageFooterSectionProps
11
+ } from '../../footers';
12
+
13
+ /**
14
+ * The chat footer component properties.
15
+ */
16
+ export interface IMessageFootersProps extends MessageFooterSectionProps {
17
+ /**
18
+ * The chat footer registry.
19
+ */
20
+ registry: IMessageFooterRegistry;
21
+ }
22
+
23
+ /**
24
+ * The chat footer component, which displays footer components on a row according to
25
+ * their respective positions.
26
+ */
27
+ export function MessageFooter(props: IMessageFootersProps): JSX.Element {
28
+ const { message, model, registry } = props;
29
+ const footer = registry.getFooter();
30
+
31
+ return (
32
+ <Box sx={{ display: 'flex', justifyContent: 'space-between' }}>
33
+ {footer.left?.component ? (
34
+ <footer.left.component message={message} model={model} />
35
+ ) : (
36
+ <div />
37
+ )}
38
+ {footer.center?.component ? (
39
+ <footer.center.component message={message} model={model} />
40
+ ) : (
41
+ <div />
42
+ )}
43
+ {footer.right?.component ? (
44
+ <footer.right.component message={message} model={model} />
45
+ ) : (
46
+ <div />
47
+ )}
48
+ </Box>
49
+ );
50
+ }
@@ -0,0 +1,7 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+
6
+ export * from './registry';
7
+ export * from './types';
@@ -0,0 +1,52 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+
6
+ import { Token } from '@lumino/coreutils';
7
+ import { MessageFooter, MessageFooterSection } from './types';
8
+
9
+ /**
10
+ * The interface of a registry to provide chat footer.
11
+ */
12
+ export interface IMessageFooterRegistry {
13
+ /**
14
+ * Get the message footer.
15
+ */
16
+ getFooter(): MessageFooter;
17
+ /**
18
+ * Add a message footer section.
19
+ * If multiple labextensions add a section in the same region, only
20
+ * the last one will be displayed.
21
+ */
22
+ addSection(section: MessageFooterSection): void;
23
+ }
24
+
25
+ /**
26
+ * The default implementation of the message footer registry.
27
+ */
28
+ export class MessageFooterRegistry implements IMessageFooterRegistry {
29
+ /**
30
+ * Get the footer from the registry.
31
+ */
32
+ getFooter(): MessageFooter {
33
+ return this._footers;
34
+ }
35
+
36
+ /**
37
+ * Add a message footer.
38
+ * If several extension add footers, only the last one will be displayed.
39
+ */
40
+ addSection(footer: MessageFooterSection): void {
41
+ this._footers[footer.position] = footer;
42
+ }
43
+
44
+ private _footers: MessageFooter = {};
45
+ }
46
+
47
+ /**
48
+ * The token providing the chat footer registry.
49
+ */
50
+ export const IMessageFooterRegistry = new Token<IMessageFooterRegistry>(
51
+ '@jupyter/chat:ChatFooterRegistry'
52
+ );
@@ -0,0 +1,33 @@
1
+ /*
2
+ * Copyright (c) Jupyter Development Team.
3
+ * Distributed under the terms of the Modified BSD License.
4
+ */
5
+
6
+ import { IChatModel } from '../model';
7
+ import { IChatMessage } from '../types';
8
+
9
+ /**
10
+ * The props sent passed to each `MessageFooterSection` React component.
11
+ */
12
+ export type MessageFooterSectionProps = {
13
+ model: IChatModel;
14
+ message: IChatMessage;
15
+ };
16
+
17
+ /**
18
+ * A message footer section which can be added to the footer registry.
19
+ */
20
+ export type MessageFooterSection = {
21
+ component: React.FC<MessageFooterSectionProps>;
22
+ position: 'left' | 'center' | 'right';
23
+ };
24
+
25
+ /**
26
+ * The message footer returned by the registry, composed of 'left', 'center',
27
+ * and 'right' sections.
28
+ */
29
+ export type MessageFooter = {
30
+ left?: MessageFooterSection;
31
+ center?: MessageFooterSection;
32
+ right?: MessageFooterSection;
33
+ };
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@
6
6
  export * from './active-cell-manager';
7
7
  export * from './chat-commands';
8
8
  export * from './components';
9
+ export * from './footers';
9
10
  export * from './icons';
10
11
  export * from './input-model';
11
12
  export * from './model';
package/src/types.ts CHANGED
@@ -17,6 +17,10 @@ export interface IUser {
17
17
  * The string to use to mention a user in the chat.
18
18
  */
19
19
  mention_name?: string;
20
+ /**
21
+ * Boolean identifying if user is a bot.
22
+ */
23
+ bot?: boolean;
20
24
  }
21
25
 
22
26
  /**