Skip to content

Commit 350de83

Browse files
committed
Only display activity if owner + owner warning dialog
1 parent e792424 commit 350de83

File tree

7 files changed

+82
-96
lines changed

7 files changed

+82
-96
lines changed

packages/collaboration-extension/src/collaboration.ts

+3-37
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import { IAwareness } from '@jupyter/ydoc';
2727

2828
import {
2929
ActivityDisplay,
30-
addDisplay,
3130
Chatbox,
3231
CollaboratorsPanel,
3332
IGlobalAwareness,
@@ -161,7 +160,7 @@ export const rtcPanelPlugin: JupyterFrontEndPlugin<void> = {
161160
userPanel.addClass('jp-RTCPanel');
162161
app.shell.add(userPanel, 'left', { rank: 300 });
163162

164-
const roles = new Roles(user, awareness, awarenessProvider);
163+
const roles = new Roles(user, awareness, awarenessProvider, translator);
165164

166165
const currentUserPanel = new UserInfoPanel(user, roles);
167166
currentUserPanel.title.label = trans.__('User info');
@@ -181,11 +180,10 @@ export const rtcPanelPlugin: JupyterFrontEndPlugin<void> = {
181180
collaboratorsPanel.title.label = trans.__('Online Collaborators');
182181
userPanel.addWidget(collaboratorsPanel);
183182

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

188-
189187
const chatPanel = new SidePanel({
190188
alignment: 'justify'
191189
});
@@ -204,6 +202,7 @@ export const rtcPanelPlugin: JupyterFrontEndPlugin<void> = {
204202

205203
pollTab.title.label = trans.__('Polls');
206204
chatPanel.addWidget(pollTab);
205+
207206
}
208207
};
209208

@@ -255,37 +254,4 @@ export const cellTracker: JupyterFrontEndPlugin<void> = {
255254

256255
}
257256

258-
}
259-
260-
export const activeUsersDisplay: JupyterFrontEndPlugin<void> = {
261-
262-
id: '@jupyter/collaboration-extension:activeUsersDisplay',
263-
description:
264-
'Display how many users are working on each cell',
265-
autoStart: true,
266-
requires: [INotebookTracker],
267-
activate: (
268-
app: JupyterFrontEnd,
269-
tracker: INotebookTracker
270-
): void => {
271-
272-
tracker.widgetAdded.connect((sender, notebookPanel) => {
273-
const notebook = notebookPanel.content;
274-
275-
notebook.model?.cells.changed.connect(() => {
276-
277-
notebook.widgets.forEach(cell => {
278-
addDisplay(cell);
279-
280-
cell.model.metadataChanged.connect(() => {
281-
addDisplay(cell);
282-
})
283-
});
284-
285-
});
286-
287-
notebook.widgets.forEach(cell => addDisplay(cell));
288-
289-
});
290-
}
291257
}

packages/collaboration-extension/src/index.ts

+2-4
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ import {
2020
rtcGlobalAwarenessPlugin,
2121
rtcPanelPlugin,
2222
userEditorCursors,
23-
cellTracker,
24-
activeUsersDisplay
23+
cellTracker
2524
} from './collaboration';
2625
import { sharedLink } from './sharedlink';
2726

@@ -40,8 +39,7 @@ const plugins: JupyterFrontEndPlugin<any>[] = [
4039
rtcPanelPlugin,
4140
sharedLink,
4241
userEditorCursors,
43-
cellTracker,
44-
activeUsersDisplay
42+
cellTracker
4543
];
4644

4745
export default plugins;

packages/collaboration/src/activeusersdisplay.ts

-42
This file was deleted.

packages/collaboration/src/activitydisplay.tsx

+41-8
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,31 @@
1-
import * as React from 'react';
21
import { ReactWidget } from '@jupyterlab/apputils';
32
import { INotebookTracker, Notebook, NotebookPanel } from '@jupyterlab/notebook';
3+
import { User } from '@jupyterlab/services';
4+
5+
import * as React from 'react';
46
import Plot from 'react-plotly.js';
57

8+
import { Roles, Role } from './roles';
9+
10+
611
export class ActivityDisplay extends ReactWidget {
712

813
private _tracker: INotebookTracker
14+
private _currentUser: User.IManager;
15+
private _roles: Roles;
916

10-
constructor(tracker: INotebookTracker) {
17+
constructor(tracker: INotebookTracker, currentUser: User.IManager, roles: Roles) {
1118

1219
super();
1320

1421
this._tracker = tracker;
22+
this._currentUser = currentUser;
23+
this._roles = roles;
1524

1625
}
1726

1827
render() {
19-
return <ActivityDisplayComponent tracker={this._tracker}/>
28+
return <ActivityDisplayComponent tracker={this._tracker} currentUser={this._currentUser} userRoles={this._roles}/>
2029
}
2130

2231
}
@@ -25,10 +34,15 @@ export class ActivityDisplay extends ReactWidget {
2534
interface ActivityDisplayComponentProps {
2635

2736
tracker: INotebookTracker;
37+
currentUser: User.IManager;
38+
userRoles: Roles
2839

2940
}
3041

31-
const ActivityDisplayComponent: React.FC<ActivityDisplayComponentProps> = ({tracker}) => {
42+
const ActivityDisplayComponent: React.FC<ActivityDisplayComponentProps> = ({tracker, currentUser, userRoles}) => {
43+
44+
const user = currentUser;
45+
const roles = userRoles;
3246

3347
const [state, setState] = React.useState<number[]>([]);
3448

@@ -75,16 +89,35 @@ const ActivityDisplayComponent: React.FC<ActivityDisplayComponentProps> = ({trac
7589
x: state,
7690
type: 'bar',
7791
orientation: 'h',
78-
marker: {color: 'green'}
92+
marker: {color: 'green'},
93+
hovertemplate: '%{x} user(s) on cell %{y}'
7994
}] as Plotly.Data[];
8095

8196
const layout = {
8297
width: 300,
8398
height: 500,
84-
xaxis: {title: 'Active users'},
85-
yaxis: {title: 'Cell', autorange: 'reversed' as const}
99+
xaxis: {
100+
title: 'Active users'
101+
},
102+
yaxis: {
103+
title: 'Cell',
104+
autorange: 'reversed' as const
105+
},
106+
margin: {
107+
l: 60,
108+
r: 30,
109+
t: 30,
110+
b: 60
111+
},
112+
hoverlabel: {
113+
namelength: 0
114+
}
86115
};
87116

88-
return <Plot className='jp-graph' data={data} layout={layout}/>
117+
return <div>
118+
{roles.get(user.identity!.username) === Role.Owner && (
119+
<Plot className='jp-graph' data={data} layout={layout}/>
120+
)}
121+
</div>
89122

90123
}

packages/collaboration/src/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ export * from './messageEncoding';
1616
export * from './polls';
1717
export * from './roles';
1818
export * from './cellTracker';
19-
export * from './activeusersdisplay';
20-
export * from './activitydisplay';
19+
export * from './activitydisplay';
20+
export * from './ownerdialog';
+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { Dialog, showDialog } from '@jupyterlab/apputils';
2+
import { ITranslator, nullTranslator } from '@jupyterlab/translation';
3+
4+
export async function showOwnerDialog(translator: ITranslator | null): Promise<Dialog.IResult<string>> {
5+
6+
const trans = (translator ?? nullTranslator).load('collaboration');
7+
8+
return showDialog({
9+
title: trans.__('Owner'),
10+
body: trans.__('You have been set as the session owner and have been granted extra privileges. Be aware that ' +
11+
'refreshing or closing the page may make you lose those privileges.'),
12+
buttons: [
13+
Dialog.okButton({label: trans.__('OK')})
14+
]
15+
});
16+
17+
}

packages/collaboration/src/roles.ts

+17-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1+
import { IChatMessage, WebSocketAwarenessProvider } from '@jupyter/docprovider';
12
import { User } from '@jupyterlab/services';
3+
import { ITranslator } from '@jupyterlab/translation';
4+
25
import { Awareness } from 'y-protocols/awareness';
36

4-
import { IChatMessage, WebSocketAwarenessProvider } from '@jupyter/docprovider';
5-
import { ICollaboratorAwareness } from './tokens';
67

8+
import { showOwnerDialog } from './ownerdialog';
9+
import { ICollaboratorAwareness } from './tokens';
710
import * as msgEnc from './messageEncoding';
11+
812
import * as time from 'lib0/time';
913

1014

@@ -26,12 +30,14 @@ export class Roles {
2630
private _aProvider: WebSocketAwarenessProvider;
2731
private _connectedAt: number;
2832
private _currentUser: User.IManager;
33+
private _translator: ITranslator | null;
2934

30-
constructor(currentUser: User.IManager, awareness: Awareness, aProvider: WebSocketAwarenessProvider) {
35+
constructor(currentUser: User.IManager, awareness: Awareness, aProvider: WebSocketAwarenessProvider, translator: ITranslator | null) {
3136
this._awareness = awareness;
3237
this._aProvider = aProvider;
3338
this._connectedAt = time.getUnixTime();
3439
this._currentUser = currentUser;
40+
this._translator = translator;
3541

3642
this._awareness.on('change', this._onAwarenessChanged);
3743

@@ -47,6 +53,14 @@ export class Roles {
4753
// Once connection is set, request other users' timestamps to check if one came before
4854
setTimeout(() => {this._aProvider.sendMessage('times')}, 500);
4955

56+
setTimeout(async () => {
57+
if (this._map.get(currentUser.identity!.username) === Role.Owner) {
58+
59+
await showOwnerDialog(this._translator);
60+
61+
}
62+
}, 1000);
63+
5064
}
5165

5266
// Handle collaborator change

0 commit comments

Comments
 (0)