@jupyter/docprovider 3.0.0-beta.3 → 3.0.0-beta.4

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.
@@ -0,0 +1,11 @@
1
+ import { ReactWidget } from '@jupyterlab/apputils';
2
+ import { IForkProvider } from './ydrive';
3
+ export declare class TimelineWidget extends ReactWidget {
4
+ private apiURL;
5
+ private provider;
6
+ private contentType;
7
+ private format;
8
+ constructor(apiURL: string, provider: IForkProvider, contentType: string, format: string);
9
+ render(): JSX.Element;
10
+ updateContent(apiURL: string, provider: IForkProvider): void;
11
+ }
@@ -0,0 +1,27 @@
1
+ /* -----------------------------------------------------------------------------
2
+ | Copyright (c) Jupyter Development Team.
3
+ | Distributed under the terms of the Modified BSD License.
4
+ |----------------------------------------------------------------------------*/
5
+ import { ReactWidget } from '@jupyterlab/apputils';
6
+ import { TimelineSliderComponent } from './component';
7
+ import * as React from 'react';
8
+ export class TimelineWidget extends ReactWidget {
9
+ constructor(apiURL, provider, contentType, format) {
10
+ super();
11
+ this.apiURL = apiURL;
12
+ this.provider = provider;
13
+ this.contentType = contentType;
14
+ this.format = format;
15
+ this.addClass('jp-timelineSliderWrapper');
16
+ }
17
+ render() {
18
+ return (React.createElement(TimelineSliderComponent, { key: this.apiURL, apiURL: this.apiURL, provider: this.provider, contentType: this.contentType, format: this.format }));
19
+ }
20
+ updateContent(apiURL, provider) {
21
+ this.apiURL = apiURL;
22
+ this.provider = provider;
23
+ this.contentType = this.provider.contentType;
24
+ this.format = this.provider.format;
25
+ this.update();
26
+ }
27
+ }
@@ -1,25 +1,18 @@
1
1
  import { User } from '@jupyterlab/services';
2
2
  import { IDisposable } from '@lumino/disposable';
3
- import { IStream } from '@lumino/signaling';
4
3
  import { IAwareness } from '@jupyter/ydoc';
5
4
  import { WebsocketProvider } from 'y-websocket';
6
- import { IAwarenessProvider } from './tokens';
7
5
  export interface IContent {
8
6
  type: string;
9
7
  body: string;
10
8
  }
11
- export interface IChatMessage {
12
- sender: string;
13
- timestamp: number;
14
- content: IContent;
15
- }
16
9
  /**
17
10
  * A class to provide Yjs synchronization over WebSocket.
18
11
  *
19
12
  * We specify custom messages that the server can interpret. For reference please look in yjs_ws_server.
20
13
  *
21
14
  */
