@jupyter/collaboration 1.0.0-alpha.7 → 1.0.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -3,7 +3,8 @@
3
3
  * @module collaboration
4
4
  */
5
5
  export * from './tokens';
6
+ export * from './collaboratorspanel';
6
7
  export * from './cursors';
7
8
  export * from './menu';
9
+ export * from './sharedlink';
8
10
  export * from './userinfopanel';
9
- export * from './collaboratorspanel';
package/lib/index.js CHANGED
@@ -5,7 +5,8 @@
5
5
  * @module collaboration
6
6
  */
7
7
  export * from './tokens';
8
+ export * from './collaboratorspanel';
8
9
  export * from './cursors';
9
10
  export * from './menu';
11
+ export * from './sharedlink';
10
12
  export * from './userinfopanel';
11
- export * from './collaboratorspanel';
@@ -0,0 +1,18 @@
1
+ import { Dialog } from '@jupyterlab/apputils';
2
+ import { ITranslator } from '@jupyterlab/translation';
3
+ /**
4
+ * Shared link dialog options
5
+ */
6
+ export interface ISharedLinkDialogOptions {
7
+ /**
8
+ * Translation object.
9
+ */
10
+ translator?: ITranslator | null;
11
+ }
12
+ /**
13
+ * Show the shared link dialog
14
+ *
15
+ * @param options Shared link dialog options
16
+ * @returns Dialog result
17
+ */
18
+ export declare function showSharedLinkDialog({ translator }: ISharedLinkDialogOptions): Promise<Dialog.IResult<string>>;
@@ -0,0 +1,122 @@
1
+ // Copyright (c) Jupyter Development Team.
2
+ // Distributed under the terms of the Modified BSD License.
3
+ import { Dialog, showDialog } from '@jupyterlab/apputils';
4
+ import { PageConfig, URLExt } from '@jupyterlab/coreutils';
5
+ import { nullTranslator } from '@jupyterlab/translation';
6
+ import { Widget } from '@lumino/widgets';
7
+ /**
8
+ * Show the shared link dialog
9
+ *
10
+ * @param options Shared link dialog options
11
+ * @returns Dialog result
12
+ */
13
+ export async function showSharedLinkDialog({ translator }) {
14
+ const trans = (translator !== null && translator !== void 0 ? translator : nullTranslator).load('collaboration');
15
+ const token = PageConfig.getToken();
16
+ const url = new URL(URLExt.normalize(PageConfig.getUrl({
17
+ workspace: PageConfig.defaultWorkspace
18
+ })));
19
+ return showDialog({
20
+ title: trans.__('Share Jupyter Server Link'),
21
+ body: new SharedLinkBody(url.toString(), token, PageConfig.getOption('hubUser') !== '', trans),
22
+ buttons: [
23
+ Dialog.cancelButton(),
24
+ Dialog.okButton({
25
+ label: trans.__('Copy Link'),
26
+ caption: trans.__('Copy the link to the Jupyter Server')
27
+ })
28
+ ]
29
+ });
30
+ }
31
+ class SharedLinkBody extends Widget {
32
+ constructor(_url, _token, _behindHub, _trans) {
33
+ super();
34
+ this._url = _url;
35
+ this._token = _token;
36
+ this._behindHub = _behindHub;
37
+ this._trans = _trans;
38
+ this._tokenCheckbox = null;
39
+ this.onTokenChange = (e) => {
40
+ const target = e.target;
41
+ this.updateContent(target === null || target === void 0 ? void 0 : target.checked);
42
+ };
43
+ this._warning = document.createElement('div');
44
+ this.populateBody(this.node);
45
+ this.addClass('jp-shared-link-body');
46
+ }
47
+ /**
48
+ * Returns the input value.
49
+ */
50
+ getValue() {
51
+ var _a;
52
+ const withToken = ((_a = this._tokenCheckbox) === null || _a === void 0 ? void 0 : _a.checked) === true;
53
+ if (withToken) {
54
+ const url_ = new URL(this._url);
55
+ url_.searchParams.set('token', this._token);
56
+ return url_.toString();
57
+ }
58
+ else {
59
+ return this._url;
60
+ }
61
+ }
62
+ onAfterAttach(msg) {
63
+ var _a;
64
+ super.onAfterAttach(msg);
65
+ (_a = this._tokenCheckbox) === null || _a === void 0 ? void 0 : _a.addEventListener('change', this.onTokenChange);
66
+ }
67
+ onBeforeDetach(msg) {
68
+ var _a;
69
+ (_a = this._tokenCheckbox) === null || _a === void 0 ? void 0 : _a.removeEventListener('change', this.onTokenChange);
70
+ super.onBeforeDetach(msg);
71
+ }
72
+ updateContent(withToken) {
73
+ this._warning.innerHTML = '';
74
+ const urlInput = this.node.querySelector('input[readonly]');
75
+ if (withToken) {
76
+ if (urlInput) {
77
+ const url_ = new URL(this._url);
78
+ url_.searchParams.set('token', this._token.slice(0, 5));
79
+ urlInput.value = url_.toString() + '…';
80
+ }
81
+ this._warning.appendChild(document.createElement('h3')).textContent =
82
+ this._trans.__('Security warning!');
83
+ this._warning.insertAdjacentText('beforeend', this._trans.__('Anyone with this link has full access to your notebook server, including all your files!'));
84
+ this._warning.insertAdjacentHTML('beforeend', '<br>');
85
+ this._warning.insertAdjacentText('beforeend', this._trans.__('Please be careful who you share it with.'));
86
+ this._warning.insertAdjacentHTML('beforeend', '<br>');
87
+ if (this._behindHub) {
88
+ this._warning.insertAdjacentText('beforeend', // You can restart the server to revoke the token in a JupyterHub
89
+ this._trans.__('They will be able to access this server AS YOU.'));
90
+ this._warning.insertAdjacentHTML('beforeend', '<br>');
91
+ this._warning.insertAdjacentText('beforeend', this._trans.__('To revoke access, go to File -> Hub Control Panel, and restart your server.'));
92
+ }
93
+ else {
94
+ this._warning.insertAdjacentText('beforeend',
95
+ // Elsewhere, you *must* shut down your server - no way to revoke it
96
+ this._trans.__('Currently, there is no way to revoke access other than shutting down your server.'));
97
+ }
98
+ }
99
+ else {
100
+ if (urlInput) {
101
+ urlInput.value = this._url;
102
+ }
103
+ if (this._behindHub) {
104
+ this._warning.insertAdjacentText('beforeend', this._trans.__('Only users with `access:servers` permissions for this server will be able to use this link.'));
105
+ }
106
+ else {
107
+ this._warning.insertAdjacentText('beforeend', this._trans.__('Only authenticated users will be able to use this link.'));
108
+ }
109
+ }
110
+ }
111
+ populateBody(dialogBody) {
112
+ dialogBody.insertAdjacentHTML('afterbegin', `<input readonly value="${this._url}">`);
113
+ if (this._token) {
114
+ const label = dialogBody.appendChild(document.createElement('label'));
115
+ label.insertAdjacentHTML('beforeend', '<input type="checkbox">');
116
+ this._tokenCheckbox = label.firstChild;
117
+ label.insertAdjacentText('beforeend', this._trans.__('Include token in URL'));
118
+ dialogBody.insertAdjacentElement('beforeend', this._warning);
119
+ this.updateContent(false);
120
+ }
121
+ }
122
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jupyter/collaboration",
3
- "version": "1.0.0-alpha.7",
3
+ "version": "1.0.0-alpha.9",
4
4
  "description": "JupyterLab - Real-Time Collaboration Widgets",
5
5
  "homepage": "https://github.com/jupyterlab/jupyter_collaboration",
6
6
  "bugs": {
@@ -41,13 +41,13 @@
41
41
  "dependencies": {
42
42
  "@codemirror/state": "^6.2.0",
43
43
  "@codemirror/view": "^6.7.0",
44
- "@jupyterlab/apputils": "^4.0.0-beta.0",
45
- "@jupyterlab/coreutils": "^6.0.0-beta.0",
46
- "@jupyterlab/services": "^7.0.0-beta.0",
47
- "@jupyterlab/ui-components": "^4.0.0-beta.0",
48
- "@lumino/coreutils": "^2.0.0",
44
+ "@jupyterlab/apputils": "^4.0.0",
45
+ "@jupyterlab/coreutils": "^6.0.0",
46
+ "@jupyterlab/services": "^7.0.0",
47
+ "@jupyterlab/ui-components": "^4.0.0",
48
+ "@lumino/coreutils": "^2.1.0",
49
49
  "@lumino/virtualdom": "^2.0.0",
50
- "@lumino/widgets": "^2.0.0",
50
+ "@lumino/widgets": "^2.1.0",
51
51
  "react": "^18.2.0",
52
52
  "y-protocols": "^1.0.5",
53
53
  "yjs": "^13.5.40"
@@ -55,7 +55,7 @@
55
55
  "devDependencies": {
56
56
  "@types/react": "^18.0.27",
57
57
  "rimraf": "^4.1.2",
58
- "typescript": "~5.0.2"
58
+ "typescript": "~5.0.4"
59
59
  },
60
60
  "publishConfig": {
61
61
  "access": "public"
package/style/base.css CHANGED
@@ -5,3 +5,7 @@
5
5
 
6
6
  @import url('./menu.css');
7
7
  @import url('./sidepanel.css');
8
+
9
+ .jp-shared-link-body {
10
+ user-select: none;
11
+ }
package/lib/utils.d.ts DELETED
@@ -1,8 +0,0 @@
1
- /**
2
- * Call the API extension
3
- *
4
- * @param endPoint API REST end point for the extension
5
- * @param init Initial values for the request
6
- * @returns The response body interpreted as JSON
7
- */
8
- export declare function requestAPI<T>(endPoint?: string, init?: RequestInit): Promise<T>;
package/lib/utils.js DELETED
@@ -1,35 +0,0 @@
1
- // Copyright (c) Jupyter Development Team.
2
- // Distributed under the terms of the Modified BSD License.
3
- import { URLExt } from '@jupyterlab/coreutils';
4
- import { ServerConnection } from '@jupyterlab/services';
5
- /**
6
- * Call the API extension
7
- *
8
- * @param endPoint API REST end point for the extension
9
- * @param init Initial values for the request
10
- * @returns The response body interpreted as JSON
11
- */
12
- export async function requestAPI(endPoint = '', init = {}) {
13
- const settings = ServerConnection.makeSettings();
14
- const requestUrl = URLExt.join(settings.baseUrl, endPoint);
15
- let response;
16
- try {
17
- response = await ServerConnection.makeRequest(requestUrl, init, settings);
18
- }
19
- catch (error) {
20
- throw new ServerConnection.NetworkError(error);
21
- }
22
- let data = await response.text();
23
- if (data.length > 0) {
24
- try {
25
- data = JSON.parse(data);
26
- }
27
- catch (error) {
28
- console.log('Not a JSON response body.', response);
29
- }
30
- }
31
- if (!response.ok) {
32
- throw new ServerConnection.ResponseError(response, data.message || data);
33
- }
34
- return data;
35
- }