Skip to content

Commit

Permalink
Register RTC content provider
Browse files Browse the repository at this point in the history
  • Loading branch information
davidbrochart committed Sep 5, 2024
1 parent 1492678 commit 561a377
Show file tree
Hide file tree
Showing 4 changed files with 143 additions and 227 deletions.
219 changes: 20 additions & 199 deletions packages/docprovider-extension/src/filebrowser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,104 +3,57 @@
* Distributed under the terms of the Modified BSD License.
*/

import { Drive } from '@jupyterlab/services';
import {
ILabShell,
IRouter,
JupyterFrontEnd,
JupyterFrontEndPlugin
} from '@jupyterlab/application';
import { Dialog, showDialog } from '@jupyterlab/apputils';
import { DocumentWidget, IDocumentWidget } from '@jupyterlab/docregistry';
import { Widget } from '@lumino/widgets';
import {
FileBrowser,
IDefaultFileBrowser,
IFileBrowserFactory
} from '@jupyterlab/filebrowser';
import { IStatusBar } from '@jupyterlab/statusbar';

import { IEditorTracker } from '@jupyterlab/fileeditor';
import { ILogger, ILoggerRegistry } from '@jupyterlab/logconsole';
import { INotebookTracker } from '@jupyterlab/notebook';
import { ISettingRegistry } from '@jupyterlab/settingregistry';
import { ITranslator, nullTranslator } from '@jupyterlab/translation';

import { CommandRegistry } from '@lumino/commands';

import { YFile, YNotebook } from '@jupyter/ydoc';

import {
ICollaborativeDrive,
IForkProvider,
IGlobalAwareness,
TimelineWidget,
YDrive
RtcContentProvider
} from '@jupyter/docprovider';
import { Awareness } from 'y-protocols/awareness';
import { URLExt } from '@jupyterlab/coreutils';

/**
* The command IDs used by the file browser plugin.
* The RTC content provider.
*/
namespace CommandIDs {
export const openPath = 'filebrowser:open-path';
}
const DOCUMENT_TIMELINE_URL = 'api/collaboration/timeline';

/**
* The default collaborative drive provider.
*/
export const drive: JupyterFrontEndPlugin<ICollaborativeDrive> = {
id: '@jupyter/docprovider-extension:drive',
description: 'The default collaborative drive provider',
provides: ICollaborativeDrive,
export const rtcContentProvider: JupyterFrontEndPlugin<void> = {
id: '@jupyter/docprovider-extension:content',
description: 'The RTC content provider',
autoStart: true,
requires: [ITranslator],
optional: [IGlobalAwareness],
optional: [IGlobalAwareness, ISettingRegistry],
activate: (
app: JupyterFrontEnd,
translator: ITranslator,
globalAwareness: Awareness | null
): ICollaborativeDrive => {
globalAwareness: Awareness | null,
settingRegistry: ISettingRegistry | null
): void => {
const trans = translator.load('jupyter_collaboration');
const drive = new YDrive(app.serviceManager.user, trans, globalAwareness);
app.serviceManager.contents.addDrive(drive);
return drive;
}
};
const rtcContentProvider = new RtcContentProvider(app.serviceManager.user, trans, globalAwareness);

/**
* Plugin to register the shared model factory for the content type 'file'.
*/
export const yfile: JupyterFrontEndPlugin<void> = {
id: '@jupyter/docprovider-extension:yfile',
description:
"Plugin to register the shared model factory for the content type 'file'",
autoStart: true,
requires: [ICollaborativeDrive],
optional: [],
activate: (app: JupyterFrontEnd, drive: ICollaborativeDrive): void => {
const yFileFactory = () => {
return new YFile();
};
drive.sharedModelFactory.registerDocumentFactory('file', yFileFactory);
}
};
rtcContentProvider.sharedModelFactory.registerDocumentFactory('file', yFileFactory);

/**
* Plugin to register the shared model factory for the content type 'notebook'.
*/
export const ynotebook: JupyterFrontEndPlugin<void> = {
id: '@jupyter/docprovider-extension:ynotebook',
description:
"Plugin to register the shared model factory for the content type 'notebook'",
autoStart: true,
requires: [ICollaborativeDrive],
optional: [ISettingRegistry],
activate: (
app: JupyterFrontEnd,
drive: YDrive,
settingRegistry: ISettingRegistry | null
): void => {
let disableDocumentWideUndoRedo = true;

// Fetch settings if possible.
Expand Down Expand Up @@ -128,63 +81,31 @@ export const ynotebook: JupyterFrontEndPlugin<void> = {
disableDocumentWideUndoRedo
});
};
drive.sharedModelFactory.registerDocumentFactory(
rtcContentProvider.sharedModelFactory.registerDocumentFactory(
'notebook',
yNotebookFactory
);

Drive.getContentProviderRegistry().register(rtcContentProvider);
}
};

