@theia/notebook 1.54.0 → 1.55.0-next.25
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/browser/contributions/notebook-cell-actions-contribution.d.ts.map +1 -1
- package/lib/browser/contributions/notebook-cell-actions-contribution.js +54 -9
- package/lib/browser/contributions/notebook-cell-actions-contribution.js.map +1 -1
- package/lib/browser/contributions/notebook-status-bar-contribution.d.ts +7 -9
- package/lib/browser/contributions/notebook-status-bar-contribution.d.ts.map +1 -1
- package/lib/browser/contributions/notebook-status-bar-contribution.js +21 -33
- package/lib/browser/contributions/notebook-status-bar-contribution.js.map +1 -1
- package/lib/browser/notebook-editor-widget.d.ts +4 -0
- package/lib/browser/notebook-editor-widget.d.ts.map +1 -1
- package/lib/browser/notebook-editor-widget.js +26 -3
- package/lib/browser/notebook-editor-widget.js.map +1 -1
- package/lib/browser/notebook-frontend-module.d.ts.map +1 -1
- package/lib/browser/notebook-frontend-module.js +3 -1
- package/lib/browser/notebook-frontend-module.js.map +1 -1
- package/lib/browser/renderers/cell-output-webview.d.ts +17 -3
- package/lib/browser/renderers/cell-output-webview.d.ts.map +1 -1
- package/lib/browser/renderers/cell-output-webview.js +2 -1
- package/lib/browser/renderers/cell-output-webview.js.map +1 -1
- package/lib/browser/service/notebook-cell-editor-service.d.ts +3 -0
- package/lib/browser/service/notebook-cell-editor-service.d.ts.map +1 -1
- package/lib/browser/service/notebook-cell-editor-service.js +26 -2
- package/lib/browser/service/notebook-cell-editor-service.js.map +1 -1
- package/lib/browser/service/notebook-cell-status-bar-service.d.ts +39 -0
- package/lib/browser/service/notebook-cell-status-bar-service.d.ts.map +1 -0
- package/lib/browser/service/notebook-cell-status-bar-service.js +69 -0
- package/lib/browser/service/notebook-cell-status-bar-service.js.map +1 -0
- package/lib/browser/service/notebook-editor-widget-service.d.ts +4 -0
- package/lib/browser/service/notebook-editor-widget-service.d.ts.map +1 -1
- package/lib/browser/service/notebook-editor-widget-service.js +19 -0
- package/lib/browser/service/notebook-editor-widget-service.js.map +1 -1
- package/lib/browser/view/notebook-cell-editor.d.ts +1 -0
- package/lib/browser/view/notebook-cell-editor.d.ts.map +1 -1
- package/lib/browser/view/notebook-cell-editor.js +19 -13
- package/lib/browser/view/notebook-cell-editor.js.map +1 -1
- package/lib/browser/view/notebook-cell-list-view.d.ts +4 -1
- package/lib/browser/view/notebook-cell-list-view.d.ts.map +1 -1
- package/lib/browser/view/notebook-cell-list-view.js +36 -13
- package/lib/browser/view/notebook-cell-list-view.js.map +1 -1
- package/lib/browser/view/notebook-cell-toolbar.js +1 -1
- package/lib/browser/view/notebook-cell-toolbar.js.map +1 -1
- package/lib/browser/view/notebook-code-cell-view.d.ts +30 -12
- package/lib/browser/view/notebook-code-cell-view.d.ts.map +1 -1
- package/lib/browser/view/notebook-code-cell-view.js +99 -71
- package/lib/browser/view/notebook-code-cell-view.js.map +1 -1
- package/lib/browser/view/notebook-main-toolbar.js +4 -4
- package/lib/browser/view/notebook-main-toolbar.js.map +1 -1
- package/lib/browser/view/notebook-markdown-cell-view.d.ts +5 -0
- package/lib/browser/view/notebook-markdown-cell-view.d.ts.map +1 -1
- package/lib/browser/view/notebook-markdown-cell-view.js +22 -5
- package/lib/browser/view/notebook-markdown-cell-view.js.map +1 -1
- package/lib/browser/view-model/notebook-cell-model.d.ts +12 -0
- package/lib/browser/view-model/notebook-cell-model.d.ts.map +1 -1
- package/lib/browser/view-model/notebook-cell-model.js +19 -0
- package/lib/browser/view-model/notebook-cell-model.js.map +1 -1
- package/lib/browser/view-model/notebook-cell-output-model.d.ts +0 -3
- package/lib/browser/view-model/notebook-cell-output-model.d.ts.map +1 -1
- package/lib/browser/view-model/notebook-cell-output-model.js +0 -6
- package/lib/browser/view-model/notebook-cell-output-model.js.map +1 -1
- package/lib/browser/view-model/notebook-model.d.ts +2 -1
- package/lib/browser/view-model/notebook-model.d.ts.map +1 -1
- package/lib/browser/view-model/notebook-model.js +3 -0
- package/lib/browser/view-model/notebook-model.js.map +1 -1
- package/package.json +7 -7
- package/src/browser/contributions/notebook-cell-actions-contribution.ts +60 -10
- package/src/browser/contributions/notebook-status-bar-contribution.ts +23 -34
- package/src/browser/notebook-editor-widget.tsx +34 -9
- package/src/browser/notebook-frontend-module.ts +6 -2
- package/src/browser/renderers/cell-output-webview.ts +21 -3
- package/src/browser/service/notebook-cell-editor-service.ts +21 -3
- package/src/browser/service/notebook-cell-status-bar-service.ts +94 -0
- package/src/browser/service/notebook-editor-widget-service.ts +20 -0
- package/src/browser/style/index.css +54 -9
- package/src/browser/view/notebook-cell-editor.tsx +18 -11
- package/src/browser/view/notebook-cell-list-view.tsx +44 -13
- package/src/browser/view/notebook-cell-toolbar.tsx +1 -1
- package/src/browser/view/notebook-code-cell-view.tsx +143 -92
- package/src/browser/view/notebook-main-toolbar.tsx +4 -4
- package/src/browser/view/notebook-markdown-cell-view.tsx +30 -6
- package/src/browser/view-model/notebook-cell-model.ts +29 -0
- package/src/browser/view-model/notebook-cell-output-model.ts +0 -8
- package/src/browser/view-model/notebook-model.ts +5 -1
|
@@ -26,9 +26,19 @@ import { NotebookContextManager } from '../service/notebook-context-manager';
|
|
|
26
26
|
|
|
27
27
|
export interface CellRenderer {
|
|
28
28
|
render(notebookData: NotebookModel, cell: NotebookCellModel, index: number): React.ReactNode
|
|
29
|
+
renderSidebar(notebookModel: NotebookModel, cell: NotebookCellModel): React.ReactNode
|
|
29
30
|
renderDragImage(cell: NotebookCellModel): HTMLElement
|
|
30
31
|
}
|
|
31
32
|
|
|
33
|
+
export function observeCellHeight(ref: HTMLDivElement | null, cell: NotebookCellModel): void {
|
|
34
|
+
if (ref) {
|
|
35
|
+
cell.cellHeight = ref?.getBoundingClientRect().height ?? 0;
|
|
36
|
+
new ResizeObserver(entries =>
|
|
37
|
+
cell.cellHeight = ref?.getBoundingClientRect().height ?? 0
|
|
38
|
+
).observe(ref);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
32
42
|
interface CellListProps {
|
|
33
43
|
renderers: Map<CellKind, CellRenderer>;
|
|
34
44
|
notebookModel: NotebookModel;
|
|
@@ -109,7 +119,7 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
109
119
|
}
|
|
110
120
|
|
|
111
121
|
override render(): React.ReactNode {
|
|
112
|
-
return <ul className='theia-notebook-cell-list' ref={this.cellListRef}>
|
|
122
|
+
return <ul className='theia-notebook-cell-list' ref={this.cellListRef} onDragStart={e => this.onDragStart(e)}>
|
|
113
123
|
{this.props.notebookModel.cells
|
|
114
124
|
.map((cell, index) =>
|
|
115
125
|
<React.Fragment key={'cell-' + cell.handle}>
|
|
@@ -119,13 +129,8 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
119
129
|
onAddNewCell={(commandId: string) => this.onAddNewCell(commandId, index)}
|
|
120
130
|
onDrop={e => this.onDrop(e, index)}
|
|
121
131
|
onDragOver={e => this.onDragOver(e, cell, 'top')} />
|
|
122
|
-
{this.shouldRenderDragOverIndicator(cell, 'top')
|
|
132
|
+
<CellDropIndicator visible={this.shouldRenderDragOverIndicator(cell, 'top')} />
|
|
123
133
|
<li className={'theia-notebook-cell' + (this.state.selectedCell === cell ? ' focused' : '') + (this.isEnabled() ? ' draggable' : '')}
|
|
124
|
-
onClick={e => {
|
|
125
|
-
this.setState({ ...this.state, selectedCell: cell });
|
|
126
|
-
this.props.notebookModel.setSelectedCell(cell, false);
|
|
127
|
-
}}
|
|
128
|
-
onDragStart={e => this.onDragStart(e, index, cell)}
|
|
129
134
|
onDragEnd={e => {
|
|
130
135
|
NotebookCellListView.dragGhost?.remove();
|
|
131
136
|
this.setState({ ...this.state, dragOverIndicator: undefined });
|
|
@@ -134,6 +139,7 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
134
139
|
onDrop={e => this.onDrop(e, index)}
|
|
135
140
|
draggable={true}
|
|
136
141
|
tabIndex={-1}
|
|
142
|
+
data-cell-handle={cell.handle}
|
|
137
143
|
ref={ref => {
|
|
138
144
|
if (ref && cell === this.state.selectedCell && this.state.scrollIntoView) {
|
|
139
145
|
ref.scrollIntoView({ block: 'nearest' });
|
|
@@ -141,8 +147,16 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
141
147
|
ref.focus();
|
|
142
148
|
}
|
|
143
149
|
}
|
|
144
|
-
}}
|
|
145
|
-
|
|
150
|
+
}}
|
|
151
|
+
onClick={e => {
|
|
152
|
+
this.setState({ ...this.state, selectedCell: cell });
|
|
153
|
+
this.props.notebookModel.setSelectedCell(cell, false);
|
|
154
|
+
}}
|
|
155
|
+
>
|
|
156
|
+
<div className='theia-notebook-cell-sidebar'>
|
|
157
|
+
<div className={'theia-notebook-cell-marker' + (this.state.selectedCell === cell ? ' theia-notebook-cell-marker-selected' : '')}></div>
|
|
158
|
+
{this.renderCellSidebar(cell)}
|
|
159
|
+
</div>
|
|
146
160
|
<div className='theia-notebook-cell-content'>
|
|
147
161
|
{this.renderCellContent(cell, index)}
|
|
148
162
|
</div>
|
|
@@ -152,7 +166,7 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
152
166
|
})
|
|
153
167
|
}
|
|
154
168
|
</li>
|
|
155
|
-
{this.shouldRenderDragOverIndicator(cell, 'bottom')
|
|
169
|
+
<CellDropIndicator visible={this.shouldRenderDragOverIndicator(cell, 'bottom')} />
|
|
156
170
|
</React.Fragment>
|
|
157
171
|
)
|
|
158
172
|
}
|
|
@@ -173,13 +187,30 @@ export class NotebookCellListView extends React.Component<CellListProps, Noteboo
|
|
|
173
187
|
return renderer.render(this.props.notebookModel, cell, index);
|
|
174
188
|
}
|
|
175
189
|
|
|
176
|
-
|
|
190
|
+
renderCellSidebar(cell: NotebookCellModel): React.ReactNode {
|
|
191
|
+
const renderer = this.props.renderers.get(cell.cellKind);
|
|
192
|
+
if (!renderer) {
|
|
193
|
+
throw new Error(`No renderer found for cell type ${cell.cellKind}`);
|
|
194
|
+
}
|
|
195
|
+
return renderer.renderSidebar(this.props.notebookModel, cell);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
protected onDragStart(event: React.DragEvent<HTMLElement>): void {
|
|
177
199
|
event.stopPropagation();
|
|
178
200
|
if (!this.isEnabled()) {
|
|
179
201
|
event.preventDefault();
|
|
180
202
|
return;
|
|
181
203
|
}
|
|
182
204
|
|
|
205
|
+
const cellHandle = (event.target as HTMLLIElement).getAttribute('data-cell-handle');
|
|
206
|
+
|
|
207
|
+
if (!cellHandle) {
|
|
208
|
+
throw new Error('Cell handle not found in element for cell drag event');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const index = this.props.notebookModel.getCellIndexByHandle(parseInt(cellHandle));
|
|
212
|
+
const cell = this.props.notebookModel.cells[index];
|
|
213
|
+
|
|
183
214
|
NotebookCellListView.dragGhost = document.createElement('div');
|
|
184
215
|
NotebookCellListView.dragGhost.classList.add('theia-notebook-drag-ghost-image');
|
|
185
216
|
NotebookCellListView.dragGhost.appendChild(this.props.renderers.get(cell.cellKind)?.renderDragImage(cell) ?? document.createElement('div'));
|
|
@@ -274,6 +305,6 @@ export function NotebookCellDivider({ isVisible, onAddNewCell, onDrop, onDragOve
|
|
|
274
305
|
</li>;
|
|
275
306
|
}
|
|
276
307
|
|
|
277
|
-
function CellDropIndicator(): React.JSX.Element {
|
|
278
|
-
return <div className='theia-notebook-cell-drop-indicator' />;
|
|
308
|
+
function CellDropIndicator(props: { visible: boolean }): React.JSX.Element {
|
|
309
|
+
return <div className='theia-notebook-cell-drop-indicator' style={{ visibility: props.visible ? 'visible' : 'hidden' }} />;
|
|
279
310
|
}
|
|
@@ -48,7 +48,7 @@ abstract class NotebookCellActionBar extends React.Component<NotebookCellToolbar
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
protected renderItem(item: NotebookCellToolbarItem): React.ReactNode {
|
|
51
|
-
return <div key={item.id} title={item.label} onClick={item.onClick} className={`${item.icon} ${ACTION_ITEM} theia-notebook-cell-toolbar-item`} />;
|
|
51
|
+
return <div key={item.id} id={item.id} title={item.label} onClick={item.onClick} className={`${item.icon} ${ACTION_ITEM} theia-notebook-cell-toolbar-item`} />;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
}
|
|
@@ -17,18 +17,17 @@
|
|
|
17
17
|
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
18
18
|
import * as React from '@theia/core/shared/react';
|
|
19
19
|
import { MonacoEditorServices } from '@theia/monaco/lib/browser/monaco-editor';
|
|
20
|
-
import { CellOutputWebviewFactory, CellOutputWebview } from '../renderers/cell-output-webview';
|
|
21
20
|
import { NotebookRendererRegistry } from '../notebook-renderer-registry';
|
|
22
21
|
import { NotebookCellModel } from '../view-model/notebook-cell-model';
|
|
23
22
|
import { NotebookModel } from '../view-model/notebook-model';
|
|
24
23
|
import { CellEditor } from './notebook-cell-editor';
|
|
25
|
-
import { CellRenderer } from './notebook-cell-list-view';
|
|
24
|
+
import { CellRenderer, observeCellHeight } from './notebook-cell-list-view';
|
|
26
25
|
import { NotebookCellToolbarFactory } from './notebook-cell-toolbar-factory';
|
|
27
26
|
import { NotebookCellActionContribution, NotebookCellCommands } from '../contributions/notebook-cell-actions-contribution';
|
|
28
27
|
import { CellExecution, NotebookExecutionStateService } from '../service/notebook-execution-state-service';
|
|
29
28
|
import { codicon } from '@theia/core/lib/browser';
|
|
30
29
|
import { NotebookCellExecutionState } from '../../common';
|
|
31
|
-
import { CommandRegistry, DisposableCollection, nls } from '@theia/core';
|
|
30
|
+
import { CancellationToken, CommandRegistry, DisposableCollection, nls } from '@theia/core';
|
|
32
31
|
import { NotebookContextManager } from '../service/notebook-context-manager';
|
|
33
32
|
import { NotebookViewportService } from './notebook-viewport-service';
|
|
34
33
|
import { EditorPreferences } from '@theia/editor/lib/browser';
|
|
@@ -36,6 +35,9 @@ import { NotebookOptionsService } from '../service/notebook-options';
|
|
|
36
35
|
import { MarkdownRenderer } from '@theia/core/lib/browser/markdown-rendering/markdown-renderer';
|
|
37
36
|
import { MarkdownString } from '@theia/monaco-editor-core/esm/vs/base/common/htmlContent';
|
|
38
37
|
import { NotebookCellEditorService } from '../service/notebook-cell-editor-service';
|
|
38
|
+
import { CellOutputWebview } from '../renderers/cell-output-webview';
|
|
39
|
+
import { NotebookCellStatusBarItem, NotebookCellStatusBarItemList, NotebookCellStatusBarService } from '../service/notebook-cell-status-bar-service';
|
|
40
|
+
import { LabelParser } from '@theia/core/lib/browser/label-parser';
|
|
39
41
|
|
|
40
42
|
@injectable()
|
|
41
43
|
export class NotebookCodeCellRenderer implements CellRenderer {
|
|
@@ -45,9 +47,6 @@ export class NotebookCodeCellRenderer implements CellRenderer {
|
|
|
45
47
|
@inject(NotebookRendererRegistry)
|
|
46
48
|
protected readonly notebookRendererRegistry: NotebookRendererRegistry;
|
|
47
49
|
|
|
48
|
-
@inject(CellOutputWebviewFactory)
|
|
49
|
-
protected readonly cellOutputWebviewFactory: CellOutputWebviewFactory;
|
|
50
|
-
|
|
51
50
|
@inject(NotebookCellToolbarFactory)
|
|
52
51
|
protected readonly notebookCellToolbarFactory: NotebookCellToolbarFactory;
|
|
53
52
|
|
|
@@ -75,40 +74,47 @@ export class NotebookCodeCellRenderer implements CellRenderer {
|
|
|
75
74
|
@inject(MarkdownRenderer)
|
|
76
75
|
protected readonly markdownRenderer: MarkdownRenderer;
|
|
77
76
|
|
|
77
|
+
@inject(CellOutputWebview)
|
|
78
|
+
protected readonly outputWebview: CellOutputWebview;
|
|
79
|
+
|
|
80
|
+
@inject(NotebookCellStatusBarService)
|
|
81
|
+
protected readonly notebookCellStatusBarService: NotebookCellStatusBarService;
|
|
82
|
+
|
|
83
|
+
@inject(LabelParser)
|
|
84
|
+
protected readonly labelParser: LabelParser;
|
|
85
|
+
|
|
78
86
|
render(notebookModel: NotebookModel, cell: NotebookCellModel, handle: number): React.ReactNode {
|
|
79
|
-
return <div>
|
|
80
|
-
<div className='theia-notebook-cell-
|
|
81
|
-
<
|
|
82
|
-
{this.
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
notebookCellEditorService={this.notebookCellEditorService}
|
|
94
|
-
fontInfo={this.notebookOptionsService.editorFontInfo} />
|
|
95
|
-
<NotebookCodeCellStatus cell={cell} notebook={notebookModel}
|
|
96
|
-
commandRegistry={this.commandRegistry}
|
|
97
|
-
executionStateService={this.executionStateService}
|
|
98
|
-
onClick={() => cell.requestFocusEditor()} />
|
|
99
|
-
</div >
|
|
87
|
+
return <div className='theia-notebook-cell-with-sidebar' ref={ref => observeCellHeight(ref, cell)}>
|
|
88
|
+
<div className='theia-notebook-cell-editor-container'>
|
|
89
|
+
<CellEditor notebookModel={notebookModel} cell={cell}
|
|
90
|
+
monacoServices={this.monacoServices}
|
|
91
|
+
notebookContextManager={this.notebookContextManager}
|
|
92
|
+
notebookViewportService={this.notebookViewportService}
|
|
93
|
+
notebookCellEditorService={this.notebookCellEditorService}
|
|
94
|
+
fontInfo={this.notebookOptionsService.editorFontInfo} />
|
|
95
|
+
<NotebookCodeCellStatus cell={cell} notebook={notebookModel}
|
|
96
|
+
commandRegistry={this.commandRegistry}
|
|
97
|
+
executionStateService={this.executionStateService}
|
|
98
|
+
cellStatusBarService={this.notebookCellStatusBarService}
|
|
99
|
+
labelParser={this.labelParser}
|
|
100
|
+
onClick={() => cell.requestFocusEditor()} />
|
|
100
101
|
</div >
|
|
101
|
-
<div className='theia-notebook-cell-with-sidebar'>
|
|
102
|
-
<NotebookCodeCellOutputs cell={cell} notebook={notebookModel} outputWebviewFactory={this.cellOutputWebviewFactory}
|
|
103
|
-
renderSidebar={() =>
|
|
104
|
-
this.notebookCellToolbarFactory.renderSidebar(NotebookCellActionContribution.OUTPUT_SIDEBAR_MENU, cell, {
|
|
105
|
-
contextMenuArgs: () => [notebookModel, cell, cell.outputs[0]]
|
|
106
|
-
})
|
|
107
|
-
} />
|
|
108
|
-
</div>
|
|
109
102
|
</div >;
|
|
110
103
|
}
|
|
111
104
|
|
|
105
|
+
renderSidebar(notebookModel: NotebookModel, cell: NotebookCellModel): React.ReactNode {
|
|
106
|
+
return <div>
|
|
107
|
+
<NotebookCodeCellSidebar cell={cell} notebook={notebookModel} notebookCellToolbarFactory={this.notebookCellToolbarFactory} />
|
|
108
|
+
<NotebookCodeCellOutputs cell={cell} notebook={notebookModel} outputWebview={this.outputWebview}
|
|
109
|
+
renderSidebar={() =>
|
|
110
|
+
this.notebookCellToolbarFactory.renderSidebar(NotebookCellActionContribution.OUTPUT_SIDEBAR_MENU, cell, {
|
|
111
|
+
contextMenuArgs: () => [notebookModel, cell, cell.outputs[0]]
|
|
112
|
+
})
|
|
113
|
+
} />
|
|
114
|
+
</div>;
|
|
115
|
+
|
|
116
|
+
}
|
|
117
|
+
|
|
112
118
|
renderDragImage(cell: NotebookCellModel): HTMLElement {
|
|
113
119
|
const dragImage = document.createElement('div');
|
|
114
120
|
dragImage.className = 'theia-notebook-drag-image';
|
|
@@ -151,11 +157,44 @@ export class NotebookCodeCellRenderer implements CellRenderer {
|
|
|
151
157
|
|
|
152
158
|
}
|
|
153
159
|
|
|
160
|
+
export interface NotebookCodeCellSidebarProps {
|
|
161
|
+
cell: NotebookCellModel;
|
|
162
|
+
notebook: NotebookModel;
|
|
163
|
+
notebookCellToolbarFactory: NotebookCellToolbarFactory
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export class NotebookCodeCellSidebar extends React.Component<NotebookCodeCellSidebarProps> {
|
|
167
|
+
|
|
168
|
+
protected toDispose = new DisposableCollection();
|
|
169
|
+
|
|
170
|
+
constructor(props: NotebookCodeCellSidebarProps) {
|
|
171
|
+
super(props);
|
|
172
|
+
|
|
173
|
+
this.toDispose.push(props.cell.onDidCellHeightChange(() => this.forceUpdate()));
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
override componentWillUnmount(): void {
|
|
177
|
+
this.toDispose.dispose();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
override render(): React.ReactNode {
|
|
181
|
+
return <div className='theia-notebook-cell-sidebar-actions' style={{ height: `${this.props.cell.cellHeight}px` }}>
|
|
182
|
+
{this.props.notebookCellToolbarFactory.renderSidebar(NotebookCellActionContribution.CODE_CELL_SIDEBAR_MENU, this.props.cell, {
|
|
183
|
+
contextMenuArgs: () => [this.props.cell], commandArgs: () => [this.props.notebook, this.props.cell]
|
|
184
|
+
})
|
|
185
|
+
}
|
|
186
|
+
<CodeCellExecutionOrder cell={this.props.cell} />
|
|
187
|
+
</div>;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
154
191
|
export interface NotebookCodeCellStatusProps {
|
|
155
192
|
notebook: NotebookModel;
|
|
156
193
|
cell: NotebookCellModel;
|
|
157
194
|
commandRegistry: CommandRegistry;
|
|
195
|
+
cellStatusBarService: NotebookCellStatusBarService;
|
|
158
196
|
executionStateService?: NotebookExecutionStateService;
|
|
197
|
+
labelParser: LabelParser;
|
|
159
198
|
onClick: () => void;
|
|
160
199
|
}
|
|
161
200
|
|
|
@@ -168,6 +207,8 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
|
|
|
168
207
|
|
|
169
208
|
protected toDispose = new DisposableCollection();
|
|
170
209
|
|
|
210
|
+
protected statusBarItems: NotebookCellStatusBarItemList[] = [];
|
|
211
|
+
|
|
171
212
|
constructor(props: NotebookCodeCellStatusProps) {
|
|
172
213
|
super(props);
|
|
173
214
|
|
|
@@ -198,6 +239,19 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
|
|
|
198
239
|
this.toDispose.push(props.cell.onDidChangeLanguage(() => {
|
|
199
240
|
this.forceUpdate();
|
|
200
241
|
}));
|
|
242
|
+
|
|
243
|
+
this.updateStatusBarItems();
|
|
244
|
+
this.props.cellStatusBarService.onDidChangeItems(() => this.updateStatusBarItems());
|
|
245
|
+
this.props.notebook.onContentChanged(() => this.updateStatusBarItems());
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
async updateStatusBarItems(): Promise<void> {
|
|
249
|
+
this.statusBarItems = await this.props.cellStatusBarService.getStatusBarItemsForCell(
|
|
250
|
+
this.props.notebook.uri,
|
|
251
|
+
this.props.notebook.cells.indexOf(this.props.cell),
|
|
252
|
+
this.props.notebook.viewType,
|
|
253
|
+
CancellationToken.None);
|
|
254
|
+
this.forceUpdate();
|
|
201
255
|
}
|
|
202
256
|
|
|
203
257
|
override componentWillUnmount(): void {
|
|
@@ -208,6 +262,7 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
|
|
|
208
262
|
return <div className='notebook-cell-status' onClick={() => this.props.onClick()}>
|
|
209
263
|
<div className='notebook-cell-status-left'>
|
|
210
264
|
{this.props.executionStateService && this.renderExecutionState()}
|
|
265
|
+
{this.statusBarItems?.length && this.renderStatusBarItems()}
|
|
211
266
|
</div>
|
|
212
267
|
<div className='notebook-cell-status-right'>
|
|
213
268
|
<span className='notebook-cell-language-label' onClick={() => {
|
|
@@ -217,7 +272,7 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
|
|
|
217
272
|
</div>;
|
|
218
273
|
}
|
|
219
274
|
|
|
220
|
-
|
|
275
|
+
protected renderExecutionState(): React.ReactNode {
|
|
221
276
|
const state = this.state.currentExecution?.state;
|
|
222
277
|
const { lastRunSuccess } = this.props.cell.internalMetadata;
|
|
223
278
|
|
|
@@ -243,7 +298,7 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
|
|
|
243
298
|
</>;
|
|
244
299
|
}
|
|
245
300
|
|
|
246
|
-
|
|
301
|
+
protected getExecutionTime(): number {
|
|
247
302
|
const { runStartTime, runEndTime } = this.props.cell.internalMetadata;
|
|
248
303
|
const { executionTime } = this.state;
|
|
249
304
|
if (runStartTime !== undefined && runEndTime !== undefined) {
|
|
@@ -252,87 +307,83 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
|
|
|
252
307
|
return executionTime;
|
|
253
308
|
}
|
|
254
309
|
|
|
255
|
-
|
|
310
|
+
protected renderTime(ms: number): string {
|
|
256
311
|
return `${(ms / 1000).toLocaleString(undefined, { maximumFractionDigits: 1, minimumFractionDigits: 1 })}s`;
|
|
257
312
|
}
|
|
313
|
+
|
|
314
|
+
protected renderStatusBarItems(): React.ReactNode {
|
|
315
|
+
return <>
|
|
316
|
+
{
|
|
317
|
+
this.statusBarItems.flatMap((itemList, listIndex) =>
|
|
318
|
+
itemList.items.map((item, index) => this.renderStatusBarItem(item, `${listIndex}-${index}`)
|
|
319
|
+
)
|
|
320
|
+
)
|
|
321
|
+
}
|
|
322
|
+
</>;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
protected renderStatusBarItem(item: NotebookCellStatusBarItem, key: string): React.ReactNode {
|
|
326
|
+
const content = this.props.labelParser.parse(item.text).map(part => {
|
|
327
|
+
if (typeof part === 'string') {
|
|
328
|
+
return part;
|
|
329
|
+
} else {
|
|
330
|
+
return <span key={part.name} className={`codicon codicon-${part.name}`}></span>;
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
return <div key={key} className={`cell-status-bar-item ${item.command ? 'cell-status-item-has-command' : ''}`} onClick={async () => {
|
|
334
|
+
if (item.command) {
|
|
335
|
+
if (typeof item.command === 'string') {
|
|
336
|
+
this.props.commandRegistry.executeCommand(item.command);
|
|
337
|
+
} else {
|
|
338
|
+
this.props.commandRegistry.executeCommand(item.command.id, ...(item.command.arguments ?? []));
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}}>
|
|
342
|
+
{content}
|
|
343
|
+
</div>;
|
|
344
|
+
}
|
|
345
|
+
|
|
258
346
|
}
|
|
259
347
|
|
|
260
348
|
interface NotebookCellOutputProps {
|
|
261
349
|
cell: NotebookCellModel;
|
|
262
350
|
notebook: NotebookModel;
|
|
263
|
-
|
|
351
|
+
outputWebview: CellOutputWebview;
|
|
264
352
|
renderSidebar: () => React.ReactNode;
|
|
265
353
|
}
|
|
266
354
|
|
|
267
355
|
export class NotebookCodeCellOutputs extends React.Component<NotebookCellOutputProps> {
|
|
268
356
|
|
|
269
|
-
protected outputsWebview: CellOutputWebview | undefined;
|
|
270
|
-
protected outputsWebviewPromise: Promise<CellOutputWebview> | undefined;
|
|
271
|
-
|
|
272
357
|
protected toDispose = new DisposableCollection();
|
|
273
358
|
|
|
274
|
-
|
|
275
|
-
super(props);
|
|
276
|
-
}
|
|
359
|
+
protected outputHeight: number = 0;
|
|
277
360
|
|
|
278
361
|
override async componentDidMount(): Promise<void> {
|
|
279
|
-
const { cell
|
|
280
|
-
this.toDispose.push(cell.onDidChangeOutputs(() => this.
|
|
281
|
-
this.toDispose.push(cell.onDidChangeOutputVisibility(
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
this.
|
|
285
|
-
this.outputsWebviewPromise = undefined;
|
|
362
|
+
const { cell } = this.props;
|
|
363
|
+
this.toDispose.push(cell.onDidChangeOutputs(() => this.forceUpdate()));
|
|
364
|
+
this.toDispose.push(this.props.cell.onDidChangeOutputVisibility(() => this.forceUpdate()));
|
|
365
|
+
this.toDispose.push(this.props.outputWebview.onDidRenderOutput(event => {
|
|
366
|
+
if (event.cellHandle === this.props.cell.handle) {
|
|
367
|
+
this.outputHeight = event.outputHeight;
|
|
286
368
|
this.forceUpdate();
|
|
287
|
-
} else {
|
|
288
|
-
this.updateOutputs();
|
|
289
369
|
}
|
|
290
370
|
}));
|
|
291
|
-
if (cell.outputs.length > 0) {
|
|
292
|
-
this.outputsWebviewPromise = outputWebviewFactory(cell, notebook).then(webview => {
|
|
293
|
-
this.outputsWebview = webview;
|
|
294
|
-
this.forceUpdate();
|
|
295
|
-
return webview;
|
|
296
|
-
});
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
protected async updateOutputs(): Promise<void> {
|
|
301
|
-
const { cell, notebook, outputWebviewFactory } = this.props;
|
|
302
|
-
if (!this.outputsWebviewPromise && cell.outputs.length > 0) {
|
|
303
|
-
this.outputsWebviewPromise = outputWebviewFactory(cell, notebook).then(webview => {
|
|
304
|
-
this.outputsWebview = webview;
|
|
305
|
-
this.forceUpdate();
|
|
306
|
-
return webview;
|
|
307
|
-
});
|
|
308
|
-
this.forceUpdate();
|
|
309
|
-
} else if (this.outputsWebviewPromise && cell.outputs.length === 0 && cell.internalMetadata.runEndTime) {
|
|
310
|
-
(await this.outputsWebviewPromise).dispose();
|
|
311
|
-
this.outputsWebview = undefined;
|
|
312
|
-
this.outputsWebviewPromise = undefined;
|
|
313
|
-
this.forceUpdate();
|
|
314
|
-
}
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
override async componentDidUpdate(): Promise<void> {
|
|
318
|
-
if (!(await this.outputsWebviewPromise)?.isAttached()) {
|
|
319
|
-
(await this.outputsWebviewPromise)?.attachWebview();
|
|
320
|
-
}
|
|
321
371
|
}
|
|
322
372
|
|
|
323
|
-
override
|
|
373
|
+
override componentWillUnmount(): void {
|
|
324
374
|
this.toDispose.dispose();
|
|
325
|
-
(await this.outputsWebviewPromise)?.dispose();
|
|
326
375
|
}
|
|
327
376
|
|
|
328
377
|
override render(): React.ReactNode {
|
|
329
|
-
|
|
330
|
-
|
|
378
|
+
if (!this.props.cell.outputs?.length) {
|
|
379
|
+
return <></>;
|
|
380
|
+
}
|
|
381
|
+
if (this.props.cell.outputVisible) {
|
|
382
|
+
return <div style={{ minHeight: this.outputHeight }}>
|
|
331
383
|
{this.props.renderSidebar()}
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
384
|
+
</div>;
|
|
385
|
+
}
|
|
386
|
+
return <div className='theia-notebook-collapsed-output-container'><i className='theia-notebook-collapsed-output'>{nls.localizeByDefault('Outputs are collapsed')}</i></div>;
|
|
336
387
|
}
|
|
337
388
|
|
|
338
389
|
}
|
|
@@ -152,17 +152,17 @@ export class NotebookMainToolbar extends React.Component<NotebookMainToolbarProp
|
|
|
152
152
|
|
|
153
153
|
override render(): React.ReactNode {
|
|
154
154
|
const menuItems = this.getMenuItems();
|
|
155
|
-
return <div className='theia-notebook-main-toolbar'>
|
|
155
|
+
return <div className='theia-notebook-main-toolbar' id='notebook-main-toolbar'>
|
|
156
156
|
{menuItems.slice(0, menuItems.length - this.calculateNumberOfHiddenItems(menuItems)).map(item => this.renderMenuItem(item))}
|
|
157
157
|
{
|
|
158
158
|
this.state.numberOfHiddenItems > 0 &&
|
|
159
159
|
<span className={`${codicon('ellipsis')} action-label theia-notebook-main-toolbar-item`} onClick={e => this.renderContextMenu(e.nativeEvent, menuItems)} />
|
|
160
160
|
}
|
|
161
161
|
<div ref={element => this.gapElementChanged(element)} style={{ flexGrow: 1 }}></div>
|
|
162
|
-
<div className='theia-notebook-main-toolbar-item action-label'
|
|
162
|
+
<div className='theia-notebook-main-toolbar-item action-label' id={NotebookCommands.SELECT_KERNEL_COMMAND.id}
|
|
163
163
|
onClick={() => this.props.commandRegistry.executeCommand(NotebookCommands.SELECT_KERNEL_COMMAND.id, this.props.notebookModel)}>
|
|
164
164
|
<span className={codicon('server-environment')} />
|
|
165
|
-
<span className=' theia-notebook-main-toolbar-item-text'>
|
|
165
|
+
<span className=' theia-notebook-main-toolbar-item-text' id='kernel-text'>
|
|
166
166
|
{this.state.selectedKernelLabel ?? nls.localizeByDefault('Select Kernel')}
|
|
167
167
|
</span>
|
|
168
168
|
</div>
|
|
@@ -195,7 +195,7 @@ export class NotebookMainToolbar extends React.Component<NotebookMainToolbarProp
|
|
|
195
195
|
const command = this.props.commandRegistry.getCommand(item.command ?? '') as NotebookCommand | undefined;
|
|
196
196
|
const label = command?.shortTitle ?? item.label;
|
|
197
197
|
const title = command?.tooltip ?? item.label;
|
|
198
|
-
return <div key={item.id} title={title} className={`theia-notebook-main-toolbar-item action-label${this.getAdditionalClasses(item)}`}
|
|
198
|
+
return <div key={item.id} id={item.id} title={title} className={`theia-notebook-main-toolbar-item action-label${this.getAdditionalClasses(item)}`}
|
|
199
199
|
onClick={() => {
|
|
200
200
|
if (item.command && (!item.when || this.props.contextKeyService.match(item.when, this.props.editorNode))) {
|
|
201
201
|
this.props.commandRegistry.executeCommand(item.command, this.props.notebookModel.uri);
|
|
@@ -18,7 +18,7 @@ import * as React from '@theia/core/shared/react';
|
|
|
18
18
|
import { MarkdownRenderer } from '@theia/core/lib/browser/markdown-rendering/markdown-renderer';
|
|
19
19
|
import { MarkdownStringImpl } from '@theia/core/lib/common/markdown-rendering/markdown-string';
|
|
20
20
|
import { NotebookModel } from '../view-model/notebook-model';
|
|
21
|
-
import { CellRenderer } from './notebook-cell-list-view';
|
|
21
|
+
import { CellRenderer, observeCellHeight } from './notebook-cell-list-view';
|
|
22
22
|
import { NotebookCellModel } from '../view-model/notebook-cell-model';
|
|
23
23
|
import { CellEditor } from './notebook-cell-editor';
|
|
24
24
|
import { inject, injectable } from '@theia/core/shared/inversify';
|
|
@@ -30,6 +30,8 @@ import { NotebookCodeCellStatus } from './notebook-code-cell-view';
|
|
|
30
30
|
import { NotebookEditorFindMatch, NotebookEditorFindMatchOptions } from './notebook-find-widget';
|
|
31
31
|
import * as mark from 'advanced-mark.js';
|
|
32
32
|
import { NotebookCellEditorService } from '../service/notebook-cell-editor-service';
|
|
33
|
+
import { NotebookCellStatusBarService } from '../service/notebook-cell-status-bar-service';
|
|
34
|
+
import { LabelParser } from '@theia/core/lib/browser/label-parser';
|
|
33
35
|
|
|
34
36
|
@injectable()
|
|
35
37
|
export class NotebookMarkdownCellRenderer implements CellRenderer {
|
|
@@ -51,6 +53,12 @@ export class NotebookMarkdownCellRenderer implements CellRenderer {
|
|
|
51
53
|
@inject(NotebookCellEditorService)
|
|
52
54
|
protected readonly notebookCellEditorService: NotebookCellEditorService;
|
|
53
55
|
|
|
56
|
+
@inject(NotebookCellStatusBarService)
|
|
57
|
+
protected readonly notebookCellStatusBarService: NotebookCellStatusBarService;
|
|
58
|
+
|
|
59
|
+
@inject(LabelParser)
|
|
60
|
+
protected readonly labelParser: LabelParser;
|
|
61
|
+
|
|
54
62
|
render(notebookModel: NotebookModel, cell: NotebookCellModel): React.ReactNode {
|
|
55
63
|
return <MarkdownCell
|
|
56
64
|
markdownRenderer={this.markdownRenderer}
|
|
@@ -60,7 +68,14 @@ export class NotebookMarkdownCellRenderer implements CellRenderer {
|
|
|
60
68
|
cell={cell}
|
|
61
69
|
notebookModel={notebookModel}
|
|
62
70
|
notebookContextManager={this.notebookContextManager}
|
|
63
|
-
notebookCellEditorService={this.notebookCellEditorService}
|
|
71
|
+
notebookCellEditorService={this.notebookCellEditorService}
|
|
72
|
+
notebookCellStatusBarService={this.notebookCellStatusBarService}
|
|
73
|
+
labelParser={this.labelParser}
|
|
74
|
+
/>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
renderSidebar(notebookModel: NotebookModel, cell: NotebookCellModel): React.ReactNode {
|
|
78
|
+
return <div className='theia-notebook-markdown-sidebar'></div>;
|
|
64
79
|
}
|
|
65
80
|
|
|
66
81
|
renderDragImage(cell: NotebookCellModel): HTMLElement {
|
|
@@ -82,11 +97,15 @@ interface MarkdownCellProps {
|
|
|
82
97
|
notebookModel: NotebookModel;
|
|
83
98
|
notebookContextManager: NotebookContextManager;
|
|
84
99
|
notebookOptionsService: NotebookOptionsService;
|
|
85
|
-
notebookCellEditorService: NotebookCellEditorService
|
|
100
|
+
notebookCellEditorService: NotebookCellEditorService;
|
|
101
|
+
notebookCellStatusBarService: NotebookCellStatusBarService;
|
|
102
|
+
labelParser: LabelParser;
|
|
86
103
|
}
|
|
87
104
|
|
|
88
105
|
function MarkdownCell({
|
|
89
|
-
markdownRenderer, monacoServices, cell, notebookModel, notebookContextManager,
|
|
106
|
+
markdownRenderer, monacoServices, cell, notebookModel, notebookContextManager,
|
|
107
|
+
notebookOptionsService, commandRegistry, notebookCellEditorService, notebookCellStatusBarService,
|
|
108
|
+
labelParser
|
|
90
109
|
}: MarkdownCellProps): React.JSX.Element {
|
|
91
110
|
const [editMode, setEditMode] = React.useState(cell.editing);
|
|
92
111
|
let empty = false;
|
|
@@ -135,7 +154,7 @@ function MarkdownCell({
|
|
|
135
154
|
}
|
|
136
155
|
|
|
137
156
|
return editMode ?
|
|
138
|
-
(<div className='theia-notebook-markdown-editor-container' key="code">
|
|
157
|
+
(<div className='theia-notebook-markdown-editor-container' key="code" ref={ref => observeCellHeight(ref, cell)}>
|
|
139
158
|
<CellEditor notebookModel={notebookModel} cell={cell}
|
|
140
159
|
monacoServices={monacoServices}
|
|
141
160
|
notebookContextManager={notebookContextManager}
|
|
@@ -143,11 +162,16 @@ function MarkdownCell({
|
|
|
143
162
|
fontInfo={notebookOptionsService.editorFontInfo} />
|
|
144
163
|
<NotebookCodeCellStatus cell={cell} notebook={notebookModel}
|
|
145
164
|
commandRegistry={commandRegistry}
|
|
165
|
+
cellStatusBarService={notebookCellStatusBarService}
|
|
166
|
+
labelParser={labelParser}
|
|
146
167
|
onClick={() => cell.requestFocusEditor()} />
|
|
147
168
|
</div >) :
|
|
148
169
|
(<div className='theia-notebook-markdown-content' key="markdown"
|
|
149
170
|
onDoubleClick={() => cell.requestEdit()}
|
|
150
|
-
ref={node =>
|
|
171
|
+
ref={node => {
|
|
172
|
+
node?.replaceChildren(...markdownContent);
|
|
173
|
+
observeCellHeight(node, cell);
|
|
174
|
+
}}
|
|
151
175
|
/>);
|
|
152
176
|
}
|
|
153
177
|
|
|
@@ -62,6 +62,10 @@ export interface NotebookCell {
|
|
|
62
62
|
metadata: NotebookCellMetadata;
|
|
63
63
|
internalMetadata: NotebookCellInternalMetadata;
|
|
64
64
|
text: string;
|
|
65
|
+
/**
|
|
66
|
+
* The selection of the cell. Zero-based line/character coordinates.
|
|
67
|
+
*/
|
|
68
|
+
selection: Range | undefined;
|
|
65
69
|
onDidChangeOutputs?: Event<NotebookCellOutputsSplice>;
|
|
66
70
|
onDidChangeOutputItems?: Event<CellOutput>;
|
|
67
71
|
onDidChangeLanguage: Event<string>;
|
|
@@ -129,6 +133,9 @@ export class NotebookCellModel implements NotebookCell, Disposable {
|
|
|
129
133
|
protected onDidRequestCenterEditorEmitter = new Emitter<void>();
|
|
130
134
|
readonly onDidRequestCenterEditor = this.onDidRequestCenterEditorEmitter.event;
|
|
131
135
|
|
|
136
|
+
protected onDidCellHeightChangeEmitter = new Emitter<number>();
|
|
137
|
+
readonly onDidCellHeightChange = this.onDidCellHeightChangeEmitter.event;
|
|
138
|
+
|
|
132
139
|
@inject(NotebookCellModelProps)
|
|
133
140
|
protected readonly props: NotebookCellModelProps;
|
|
134
141
|
|
|
@@ -251,6 +258,28 @@ export class NotebookCellModel implements NotebookCell, Disposable {
|
|
|
251
258
|
}
|
|
252
259
|
}
|
|
253
260
|
|
|
261
|
+
protected _selection: Range | undefined = undefined;
|
|
262
|
+
|
|
263
|
+
get selection(): Range | undefined {
|
|
264
|
+
return this._selection;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
set selection(selection: Range | undefined) {
|
|
268
|
+
this._selection = selection;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
protected _cellheight: number = 0;
|
|
272
|
+
get cellHeight(): number {
|
|
273
|
+
return this._cellheight;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
set cellHeight(height: number) {
|
|
277
|
+
if (height !== this._cellheight) {
|
|
278
|
+
this.onDidCellHeightChangeEmitter.fire(height);
|
|
279
|
+
this._cellheight = height;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
254
283
|
@postConstruct()
|
|
255
284
|
protected init(): void {
|
|
256
285
|
this._outputs = this.props.outputs.map(op => new NotebookCellOutputModel(op));
|