Skip to content

Commit 9780e82

Browse files
authored
UI/UX improvements (#11)
* Display message as user message * Add an attachement opener registry
1 parent 2733f86 commit 9780e82

3 files changed

Lines changed: 73 additions & 6 deletions

File tree

src/index.ts

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
1-
import { ChatWidget, INotebookAttachment } from '@jupyter/chat';
1+
import {
2+
AttachmentOpenerRegistry,
3+
ChatWidget,
4+
IAttachment,
5+
INotebookAttachment
6+
} from '@jupyter/chat';
27
import {
38
JupyterFrontEnd,
49
JupyterFrontEndPlugin
510
} from '@jupyterlab/application';
611
import { ICodeCellModel } from '@jupyterlab/cells';
7-
import { INotebookTracker } from '@jupyterlab/notebook';
12+
import { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook';
813
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
914
import { ISettingRegistry } from '@jupyterlab/settingregistry';
1015
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
1116
import { infoIcon } from '@jupyterlab/ui-components';
1217

1318
import { TutorChatModel } from './model';
19+
import { isContinuous } from './utils';
1420

1521
const INFO_ICON_BASE_64 = btoa(infoIcon.svgstr);
1622

@@ -47,6 +53,53 @@ const plugin: JupyterFrontEndPlugin<void> = {
4753
const { commands } = app;
4854
const trans = (translator ?? nullTranslator).load('jupyterlab');
4955

56+
// The attachment opener registry.
57+
const attachmentOpenerRegistry = new AttachmentOpenerRegistry();
58+
59+
attachmentOpenerRegistry.set('file', (attachment: IAttachment) => {
60+
app.commands.execute('docmanager:open', { path: attachment.value });
61+
});
62+
63+
attachmentOpenerRegistry.set(
64+
'notebook',
65+
async (attachment: IAttachment) => {
66+
// Reveal the notebook.
67+
const widget = await app.commands.execute('docmanager:open', {
68+
path: attachment.value
69+
});
70+
71+
// Check if cells are attached.
72+
if (
73+
widget &&
74+
attachment.type === 'notebook' &&
75+
attachment.cells?.length
76+
) {
77+
const panel = widget as NotebookPanel;
78+
await panel.context.ready;
79+
80+
// Get the attached cell indexes in order.
81+
const cellList = panel.context.model.cells;
82+
const cellIds = attachment.cells.map(cell => cell.id);
83+
const range: number[] = [];
84+
for (let i = 0; i < cellList.length; i++) {
85+
if (cellIds.includes(cellList.get(i).id)) {
86+
range.push(i);
87+
}
88+
}
89+
range.sort();
90+
91+
// Set the first cell as active.
92+
panel.content.activeCellIndex = range[0];
93+
94+
// If cells are contiguous, select all of them.
95+
if (isContinuous(range)) {
96+
panel.content.extendContiguousSelectionTo(range[range.length - 1]);
97+
}
98+
}
99+
}
100+
);
101+
102+
// Build the chat.
50103
const tutorModel = new TutorChatModel({
51104
id: 'jupyter-ai-tutor',
52105
translator: translator ?? undefined
@@ -57,7 +110,8 @@ const plugin: JupyterFrontEndPlugin<void> = {
57110
translator: translator ?? undefined,
58111
welcomeMessage: trans.__(
59112
`## Select a code cell and click **Explain Code** <img src="data:image/svg+xml;base64,${INFO_ICON_BASE_64}" /> to get started.`
60-
)
113+
),
114+
attachmentOpenerRegistry
61115
});
62116
chatWidget.id = 'jupyter-ai-tutor-panel';
63117
chatWidget.title.label = trans.__('Tutor');

src/model.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ export class TutorChatModel extends AbstractChatModel {
4747
this.setReady();
4848
}
4949

50-
get user(): IUser | undefined {
51-
return undefined;
50+
get user(): IUser {
51+
return { username: 'user', display_name: 'You' };
5252
}
5353

5454
sendMessage(message: ITutorNewMessage): void {
@@ -57,7 +57,7 @@ export class TutorChatModel extends AbstractChatModel {
5757
id: UUID.uuid4(),
5858
time: Date.now() / 1000,
5959
body: message.body,
60-
sender: this.user ?? { username: 'user', display_name: 'You' },
60+
sender: this.user,
6161
attachments: message.attachments
6262
};
6363
this.messageAdded(userMsg);

src/utils.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
export function isContinuous(numbers: number[]): boolean {
2+
if (numbers.length <= 1) {
3+
return true;
4+
}
5+
6+
for (let i = 1; i < numbers.length; i++) {
7+
if (numbers[i] !== numbers[i - 1] + 1) {
8+
return false;
9+
}
10+
}
11+
12+
return true;
13+
}

0 commit comments

Comments
 (0)