/**
* A plugin to add a timeline slider status item to the status bar.
*/
export const statusBarTimeline: JupyterFrontEndPlugin<void> = {
id: '@jupyter/docprovider-extension:statusBarTimeline',
description: 'Plugin to add a timeline slider to the status bar',
autoStart: true,
requires: [IStatusBar, ICollaborativeDrive],
requires: [IStatusBar],
activate: async (
app: JupyterFrontEnd,
statusBar: IStatusBar,
drive: ICollaborativeDrive
statusBar: IStatusBar
): Promise<void> => {
function isYDrive(drive: YDrive | ICollaborativeDrive): drive is YDrive {
return 'getProviderForPath' in drive;
}
try {
let sliderItem: Widget | null = null;
let timelineWidget: TimelineWidget | null = null;

const updateTimelineForDocument = async (documentPath: string) => {
if (drive && isYDrive(drive)) {
// Dispose of the previous timelineWidget if it exists
if (timelineWidget) {
timelineWidget.dispose();
timelineWidget = null;
}

const provider = (await drive.getProviderForPath(
documentPath
)) as IForkProvider;
const fullPath = URLExt.join(
app.serviceManager.serverSettings.baseUrl,
DOCUMENT_TIMELINE_URL,
documentPath.split(':')[1]
);

timelineWidget = new TimelineWidget(
fullPath,
provider,
provider.contentType,
provider.format
);

const elt = document.getElementById('jp-slider-status-bar');
if (elt && !timelineWidget.isAttached) {
Widget.attach(timelineWidget, elt);
}
}
};

if (app.shell.currentChanged) {
app.shell.currentChanged.connect(async (_, args) => {
const currentWidget = args.newValue as DocumentWidget;
Expand All @@ -194,7 +115,7 @@ export const statusBarTimeline: JupyterFrontEndPlugin<void> = {
timelineWidget = null;
}
if (currentWidget && 'context' in currentWidget) {
await updateTimelineForDocument(currentWidget.context.path);
// FIXME
}
});
}
Expand Down Expand Up @@ -222,50 +143,6 @@ export const statusBarTimeline: JupyterFrontEndPlugin<void> = {
}
};

/**
* The default file browser factory provider.
*/
export const defaultFileBrowser: JupyterFrontEndPlugin<IDefaultFileBrowser> = {
id: '@jupyter/docprovider-extension:defaultFileBrowser',
description: 'The default file browser factory provider',
provides: IDefaultFileBrowser,
requires: [ICollaborativeDrive, IFileBrowserFactory],
optional: [
IRouter,
JupyterFrontEnd.ITreeResolver,
ILabShell,
ISettingRegistry
],
activate: async (
app: JupyterFrontEnd,
drive: YDrive,
fileBrowserFactory: IFileBrowserFactory,
router: IRouter | null,
tree: JupyterFrontEnd.ITreeResolver | null,
labShell: ILabShell | null
): Promise<IDefaultFileBrowser> => {
const { commands } = app;

app.serviceManager.contents.addDrive(drive);

// Manually restore and load the default file browser.
const defaultBrowser = fileBrowserFactory.createFileBrowser('filebrowser', {
auto: false,
restore: false,
driveName: drive.name
});
void Private.restoreBrowser(
defaultBrowser,
commands,
router,
tree,
labShell
);

return defaultBrowser;
}
};

/**
* The default collaborative drive provider.
*/
Expand Down Expand Up @@ -359,59 +236,3 @@ export const logger: JupyterFrontEndPlugin<void> = {
})();
}
};

