Skip to content

Commit 935448c

Browse files
committed
Moar migration
1 parent 8b48cb7 commit 935448c

21 files changed

+344
-89
lines changed

CLAUDE.md

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
# CLAUDE.md
22

3-
Jupyter React UI - React components and utilities for building Jupyter-based applications.
3+
Jupyter React UI - Generic React components and utilities for building Jupyter-based applications.
44

55
## Architecture
66

77
**IMPORTANT**: Dependency direction is `@datalayer/core` depends on `@datalayer/jupyter-react`.
88
- Core imports from jupyter-ui (NOT the other way around)
9-
- When migrating code, ensure jupyter-ui core is adapted so that it no longer depends on datalyer code.
9+
- When migrating code, ensure jupyter-ui core is adapted so that it no longer depends on datalayer code.
1010
- Backward compatibility does not need to be preserved when migrating things from `@datalayer/jupyter-react` to `@datalayer/core`
11+
- **Jupyter-ui is completely generic** - no Datalayer-specific functionality should remain
1112

1213
## Development Commands
1314

@@ -18,12 +19,40 @@ Jupyter React UI - React components and utilities for building Jupyter-based app
1819

1920
## Key Components
2021

21-
- Jupyter components: Cell, Console, Notebook, Terminal, Viewer
22-
- Service providers: ServiceManagerProvider, utility functions for creating ServiceManagers
23-
- State management: Zustand stores for component state
24-
- JupyterLab integration: Support for extensions and themes
22+
- **Jupyter components**: Cell, Console, Notebook, Terminal, Viewer (all generic)
23+
- **Service providers**: ServiceManagerProvider, ServiceManagerLess (generic implementations)
24+
- **State management**: JupyterReactState (generic Zustand store)
25+
- **Collaboration system**: Extensible plugin-based collaboration with built-in Jupyter provider
26+
- **JupyterLab integration**: Support for extensions and themes
27+
28+
## Collaboration System
29+
30+
**Plugin-based extensible architecture:**
31+
- `CollaborationProviderRegistry` - Global registry for collaboration providers
32+
- `ICollaborationProviderImpl` - Interface all providers must implement
33+
- `JupyterCollaborationProvider` - Built-in provider for Jupyter Lab/Server collaboration
34+
- Built-in providers auto-registered on import
35+
36+
**Usage:**
37+
```typescript
38+
// Use built-in Jupyter collaboration
39+
<Notebook collaborative="jupyter" ... />
40+
41+
// Extensions can register custom providers
42+
collaborationProviderRegistry.register('custom', new CustomProvider());
43+
<Notebook collaborative="custom" ... />
44+
```
2545

2646
## Migration Notes
2747

28-
When migrating functionality:
29-
1. Core should import what it needs from jupyter-ui
48+
**Completed Migration (v1.0.7):**
49+
1. ✅ Removed all Datalayer-specific configuration from JupyterConfig
50+
2. ✅ Made JupyterReactState completely generic (no datalayerConfig)
51+
3. ✅ Moved DatalayerCollaboration to core package
52+
4. ✅ Created extensible collaboration system with plugin pattern
53+
5. ✅ Removed hardcoded collaboration logic from Notebook component
54+
55+
**Extension Points:**
56+
- Core can extend JupyterReactState with DatalayerReactState
57+
- Core can register additional collaboration providers
58+
- Core can extend ServiceManagerLess with Datalayer-specific managers

packages/react/src/components/codemirror/CodeMirrorDatalayerEditor.tsx renamed to packages/react/src/components/codemirror/CodeMirrorEditor.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import useOutputsStore from '../output/OutputState';
1616
import codeMirrorTheme from './CodeMirrorTheme';
1717
import CodeMirrorOutputToolbar from './CodeMirrorOutputToolbar';
1818

