Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion jupyter_rtc_core/outputs/output_processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ def process_incoming_message(self, channel: str, msg: list[bytes]):
room_id = f"json:notebook:{self._file_id}"
asyncio.create_task(self.clear_cell_outputs(cell_id, room_id))
self.outputs_manager.clear(file_id=self._file_id, cell_id=cell_id)
self.outputs_manager.clear(file_id=self._file_id)
self.log.info(f"Saving (msg_id, cell_id): ({msg_id} {cell_id})")
self.set_cell_id(msg_id, cell_id)

Expand Down
113 changes: 37 additions & 76 deletions src/notebook.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,14 @@
// @ts-nocheck
import {
Cell,
CodeCell,
CellModel,
CodeCellModel,
MarkdownCellModel,
RawCellModel
} from '@jupyterlab/cells';
import { CodeCell, CodeCellModel } from '@jupyterlab/cells';
import { NotebookPanel } from '@jupyterlab/notebook';
import { KernelMessage } from '@jupyterlab/services';
import {
CellChange,
createMutex,
ISharedCodeCell,
ISharedMarkdownCell,
ISharedRawCell,
YCodeCell
} from '@jupyter/ydoc';
import { CellChange, createMutex, ISharedCodeCell } from '@jupyter/ydoc';
import { IOutputAreaModel, OutputAreaModel } from '@jupyterlab/outputarea';
import { IOutputModel } from '@jupyterlab/rendermime';
import { requestAPI } from './handler';
import { CellList } from '@jupyterlab/notebook';

import { ObservableList } from '@jupyterlab/observables';

const globalModelDBMutex = createMutex();


// @ts-ignore
CodeCellModel.prototype._onSharedModelChanged = function (
slot: ISharedCodeCell,
Expand Down Expand Up @@ -130,92 +113,70 @@ CodeCellModel.prototype.onOutputsChange = function (
event: IOutputAreaModel.ChangedArgs
) {
console.debug('Inside onOutputsChange, called with event: ', event);
return
// @ts-ignore
const codeCell = this.sharedModel as YCodeCell;
globalModelDBMutex(() => {
if (event.type == 'remove') {
codeCell.updateOutputs(event.oldIndex, event.oldValues.length, []);
}
});
};

class RtcOutputAreaModel extends OutputAreaModel implements IOutputAreaModel{
/**
* Construct a new observable outputs instance.
*/
/* A new OutputAreaModel that loads outputs from outputs service */
class RtcOutputAreaModel extends OutputAreaModel implements IOutputAreaModel {
constructor(options: IOutputAreaModel.IOptions = {}) {
super({...options, values: []})
super({ ...options, values: [] });
// @ts-ignore
this._trusted = !!options.trusted;
// @ts-ignore
this.contentFactory =
options.contentFactory || OutputAreaModel.defaultContentFactory;
this.list = new ObservableList<IOutputModel>();
// @ts-ignore
this.list.changed.connect(this._onListChanged, this);
if (options.values) {
// Create an array to store promises for each value
const valuePromises = options.values.map((value, originalIndex) => {
console.log("originalIndex: ", originalIndex, ", value: ", value);
// If value has a URL, fetch the data, otherwise just use the value directly
const valuePromises = options.values.map((value, index) => {
console.debug('output #${index}, value: ${value}');
// @ts-ignore
if (value.metadata?.url) {
// @ts-ignore
Comment on lines +122 to +136
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are all of these @ts-ignores needed?

return requestAPI(value.metadata.url)
.then(data => {
console.log("data from outputs service: " , data)
return {data, originalIndex}
return data;
})
.catch(error => {
console.error('Error fetching output:', error);
// If fetch fails, return original value to maintain order
return { data: null, originalIndex };
return null;
});
} else {
// For values without url, return immediately with original value
return Promise.resolve({ data: value, originalIndex });
return Promise.resolve(value);
}
});

// Wait for all promises to resolve and add values in original order
Promise.all(valuePromises)
.then(results => {
// Sort by original index to maintain order
results.sort((a, b) => a.originalIndex - b.originalIndex);

console.log("After fetching outputs...")
// Add each value in order
results.forEach((result) => {
console.log("originalIndex: ", result.originalIndex, ", data: ", result.data)
if(result.data && !this.isDisposed){
const index = this._add(result.data) - 1;
const item = this.list.get(index);
item.changed.connect(this._onGenericChange, this);
}
});

// Connect the list changed handler after all items are added
//this.list.changed.connect(this._onListChanged, this);
})/*
.catch(error => {
console.error('Error processing values:', error);
// If something goes wrong, fall back to original behavior
options.values.forEach(value => {
const index = this._add(value) - 1;
Promise.all(valuePromises).then(results => {
console.log('After fetching from outputs service:');
// Add each value in order
results.forEach((data, index) => {
console.debug('output #${index}, data: ${data}');
if (data && !this.isDisposed) {
// @ts-ignore
const index = this._add(data) - 1;
const item = this.list.get(index);
// @ts-ignore
item.changed.connect(this._onGenericChange, this);
});
this.list.changed.connect(this._onListChanged, this);
});*/
} else {
// If no values, just connect the list changed handler
//this.list.changed.connect(this._onListChanged, this);
}
});
});
}

this.list.changed.connect(this._onListChanged, this);
}
}

CodeCellModel.ContentFactory.prototype.createOutputArea = function(options: IOutputAreaModel.IOptions): IOutputAreaModel {
CodeCellModel.ContentFactory.prototype.createOutputArea = function (
options: IOutputAreaModel.IOptions
): IOutputAreaModel {
return new RtcOutputAreaModel(options);
}
};

export class YNotebookContentFactory extends NotebookPanel.ContentFactory implements NotebookPanel.IContentFactory{
export class YNotebookContentFactory
extends NotebookPanel.ContentFactory
implements NotebookPanel.IContentFactory
{
createCodeCell(options: CodeCell.IOptions): CodeCell {
return new CodeCell(options).initializeState();
}
Expand Down
Loading