Skip to content

Commit eb95756

Browse files
committed
test
1 parent 935448c commit eb95756

37 files changed

+1466
-127
lines changed

CLAUDE.md

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,34 +25,35 @@ Jupyter React UI - Generic React components and utilities for building Jupyter-b
2525
- **Collaboration system**: Extensible plugin-based collaboration with built-in Jupyter provider
2626
- **JupyterLab integration**: Support for extensions and themes
2727

28-
## Collaboration System
28+
## Extension Architecture
2929

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
30+
**Generic Provider Pattern**: `ICollaborationProvider = string | undefined` - accepts any provider name
31+
- `CollaborationProviderRegistry` - Global registry validates providers at runtime
32+
- `JupyterCollaborationProvider` - Built-in for Jupyter Lab/Server collaboration
33+
- Extensions auto-register providers on import
3534

36-
**Usage:**
3735
```typescript
38-
// Use built-in Jupyter collaboration
36+
// Built-in provider
3937
<Notebook collaborative="jupyter" ... />
4038

41-
// Extensions can register custom providers
42-
collaborationProviderRegistry.register('custom', new CustomProvider());
43-
<Notebook collaborative="custom" ... />
39+
// Extensions register custom providers automatically
40+
import '@datalayer/core'; // Auto-registers 'datalayer' provider
41+
<Notebook collaborative="datalayer" ... />
4442
```
4543

