Skip to content

Commit e821eb6

Browse files
authored
Add user info to awareness (#355)
Add peer cursors cm extension Co-authored-by: Frédéric Collonval <[email protected]>
1 parent b277dbe commit e821eb6

File tree

3 files changed

+54
-24
lines changed

3 files changed

+54
-24
lines changed

packages/react/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
"@jupyter-widgets/html-manager": "^1.0.0",
7070
"@jupyter-widgets/jupyterlab-manager": "^5.0.0",
7171
"@jupyter-widgets/output": "^6.0.0",
72+
"@jupyter/collaboration": "^3.1.0",
7273
"@jupyter/web-components": "^0.15.3",
7374
"@jupyter/ydoc": "3.0.2",
7475
"@jupyterlab/application": "^4.0.0",

packages/react/src/components/notebook/BaseNotebook.tsx

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* MIT License
55
*/
66

7-
import { ISharedNotebook, IYText, YNotebook } from '@jupyter/ydoc';
7+
import { type ISharedNotebook, type IYText, YNotebook } from '@jupyter/ydoc';
88
import type { ISessionContext } from '@jupyterlab/apputils';
99
import type { Cell, CodeCell, ICellModel } from '@jupyterlab/cells';
1010
import { type IEditorServices } from '@jupyterlab/codeeditor';
@@ -78,6 +78,7 @@ import { Lumino } from '../lumino';
7878
import { Loader } from '../utils';
7979
import type { DatalayerNotebookExtension } from './Notebook';
8080
import addNotebookCommands from './NotebookCommands';
81+
import { remoteUserCursors } from '@jupyter/collaboration';
8182

8283
const COMPLETER_TIMEOUT_MILLISECONDS = 1000;
8384
const DEFAULT_EXTENSIONS = new Array<DatalayerNotebookExtension>();
@@ -891,30 +892,36 @@ class CommonFeatures {
891892
themes.addTheme(theme);
892893
}
893894

894-
const editorExtensions = () => {
895-
const registry = new EditorExtensionRegistry();
896-
for (const extensionFactory of EditorExtensionRegistry.getDefaultExtensions(
897-
{ themes }
898-
)) {
899-
registry.addExtension(extensionFactory);
895+
const editorExtensions = new EditorExtensionRegistry();
896+
for (const extensionFactory of EditorExtensionRegistry.getDefaultExtensions(
897+
{ themes }
898+
)) {
899+
editorExtensions.addExtension(extensionFactory);
900+
}
901+
editorExtensions.addExtension({
902+
name: 'shared-model-binding',
903+
factory: options => {
904+
const sharedModel = options.model.sharedModel as IYText;
905+
return EditorExtensionRegistry.createImmutableExtension(
906+
ybinding({
907+
ytext: sharedModel.ysource,
908+
undoManager: sharedModel.undoManager ?? undefined,
909+
})
910+
);
911+
},
912+
});
913+
editorExtensions.addExtension({
914+
name: 'remote-user-cursors',
915+
factory(options) {
916+
const { awareness, ysource: ytext } = options.model.sharedModel as any;
917+
return EditorExtensionRegistry.createImmutableExtension(
918+
remoteUserCursors({ awareness, ytext })
919+
);
900920
}
901-
registry.addExtension({
902-
name: 'shared-model-binding',
903-
factory: options => {
904-
const sharedModel = options.model.sharedModel as IYText;
905-
return EditorExtensionRegistry.createImmutableExtension(
906-
ybinding({
907-
ytext: sharedModel.ysource,
908-
undoManager: sharedModel.undoManager ?? undefined,
909-
})
910-
);
911-
},
912-
});
913-
return registry;
914-
};
921+
})
915922

916923
const factoryService = new CodeMirrorEditorFactory({
917-
extensions: editorExtensions(),
924+
extensions: editorExtensions,
918925
languages: languages,
919926
});
920927
this._editorServices = {

packages/react/src/components/notebook/SimpleNotebook.tsx

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export interface ISimpleNotebookProps {
3131
/**
3232
* Collaboration server providing the document rooms.
3333
*/
34-
collaborationServer: CollaborationServer;
34+
collaborationServer?: CollaborationServer;
3535
/**
3636
* Custom command registry.
3737
*
@@ -154,11 +154,33 @@ export function SimpleNotebook(
154154
});
155155

156156
useEffect(() => {
157-
if (model) setIsLoading(false);
157+
if (model) {
158+
setIsLoading(false);
159+
}
158160

159161
onNotebookModelChanged?.(model);
160162
}, [model, onNotebookModelChanged]);
161163

164+
useEffect(() => {
165+
// Set user identity if collaborating using Jupyter collaboration
166+
const setUserIdentity = () => {
167+
if (collaborationServer?.type === 'jupyter' && model) {
168+
// Yjs details are hidden from the interface
169+
(model.sharedModel as any).awareness.setLocalStateField(
170+
'user',
171+
serviceManager.user.identity
172+
);
173+
}
174+
};
175+
176+
setUserIdentity();
177+
serviceManager.user.userChanged.connect(setUserIdentity);
178+
179+
return () => {
180+
serviceManager.user.userChanged.disconnect(setUserIdentity);
181+
};
182+
}, [collaborationServer, model, serviceManager]);
183+
162184
return isLoading ? (
163185
<Loader key="notebook-loader" />
164186
) : (

0 commit comments

Comments
 (0)