19-
export const CodeMirrorDatalayerEditor = (props: {
19+
export const CodeMirrorEditor = (props: {
2020
code: string;
2121
codePre?: string;
2222
outputAdapter: OutputAdapter;
@@ -147,4 +147,4 @@ export const CodeMirrorDatalayerEditor = (props: {
147147
);
148148
};
149149

150-
export default CodeMirrorDatalayerEditor;
150+
export default CodeMirrorEditor;

packages/react/src/components/codemirror/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
* MIT License
55
*/
66

7-
export * from './CodeMirrorDatalayerEditor';
7+
export * from './CodeMirrorEditor';
88
export * from './CodeMirrorOutputToolbar';
99
export * from './CodeMirrorTheme';

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

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
import { YNotebook } from '@jupyter/ydoc';
88
import { Cell, ICellModel } from '@jupyterlab/cells';
9-
import { URLExt } from '@jupyterlab/coreutils';
109
import { createGlobalStyle } from 'styled-components';
1110
import { INotebookContent } from '@jupyterlab/nbformat';
1211
import { NotebookModel } from '@jupyterlab/notebook';
@@ -20,15 +19,17 @@ import { WebsocketProvider as YWebsocketProvider } from 'y-websocket';
2019
import { jupyterReactStore, KernelTransfer, OnSessionConnection, } from '../../state';
2120
import { newUuid, sleep } from '../../utils';
2221
import { asObservable, Lumino } from '../lumino';
23-
import { COLLABORATION_ROOM_URL_PATH, ICollaborationProvider, Kernel, Lite, requestJupyterCollaborationSession, useJupyter } from './../../jupyter';
22+
import { collaborationProviderRegistry, ICollaborationProvider, Kernel, Lite, useJupyter } from './../../jupyter';
23+
// Import to register built-in providers
24+
import './../../jupyter/collaboration/registerBuiltinProviders';
2425
import { CellMetadataEditor } from './cell/metadata';
2526
import { NotebookAdapter } from './NotebookAdapter';
2627
import { useNotebookStore } from './NotebookState';
2728
import { INotebookToolbarProps } from './toolbar';
2829
import { Loader } from '../utils';
2930

3031
import './Notebook.css';
31-
import { DatalayerNotebookExtension } from './NotebookExtensions';
32+
import { NotebookExtension } from './NotebookExtensions';
3233

3334
export type ExternalIPyWidgets = {
3435
name: string;
@@ -53,7 +54,7 @@ export type INotebookProps = {
5354
cellMetadataPanel?: boolean;
5455
cellSidebarMargin?: number;
5556
collaborative?: ICollaborationProvider;
56-
extensions?: DatalayerNotebookExtension[];
57+
extensions?: NotebookExtension[];
5758
height?: string;
5859
id: string;
5960
kernel?: Kernel;
@@ -285,32 +286,25 @@ export const Notebook = (props: INotebookProps) => {
285286
if (adapter?.notebookPanel && isMounted) {
286287
sharedModel = new YNotebook();
287288
const { ydoc, awareness } = sharedModel;
288-
// Setup Collaboration.
289-
if (collaborative == 'jupyter') {
290-
const token =
291-
jupyterReactStore.getState().jupyterConfig?.jupyterServerToken;
292-
const session = await requestJupyterCollaborationSession('json', 'notebook', path!);
293-
const documentURL = URLExt.join(
294-
serviceManager?.serverSettings.wsUrl!,
295-
COLLABORATION_ROOM_URL_PATH
296-
);
297-
const documentName = `${session.format}:${session.type}:${session.fileId}`;
298-
provider = new YWebsocketProvider(documentURL, documentName, ydoc, {
299-
disableBc: true,
300-
params: {
301-
sessionId: session.sessionId,
302-
token: token!,
303-
},
289+
// Setup Collaboration using the provider registry.
290+
try {
291+
const token = jupyterReactStore.getState().jupyterConfig?.jupyterServerToken;
292+
provider = await collaborationProviderRegistry.createProvider(collaborative!, {
293+
ydoc,
304294
awareness,
295+
path: path!,
296+
serviceManager,
297+
token,
305298
});
306-
} else {
307-
// Other collaboration types can be handled by extensions
308-
console.warn(`Unsupported collaboration type: ${collaborative}`);
299+
} catch (error) {
300+
console.error(`Failed to create collaboration provider '${collaborative}':`, error);
301+
return;
309302
}
303+
310304
if (provider) {
311305
provider.on('sync', onSync);
312306
provider.on('connection-close', onConnectionClose);
313-
console.log('Collaboration is setup with websocket provider.');
307+
console.log(`Collaboration is setup with '${collaborative}' provider.`);
314308
// Create a new model using the one synchronize with the collaboration document
315309
const model = new NotebookModel({
316310
collaborationEnabled: true,

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { Box } from '@primer/react';
1515
import type { OnSessionConnection } from '../../state';
1616
import { Loader } from '../utils';
1717
import { useKernelId, useNotebookModel, Notebook2Base } from './Notebook2Base';
18-
import type { DatalayerNotebookExtension } from './NotebookExtensions';
18+
import type { NotebookExtension } from './NotebookExtensions';
1919
import type { INotebookToolbarProps } from './toolbar';
2020

2121
import './Notebook.css';
@@ -48,7 +48,7 @@ export interface INotebook2Props {
4848
/**
4949
* Notebook extensions.
5050
*/
51-
extensions?: DatalayerNotebookExtension[];
51+
extensions?: NotebookExtension[];
5252
/**
5353
* Notebook ID.
5454
*/

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ import type { OnSessionConnection } from '../../state';
3737
import { newUuid, remoteUserCursors } from '../../utils';
3838
import { Lumino } from '../lumino';
3939
import { Loader } from '../utils';
40-
import type { DatalayerNotebookExtension } from './NotebookExtensions';
40+
import type { NotebookExtension } from './NotebookExtensions';
4141
import { addNotebookCommands } from './NotebookCommands';
4242

4343
const COMPLETER_TIMEOUT_MILLISECONDS = 1000;
4444

45-
const DEFAULT_EXTENSIONS = new Array<DatalayerNotebookExtension>();
45+
const DEFAULT_EXTENSIONS = new Array<NotebookExtension>();
4646

4747
const FALLBACK_NOTEBOOK_PATH = '.datalayer/ping.ipynb';
4848

@@ -64,7 +64,7 @@ export interface INotebook2BaseProps {
6464
/**
6565
* Notebook extensions
6666
*/
67-
extensions?: DatalayerNotebookExtension[];
67+
extensions?: NotebookExtension[];
6868
/**
6969
* Kernel ID to connect to
7070
*/

packages/react/src/components/notebook/NotebookExtensions.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,14 @@ import { INotebookModel, NotebookPanel } from "@jupyterlab/notebook";
99
import { CommandRegistry } from '@lumino/commands';
1010
import { NotebookAdapter } from './NotebookAdapter';
1111

12-
export type IDatalayerNotebookExtensionProps = {
12+
export type INotebookExtensionProps = {
1313
notebookId: string;
1414
commands: CommandRegistry;
1515
panel: NotebookPanel;
1616
adapter?: NotebookAdapter;
1717
};
1818

19-
export type DatalayerNotebookExtension = DocumentRegistry.IWidgetExtension<NotebookPanel,INotebookModel> & {
20-
init(props: IDatalayerNotebookExtensionProps): void;
19+
export type NotebookExtension = DocumentRegistry.IWidgetExtension<NotebookPanel,INotebookModel> & {
20+
init(props: INotebookExtensionProps): void;
2121
get component(): JSX.Element | null;
2222
};

packages/react/src/components/notebook/cell/sidebar/CellSidebarExtension.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import type { PanelLayout, Widget } from '@lumino/widgets';
1515
import { Signal } from '@lumino/signaling';
1616
import { JupyterReactTheme } from '../../../../theme';
1717
import { CellSidebar, type ICellSidebarProps } from './CellSidebar';
18-
import { DatalayerNotebookExtension, IDatalayerNotebookExtensionProps } from '../../NotebookExtensions';
18+
import { NotebookExtension, INotebookExtensionProps } from '../../NotebookExtensions';
1919

2020
class CellSidebarFactory implements IDisposable {
2121
private _isDisposed = false;
@@ -127,7 +127,7 @@ type ICellSidebarExtensionOptions = {
127127
/**
128128
* Cell sidebar extension for notebook panels.
129129
*/
130-
export class CellSidebarExtension implements DatalayerNotebookExtension {
130+
export class CellSidebarExtension implements NotebookExtension {
131131
protected factory: React.JSXElementConstructor<ICellSidebarProps>;
132132
protected commands?: CommandRegistry;
133133
protected nbgrader?: boolean;
@@ -162,7 +162,7 @@ export class CellSidebarExtension implements DatalayerNotebookExtension {
162162
return sidebar;
163163
}
164164

165-
init(props: IDatalayerNotebookExtensionProps): void {
165+
init(props: INotebookExtensionProps): void {
166166
this.commands = props.commands;
167167
}
168168
}

packages/react/src/components/output/Output.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ import { useJupyter } from '../../jupyter/JupyterContext';
1515
import { IExecutionPhaseOutput, Kernel } from '../../jupyter/kernel';
1616
import { newUuid } from '../../utils';
1717
import { KernelActionMenu, KernelProgressBar } from '../kernel';
18-
// import { CodeMirrorDatalayerEditor } from '../codemirror';
18+
// import { CodeMirrorEditor } from '../codemirror';
1919
import { OutputAdapter } from './OutputAdapter';
2020
import { OutputRenderer } from './OutputRenderer';
2121
import { useOutputsStore } from './OutputState';
2222

2323
import './Output.css';
24-
import { CodeMirrorDatalayerEditor } from '../codemirror';
24+
import { CodeMirrorEditor } from '../codemirror';
2525

2626
export type IOutputProps = {
2727
adapter?: OutputAdapter;
@@ -170,7 +170,7 @@ export const Output = (props: IOutputProps) => {
170170
},
171171
}}
172172
>
173-
<CodeMirrorDatalayerEditor
173+
<CodeMirrorEditor
174174
autoRun={autoRun}
175175
code={code}
176176
codePre={codePre}

packages/react/src/examples/extensions/celltoolbar/CellToolbar.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66

77
import { ReactWidget } from '@jupyterlab/apputils';
88
import { CodeCell } from '@jupyterlab/cells';
9-
import { IDatalayerNotebookExtensionProps } from '../../../components';
9+
import { INotebookExtensionProps } from '../../../components';
1010
import { CellToolbarComponent } from './CellToolbarComponent';
1111

1212
export const DATALAYER_CELL_TOOLBAR_CLASS = 'dla-CellToolbar-Container';
1313

1414
export class CellToolbar extends ReactWidget {
1515
private _cell: CodeCell;
16-
private _props: IDatalayerNotebookExtensionProps;
16+
private _props: INotebookExtensionProps;
1717

18-
constructor(cell: CodeCell, props: IDatalayerNotebookExtensionProps) {
18+
constructor(cell: CodeCell, props: INotebookExtensionProps) {
1919
super();
2020
this._cell = cell;
2121
this._props = props;

0 commit comments

Comments
 (0)