Skip to content

Commit 2999401

Browse files
committed
Link dot plot to chatbox
1 parent 43b21cd commit 2999401

File tree

4 files changed

+73
-19
lines changed

4 files changed

+73
-19
lines changed

packages/collaboration-extension/src/collaboration.ts

+8-4
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,7 @@ export const rtcPanelPlugin: JupyterFrontEndPlugin<void> = {
180180
collaboratorsPanel.title.label = trans.__('Online Collaborators');
181181
userPanel.addWidget(collaboratorsPanel);
182182

183-
const activityDisplay = new ActivityDisplay(tracker, user, roles);
184-
activityDisplay.title.label = trans.__('User activity');
185-
userPanel.addWidget(activityDisplay);
183+
186184

187185
const chatPanel = new SidePanel({
188186
alignment: 'justify'
@@ -193,12 +191,18 @@ export const rtcPanelPlugin: JupyterFrontEndPlugin<void> = {
193191
chatPanel.addClass('jp-RTCPanel');
194192
app.shell.add(chatPanel, 'left', { rank: 301 });
195193

196-
const chatbox = new Chatbox(user, awarenessProvider, roles);
194+
const chatbox = new Chatbox(user, awarenessProvider);
195+
chatbox.id = 'jp-chatbox';
197196
chatbox.title.label = trans.__('Chat with collaborators');
198197
chatPanel.addWidget(chatbox);
199198

199+
const activityDisplay = new ActivityDisplay(tracker, user, roles, app, chatPanel);
200+
activityDisplay.title.label = trans.__('User activity');
201+
userPanel.addWidget(activityDisplay);
202+
200203
setTimeout(() => {
201204
const pollTab = new PollList(user, awarenessProvider, roles);
205+
pollTab.id = 'jp-polls';
202206
pollTab.title.label = trans.__('Polls');
203207
chatPanel.addWidget(pollTab);
204208
}, 1000);

packages/collaboration/src/activitydisplay.tsx

+19-5
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
import { ReactWidget } from '@jupyterlab/apputils';
22
import { INotebookTracker } from '@jupyterlab/notebook';
33
import { User } from '@jupyterlab/services';
4+
import { JupyterFrontEnd } from '@jupyterlab/application';
45

56
import * as React from 'react';
67

78
import { ActivityBarGraph } from './activitybargraph';
89
import { ActivityDotPlot } from './activitydotplot';
910
import { Role, Roles } from './roles';
11+
import { SidePanel } from '@jupyterlab/ui-components';
1012

1113
export interface ActivityDisplayComponentProps {
1214

1315
tracker: INotebookTracker;
1416
currentUser: User.IManager;
15-
userRoles: Roles
17+
userRoles: Roles;
18+
app: JupyterFrontEnd;
19+
chatPanel: SidePanel;
1620

1721
}
1822

@@ -27,31 +31,41 @@ export class ActivityDisplay extends ReactWidget {
2731
private _tracker: INotebookTracker
2832
private _currentUser: User.IManager;
2933
private _roles: Roles;
34+
private _app: JupyterFrontEnd;
35+
private _chatPanel: SidePanel;
3036

31-
constructor(tracker: INotebookTracker, currentUser: User.IManager, roles: Roles) {
37+
constructor(tracker: INotebookTracker, currentUser: User.IManager, roles: Roles, app: JupyterFrontEnd, chatPanel: SidePanel) {
3238

3339
super();
3440

3541
this._tracker = tracker;
3642
this._currentUser = currentUser;
3743
this._roles = roles;
44+
this._app = app;
45+
this._chatPanel = chatPanel;
3846

3947
}
4048

4149
render() {
42-
return <ActivityDisplayComponent tracker={this._tracker} currentUser={this._currentUser} userRoles={this._roles}/>
50+
return <ActivityDisplayComponent
51+
tracker={this._tracker}
52+
currentUser={this._currentUser}
53+
userRoles={this._roles}
54+
app={this._app}
55+
chatPanel={this._chatPanel}
56+
/>
4357
}
4458

4559
}
4660

47-
const ActivityDisplayComponent: React.FC<ActivityDisplayComponentProps> = ({tracker, currentUser, userRoles}) => {
61+
const ActivityDisplayComponent: React.FC<ActivityDisplayComponentProps> = ({tracker, currentUser, userRoles, app, chatPanel}) => {
4862

4963
const [showBarGraph, setShowBarGraph] = React.useState(true);
5064

5165
const switchGraph = () => {setShowBarGraph(prev => !prev)};
5266

5367
const barGraph = ActivityBarGraph({tracker});
54-
const dotPlot = ActivityDotPlot({tracker});
68+
const dotPlot = ActivityDotPlot({tracker, app, chatPanel});
5569

5670
return <div>
5771
{userRoles.get(currentUser.identity!.username) === Role.Owner && (

packages/collaboration/src/activitydotplot.tsx

+31-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,22 @@
11
import { Notebook, NotebookPanel } from '@jupyterlab/notebook';
2+
import { JupyterFrontEnd } from '@jupyterlab/application';
23

34
import * as React from 'react';
45
import Plot from 'react-plotly.js';
56

67
import { GraphProps } from './activitydisplay';
78
import { SimpleUser } from './cellTracker';
9+
import { SidePanel } from '@jupyterlab/ui-components';
10+
import { Chatbox } from './chatbox';
811

9-
export const ActivityDotPlot: React.FC<GraphProps> = ({tracker}) => {
12+
interface DotPlotProps extends GraphProps {
13+
14+
app: JupyterFrontEnd;
15+
chatPanel: SidePanel
16+
17+
}
18+
19+
export const ActivityDotPlot: React.FC<DotPlotProps> = ({tracker, app, chatPanel}) => {
1020

1121
const [state, setState] = React.useState<SimpleUser[][]>([]);
1222

@@ -102,6 +112,25 @@ export const ActivityDotPlot: React.FC<GraphProps> = ({tracker}) => {
102112
}
103113
};
104114

105-
return <Plot className='jp-graph' data={data} layout={layout}/>
115+
const handleDotClick = (data: any) => {
116+
117+
app.shell.activateById('jp-chat-panel');
118+
119+
const chatbox = chatPanel.widgets.find(widget => widget.id === 'jp-chatbox') as Chatbox | null;
120+
121+
if (chatbox) {
122+
123+
chatbox.show();
124+
chatbox.focusOnWritingField();
125+
126+
}
127+
128+
const polls = chatPanel.widgets.find(widget => widget.id === 'jp-polls');
129+
130+
if (polls) polls.hide();
131+
132+
}
133+
134+
return <Plot className='jp-graph' data={data} layout={layout} onClick={handleDotClick}/>
106135

107136
}

packages/collaboration/src/chatbox.tsx

+15-8
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,35 @@ import { User } from '@jupyterlab/services';
66
import { WebSocketAwarenessProvider, IChatMessage } from '@jupyter/docprovider';
77

88
import * as msgEnc from './messageEncoding';
9-
import { Roles } from './roles';
109

1110
export class Chatbox extends ReactWidget {
1211

1312
private _currentUser: User.IManager;
1413
private _awarenessProvider: WebSocketAwarenessProvider;
15-
private _roles: Roles;
1614

17-
constructor(currentUser: User.IManager, awarenessProvider: WebSocketAwarenessProvider, roles: Roles) {
15+
constructor(currentUser: User.IManager, awarenessProvider: WebSocketAwarenessProvider) {
1816
super();
1917

2018
this._currentUser = currentUser;
2119
this._awarenessProvider = awarenessProvider;
22-
this._roles = roles;
2320

2421
this.addClass('jp-Chat-Panel')
2522
}
2623

24+
focusOnWritingField() {
25+
26+
const writingField = this.node?.querySelector('.jp-Chat-WritableField') as HTMLTextAreaElement | null;
27+
28+
if (writingField) {
29+
30+
writingField.focus();
31+
32+
}
33+
34+
}
35+
2736
render(): JSX.Element {
28-
return <ChatBoxComponent currentUser={this._currentUser} awarenessProvider={this._awarenessProvider} userRoles={this._roles}/>;
37+
return <ChatBoxComponent currentUser={this._currentUser} awarenessProvider={this._awarenessProvider}/>;
2938
}
3039

3140
}
@@ -34,7 +43,6 @@ interface ChatBoxComponentProps {
3443

3544
currentUser: User.IManager;
3645
awarenessProvider: WebSocketAwarenessProvider;
37-
userRoles: Roles
3846

3947
}
4048

@@ -48,11 +56,10 @@ interface ChatBoxComponentState {
4856

4957
}
5058

51-
const ChatBoxComponent: React.FC<ChatBoxComponentProps> = ({currentUser, awarenessProvider, userRoles}) => {
59+
const ChatBoxComponent: React.FC<ChatBoxComponentProps> = ({currentUser, awarenessProvider}) => {
5260

5361
const user = currentUser;
5462
const aProvider = awarenessProvider;
55-
// const roles = userRoles;
5663

5764
// Getter and setter for the chat state
5865
const [state, setState] = React.useState<ChatBoxComponentState>({message: '', messages: []});

0 commit comments

Comments
 (0)