Fix split cell not working with attachments (#19587)

This commit is contained in:
Barbara Valdez
2022-06-01 16:23:46 -07:00
committed by GitHub
parent 071f631c34
commit f06fd7f6f7
4 changed files with 108 additions and 8 deletions

View File

@@ -1079,6 +1079,96 @@ suite('Cell Model', function (): void {
assert.deepStrictEqual(serializedCell.attachments, undefined, 'JSON should not include attachments if attachments do not exist'); assert.deepStrictEqual(serializedCell.attachments, undefined, 'JSON should not include attachments if attachments do not exist');
}); });
test('Should remove unused attachments name when updating cell source', async function () {
const cellAttachment = JSON.parse('{"ads.png":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAggg=="}}');
let notebookModel = new NotebookModelStub({
name: '',
version: '',
mimetype: ''
});
let contents: nb.ICellContents = {
cell_type: CellTypes.Markdown,
source: '',
attachments: cellAttachment
};
let model = factory.createCell(contents, { notebook: notebookModel, isTrusted: false });
assert.deepStrictEqual(model.attachments, contents.attachments, 'Attachments do not match in cellModel');
model.source = 'Test';
assert.notDeepStrictEqual(model.attachments, contents.attachments, 'Unused attachments are not removed after updating cell source');
});
test('Should not remove attachments that are still referenced in cell after updating the cell source', async function () {
const cellAttachment = JSON.parse('{"ads.png":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAggg=="}}');
let notebookModel = new NotebookModelStub({
name: '',
version: '',
mimetype: ''
});
let contents: nb.ICellContents = {
cell_type: CellTypes.Markdown,
source: '![ads.png](attachment:ads.png)',
attachments: cellAttachment
};
let model = factory.createCell(contents, { notebook: notebookModel, isTrusted: false });
model.source = '![ads.png](attachment:ads.png) \n Test';
assert.deepStrictEqual(model.attachments, contents.attachments, 'Attachments referenced in cell were removed');
});
test('Should update cell attachments', async function () {
const cellAttachment = JSON.parse('{"ads.png":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAggg=="}}');
let notebookModel = new NotebookModelStub({
name: '',
version: '',
mimetype: ''
});
let contents: nb.ICellContents = {
cell_type: CellTypes.Markdown,
source: '![ads.png](attachment:ads.png)'
};
let model = factory.createCell(contents, { notebook: notebookModel, isTrusted: false });
model.updateAttachmentsFromSource('![ads.png](attachment:ads.png)', cellAttachment);
assert.deepStrictEqual(model.attachments, cellAttachment, 'Cell attachments are not updated correctly');
});
test('Should not update cell attachments if they are not referenced in cell source', async function () {
const cellAttachment = JSON.parse('{"ads.png":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAggg=="}}');
let notebookModel = new NotebookModelStub({
name: '',
version: '',
mimetype: ''
});
let contents: nb.ICellContents = {
cell_type: CellTypes.Markdown,
source: '![ads.png](attachment:ads.png)'
};
let model = factory.createCell(contents, { notebook: notebookModel, isTrusted: false });
model.updateAttachmentsFromSource('test', cellAttachment);
assert.notDeepStrictEqual(model.attachments, cellAttachment, 'Cell attachments are updated when they are not referenced in cell source');
});
test('Should not update cell attachments if the attachment reference is not in the correct format', async function () {
const cellAttachment = JSON.parse('{"ads.png":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAggg=="}}');
let notebookModel = new NotebookModelStub({
name: '',
version: '',
mimetype: ''
});
let contents: nb.ICellContents = {
cell_type: CellTypes.Markdown,
source: '![ads.png](attachment:ads.png)'
};
let model = factory.createCell(contents, { notebook: notebookModel, isTrusted: false });
model.updateAttachmentsFromSource('ads.png', cellAttachment);
assert.notDeepStrictEqual(model.attachments, cellAttachment, 'Cell attachments are updated when the reference is not in the correct format');
});
test('Should not have cache chart data after new cell created', async function () { test('Should not have cache chart data after new cell created', async function () {
let notebookModel = new NotebookModelStub({ let notebookModel = new NotebookModelStub({
name: '', name: '',

View File

@@ -334,7 +334,7 @@ export class CellModel extends Disposable implements ICellModel {
} }
public set source(newSource: string | string[]) { public set source(newSource: string | string[]) {
this.cleanUnusedAttachments(Array.isArray(newSource) ? newSource.join() : newSource); this.updateAttachmentsFromSource(Array.isArray(newSource) ? newSource.join() : newSource);
newSource = this.attachImageFromSource(newSource); newSource = this.attachImageFromSource(newSource);
newSource = this.getMultilineSource(newSource); newSource = this.getMultilineSource(newSource);
if (this._source !== newSource) { if (this._source !== newSource) {
@@ -358,12 +358,8 @@ export class CellModel extends Disposable implements ICellModel {
return newSource; return newSource;
} }
/** public updateAttachmentsFromSource(source: string, attachments?: nb.ICellAttachments): void {
* Cleans up the attachments, removing any ones that aren't being currently used in the specified source string. const originalAttachments = attachments ? attachments : this._attachments;
* @param source The new source string to check for attachments being used
*/
private cleanUnusedAttachments(source: string): void {
const originalAttachments = this._attachments;
this._attachments = {}; this._attachments = {};
// Find existing attachments in the form ![...](attachment:...) so that we can make sure we keep those attachments // Find existing attachments in the form ![...](attachment:...) so that we can make sure we keep those attachments
const attachmentRegex = /!\[.*?\]\(attachment:(.*?)\)/g; const attachmentRegex = /!\[.*?\]\(attachment:(.*?)\)/g;

View File

@@ -554,6 +554,13 @@ export interface ICellModel {
* Returns the name of the attachment added to metadata. * Returns the name of the attachment added to metadata.
*/ */
addAttachment(mimeType: string, base64Encoding: string, name: string): string; addAttachment(mimeType: string, base64Encoding: string, name: string): string;
/**
* Updates the current cell attachments with the attachments provided.
* If no attachments are passed in then it cleans up the current cell attachments and removes any ones that aren't being currently used in the specified source string.
* @param source The new source string to check for attachments being used
* @param attachments (Optional) The new attachments for the cell
*/
updateAttachmentsFromSource(source: string, attachments?: nb.ICellAttachments): void;
richTextCursorPosition: ICaretPosition; richTextCursorPosition: ICaretPosition;
markdownCursorPosition: IPosition; markdownCursorPosition: IPosition;
/** /**

View File

@@ -570,10 +570,11 @@ export class NotebookModel extends Disposable implements INotebookModel {
let range = model.getFullModelRange(); let range = model.getFullModelRange();
let selection = editorControl.getSelection(); let selection = editorControl.getSelection();
let source = this.cells[index].source; let source = this.cells[index].source;
let newCell = undefined, tailCell = undefined, partialSource = undefined; let newCell: ICellModel = undefined, tailCell: ICellModel = undefined, partialSource = undefined;
let newCellIndex = index; let newCellIndex = index;
let tailCellIndex = index; let tailCellIndex = index;
let splitCells: SplitCell[] = []; let splitCells: SplitCell[] = [];
let attachments = {};
// Save UI state // Save UI state
let showMarkdown = this.cells[index].showMarkdown; let showMarkdown = this.cells[index].showMarkdown;
@@ -607,6 +608,9 @@ export class NotebookModel extends Disposable implements INotebookModel {
partialSource = source.slice(selection.startLineNumber - 1, selection.startLineNumber)[0].slice(0, selection.startColumn - 1); partialSource = source.slice(selection.startLineNumber - 1, selection.startLineNumber)[0].slice(0, selection.startColumn - 1);
headsource = headsource.concat(partialSource.toString()); headsource = headsource.concat(partialSource.toString());
} }
// Save attachments before updating cell contents
attachments = this.cells[index].attachments;
// No need to update attachments, since unused attachments are removed when updating the cell source
this.cells[index].source = headsource; this.cells[index].source = headsource;
splitCells.push({ cell: this.cells[index], prefix: undefined }); splitCells.push({ cell: this.cells[index], prefix: undefined });
} }
@@ -628,6 +632,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
//If the selection is not from the start of the cell, create a new cell. //If the selection is not from the start of the cell, create a new cell.
if (headContent.length) { if (headContent.length) {
newCell = this.createCell(cellType, language); newCell = this.createCell(cellType, language);
newCell.updateAttachmentsFromSource(newSource.join(), attachments);
newCell.source = newSource; newCell.source = newSource;
newCellIndex++; newCellIndex++;
this.insertCell(newCell, newCellIndex, false); this.insertCell(newCell, newCellIndex, false);
@@ -651,6 +656,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
if (tailSource[0] === '\r\n' || tailSource[0] === '\n') { if (tailSource[0] === '\r\n' || tailSource[0] === '\n') {
newlinesBeforeTailCellContent = tailSource.splice(0, 1)[0]; newlinesBeforeTailCellContent = tailSource.splice(0, 1)[0];
} }
tailCell.updateAttachmentsFromSource(tailSource.join(), attachments);
tailCell.source = tailSource; tailCell.source = tailSource;
tailCellIndex = newCellIndex + 1; tailCellIndex = newCellIndex + 1;
this.insertCell(tailCell, tailCellIndex, false); this.insertCell(tailCell, tailCellIndex, false);
@@ -684,6 +690,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
let firstCell = cells[0].cell; let firstCell = cells[0].cell;
// Append the other cell sources to the first cell // Append the other cell sources to the first cell
for (let i = 1; i < cells.length; i++) { for (let i = 1; i < cells.length; i++) {
firstCell.attachments = { ...firstCell.attachments, ...cells[i].cell.attachments };
firstCell.source = cells[i].prefix ? [...firstCell.source, ...cells[i].prefix, ...cells[i].cell.source] : [...firstCell.source, ...cells[i].cell.source]; firstCell.source = cells[i].prefix ? [...firstCell.source, ...cells[i].prefix, ...cells[i].cell.source] : [...firstCell.source, ...cells[i].cell.source];
} }
// Set newly created cell as active cell // Set newly created cell as active cell