@theia/notebook 1.53.2 → 1.55.0-next.14

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.
Files changed (84) hide show
  1. package/lib/browser/contributions/notebook-actions-contribution.d.ts.map +1 -1
  2. package/lib/browser/contributions/notebook-actions-contribution.js +5 -2
  3. package/lib/browser/contributions/notebook-actions-contribution.js.map +1 -1
  4. package/lib/browser/contributions/notebook-cell-actions-contribution.d.ts.map +1 -1
  5. package/lib/browser/contributions/notebook-cell-actions-contribution.js +10 -6
  6. package/lib/browser/contributions/notebook-cell-actions-contribution.js.map +1 -1
  7. package/lib/browser/contributions/notebook-status-bar-contribution.d.ts +7 -9
  8. package/lib/browser/contributions/notebook-status-bar-contribution.d.ts.map +1 -1
  9. package/lib/browser/contributions/notebook-status-bar-contribution.js +21 -33
  10. package/lib/browser/contributions/notebook-status-bar-contribution.js.map +1 -1
  11. package/lib/browser/index.d.ts +1 -0
  12. package/lib/browser/index.d.ts.map +1 -1
  13. package/lib/browser/index.js +1 -0
  14. package/lib/browser/index.js.map +1 -1
  15. package/lib/browser/notebook-editor-widget.d.ts +4 -0
  16. package/lib/browser/notebook-editor-widget.d.ts.map +1 -1
  17. package/lib/browser/notebook-editor-widget.js +27 -4
  18. package/lib/browser/notebook-editor-widget.js.map +1 -1
  19. package/lib/browser/notebook-frontend-module.d.ts.map +1 -1
  20. package/lib/browser/notebook-frontend-module.js +3 -1
  21. package/lib/browser/notebook-frontend-module.js.map +1 -1
  22. package/lib/browser/notebook-open-handler.d.ts +3 -2
  23. package/lib/browser/notebook-open-handler.d.ts.map +1 -1
  24. package/lib/browser/notebook-open-handler.js +12 -5
  25. package/lib/browser/notebook-open-handler.js.map +1 -1
  26. package/lib/browser/renderers/cell-output-webview.d.ts +17 -3
  27. package/lib/browser/renderers/cell-output-webview.d.ts.map +1 -1
  28. package/lib/browser/renderers/cell-output-webview.js +2 -1
  29. package/lib/browser/renderers/cell-output-webview.js.map +1 -1
  30. package/lib/browser/service/notebook-cell-editor-service.d.ts +19 -0
  31. package/lib/browser/service/notebook-cell-editor-service.d.ts.map +1 -0
  32. package/lib/browser/service/notebook-cell-editor-service.js +77 -0
  33. package/lib/browser/service/notebook-cell-editor-service.js.map +1 -0
  34. package/lib/browser/service/notebook-editor-widget-service.d.ts +4 -0
  35. package/lib/browser/service/notebook-editor-widget-service.d.ts.map +1 -1
  36. package/lib/browser/service/notebook-editor-widget-service.js +19 -0
  37. package/lib/browser/service/notebook-editor-widget-service.js.map +1 -1
  38. package/lib/browser/view/notebook-cell-editor.d.ts +2 -0
  39. package/lib/browser/view/notebook-cell-editor.d.ts.map +1 -1
  40. package/lib/browser/view/notebook-cell-editor.js +12 -1
  41. package/lib/browser/view/notebook-cell-editor.js.map +1 -1
  42. package/lib/browser/view/notebook-cell-list-view.d.ts +4 -1
  43. package/lib/browser/view/notebook-cell-list-view.d.ts.map +1 -1
  44. package/lib/browser/view/notebook-cell-list-view.js +36 -13
  45. package/lib/browser/view/notebook-cell-list-view.js.map +1 -1
  46. package/lib/browser/view/notebook-code-cell-view.d.ts +19 -9
  47. package/lib/browser/view/notebook-code-cell-view.d.ts.map +1 -1
  48. package/lib/browser/view/notebook-code-cell-view.js +58 -70
  49. package/lib/browser/view/notebook-code-cell-view.js.map +1 -1
  50. package/lib/browser/view/notebook-markdown-cell-view.d.ts +3 -0
  51. package/lib/browser/view/notebook-markdown-cell-view.d.ts.map +1 -1
  52. package/lib/browser/view/notebook-markdown-cell-view.js +17 -5
  53. package/lib/browser/view/notebook-markdown-cell-view.js.map +1 -1
  54. package/lib/browser/view-model/notebook-cell-model.d.ts +5 -0
  55. package/lib/browser/view-model/notebook-cell-model.d.ts.map +1 -1
  56. package/lib/browser/view-model/notebook-cell-model.js +10 -0
  57. package/lib/browser/view-model/notebook-cell-model.js.map +1 -1
  58. package/lib/browser/view-model/notebook-cell-output-model.d.ts +0 -3
  59. package/lib/browser/view-model/notebook-cell-output-model.d.ts.map +1 -1
  60. package/lib/browser/view-model/notebook-cell-output-model.js +0 -6
  61. package/lib/browser/view-model/notebook-cell-output-model.js.map +1 -1
  62. package/lib/browser/view-model/notebook-model.d.ts +2 -1
  63. package/lib/browser/view-model/notebook-model.d.ts.map +1 -1
  64. package/lib/browser/view-model/notebook-model.js +3 -0
  65. package/lib/browser/view-model/notebook-model.js.map +1 -1
  66. package/package.json +8 -8
  67. package/src/browser/contributions/notebook-actions-contribution.ts +4 -1
  68. package/src/browser/contributions/notebook-cell-actions-contribution.ts +10 -7
  69. package/src/browser/contributions/notebook-status-bar-contribution.ts +23 -34
  70. package/src/browser/index.ts +1 -0
  71. package/src/browser/notebook-editor-widget.tsx +35 -10
  72. package/src/browser/notebook-frontend-module.ts +6 -2
  73. package/src/browser/notebook-open-handler.ts +13 -7
  74. package/src/browser/renderers/cell-output-webview.ts +21 -3
  75. package/src/browser/service/notebook-cell-editor-service.ts +74 -0
  76. package/src/browser/service/notebook-editor-widget-service.ts +20 -0
  77. package/src/browser/style/index.css +41 -10
  78. package/src/browser/view/notebook-cell-editor.tsx +18 -5
  79. package/src/browser/view/notebook-cell-list-view.tsx +44 -13
  80. package/src/browser/view/notebook-code-cell-view.tsx +82 -87
  81. package/src/browser/view/notebook-markdown-cell-view.tsx +19 -5
  82. package/src/browser/view-model/notebook-cell-model.ts +13 -0
  83. package/src/browser/view-model/notebook-cell-output-model.ts +0 -8
  84. 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') && <CellDropIndicator />}
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
- <div className={'theia-notebook-cell-marker' + (this.state.selectedCell === cell ? ' theia-notebook-cell-marker-selected' : '')}></div>
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') && <CellDropIndicator />}
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
- protected onDragStart(event: React.DragEvent<HTMLLIElement>, index: number, cell: NotebookCellModel): void {
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
  }