46-
## Migration Notes
44+
## Migration Status
4745

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
46+
**✅ Complete (v1.0.7)**: 100% generic, no Datalayer dependencies
47+
- Generic collaboration types (`ICollaborationProvider = string | undefined`)
48+
- Extensible state management (`JupyterReactState`)
49+
- Plugin-based collaboration system
50+
- Generic component naming (CodeMirrorEditor, NotebookExtension)
51+
- One-way dependency: extensions → jupyter-ui (never reverse)
5452

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
53+
## Recent Updates (Session 2025-08-13)
54+
55+
- Fixed collaboration interface types (IJupyterCollaborationServer correctly has type: 'jupyter')
56+
- Made ICollaborationProvider truly generic accepting any string provider name
57+
- Created CollaborationProviderRegistry with runtime validation
58+
- Added comprehensive generic examples in `src/examples/generic/`
59+
- Renamed components to generic names (CodeMirrorEditor, NotebookExtension)
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/*
2+
* Copyright (c) 2021-2023 Datalayer, Inc.
3+
*
4+
* MIT License
5+
*/
6+
7+
import { WebsocketProvider as YWebsocketProvider } from 'y-websocket';
8+
import {
9+
ICollaborationProviderImpl,
10+
ICollaborationOptions,
11+
collaborationProviderRegistry
12+
} from '../../index';
13+
14+
/**
15+
* Example custom collaboration provider demonstrating how to extend
16+
* the generic collaboration system without any Datalayer dependencies.
17+
*
18+
* This provider can be used with any WebSocket-based collaboration server.
19+
*/
20+
export class CustomCollaborationProvider implements ICollaborationProviderImpl {
21+
readonly name = 'custom-example';
22+
23+
/**
24+
* Create a custom WebSocket provider for collaboration
25+
* @param options - Collaboration options containing ydoc, awareness, path, etc.
26+
* @returns Promise that resolves to a configured YWebsocketProvider
27+
*/
28+
async createProvider(options: ICollaborationOptions): Promise<YWebsocketProvider> {
29+
const { ydoc, awareness, path, token } = options;
30+
31+
if (!path) {
32+
throw new Error('Path is required for custom collaboration');
33+
}
34+
35+
// Example: Connect to a custom collaboration server
36+
// You would replace this with your actual server configuration
37+
const wsUrl = options.wsUrl || 'ws://localhost:1234/collaboration';
38+
const roomName = `custom-room-${path.replace(/\//g, '-')}`;
39+
40+
console.log(`Creating custom collaboration provider for room: ${roomName}`);
41+
42+
// Create the WebSocket provider with custom configuration
43+
const provider = new YWebsocketProvider(
44+
wsUrl,
45+
roomName,
46+
ydoc,
47+
{
48+
awareness,
49+
params: {
50+
// Custom parameters for your collaboration server
51+
path,
52+
token: token || '',
53+
timestamp: Date.now().toString(),
54+
// Add any custom parameters your server needs
55+
customParam: 'example-value'
56+
},
57+
// Custom WebSocket options
58+
connect: true,
59+
// Disable broadcasting to other browser tabs (optional)
60+
disableBc: false,
61+
// Custom protocols (optional)
62+
protocols: [],
63+
}
64+
);
65+
66+
// Optional: Add custom event handlers
67+
provider.on('status', (event: any) => {
68+
console.log(`Custom provider status: ${event.status}`);
69+
});
70+
71+
provider.on('sync', (isSynced: boolean) => {
72+
console.log(`Custom provider synced: ${isSynced}`);
73+
});
74+
75+
// Optional: Custom authentication or initialization
76+
await this.authenticate(token);
77+
78+
return provider;
79+
}
80+
81+
/**
82+
* Example authentication method
83+
* Replace with your actual authentication logic
84+
*/
85+
private async authenticate(token?: string): Promise<void> {
86+
if (!token) {
87+
console.log('No token provided, using anonymous mode');
88+
return;
89+
}
90+
91+
// Simulate authentication
92+
return new Promise((resolve) => {
93+
setTimeout(() => {
94+
console.log('Custom provider authenticated');
95+
resolve();
96+
}, 100);
97+
});
98+
}
99+
}
100+
101+
/**
102+
* Alternative simple collaboration provider for local development
103+
*/
104+
export class LocalCollaborationProvider implements ICollaborationProviderImpl {
105+
readonly name = 'local-dev';
106+
107+
async createProvider(options: ICollaborationOptions): Promise<YWebsocketProvider> {
108+
const { ydoc, awareness, path } = options;
109+
110+
// Use a local WebSocket server for development
111+
const provider = new YWebsocketProvider(
112+
'ws://localhost:1234',
113+
`local-${path}`,
114+
ydoc,
115+
{
116+
awareness,
117+
connect: false, // Don't connect automatically
118+
}
119+
);
120+
121+
// For local development, we might not have a real server
122+
// So we can work in offline mode
123+
console.log('LocalCollaborationProvider created in offline mode');
124+
125+
return provider;
126+
}
127+
}
128+
129+
/**
130+
* Mock collaboration provider for testing
131+
*/
132+
export class MockCollaborationProvider implements ICollaborationProviderImpl {
133+
readonly name = 'mock';
134+
135+
async createProvider(options: ICollaborationOptions): Promise<YWebsocketProvider> {
136+
const { ydoc, awareness } = options;
137+
138+
// Create a provider that doesn't actually connect anywhere
139+
const provider = new YWebsocketProvider(
140+
'ws://mock-server',
141+
'mock-room',
142+
ydoc,
143+
{
144+
awareness,
145+
connect: false, // Never actually connect
146+
}
147+
);
148+
149+
// Simulate successful connection
150+
setTimeout(() => {
151+
(provider as any).wsconnected = true;
152+
provider.emit('status', [{ status: 'connected' }]);
153+
}, 500);
154+
155+
return provider;
156+
}
157+
}
158+
159+
/**
160+
* Register all custom providers when this module is imported
161+
* This demonstrates the auto-registration pattern
162+
*/
163+
export function registerCustomProviders(): void {
164+
console.log('Registering custom collaboration providers...');
165+
166+
// Register the custom provider
167+
collaborationProviderRegistry.register('custom-example', new CustomCollaborationProvider());
168+
169+
// Register the local development provider
170+
collaborationProviderRegistry.register('local-dev', new LocalCollaborationProvider());
171+
172+
// Register the mock provider for testing
173+
collaborationProviderRegistry.register('mock', new MockCollaborationProvider());
174+
175+
console.log('Custom providers registered:', collaborationProviderRegistry.getProviderNames());
176+
}
177+
178+
// Auto-register on import (optional)
179+
// Uncomment this line to auto-register when the module is imported
180+
// registerCustomProviders();
181+
182+
export default CustomCollaborationProvider;

0 commit comments

Comments
 (0)