Skip to content

Commit

Permalink
Add the factory for the chat document and widget
Browse files Browse the repository at this point in the history
  • Loading branch information
brichet committed Apr 7, 2024
1 parent 4dca085 commit 3ae72aa
Show file tree
Hide file tree
Showing 15 changed files with 993 additions and 138 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import warnings
warnings.warn("Importing 'jupyterlab_collaborative_chat' outside a proper installation.")
__version__ = "dev"
from .handlers import setup_handlers


def _jupyter_labextension_paths():
Expand All @@ -28,12 +27,10 @@ def _jupyter_server_extension_points():

def _load_jupyter_server_extension(server_app):
"""Registers the API handler to receive HTTP requests from the frontend extension.
Parameters
----------
server_app: jupyterlab.labapp.LabApp
JupyterLab application instance
"""
setup_handlers(server_app.web_app)
name = "jupyterlab_collaborative_chat"
server_app.log.info(f"Registered {name} server extension")

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.

# TODO: remove this module in favor of the one in jupyter_ydoc when released.

import json
from functools import partial
from typing import Any, Callable, List

from jupyter_ydoc.ybasedoc import YBaseDoc
from pycrdt import Array, Map


class YChat(YBaseDoc):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self._ydoc["content"] = self._ycontent = Map()
self._ydoc["messages"] = self._ymessages = Array()

@property
def version(self) -> str:
"""
Returns the version of the document.
:return: Document's version.
:rtype: str
"""
return "1.0.0"

@property
def messages(self) -> List:
return self._ymessages.to_py()

def get(self) -> str:
"""
Returns the messages of the document.
:return: Document's messages.
:rtype: Any
"""

messages = self._ymessages.to_py()
data = dict(messages=messages)
return json.dumps(data, indent=2, sort_keys=True)

def set(self, value: str) -> None:
"""
Sets the content of the document.
:param value: The content of the document.
:type value: str
"""
contents = json.loads(value)
if "messages" in contents.keys():
with self._ydoc.transaction():
for v in contents["messages"]:
self._ymessages.append(v)

def observe(self, callback: Callable[[str, Any], None]) -> None:
self.unobserve()
self._subscriptions[self._ystate] = self._ystate.observe(partial(callback, "state"))
self._subscriptions[self._ymessages] = self._ymessages.observe(
partial(callback, "messages")
)
self._subscriptions[self._ycontent] = self._ycontent.observe(partial(callback, "content"))
12 changes: 11 additions & 1 deletion packages/jupyterlab-collaborative-chat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,20 @@
"watch:labextension": "jupyter labextension watch ."
},
"dependencies": {
"@jupyter/collaboration": "^2.0.11",
"@jupyter/docprovider": "^2.0.11",
"@jupyterlab/application": "^4.0.5",
"@jupyterlab/apputils": "^4.0.5",
"@jupyterlab/coreutils": "^6.0.5",
"@jupyterlab/docregistry": "^4.0.5",
"@jupyterlab/rendermime": "^4.0.5",
"@jupyterlab/services": "^7.0.5",
"@jupyterlab/settingregistry": "^4.0.5"
"@jupyterlab/settingregistry": "^4.0.5",
"@lumino/coreutils": "^2.1.0",
"@lumino/signaling": "^2.1.0",
"chat-jupyter": "0.1.0",
"y-protocols": "^1.0.5",
"yjs": "^13.5.40"
},
"devDependencies": {
"@jupyterlab/builder": "^4.0.0",
Expand Down
9 changes: 8 additions & 1 deletion packages/jupyterlab-collaborative-chat/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ classifiers = [
"Programming Language :: Python :: 3.12",
]
dependencies = [
"jupyter_server>=2.0.1,<3"
"jupyterlab~=4.0",
"jupyter_collaboration",
"jupyter_server>=2.0.1,<3",
"jupyter_ydoc>=2.0.0,<3.0.0",
"pycrdt"
]
dynamic = ["version", "description", "authors", "urls", "keywords"]

Expand Down Expand Up @@ -86,3 +90,6 @@ before-build-python = ["jlpm clean:all"]

[tool.check-wheel-contents]
ignore = ["W002"]

[project.entry-points.jupyter_ydoc]
chat = "jupyterlab_collaborative_chat.ychat:YChat"
14 changes: 14 additions & 0 deletions packages/jupyterlab-collaborative-chat/schema/chat.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"title": "Jupyter chat configuration",
"description": "Configuration for the chat panel",
"type": "object",
"properties": {
"sendWithShiftEnter": {
"description": "Whether to send a message via Shift-Enter instead of Enter.",
"type": "boolean",
"default": false,
"readOnly": false
}
},
"additionalProperties": false
}
8 changes: 0 additions & 8 deletions packages/jupyterlab-collaborative-chat/schema/plugin.json