22
- export declare class WebSocketAwarenessProvider extends WebsocketProvider implements IAwarenessProvider, IDisposable {
15
+ export declare class WebSocketAwarenessProvider extends WebsocketProvider implements IDisposable {
23
16
  /**
24
17
  * Construct a new WebSocketAwarenessProvider
25
18
  *
@@ -27,22 +20,11 @@ export declare class WebSocketAwarenessProvider extends WebsocketProvider implem
27
20
  */
28
21
  constructor(options: WebSocketAwarenessProvider.IOptions);
29
22
  get isDisposed(): boolean;
30
- /**
31
- * A signal to subscribe for incoming messages.
32
- */
33
- get messageStream(): IStream<this, IChatMessage>;
34
23
  dispose(): void;
35
- /**
36
- * Send a message to every collaborator.
37
- *
38
- * @param msg message
39
- */
40
- sendMessage(msg: string): void;
41
24
  private _onUserChanged;
42
25
  private _isDisposed;
43
26
  private _user;
44
27
  private _awareness;
45
- private _messageStream;
46
28
  }
47
29
  /**
48
30
  * A namespace for WebSocketAwarenessProvider statics.
package/lib/awareness.js CHANGED
@@ -2,11 +2,7 @@
2
2
  | Copyright (c) Jupyter Development Team.
3
3
  | Distributed under the terms of the Modified BSD License.
4
4
  |----------------------------------------------------------------------------*/
5
- import { Stream } from '@lumino/signaling';
6
- import * as decoding from 'lib0/decoding';
7
- import * as encoding from 'lib0/encoding';
8
5
  import { WebsocketProvider } from 'y-websocket';
9
- import { MessageType } from './utils';
10
6
  /**
11
7
  * A class to provide Yjs synchronization over WebSocket.
12
8
  *
@@ -30,22 +26,10 @@ export class WebSocketAwarenessProvider extends WebsocketProvider {
30
26
  .then(() => this._onUserChanged(this._user))
31
27
  .catch(e => console.error(e));
32
28
  this._user.userChanged.connect(this._onUserChanged, this);
33
- this._messageStream = new Stream(this);
34
- this.messageHandlers[MessageType.CHAT] = (encoder, decoder, provider, emitSynced, messageType) => {
35
- const content = decoding.readVarString(decoder);
36
- const data = JSON.parse(content);
37
- this._messageStream.emit(data);
38
- };
39
29
  }
40
30
  get isDisposed() {
41
31
  return this._isDisposed;
42
32
  }
43
- /**
44
- * A signal to subscribe for incoming messages.
45
- */
46
- get messageStream() {
47
- return this._messageStream;
48
- }
49
33
  dispose() {
50
34
  if (this._isDisposed) {
51
35
  return;
@@ -54,21 +38,6 @@ export class WebSocketAwarenessProvider extends WebsocketProvider {
54
38
  this._isDisposed = true;
55
39
  this.destroy();
56
40
  }
57
- /**
58
- * Send a message to every collaborator.
59
- *
60
- * @param msg message
61
- */
62
- sendMessage(msg) {
63
- const data = {
64
- type: 'text',
65
- body: msg
66
- };
67
- const encoder = encoding.createEncoder();
68
- encoding.writeVarUint(encoder, MessageType.CHAT);
69
- encoding.writeVarString(encoder, JSON.stringify(data));
70
- this.ws.send(encoding.toUint8Array(encoder));
71
- }
72
41
  _onUserChanged(user) {
73
42
  this._awareness.setLocalStateField('user', user.identity);
74
43
  }
@@ -0,0 +1,11 @@
1
+ import React from 'react';
2
+ import '../style/slider.css';
3
+ import { IForkProvider } from './ydrive';
4
+ type Props = {
5
+ apiURL: string;
6
+ provider: IForkProvider;
7
+ contentType: string;
8
+ format: string;
9
+ };
10
+ export declare const TimelineSliderComponent: React.FC<Props>;
11
+ export {};
@@ -0,0 +1,135 @@
1
+ /* -----------------------------------------------------------------------------
2
+ | Copyright (c) Jupyter Development Team.
3
+ | Distributed under the terms of the Modified BSD License.
4
+ |----------------------------------------------------------------------------*/
5
+ import React, { useState, useRef } from 'react';
6
+ import '../style/slider.css';
7
+ import { requestUndoRedo, requestDocSession, requestDocumentTimeline } from './requests';
8
+ import { historyIcon } from '@jupyterlab/ui-components';
9
+ import { Notification } from '@jupyterlab/apputils';
10
+ export const TimelineSliderComponent = ({ apiURL, provider, contentType, format }) => {
11
+ const [data, setData] = useState({
12
+ roomId: '',
13
+ timestamps: [],
14
+ forkRoom: '',
15
+ sessionId: ''
16
+ });
17
+ const [currentTimestampIndex, setCurrentTimestampIndex] = useState(data.timestamps.length - 1);
18
+ const [toggle, setToggle] = useState(false);
19
+ const [isBtn, setIsBtn] = useState(false);
20
+ const isFirstChange = useRef(true);
21
+ const isFirstSliderChange = useRef(true);
22
+ const sessionRef = useRef(null);
23
+ async function fetchTimeline(notebookPath) {
24
+ try {
25
+ if (isFirstChange.current) {
26
+ const response = await requestDocumentTimeline(format, contentType, notebookPath);
27
+ if (!response.ok) {
28
+ if (response.status === 404) {
29
+ throw new Error('Not found');
30
+ }
31
+ else if (response.status === 503) {
32
+ throw new Error('WebSocket closed');
33
+ }
34
+ else {
35
+ throw new Error(`Failed to fetch data: ${response.statusText}`);
36
+ }
37
+ }
38
+ const text = await response.text();
39
+ let data = { roomId: '', timestamps: [], forkRoom: '', sessionId: '' };
40
+ if (text) {
41
+ Notification.warning('Document is now in read-only mode. Changes will not be saved.', { autoClose: 2500 });
42
+ data = JSON.parse(text);
43
+ setData(data);
44
+ setCurrentTimestampIndex(data.timestamps.length - 1);
45
+ provider.connectToForkDoc(data.forkRoom, data.sessionId);
46
+ sessionRef.current = await requestDocSession(format, contentType, extractFilenameFromURL(apiURL));
47
+ }
48
+ setToggle(true);
49
+ isFirstChange.current = false;
50
+ return data;
51
+ }
52
+ }
53
+ catch (error) {
54
+ console.error('Error fetching data:', error);
55
+ }
56
+ }
57
+ const handleRestore = async () => {
58
+ if (!sessionRef.current) {
59
+ console.error('Session is not initialized');
60
+ return;
61
+ }
62
+ const response = await requestUndoRedo(`${sessionRef.current.format}:${sessionRef.current.type}:${sessionRef.current.fileId}`, 'restore', 0, data.forkRoom);
63
+ if (response.code === 200) {
64
+ Notification.success(response.status, { autoClose: 4000 });
65
+ provider.reconnect();
66
+ setToggle(false);
67
+ isFirstChange.current = true;
68
+ }
69
+ else {
70
+ Notification.error(response.status, { autoClose: 4000 });
71
+ }
72
+ };
73
+ const handleSliderChange = async (event) => {
74
+ const currentTimestamp = parseInt(event.target.value);
75
+ const steps = Math.abs(currentTimestamp - currentTimestampIndex);
76
+ try {
77
+ const action = determineAction(currentTimestamp);
78
+ setCurrentTimestampIndex(currentTimestamp);
79
+ if (isFirstSliderChange.current) {
80
+ setIsBtn(true);
81
+ isFirstSliderChange.current = false;
82
+ }
83
+ if (!sessionRef.current) {
84
+ console.error('Session is not initialized');
85
+ return;
86
+ }
87
+ await requestUndoRedo(`${sessionRef.current.format}:${sessionRef.current.type}:${sessionRef.current.fileId}`, action, steps, data.forkRoom);
88
+ }
89
+ catch (error) {
90
+ console.error('Error fetching or applying updates:', error);
91
+ }
92
+ };
93
+ function determineAction(currentTimestamp) {
94
+ return currentTimestamp < currentTimestampIndex ? 'undo' : 'redo';
95
+ }
96
+ function extractFilenameFromURL(url) {
97
+ try {
98
+ const parsedURL = new URL(url);
99
+ const pathname = parsedURL.pathname;
100
+ const segments = pathname.split('/');
101
+ return segments.slice(4 - segments.length).join('/');
102
+ }
103
+ catch (error) {
104
+ console.error('Invalid URL:', error);
105
+ return '';
106
+ }
107
+ }
108
+ const formatTimestamp = (timestamp) => {
109
+ const date = new Date(timestamp * 1000);
110
+ const year = date.getFullYear();
111
+ const month = String(date.getMonth() + 1).padStart(2, '0');
112
+ const day = String(date.getDate()).padStart(2, '0');
113
+ const hours = String(date.getHours()).padStart(2, '0');
114
+ const minutes = String(date.getMinutes()).padStart(2, '0');
115
+ const seconds = String(date.getSeconds()).padStart(2, '0');
116
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
117
+ };
118
+ return (React.createElement("div", { className: "jp-sliderContainer" },
119
+ React.createElement("div", { onClick: () => {
120
+ fetchTimeline(extractFilenameFromURL(apiURL));
121
+ }, className: "jp-mod-highlighted", title: "Document Timeline" },
122
+ React.createElement(historyIcon.react, { marginRight: "4px" })),
123
+ toggle && (React.createElement("div", { className: "jp-timestampDisplay" },
124
+ React.createElement("input", { type: "range", min: 0, max: data.timestamps.length - 1, value: currentTimestampIndex, onChange: handleSliderChange, className: "jp-Slider" }),
125
+ React.createElement("div", null,
126
+ React.createElement("strong", null,
127
+ extractFilenameFromURL(apiURL).split('/').pop(),
128
+ " "),
129
+ ' '),
130
+ isBtn && (React.createElement("div", { className: "jp-restoreBtnContainer" },
131
+ React.createElement("button", { onClick: handleRestore, className: "jp-ToolbarButtonComponent jp-restoreBtn" },
132
+ "Restore version",
133
+ ' ',
134
+ formatTimestamp(data.timestamps[currentTimestampIndex]))))))));
135
+ };
package/lib/index.d.ts CHANGED
@@ -8,3 +8,4 @@ export * from './requests';
8
8
  export * from './ydrive';
9
9
  export * from './yprovider';
10
10
  export * from './tokens';
11
+ export * from './TimelineSlider';
package/lib/index.js CHANGED
@@ -12,3 +12,4 @@ export * from './requests';
12
12
  export * from './ydrive';
13
13
  export * from './yprovider';
14
14
  export * from './tokens';
15
+ export * from './TimelineSlider';
package/lib/requests.d.ts CHANGED
@@ -21,3 +21,5 @@ export interface ISessionModel {
21
21
  sessionId: string;
22
22
  }
23
23
  export declare function requestDocSession(format: string, type: string, path: string): Promise<ISessionModel>;
24
+ export declare function requestDocumentTimeline(format: string, type: string, path: string): Promise<any>;
25
+ export declare function requestUndoRedo(roomid: string, action: 'undo' | 'redo' | 'restore', steps: number, forkRoom: string): Promise<any>;
package/lib/requests.js CHANGED
@@ -9,6 +9,8 @@ import { ServerConnection } from '@jupyterlab/services';
9
9
  * See https://github.com/jupyterlab/jupyter_collaboration
10
10
  */
11
11
  const DOC_SESSION_URL = 'api/collaboration/session';
12
+ const DOC_FORK_URL = 'api/collaboration/undo_redo';
13
+ const TIMELINE_URL = 'api/collaboration/timeline';
12
14
  export async function requestDocSession(format, type, path) {
13
15
  const settings = ServerConnection.makeSettings();
14
16
  const url = URLExt.join(settings.baseUrl, DOC_SESSION_URL, encodeURIComponent(path));
@@ -37,3 +39,45 @@ export async function requestDocSession(format, type, path) {
37
39
  }
38
40
  return data;
39
41
  }
42
+ export async function requestDocumentTimeline(format, type, path) {
43
+ const settings = ServerConnection.makeSettings();
44
+ let url = URLExt.join(settings.baseUrl, TIMELINE_URL, path);
45
+ url = url.concat(`?format=${format}&&type=${type}`);
46
+ const body = {
47
+ method: 'GET'
48
+ };
49
+ let response;
50
+ try {
51
+ response = await ServerConnection.makeRequest(url, body, settings);
52
+ }
53
+ catch (error) {
54
+ throw new ServerConnection.NetworkError(error);
55
+ }
56
+ return response;
57
+ }
58
+ export async function requestUndoRedo(roomid, action, steps, forkRoom) {
59
+ const settings = ServerConnection.makeSettings();
60
+ let url = URLExt.join(settings.baseUrl, DOC_FORK_URL, encodeURIComponent(roomid));
61
+ url = url.concat(`?action=${action}&&steps=${steps}&&forkRoom=${forkRoom}`);
62
+ const body = { method: 'PUT' };
63
+ let response;
64
+ try {
65
+ response = await ServerConnection.makeRequest(url, body, settings);
66
+ }
67
+ catch (error) {
68
+ throw new ServerConnection.NetworkError(error);
69
+ }
70
+ let data = await response.text();
71
+ if (data.length > 0) {
72
+ try {
73
+ data = JSON.parse(data);
74
+ }
75
+ catch (error) {
76
+ console.log('Not a JSON response body.', response);
77
+ }
78
+ }
79
+ if (!response.ok) {
80
+ throw new ServerConnection.ResponseError(response, data.message || data);
81
+ }
82
+ return data;
83
+ }
package/lib/tokens.d.ts CHANGED
@@ -1,8 +1,7 @@
1
1
  import { DocumentChange, YDocument } from '@jupyter/ydoc';
2
2
  import { Contents } from '@jupyterlab/services';
3
3
  import { Token } from '@lumino/coreutils';
4
- import { IStream } from '@lumino/signaling';
5
- import { IChatMessage } from './awareness';
4
+ import { WebSocketProvider } from './yprovider';
6
5
  /**
7
6
  * The collaborative drive.
8
7
  */
@@ -24,6 +23,7 @@ export interface ICollaborativeDrive extends Contents.IDrive {
24
23
  * SharedModel factory for the YDrive.
25
24
  */
26
25
  readonly sharedModelFactory: ISharedModelFactory;
26
+ readonly providers: Map<string, WebSocketProvider>;
27
27
  }
28
28
  /**
29
29
  * Yjs sharedModel factory for real-time collaboration.
@@ -37,18 +37,3 @@ export interface ISharedModelFactory extends Contents.ISharedFactory {
37
37
  */
38
38
  registerDocumentFactory(type: Contents.ContentType, factory: SharedDocumentFactory): void;
39
39
  }
40
- /**
41
- * A provider interface for global awareness features.
42
- */
43
- export interface IAwarenessProvider {
44
- /**
45
- * A signal to subscribe for incoming messages.
46
- */
47
- readonly messageStream: IStream<this, IChatMessage>;
48
- /**
49
- * Send a message to every collaborator.
50
- *
51
- * @param msg message
52
- */
53
- sendMessage(msg: string): void;
54
- }
package/lib/ydrive.d.ts CHANGED
@@ -1,8 +1,15 @@
1
1
  import { TranslationBundle } from '@jupyterlab/translation';
2
2
  import { Contents, Drive, User } from '@jupyterlab/services';
3
3
  import { ISignal } from '@lumino/signaling';
4
+ import { WebSocketProvider } from './yprovider';
4
5
  import { ICollaborativeDrive, ISharedModelFactory } from './tokens';
5
6
  import { Awareness } from 'y-protocols/awareness';
7
+ export interface IForkProvider {
8
+ connectToForkDoc: (forkRoomId: string, sessionId: string) => Promise<void>;
9
+ reconnect: () => Promise<void>;
10
+ contentType: string;
11
+ format: string;
12
+ }
6
13
  /**
7
14
  * A Collaborative implementation for an `IDrive`, talking to the
8
15
  * server using the Jupyter REST API and a WebSocket connection.
@@ -18,6 +25,7 @@ export declare class YDrive extends Drive implements ICollaborativeDrive {
18
25
  * SharedModel factory for the YDrive.
19
26
  */
20
27
  readonly sharedModelFactory: ISharedModelFactory;
28
+ get providers(): Map<string, WebSocketProvider>;
21
29
  /**
22
30
  * Dispose of the resources held by the manager.
23
31
  */
package/lib/ydrive.js CHANGED
@@ -103,6 +103,9 @@ export class YDrive extends Drive {
103
103
  this._ydriveFileChanged.emit(change);
104
104
  });
105
105
  }