@@ -17,12 +17,11 @@
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';
@@ -35,6 +34,8 @@ import { EditorPreferences } from '@theia/editor/lib/browser';
35
34
  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';
37
+ import { NotebookCellEditorService } from '../service/notebook-cell-editor-service';
38
+ import { CellOutputWebview } from '../renderers/cell-output-webview';
38
39
 
39
40
  @injectable()
40
41
  export class NotebookCodeCellRenderer implements CellRenderer {
@@ -44,9 +45,6 @@ export class NotebookCodeCellRenderer implements CellRenderer {
44
45
  @inject(NotebookRendererRegistry)
45
46
  protected readonly notebookRendererRegistry: NotebookRendererRegistry;
46
47
 
47
- @inject(CellOutputWebviewFactory)
48
- protected readonly cellOutputWebviewFactory: CellOutputWebviewFactory;
49
-
50
48
  @inject(NotebookCellToolbarFactory)
51
49
  protected readonly notebookCellToolbarFactory: NotebookCellToolbarFactory;
52
50
 
@@ -62,6 +60,9 @@ export class NotebookCodeCellRenderer implements CellRenderer {
62
60
  @inject(EditorPreferences)
63
61
  protected readonly editorPreferences: EditorPreferences;
64
62
 
63
+ @inject(NotebookCellEditorService)
64
+ protected readonly notebookCellEditorService: NotebookCellEditorService;
65
+
65
66
  @inject(CommandRegistry)
66
67
  protected readonly commandRegistry: CommandRegistry;
67
68
 
@@ -71,39 +72,39 @@ export class NotebookCodeCellRenderer implements CellRenderer {
71
72
  @inject(MarkdownRenderer)
72
73
  protected readonly markdownRenderer: MarkdownRenderer;
73
74
 
75
+ @inject(CellOutputWebview)
76
+ protected readonly outputWebview: CellOutputWebview;
77
+
74
78
  render(notebookModel: NotebookModel, cell: NotebookCellModel, handle: number): React.ReactNode {
75
- return <div>
76
- <div className='theia-notebook-cell-with-sidebar'>
77
- <div className='theia-notebook-cell-sidebar'>
78
- {this.notebookCellToolbarFactory.renderSidebar(NotebookCellActionContribution.CODE_CELL_SIDEBAR_MENU, cell, {
79
- contextMenuArgs: () => [cell], commandArgs: () => [notebookModel, cell]
80
- })
81
- }
82
- <CodeCellExecutionOrder cell={cell} />
83
- </div>
84
- <div className='theia-notebook-cell-editor-container'>
85
- <CellEditor notebookModel={notebookModel} cell={cell}
86
- monacoServices={this.monacoServices}
87
- notebookContextManager={this.notebookContextManager}
88
- notebookViewportService={this.notebookViewportService}
89
- fontInfo={this.notebookOptionsService.editorFontInfo} />
90
- <NotebookCodeCellStatus cell={cell} notebook={notebookModel}
91
- commandRegistry={this.commandRegistry}
92
- executionStateService={this.executionStateService}
93
- onClick={() => cell.requestFocusEditor()} />
94
- </div >
79
+ return <div className='theia-notebook-cell-with-sidebar' ref={ref => observeCellHeight(ref, cell)}>
80
+ <div className='theia-notebook-cell-editor-container'>
81
+ <CellEditor notebookModel={notebookModel} cell={cell}
82
+ monacoServices={this.monacoServices}
83
+ notebookContextManager={this.notebookContextManager}
84
+ notebookViewportService={this.notebookViewportService}
85
+ notebookCellEditorService={this.notebookCellEditorService}
86
+ fontInfo={this.notebookOptionsService.editorFontInfo} />
87
+ <NotebookCodeCellStatus cell={cell} notebook={notebookModel}
88
+ commandRegistry={this.commandRegistry}
89
+ executionStateService={this.executionStateService}
90
+ onClick={() => cell.requestFocusEditor()} />
95
91
  </div >
96
- <div className='theia-notebook-cell-with-sidebar'>
97
- <NotebookCodeCellOutputs cell={cell} notebook={notebookModel} outputWebviewFactory={this.cellOutputWebviewFactory}
98
- renderSidebar={() =>
99
- this.notebookCellToolbarFactory.renderSidebar(NotebookCellActionContribution.OUTPUT_SIDEBAR_MENU, cell, {
100
- contextMenuArgs: () => [notebookModel, cell, cell.outputs[0]]
101
- })
102
- } />
103
- </div>
104
92
  </div >;
105
93
  }
106
94
 
95
+ renderSidebar(notebookModel: NotebookModel, cell: NotebookCellModel): React.ReactNode {
96
+ return <div>
97
+ <NotebookCodeCellSidebar cell={cell} notebook={notebookModel} notebookCellToolbarFactory={this.notebookCellToolbarFactory} />
98
+ <NotebookCodeCellOutputs cell={cell} notebook={notebookModel} outputWebview={this.outputWebview}
99
+ renderSidebar={() =>
100
+ this.notebookCellToolbarFactory.renderSidebar(NotebookCellActionContribution.OUTPUT_SIDEBAR_MENU, cell, {
101
+ contextMenuArgs: () => [notebookModel, cell, cell.outputs[0]]
102
+ })
103
+ } />
104
+ </div>;
105
+
106
+ }
107
+
107
108
  renderDragImage(cell: NotebookCellModel): HTMLElement {
108
109
  const dragImage = document.createElement('div');
109
110
  dragImage.className = 'theia-notebook-drag-image';
@@ -146,6 +147,37 @@ export class NotebookCodeCellRenderer implements CellRenderer {
146
147
 
147
148
  }
148
149
 
150
+ export interface NotebookCodeCellSidebarProps {
151
+ cell: NotebookCellModel;
152
+ notebook: NotebookModel;
153
+ notebookCellToolbarFactory: NotebookCellToolbarFactory
154
+ }
155
+
156
+ export class NotebookCodeCellSidebar extends React.Component<NotebookCodeCellSidebarProps> {
157
+
158
+ protected toDispose = new DisposableCollection();
159
+
160
+ constructor(props: NotebookCodeCellSidebarProps) {
161
+ super(props);
162
+
163
+ this.toDispose.push(props.cell.onDidCellHeightChange(() => this.forceUpdate()));
164
+ }
165
+
166
+ override componentWillUnmount(): void {
167
+ this.toDispose.dispose();
168
+ }
169
+
170
+ override render(): React.ReactNode {
171
+ return <div className='theia-notebook-cell-sidebar-actions' style={{ height: `${this.props.cell.cellHeight}px` }}>
172
+ {this.props.notebookCellToolbarFactory.renderSidebar(NotebookCellActionContribution.CODE_CELL_SIDEBAR_MENU, this.props.cell, {
173
+ contextMenuArgs: () => [this.props.cell], commandArgs: () => [this.props.notebook, this.props.cell]
174
+ })
175
+ }
176
+ <CodeCellExecutionOrder cell={this.props.cell} />
177
+ </div>;
178
+ }
179
+ }
180
+
149
181
  export interface NotebookCodeCellStatusProps {
150
182
  notebook: NotebookModel;
151
183
  cell: NotebookCellModel;
@@ -255,79 +287,42 @@ export class NotebookCodeCellStatus extends React.Component<NotebookCodeCellStat
255
287
  interface NotebookCellOutputProps {
256
288
  cell: NotebookCellModel;
257
289
  notebook: NotebookModel;
258
- outputWebviewFactory: CellOutputWebviewFactory;
290
+ outputWebview: CellOutputWebview;
259
291
  renderSidebar: () => React.ReactNode;
260
292
  }
261
293
 
262
294
  export class NotebookCodeCellOutputs extends React.Component<NotebookCellOutputProps> {
263
295
 
264
- protected outputsWebview: CellOutputWebview | undefined;
265
- protected outputsWebviewPromise: Promise<CellOutputWebview> | undefined;
266
-
267
296
  protected toDispose = new DisposableCollection();
268
297
 
269
- constructor(props: NotebookCellOutputProps) {
270
- super(props);
271
- }
298
+ protected outputHeight: number = 0;
272
299
 
273
300
  override async componentDidMount(): Promise<void> {
274
- const { cell, notebook, outputWebviewFactory } = this.props;
275
- this.toDispose.push(cell.onDidChangeOutputs(() => this.updateOutputs()));
276
- this.toDispose.push(cell.onDidChangeOutputVisibility(visible => {
277
- if (!visible && this.outputsWebview) {
278
- this.outputsWebview?.dispose();
279
- this.outputsWebview = undefined;
280
- this.outputsWebviewPromise = undefined;
301
+ const { cell } = this.props;
302
+ this.toDispose.push(cell.onDidChangeOutputs(() => this.forceUpdate()));
303
+ this.toDispose.push(this.props.cell.onDidChangeOutputVisibility(() => this.forceUpdate()));
304
+ this.toDispose.push(this.props.outputWebview.onDidRenderOutput(event => {
305
+ if (event.cellHandle === this.props.cell.handle) {
306
+ this.outputHeight = event.outputHeight;
281
307
  this.forceUpdate();
282
- } else {
283
- this.updateOutputs();
284
308
  }
285
309
  }));
286
- if (cell.outputs.length > 0) {
287
- this.outputsWebviewPromise = outputWebviewFactory(cell, notebook).then(webview => {
288
- this.outputsWebview = webview;
289
- this.forceUpdate();
290
- return webview;
291
- });
292
- }
293
310
  }
294
311
 
295
- protected async updateOutputs(): Promise<void> {
296
- const { cell, notebook, outputWebviewFactory } = this.props;
297
- if (!this.outputsWebviewPromise && cell.outputs.length > 0) {
298
- this.outputsWebviewPromise = outputWebviewFactory(cell, notebook).then(webview => {
299
- this.outputsWebview = webview;
300
- this.forceUpdate();
301
- return webview;
302
- });
303
- this.forceUpdate();
304
- } else if (this.outputsWebviewPromise && cell.outputs.length === 0 && cell.internalMetadata.runEndTime) {
305
- (await this.outputsWebviewPromise).dispose();
306
- this.outputsWebview = undefined;
307
- this.outputsWebviewPromise = undefined;
308
- this.forceUpdate();
309
- }
310
- }
311
-
312
- override async componentDidUpdate(): Promise<void> {
313
- if (!(await this.outputsWebviewPromise)?.isAttached()) {
314
- (await this.outputsWebviewPromise)?.attachWebview();
315
- }
316
- }
317
-
318
- override async componentWillUnmount(): Promise<void> {
312
+ override componentWillUnmount(): void {
319
313
  this.toDispose.dispose();
320
- (await this.outputsWebviewPromise)?.dispose();
321
314
  }
322
315
 
323
316
  override render(): React.ReactNode {
324
- return this.outputsWebview && this.props.cell.outputVisible ?
325
- <>
317
+ if (!this.props.cell.outputs?.length) {
318
+ return <></>;
319
+ }
320
+ if (this.props.cell.outputVisible) {
321
+ return <div style={{ minHeight: this.outputHeight }}>
326
322
  {this.props.renderSidebar()}
327
- {this.outputsWebview.render()}
328
- </> :
329
- this.props.cell.outputs?.length ? <i className='theia-notebook-collapsed-output'>{nls.localizeByDefault('Outputs are collapsed')}</i> : <></>;
330
-
323
+ </div>;
324
+ }
325
+ return <div className='theia-notebook-collapsed-output-container'><i className='theia-notebook-collapsed-output'>{nls.localizeByDefault('Outputs are collapsed')}</i></div>;
331
326
  }
332
327
 
333
328
  }
@@ -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';
@@ -29,6 +29,7 @@ import { NotebookOptionsService } from '../service/notebook-options';
29
29
  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
+ import { NotebookCellEditorService } from '../service/notebook-cell-editor-service';
32
33
 
33
34
  @injectable()
34
35
  export class NotebookMarkdownCellRenderer implements CellRenderer {
@@ -47,6 +48,9 @@ export class NotebookMarkdownCellRenderer implements CellRenderer {
47
48
  @inject(NotebookOptionsService)
48
49
  protected readonly notebookOptionsService: NotebookOptionsService;
49
50
 
51
+ @inject(NotebookCellEditorService)
52
+ protected readonly notebookCellEditorService: NotebookCellEditorService;
53
+
50
54
  render(notebookModel: NotebookModel, cell: NotebookCellModel): React.ReactNode {
51
55
  return <MarkdownCell
52
56
  markdownRenderer={this.markdownRenderer}
@@ -55,7 +59,12 @@ export class NotebookMarkdownCellRenderer implements CellRenderer {
55
59
  notebookOptionsService={this.notebookOptionsService}
56
60
  cell={cell}
57
61
  notebookModel={notebookModel}
58
- notebookContextManager={this.notebookContextManager} />;
62
+ notebookContextManager={this.notebookContextManager}
63
+ notebookCellEditorService={this.notebookCellEditorService} />;
64
+ }
65
+
66
+ renderSidebar(notebookModel: NotebookModel, cell: NotebookCellModel): React.ReactNode {
67
+ return <div className='theia-notebook-markdown-sidebar'></div>;
59
68
  }
60
69
 
61
70
  renderDragImage(cell: NotebookCellModel): HTMLElement {
@@ -77,10 +86,11 @@ interface MarkdownCellProps {
77
86
  notebookModel: NotebookModel;
78
87
  notebookContextManager: NotebookContextManager;
79
88
  notebookOptionsService: NotebookOptionsService;
89
+ notebookCellEditorService: NotebookCellEditorService
80
90
  }
81
91
 
82
92
  function MarkdownCell({
83
- markdownRenderer, monacoServices, cell, notebookModel, notebookContextManager, notebookOptionsService, commandRegistry
93
+ markdownRenderer, monacoServices, cell, notebookModel, notebookContextManager, notebookOptionsService, commandRegistry, notebookCellEditorService
84
94
  }: MarkdownCellProps): React.JSX.Element {
85
95
  const [editMode, setEditMode] = React.useState(cell.editing);
86
96
  let empty = false;
@@ -129,10 +139,11 @@ function MarkdownCell({
129
139
  }
130
140
 
131
141
  return editMode ?
132
- (<div className='theia-notebook-markdown-editor-container' key="code">
142
+ (<div className='theia-notebook-markdown-editor-container' key="code" ref={ref => observeCellHeight(ref, cell)}>
133
143
  <CellEditor notebookModel={notebookModel} cell={cell}
134
144
  monacoServices={monacoServices}
135
145
  notebookContextManager={notebookContextManager}
146
+ notebookCellEditorService={notebookCellEditorService}
136
147
  fontInfo={notebookOptionsService.editorFontInfo} />
137
148
  <NotebookCodeCellStatus cell={cell} notebook={notebookModel}
138
149
  commandRegistry={commandRegistry}
@@ -140,7 +151,10 @@ function MarkdownCell({
140
151
  </div >) :
141
152
  (<div className='theia-notebook-markdown-content' key="markdown"
142
153
  onDoubleClick={() => cell.requestEdit()}
143
- ref={node => node?.replaceChildren(...markdownContent)}
154
+ ref={node => {
155
+ node?.replaceChildren(...markdownContent);
156
+ observeCellHeight(node, cell);
157
+ }}
144
158
  />);
145
159
  }
146
160
 
@@ -129,6 +129,9 @@ export class NotebookCellModel implements NotebookCell, Disposable {
129
129
  protected onDidRequestCenterEditorEmitter = new Emitter<void>();
130
130
  readonly onDidRequestCenterEditor = this.onDidRequestCenterEditorEmitter.event;
131
131
 
132
+ protected onDidCellHeightChangeEmitter = new Emitter<number>();
133
+ readonly onDidCellHeightChange = this.onDidCellHeightChangeEmitter.event;
134
+
132
135
  @inject(NotebookCellModelProps)
133
136
  protected readonly props: NotebookCellModelProps;
134
137
 
@@ -251,6 +254,16 @@ export class NotebookCellModel implements NotebookCell, Disposable {
251
254
  }
252
255
  }
253
256
 
257
+ protected _cellheight: number = 0;
258
+ get cellHeight(): number {
259
+ return this._cellheight;
260
+ }
261
+
262
+ set cellHeight(height: number) {
263
+ this.onDidCellHeightChangeEmitter.fire(height);
264
+ this._cellheight = height;
265
+ }
266
+
254
267
  @postConstruct()
255
268
  protected init(): void {
256
269
  this._outputs = this.props.outputs.map(op => new NotebookCellOutputModel(op));
@@ -23,9 +23,6 @@ export class NotebookCellOutputModel implements Disposable {
23
23
  private didChangeDataEmitter = new Emitter<void>();
24
24
  readonly onDidChangeData = this.didChangeDataEmitter.event;
25
25
 
26
- private requestOutputPresentationChangeEmitter = new Emitter<void>();
27
- readonly onRequestOutputPresentationChange = this.requestOutputPresentationChangeEmitter.event;
28
-
29
26
  get outputId(): string {
30
27
  return this.rawOutput.outputId;
31
28
  }
@@ -54,11 +51,6 @@ export class NotebookCellOutputModel implements Disposable {
54
51
 
55
52
  dispose(): void {
56
53
  this.didChangeDataEmitter.dispose();
57
- this.requestOutputPresentationChangeEmitter.dispose();
58
- }
59
-
60
- requestOutputPresentationUpdate(): void {
61
- this.requestOutputPresentationChangeEmitter.fire();
62
54
  }
63
55
 
64
56
  getData(): CellOutput {
@@ -509,10 +509,14 @@ export class NotebookModel implements Saveable, Disposable {
509
509
  return true;
510
510
  }
511
511
 
512
- protected getCellIndexByHandle(handle: number): number {
512
+ getCellIndexByHandle(handle: number): number {
513
513
  return this.cells.findIndex(c => c.handle === handle);
514
514
  }
515
515
 
516
+ getCellByHandle(handle: number): NotebookCellModel | undefined {
517
+ return this.cells.find(c => c.handle === handle);
518
+ }
519
+
516
520
  protected isCellMetadataChanged(a: NotebookCellMetadata, b: NotebookCellMetadata): boolean {
517
521
  const keys = new Set<keyof NotebookCellMetadata>([...Object.keys(a || {}), ...Object.keys(b || {})]);
518
522
  for (const key of keys) {