Skip to content

Commit a15822f

Browse files
committed
Finalize merge
1 parent 772d681 commit a15822f

File tree

2 files changed

+89
-47
lines changed

2 files changed

+89
-47
lines changed

jupyter_collaboration/handlers.py

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212
from jupyter_server.auth import authorized
1313
from jupyter_server.base.handlers import APIHandler, JupyterHandler
1414
from jupyter_ydoc import ydocs as YDOCS
15-
from pycrdt import Doc
16-
from pycrdt_websocket.websocket_server import YRoom
15+
from pycrdt import Doc, Map
16+
from pycrdt_websocket.yroom import YRoom
1717
from pycrdt_websocket.ystore import BaseYStore
1818
from pycrdt_websocket.yutils import YMessageType, write_var_uint
1919
from tornado import web
@@ -409,7 +409,7 @@ async def put(self, room_id):
409409
update = root_room.ydoc.get_update()
410410
fork_ydoc = Doc()
411411
fork_ydoc.apply_update(update)
412-
fork_room = YRoom(fork_ydoc)
412+
fork_room = YRoom(ydoc=fork_ydoc)
413413
self._websocket_server.add_room(idx, fork_room)
414414
root_room.fork_ydocs.add(fork_ydoc)
415415
data = json.dumps({
@@ -440,8 +440,21 @@ async def put(self):
440440
Merges back a fork into a root document.
441441
"""
442442
model = self.get_json_body()
443-
fork_room = await self._websocket_server.get_room(model["fork_roomid"])
443+
fork_roomid = model["fork_roomid"]
444444
root_room = await self._websocket_server.get_room(model["root_roomid"])
445-
update = fork_room.ydoc.get_update()
446-
root_room.ydoc.apply_update(update)
445+
root_ydoc = root_room.ydoc
446+
idx = f"fork_{fork_roomid}"
447+
root_state = root_ydoc.get("state", type=Map)
448+
if idx in root_state:
449+
del root_state[idx]
450+
else:
451+
raise RuntimeError(f"Could not find root document fork with ID: {fork_roomid}")
452+
fork_room = await self._websocket_server.get_room(fork_roomid)
453+
fork_ydoc = fork_room.ydoc
454+
update = fork_ydoc.get_update()
455+
root_ydoc.apply_update(update)
456+
root_room.fork_ydocs.remove(fork_ydoc)
457+
fork_state = fork_ydoc.get("state", type=Map)
458+
fork_state["merge"] = fork_roomid
459+
#self._websocket_server.delete_room(name=fork_roomid)
447460
self.set_status(200)

packages/collaboration-extension/src/collaboration.ts

Lines changed: 70 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,7 @@ export class EditingModeExtension implements DocumentRegistry.IWidgetExtension<N
248248
const reviewMenu = new Menu({ commands: reviewCommands });
249249

250250
const sharedModel = context.model.sharedModel;
251+
const suggestions: {[key: string]: Menu.IItem} = {};
251252
var myForkId = ''; // curently allows only one suggestion per user
252253

253254
editingMenu.title.label = 'Editing';
@@ -321,49 +322,77 @@ export class EditingModeExtension implements DocumentRegistry.IWidgetExtension<N
321322
if (changes.stateChange) {
322323
changes.stateChange.forEach(value => {
323324
const forkPrefix = 'fork_';
324-
if (value.name.startsWith(forkPrefix)) {
325-
const newForkId = value.name.slice(forkPrefix.length);
326-
suggestionCommands.addCommand(newForkId, {
327-
label: newForkId,
328-
execute: () => {
329-
if (myForkId === newForkId) {
330-
editingMenu.title.label = 'Suggesting';
331-
// our suggestion, cannot be reviewed
332-
reviewMenu.clearItems();
333-
}
334-
else {
335-
editingMenu.title.label = 'Editing';
336-
// not our suggestion, can be reviewed
337-
reviewMenu.clearItems();
338-
reviewMenu.addItem({type: 'command', command: 'merge'});
339-
reviewMenu.addItem({type: 'command', command: 'discard'});
340-
}
341-
suggestionMenu.title.label = newForkId;
342-
sharedModel.provider.connectFork(newForkId);
343-
open_dialog('Suggesting', this._trans);
344-
}
345-
});
346-
suggestionMenu.addItem({type: 'command', command: newForkId});
347-
if ((myForkId !== 'pending') && (myForkId !== newForkId)) {
348-
const dialog = new Dialog({
349-
title: this._trans.__('New suggestion'),
350-
body: this._trans.__('View suggestion?'),
351-
buttons: [
352-
Dialog.okButton({ label: 'View' }),
353-
Dialog.cancelButton({ label: 'Discard' }),
354-
],
355-
});
356-
dialog.launch().then(resp => {
357-
dialog.close();
358-
if (resp.button.label === 'View') {
359-
sharedModel.provider.connectFork(newForkId);
360-
suggestionMenu.title.label = newForkId;
361-
editingMenu.title.label = 'Editing';
362-
reviewMenu.clearItems();
363-
reviewMenu.addItem({type: 'command', command: 'merge'});
364-
reviewMenu.addItem({type: 'command', command: 'discard'});
325+
if (value.name === 'merge') {
326+
// FIXME: a client who is not connected to the fork should not see this update
327+
if (sharedModel.currentRoomId === value.newValue) {
328+
editingMenu.title.label = 'Editing';
329+
suggestionMenu.title.label = 'Root';
330+
const item: Menu.IItem = suggestions[value.newValue];
331+
delete suggestions[value.newValue];
332+
suggestionMenu.removeItem(item);
333+
reviewMenu.clearItems();
334+
sharedModel.provider.connectFork(sharedModel.rootRoomId);
335+
open_dialog('Editing', this._trans);
336+
}
337+
}
338+
else if (value.name.startsWith(forkPrefix)) {
339+
const forkId = value.name.slice(forkPrefix.length);
340+
if (value.newValue === 'new') {
341+
suggestionCommands.addCommand(forkId, {
342+
label: forkId,
343+
execute: () => {
344+
if (myForkId === forkId) {
345+
editingMenu.title.label = 'Suggesting';
346+
// our suggestion, cannot be reviewed
347+
reviewMenu.clearItems();
348+
}
349+
else {
350+
editingMenu.title.label = 'Editing';
351+
// not our suggestion, can be reviewed
352+
reviewMenu.clearItems();
353+
reviewMenu.addItem({type: 'command', command: 'merge'});
354+
reviewMenu.addItem({type: 'command', command: 'discard'});
355+
}
356+
suggestionMenu.title.label = forkId;
357+
sharedModel.provider.connectFork(forkId);
358+
open_dialog('Suggesting', this._trans);
365359
}
366360
});
361+
const item = suggestionMenu.addItem({type: 'command', command: forkId});
362+
suggestions[forkId] = item;
363+
if ((myForkId !== 'pending') && (myForkId !== forkId)) {
364+
const dialog = new Dialog({
365+
title: this._trans.__('New suggestion'),
366+
body: this._trans.__('View suggestion?'),
367+
buttons: [
368+
Dialog.okButton({ label: 'View' }),
369+
Dialog.cancelButton({ label: 'Discard' }),
370+
],
371+
});
372+
dialog.launch().then(resp => {
373+
dialog.close();
374+
if (resp.button.label === 'View') {
375+
sharedModel.provider.connectFork(forkId);
376+
suggestionMenu.title.label = forkId;
377+
editingMenu.title.label = 'Editing';
378+
reviewMenu.clearItems();
379+
reviewMenu.addItem({type: 'command', command: 'merge'});
380+
reviewMenu.addItem({type: 'command', command: 'discard'});
381+
}
382+
});
383+
}
384+
}
385+
else if (value.newValue === undefined) {
386+
if (sharedModel.currentRoomId === forkId) {
387+
editingMenu.title.label = 'Editing';
388+
suggestionMenu.title.label = 'Root';
389+
const item: Menu.IItem = suggestions[value.newValue];
390+
delete suggestions[value.newValue];
391+
suggestionMenu.removeItem(item);
392+
reviewMenu.clearItems();
393+
sharedModel.provider.connectFork(sharedModel.rootRoomId);
394+
open_dialog('Editing', this._trans);
395+
}
367396
}
368397
}
369398
});

0 commit comments

Comments
 (0)