@jupyter/chat 0.1.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.
- package/lib/__tests__/model.spec.d.ts +1 -0
- package/lib/__tests__/model.spec.js +72 -0
- package/lib/__tests__/widgets.spec.d.ts +1 -0
- package/lib/__tests__/widgets.spec.js +33 -0
- package/lib/components/chat-input.d.ts +33 -0
- package/lib/components/chat-input.js +60 -0
- package/lib/components/chat-messages.d.ts +32 -0
- package/lib/components/chat-messages.js +162 -0
- package/lib/components/chat.d.ts +43 -0
- package/lib/components/chat.js +100 -0
- package/lib/components/copy-button.d.ts +6 -0
- package/lib/components/copy-button.js +35 -0
- package/lib/components/jl-theme-provider.d.ts +6 -0
- package/lib/components/jl-theme-provider.js +19 -0
- package/lib/components/mui-extras/stacking-alert.d.ts +28 -0
- package/lib/components/mui-extras/stacking-alert.js +56 -0
- package/lib/components/rendermime-markdown.d.ts +12 -0
- package/lib/components/rendermime-markdown.js +54 -0
- package/lib/components/scroll-container.d.ts +23 -0
- package/lib/components/scroll-container.js +51 -0
- package/lib/components/toolbar.d.ts +11 -0
- package/lib/components/toolbar.js +30 -0
- package/lib/icons.d.ts +2 -0
- package/lib/icons.js +11 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +10 -0
- package/lib/model.d.ts +177 -0
- package/lib/model.js +128 -0
- package/lib/theme-provider.d.ts +3 -0
- package/lib/theme-provider.js +133 -0
- package/lib/types.d.ts +49 -0
- package/lib/types.js +5 -0
- package/lib/widgets/chat-error.d.ts +2 -0
- package/lib/widgets/chat-error.js +26 -0
- package/lib/widgets/chat-sidebar.d.ts +4 -0
- package/lib/widgets/chat-sidebar.js +15 -0
- package/lib/widgets/chat-widget.d.ts +19 -0
- package/lib/widgets/chat-widget.js +28 -0
- package/package.json +209 -0
- package/src/__tests__/model.spec.ts +84 -0
- package/src/__tests__/widgets.spec.ts +43 -0
- package/src/components/chat-input.tsx +143 -0
- package/src/components/chat-messages.tsx +283 -0
- package/src/components/chat.tsx +179 -0
- package/src/components/copy-button.tsx +55 -0
- package/src/components/jl-theme-provider.tsx +28 -0
- package/src/components/mui-extras/stacking-alert.tsx +105 -0
- package/src/components/rendermime-markdown.tsx +88 -0
- package/src/components/scroll-container.tsx +74 -0
- package/src/components/toolbar.tsx +50 -0
- package/src/icons.ts +15 -0
- package/src/index.ts +11 -0
- package/src/model.ts +272 -0
- package/src/theme-provider.ts +137 -0
- package/src/types/mui.d.ts +18 -0
- package/src/types/svg.d.ts +17 -0
- package/src/types.ts +58 -0
- package/src/widgets/chat-error.tsx +43 -0
- package/src/widgets/chat-sidebar.tsx +30 -0
- package/src/widgets/chat-widget.tsx +51 -0
- package/style/base.css +13 -0
- package/style/chat-settings.css +10 -0
- package/style/chat.css +53 -0
- package/style/icons/chat.svg +6 -0
- package/style/index.css +6 -0
- package/style/index.js +6 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Jupyter Development Team.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { createTheme } from '@mui/material/styles';
|
|
6
|
+
function getCSSVariable(name) {
|
|
7
|
+
return getComputedStyle(document.body).getPropertyValue(name).trim();
|
|
8
|
+
}
|
|
9
|
+
export async function pollUntilReady() {
|
|
10
|
+
while (!document.body.hasAttribute('data-jp-theme-light')) {
|
|
11
|
+
await new Promise(resolve => setTimeout(resolve, 100)); // Wait 100ms
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export async function getJupyterLabTheme() {
|
|
15
|
+
await pollUntilReady();
|
|
16
|
+
const light = document.body.getAttribute('data-jp-theme-light');
|
|
17
|
+
return createTheme({
|
|
18
|
+
spacing: 4,
|
|
19
|
+
components: {
|
|
20
|
+
MuiButton: {
|
|
21
|
+
defaultProps: {
|
|
22
|
+
size: 'small'
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
MuiFilledInput: {
|
|
26
|
+
defaultProps: {
|
|
27
|
+
margin: 'dense'
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
MuiFormControl: {
|
|
31
|
+
defaultProps: {
|
|
32
|
+
margin: 'dense',
|
|
33
|
+
size: 'small'
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
MuiFormHelperText: {
|
|
37
|
+
defaultProps: {
|
|
38
|
+
margin: 'dense'
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
MuiIconButton: {
|
|
42
|
+
defaultProps: {
|
|
43
|
+
size: 'small'
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
MuiInputBase: {
|
|
47
|
+
defaultProps: {
|
|
48
|
+
margin: 'dense',
|
|
49
|
+
size: 'small'
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
MuiInputLabel: {
|
|
53
|
+
defaultProps: {
|
|
54
|
+
margin: 'dense'
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
MuiListItem: {
|
|
58
|
+
defaultProps: {
|
|
59
|
+
dense: true
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
MuiOutlinedInput: {
|
|
63
|
+
defaultProps: {
|
|
64
|
+
margin: 'dense'
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
MuiFab: {
|
|
68
|
+
defaultProps: {
|
|
69
|
+
size: 'small'
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
MuiTable: {
|
|
73
|
+
defaultProps: {
|
|
74
|
+
size: 'small'
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
MuiTextField: {
|
|
78
|
+
defaultProps: {
|
|
79
|
+
margin: 'dense',
|
|
80
|
+
size: 'small'
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
MuiToolbar: {
|
|
84
|
+
defaultProps: {
|
|
85
|
+
variant: 'dense'
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
palette: {
|
|
90
|
+
background: {
|
|
91
|
+
paper: getCSSVariable('--jp-layout-color1'),
|
|
92
|
+
default: getCSSVariable('--jp-layout-color1')
|
|
93
|
+
},
|
|
94
|
+
mode: light === 'true' ? 'light' : 'dark',
|
|
95
|
+
primary: {
|
|
96
|
+
main: getCSSVariable('--jp-brand-color1'),
|
|
97
|
+
light: getCSSVariable('--jp-brand-color2'),
|
|
98
|
+
dark: getCSSVariable('--jp-brand-color0')
|
|
99
|
+
},
|
|
100
|
+
error: {
|
|
101
|
+
main: getCSSVariable('--jp-error-color1'),
|
|
102
|
+
light: getCSSVariable('--jp-error-color2'),
|
|
103
|
+
dark: getCSSVariable('--jp-error-color0')
|
|
104
|
+
},
|
|
105
|
+
warning: {
|
|
106
|
+
main: getCSSVariable('--jp-warn-color1'),
|
|
107
|
+
light: getCSSVariable('--jp-warn-color2'),
|
|
108
|
+
dark: getCSSVariable('--jp-warn-color0')
|
|
109
|
+
},
|
|
110
|
+
success: {
|
|
111
|
+
main: getCSSVariable('--jp-success-color1'),
|
|
112
|
+
light: getCSSVariable('--jp-success-color2'),
|
|
113
|
+
dark: getCSSVariable('--jp-success-color0')
|
|
114
|
+
},
|
|
115
|
+
text: {
|
|
116
|
+
primary: getCSSVariable('--jp-ui-font-color1'),
|
|
117
|
+
secondary: getCSSVariable('--jp-ui-font-color2'),
|
|
118
|
+
disabled: getCSSVariable('--jp-ui-font-color3')
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
shape: {
|
|
122
|
+
borderRadius: 2
|
|
123
|
+
},
|
|
124
|
+
typography: {
|
|
125
|
+
fontFamily: getCSSVariable('--jp-ui-font-family'),
|
|
126
|
+
fontSize: 12,
|
|
127
|
+
htmlFontSize: 16,
|
|
128
|
+
button: {
|
|
129
|
+
textTransform: 'capitalize'
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The user description.
|
|
3
|
+
*/
|
|
4
|
+
export interface IUser {
|
|
5
|
+
username: string;
|
|
6
|
+
name?: string;
|
|
7
|
+
display_name?: string;
|
|
8
|
+
initials?: string;
|
|
9
|
+
color?: string;
|
|
10
|
+
avatar_url?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* The configuration interface.
|
|
14
|
+
*/
|
|
15
|
+
export interface IConfig {
|
|
16
|
+
sendWithShiftEnter?: boolean;
|
|
17
|
+
lastRead?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The chat message decription.
|
|
21
|
+
*/
|
|
22
|
+
export interface IChatMessage {
|
|
23
|
+
type: 'msg';
|
|
24
|
+
body: string;
|
|
25
|
+
id: string;
|
|
26
|
+
time: number;
|
|
27
|
+
sender: IUser | string;
|
|
28
|
+
raw_time?: boolean;
|
|
29
|
+
deleted?: boolean;
|
|
30
|
+
edited?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The chat history interface.
|
|
34
|
+
*/
|
|
35
|
+
export interface IChatHistory {
|
|
36
|
+
messages: IChatMessage[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The content of a new message.
|
|
40
|
+
*/
|
|
41
|
+
export interface INewMessage {
|
|
42
|
+
body: string;
|
|
43
|
+
id?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* An empty interface to describe optional settings taht could be fetched from server.
|
|
47
|
+
*/
|
|
48
|
+
export interface ISettings {
|
|
49
|
+
}
|
package/lib/types.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Jupyter Development Team.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { ReactWidget } from '@jupyterlab/apputils';
|
|
6
|
+
import { Alert, Box } from '@mui/material';
|
|
7
|
+
import React from 'react';
|
|
8
|
+
import { JlThemeProvider } from '../components/jl-theme-provider';
|
|
9
|
+
import { chatIcon } from '../icons';
|
|
10
|
+
export function buildErrorWidget(themeManager) {
|
|
11
|
+
const ErrorWidget = ReactWidget.create(React.createElement(JlThemeProvider, { themeManager: themeManager },
|
|
12
|
+
React.createElement(Box, { sx: {
|
|
13
|
+
width: '100%',
|
|
14
|
+
height: '100%',
|
|
15
|
+
boxSizing: 'border-box',
|
|
16
|
+
background: 'var(--jp-layout-color0)',
|
|
17
|
+
display: 'flex',
|
|
18
|
+
flexDirection: 'column'
|
|
19
|
+
} },
|
|
20
|
+
React.createElement(Box, { sx: { padding: 4 } },
|
|
21
|
+
React.createElement(Alert, { severity: "error" }, "There seems to be a problem with the Chat backend, please look at the JupyterLab server logs or contact your administrator to correct this problem.")))));
|
|
22
|
+
ErrorWidget.id = 'jupyter-chat::chat';
|
|
23
|
+
ErrorWidget.title.icon = chatIcon;
|
|
24
|
+
ErrorWidget.title.caption = 'Jupyter Chat'; // TODO: i18n
|
|
25
|
+
return ErrorWidget;
|
|
26
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { IThemeManager, ReactWidget } from '@jupyterlab/apputils';
|
|
2
|
+
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
3
|
+
import { IChatModel } from '../model';
|
|
4
|
+
export declare function buildChatSidebar(chatModel: IChatModel, themeManager: IThemeManager | null, rmRegistry: IRenderMimeRegistry): ReactWidget;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Jupyter Development Team.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { ReactWidget } from '@jupyterlab/apputils';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { Chat } from '../components/chat';
|
|
8
|
+
import { chatIcon } from '../icons';
|
|
9
|
+
export function buildChatSidebar(chatModel, themeManager, rmRegistry) {
|
|
10
|
+
const ChatWidget = ReactWidget.create(React.createElement(Chat, { model: chatModel, themeManager: themeManager, rmRegistry: rmRegistry }));
|
|
11
|
+
ChatWidget.id = 'jupyter-chat::side-panel';
|
|
12
|
+
ChatWidget.title.icon = chatIcon;
|
|
13
|
+
ChatWidget.title.caption = 'Jupyter Chat'; // TODO: i18n
|
|
14
|
+
return ChatWidget;
|
|
15
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ReactWidget } from '@jupyterlab/apputils';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Chat } from '../components/chat';
|
|
4
|
+
import { IChatModel } from '../model';
|
|
5
|
+
export declare class ChatWidget extends ReactWidget {
|
|
6
|
+
constructor(options: Chat.IOptions);
|
|
7
|
+
/**
|
|
8
|
+
* Gte the model of the widget.
|
|
9
|
+
*/
|
|
10
|
+
get model(): IChatModel;
|
|
11
|
+
render(): React.JSX.Element;
|
|
12
|
+
private readonly _model;
|
|
13
|
+
private _themeManager;
|
|
14
|
+
private _rmRegistry;
|
|
15
|
+
}
|
|
16
|
+
export declare namespace ChatWidget {
|
|
17
|
+
interface IOptions extends Chat.IOptions {
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Jupyter Development Team.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { ReactWidget } from '@jupyterlab/apputils';
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { Chat } from '../components/chat';
|
|
8
|
+
import { chatIcon } from '../icons';
|
|
9
|
+
export class ChatWidget extends ReactWidget {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super();
|
|
12
|
+
this.id = 'jupyter-chat::widget';
|
|
13
|
+
this.title.icon = chatIcon;
|
|
14
|
+
this.title.caption = 'Jupyter Chat'; // TODO: i18n
|
|
15
|
+
this._model = options.model;
|
|
16
|
+
this._themeManager = (options === null || options === void 0 ? void 0 : options.themeManager) || null;
|
|
17
|
+
this._rmRegistry = options.rmRegistry;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Gte the model of the widget.
|
|
21
|
+
*/
|
|
22
|
+
get model() {
|
|
23
|
+
return this._model;
|
|
24
|
+
}
|
|
25
|
+
render() {
|
|
26
|
+
return (React.createElement(Chat, { model: this._model, themeManager: this._themeManager, rmRegistry: this._rmRegistry }));
|
|
27
|
+
}
|
|
28
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jupyter/chat",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A package that provides UI components that can be used to create a chat in a Jupyterlab extension.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"jupyter",
|
|
7
|
+
"jupyterlab",
|
|
8
|
+
"jupyterlab-extension"
|
|
9
|
+
],
|
|
10
|
+
"homepage": "https://github.com/jupyterlab/jupyter-chat",
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/jupyterlab/jupyter-chat/issues"
|
|
13
|
+
},
|
|
14
|
+
"license": "BSD-3-Clause",
|
|
15
|
+
"author": {
|
|
16
|
+
"name": "Jupyter Development Team",
|
|
17
|
+
"email": "jupyter@googlegroups.com"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"lib/**/*.{d.ts,eot,gif,html,jpg,js,js.map,json,png,svg,woff2,ttf}",
|
|
21
|
+
"style/**/*.{css,js,eot,gif,html,jpg,json,png,svg,woff2,ttf}",
|
|
22
|
+
"src/**/*.{ts,tsx}",
|
|
23
|
+
"schema/*.json"
|
|
24
|
+
],
|
|
25
|
+
"main": "lib/index.js",
|
|
26
|
+
"types": "lib/index.d.ts",
|
|
27
|
+
"style": "style/index.css",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/jupyterlab/jupyter-chat.git"
|
|
31
|
+
},
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "jlpm build:lib",
|
|
34
|
+
"build:prod": "jlpm clean && jlpm build:lib:prod",
|
|
35
|
+
"build:lib": "tsc --sourceMap",
|
|
36
|
+
"build:lib:prod": "tsc",
|
|
37
|
+
"clean": "jlpm clean:lib",
|
|
38
|
+
"clean:lib": "rimraf lib tsconfig.tsbuildinfo",
|
|
39
|
+
"clean:lintcache": "rimraf .eslintcache .stylelintcache",
|
|
40
|
+
"clean:all": "jlpm clean:lib && jlpm clean:lintcache",
|
|
41
|
+
"eslint": "jlpm eslint:check --fix",
|
|
42
|
+
"eslint:check": "eslint . --cache --ext .ts,.tsx",
|
|
43
|
+
"install:extension": "jlpm build",
|
|
44
|
+
"lint": "jlpm stylelint && jlpm prettier && jlpm eslint",
|
|
45
|
+
"lint:check": "jlpm stylelint:check && jlpm prettier:check && jlpm eslint:check",
|
|
46
|
+
"prettier": "jlpm prettier:base --write --list-different",
|
|
47
|
+
"prettier:base": "prettier \"**/*{.ts,.tsx,.js,.jsx,.css,.json,.md}\"",
|
|
48
|
+
"prettier:check": "jlpm prettier:base --check",
|
|
49
|
+
"stylelint": "jlpm stylelint:check --fix",
|
|
50
|
+
"stylelint:check": "stylelint --cache \"style/**/*.css\"",
|
|
51
|
+
"test": "jest --coverage",
|
|
52
|
+
"watch:src": "tsc -w --sourceMap"
|
|
53
|
+
},
|
|
54
|
+
"dependencies": {
|
|
55
|
+
"@emotion/react": "^11.10.5",
|
|
56
|
+
"@emotion/styled": "^11.10.5",
|
|
57
|
+
"@jupyterlab/apputils": "^4.0.0",
|
|
58
|
+
"@jupyterlab/rendermime": "^4.0.0",
|
|
59
|
+
"@jupyterlab/ui-components": "^4.0.0",
|
|
60
|
+
"@lumino/disposable": "^2.0.0",
|
|
61
|
+
"@lumino/signaling": "^2.0.0",
|
|
62
|
+
"@mui/icons-material": "^5.11.0",
|
|
63
|
+
"@mui/material": "^5.11.0",
|
|
64
|
+
"clsx": "^2.1.0",
|
|
65
|
+
"react": "^18.2.0",
|
|
66
|
+
"react-dom": "^18.2.0"
|
|
67
|
+
},
|
|
68
|
+
"devDependencies": {
|
|
69
|
+
"@types/jest": "^29.2.0",
|
|
70
|
+
"@types/json-schema": "^7.0.11",
|
|
71
|
+
"@types/react": "^18.2.0",
|
|
72
|
+
"@types/react-addons-linked-state-mixin": "^0.14.22",
|
|
73
|
+
"@types/react-dom": "^18.2.0",
|
|
74
|
+
"@typescript-eslint/eslint-plugin": "^6.1.0",
|
|
75
|
+
"@typescript-eslint/parser": "^6.1.0",
|
|
76
|
+
"css-loader": "^6.7.1",
|
|
77
|
+
"eslint": "^8.36.0",
|
|
78
|
+
"eslint-config-prettier": "^8.8.0",
|
|
79
|
+
"eslint-plugin-prettier": "^5.0.0",
|
|
80
|
+
"jest": "^29.2.0",
|
|
81
|
+
"npm-run-all": "^4.1.5",
|
|
82
|
+
"prettier": "^3.0.0",
|
|
83
|
+
"rimraf": "^5.0.1",
|
|
84
|
+
"source-map-loader": "^1.0.2",
|
|
85
|
+
"style-loader": "^3.3.1",
|
|
86
|
+
"stylelint": "^15.10.1",
|
|
87
|
+
"stylelint-config-recommended": "^13.0.0",
|
|
88
|
+
"stylelint-config-standard": "^34.0.0",
|
|
89
|
+
"stylelint-csstree-validator": "^3.0.0",
|
|
90
|
+
"stylelint-prettier": "^4.0.0",
|
|
91
|
+
"typescript": "~5.0.2"
|
|
92
|
+
},
|
|
93
|
+
"sideEffects": [
|
|
94
|
+
"style/*.css",
|
|
95
|
+
"style/index.js"
|
|
96
|
+
],
|
|
97
|
+
"styleModule": "style/index.js",
|
|
98
|
+
"publishConfig": {
|
|
99
|
+
"access": "public"
|
|
100
|
+
},
|
|
101
|
+
"jupyterlab": {
|
|
102
|
+
"discovery": {
|
|
103
|
+
"server": {
|
|
104
|
+
"managers": [
|
|
105
|
+
"pip"
|
|
106
|
+
],
|
|
107
|
+
"base": {
|
|
108
|
+
"name": "jupyter_chat"
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"extension": false,
|
|
113
|
+
"schemaDir": "schema"
|
|
114
|
+
},
|
|
115
|
+
"eslintIgnore": [
|
|
116
|
+
"node_modules",
|
|
117
|
+
"dist",
|
|
118
|
+
"coverage",
|
|
119
|
+
"**/*.d.ts",
|
|
120
|
+
"tests",
|
|
121
|
+
"**/__tests__",
|
|
122
|
+
"ui-tests"
|
|
123
|
+
],
|
|
124
|
+
"eslintConfig": {
|
|
125
|
+
"extends": [
|
|
126
|
+
"eslint:recommended",
|
|
127
|
+
"plugin:@typescript-eslint/eslint-recommended",
|
|
128
|
+
"plugin:@typescript-eslint/recommended",
|
|
129
|
+
"plugin:prettier/recommended"
|
|
130
|
+
],
|
|
131
|
+
"parser": "@typescript-eslint/parser",
|
|
132
|
+
"parserOptions": {
|
|
133
|
+
"project": "tsconfig.json",
|
|
134
|
+
"sourceType": "module"
|
|
135
|
+
},
|
|
136
|
+
"plugins": [
|
|
137
|
+
"@typescript-eslint"
|
|
138
|
+
],
|
|
139
|
+
"rules": {
|
|
140
|
+
"@typescript-eslint/naming-convention": [
|
|
141
|
+
"error",
|
|
142
|
+
{
|
|
143
|
+
"selector": "interface",
|
|
144
|
+
"format": [
|
|
145
|
+
"PascalCase"
|
|
146
|
+
],
|
|
147
|
+
"custom": {
|
|
148
|
+
"regex": "^I[A-Z]",
|
|
149
|
+
"match": true
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
],
|
|
153
|
+
"@typescript-eslint/no-unused-vars": [
|
|
154
|
+
"warn",
|
|
155
|
+
{
|
|
156
|
+
"args": "none"
|
|
157
|
+
}
|
|
158
|
+
],
|
|
159
|
+
"@typescript-eslint/no-explicit-any": "off",
|
|
160
|
+
"@typescript-eslint/no-namespace": "off",
|
|
161
|
+
"@typescript-eslint/no-use-before-define": "off",
|
|
162
|
+
"@typescript-eslint/quotes": [
|
|
163
|
+
"error",
|
|
164
|
+
"single",
|
|
165
|
+
{
|
|
166
|
+
"avoidEscape": true,
|
|
167
|
+
"allowTemplateLiterals": false
|
|
168
|
+
}
|
|
169
|
+
],
|
|
170
|
+
"curly": [
|
|
171
|
+
"error",
|
|
172
|
+
"all"
|
|
173
|
+
],
|
|
174
|
+
"eqeqeq": "error",
|
|
175
|
+
"prefer-arrow-callback": "error"
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
"prettier": {
|
|
179
|
+
"singleQuote": true,
|
|
180
|
+
"trailingComma": "none",
|
|
181
|
+
"arrowParens": "avoid",
|
|
182
|
+
"endOfLine": "auto",
|
|
183
|
+
"overrides": [
|
|
184
|
+
{
|
|
185
|
+
"files": "package.json",
|
|
186
|
+
"options": {
|
|
187
|
+
"tabWidth": 4
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
},
|
|
192
|
+
"stylelint": {
|
|
193
|
+
"extends": [
|
|
194
|
+
"stylelint-config-recommended",
|
|
195
|
+
"stylelint-config-standard",
|
|
196
|
+
"stylelint-prettier/recommended"
|
|
197
|
+
],
|
|
198
|
+
"plugins": [
|
|
199
|
+
"stylelint-csstree-validator"
|
|
200
|
+
],
|
|
201
|
+
"rules": {
|
|
202
|
+
"csstree/validator": true,
|
|
203
|
+
"property-no-vendor-prefix": null,
|
|
204
|
+
"selector-class-pattern": "^([a-z][A-z\\d]*)(-[A-z\\d]+)*$",
|
|
205
|
+
"selector-no-vendor-prefix": null,
|
|
206
|
+
"value-no-vendor-prefix": null
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Jupyter Development Team.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Example of [Jest](https://jestjs.io/docs/getting-started) unit tests
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { ChatModel, IChatModel } from '../model';
|
|
11
|
+
import { IChatMessage } from '../types';
|
|
12
|
+
|
|
13
|
+
describe('test chat model', () => {
|
|
14
|
+
describe('model instantiation', () => {
|
|
15
|
+
it('should create a ChatModel', () => {
|
|
16
|
+
const model = new ChatModel();
|
|
17
|
+
expect(model).toBeInstanceOf(ChatModel);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('should dispose a ChatModel', () => {
|
|
21
|
+
const model = new ChatModel();
|
|
22
|
+
model.dispose();
|
|
23
|
+
expect(model.isDisposed).toBeTruthy();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
describe('incoming message', () => {
|
|
28
|
+
class TestChat extends ChatModel {
|
|
29
|
+
protected formatChatMessage(message: IChatMessage): IChatMessage {
|
|
30
|
+
message.body = 'formatted msg';
|
|
31
|
+
return message;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let model: IChatModel;
|
|
36
|
+
let messages: IChatMessage[];
|
|
37
|
+
const msg = {
|
|
38
|
+
type: 'msg',
|
|
39
|
+
id: 'message1',
|
|
40
|
+
time: Date.now() / 1000,
|
|
41
|
+
body: 'message test',
|
|
42
|
+
sender: { username: 'user' }
|
|
43
|
+
} as IChatMessage;
|
|
44
|
+
|
|
45
|
+
beforeEach(() => {
|
|
46
|
+
messages = [];
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should signal incoming message', () => {
|
|
50
|
+
model = new ChatModel();
|
|
51
|
+
model.messagesUpdated.connect((sender: IChatModel) => {
|
|
52
|
+
expect(sender).toBe(model);
|
|
53
|
+
messages = model.messages;
|
|
54
|
+
});
|
|
55
|
+
model.messageAdded(msg);
|
|
56
|
+
expect(messages).toHaveLength(1);
|
|
57
|
+
expect(messages[0]).toBe(msg);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should format message', () => {
|
|
61
|
+
model = new TestChat();
|
|
62
|
+
model.messagesUpdated.connect((sender: IChatModel) => {
|
|
63
|
+
expect(sender).toBe(model);
|
|
64
|
+
messages = model.messages;
|
|
65
|
+
});
|
|
66
|
+
model.messageAdded({ ...msg });
|
|
67
|
+
expect(messages).toHaveLength(1);
|
|
68
|
+
expect(messages[0]).not.toBe(msg);
|
|
69
|
+
expect((messages[0] as IChatMessage).body).toBe('formatted msg');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('model config', () => {
|
|
74
|
+
it('should have empty config', () => {
|
|
75
|
+
const model = new ChatModel();
|
|
76
|
+
expect(model.config.sendWithShiftEnter).toBeUndefined();
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should allow config', () => {
|
|
80
|
+
const model = new ChatModel({ config: { sendWithShiftEnter: true } });
|
|
81
|
+
expect(model.config.sendWithShiftEnter).toBeTruthy();
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Jupyter Development Team.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Example of [Jest](https://jestjs.io/docs/getting-started) unit tests
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
IRenderMimeRegistry,
|
|
12
|
+
RenderMimeRegistry
|
|
13
|
+
} from '@jupyterlab/rendermime';
|
|
14
|
+
import { ChatModel, IChatModel } from '../model';
|
|
15
|
+
import { ChatWidget } from '../widgets/chat-widget';
|
|
16
|
+
|
|
17
|
+
describe('test chat widget', () => {
|
|
18
|
+
let model: IChatModel;
|
|
19
|
+
let rmRegistry: IRenderMimeRegistry;
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
model = new ChatModel();
|
|
23
|
+
rmRegistry = new RenderMimeRegistry();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe('model instantiation', () => {
|
|
27
|
+
it('should create a ChatModel', () => {
|
|
28
|
+
const widget = new ChatWidget({ model, rmRegistry });
|
|
29
|
+
expect(widget).toBeInstanceOf(ChatWidget);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should dispose a ChatModel', () => {
|
|
33
|
+
const widget = new ChatWidget({ model, rmRegistry });
|
|
34
|
+
widget.dispose();
|
|
35
|
+
expect(widget.isDisposed).toBeTruthy();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should provides the model', () => {
|
|
39
|
+
const widget = new ChatWidget({ model, rmRegistry });
|
|
40
|
+
expect(widget.model).toBe(model);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
});
|