From a33c9a0faf5cf8ecd536b798cf527bee5e0ded16 Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Wed, 7 Aug 2024 13:20:29 +0200 Subject: [PATCH 1/8] Add user documentation --- .readthedocs.yaml | 21 ++++ docs/Makefile | 20 ++++ docs/make.bat | 35 ++++++ docs/requirements.txt | 3 + .../_static/images/code-toolbar-above.png | Bin 0 -> 665 bytes .../_static/images/code-toolbar-below.png | Bin 0 -> 680 bytes .../_static/images/code-toolbar-copy.png | Bin 0 -> 591 bytes .../_static/images/code-toolbar-replace.png | Bin 0 -> 524 bytes .../_static/images/collaboarative-chat.png | Bin 0 -> 167570 bytes .../_static/images/left-panel-new-chat.png | Bin 0 -> 1906 bytes docs/source/conf.py | 29 +++++ docs/source/developers/contributing/index.md | 12 ++ .../developers/contributing/jupyter-chat.md | 21 ++++ .../jupyterlab-collaborative-chat.md | 3 + docs/source/developers/index.md | 11 ++ docs/source/index.md | 23 ++++ docs/source/users/index.md | 107 ++++++++++++++++++ pyproject.toml | 8 ++ 18 files changed, 293 insertions(+) create mode 100644 .readthedocs.yaml create mode 100644 docs/Makefile create mode 100644 docs/make.bat create mode 100644 docs/requirements.txt create mode 100644 docs/source/_static/images/code-toolbar-above.png create mode 100644 docs/source/_static/images/code-toolbar-below.png create mode 100644 docs/source/_static/images/code-toolbar-copy.png create mode 100644 docs/source/_static/images/code-toolbar-replace.png create mode 100644 docs/source/_static/images/collaboarative-chat.png create mode 100644 docs/source/_static/images/left-panel-new-chat.png create mode 100644 docs/source/conf.py create mode 100644 docs/source/developers/contributing/index.md create mode 100644 docs/source/developers/contributing/jupyter-chat.md create mode 100644 docs/source/developers/contributing/jupyterlab-collaborative-chat.md create mode 100644 docs/source/developers/index.md create mode 100644 docs/source/index.md create mode 100644 docs/source/users/index.md diff --git a/.readthedocs.yaml b/.readthedocs.yaml new file mode 100644 index 0000000..b905cd8 --- /dev/null +++ b/.readthedocs.yaml @@ -0,0 +1,21 @@ +# Read the Docs configuration file +# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details + +version: 2 + +build: + os: ubuntu-22.04 + tools: + python: "3.11" + nodejs: "18" + +# Build documentation in the docs/ directory with Sphinx +sphinx: + configuration: docs/source/conf.py + +python: + install: + - method: pip + path: . + extra_requirements: + - docs diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..d0c3cbf --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..747ffb7 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..ba872ef --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,3 @@ +sphinx +myst-parser +pydata_sphinx_theme \ No newline at end of file diff --git a/docs/source/_static/images/code-toolbar-above.png b/docs/source/_static/images/code-toolbar-above.png new file mode 100644 index 0000000000000000000000000000000000000000..81bb0e8a0b582834dfdb02ae0d6ceb30999ffaac GIT binary patch literal 665 zcmeAS@N?(olHy`uVBq!ia0vp^nm}y8!3HFIb_Op6QY^(zo*^7SP{WbZ0pv@TxJHx& z=ckpFCl;kLr03=5rs@_a7p11=6=&p^yl38T2UMgDQsi8enpl#VpQjL#nVZTGo|>Xy zV6Na;nyz4EU}U0TXlP|(3PcLduE8OnwOMQ!7#P2Jx;TbJw7#9bchw^Ykp_EV&*bz2 zr;hpQxCDND&RfH9|6ouJxAeht$4;?t2bEMS&T-xURiB(4{Y`)dJk2-n#?X#ZbjS?qQ zg3fUn_zIui#IPf7{k-B>Rr%kVQ@t+cZEyWjcj;|eq~3J@opFL4{goP;t*__R{NB&B z;cni`601d>zL#rez7}0KsegG}YUKXX%)dPuSAKIn+;!(=NmR_SULUo`Kkt2h^H2DA u($b)XQERKt3GYp)5pR6)4jvB>hP=vz1ye14SA7H~8wO8TKbLh*2~7Zy94O@g literal 0 HcmV?d00001 diff --git a/docs/source/_static/images/code-toolbar-below.png b/docs/source/_static/images/code-toolbar-below.png new file mode 100644 index 0000000000000000000000000000000000000000..7414841ad8ac0ec4630b7e1c7c74c2e526ccedf8 GIT binary patch literal 680 zcmV;Z0$2TsP)#00004b3#c}2nYxW zdZgXgFbngSdJ^%m!D|AIzbVG7w zVRUJ4ZXi@?ZDjygWn>^QHy}ZEXCN{#GBhADF*-CfIx;pOLq$_m0Tfs300065Nklorkxk9;>UPZj12bDm`8oC$MX*To;_-~SeP1tCd=kfcILQXwR%h=gS9*#y%x zF`Z6vxm-RX5Rb>9C<-!}jPD#4ba$^-E3{fIIF9oX!5gty49#W}g+k$BJaD@QgTcoI z0l;w_Xqx6550pHePUJ#-9*Jo2L0N*FA4Z_WOMTwdc9+3EXbZIk}75OnTE+Q%#&|r&^?D^2 z0{}^qP%f9Ds;cjtz-#fZ@NzSM1;a4V>2$ytL%m){KA$I9m$U`xx{mdF4Z|=n91h9W zCH<0?WqDO<+cw#{k!a?TkPKbjmSv&a?P9;*dt;l;2FK$O0FX!|zV$xNIaF0eDwTRW zSLidTX&Q80|1o}h=fmNE#bV)&FPBRIK&@7LJ6CAQbUOWT-0ymGT^Gq@GE}Z#HS^JE z^liH*lL@xlEdU^!%|cNWFUC1XrBVr%=T|N0KIv|^^CWY*T;Nsr4w0ztNJx_2II=8z z)g7kQ_(A#?WZO38^Ent}C>D#5B#C6*Nc^fr;!FxjDug5zLXrw0NyQg~Jh6o?lAHek O0000Xy zV6Na;nyz4EU}U0TXlP|(U}a*d;OrV4a;~nCgMoo@m8XkiNJQ(~8T(f~au8|Xf5MeT z^ysM$v$A~-aR;2Fj~;XX#8|`G9g?)LHL82+(xnMij!6LpJ=-JR9okz^zUg>k`Q|g> z|If|QH=gsSc;5Nvlk4Z4xi99?G}WYas)?(X%Kb?#k1U>5*c9!)d!%>PS+$!vVIixh z@-#JktT^+sM9B0@=5B!@Qd%BJS<>X5ViJE<-8q%3j+kMXQ|5f zvooxFZ6v{Sq&M#2|C#UBYb^axJO6B&vxw`WV@rcN{gyj#zkM~$)p}=yPQ==a$bzbQm!JJ6#q zmYPrgS(uwBVKmpzwbwpw&Sahm9-G2e3$icWOz61k_a5FoKVBA9@CIH T-P%Y47}*S-u6{1-oD!MXy zV6Na;nyz4EU}U0TXlP|(WMyoq;OrV4a$D|Jsw)#bwIU{Qfteid^4k&*JS;fyvgFgZ15b-OSFH*VY5m-@@#NpS z_n`s|#|m9yufO$Q= z=dvkP(Rp=8U#59#t$F`W)A#a%OsRgYvNUtcv%d3P0#nwW_4*f{r{>9|xpb@EyuU8F zx4%uBZP)QwqHgTe~DWM4f DJj2>@ literal 0 HcmV?d00001 diff --git a/docs/source/_static/images/collaboarative-chat.png b/docs/source/_static/images/collaboarative-chat.png new file mode 100644 index 0000000000000000000000000000000000000000..3da5fbb16459e0d0913e153a35b57b05ff128c09 GIT binary patch literal 167570 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 z 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 XCl@S3G#9|^rBMkTYDrO45le{#MQuf` z6>HLzn%WgNO0}kFipDZX(HQp+xaZvOobP+id(Lyt_v4%9>|`S@q9_6Y0K{#t!CX%m zda_`k;K>!N1xuVj;I5@D0(dg_fq|(fSpjG5iE|4N!bKw^Q2=yUI2NUMHy{#)3cGtd z9LM4BGd+>c|5vh#L?LmQ@GuYpgGB*6P=O$bA;=;M4Y~-qXaKqZxpDz|1)>kKvUWq{ z8RO?qK91PJED(6|MsYmOZTeil85r}G(^{FwOMM|-FD{c}eMPs=W!1&YyuY*a@}0|{j59@(|B!6KEyrzcyVv}3GtJIu`U z^V?y?K&;R7dy|;|t9_l*y|1S*eUoU(e zyh3Uq`z%L!ro=$Pn1en-&7QjQVuAnzMR7Wv{{70|(WSXLi;fyy6{7CnsQ)pHFyJlb z*09^B#@BYgEH7sl6r}hzM$aNEtviTSS95LD=dhA1F3dBEXJlXY;0>uNlM&4|PiLGq z-E2w~@?hIc%)FUq2}W2=D<$y3z25sMzO24DW&8WGL~D5Vm$C$W55)VmldspV4OAtR zF|%gj+{H3)W0~(}!|~u_Y<`^c@b*iqGKY$1%f|Wklz7+WX$CF$Ba#h{)HXreNJ|Sm zE@F^b`w`Kux}PmX>h;i(z-@ z@7TNQNSNl+mxO)+N*^c?b`>Y3X8z_n0V#t@$3Kmm76<=kd7< zMQ_>;#6TMhQ)#Lg3KNAKJ*@AAC}x_NN|5IK!l^-x^ERv-My0=*VpXJi>-5YO^pi4% ze>hxARo8(LcW=s2WxMTogPO1K>zA(gnwDfmerFQ44;R~>toj~Ym{7k2dwBZu^X}wM z9^}JJ_gk|pgPmR4P3SOB;@!Z_t{@$${LRMwmhrt;&8A!$dvy+ljOn4Yh0M|r9ZgMl z`nQLN9b8>q542@EJ-st0&HxiK9G&D5wGFS9Ra9aPN~*)}k<$XMQ4A>K#Fn>uoYLMq zN;XtlE+WsZxDc^2vOyr<9=Vn?PG8; zuVU{AfEFVy!`Y{i-eIF)KSvf8lj;wvt!N(l?5eL8Xsqp}+MiHHe-QFwKK-3!)pYRC z&=9+$ySDaQaNtOZQ2~?5j9UvfC`vHe;TA`qQd9p+*n@<`75W#&*MMCmzG(o zWdcm7PL$@$*m9-H?d_p-kZ-1pk*48`C04m$s6hE2+#677&T~r-N5>HlWxa*r991!_ z{|1rKzq;4;wDdY)0Z}0RjMHmz&M0GDyQb7idh_S!$ZZd>KMh(m4p1f8#WVcdm=c`B z9BpZjawi-fhuyJ53OJ(ZN!eO_u_GG11K%WcdA*^(s74F_S)l#3qxc|#kHFDU!@7yC z9A@X!(n<*fcxyW+wCbTw|AZZj8vmwtqYWoE&IoIZ#5664lqIKV1G4jJUZY*gIwIv^ zk7>qq2fxi9+GCDjPWKd_R#;qeUpWZa)-#z7YHT0}mp(->r*}M!nN%D4aM@&Y2MK$03gS!ELo-KVY!;Y_fB(-L2QxXWb zU4~NmztW<<9P>_xdG$W{QjPQ+n~lKvnY@GtLiF!%4n3L`;Xj?dZw9Bwh@bapK=}n| zq92DYx2by{HvHS5siQmdM~mQ2g?HLsLHw<)?{B`Wd0lR2E68HMwX}qIe>~87r=oLf z=sLfg4zy`$Rf+8MFA`xWy^yd73S-@*V;SUq%+WhOOd*&t4b!%q4TU~BCJYp}eP_zxvboaF!j literal 0 HcmV?d00001 diff --git a/docs/source/conf.py b/docs/source/conf.py new file mode 100644 index 0000000..91eb288 --- /dev/null +++ b/docs/source/conf.py @@ -0,0 +1,29 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = 'jupyter-chat' +copyright = '2024, Jupyter Development Team' +author = 'Jupyter Development Team' + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + 'myst_parser' +] + +templates_path = ['_templates'] +exclude_patterns = [] + +myst_enable_extensions = ["attrs_inline"] + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = 'pydata_sphinx_theme' +html_static_path = ['_static'] diff --git a/docs/source/developers/contributing/index.md b/docs/source/developers/contributing/index.md new file mode 100644 index 0000000..47e6c2a --- /dev/null +++ b/docs/source/developers/contributing/index.md @@ -0,0 +1,12 @@ +# Contributing + +This is the contributors documentation. + +```{toctree} +--- +maxdepth: 2 +--- + +./jupyter-chat +./jupyterlab-collaborative-chat +``` diff --git a/docs/source/developers/contributing/jupyter-chat.md b/docs/source/developers/contributing/jupyter-chat.md new file mode 100644 index 0000000..073b03f --- /dev/null +++ b/docs/source/developers/contributing/jupyter-chat.md @@ -0,0 +1,21 @@ +# @jupyter/chat + +The `@jupyter/chat` package is a frontend package (React) compatible with jupyterlab. +It is not an extension, and cannot be used on its own. It can be used with one of the +extensions provided in this repo (jupyterlab-collaborative-chat or jupyterlab-ws-chat). + +## Building the package + +The following commands are using `jlpm` but should work as well using `yarn` instead. + +From the root of the repository: + +```bash +jlpm build:core +``` + +From the package itself (`./packages/jupyter-chat`): + +```bash +jlpm build +``` diff --git a/docs/source/developers/contributing/jupyterlab-collaborative-chat.md b/docs/source/developers/contributing/jupyterlab-collaborative-chat.md new file mode 100644 index 0000000..bfe903e --- /dev/null +++ b/docs/source/developers/contributing/jupyterlab-collaborative-chat.md @@ -0,0 +1,3 @@ +# jupyterlab-collaborative-chat + +This is the contributors documentation for `jupyterlab-collaborative-chat` extension. diff --git a/docs/source/developers/index.md b/docs/source/developers/index.md new file mode 100644 index 0000000..3176189 --- /dev/null +++ b/docs/source/developers/index.md @@ -0,0 +1,11 @@ +# Developers + +This is the developers documentation. + +```{toctree} +--- +maxdepth: 2 +--- + +./contributing/index.md +``` diff --git a/docs/source/index.md b/docs/source/index.md new file mode 100644 index 0000000..f141458 --- /dev/null +++ b/docs/source/index.md @@ -0,0 +1,23 @@ +# jupyter-chat + +Jupyter-chat will help you to easily include a chat in a jupyter based application. + +This documentation includes several projects all together: + +- `@jupyter/chat`, a front-end package (typescript), including all the components +required to build a chat. This package is designed to be used by an extension. + +- `jupyterlab-collaborative-chat`, an extension built on top of `@jupyter/chat`, using +the collaborative edition as a messaging system. + +- `jupyterlab-ws-chat`, an other extension built on top of `@jupyter/chat`, using +websocket as a messaging system. + +```{toctree} +--- +maxdepth: 3 +--- + +users/index +developers/index +``` diff --git a/docs/source/users/index.md b/docs/source/users/index.md new file mode 100644 index 0000000..10e416f --- /dev/null +++ b/docs/source/users/index.md @@ -0,0 +1,107 @@ +# Users + +## jupyterlab-collaborative-chat + +The `jupyterlab-collaborative-chat` extension adds collaborative chats to jupyterlab. + +![collaborative chat](../_static/images/collaboarative-chat.png) + +These chats use the collaborative edition in jupyterlab [jupyter_collaboration](https://jupyterlab-realtime-collaboration.readthedocs.io/en/latest/). + +### Install collaborative chat + +The collaborative chat is available on [PyPI](https://pypi.org/project/jupyterlab-collaborative-chat/). + +```bash +pip install jupyterlab-collaborative-chat +``` + +To uninstall the package: + +```bash +pip uninstall jupyterlab-collaborative-chat +``` + +### Create a chat + +There are several ways to create a chat: + +- using the menu : *file -> new -> chat* +- using the commands palette (`Ctrl+Shift+C`) -> *Create a new chat* +- from the left panel ![chat icon](../../../packages/jupyter-chat/style/icons/chat.svg){w=24px}, +click on the button ![left panel new chat](../_static/images/left-panel-new-chat.png){h=24px} + +Validating the dialog will create the new chat. + +Creating a chat actually creates a file in the tree files. + +```{warning} +Currently, the left panel can only discover chat files in the root directory (to avoid +computation issues in large tree files), so it only creates chat files in the root +directory. + +Creating a chat using the menu or the command palette will create the file in the +current directory of the file browser. +``` + +### Open a chat + +There are also several ways to open a chat: + +- opening the file from the file browser +- using the commands palette (`Ctrl+Shift+C`) -> *Open a chat*. It opens a dialog to +enter fill the file path +- from the left panel ![chat icon](../../../packages/jupyter-chat/style/icons/chat.svg){w=24px}, +there is a dropdown listing the chat files, in the root directory only. + +```{note} +Opening the chat from the file browser or the command palette will open it in the main +area, like any other document. + +Opening a chat from the left panel will open it in the left panel. +``` + +## jupyterlab-ws-chat + +The `jupyterlab-ws-chat` extension adds a chat panel relying on websocket for messaging. + +```{warning} +This extension is currently under development, and users may encounter issues with it. +``` + +### Install websocket chat + +The websocket chat is available on [PyPI](https://pypi.org/project/jupyterlab-ws-chat/). + +```bash +pip install jupyterlab-ws-chat +``` + +To uninstall the package: + +```bash +pip uninstall jupyterlab-ws-chat +``` + +### Open the chat + +The chat can be opened from the left panel ![chat icon](../../../packages/jupyter-chat/style/icons/chat.svg){w=24px}. + +## Using the chat + +The chat UI is composed of a list of messages and an input to send new messages. + +A message can be edited or deleted by its author, using a toolbar in the message. + +### Code toolbar + +When code is inserted in a message, a toolbar is displayed under the code section (if +the options is set up from the settings). + +From this toolbar, the code can be copied to the clipboard: ![code toolbar copy](../_static/images/code-toolbar-copy.png){w=24px}. + +If a notebook is opened and visible, other actions are available: + +- copy the code to a new cell above the current one: ![code toolbar cell above](../_static/images/code-toolbar-above.png){w=24px} +- copy the the code to a new cell below the current one: ![code toolbar cell below](../_static/images/code-toolbar-below.png){w=24px} +- replace the content of the current cell with the code: ![code toolbar cell replace](../_static/images/code-toolbar-replace.png){w=24px} diff --git a/pyproject.toml b/pyproject.toml index 7d806ad..a7675cf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,14 @@ classifiers = [ ] dynamic = ["version", "description", "authors", "urls", "keywords"] +[project.optional-dependencies] +docs = [ + "jupyterlab>=4.0.0", + "sphinx", + "myst-parser", + "pydata-sphinx-theme" +] + [tool.hatch.version] source = "nodejs" path = "package.json" From fc9f166378bb05812b9afbca0e15a0f76862aed5 Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Wed, 7 Aug 2024 16:09:27 +0200 Subject: [PATCH 2/8] Add contributors documentation --- docs/source/developers/contributing/index.md | 4 +- .../developers/contributing/jupyter-chat.md | 3 +- .../jupyterlab-collaborative-chat.md | 75 ++++++++++++++++++- .../contributing/jupyterlab-ws-chat.md | 38 ++++++++++ 4 files changed, 116 insertions(+), 4 deletions(-) create mode 100644 docs/source/developers/contributing/jupyterlab-ws-chat.md diff --git a/docs/source/developers/contributing/index.md b/docs/source/developers/contributing/index.md index 47e6c2a..12105fb 100644 --- a/docs/source/developers/contributing/index.md +++ b/docs/source/developers/contributing/index.md @@ -1,6 +1,8 @@ # Contributing -This is the contributors documentation. +This project is part of *jupyterlab* organization. + +Before contributing to it, please read the [jupyter contributing guide](https://docs.jupyter.org/en/latest/contributing/content-contributor.html). ```{toctree} --- diff --git a/docs/source/developers/contributing/jupyter-chat.md b/docs/source/developers/contributing/jupyter-chat.md index 073b03f..1253882 100644 --- a/docs/source/developers/contributing/jupyter-chat.md +++ b/docs/source/developers/contributing/jupyter-chat.md @@ -6,11 +6,10 @@ extensions provided in this repo (jupyterlab-collaborative-chat or jupyterlab-ws ## Building the package -The following commands are using `jlpm` but should work as well using `yarn` instead. - From the root of the repository: ```bash +# In the following command, 'jlpm' can be replaced with 'yarn' jlpm build:core ``` diff --git a/docs/source/developers/contributing/jupyterlab-collaborative-chat.md b/docs/source/developers/contributing/jupyterlab-collaborative-chat.md index bfe903e..13659ec 100644 --- a/docs/source/developers/contributing/jupyterlab-collaborative-chat.md +++ b/docs/source/developers/contributing/jupyterlab-collaborative-chat.md @@ -1,3 +1,76 @@ # jupyterlab-collaborative-chat -This is the contributors documentation for `jupyterlab-collaborative-chat` extension. +The `jupyterlab-collaborative-chat` extension adds collaborative chats to jupyterlab. + +## Development installation + +Installing this extension in development mode requires an environment with *python* and *nodejs*. + +```bash +# In the following commands, 'mamba' can be replaced with 'conda' +mamba create -n jupyter-chat python nodejs +mamba activate jupyter-chat +``` + +The following command install the extension in development mode: + +```bash +# Install the extension +./scripts/install.sh collaborative + +# Symlink the assets +jupyter labextension develop --overwrite packages/jupyterlab-collaborative-chat +``` + +To uninstall it, run: + +```bash +pip uninstall jupyterlab-collaborative-chat +``` + +## Building the assets + +Changes in typescript sources of `@jupyter/chat` or `jupyterlab-collaborative-chat` must +be build again to be available in the jupyterlab. + +```bash +jlpm build:collaborative +``` + +## Testing locally the extension + +`jupyterlab-collaborative-chat` package has unit tests and integration tests. + +### Unit tests + +There are a few unit tests in *packages/jupyterlab-collaborative-chat/src/__tests__*. + +They make use of [jest](https://jestjs.io/). + +The following commands run them: + +```bash +cd ./packages/jupyterlab-collaborative-chat +jlpm test +``` + +### Integration tests + +There are more integration tests, located in *packages/jupyterlab-collaborative-chat/ui-tests*. + +They make use of [playwright](https://playwright.dev/). + +The following commands run them: + +```bash +cd ./packages/jupyterlab-collaborative-chat/ui-tests + +# Install the tests dependencies +jlpm install + +# Install the tests browser +jlpm playwright install + +# Run the tests +jlpm test +``` diff --git a/docs/source/developers/contributing/jupyterlab-ws-chat.md b/docs/source/developers/contributing/jupyterlab-ws-chat.md new file mode 100644 index 0000000..ca672fb --- /dev/null +++ b/docs/source/developers/contributing/jupyterlab-ws-chat.md @@ -0,0 +1,38 @@ +# jupyterlab-collaborative-chat + +The `jupyterlab-ws-chat` extension adds a chat panel relying on websocket for messaging. + +## Development installation + +Installing this extension in development mode requires an environment with *python* and *nodejs*. + +```bash +# In the following commands, 'mamba' can be replaced with 'conda' +mamba create -n jupyter-chat python nodejs +mamba activate jupyter-chat +``` + +The following command install the extension in development mode: + +```bash +# Install the extension +./scripts/install.sh ws + +# Symlink the assets +jupyter labextension develop --overwrite packages/jupyterlab-ws-chat +``` + +To uninstall it, run: + +```bash +pip uninstall jupyterlab-ws-chat +``` + +## Building the assets + +Changes in typescript sources of `@jupyter/chat` or `jupyterlab-ws-chat` must +be build again to be available in the jupyterlab. + +```bash +jlpm build:ws +``` From b1106a6d840550f9a689b5c2f0bdce6edc1c5508 Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Wed, 7 Aug 2024 16:52:57 +0200 Subject: [PATCH 3/8] Add some user documentation --- docs/source/users/index.md | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/docs/source/users/index.md b/docs/source/users/index.md index 10e416f..e7f271e 100644 --- a/docs/source/users/index.md +++ b/docs/source/users/index.md @@ -93,10 +93,16 @@ The chat UI is composed of a list of messages and an input to send new messages. A message can be edited or deleted by its author, using a toolbar in the message. +### Notifications and navigation + +If enabled in [settings](#chat-settings), new unread messages generate a notification. + +A down arrow in the messages list allow to navigate to the last message. This button is highlighted if some new messages are unread. + ### Code toolbar When code is inserted in a message, a toolbar is displayed under the code section (if -the options is set up from the settings). +the options is set up from the [settings](#chat-settings)). From this toolbar, the code can be copied to the clipboard: ![code toolbar copy](../_static/images/code-toolbar-copy.png){w=24px}. @@ -105,3 +111,31 @@ If a notebook is opened and visible, other actions are available: - copy the code to a new cell above the current one: ![code toolbar cell above](../_static/images/code-toolbar-above.png){w=24px} - copy the the code to a new cell below the current one: ![code toolbar cell below](../_static/images/code-toolbar-below.png){w=24px} - replace the content of the current cell with the code: ![code toolbar cell replace](../_static/images/code-toolbar-replace.png){w=24px} + +(chat-settings)= + +## Chat settings + +Some jupyterlab settings are available for the chats (included with `jupyterlab-collaborative-chat` and `jupyterlab-ws-chat`), in the setting panel (menu `Settings->Settings Editor`), with the entry *Chat*. + +These settings includes: + +- **sendWithShiftEnter** + + Whether to send a message via Shift-Enter instead of Enter.\ + Default: false + +- **stackMessages** + + Whether to stack consecutive messages from same user.\ + Default: true + +- **unreadNotifications** + + Whether to enable or not the notifications on unread messages.\ + Default: true + +- **enableCodeToolbar** + + Whether to enable or not the code toolbar.\ + Default: true From 6711d6c48e43b3c5aae3eea8a0f7e4b894f650b1 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Thu, 8 Aug 2024 08:54:57 +0000 Subject: [PATCH 4/8] Automatic application of license header --- docs/Makefile | 3 +++ docs/make.bat | 3 +++ docs/source/conf.py | 3 +++ 3 files changed, 9 insertions(+) diff --git a/docs/Makefile b/docs/Makefile index d0c3cbf..f0c2964 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -1,3 +1,6 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + # Minimal makefile for Sphinx documentation # diff --git a/docs/make.bat b/docs/make.bat index 747ffb7..121faaf 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -1,3 +1,6 @@ +rem Copyright (c) Jupyter Development Team. +rem Distributed under the terms of the Modified BSD License. + @ECHO OFF pushd %~dp0 diff --git a/docs/source/conf.py b/docs/source/conf.py index 91eb288..469659c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -1,3 +1,6 @@ +# Copyright (c) Jupyter Development Team. +# Distributed under the terms of the Modified BSD License. + # Configuration file for the Sphinx documentation builder. # # For the full list of built-in configuration values, see the documentation: From 6f17be5a32253d798b88d57649a35dcbffb75500 Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Thu, 8 Aug 2024 14:55:52 +0200 Subject: [PATCH 5/8] Documentation about adding a chat in an extension --- docs/source/conf.py | 5 +- docs/source/developers/contributing/index.md | 1 + .../extending-extension.md | 1 + .../extension-providing-chat.md | 377 ++++++++++++++++++ .../developers/developing_extensions/index.md | 15 + docs/source/developers/index.md | 6 +- docs/source/users/index.md | 2 + pyproject.toml | 5 +- 8 files changed, 407 insertions(+), 5 deletions(-) create mode 100644 docs/source/developers/developing_extensions/extending-extension.md create mode 100644 docs/source/developers/developing_extensions/extension-providing-chat.md create mode 100644 docs/source/developers/developing_extensions/index.md diff --git a/docs/source/conf.py b/docs/source/conf.py index 469659c..002936c 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -17,13 +17,14 @@ # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration extensions = [ - 'myst_parser' + 'myst_parser', + 'sphinx_copybutton' ] templates_path = ['_templates'] exclude_patterns = [] -myst_enable_extensions = ["attrs_inline"] +myst_enable_extensions = ["attrs_block", "attrs_inline"] # -- Options for HTML output ------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output diff --git a/docs/source/developers/contributing/index.md b/docs/source/developers/contributing/index.md index 12105fb..b0864d7 100644 --- a/docs/source/developers/contributing/index.md +++ b/docs/source/developers/contributing/index.md @@ -11,4 +11,5 @@ maxdepth: 2 ./jupyter-chat ./jupyterlab-collaborative-chat +./jupyterlab-ws-chat ``` diff --git a/docs/source/developers/developing_extensions/extending-extension.md b/docs/source/developers/developing_extensions/extending-extension.md new file mode 100644 index 0000000..8d6c202 --- /dev/null +++ b/docs/source/developers/developing_extensions/extending-extension.md @@ -0,0 +1 @@ +# Extending a chat extension diff --git a/docs/source/developers/developing_extensions/extension-providing-chat.md b/docs/source/developers/developing_extensions/extension-providing-chat.md new file mode 100644 index 0000000..c66488a --- /dev/null +++ b/docs/source/developers/developing_extensions/extension-providing-chat.md @@ -0,0 +1,377 @@ +# Providing a chat in a jupyter extension + +Since `@jupyter/chat` is a front end package, extensions using it needs to depend on it +from the javascript package. + +The package is available on [npmjs](https://www.npmjs.com/package/@jupyter/chat). + +This package provides all the UI components to build a chat, including a widget, +but is not tied to any messaging technology. + +```{important} +It's up to the extension to choose which messaging technology to use. +``` + +## Add the dependency + +In the extension *package.json* file, the dependency must be added to the `dependencies` +section. + +```json +"@jupyter/chat": "^0.3.0" +``` + +## Including a chat in an extension + +The package provide a jupyterlab widget (UI), that can be instantiated from the extension. + +```typescript +import { ChatWidget } from '@jupyter/chat'; +``` + +This widget needs at least 2 arguments, the [model](#model) and the +[rendermime registry](#rendermime-registry). + +(model)= + +### Model + +The model is the entry point to use the chat in a javascript/typescript package. + +A model is provided by the package, and already includes all the required method to +interact with the UI part of the chat. + +The extension has to provide a class extending the `@jupyter/chat` model, including the +method `addMessage()`. + +This method is called when a user send a message using the input of the chat. It should +contain the code that will dispatch the message through the messaging technology. + +In the following example, the message is logged to the console and added in the message +list. + +```typescript +import { ChatModel, IChatMessage, INewMessage } from '@jupyter/chat'; + +class MyModel extends ChatModel { + addMessage( + newMessage: INewMessage + ): Promise | boolean | void { + console.log(`New Message:\n${newMessage.body}`); + const message: IChatMessage = { + body: newMessage.body, + id: newMessage.id ?? UUID.uuid4(), + type: 'msg', + time: Date.now() / 1000, + sender: { username: 'me' } + }; + this.messageAdded(message); + } +} +``` + +(rendermime-registry)= + +### Rendermime registry + +The rendermime registry is required to display the messages using markdown syntax. +This registry is provided by jupyterlab with a token, and must be required by the +extension. + +### A full example + +The example below adds a new chat panel to the right. + +When a user sends a message, it is logged in the console and added to the message list. + +```{tip} +In this example, no messages are sent to other potential users. + +An exchange system must be included and use the `addMessage()` and `messageAdded()` +methods to correctly manage message transmission and reception. +``` + +```typescript +import { + ChatModel, + ChatWidget, + IChatMessage, + INewMessage +} from '@jupyter/chat'; +import { + JupyterFrontEnd, + JupyterFrontEndPlugin +} from '@jupyterlab/application'; +import { IRenderMimeRegistry } from '@jupyterlab/rendermime'; +import { UUID } from '@lumino/coreutils'; + +class MyModel extends ChatModel { + addMessage( + newMessage: INewMessage + ): Promise | boolean | void { + console.log(`New Message:\n${newMessage.body}`); + const message: IChatMessage = { + body: newMessage.body, + id: newMessage.id ?? UUID.uuid4(), + type: 'msg', + time: Date.now() / 1000, + sender: { username: 'me' } + }; + this.messageAdded(message); + } +} + +const myChatExtension: JupyterFrontEndPlugin = { + id: 'myExtension:plugin', + autoStart: true, + requires: [IRenderMimeRegistry], + activate: (app: JupyterFrontEnd, rmRegistry: IRenderMimeRegistry): void => { + const model = new MyModel(); + const widget = new ChatWidget({ model, rmRegistry }); + + app.shell.add(widget, 'right'); + } +}; + +export default [myChatExtension]; +``` + +## Optional parameters of the model + +The model accept some options in the constructor, which bring some additional +features to the chat. + +```typescript +interface IOptions { + /** + * Initial config for the chat widget. + */ + config?: IConfig; + + /** + * Commands registry. + */ + commands?: CommandRegistry; + + /** + * Active cell manager + */ + activeCellManager?: IActiveCellManager | null; +} +``` + +### config + +The config option can be used to set initial [settings](#chat-settings) to the model. + +Here is the definition of the config option: + +```typescript +interface IConfig { + /** + * Whether to send a message via Shift-Enter instead of Enter. + */ + sendWithShiftEnter?: boolean; + /** + * Last read message (no use yet). + */ + lastRead?: number; + /** + * Whether to stack consecutive messages from same user. + */ + stackMessages?: boolean; + /** + * Whether to enable or not the notifications on unread messages. + */ + unreadNotifications?: boolean; + /** + * Whether to enable or not the code toolbar. + */ + enableCodeToolbar?: boolean; +} +``` + +If the option is not provided, the default values will be used. + +The config can still be modified later using the setter, which allow partial config +object: + +```typescript +set config(value: Partial) +``` + +### commands + +The *commands* option is mandatory to handle the notifications in the chat. + +It is the `CommandRegistry` provided by the jupyterlab application. In the previous +example, the modification would be: + +{emphasize-lines="6,7"} + +```typescript +const myChatExtension: JupyterFrontEndPlugin = { + id: 'myExtension:plugin', + autoStart: true, + requires: [IRenderMimeRegistry], + activate: (app: JupyterFrontEnd, rmRegistry: IRenderMimeRegistry): void => { + const { commands } = app; + const model = new MyModel({ commands }); + const widget = new ChatWidget({ model, rmRegistry }); + + app.shell.add(widget, 'right'); + } +}; +``` + +### activeCellManager + +The *activeCellManager* is mandatory to include the [code toolbar](#code-toolbar) to the +chat. + +The active cell manager will ensure that a Notebook is visible, with an active cell, to +enable the buttons in the code toolbar. + +This active cell manager must be instantiate in the extension to be propagated to the +model. It requires the `INotebookTracker` token, provided by the *notebook-extension* of +jupyterlab. Again, in the previous example, the modification would be: + +{emphasize-lines="2,14,17,20,21,22,23,24"} + +```typescript +import { + ActiveCellManager, + ChatModel, + ChatWidget, + IChatMessage, + INewMessage +} from '@jupyter/chat'; + +... + +const myChatExtension: JupyterFrontEndPlugin = { + id: 'myExtension:plugin', + autoStart: true, + requires: [INotebookTracker, IRenderMimeRegistry], + activate: ( + app: JupyterFrontEnd, + notebookTracker: INotebookTracker, + rmRegistry: IRenderMimeRegistry + ): void => { + const activeCellManager = new ActiveCellManager({ + tracker: notebookTracker, + shell: app.shell + }); + const model = new MyModel({ activeCellManager }); + const widget = new ChatWidget({ model, rmRegistry }); + + app.shell.add(widget, 'right'); + } +}; +``` + +## Optional parameters of the widget + +### themeManager + +The `themeManager` allows to get the themes from jupyterlab. It is not mandatory but +some components would not be visible with some themes if it is not provided. + +This Theme manager can come from the `IThemeManager` token, provided by the +*apputils-extension* of jupyterlab. + +{emphasize-lines="1,7,11,14"} + +```typescript +import { IThemeManager } from '@jupyterlab/apputils'; + +const myChatExtension: JupyterFrontEndPlugin = { + id: 'myExtension:plugin', + autoStart: true, + requires: [IRenderMimeRegistry], + optional: [IThemeManager], + activate: ( + app: JupyterFrontEnd, + rmRegistry: IRenderMimeRegistry, + themeManager: IThemeManager | null + ): void => { + const model = new MyModel(); + const widget = new ChatWidget({ model, rmRegistry, themeManager }); + + app.shell.add(widget, 'right'); + } +}; +``` + +### autocompletionRegistry + +The `autocompletionRegistry` adds autocompletion feature to the chat input. This can be +useful for automating chat reading, like in [jupyter-ai](https://github.com/jupyterlab/jupyter-ai). + +It uses the `Autocomplete` from [Material UI](https://mui.com/material-ui/react-autocomplete/), +and can be customized using its [API](https://mui.com/material-ui/api/autocomplete/). + +Several *Autocompletion properties* objects (implementing `IAutocompletionCommandsProps`) can be +added to the registry. + +```{warning} +Currently, only one *autocompletion properties* object can be used for a chat widget, +even if several coexist in the registry.\ +The used one will be designed by the widget's option `autocompletionName`, otherwise a +default will be used. +``` + +An *autocompletion properties* object needs at least two properties: + +- **opener**, a character string that triggers the opening of the popup if entered at +the beginning of the input.\ + For example typing `/` could open propositions like (`/ask`, `/help`, ...). +- **commands**, a list of commands or a functions returning a list commands. + +```{tip} +The *autocompletion command* is an object containing at least a `label` property, but +which can also contain a `value` property. +``` + +As a simple example using a commands list (commands list from *jupyter-ai*): + +```typescript +import { + AutocompletionRegistry, + ChatModel, + ChatWidget, + IChatMessage, + IAutocompletionCommandsProps, + INewMessage +} from '@jupyter/chat'; + +... + +const options = ['/ask', '/clear', '/export', '/generate', '/help', '/learn']; +const autocompletionCommands: IAutocompletionCommandsProps = { + opener: '/', + commands: options.map(option => { + return { label: option }; + }) +}; + +const myChatExtension: JupyterFrontEndPlugin = { + id: 'myExtension:plugin', + autoStart: true, + requires: [IRenderMimeRegistry], + activate: (app: JupyterFrontEnd, rmRegistry: IRenderMimeRegistry): void => { + const autocompletionRegistry = new AutocompletionRegistry(); + autocompletionRegistry.add('default', autocompletionCommands); + + const model = new MyModel(); + const widget = new ChatWidget({ + model, + rmRegistry, + autocompletionRegistry + }); + + app.shell.add(widget, 'right'); + } +}; + +``` diff --git a/docs/source/developers/developing_extensions/index.md b/docs/source/developers/developing_extensions/index.md new file mode 100644 index 0000000..e2edec2 --- /dev/null +++ b/docs/source/developers/developing_extensions/index.md @@ -0,0 +1,15 @@ +# Developing extensions + +Other extensions can depends on one or the other of the packages. + +This section describe how an extension can provide a chat, and how an extension can +extend the features of a chat extension. + +```{toctree} +--- +maxdepth: 2 +--- + +./extension-providing-chat +./extending-extension +``` diff --git a/docs/source/developers/index.md b/docs/source/developers/index.md index 3176189..6194065 100644 --- a/docs/source/developers/index.md +++ b/docs/source/developers/index.md @@ -1,11 +1,15 @@ # Developers -This is the developers documentation. +This section is addressed to developers, and contains documentation about: + +- how to develop an extension providing a chat or extending a chat extension +- how to contribute to this project ```{toctree} --- maxdepth: 2 --- +./developing_extensions/index.md ./contributing/index.md ``` diff --git a/docs/source/users/index.md b/docs/source/users/index.md index e7f271e..facf34a 100644 --- a/docs/source/users/index.md +++ b/docs/source/users/index.md @@ -99,6 +99,8 @@ If enabled in [settings](#chat-settings), new unread messages generate a notific A down arrow in the messages list allow to navigate to the last message. This button is highlighted if some new messages are unread. +(code-toolbar)= + ### Code toolbar When code is inserted in a message, a toolbar is displayed under the code section (if diff --git a/pyproject.toml b/pyproject.toml index a7675cf..e49330a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,9 +30,10 @@ dynamic = ["version", "description", "authors", "urls", "keywords"] [project.optional-dependencies] docs = [ "jupyterlab>=4.0.0", - "sphinx", "myst-parser", - "pydata-sphinx-theme" + "pydata-sphinx-theme", + "sphinx", + "sphinx-copybutton" ] [tool.hatch.version] From 1e499ccc51716ebc8798420071b8088f31387489 Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Thu, 8 Aug 2024 17:37:07 +0200 Subject: [PATCH 6/8] Add some documentation about integrating jupyterlab-collaborative-chat --- docs/source/developers/contributing/index.md | 2 +- .../jupyterlab-collaborative-chat.md | 2 +- .../contributing/jupyterlab-ws-chat.md | 2 +- .../extending-extension.md | 1 - .../extension-providing-chat.md | 2 + .../developers/developing_extensions/index.md | 6 +- .../using-chat-extensions.md | 152 ++++++++++++++++++ docs/source/developers/index.md | 2 +- docs/source/users/index.md | 6 +- 9 files changed, 164 insertions(+), 11 deletions(-) delete mode 100644 docs/source/developers/developing_extensions/extending-extension.md create mode 100644 docs/source/developers/developing_extensions/using-chat-extensions.md diff --git a/docs/source/developers/contributing/index.md b/docs/source/developers/contributing/index.md index b0864d7..8ff6df4 100644 --- a/docs/source/developers/contributing/index.md +++ b/docs/source/developers/contributing/index.md @@ -1,6 +1,6 @@ # Contributing -This project is part of *jupyterlab* organization. +This project is included in *jupyterlab* organization. Before contributing to it, please read the [jupyter contributing guide](https://docs.jupyter.org/en/latest/contributing/content-contributor.html). diff --git a/docs/source/developers/contributing/jupyterlab-collaborative-chat.md b/docs/source/developers/contributing/jupyterlab-collaborative-chat.md index 13659ec..3bc588d 100644 --- a/docs/source/developers/contributing/jupyterlab-collaborative-chat.md +++ b/docs/source/developers/contributing/jupyterlab-collaborative-chat.md @@ -1,4 +1,4 @@ -# jupyterlab-collaborative-chat +# Collaborative chat The `jupyterlab-collaborative-chat` extension adds collaborative chats to jupyterlab. diff --git a/docs/source/developers/contributing/jupyterlab-ws-chat.md b/docs/source/developers/contributing/jupyterlab-ws-chat.md index ca672fb..246e3fe 100644 --- a/docs/source/developers/contributing/jupyterlab-ws-chat.md +++ b/docs/source/developers/contributing/jupyterlab-ws-chat.md @@ -1,4 +1,4 @@ -# jupyterlab-collaborative-chat +# Websocket chat The `jupyterlab-ws-chat` extension adds a chat panel relying on websocket for messaging. diff --git a/docs/source/developers/developing_extensions/extending-extension.md b/docs/source/developers/developing_extensions/extending-extension.md deleted file mode 100644 index 8d6c202..0000000 --- a/docs/source/developers/developing_extensions/extending-extension.md +++ /dev/null @@ -1 +0,0 @@ -# Extending a chat extension diff --git a/docs/source/developers/developing_extensions/extension-providing-chat.md b/docs/source/developers/developing_extensions/extension-providing-chat.md index c66488a..46c32ca 100644 --- a/docs/source/developers/developing_extensions/extension-providing-chat.md +++ b/docs/source/developers/developing_extensions/extension-providing-chat.md @@ -303,6 +303,8 @@ const myChatExtension: JupyterFrontEndPlugin = { }; ``` +(autocompletion-registry)= + ### autocompletionRegistry The `autocompletionRegistry` adds autocompletion feature to the chat input. This can be diff --git a/docs/source/developers/developing_extensions/index.md b/docs/source/developers/developing_extensions/index.md index e2edec2..b3c47b1 100644 --- a/docs/source/developers/developing_extensions/index.md +++ b/docs/source/developers/developing_extensions/index.md @@ -2,8 +2,8 @@ Other extensions can depends on one or the other of the packages. -This section describe how an extension can provide a chat, and how an extension can -extend the features of a chat extension. +This section describe how an extension can provide a chat, and how to make use of one +of the chat extensions in another extension. ```{toctree} --- @@ -11,5 +11,5 @@ maxdepth: 2 --- ./extension-providing-chat -./extending-extension +./using-chat-extensions ``` diff --git a/docs/source/developers/developing_extensions/using-chat-extensions.md b/docs/source/developers/developing_extensions/using-chat-extensions.md new file mode 100644 index 0000000..64d35d6 --- /dev/null +++ b/docs/source/developers/developing_extensions/using-chat-extensions.md @@ -0,0 +1,152 @@ +# Using a chat extension in another extension + +## Collaborative chat + +The collaborative chat depends on [jupyter collaboration](https://jupyterlab-realtime-collaboration.readthedocs.io/en/latest/index.html) +to exchange the messages. + +As a very brief summary, jupyter collaboration allows jupyterlab users to share a +document in real time, based on [CRDT](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type). +All changes made to the document are propagated to all users. These change can occur +from the frontend or from the backend. The shared document has an object representation +in Typescript (for the frontend) and in Python (for the backend). These representation +can be accessed and used by external extensions. + +### Exposed token + +`jupyterlab-collaborative-chat` expose several token that allow external extension to +interact with. + +#### IChatFactory + +This token is composed of: + +- `widgetConfig` object, to retrieve and change the current [settings](#chat-settings) +of all the chats +- `tracker`, a widget tracker that allow to track all the collaborative chats, and to +get the current one. + +```{caution} +Currently the widget tracker only track the main area widgets, not the one opened in the +side panel. +``` + +#### IChatPanel + +This token is a pointer to the left panel containing chats.\ +It can be useful to programmatically open chat in the panel for example, or to list the +opened chats. + +#### IAutocompletionRegistry + +this is the [autocompletion registry](#autocompletion-registry) used by the chat widgets. + +Autocompletion commands can be added to it, and than usable from the chat widget. + +### Interact with the chat from the backend + +`jupyter_collaboration` provides a websocket server to handle every shared document +on the server side. This websocket server allows to retrieve a shared document. + +In addition, when a shared document is created, an event is emitted. We can use that +event data to trigger a connection to the shared document. + +Below is an example of an server extension that respond every message written to any +collaborative chat: + +```python +import jupyter_collaboration +import time +import uuid +from functools import partial +from jupyter_collaboration.utils import JUPYTER_COLLABORATION_EVENTS_URI +from jupyter_events import EventLogger +from jupyter_server.extension.application import ExtensionApp +from pycrdt import ArrayEvent + +from .ychat import YChat + + +if int(jupyter_collaboration.__version__[0]) >= 3: + COLLAB_VERSION = 3 +else: + COLLAB_VERSION = 2 + +BOT = { + "username": str(uuid.uuid4()), + "name": "user", + "display_name": "User" +} + + +class MyExtension(ExtensionApp): + name = "my_extension" + app_name = "My Extension" + description = """ + this extension interact with collaborative chats + """ + + def initialize(self): + super().initialize() + self.event_logger = self.serverapp.web_app.settings["event_logger"] + self.event_logger.add_listener( + schema_id=JUPYTER_COLLABORATION_EVENTS_URI, + listener=self.connect_chat + ) + + async def connect_chat(self, logger: EventLogger, schema_id: str, data: dict) -> None: + if data["room"].startswith("text:chat:") \ + and data["action"] == "initialize"\ + and data["msg"] == "Room initialized": + + self.log.info(f"Collaborative chat server is listening for {data["room"]}") + chat = await self.get_chat(data["room"]) + callback = partial(self.on_change, chat) + chat.ymessages.observe(callback) + + async def get_chat(self, room_id: str) -> YChat: + if COLLAB_VERSION == 3: + collaboration = self.serverapp.web_app.settings["jupyter_server_ydoc"] + document = await collaboration.get_document( + room_id=room_id, + copy=False + ) + else: + collaboration = self.serverapp.web_app.settings["jupyter_collaboration"] + server = collaboration.ywebsocket_server + + room = await server.get_room(room_id) + document = room._document + return document + + def on_change(self, chat: YChat, events: ArrayEvent) -> None: + for change in events.delta: + if not "insert" in change.keys(): + continue + messages = change["insert"] + for message in messages: + if message["sender"] == BOT["username"] or message["raw_time"]: + continue + chat.create_task( + self.write_message( + chat, + f"Received:\n\n- **id**: *{message["id"]}*:\n\n- **body**: *{message["body"]}*") + ) + + async def write_message(self, chat: YChat, body: str) -> None: + bot = chat.get_user_by_name(BOT["name"]) + if not bot: + chat.set_user(BOT) + else: + BOT["username"] = bot["username"] + + chat.add_message({ + "type": "msg", + "body": body, + "id": str(uuid.uuid4()), + "time": time.time(), + "sender": BOT["username"], + "raw_time": False + }) + +``` diff --git a/docs/source/developers/index.md b/docs/source/developers/index.md index 6194065..92d0d42 100644 --- a/docs/source/developers/index.md +++ b/docs/source/developers/index.md @@ -2,7 +2,7 @@ This section is addressed to developers, and contains documentation about: -- how to develop an extension providing a chat or extending a chat extension +- how to develop an extension providing a chat or to include a chat extension - how to contribute to this project ```{toctree} diff --git a/docs/source/users/index.md b/docs/source/users/index.md index facf34a..95051dd 100644 --- a/docs/source/users/index.md +++ b/docs/source/users/index.md @@ -1,6 +1,6 @@ # Users -## jupyterlab-collaborative-chat +## Collaborative chat The `jupyterlab-collaborative-chat` extension adds collaborative chats to jupyterlab. @@ -61,7 +61,7 @@ area, like any other document. Opening a chat from the left panel will open it in the left panel. ``` -## jupyterlab-ws-chat +## Websocket chat The `jupyterlab-ws-chat` extension adds a chat panel relying on websocket for messaging. @@ -87,7 +87,7 @@ pip uninstall jupyterlab-ws-chat The chat can be opened from the left panel ![chat icon](../../../packages/jupyter-chat/style/icons/chat.svg){w=24px}. -## Using the chat +## Chat usage The chat UI is composed of a list of messages and an input to send new messages. From aa4c25ee201b08639e34654168e7d1987a980e71 Mon Sep 17 00:00:00 2001 From: Nicolas Brichet Date: Fri, 9 Aug 2024 10:19:23 +0200 Subject: [PATCH 7/8] Some corrections in the documentation --- docs/source/developers/contributing/index.md | 5 +- .../developers/contributing/jupyter-chat.md | 6 ++- .../jupyterlab-collaborative-chat.md | 9 ++-- .../contributing/jupyterlab-ws-chat.md | 5 +- .../extension-providing-chat.md | 45 +++++++++------- .../developers/developing_extensions/index.md | 4 +- .../using-chat-extensions.md | 44 +++++++-------- docs/source/developers/index.md | 4 +- docs/source/index.md | 8 +-- docs/source/users/index.md | 53 +++++++++++-------- 10 files changed, 105 insertions(+), 78 deletions(-) diff --git a/docs/source/developers/contributing/index.md b/docs/source/developers/contributing/index.md index 8ff6df4..52c1328 100644 --- a/docs/source/developers/contributing/index.md +++ b/docs/source/developers/contributing/index.md @@ -1,8 +1,9 @@ # Contributing -This project is included in *jupyterlab* organization. +We would be glad to review all incoming contributions. -Before contributing to it, please read the [jupyter contributing guide](https://docs.jupyter.org/en/latest/contributing/content-contributor.html). +This project is included in *jupyterlab* organization, please read the +[jupyter contributing guide](https://docs.jupyter.org/en/latest/contributing/content-contributor.html). ```{toctree} --- diff --git a/docs/source/developers/contributing/jupyter-chat.md b/docs/source/developers/contributing/jupyter-chat.md index 1253882..a9bbcae 100644 --- a/docs/source/developers/contributing/jupyter-chat.md +++ b/docs/source/developers/contributing/jupyter-chat.md @@ -1,8 +1,10 @@ # @jupyter/chat The `@jupyter/chat` package is a frontend package (React) compatible with jupyterlab. -It is not an extension, and cannot be used on its own. It can be used with one of the -extensions provided in this repo (jupyterlab-collaborative-chat or jupyterlab-ws-chat). +It is not an extension, and cannot be used on its own. It is designed to be used in an +extension.\ +In this repository, it is currently used in `jupyterlab-collaborative-chat` and +`jupyterlab-ws-chat`. ## Building the package diff --git a/docs/source/developers/contributing/jupyterlab-collaborative-chat.md b/docs/source/developers/contributing/jupyterlab-collaborative-chat.md index 3bc588d..1e2831b 100644 --- a/docs/source/developers/contributing/jupyterlab-collaborative-chat.md +++ b/docs/source/developers/contributing/jupyterlab-collaborative-chat.md @@ -4,7 +4,8 @@ The `jupyterlab-collaborative-chat` extension adds collaborative chats to jupyte ## Development installation -Installing this extension in development mode requires an environment with *python* and *nodejs*. +Installing this extension in development mode requires an environment with *python* and +*nodejs*. ```bash # In the following commands, 'mamba' can be replaced with 'conda' @@ -12,7 +13,7 @@ mamba create -n jupyter-chat python nodejs mamba activate jupyter-chat ``` -The following command install the extension in development mode: +The following commands install the extension in development mode: ```bash # Install the extension @@ -43,7 +44,7 @@ jlpm build:collaborative ### Unit tests -There are a few unit tests in *packages/jupyterlab-collaborative-chat/src/__tests__*. +There are a few unit tests in *packages/jupyterlab-collaborative-chat/src/\_\_tests\_\_*. They make use of [jest](https://jestjs.io/). @@ -56,7 +57,7 @@ jlpm test ### Integration tests -There are more integration tests, located in *packages/jupyterlab-collaborative-chat/ui-tests*. +The integration tests are located in *packages/jupyterlab-collaborative-chat/ui-tests*. They make use of [playwright](https://playwright.dev/). diff --git a/docs/source/developers/contributing/jupyterlab-ws-chat.md b/docs/source/developers/contributing/jupyterlab-ws-chat.md index 246e3fe..de1601b 100644 --- a/docs/source/developers/contributing/jupyterlab-ws-chat.md +++ b/docs/source/developers/contributing/jupyterlab-ws-chat.md @@ -4,7 +4,8 @@ The `jupyterlab-ws-chat` extension adds a chat panel relying on websocket for me ## Development installation -Installing this extension in development mode requires an environment with *python* and *nodejs*. +Installing this extension in development mode requires an environment with *python* and +*nodejs*. ```bash # In the following commands, 'mamba' can be replaced with 'conda' @@ -12,7 +13,7 @@ mamba create -n jupyter-chat python nodejs mamba activate jupyter-chat ``` -The following command install the extension in development mode: +The following commands install the extension in development mode: ```bash # Install the extension diff --git a/docs/source/developers/developing_extensions/extension-providing-chat.md b/docs/source/developers/developing_extensions/extension-providing-chat.md index 46c32ca..805910f 100644 --- a/docs/source/developers/developing_extensions/extension-providing-chat.md +++ b/docs/source/developers/developing_extensions/extension-providing-chat.md @@ -12,7 +12,7 @@ but is not tied to any messaging technology. It's up to the extension to choose which messaging technology to use. ``` -## Add the dependency +## Adding the dependency In the extension *package.json* file, the dependency must be added to the `dependencies` section. @@ -23,7 +23,8 @@ section. ## Including a chat in an extension -The package provide a jupyterlab widget (UI), that can be instantiated from the extension. +The package provide a jupyterlab widget (UI), that can be instantiated from the +extension. ```typescript import { ChatWidget } from '@jupyter/chat'; @@ -38,17 +39,17 @@ This widget needs at least 2 arguments, the [model](#model) and the The model is the entry point to use the chat in a javascript/typescript package. -A model is provided by the package, and already includes all the required method to +A model is provided by the package, and already includes all the required methods to interact with the UI part of the chat. -The extension has to provide a class extending the `@jupyter/chat` model, including the -method `addMessage()`. +The extension has to provide a class extending the `@jupyter/chat` model, implementing +at least the `addMessage()` method. This method is called when a user send a message using the input of the chat. It should contain the code that will dispatch the message through the messaging technology. -In the following example, the message is logged to the console and added in the message -list. +As an example, here is a simple model that log the message to the console and add it in +the message list. ```typescript import { ChatModel, IChatMessage, INewMessage } from '@jupyter/chat'; @@ -80,7 +81,7 @@ extension. ### A full example -The example below adds a new chat panel to the right. +The example below adds a new chat to the right panel. When a user sends a message, it is logged in the console and added to the message list. @@ -134,11 +135,12 @@ const myChatExtension: JupyterFrontEndPlugin = { }; export default [myChatExtension]; + ``` ## Optional parameters of the model -The model accept some options in the constructor, which bring some additional +The model accepts some options in the constructor, which bring some additional features to the chat. ```typescript @@ -229,12 +231,12 @@ const myChatExtension: JupyterFrontEndPlugin = { The *activeCellManager* is mandatory to include the [code toolbar](#code-toolbar) to the chat. -The active cell manager will ensure that a Notebook is visible, with an active cell, to +The active cell manager ensures that a Notebook is visible and has an active cell, to enable the buttons in the code toolbar. -This active cell manager must be instantiate in the extension to be propagated to the +This active cell manager must be instantiate in the extension, to be propagated to the model. It requires the `INotebookTracker` token, provided by the *notebook-extension* of -jupyterlab. Again, in the previous example, the modification would be: +jupyterlab. In the previous example, the modification would be: {emphasize-lines="2,14,17,20,21,22,23,24"} @@ -308,13 +310,15 @@ const myChatExtension: JupyterFrontEndPlugin = { ### autocompletionRegistry The `autocompletionRegistry` adds autocompletion feature to the chat input. This can be -useful for automating chat reading, like in [jupyter-ai](https://github.com/jupyterlab/jupyter-ai). +useful for automating chat messages reading, like in +[jupyter-ai](https://github.com/jupyterlab/jupyter-ai). -It uses the `Autocomplete` from [Material UI](https://mui.com/material-ui/react-autocomplete/), +It uses the `Autocomplete` from +[Material UI](https://mui.com/material-ui/react-autocomplete/), and can be customized using its [API](https://mui.com/material-ui/api/autocomplete/). -Several *Autocompletion properties* objects (implementing `IAutocompletionCommandsProps`) can be -added to the registry. +Several *Autocompletion properties* objects (implementing +`IAutocompletionCommandsProps`) can be added to the registry. ```{warning} Currently, only one *autocompletion properties* object can be used for a chat widget, @@ -335,7 +339,13 @@ The *autocompletion command* is an object containing at least a `label` property which can also contain a `value` property. ``` -As a simple example using a commands list (commands list from *jupyter-ai*): +```{tip} +Adding the `renderOption` in the property `props` of the *autocompletion command* allows +to customize the rendering of the entries. Some documentation about it can be found in +the [Material UI API](https://mui.com/material-ui/api/autocomplete/). +``` + +Here is a simple example using a commands list (commands list copied from *jupyter-ai*): ```typescript import { @@ -375,5 +385,4 @@ const myChatExtension: JupyterFrontEndPlugin = { app.shell.add(widget, 'right'); } }; - ``` diff --git a/docs/source/developers/developing_extensions/index.md b/docs/source/developers/developing_extensions/index.md index b3c47b1..da6dd3b 100644 --- a/docs/source/developers/developing_extensions/index.md +++ b/docs/source/developers/developing_extensions/index.md @@ -1,8 +1,8 @@ # Developing extensions -Other extensions can depends on one or the other of the packages. +Other extensions can depends on one or other of the packages. -This section describe how an extension can provide a chat, and how to make use of one +This section describes how an extension can provide a chat, and how to make use of one of the chat extensions in another extension. ```{toctree} diff --git a/docs/source/developers/developing_extensions/using-chat-extensions.md b/docs/source/developers/developing_extensions/using-chat-extensions.md index 64d35d6..765b81a 100644 --- a/docs/source/developers/developing_extensions/using-chat-extensions.md +++ b/docs/source/developers/developing_extensions/using-chat-extensions.md @@ -6,15 +6,16 @@ The collaborative chat depends on [jupyter collaboration](https://jupyterlab-rea to exchange the messages. As a very brief summary, jupyter collaboration allows jupyterlab users to share a -document in real time, based on [CRDT](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type). -All changes made to the document are propagated to all users. These change can occur -from the frontend or from the backend. The shared document has an object representation -in Typescript (for the frontend) and in Python (for the backend). These representation +document in real time, based on +[CRDT](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type). Any change +made to the document is propagated to all users. These change can occur from the +frontend or from the backend. The shared document has an object representation in +Typescript (for the frontend) and in Python (for the backend). These representations can be accessed and used by external extensions. ### Exposed token -`jupyterlab-collaborative-chat` expose several token that allow external extension to +`jupyterlab-collaborative-chat` expose several tokens that allow external extensions to interact with. #### IChatFactory @@ -23,25 +24,26 @@ This token is composed of: - `widgetConfig` object, to retrieve and change the current [settings](#chat-settings) of all the chats -- `tracker`, a widget tracker that allow to track all the collaborative chats, and to -get the current one. +- `tracker`, a widget tracker that allows to track all the collaborative chats, and to +retrieve the current one. ```{caution} -Currently the widget tracker only track the main area widgets, not the one opened in the -side panel. +Currently the widget tracker only track the main area widgets, not the ones opened in +the side panel. ``` #### IChatPanel This token is a pointer to the left panel containing chats.\ -It can be useful to programmatically open chat in the panel for example, or to list the +It can be used to programmatically open chat in the panel for example, or to list the opened chats. #### IAutocompletionRegistry -this is the [autocompletion registry](#autocompletion-registry) used by the chat widgets. +This is the [autocompletion registry](#autocompletion-registry) used by the chat +widgets. -Autocompletion commands can be added to it, and than usable from the chat widget. +Autocompletion commands can be added to it, and than usable from the chat input. ### Interact with the chat from the backend @@ -49,10 +51,10 @@ Autocompletion commands can be added to it, and than usable from the chat widget on the server side. This websocket server allows to retrieve a shared document. In addition, when a shared document is created, an event is emitted. We can use that -event data to trigger a connection to the shared document. +event to trigger a connection to the shared document. -Below is an example of an server extension that respond every message written to any -collaborative chat: +Here's an example of a server extension that responds to every message received in one +of the collaborative chats: ```python import jupyter_collaboration @@ -72,7 +74,7 @@ if int(jupyter_collaboration.__version__[0]) >= 3: else: COLLAB_VERSION = 2 -BOT = { +USER = { "username": str(uuid.uuid4()), "name": "user", "display_name": "User" @@ -125,7 +127,7 @@ class MyExtension(ExtensionApp): continue messages = change["insert"] for message in messages: - if message["sender"] == BOT["username"] or message["raw_time"]: + if message["sender"] == USER["username"] or message["raw_time"]: continue chat.create_task( self.write_message( @@ -134,18 +136,18 @@ class MyExtension(ExtensionApp): ) async def write_message(self, chat: YChat, body: str) -> None: - bot = chat.get_user_by_name(BOT["name"]) + bot = chat.get_user_by_name(USER["name"]) if not bot: - chat.set_user(BOT) + chat.set_user(USER) else: - BOT["username"] = bot["username"] + USER["username"] = bot["username"] chat.add_message({ "type": "msg", "body": body, "id": str(uuid.uuid4()), "time": time.time(), - "sender": BOT["username"], + "sender": USER["username"], "raw_time": False }) diff --git a/docs/source/developers/index.md b/docs/source/developers/index.md index 92d0d42..031b09f 100644 --- a/docs/source/developers/index.md +++ b/docs/source/developers/index.md @@ -1,8 +1,8 @@ # Developers -This section is addressed to developers, and contains documentation about: +This section is aimed at developers and contains documentation on : -- how to develop an extension providing a chat or to include a chat extension +- how to develop a chat extension or include one of the chat extensions - how to contribute to this project ```{toctree} diff --git a/docs/source/index.md b/docs/source/index.md index f141458..ad3781e 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -1,17 +1,17 @@ # jupyter-chat -Jupyter-chat will help you to easily include a chat in a jupyter based application. +Jupyter-chat allows you to easily include a chat in a jupyter based application. This documentation includes several projects all together: - `@jupyter/chat`, a front-end package (typescript), including all the components -required to build a chat. This package is designed to be used by an extension. +required to build a chat. This package is designed to be used in an extension. - `jupyterlab-collaborative-chat`, an extension built on top of `@jupyter/chat`, using -the collaborative edition as a messaging system. +the collaborative edition as messaging system. - `jupyterlab-ws-chat`, an other extension built on top of `@jupyter/chat`, using -websocket as a messaging system. +websocket as messaging system. ```{toctree} --- diff --git a/docs/source/users/index.md b/docs/source/users/index.md index 95051dd..8e8c4b2 100644 --- a/docs/source/users/index.md +++ b/docs/source/users/index.md @@ -6,7 +6,8 @@ The `jupyterlab-collaborative-chat` extension adds collaborative chats to jupyte ![collaborative chat](../_static/images/collaboarative-chat.png) -These chats use the collaborative edition in jupyterlab [jupyter_collaboration](https://jupyterlab-realtime-collaboration.readthedocs.io/en/latest/). +These chats use [jupyter_collaboration](https://jupyterlab-realtime-collaboration.readthedocs.io/en/latest/), +the collaborative edition of documents in jupyterlab. ### Install collaborative chat @@ -33,24 +34,24 @@ click on the button ![left panel new chat](../_static/images/left-panel-new-chat Validating the dialog will create the new chat. -Creating a chat actually creates a file in the tree files. +Creating a chat actually creates a file (shared document) in the tree files. ```{warning} Currently, the left panel can only discover chat files in the root directory (to avoid -computation issues in large tree files), so it only creates chat files in the root -directory. +computation issues in large nested tree files), so it only creates chat files in the +root directory. -Creating a chat using the menu or the command palette will create the file in the -current directory of the file browser. +On the other hand, creating a chat using the menu or the command palette will create +the file in the current directory of the file browser. ``` ### Open a chat There are also several ways to open a chat: -- opening the file from the file browser +- opening the file from the file browser (double click on it) - using the commands palette (`Ctrl+Shift+C`) -> *Open a chat*. It opens a dialog to -enter fill the file path +type the file path - from the left panel ![chat icon](../../../packages/jupyter-chat/style/icons/chat.svg){w=24px}, there is a dropdown listing the chat files, in the root directory only. @@ -63,7 +64,8 @@ Opening a chat from the left panel will open it in the left panel. ## Websocket chat -The `jupyterlab-ws-chat` extension adds a chat panel relying on websocket for messaging. +The `jupyterlab-ws-chat` extension adds a chat panel using websocket for messages +exchange. ```{warning} This extension is currently under development, and users may encounter issues with it. @@ -85,46 +87,55 @@ pip uninstall jupyterlab-ws-chat ### Open the chat -The chat can be opened from the left panel ![chat icon](../../../packages/jupyter-chat/style/icons/chat.svg){w=24px}. +The chat can be opened from the left panel +![chat icon](../../../packages/jupyter-chat/style/icons/chat.svg){w=24px}. ## Chat usage The chat UI is composed of a list of messages and an input to send new messages. -A message can be edited or deleted by its author, using a toolbar in the message. +A message can be edited or deleted by its author, using a dedicated toolbar in the +message. ### Notifications and navigation If enabled in [settings](#chat-settings), new unread messages generate a notification. -A down arrow in the messages list allow to navigate to the last message. This button is highlighted if some new messages are unread. +A down arrow in the messages list allow to navigate to the last message. This button is +highlighted if some new messages are unread. (code-toolbar)= ### Code toolbar -When code is inserted in a message, a toolbar is displayed under the code section (if -the options is set up from the [settings](#chat-settings)). +When code is inserted in a message, a toolbar is displayed under the code section (the +options must be set up from the [settings](#chat-settings)). -From this toolbar, the code can be copied to the clipboard: ![code toolbar copy](../_static/images/code-toolbar-copy.png){w=24px}. +From this toolbar, the code can be copied to the clipboard: +![code toolbar copy](../_static/images/code-toolbar-copy.png){w=24px}. -If a notebook is opened and visible, other actions are available: +If a notebook is opened and visible (and has an active cell), other actions are +available: -- copy the code to a new cell above the current one: ![code toolbar cell above](../_static/images/code-toolbar-above.png){w=24px} -- copy the the code to a new cell below the current one: ![code toolbar cell below](../_static/images/code-toolbar-below.png){w=24px} -- replace the content of the current cell with the code: ![code toolbar cell replace](../_static/images/code-toolbar-replace.png){w=24px} +- copy the code to a new cell above the active one: +![code toolbar cell above](../_static/images/code-toolbar-above.png){w=24px} +- copy the the code to a new cell below the active one: +![code toolbar cell below](../_static/images/code-toolbar-below.png){w=24px} +- replace the content of the active cell with the code: +![code toolbar cell replace](../_static/images/code-toolbar-replace.png){w=24px} (chat-settings)= ## Chat settings -Some jupyterlab settings are available for the chats (included with `jupyterlab-collaborative-chat` and `jupyterlab-ws-chat`), in the setting panel (menu `Settings->Settings Editor`), with the entry *Chat*. +Some jupyterlab settings are available for the chats in the setting panel +(menu `Settings->Settings Editor`), with the entry *Chat*. These settings includes: - **sendWithShiftEnter** - Whether to send a message via Shift-Enter instead of Enter.\ + Whether to send a message using Shift-Enter instead of Enter.\ Default: false - **stackMessages** From c69c3726683074f813dcc2d74d0169bad32bba76 Mon Sep 17 00:00:00 2001 From: Jeremy Tuloup Date: Wed, 14 Aug 2024 09:35:14 +0200 Subject: [PATCH 8/8] Minor typo fixes --- .../contributing/jupyterlab-collaborative-chat.md | 2 +- .../developing_extensions/extension-providing-chat.md | 8 ++++---- docs/source/developers/developing_extensions/index.md | 2 +- .../developing_extensions/using-chat-extensions.md | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/source/developers/contributing/jupyterlab-collaborative-chat.md b/docs/source/developers/contributing/jupyterlab-collaborative-chat.md index 1e2831b..a1a494f 100644 --- a/docs/source/developers/contributing/jupyterlab-collaborative-chat.md +++ b/docs/source/developers/contributing/jupyterlab-collaborative-chat.md @@ -32,7 +32,7 @@ pip uninstall jupyterlab-collaborative-chat ## Building the assets Changes in typescript sources of `@jupyter/chat` or `jupyterlab-collaborative-chat` must -be build again to be available in the jupyterlab. +be built again to be available in the jupyterlab. ```bash jlpm build:collaborative diff --git a/docs/source/developers/developing_extensions/extension-providing-chat.md b/docs/source/developers/developing_extensions/extension-providing-chat.md index 805910f..328a329 100644 --- a/docs/source/developers/developing_extensions/extension-providing-chat.md +++ b/docs/source/developers/developing_extensions/extension-providing-chat.md @@ -23,7 +23,7 @@ section. ## Including a chat in an extension -The package provide a jupyterlab widget (UI), that can be instantiated from the +The package provides a jupyterlab widget (UI), that can be instantiated from the extension. ```typescript @@ -45,10 +45,10 @@ interact with the UI part of the chat. The extension has to provide a class extending the `@jupyter/chat` model, implementing at least the `addMessage()` method. -This method is called when a user send a message using the input of the chat. It should +This method is called when a user sends a message using the input of the chat. It should contain the code that will dispatch the message through the messaging technology. -As an example, here is a simple model that log the message to the console and add it in +As an example, here is a simple model that logs the message to the console and adds it to the message list. ```typescript @@ -234,7 +234,7 @@ chat. The active cell manager ensures that a Notebook is visible and has an active cell, to enable the buttons in the code toolbar. -This active cell manager must be instantiate in the extension, to be propagated to the +This active cell manager must be instantiated in the extension, to be propagated to the model. It requires the `INotebookTracker` token, provided by the *notebook-extension* of jupyterlab. In the previous example, the modification would be: diff --git a/docs/source/developers/developing_extensions/index.md b/docs/source/developers/developing_extensions/index.md index da6dd3b..ae41ca7 100644 --- a/docs/source/developers/developing_extensions/index.md +++ b/docs/source/developers/developing_extensions/index.md @@ -1,6 +1,6 @@ # Developing extensions -Other extensions can depends on one or other of the packages. +Other extensions can depend on one or other of the packages. This section describes how an extension can provide a chat, and how to make use of one of the chat extensions in another extension. diff --git a/docs/source/developers/developing_extensions/using-chat-extensions.md b/docs/source/developers/developing_extensions/using-chat-extensions.md index 765b81a..a185629 100644 --- a/docs/source/developers/developing_extensions/using-chat-extensions.md +++ b/docs/source/developers/developing_extensions/using-chat-extensions.md @@ -8,7 +8,7 @@ to exchange the messages. As a very brief summary, jupyter collaboration allows jupyterlab users to share a document in real time, based on [CRDT](https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type). Any change -made to the document is propagated to all users. These change can occur from the +made to the document is propagated to all users. These changes can occur from the frontend or from the backend. The shared document has an object representation in Typescript (for the frontend) and in Python (for the backend). These representations can be accessed and used by external extensions. @@ -28,7 +28,7 @@ of all the chats retrieve the current one. ```{caution} -Currently the widget tracker only track the main area widgets, not the ones opened in +Currently the widget tracker only tracks the main area widgets, not the ones opened in the side panel. ``` @@ -43,7 +43,7 @@ opened chats. This is the [autocompletion registry](#autocompletion-registry) used by the chat widgets. -Autocompletion commands can be added to it, and than usable from the chat input. +Autocompletion commands can be added to it, and then be used from the chat input. ### Interact with the chat from the backend