Skip to content

Commit 9b1e3c6

Browse files
committed
Adding Accept and Reject All buttons for bulk changes.
1 parent a6cab6d commit 9b1e3c6

File tree

4 files changed

+140
-10
lines changed

4 files changed

+140
-10
lines changed

src/diff/base-unified-diff.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -123,17 +123,20 @@ export abstract class BaseUnifiedDiffManager {
123123
/**
124124
* Accept all changes
125125
*/
126-
protected acceptAll(): void {
127-
// simply accept the current state
126+
public acceptAll(): void {
127+
const sharedModel = this.getSharedModel();
128+
this._originalSource = sharedModel.getSource();
129+
this._newSource = this._originalSource;
128130
this._deactivate();
129131
}
130132

131133
/**
132134
* Reject all changes
133135
*/
134-
protected rejectAll(): void {
136+
public rejectAll(): void {
135137
const sharedModel = this.getSharedModel();
136138
sharedModel.setSource(this._originalSource);
139+
this._newSource = this._originalSource;
137140
this._deactivate();
138141
}
139142

@@ -172,9 +175,9 @@ export abstract class BaseUnifiedDiffManager {
172175
protected showActionButtons: boolean;
173176
protected acceptAllButton: ToolbarButton | null = null;
174177
protected rejectAllButton: ToolbarButton | null = null;
175-
private _originalSource: string;
176178
private _newSource: string;
177179
private _isInitialized: boolean;
178180
private _isDisposed: boolean;
179181
private _diffCompartment: Compartment;
182+
public _originalSource: string;
180183
}

src/diff/unified-cell.ts

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,17 @@ export class UnifiedCellDiffManager extends BaseUnifiedDiffManager {
3333
super(options);
3434
this._cell = options.cell;
3535
this._cellFooterTracker = options.cellFooterTracker;
36+
this._originalSource = options.originalSource ?? '';
3637
this.activate();
3738
}
3839

40+
/**
41+
* Check if this cell still has pending changes
42+
*/
43+
public hasPendingChanges(): boolean {
44+
return this._originalSource !== this._cell.sharedModel.getSource();
45+
}
46+
3947
/**
4048
* Get the shared model for source manipulation
4149
*/
@@ -51,6 +59,11 @@ export class UnifiedCellDiffManager extends BaseUnifiedDiffManager {
5159
return;
5260
}
5361

62+
if (!this.hasPendingChanges()) {
63+
this.removeToolbarButtons();
64+
return;
65+
}
66+
5467
const cellId = this._cell.id;
5568
const footer = this._cellFooterTracker.getFooter(cellId);
5669
if (!footer) {
@@ -59,19 +72,17 @@ export class UnifiedCellDiffManager extends BaseUnifiedDiffManager {
5972

6073
this.acceptAllButton = new ToolbarButton({
6174
icon: checkIcon,
62-
label: this.trans.__('Accept All'),
63-
tooltip: this.trans.__('Accept all chunks'),
75+
label: this.trans.__('Accept'),
76+
tooltip: this.trans.__('Accept changes in this cell'),
6477
enabled: true,
65-
className: 'jp-UnifiedDiff-acceptAll',
6678
onClick: () => this.acceptAll()
6779
});
6880

6981
this.rejectAllButton = new ToolbarButton({
7082
icon: undoIcon,
71-
label: this.trans.__('Reject All'),
72-
tooltip: this.trans.__('Reject all chunks'),
83+
label: this.trans.__('Reject'),
84+
tooltip: this.trans.__('Reject changes in this cell'),
7385
enabled: true,
74-
className: 'jp-UnifiedDiff-rejectAll',
7586
onClick: () => this.rejectAll()
7687
});
7788

src/plugin.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
UnifiedFileDiffManager
2020
} from './diff/unified-file';
2121
import { CodeMirrorEditor } from '@jupyterlab/codemirror';
22+
import { ToolbarButton } from '@jupyterlab/ui-components';
2223

2324
/**
2425
* The translation namespace for the plugin.
@@ -63,6 +64,29 @@ export function findCell(
6364
return cell ?? null;
6465
}
6566

67+
/**
68+
* Registry for notebook-level diff managers
69+
*/
70+
const notebookDiffRegistry = new Map<string, UnifiedCellDiffManager[]>();
71+
72+
let registerCellManager = (
73+
notebookId: string,
74+
manager: UnifiedCellDiffManager
75+
): void => {
76+
if (!notebookDiffRegistry.has(notebookId)) {
77+
notebookDiffRegistry.set(notebookId, []);
78+
}
79+
notebookDiffRegistry.get(notebookId)!.push(manager);
80+
};
81+
82+
function getNotebookManagers(notebookId: string) {
83+
return notebookDiffRegistry.get(notebookId) || [];
84+
}
85+
86+
function clearNotebookManagers(notebookId: string) {
87+
notebookDiffRegistry.delete(notebookId);
88+
}
89+
6690
/**
6791
* Split cell diff plugin - shows side-by-side comparison
6892
*/
@@ -283,8 +307,69 @@ const unifiedCellDiffPlugin: JupyterFrontEndPlugin<void> = {
283307
trans
284308
});
285309
cellDiffManagers.set(cell.id, manager);
310+
311+
registerCellManager(currentNotebook.id, manager);
286312
}
287313
});
314+
notebookTracker.widgetAdded.connect((sender, notebookPanel) => {
315+
const notebookId = notebookPanel.id;
316+
317+
let acceptAllButton: ToolbarButton | null = null;
318+
let rejectAllButton: ToolbarButton | null = null;
319+
320+
function updateToolbar() {
321+
const managers = getNotebookManagers(notebookId);
322+
323+
const anyPending = managers.some(m => m.hasPendingChanges());
324+
if (!anyPending) {
325+
if (acceptAllButton) {
326+
acceptAllButton.dispose();
327+
}
328+
if (rejectAllButton) {
329+
rejectAllButton.dispose();
330+
}
331+
acceptAllButton = null;
332+
rejectAllButton = null;
333+
return;
334+
}
335+
336+
if (!acceptAllButton) {
337+
acceptAllButton = new ToolbarButton({
338+
label: trans.__('Accept All'),
339+
className: 'accept-all-changes',
340+
tooltip: trans.__('Accept all changes in this notebook'),
341+
onClick: () => {
342+
getNotebookManagers(notebookId).forEach(m => m.acceptAll());
343+
updateToolbar();
344+
}
345+
});
346+
notebookPanel.toolbar.addItem('accept-all-changes', acceptAllButton);
347+
}
348+
349+
if (!rejectAllButton) {
350+
rejectAllButton = new ToolbarButton({
351+
label: trans.__('Reject All'),
352+
className: 'reject-all-changes',
353+
tooltip: trans.__('Reject all changes in this notebook'),
354+
onClick: () => {
355+
getNotebookManagers(notebookId).forEach(m => m.rejectAll());
356+
updateToolbar();
357+
}
358+
});
359+
notebookPanel.toolbar.addItem('reject-all-changes', rejectAllButton);
360+
}
361+
}
362+
363+
notebookPanel.disposed.connect(() => clearNotebookManagers(notebookId));
364+
notebookPanel.node.addEventListener('diff-updated', updateToolbar);
365+
366+
const originalRegister = registerCellManager;
367+
registerCellManager = (nid: string, manager: UnifiedCellDiffManager) => {
368+
originalRegister(nid, manager);
369+
const event = new Event('diff-updated');
370+
notebookPanel.node.dispatchEvent(event);
371+
};
372+
});
288373
}
289374
};
290375

style/base.css

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,34 @@
7777
background-color: var(--jp-layout-color3);
7878
border-color: var(--jp-border-color1);
7979
}
80+
81+
.jp-ToolbarButtonComponent.accept-all-changes {
82+
background-color: #28a745;
83+
cursor: pointer;
84+
padding: 2px 8px;
85+
border-radius: 4px;
86+
font-size: 12px;
87+
transition:
88+
background-color 0.2s,
89+
border-color 0.2s;
90+
}
91+
92+
.jp-ToolbarButtonComponent.accept-all-changes:hover {
93+
background-color: #058522;
94+
}
95+
96+
.jp-ToolbarButtonComponent.reject-all-changes {
97+
background-color: #dc3545;
98+
cursor: pointer;
99+
padding: 2px 8px;
100+
border-radius: 4px;
101+
font-size: 12px;
102+
font-weight: bold;
103+
transition:
104+
background-color 0.2s,
105+
border-color 0.2s;
106+
}
107+
108+
.jp-ToolbarButtonComponent.reject-all-changes:hover {
109+
background-color: #c82333;
110+
}

0 commit comments

Comments
 (0)