@jupyter/docprovider-extension 5.0.0-alpha.0 → 5.0.0-rc.0
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/conflictDiffWidget.d.ts +39 -0
- package/lib/conflictDiffWidget.js +184 -0
- package/lib/yprovider.js +77 -5
- package/package.json +23 -18
- package/style/conflictDiff.css +37 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type * as nbformat from '@jupyterlab/nbformat';
|
|
2
|
+
import type { CodeEditor } from '@jupyterlab/codeeditor';
|
|
3
|
+
import type { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
4
|
+
import type { TranslationBundle } from '@jupyterlab/translation';
|
|
5
|
+
import { Widget } from '@lumino/widgets';
|
|
6
|
+
import 'nbdime/lib/styles/variables.css';
|
|
7
|
+
import 'nbdime/lib/styles/common.css';
|
|
8
|
+
import 'nbdime/lib/styles/diff.css';
|
|
9
|
+
import 'nbdime/lib/upstreaming/flexpanel.css';
|
|
10
|
+
import 'nbdime/lib/common/collapsible.css';
|
|
11
|
+
import '../style/conflictDiff.css';
|
|
12
|
+
/**
|
|
13
|
+
* A widget that shows a side-by-side diff between two in-memory notebooks.
|
|
14
|
+
* Uses nbdime's NotebookDiffModel/NotebookDiffWidget for rendering.
|
|
15
|
+
*
|
|
16
|
+
* Because nbdime bundles its own @lumino/widgets (separate from JupyterLab's),
|
|
17
|
+
* we extend Widget and append the nbdime widget's DOM node directly instead
|
|
18
|
+
* of using Panel.addWidget(), which would fail due to the class identity mismatch.
|
|
19
|
+
*/
|
|
20
|
+
export declare class ConflictDiffWidget extends Widget {
|
|
21
|
+
private _nbdiffWidget;
|
|
22
|
+
private _editorFactory;
|
|
23
|
+
private _rendermime;
|
|
24
|
+
private _trans;
|
|
25
|
+
constructor(options: ConflictDiffWidget.IOptions);
|
|
26
|
+
create(options: ConflictDiffWidget.ICreateOptions): Promise<void>;
|
|
27
|
+
dispose(): void;
|
|
28
|
+
}
|
|
29
|
+
export declare namespace ConflictDiffWidget {
|
|
30
|
+
interface IOptions {
|
|
31
|
+
translator?: TranslationBundle;
|
|
32
|
+
editorFactory: CodeEditor.Factory;
|
|
33
|
+
rendermime: IRenderMimeRegistry;
|
|
34
|
+
}
|
|
35
|
+
interface ICreateOptions {
|
|
36
|
+
base: nbformat.INotebookContent;
|
|
37
|
+
remote: nbformat.INotebookContent;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) Jupyter Development Team.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { nullTranslator } from '@jupyterlab/translation';
|
|
6
|
+
import { Widget } from '@lumino/widgets';
|
|
7
|
+
import { NotebookDiffModel } from 'nbdime/lib/diff/model';
|
|
8
|
+
import { NotebookDiffWidget } from 'nbdime/lib/diff/widget';
|
|
9
|
+
import 'nbdime/lib/styles/variables.css';
|
|
10
|
+
import 'nbdime/lib/styles/common.css';
|
|
11
|
+
import 'nbdime/lib/styles/diff.css';
|
|
12
|
+
import 'nbdime/lib/upstreaming/flexpanel.css';
|
|
13
|
+
import 'nbdime/lib/common/collapsible.css';
|
|
14
|
+
import '../style/conflictDiff.css';
|
|
15
|
+
/**
|
|
16
|
+
* A widget that shows a side-by-side diff between two in-memory notebooks.
|
|
17
|
+
* Uses nbdime's NotebookDiffModel/NotebookDiffWidget for rendering.
|
|
18
|
+
*
|
|
19
|
+
* Because nbdime bundles its own @lumino/widgets (separate from JupyterLab's),
|
|
20
|
+
* we extend Widget and append the nbdime widget's DOM node directly instead
|
|
21
|
+
* of using Panel.addWidget(), which would fail due to the class identity mismatch.
|
|
22
|
+
*/
|
|
23
|
+
export class ConflictDiffWidget extends Widget {
|
|
24
|
+
constructor(options) {
|
|
25
|
+
var _a;
|
|
26
|
+
super();
|
|
27
|
+
this._nbdiffWidget = null;
|
|
28
|
+
this.addClass('nbdime-Widget');
|
|
29
|
+
this._editorFactory = options.editorFactory;
|
|
30
|
+
this._rendermime = options.rendermime;
|
|
31
|
+
this._trans =
|
|
32
|
+
(_a = options.translator) !== null && _a !== void 0 ? _a : nullTranslator.load('jupyter_collaboration');
|
|
33
|
+
this.node.style.display = 'flex';
|
|
34
|
+
this.node.style.flexDirection = 'column';
|
|
35
|
+
this.node.style.height = '100%';
|
|
36
|
+
this.node.style.overflow = 'auto';
|
|
37
|
+
}
|
|
38
|
+
async create(options) {
|
|
39
|
+
const diff = _diffNotebooks(options.base, options.remote);
|
|
40
|
+
const model = new NotebookDiffModel(options.base, diff);
|
|
41
|
+
const diffWidget = new NotebookDiffWidget({
|
|
42
|
+
model,
|
|
43
|
+
rendermime: this._rendermime,
|
|
44
|
+
editorFactory: this._editorFactory
|
|
45
|
+
});
|
|
46
|
+
await diffWidget.init();
|
|
47
|
+
this._nbdiffWidget = diffWidget;
|
|
48
|
+
this.node.appendChild(_makeHeaderNode(this._trans.__('Server version'), this._trans.__('Local version')));
|
|
49
|
+
this.node.appendChild(diffWidget.node);
|
|
50
|
+
}
|
|
51
|
+
dispose() {
|
|
52
|
+
var _a;
|
|
53
|
+
if (this.isDisposed) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
(_a = this._nbdiffWidget) === null || _a === void 0 ? void 0 : _a.dispose();
|
|
57
|
+
super.dispose();
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function _makeHeaderNode(baseLabel, remoteLabel) {
|
|
61
|
+
const node = document.createElement('div');
|
|
62
|
+
node.className = 'jp-conflict-diff-header nbdime-Diff';
|
|
63
|
+
const banner = document.createElement('div');
|
|
64
|
+
banner.className = 'nbdime-header-banner';
|
|
65
|
+
const base = document.createElement('span');
|
|
66
|
+
base.className = 'nbdime-header-base';
|
|
67
|
+
base.textContent = baseLabel;
|
|
68
|
+
const remote = document.createElement('span');
|
|
69
|
+
remote.className = 'nbdime-header-remote';
|
|
70
|
+
remote.textContent = remoteLabel;
|
|
71
|
+
banner.appendChild(base);
|
|
72
|
+
banner.appendChild(remote);
|
|
73
|
+
node.appendChild(banner);
|
|
74
|
+
return node;
|
|
75
|
+
}
|
|
76
|
+
function _getSource(cell) {
|
|
77
|
+
const src = cell.source;
|
|
78
|
+
return Array.isArray(src) ? src.join('') : src;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Compute index pairs (baseIdx, remoteIdx) for the longest common subsequence
|
|
82
|
+
* of cell IDs between two lists.
|
|
83
|
+
*/
|
|
84
|
+
function _lcs(a, b) {
|
|
85
|
+
const m = a.length, n = b.length;
|
|
86
|
+
const dp = Array.from({ length: m + 1 }, () => new Array(n + 1).fill(0));
|
|
87
|
+
for (let i = 1; i <= m; i++) {
|
|
88
|
+
for (let j = 1; j <= n; j++) {
|
|
89
|
+
dp[i][j] =
|
|
90
|
+
a[i - 1] === b[j - 1]
|
|
91
|
+
? dp[i - 1][j - 1] + 1
|
|
92
|
+
: Math.max(dp[i - 1][j], dp[i][j - 1]);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const result = [];
|
|
96
|
+
let i = m, j = n;
|
|
97
|
+
while (i > 0 && j > 0) {
|
|
98
|
+
if (a[i - 1] === b[j - 1]) {
|
|
99
|
+
result.unshift([i - 1, j - 1]);
|
|
100
|
+
i--;
|
|
101
|
+
j--;
|
|
102
|
+
}
|
|
103
|
+
else if (dp[i - 1][j] > dp[i][j - 1]) {
|
|
104
|
+
i--;
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
j--;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return result;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Compute a notebook-level IDiffEntry[] for use with NotebookDiffModel.
|
|
114
|
+
* Matches cells by id using LCS; changed-source cells appear as remove+add.
|
|
115
|
+
*/
|
|
116
|
+
function _diffNotebooks(base, remote) {
|
|
117
|
+
const baseCells = base.cells;
|
|
118
|
+
const remoteCells = remote.cells;
|
|
119
|
+
const baseIds = baseCells.map(c => { var _a; return (_a = c.id) !== null && _a !== void 0 ? _a : ''; });
|
|
120
|
+
const remoteIds = remoteCells.map(c => { var _a; return (_a = c.id) !== null && _a !== void 0 ? _a : ''; });
|
|
121
|
+
const matches = _lcs(baseIds, remoteIds);
|
|
122
|
+
const cellsDiff = [];
|
|
123
|
+
let bi = 0, ri = 0;
|
|
124
|
+
for (const [baseIdx, remoteIdx] of matches) {
|
|
125
|
+
if (bi < baseIdx) {
|
|
126
|
+
cellsDiff.push({ op: 'removerange', key: bi, length: baseIdx - bi });
|
|
127
|
+
}
|
|
128
|
+
if (ri < remoteIdx) {
|
|
129
|
+
cellsDiff.push({
|
|
130
|
+
op: 'addrange',
|
|
131
|
+
key: bi,
|
|
132
|
+
valuelist: remoteCells.slice(ri, remoteIdx)
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
const sourceChanged = _getSource(baseCells[baseIdx]) !== _getSource(remoteCells[remoteIdx]);
|
|
136
|
+
const metaChanged = JSON.stringify(baseCells[baseIdx].metadata) !==
|
|
137
|
+
JSON.stringify(remoteCells[remoteIdx].metadata);
|
|
138
|
+
if (sourceChanged) {
|
|
139
|
+
cellsDiff.push({ op: 'removerange', key: baseIdx, length: 1 });
|
|
140
|
+
cellsDiff.push({
|
|
141
|
+
op: 'addrange',
|
|
142
|
+
key: baseIdx,
|
|
143
|
+
valuelist: [remoteCells[remoteIdx]]
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
else if (metaChanged) {
|
|
147
|
+
cellsDiff.push({
|
|
148
|
+
op: 'patch',
|
|
149
|
+
key: baseIdx,
|
|
150
|
+
diff: [
|
|
151
|
+
{
|
|
152
|
+
op: 'replace',
|
|
153
|
+
key: 'metadata',
|
|
154
|
+
value: remoteCells[remoteIdx].metadata
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
bi = baseIdx + 1;
|
|
160
|
+
ri = remoteIdx + 1;
|
|
161
|
+
}
|
|
162
|
+
if (bi < baseCells.length) {
|
|
163
|
+
cellsDiff.push({
|
|
164
|
+
op: 'removerange',
|
|
165
|
+
key: bi,
|
|
166
|
+
length: baseCells.length - bi
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (ri < remoteCells.length) {
|
|
170
|
+
cellsDiff.push({
|
|
171
|
+
op: 'addrange',
|
|
172
|
+
key: bi,
|
|
173
|
+
valuelist: remoteCells.slice(ri)
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
const topDiff = [];
|
|
177
|
+
if (cellsDiff.length > 0) {
|
|
178
|
+
topDiff.push({ op: 'patch', key: 'cells', diff: cellsDiff });
|
|
179
|
+
}
|
|
180
|
+
if (JSON.stringify(base.metadata) !== JSON.stringify(remote.metadata)) {
|
|
181
|
+
topDiff.push({ op: 'replace', key: 'metadata', value: remote.metadata });
|
|
182
|
+
}
|
|
183
|
+
return topDiff;
|
|
184
|
+
}
|
package/lib/yprovider.js
CHANGED
|
@@ -5,6 +5,12 @@
|
|
|
5
5
|
import { ITranslator } from '@jupyterlab/translation';
|
|
6
6
|
import { WebSocketProvider, WebSocketAwarenessProvider, IAwarenessProviderFactory, IDocumentProviderFactory } from '@jupyter/docprovider';
|
|
7
7
|
import { URLExt } from '@jupyterlab/coreutils';
|
|
8
|
+
import { MainAreaWidget, ToolbarButton } from '@jupyterlab/apputils';
|
|
9
|
+
import { saveIcon, undoIcon } from '@jupyterlab/ui-components';
|
|
10
|
+
import { IEditorServices } from '@jupyterlab/codeeditor';
|
|
11
|
+
import { IDocumentManager } from '@jupyterlab/docmanager';
|
|
12
|
+
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
|
|
13
|
+
import { ConflictDiffWidget } from './conflictDiffWidget';
|
|
8
14
|
/**
|
|
9
15
|
* The plugin ID for settings.
|
|
10
16
|
*/
|
|
@@ -16,10 +22,61 @@ class WebSocketDocumentProviderFactory {
|
|
|
16
22
|
constructor(options) {
|
|
17
23
|
this._trans = options.translator;
|
|
18
24
|
this._commands = options.commands;
|
|
25
|
+
this._docManager = options.docManager;
|
|
26
|
+
this._shell = options.shell;
|
|
27
|
+
this._contents = options.contents;
|
|
28
|
+
this._editorFactory = options.editorFactory;
|
|
29
|
+
this._rendermime = options.rendermime;
|
|
19
30
|
}
|
|
20
31
|
create(options) {
|
|
32
|
+
const shell = this._shell;
|
|
33
|
+
const contents = this._contents;
|
|
34
|
+
const editorFactory = this._editorFactory;
|
|
35
|
+
const rendermime = this._rendermime;
|
|
36
|
+
const path = options.path;
|
|
37
|
+
const onConflictShowNotebookDiff = async (localContent) => {
|
|
38
|
+
const serverModel = await contents.get(path, { content: true });
|
|
39
|
+
const widget = new ConflictDiffWidget({
|
|
40
|
+
translator: this._trans,
|
|
41
|
+
editorFactory,
|
|
42
|
+
rendermime
|
|
43
|
+
});
|
|
44
|
+
await widget.create({
|
|
45
|
+
base: serverModel.content,
|
|
46
|
+
remote: localContent
|
|
47
|
+
});
|
|
48
|
+
const main = new MainAreaWidget({ content: widget });
|
|
49
|
+
main.title.label = this._trans.__('Conflict diff: %1', path);
|
|
50
|
+
main.title.closable = true;
|
|
51
|
+
main.toolbar.addItem('revertToRemote', new ToolbarButton({
|
|
52
|
+
icon: undoIcon,
|
|
53
|
+
label: this._trans.__('Revert to Remote'),
|
|
54
|
+
tooltip: this._trans.__('Discard local changes and reload the server version'),
|
|
55
|
+
onClick: () => {
|
|
56
|
+
var _a;
|
|
57
|
+
const context = (_a = this._docManager.findWidget(path)) === null || _a === void 0 ? void 0 : _a.context;
|
|
58
|
+
if (context && !context.isDisposed) {
|
|
59
|
+
void context.revert();
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}));
|
|
63
|
+
main.toolbar.addItem('saveLocalAs', new ToolbarButton({
|
|
64
|
+
icon: saveIcon,
|
|
65
|
+
label: this._trans.__('Save Local As'),
|
|
66
|
+
tooltip: this._trans.__('Save the local version with a new name'),
|
|
67
|
+
onClick: () => {
|
|
68
|
+
var _a;
|
|
69
|
+
const context = (_a = this._docManager.findWidget(path)) === null || _a === void 0 ? void 0 : _a.context;
|
|
70
|
+
if (context && !context.isDisposed) {
|
|
71
|
+
void context.saveAs();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}));
|
|
75
|
+
shell.add(main, 'main');
|
|
76
|
+
shell.activateById(main.id);
|
|
77
|
+
};
|
|
21
78
|
return new WebSocketProvider({
|
|
22
|
-
path
|
|
79
|
+
path,
|
|
23
80
|
contentType: options.contentType,
|
|
24
81
|
format: options.format,
|
|
25
82
|
model: options.model,
|
|
@@ -27,7 +84,12 @@ class WebSocketDocumentProviderFactory {
|
|
|
27
84
|
translator: this._trans,
|
|
28
85
|
serverSettings: options.serverSettings,
|
|
29
86
|
onConflictSaveAs: () => this._commands.execute('docmanager:save-as'),
|
|
30
|
-
onConflictRevert: () => this._commands.execute('docmanager:reload')
|
|
87
|
+
onConflictRevert: () => this._commands.execute('docmanager:reload'),
|
|
88
|
+
// The diff view is notebook-specific (uses nbdime), so only offer it
|
|
89
|
+
// when the document being opened is a notebook.
|
|
90
|
+
onConflictShowDiff: options.contentType === 'notebook'
|
|
91
|
+
? onConflictShowNotebookDiff
|
|
92
|
+
: undefined
|
|
31
93
|
});
|
|
32
94
|
}
|
|
33
95
|
}
|
|
@@ -51,14 +113,24 @@ class WebSocketAwarenessProviderFactory {
|
|
|
51
113
|
export const documentProviderFactoryPlugin = {
|
|
52
114
|
id: PLUGIN_ID + '-document-factory',
|
|
53
115
|
description: 'Provides a WebSocket document provider factory.',
|
|
54
|
-
requires: [
|
|
116
|
+
requires: [
|
|
117
|
+
ITranslator,
|
|
118
|
+
IEditorServices,
|
|
119
|
+
IRenderMimeRegistry,
|
|
120
|
+
IDocumentManager
|
|
121
|
+
],
|
|
55
122
|
optional: [],
|
|
56
123
|
provides: IDocumentProviderFactory,
|
|
57
|
-
activate: async (app, translator) => {
|
|
124
|
+
activate: async (app, translator, editorServices, rendermime, docManager) => {
|
|
58
125
|
const trans = translator.load('jupyter_collaboration');
|
|
59
126
|
return new WebSocketDocumentProviderFactory({
|
|
60
127
|
translator: trans,
|
|
61
|
-
commands: app.commands
|
|
128
|
+
commands: app.commands,
|
|
129
|
+
docManager,
|
|
130
|
+
shell: app.shell,
|
|
131
|
+
contents: app.serviceManager.contents,
|
|
132
|
+
editorFactory: editorServices.factoryService.newInlineEditor,
|
|
133
|
+
rendermime
|
|
62
134
|
});
|
|
63
135
|
}
|
|
64
136
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jupyter/docprovider-extension",
|
|
3
|
-
"version": "5.0.0-
|
|
3
|
+
"version": "5.0.0-rc.0",
|
|
4
4
|
"description": "JupyterLab - Collaborative Shared Models",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"jupyter",
|
|
@@ -41,8 +41,8 @@
|
|
|
41
41
|
"build:lib": "tsc --sourceMap",
|
|
42
42
|
"build:lib:prod": "tsc",
|
|
43
43
|
"build:prod": "jlpm run clean && jlpm run build:lib:prod && jlpm run build:labextension",
|
|
44
|
-
"build:labextension": "jupyter
|
|
45
|
-
"build:labextension:dev": "jupyter
|
|
44
|
+
"build:labextension": "jupyter-builder build .",
|
|
45
|
+
"build:labextension:dev": "jupyter-builder build --development True .",
|
|
46
46
|
"clean": "jlpm run clean:lib",
|
|
47
47
|
"clean:lib": "rimraf lib tsconfig.tsbuildinfo node_modules",
|
|
48
48
|
"clean:labextension": "rimraf ../../projects/jupyter-docprovider/jupyter_docprovider/labextension",
|
|
@@ -50,29 +50,34 @@
|
|
|
50
50
|
"install:extension": "jlpm run build",
|
|
51
51
|
"watch": "run-p watch:src watch:labextension",
|
|
52
52
|
"watch:src": "tsc -w",
|
|
53
|
-
"watch:labextension": "jupyter
|
|
53
|
+
"watch:labextension": "jupyter-builder watch ."
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@jupyter/collaborative-drive": "^5.0.0-
|
|
57
|
-
"@jupyter/docprovider": "^5.0.0-
|
|
58
|
-
"@jupyter/ydoc": "^4.0.0
|
|
59
|
-
"@jupyterlab/application": "^4.6.0
|
|
60
|
-
"@jupyterlab/apputils": "^4.7.0
|
|
61
|
-
"@jupyterlab/
|
|
62
|
-
"@jupyterlab/
|
|
63
|
-
"@jupyterlab/
|
|
64
|
-
"@jupyterlab/
|
|
65
|
-
"@jupyterlab/
|
|
66
|
-
"@jupyterlab/
|
|
67
|
-
"@jupyterlab/
|
|
68
|
-
"@jupyterlab/
|
|
56
|
+
"@jupyter/collaborative-drive": "^5.0.0-rc.0",
|
|
57
|
+
"@jupyter/docprovider": "^5.0.0-rc.0",
|
|
58
|
+
"@jupyter/ydoc": "^4.0.0",
|
|
59
|
+
"@jupyterlab/application": "^4.6.0",
|
|
60
|
+
"@jupyterlab/apputils": "^4.7.0",
|
|
61
|
+
"@jupyterlab/codeeditor": "^4.6.0",
|
|
62
|
+
"@jupyterlab/docmanager": "^4.6.0",
|
|
63
|
+
"@jupyterlab/docregistry": "^4.6.0",
|
|
64
|
+
"@jupyterlab/filebrowser": "^4.6.0",
|
|
65
|
+
"@jupyterlab/fileeditor": "^4.6.0",
|
|
66
|
+
"@jupyterlab/logconsole": "^4.6.0",
|
|
67
|
+
"@jupyterlab/nbformat": "^4.6.0",
|
|
68
|
+
"@jupyterlab/notebook": "^4.6.0",
|
|
69
|
+
"@jupyterlab/rendermime": "^4.6.0",
|
|
70
|
+
"@jupyterlab/settingregistry": "^4.6.0",
|
|
71
|
+
"@jupyterlab/translation": "^4.6.0",
|
|
72
|
+
"@jupyterlab/ui-components": "^4.6.0",
|
|
69
73
|
"@lumino/commands": "^2.3.2",
|
|
74
|
+
"nbdime": "^7.0.4",
|
|
70
75
|
"y-protocols": "^1.0.5",
|
|
71
76
|
"y-websocket": "^1.3.15",
|
|
72
77
|
"yjs": "^13.5.40"
|
|
73
78
|
},
|
|
74
79
|
"devDependencies": {
|
|
75
|
-
"@
|
|
80
|
+
"@jupyter/builder": "^1.2.0",
|
|
76
81
|
"@types/react": "~18.3.1",
|
|
77
82
|
"npm-run-all": "^4.1.5",
|
|
78
83
|
"rimraf": "^4.1.2",
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/* -----------------------------------------------------------------------------
|
|
2
|
+
| Copyright (c) Jupyter Development Team.
|
|
3
|
+
| Distributed under the terms of the Modified BSD License.
|
|
4
|
+
|---------------------------------------------------------------------------- */
|
|
5
|
+
|
|
6
|
+
.jp-conflict-diff-header.nbdime-Diff {
|
|
7
|
+
border-bottom: var(--jp-border-width) solid var(--jp-toolbar-border-color);
|
|
8
|
+
box-shadow: var(--jp-toolbar-box-shadow);
|
|
9
|
+
background: var(--jp-toolbar-background);
|
|
10
|
+
flex: 0 0 auto;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.jp-conflict-diff-header .nbdime-header-banner {
|
|
14
|
+
display: grid;
|
|
15
|
+
grid-template-columns: 47% 6% 47%;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.jp-conflict-diff-header .nbdime-header-base {
|
|
19
|
+
grid-column: 1;
|
|
20
|
+
display: inline-block;
|
|
21
|
+
background-color: var(--jp-diff-deleted-color0);
|
|
22
|
+
padding: 0 4px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.jp-conflict-diff-header .nbdime-header-remote {
|
|
26
|
+
grid-column: 3;
|
|
27
|
+
display: inline-block;
|
|
28
|
+
background-color: var(--jp-diff-added-color0);
|
|
29
|
+
padding: 0 4px;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/* diff.css hides .jp-Cellrow-metadata on added/deleted cells by default.
|
|
33
|
+
Override that so metadata changes are always visible in the conflict diff. */
|
|
34
|
+
.nbdime-Widget .jp-Diff-added .jp-Cellrow-metadata,
|
|
35
|
+
.nbdime-Widget .jp-Diff-deleted .jp-Cellrow-metadata {
|
|
36
|
+
display: block !important;
|
|
37
|
+
}
|