106
+ get providers() {
107
+ return this._providers;
108
+ }
106
109
  /**
107
110
  * Dispose of the resources held by the manager.
108
111
  */
@@ -2,6 +2,8 @@ import { User } from '@jupyterlab/services';
2
2
  import { TranslationBundle } from '@jupyterlab/translation';
3
3
  import { IDisposable } from '@lumino/disposable';
4
4
  import { DocumentChange, YDocument } from '@jupyter/ydoc';
5
+ import { WebsocketProvider as YWebsocketProvider } from 'y-websocket';
6
+ import { IForkProvider } from './ydrive';
5
7
  /**
6
8
  * An interface for a document provider.
7
9
  */
@@ -17,7 +19,7 @@ export interface IDocumentProvider extends IDisposable {
17
19
  * We specify custom messages that the server can interpret. For reference please look in yjs_ws_server.
18
20
  *
19
21
  */
20
- export declare class WebSocketProvider implements IDocumentProvider {
22
+ export declare class WebSocketProvider implements IDocumentProvider, IForkProvider {
21
23
  /**
22
24
  * Construct a new WebSocketProvider
23
25
  *
@@ -32,11 +34,17 @@ export declare class WebSocketProvider implements IDocumentProvider {
32
34
  * A promise that resolves when the document provider is ready.
33
35
  */
34
36
  get ready(): Promise<void>;
37
+ get contentType(): string;
38
+ get format(): string;
35
39
  /**
36
40
  * Dispose of the resources held by the object.
37
41
  */
38
42
  dispose(): void;
43
+ reconnect(): Promise<void>;
39
44
  private _connect;
45
+ connectToForkDoc(forkRoomId: string, sessionId: string): Promise<void>;
46
+ get wsProvider(): YWebsocketProvider | null;
47
+ private _disconnect;
40
48
  private _onUserChanged;
41
49
  private _onConnectionClosed;
42
50
  private _onSync;
package/lib/yprovider.js CHANGED
@@ -72,6 +72,12 @@ export class WebSocketProvider {
72
72
  get ready() {
73
73
  return this._ready.promise;
74
74
  }
75
+ get contentType() {
76
+ return this._contentType;
77
+ }
78
+ get format() {
79
+ return this._format;
80
+ }
75
81
  /**
76
82
  * Dispose of the resources held by the object.
77
83
  */
@@ -84,8 +90,13 @@ export class WebSocketProvider {
84
90
  (_a = this._yWebsocketProvider) === null || _a === void 0 ? void 0 : _a.off('connection-close', this._onConnectionClosed);
85
91
  (_b = this._yWebsocketProvider) === null || _b === void 0 ? void 0 : _b.off('sync', this._onSync);
86
92
  (_c = this._yWebsocketProvider) === null || _c === void 0 ? void 0 : _c.destroy();
93
+ this._disconnect();
87
94
  Signal.clearData(this);
88
95
  }
96
+ async reconnect() {
97
+ this._disconnect();
98
+ this._connect();
99
+ }
89
100
  async _connect() {
90
101
  const session = await requestDocSession(this._format, this._contentType, this._path);
91
102
  this._yWebsocketProvider = new YWebsocketProvider(this._serverUrl, `${session.format}:${session.type}:${session.fileId}`, this._sharedModel.ydoc, {
@@ -96,6 +107,24 @@ export class WebSocketProvider {
96
107
  this._yWebsocketProvider.on('sync', this._onSync);
97
108
  this._yWebsocketProvider.on('connection-close', this._onConnectionClosed);
98
109
  }
110
+ async connectToForkDoc(forkRoomId, sessionId) {
111
+ this._disconnect();
112
+ this._yWebsocketProvider = new YWebsocketProvider(this._serverUrl, forkRoomId, this._sharedModel.ydoc, {
113
+ disableBc: true,
114
+ params: { sessionId },
115
+ awareness: this._awareness
116
+ });
117
+ }
118
+ get wsProvider() {
119
+ return this._yWebsocketProvider;
120
+ }
121
+ _disconnect() {
122
+ var _a, _b, _c;
123
+ (_a = this._yWebsocketProvider) === null || _a === void 0 ? void 0 : _a.off('connection-close', this._onConnectionClosed);
124
+ (_b = this._yWebsocketProvider) === null || _b === void 0 ? void 0 : _b.off('sync', this._onSync);
125
+ (_c = this._yWebsocketProvider) === null || _c === void 0 ? void 0 : _c.destroy();
126
+ this._yWebsocketProvider = null;
127
+ }
99
128
  _onUserChanged(user) {
100
129
  this._awareness.setLocalStateField('user', user.identity);
101
130
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jupyter/docprovider",
3
- "version": "3.0.0-beta.3",
3
+ "version": "3.0.0-beta.4",
4
4
  "description": "JupyterLab - Document Provider",
5
5
  "homepage": "https://github.com/jupyterlab/jupyter-collaboration",
6
6
  "bugs": {
@@ -1,8 +1,6 @@
1
1
  /* -----------------------------------------------------------------------------
2
2
  | Copyright (c) Jupyter Development Team.
3
3
  | Distributed under the terms of the Modified BSD License.
4
- |----------------------------------------------------------------------------*/
5
- export var MessageType;
6
- (function (MessageType) {
7
- MessageType[MessageType["CHAT"] = 125] = "CHAT";
8
- })(MessageType || (MessageType = {}));
4
+ |---------------------------------------------------------------------------- */
5
+
6
+ @import url('./slider.css');
@@ -0,0 +1,6 @@
1
+ /* -----------------------------------------------------------------------------
2
+ | Copyright (c) Jupyter Development Team.
3
+ | Distributed under the terms of the Modified BSD License.
4
+ |---------------------------------------------------------------------------- */
5
+
6
+ @import url('./base.css');
package/style/index.js ADDED
@@ -0,0 +1,6 @@
1
+ /*-----------------------------------------------------------------------------
2
+ | Copyright (c) Jupyter Development Team.
3
+ | Distributed under the terms of the Modified BSD License.
4
+ |----------------------------------------------------------------------------*/
5
+
6
+ import './base.css';
@@ -0,0 +1,35 @@
1
+ /* -----------------------------------------------------------------------------
2
+ | Copyright (c) Jupyter Development Team.
3
+ | Distributed under the terms of the Modified BSD License.
4
+ |---------------------------------------------------------------------------- */
5
+
6
+ .jp-timelineSliderWrapper .jp-sliderContainer{
7
+ display: flex;
8
+ align-items: center;
9
+ }
10
+
11
+ .jp-Slider {
12
+ height: 4.5px
13
+ }
14
+
15
+ #jp-slider-status-bar {
16
+ display: flex;
17
+ }
18
+
19
+ .jp-timestampDisplay {
20
+ display: flex;
21
+ flex-direction: row;
22
+ align-items: center;
23
+ gap: 6px;
24
+ }
25
+
26
+ .jp-restoreBtnContainer {
27
+ width: 192px;
28
+ }
29
+
30
+ .jp-ToolbarButtonComponent.jp-restoreBtn {
31
+ cursor: pointer;
32
+ color: var(--jp-layout-color2);
33
+ width: 100%;
34
+ background: var(--jp-accept-color-normal)
35
+ }
package/lib/utils.d.ts DELETED
@@ -1,3 +0,0 @@
1
- export declare enum MessageType {
2
- CHAT = 125
3
- }