7
7
import { useState , useEffect } from 'react' ;
8
8
import { createPortal } from 'react-dom' ;
9
9
import { Box } from '@primer/react' ;
10
+ import { CommandRegistry } from '@lumino/commands' ;
11
+ import { URLExt } from '@jupyterlab/coreutils' ;
10
12
import { Cell , ICellModel } from '@jupyterlab/cells' ;
11
13
import { NotebookPanel , INotebookModel } from '@jupyterlab/notebook' ;
12
- import { CommandRegistry } from '@lumino/commands' ;
13
14
import { DocumentRegistry } from '@jupyterlab/docregistry' ;
14
15
import { IRenderMime } from '@jupyterlab/rendermime-interfaces' ;
15
16
import { INotebookContent } from '@jupyterlab/nbformat' ;
16
17
import { ServiceManager , Kernel as JupyterKernel } from '@jupyterlab/services' ;
17
- import { useJupyter , Lite , Kernel } from './../../jupyter' ;
18
+ import { WebsocketProvider as YWebsocketProvider } from 'y-websocket' ;
19
+ import { useJupyter , Lite , Kernel , requestDocSession , COLLABORATION_ROOM_URL_PATH } from './../../jupyter' ;
18
20
import { asObservable , Lumino } from '../lumino' ;
21
+ import { newUuid } from '../../utils' ;
22
+ import { OnSessionConnection , KernelTransfer } from '../../state' ;
19
23
import { CellMetadataEditor } from './cell/metadata' ;
20
24
import { ICellSidebarProps } from './cell/sidebar' ;
21
25
import { INotebookToolbarProps } from './toolbar/NotebookToolbar' ;
22
- import { newUuid } from '../../utils' ;
23
- import { OnSessionConnection , KernelTransfer } from '../../state' ;
24
26
import { useNotebookStore } from './NotebookState' ;
25
27
import { NotebookAdapter } from './NotebookAdapter' ;
26
28
@@ -50,6 +52,7 @@ export type INotebookProps = {
50
52
Toolbar ?: ( props : INotebookToolbarProps ) => JSX . Element ;
51
53
cellMetadataPanel : boolean ;
52
54
cellSidebarMargin : number ;
55
+ collaborative ?: boolean ;
53
56
extensions : DatalayerNotebookExtension [ ]
54
57
height ?: string ;
55
58
id : string ;
@@ -97,6 +100,7 @@ export const Notebook = (props: INotebookProps) => {
97
100
} ) ;
98
101
const {
99
102
Toolbar,
103
+ collaborative,
100
104
extensions,
101
105
height,
102
106
maxHeight,
@@ -114,7 +118,7 @@ export const Notebook = (props: INotebookProps) => {
114
118
const notebookStore = useNotebookStore ( ) ;
115
119
const portals = notebookStore . selectNotebookPortals ( id ) ;
116
120
// Bootstrap the Notebook Adapter.
117
- const bootstrapAdapter = ( serviceManager ?: ServiceManager . IManager , kernel ?: Kernel ) => {
121
+ const bootstrapAdapter = async ( collaborative : boolean , serviceManager ?: ServiceManager . IManager , kernel ?: Kernel ) => {
118
122
const adapter = new NotebookAdapter ( {
119
123
...props ,
120
124
id,
@@ -132,18 +136,35 @@ export const Notebook = (props: INotebookProps) => {
132
136
extension . createNew ( adapter . notebookPanel ! , adapter . context ! ) ;
133
137
setExtensionComponents ( extensionComponents . concat ( extension . component ?? < > </ > ) ) ;
134
138
} ) ;
135
- // Update the global state.
136
- notebookStore . update ( { id, state : { adapter } } ) ;
137
- // Update the global state based on events.
138
- adapter . notebookPanel ?. model ?. contentChanged . connect ( ( notebookModel , _ ) => {
139
- notebookStore . changeModel ( { id, notebookModel } )
140
- } ) ;
139
+ if ( collaborative ) {
140
+ // Setup Collaboration.
141
+ const ydoc = ( adapter . notebookPanel ?. model ?. sharedModel as any ) . ydoc ;
142
+ const session = await requestDocSession ( "json" , "notebook" , path ! ) ;
143
+ const yWebsocketProvider = new YWebsocketProvider (
144
+ URLExt . join ( serviceManager ?. serverSettings . wsUrl ! , COLLABORATION_ROOM_URL_PATH ) ,
145
+ `${ session . format } :${ session . type } :${ session . fileId } ` ,
146
+ ydoc ,
147
+ {
148
+ disableBc : true ,
149
+ params : { sessionId : session . sessionId } ,
150
+ // awareness: this._awareness
151
+ }
152
+ ) ;
153
+ console . log ( 'Collaboration is setup with websocket provider.' , yWebsocketProvider ) ;
154
+ // Update the notebook state with the adapter.
155
+ notebookStore . update ( { id, state : { adapter } } ) ;
156
+ // Update the notebook state further to events.
157
+ adapter . notebookPanel ?. model ?. contentChanged . connect ( ( notebookModel , _ ) => {
158
+ notebookStore . changeModel ( { id, notebookModel } ) ;
159
+ } ) ;
160
+ }
141
161
/*
142
- adapter.notebookPanel?.model! .sharedModel.changed.connect((_, notebookChange) => {
143
- notebookStore.notebookChange ({ id, notebookChange });
162
+ adapter.notebookPanel?.model? .sharedModel.changed.connect((_, notebookChange) => {
163
+ notebookStore.changeNotebook ({ id, notebookChange });
144
164
});
165
+ /*
145
166
adapter.notebookPanel?.content.modelChanged.connect((notebook, _) => {
146
- dispatÅch( notebookStore.notebookChange ({ id, notebook }) );
167
+ notebookStore.changeModel ({ id, notebookModel: notebook.model! } );
147
168
});
148
169
*/
149
170
adapter . notebookPanel ?. content . activeCellChanged . connect ( ( _ , cellModel ) => {
@@ -185,12 +206,12 @@ export const Notebook = (props: INotebookProps) => {
185
206
} ) ;
186
207
}
187
208
//
188
- const createAdapter = ( serviceManager ?: ServiceManager . IManager , kernel ?: Kernel ) => {
209
+ const createAdapter = ( collaborative : boolean , serviceManager ?: ServiceManager . IManager , kernel ?: Kernel ) => {
189
210
if ( ! kernel ) {
190
- bootstrapAdapter ( serviceManager , kernel ) ;
211
+ bootstrapAdapter ( collaborative , serviceManager , kernel ) ;
191
212
} else {
192
213
kernel . ready . then ( ( ) => {
193
- bootstrapAdapter ( serviceManager , kernel ) ;
214
+ bootstrapAdapter ( collaborative , serviceManager , kernel ) ;
194
215
} ) ;
195
216
}
196
217
}
@@ -206,12 +227,12 @@ export const Notebook = (props: INotebookProps) => {
206
227
// Mutation Effects.
207
228
useEffect ( ( ) => {
208
229
if ( serviceManager && serverless ) {
209
- createAdapter ( serviceManager , kernel ) ;
230
+ createAdapter ( collaborative ?? false , serviceManager , kernel ) ;
210
231
}
211
232
else if ( serviceManager && kernel ) {
212
- createAdapter ( serviceManager , kernel ) ;
233
+ createAdapter ( collaborative ?? false , serviceManager , kernel ) ;
213
234
}
214
- } , [ serviceManager , kernel ] ) ;
235
+ } , [ collaborative , serviceManager , kernel ] ) ;
215
236
useEffect ( ( ) => {
216
237
if ( adapter && adapter . kernel !== kernel ) {
217
238
adapter . setKernel ( kernel ) ;
@@ -235,15 +256,15 @@ export const Notebook = (props: INotebookProps) => {
235
256
useEffect ( ( ) => {
236
257
if ( adapter && path && adapter . path !== path ) {
237
258
disposeAdapter ( ) ;
238
- createAdapter ( serviceManager ) ;
259
+ createAdapter ( collaborative ?? false , serviceManager ) ;
239
260
}
240
261
} , [ path ] ) ;
241
262
useEffect ( ( ) => {
242
263
if ( adapter && url && adapter . url !== url ) {
243
264
disposeAdapter ( ) ;
244
- createAdapter ( serviceManager ) ;
265
+ createAdapter ( collaborative ?? false , serviceManager ) ;
245
266
}
246
- } , [ url ] ) ;
267
+ } , [ collaborative , url ] ) ;
247
268
// Dispose Effects.
248
269
useEffect ( ( ) => {
249
270
return ( ) => {
@@ -339,6 +360,7 @@ export const Notebook = (props: INotebookProps) => {
339
360
Notebook . defaultProps = {
340
361
cellMetadataPanel : false ,
341
362
cellSidebarMargin : 120 ,
363
+ collaborative : false ,
342
364
extensions : [ ] ,
343
365
height : '100vh' ,
344
366
kernelClients : [ ] ,
0 commit comments