This file was deleted.

152 changes: 152 additions & 0 deletions packages/jupyterlab-collaborative-chat/src/factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright (c) Jupyter Development Team.
* Distributed under the terms of the Modified BSD License.
*/

import { ChatWidget, IChatModel } from 'chat-jupyter';
import { IThemeManager } from '@jupyterlab/apputils';
import { ABCWidgetFactory, DocumentRegistry } from '@jupyterlab/docregistry';
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
import { Contents } from '@jupyterlab/services';
import { Awareness } from 'y-protocols/awareness';

import { CollaborativeChatModel } from './model';
import { CollaborativeChatWidget } from './widget';
import { YChat } from './ychat';

/**
* A widget factory to create new instances of CollaborativeChatWidget.
*/
export class ChatWidgetFactory extends ABCWidgetFactory<
CollaborativeChatWidget,
CollaborativeChatModel
> {
/**
* Constructor of ChatWidgetFactory.
*
* @param options Constructor options
*/
constructor(options: ChatWidgetFactory.IOptions) {
super(options);
this._themeManager = options.themeManager;
this._rmRegistry = options.rmRegistry;
}

/**
* Create a new widget given a context.
*
* @param context Contains the information of the file
* @returns The widget
*/
protected createNewWidget(
context: ChatWidgetFactory.IContext
): CollaborativeChatWidget {
context.chatModel = context.model;
context.rmRegistry = this._rmRegistry;
context.themeManager = this._themeManager;
return new CollaborativeChatWidget({
context,
content: new ChatWidget(context)
});
}

private _themeManager: IThemeManager | null;
private _rmRegistry: IRenderMimeRegistry;
}

export namespace ChatWidgetFactory {
export interface IContext
extends DocumentRegistry.IContext<CollaborativeChatModel> {
chatModel: IChatModel;
themeManager: IThemeManager | null;
rmRegistry: IRenderMimeRegistry;
}

export interface IOptions extends DocumentRegistry.IWidgetFactoryOptions {
themeManager: IThemeManager | null;
rmRegistry: IRenderMimeRegistry;
}
}

export class CollaborativeChatModelFactory
implements DocumentRegistry.IModelFactory<CollaborativeChatModel>
{
constructor(options: CollaborativeChatModel.IOptions) {
this._awareness = options.awareness;
}

collaborative = true;
/**
* The name of the model.
*
* @returns The name
*/
get name(): string {
return 'chat';
}

/**
* The content type of the file.
*
* @returns The content type
*/
get contentType(): Contents.ContentType {
return 'chat';
}

/**
* The format of the file.
*
* @returns the file format
*/
get fileFormat(): Contents.FileFormat {
return 'text';
}

/**
* Get whether the model factory has been disposed.
*
* @returns disposed status
*/

get isDisposed(): boolean {
return this._disposed;
}

/**
* Dispose the model factory.
*/
dispose(): void {
this._disposed = true;
}

/**
* Get the preferred language given the path on the file.
*
* @param path path of the file represented by this document model
* @returns The preferred language
*/
preferredLanguage(path: string): string {
return '';
}

/**
* Create a new instance of CollaborativeChatModel.
*
* @param languagePreference Language
* @param modelDB Model database
* @returns The model
*/

createNew(
options: DocumentRegistry.IModelOptions<YChat>
): CollaborativeChatModel {
return new CollaborativeChatModel({
...options,
awareness: this._awareness
});
}

private _disposed = false;
private _awareness: Awareness;
}
51 changes: 0 additions & 51 deletions packages/jupyterlab-collaborative-chat/src/handler.ts

This file was deleted.

Loading

0 comments on commit 3ae72aa

Please sign in to comment.