Skip to content

Commit

Permalink
Save suggestions to notebook metadata (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
trungleduc authored Dec 3, 2024
1 parent 16aadd3 commit 26b0012
Show file tree
Hide file tree
Showing 18 changed files with 925 additions and 192 deletions.
1 change: 1 addition & 0 deletions packages/base/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"@jupyterlab/docregistry": "^4.0.0",
"@jupyterlab/nbformat": "^4.0.0",
"@jupyterlab/notebook": "^4.0.0",
"@jupyterlab/observables": "^4.0.0",
"@jupyterlab/rendermime": "^4.0.0",
"@jupyterlab/ui-components": "^4.0.0",
"@lumino/coreutils": "^2.0.0",
Expand Down
15 changes: 15 additions & 0 deletions packages/base/src/icons.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
import { LabIcon } from '@jupyterlab/ui-components';
import hintStr from '../style/icon/hint.svg';
import minimizeStr from '../style/icon/minimize.svg';
import expandStr from '../style/icon/expand.svg';
import collapseStr from '../style/icon/collapse.svg';

export const hintIcon = new LabIcon({
name: 'jupyter-suggestions:hintIcon',
svgstr: hintStr
});
export const minimizeIcon = new LabIcon({
name: 'jupyter-suggestions:minimizeIcon',
svgstr: minimizeStr
});
export const expandIcon = new LabIcon({
name: 'jupyter-suggestions:expandIcon',
svgstr: expandStr
});
export const collapseIcon = new LabIcon({
name: 'jupyter-suggestions:collapseIcon',
svgstr: collapseStr
});
186 changes: 177 additions & 9 deletions packages/base/src/localSuggestionsManager/localSuggestionsManager.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { INotebookTracker, NotebookPanel } from '@jupyterlab/notebook';
import {
IAllSuggestions,
IDict,
ISuggestionChange,
ISuggestionData,
ISuggestionsManager
} from '../types';
import { ISignal, Signal } from '@lumino/signaling';
import { Cell, ICellModel } from '@jupyterlab/cells';
import { UUID } from '@lumino/coreutils';
import { ICell } from '@jupyterlab/nbformat';
// import { ICell } from '@jupyterlab/nbformat';

const METADATA_KEY = 'jupyter_suggestion';
export class LocalSuggestionsManager implements ISuggestionsManager {
constructor(options: LocalSuggestionsManager.IOptions) {
this._tracker = options.tracker;
Expand All @@ -31,27 +33,36 @@ export class LocalSuggestionsManager implements ISuggestionsManager {
this._isDisposed = true;
}

getAllSuggestions(notebook: NotebookPanel): IAllSuggestions | undefined {
async getAllSuggestions(
notebook: NotebookPanel
): Promise<IAllSuggestions | undefined> {
const path = notebook.context.localPath;
if (this._suggestionsMap.has(path)) {
return this._suggestionsMap.get(path);
} else {
const savedSuggestions = notebook.context.model.getMetadata(METADATA_KEY);
if (savedSuggestions) {
const currentSuggestion = new Map<string, IDict<ISuggestionData>>(
Object.entries(savedSuggestions)
);
this._suggestionsMap.set(path, currentSuggestion);
return currentSuggestion;
}
}
// TODO Read suggestions from metadata
}

getSuggestion(options: {
async getSuggestion(options: {
notebookPath: string;
cellId: string;
suggestionId: string;
}): { content: ICell } | undefined {
}): Promise<ISuggestionData | undefined> {
const { notebookPath, cellId, suggestionId } = options;
if (this._suggestionsMap.has(notebookPath)) {
const nbSuggestions = this._suggestionsMap.get(notebookPath);
if (nbSuggestions && nbSuggestions.has(cellId)) {
return nbSuggestions.get(cellId)![suggestionId];
}
}
// TODO Read suggestions from metadata
}
async addSuggestion(options: {
notebook: NotebookPanel;
Expand All @@ -69,7 +80,18 @@ export class LocalSuggestionsManager implements ISuggestionsManager {
}
const cellSuggesions = currentSuggestions.get(cellId)!;
const suggestionId = UUID.uuid4();
cellSuggesions[suggestionId] = { content: cell.model.toJSON() };
const cellModel = cell.model.toJSON();
const suggestionContent: ISuggestionData = {
content: cellModel,
newSource: cellModel.source as string
};
cellSuggesions[suggestionId] = suggestionContent;
await this._saveSuggestionToMetadata({
notebook,
cellId,
suggestionId,
content: suggestionContent
});
this._suggestionChanged.emit({
notebookPath: path,
cellId,
Expand All @@ -79,11 +101,157 @@ export class LocalSuggestionsManager implements ISuggestionsManager {
return suggestionId;
}

async acceptSuggestion(options: {
notebook: NotebookPanel;
cellId: string;
suggestionId: string;
}): Promise<boolean> {
const { notebook, cellId, suggestionId } = options;
const notebookPath = notebook.context.localPath;

const currentSuggestion = await this.getSuggestion({
notebookPath,
cellId,
suggestionId
});
if (currentSuggestion && notebook.content.model?.cells) {
const { newSource } = currentSuggestion;
for (const element of notebook.content.model.cells) {
if (element.id === cellId) {
element.sharedModel.setSource(newSource);
await this.deleteSuggestion(options);
return true;
}
}
}
return false;
}

async deleteSuggestion(options: {
notebook: NotebookPanel;
cellId: string;
suggestionId: string;
}): Promise<void> {
const { notebook, cellId, suggestionId } = options;
const notebookPath = notebook.context.localPath;
if (this._suggestionsMap.has(notebookPath)) {
const nbSuggestions = this._suggestionsMap.get(notebookPath);
if (nbSuggestions && nbSuggestions.has(cellId)) {
delete nbSuggestions.get(cellId)![suggestionId];
await this._removeSuggestionFromMetadata({
notebook,
cellId,
suggestionId
});
this._suggestionChanged.emit({
notebookPath,
cellId,
suggestionId,
operator: 'deleted'
});
}
}
}

async updateSuggestion(options: {
notebook: NotebookPanel;
cellId: string;
suggestionId: string;
newSource: string;
}): Promise<void> {
const { notebook, cellId, suggestionId, newSource } = options;
const notebookPath = notebook.context.localPath;
if (this._suggestionsMap.has(notebookPath)) {
const nbSuggestions = this._suggestionsMap.get(notebookPath);
if (
nbSuggestions &&
nbSuggestions.has(cellId) &&
nbSuggestions.get(cellId)![suggestionId]
) {
const currentSuggestion = nbSuggestions.get(cellId)![suggestionId];
currentSuggestion.newSource = newSource;
await this._updateSuggestionInMetadata({
notebook,
cellId,
suggestionId,
newSource
});
this._suggestionChanged.emit({
notebookPath,
cellId,
suggestionId,
operator: 'modified'
});
}
}
}
private async _saveSuggestionToMetadata(options: {
notebook: NotebookPanel;
cellId: string;
suggestionId: string;
content: IDict;
}) {
const { notebook, cellId, suggestionId, content } = options;
const currentSuggestions: IDict =
notebook.context.model.getMetadata(METADATA_KEY) ?? {};

const newData = {
...currentSuggestions,
[cellId]: {
...(currentSuggestions[cellId] ?? {}),
[suggestionId]: content
}
};
notebook.context.model.setMetadata(METADATA_KEY, newData);
await notebook.context.save();
}

private async _removeSuggestionFromMetadata(options: {
notebook: NotebookPanel;
cellId: string;
suggestionId: string;
}) {
const { notebook, cellId, suggestionId } = options;
const currentSuggestions: IDict | undefined =
notebook.context.model.getMetadata(METADATA_KEY);
if (!currentSuggestions || !currentSuggestions[cellId]) {
return;
}
if (currentSuggestions[cellId][suggestionId]) {
delete currentSuggestions[cellId][suggestionId];
}
notebook.context.model.setMetadata(METADATA_KEY, currentSuggestions);
await notebook.context.save();
}

private async _updateSuggestionInMetadata(options: {
notebook: NotebookPanel;
cellId: string;
suggestionId: string;
newSource: string;
}) {
const { notebook, cellId, suggestionId, newSource } = options;
const currentSuggestions: IDict<IDict<ISuggestionData>> | undefined =
notebook.context.model.getMetadata(METADATA_KEY);
if (
!currentSuggestions ||
!currentSuggestions[cellId] ||
!currentSuggestions[cellId][suggestionId]
) {
return;
}

currentSuggestions[cellId][suggestionId].newSource = newSource;

notebook.context.model.setMetadata(METADATA_KEY, currentSuggestions);
await notebook.context.save();
}

private _notebookAdded(tracker: INotebookTracker, panel: NotebookPanel) {
panel.disposed.connect(p => {
const localPath = p.context.localPath;
if (this._suggestionsMap.has(localPath)) {
// this._suggestionsMap.delete(localPath);
this._suggestionsMap.delete(localPath);
}
});
}
Expand Down
121 changes: 0 additions & 121 deletions packages/base/src/suggestionsPanel/cellWidget.ts

This file was deleted.

Loading

0 comments on commit 26b0012

Please sign in to comment.