namespace Private {
/**
* Restores file browser state and overrides state if tree resolver resolves.
*/
export async function restoreBrowser(
browser: FileBrowser,
commands: CommandRegistry,
router: IRouter | null,
tree: JupyterFrontEnd.ITreeResolver | null,
labShell: ILabShell | null
): Promise<void> {
const restoring = 'jp-mod-restoring';

browser.addClass(restoring);

if (!router) {
await browser.model.restore(browser.id);
await browser.model.refresh();
browser.removeClass(restoring);
return;
}

const listener = async () => {
router.routed.disconnect(listener);

const paths = await tree?.paths;

if (paths?.file || paths?.browser) {
// Restore the model without populating it.
await browser.model.restore(browser.id, false);
if (paths.file) {
await commands.execute(CommandIDs.openPath, {
path: paths.file,
dontShowBrowser: true
});
}
if (paths.browser) {
await commands.execute(CommandIDs.openPath, {
path: paths.browser,
dontShowBrowser: true
});
}
} else {
await browser.model.restore(browser.id);
await browser.model.refresh();
}
browser.removeClass(restoring);

if (labShell?.isEmpty('main')) {
void commands.execute('launcher:create');
}
};
router.routed.connect(listener);
}
}
10 changes: 2 additions & 8 deletions packages/docprovider-extension/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,8 @@
import { JupyterFrontEndPlugin } from '@jupyterlab/application';

import {
drive,
yfile,
ynotebook,
defaultFileBrowser,
logger,
rtcContentProvider,
statusBarTimeline
} from './filebrowser';
import { notebookCellExecutor } from './executor';
Expand All @@ -21,10 +18,7 @@ import { notebookCellExecutor } from './executor';
* Export the plugins as default.
*/
const plugins: JupyterFrontEndPlugin<any>[] = [
drive,
yfile,
ynotebook,
defaultFileBrowser,
rtcContentProvider,
logger,
notebookCellExecutor,
statusBarTimeline
Expand Down
19 changes: 1 addition & 18 deletions packages/docprovider/src/tokens.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.

import { DocumentChange, IAwareness, YDocument } from '@jupyter/ydoc';
import { IAwareness } from '@jupyter/ydoc';
import { Contents } from '@jupyterlab/services';

import { Token } from '@lumino/coreutils';
Expand All @@ -23,13 +23,6 @@ export const IGlobalAwareness = new Token<IAwareness>(
'@jupyter/collaboration:IGlobalAwareness'
);

/**
* A document factory for registering shared models
*/
export type SharedDocumentFactory = (
options: Contents.ISharedFactoryOptions
) => YDocument<DocumentChange>;

/**
* A Collaborative implementation for an `IDrive`, talking to the
* server using the Jupyter REST API and a WebSocket connection.
Expand All @@ -45,16 +38,6 @@ export interface ICollaborativeDrive extends Contents.IDrive {
* Yjs sharedModel factory for real-time collaboration.
*/
export interface ISharedModelFactory extends Contents.ISharedFactory {
/**
* Register a SharedDocumentFactory.
*
* @param type Document type
* @param factory Document factory
*/
registerDocumentFactory(
type: Contents.ContentType,
factory: SharedDocumentFactory
): void;
}

/**
Expand Down
Loading

0 comments on commit 561a377

Please sign in to comment.