@jupyterlab/notebook 4.6.0-rc.1 → 4.7.0-alpha.0

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jupyterlab/notebook",
3
- "version": "4.6.0-rc.1",
3
+ "version": "4.7.0-alpha.0",
4
4
  "description": "JupyterLab - Notebook",
5
5
  "homepage": "https://github.com/jupyterlab/jupyterlab",
6
6
  "bugs": {
@@ -41,24 +41,25 @@
41
41
  },
42
42
  "dependencies": {
43
43
  "@jupyter/ydoc": "^4.0.0",
44
- "@jupyterlab/apputils": "^4.7.0-rc.1",
45
- "@jupyterlab/cells": "^4.6.0-rc.1",
46
- "@jupyterlab/codeeditor": "^4.6.0-rc.1",
47
- "@jupyterlab/codemirror": "^4.6.0-rc.1",
48
- "@jupyterlab/coreutils": "^6.6.0-rc.1",
49
- "@jupyterlab/docregistry": "^4.6.0-rc.1",
50
- "@jupyterlab/documentsearch": "^4.6.0-rc.1",
51
- "@jupyterlab/lsp": "^4.6.0-rc.1",
52
- "@jupyterlab/markedparser-extension": "^4.6.0-rc.1",
53
- "@jupyterlab/nbformat": "^4.6.0-rc.1",
54
- "@jupyterlab/observables": "^5.6.0-rc.1",
55
- "@jupyterlab/rendermime": "^4.6.0-rc.1",
56
- "@jupyterlab/services": "^7.6.0-rc.1",
57
- "@jupyterlab/settingregistry": "^4.6.0-rc.1",
58
- "@jupyterlab/statusbar": "^4.6.0-rc.1",
59
- "@jupyterlab/toc": "^6.6.0-rc.1",
60
- "@jupyterlab/translation": "^4.6.0-rc.1",
61
- "@jupyterlab/ui-components": "^4.6.0-rc.1",
44
+ "@jupyterlab/apputils": "^4.8.0-alpha.0",
45
+ "@jupyterlab/cells": "^4.7.0-alpha.0",
46
+ "@jupyterlab/codeeditor": "^4.7.0-alpha.0",
47
+ "@jupyterlab/codemirror": "^4.7.0-alpha.0",
48
+ "@jupyterlab/coreutils": "^6.7.0-alpha.0",
49
+ "@jupyterlab/docregistry": "^4.7.0-alpha.0",
50
+ "@jupyterlab/documentsearch": "^4.7.0-alpha.0",
51
+ "@jupyterlab/lsp": "^4.7.0-alpha.0",
52
+ "@jupyterlab/markedparser-extension": "^4.7.0-alpha.0",
53
+ "@jupyterlab/nbformat": "^4.7.0-alpha.0",
54
+ "@jupyterlab/observables": "^5.7.0-alpha.0",
55
+ "@jupyterlab/outputarea": "^4.7.0-alpha.0",
56
+ "@jupyterlab/rendermime": "^4.7.0-alpha.0",
57
+ "@jupyterlab/services": "^7.7.0-alpha.0",
58
+ "@jupyterlab/settingregistry": "^4.7.0-alpha.0",
59
+ "@jupyterlab/statusbar": "^4.7.0-alpha.0",
60
+ "@jupyterlab/toc": "^6.7.0-alpha.0",
61
+ "@jupyterlab/translation": "^4.7.0-alpha.0",
62
+ "@jupyterlab/ui-components": "^4.7.0-alpha.0",
62
63
  "@lumino/algorithm": "^2.0.4",
63
64
  "@lumino/commands": "^2.3.3",
64
65
  "@lumino/coreutils": "^2.2.2",
@@ -74,7 +75,7 @@
74
75
  "react": "^18.2.0"
75
76
  },
76
77
  "devDependencies": {
77
- "@jupyterlab/testing": "^4.6.0-rc.1",
78
+ "@jupyterlab/testing": "^4.7.0-alpha.0",
78
79
  "@types/jest": "^29.2.0",
79
80
  "jest": "^29.2.0",
80
81
  "rimraf": "~5.0.5",
package/src/actions.tsx CHANGED
@@ -603,15 +603,77 @@ export namespace NotebookActions {
603
603
  lastIndex = notebook.model.cells.length;
604
604
  }
605
605
 
606
- if (shift > 0) {
607
- notebook.moveCell(firstIndex, lastIndex, lastIndex - firstIndex);
608
- } else {
609
- notebook.moveCell(firstIndex, firstIndex + shift, lastIndex - firstIndex);
610
- }
606
+ const toIndex = shift > 0 ? lastIndex : firstIndex + shift;
607
+ moveCells(notebook, firstIndex, toIndex, lastIndex - firstIndex);
611
608
 
612
609
  void Private.handleState(notebook, state, true);
613
610
  }
614
611
 
612
+ /**
613
+ * Move cells while preserving in-flight kernel futures.
614
+ *
615
+ * The underlying `jupyter-ydoc` `moveCells` implementation currently
616
+ * serializes cells to JSON and recreates them via a delete + insert
617
+ * transaction, which disposes any active kernel futures attached to the
618
+ * old widgets. This wrapper detaches futures before the move and
619
+ * reattaches them to the new widgets afterwards, and stores them in the
620
+ * undo stack so that undoing the move also restores execution state.
621
+ *
622
+ * @param notebook - The target notebook.
623
+ * @param from - Index of the first cell to move.
624
+ * @param to - Target index (as passed to `notebook.moveCell`).
625
+ * @param n - Number of cells to move.
626
+ */
627
+ export function moveCells(
628
+ notebook: Notebook,
629
+ from: number,
630
+ to: number,
631
+ n = 1
632
+ ): void {
633
+ if (!notebook.model) {
634
+ return;
635
+ }
636
+
637
+ // Mirror `Notebook.moveCell`'s bounding/no-op logic so that we do not
638
+ // capture futures or touch the undo stack when the move won't happen.
639
+ // Otherwise we could attach execution metadata to an unrelated previous
640
+ // undo item, corrupting subsequent undo behavior.
641
+ const boundedTo = Math.min(
642
+ notebook.model.cells.length - 1,
643
+ Math.max(0, to)
644
+ );
645
+ if (boundedTo === from) {
646
+ return;
647
+ }
648
+
649
+ // moveCells serializes cells to JSON and recreates widgets (delete+insert),
650
+ // which would dispose any in-flight futures. Capture them first.
651
+ const storedExecutions: Private.IStoredCellExecution[] = [];
652
+ notebook.widgets.slice(from, from + n).forEach(child => {
653
+ if (!(child instanceof CodeCell)) {
654
+ return;
655
+ }
656
+ const stored = Private.captureExecution(child);
657
+ if (stored) {
658
+ storedExecutions.push(stored);
659
+ }
660
+ });
661
+
662
+ notebook.moveCell(from, to, n);
663
+
664
+ // Immediately reconnect futures to the newly created widgets.
665
+ for (const stored of storedExecutions) {
666
+ Private.restoreExecution(notebook, stored);
667
+ }
668
+
669
+ // Store in the undo stack so that undoing the move can also restore state.
670
+ if (storedExecutions.length > 0) {
671
+ const undoManager = (notebook.model.sharedModel as YNotebook).undoManager;
672
+ const lastItem = undoManager.undoStack[undoManager.undoStack.length - 1];
673
+ lastItem?.meta.set(Private.CELL_EXECUTION_META_KEY, storedExecutions);
674
+ }
675
+ }
676
+
615
677
  /**
616
678
  * Move the selected cell(s) down.
617
679
  *
@@ -1530,6 +1592,19 @@ export namespace NotebookActions {
1530
1592
  switch (mode) {
1531
1593
  case 'below':
1532
1594
  index = notebook.activeCellIndex + 1;
1595
+ // If the active cell is a collapsed markdown heading with children,
1596
+ // insert after all the children, not just after the heading.
1597
+ {
1598
+ const activeCell = notebook.activeCell;
1599
+ if (
1600
+ activeCell instanceof MarkdownCell &&
1601
+ activeCell.headingCollapsed &&
1602
+ activeCell.numberChildNodes > 0
1603
+ ) {
1604
+ index =
1605
+ notebook.activeCellIndex + activeCell.numberChildNodes + 1;
1606
+ }
1607
+ }
1533
1608
  break;
1534
1609
  case 'belowSelected':
1535
1610
  notebook.widgets.forEach((child, childIndex) => {
@@ -1537,7 +1612,24 @@ export namespace NotebookActions {
1537
1612
  index = childIndex + 1;
1538
1613
  }
1539
1614
  });
1540
-
1615
+ // If the last selected cell is a collapsed markdown heading with children,
1616
+ // insert after all the children, not just after the heading.
1617
+ {
1618
+ const lastSelectedIndex = index - 1;
1619
+ if (
1620
+ lastSelectedIndex >= 0 &&
1621
+ lastSelectedIndex < notebook.widgets.length
1622
+ ) {
1623
+ const widget = notebook.widgets[lastSelectedIndex];
1624
+ if (
1625
+ widget instanceof MarkdownCell &&
1626
+ widget.headingCollapsed &&
1627
+ widget.numberChildNodes > 0
1628
+ ) {
1629
+ index = lastSelectedIndex + widget.numberChildNodes + 1;
1630
+ }
1631
+ }
1632
+ }
1541
1633
  break;
1542
1634
  case 'above':
1543
1635
  index = notebook.activeCellIndex;
@@ -1609,9 +1701,37 @@ export namespace NotebookActions {
1609
1701
  const state = Private.getState(notebook);
1610
1702
  notebook.mode = 'command';
1611
1703
 
1704
+ const undoManager = (notebook.model.sharedModel as YNotebook).undoManager;
1705
+
1706
+ // For cells that will be MOVED by the undo (i.e. they still exist in the
1707
+ // notebook at their current position), pre-capture their futures now before
1708
+ // sharedModel.undo() destroys those widgets. This prevents OutputArea.dispose()
1709
+ // from cancelling the future during the Y.js delete+insert that implements the move.
1710
+ const topItem = undoManager.undoStack[undoManager.undoStack.length - 1];
1711
+ const pendingExecutions = topItem?.meta.get(
1712
+ Private.CELL_EXECUTION_META_KEY
1713
+ ) as Private.IStoredCellExecution[] | undefined;
1714
+ const preCaptured = new Map<string, Private.IStoredCellExecution>();
1715
+ pendingExecutions?.forEach(stored => {
1716
+ const cell = notebook.widgets.find(w => w.model.id === stored.cellId);
1717
+ if (!(cell instanceof CodeCell)) {
1718
+ return; // cell was deleted (not moved) — handled via stored future below
1719
+ }
1720
+ // Cell still present → move undo. Fresh capture protects the future.
1721
+ const fresh = Private.captureExecution(cell) ?? {
1722
+ ...stored,
1723
+ isDone: () => true,
1724
+ buffered: []
1725
+ };
1726
+ // The undo will roll the outputs back to their state at the time of
1727
+ // the move; snapshot the current outputs so anything received since
1728
+ // then can be re-applied after the undo.
1729
+ fresh.outputs = cell.model.outputs.toJSON();
1730
+ preCaptured.set(stored.cellId, fresh);
1731
+ });
1732
+
1612
1733
  // Capture execution context from the stack item being popped.
1613
1734
  let storedExecutions: Private.IStoredCellExecution[] | undefined;
1614
- const undoManager = (notebook.model.sharedModel as YNotebook).undoManager;
1615
1735
  const onStackItemPopped = ({
1616
1736
  stackItem
1617
1737
  }: {
@@ -1625,40 +1745,13 @@ export namespace NotebookActions {
1625
1745
  notebook.model.sharedModel.undo();
1626
1746
  undoManager.off('stack-item-popped', onStackItemPopped);
1627
1747
 
1628
- // Restore execution state on resurrected cell widgets.
1629
- storedExecutions?.forEach(({ cellId, future, isDone, buffered }) => {
1630
- const cell = notebook.widgets.find(w => w.model.id === cellId);
1631
- if (!(cell instanceof CodeCell)) {
1632
- return;
1633
- }
1634
- if (isDone()) {
1635
- // Execution finished or was interrupted before undo - ensure state is idle.
1636
- cell.model.executionState = 'idle';
1637
- return;
1638
- }
1639
- // Still running - reconnect the future so the cell receives remaining
1640
- // output and stdin requests (e.g. input()), and tracks the idle transition.
1641
- cell.outputArea.reattachFuture(future);
1642
- // Replay any IOPub messages that arrived while the future was detached.
1643
- // After reattachFuture, future.onIOPub routes to the new output area.
1644
- for (const msg of buffered) {
1645
- void future.onIOPub(msg);
1646
- }
1647
- // The original execute() call targeted the old cell widget, so it will
1648
- // not update executionCount/executionState on this resurrected cell.
1649
- // Drive the idle transition here instead.
1650
- const cellRef = cell;
1651
- void future.done.then(
1652
- reply => {
1653
- if (!cellRef.isDisposed) {
1654
- cellRef.model.executionCount = reply.content.execution_count;
1655
- }
1656
- },
1657
- () => {
1658
- if (!cellRef.isDisposed) {
1659
- cellRef.model.executionState = 'idle';
1660
- }
1661
- }
1748
+ // Restore execution state on resurrected/moved cell widgets.
1749
+ // For move-undo: use freshly pre-captured data (stored data is stale).
1750
+ // For delete-undo: stored data has the futures captured at deletion time.
1751
+ storedExecutions?.forEach(stored => {
1752
+ Private.restoreExecution(
1753
+ notebook,
1754
+ preCaptured.get(stored.cellId) ?? stored
1662
1755
  );
1663
1756
  });
1664
1757
 
@@ -2568,6 +2661,15 @@ namespace Private {
2568
2661
  /** Key used to store cell execution state in Y.js undo stack item metadata. */
2569
2662
  export const CELL_EXECUTION_META_KEY = Symbol('cellExecutionState');
2570
2663
 
2664
+ /**
2665
+ * A kernel message that arrived while the future was detached, tagged with
2666
+ * its channel so it can be dispatched to the right handler on replay.
2667
+ */
2668
+ export type IBufferedMessage =
2669
+ | { channel: 'iopub'; msg: KernelMessage.IIOPubMessage }
2670
+ | { channel: 'stdin'; msg: KernelMessage.IStdinMessage }
2671
+ | { channel: 'reply'; msg: KernelMessage.IExecuteReplyMsg };
2672
+
2571
2673
  export interface IStoredCellExecution {
2572
2674
  cellId: string;
2573
2675
  future: Kernel.IShellFuture<
@@ -2575,13 +2677,28 @@ namespace Private {
2575
2677
  KernelMessage.IExecuteReplyMsg
2576
2678
  >;
2577
2679
  isDone: () => boolean;
2578
- /** IOPub messages that arrived while the future was detached. */
2579
- buffered: KernelMessage.IIOPubMessage[];
2680
+ /**
2681
+ * Kernel messages (IOPub, stdin and reply) that arrived while the future
2682
+ * was detached, in arrival order, so they can be replayed on reattach.
2683
+ */
2684
+ buffered: IBufferedMessage[];
2685
+ /**
2686
+ * Snapshot of the cell outputs to restore after an undo.
2687
+ *
2688
+ * The Y.js undo of a move (a delete + insert transaction) resurrects the
2689
+ * cell as it was when the move happened, rolling back any output received
2690
+ * since. Re-applying this snapshot after the undo prevents that loss.
2691
+ */
2692
+ outputs?: nbformat.IOutput[];
2580
2693
  }
2581
2694
 
2582
2695
  /**
2583
- * Detach the kernel future from a code cell, buffering any IOPub messages
2584
- * that arrive while it is detached so they can be replayed on reattach.
2696
+ * Detach the kernel future from a code cell, buffering any messages that
2697
+ * arrive while it is detached so they can be replayed on reattach.
2698
+ *
2699
+ * `detachFuture` clears the IOPub, stdin and reply handlers, so all three
2700
+ * channels are buffered here; otherwise a message arriving during the
2701
+ * detached window (e.g. an `input()` request on stdin) would be dropped.
2585
2702
  *
2586
2703
  * Returns null if the cell has no active future.
2587
2704
  */
@@ -2596,13 +2713,88 @@ namespace Private {
2596
2713
  void future.done.finally(() => {
2597
2714
  done = true;
2598
2715
  });
2599
- const buffered: KernelMessage.IIOPubMessage[] = [];
2716
+ const buffered: IBufferedMessage[] = [];
2600
2717
  future.onIOPub = msg => {
2601
- buffered.push(msg);
2718
+ buffered.push({ channel: 'iopub', msg });
2719
+ };
2720
+ future.onStdin = msg => {
2721
+ buffered.push({ channel: 'stdin', msg });
2722
+ };
2723
+ future.onReply = msg => {
2724
+ buffered.push({ channel: 'reply', msg });
2602
2725
  };
2603
2726
  return { cellId: cell.model.id, future, isDone: () => done, buffered };
2604
2727
  }
2605
2728
 
2729
+ /**
2730
+ * Reconnect a captured execution to the cell widget that now holds the model.
2731
+ *
2732
+ * Handles both the "still running" and "already finished" cases.
2733
+ */
2734
+ export function restoreExecution(
2735
+ notebook: Notebook,
2736
+ { cellId, future, isDone, buffered, outputs }: IStoredCellExecution
2737
+ ): void {
2738
+ const cell = notebook.widgets.find(w => w.model.id === cellId);
2739
+ if (!(cell instanceof CodeCell)) {
2740
+ return;
2741
+ }
2742
+ if (outputs && !JSONExt.deepEqual(outputs, cell.model.outputs.toJSON())) {
2743
+ // Re-apply the output snapshot taken just before the undo: the Y.js
2744
+ // undo rolled the outputs back to their state at the time of the
2745
+ // undone action. Going through the output area model keeps the
2746
+ // in-memory model and the shared model in sync (output changes are
2747
+ // not tracked by the undo manager, so this does not pollute history).
2748
+ cell.model.outputs.fromJSON(outputs);
2749
+ }
2750
+ // Reattach the future (without clearing existing outputs) and replay any
2751
+ // messages buffered while it was detached, in arrival order. This is done
2752
+ // whether or not the execution has already finished, so that final outputs
2753
+ // (or a pending stdin request) that arrived while detached are not lost
2754
+ // (e.g. if the kernel completed in the brief window during the undo).
2755
+ cell.outputArea.reattachFuture(future);
2756
+ for (const buf of buffered) {
2757
+ switch (buf.channel) {
2758
+ case 'iopub':
2759
+ void future.onIOPub(buf.msg);
2760
+ break;
2761
+ case 'stdin':
2762
+ void future.onStdin(buf.msg);
2763
+ break;
2764
+ case 'reply':
2765
+ void future.onReply(buf.msg);
2766
+ break;
2767
+ }
2768
+ }
2769
+ if (isDone()) {
2770
+ // The execution already finished (e.g. it completed or was interrupted
2771
+ // during the undo). The resurrected cell may carry a stale 'running'
2772
+ // state from its restored snapshot, so reset it synchronously rather
2773
+ // than relying solely on the asynchronous `future.done` handler below.
2774
+ cell.model.executionState = 'idle';
2775
+ } else {
2776
+ // Restore the running state on the recreated cell widget.
2777
+ cell.model.executionState = 'running';
2778
+ }
2779
+ const cellRef = cell;
2780
+ void future.done.then(
2781
+ reply => {
2782
+ if (!cellRef.isDisposed) {
2783
+ // The future is authoritative for the prompt number; a snapshot
2784
+ // taken before completion would be stale (still null). Setting a
2785
+ // non-null execution count also flips the state back to 'idle'.
2786
+ cellRef.model.executionCount = reply.content.execution_count;
2787
+ cellRef.model.executionState = 'idle';
2788
+ }
2789
+ },
2790
+ () => {
2791
+ if (!cellRef.isDisposed) {
2792
+ cellRef.model.executionState = 'idle';
2793
+ }
2794
+ }
2795
+ );
2796
+ }
2797
+
2606
2798
  /**
2607
2799
  * Notebook cell executor
2608
2800
  */
@@ -2909,8 +3101,30 @@ namespace Private {
2909
3101
  * @returns A list of 0 or more selected cells
2910
3102
  */
2911
3103
  export function selectedCells(notebook: Notebook): nbformat.ICell[] {
2912
- return notebook.widgets
2913
- .filter(cell => notebook.isSelectedOrActive(cell))
3104
+ const cellsToInclude = new Set<Cell>();
3105
+
3106
+ // Collect all selected/active cells and expand collapsed sections
3107
+ for (let i = 0; i < notebook.widgets.length; i++) {
3108
+ const cell = notebook.widgets[i];
3109
+ if (notebook.isSelectedOrActive(cell)) {
3110
+ cellsToInclude.add(cell);
3111
+
3112
+ // If this is a collapsed markdown cell, add all its children
3113
+ if (
3114
+ cell instanceof MarkdownCell &&
3115
+ cell.headingCollapsed &&
3116
+ cell.numberChildNodes > 0
3117
+ ) {
3118
+ for (let j = i + 1; j <= i + cell.numberChildNodes; j++) {
3119
+ if (notebook.widgets[j]) {
3120
+ cellsToInclude.add(notebook.widgets[j]);
3121
+ }
3122
+ }
3123
+ }
3124
+ }
3125
+ }
3126
+
3127
+ return Array.from(cellsToInclude)
2914
3128
  .map(cell => cell.model.toJSON())
2915
3129
  .map(cellJSON => {
2916
3130
  if ((cellJSON.metadata as JSONObject).deletable !== undefined) {
@@ -3117,19 +3331,40 @@ namespace Private {
3117
3331
  const model = notebook.model!;
3118
3332
  const sharedModel = model.sharedModel;
3119
3333
  const toDelete: number[] = [];
3334
+ const cellsToDeleteSet = new Set<number>();
3120
3335
 
3121
3336
  notebook.mode = 'command';
3122
3337
 
3123
- // Find the cells to delete.
3338
+ // Find the cells to delete, expanding collapsed sections.
3124
3339
  notebook.widgets.forEach((child, index) => {
3125
3340
  const deletable = child.model.getMetadata('deletable') !== false;
3126
3341
 
3127
3342
  if (notebook.isSelectedOrActive(child) && deletable) {
3128
- toDelete.push(index);
3343
+ cellsToDeleteSet.add(index);
3129
3344
  notebook.model?.deletedCells.push(child.model.id);
3345
+
3346
+ // If this is a collapsed markdown cell, mark all its children for deletion
3347
+ if (
3348
+ child instanceof MarkdownCell &&
3349
+ child.headingCollapsed &&
3350
+ child.numberChildNodes > 0
3351
+ ) {
3352
+ for (let j = index + 1; j <= index + child.numberChildNodes; j++) {
3353
+ if (notebook.widgets[j]) {
3354
+ const childDeletable =
3355
+ notebook.widgets[j].model.getMetadata('deletable') !== false;
3356
+ if (childDeletable) {
3357
+ cellsToDeleteSet.add(j);
3358
+ notebook.model?.deletedCells.push(notebook.widgets[j].model.id);
3359
+ }
3360
+ }
3361
+ }
3362
+ }
3130
3363
  }
3131
3364
  });
3132
3365
 
3366
+ toDelete.push(...Array.from(cellsToDeleteSet).sort((a, b) => a - b));
3367
+
3133
3368
  // If cells are not deletable, we may not have anything to delete.
3134
3369
  if (toDelete.length > 0) {
3135
3370
  // Detach futures before the transaction so dispose() does not cancel them.
package/src/panel.ts CHANGED
@@ -1,7 +1,5 @@
1
1
  // Copyright (c) Jupyter Development Team.
2
2
  // Distributed under the terms of the Modified BSD License.
3
- /* eslint-disable @typescript-eslint/no-explicit-any */
4
-
5
3
  import type { ISessionContext } from '@jupyterlab/apputils';
6
4
  import { Dialog, Printing, showDialog } from '@jupyterlab/apputils';
7
5
  import { isMarkdownCellModel } from '@jupyterlab/cells';
@@ -191,7 +189,7 @@ export class NotebookPanel extends DocumentWidget<Notebook, INotebookModel> {
191
189
  * Handle a change in the kernel by updating the document metadata.
192
190
  */
193
191
  private _onKernelChanged(
194
- sender: any,
192
+ sender: ISessionContext,
195
193
  args: Session.ISessionConnection.IKernelChangedArgs
196
194
  ): void {
197
195
  if (!this.model || !args.newValue) {
@@ -1,7 +1,5 @@
1
1
  // Copyright (c) Jupyter Development Team.
2
2
  // Distributed under the terms of the Modified BSD License.
3
- /* eslint-disable @typescript-eslint/no-explicit-any */
4
-
5
3
  import { Dialog, showDialog } from '@jupyterlab/apputils';
6
4
  import type {
7
5
  CellSearchProvider,
@@ -66,7 +64,7 @@ export class NotebookSearchProvider extends SearchProvider<NotebookPanel> {
66
64
  this._filtersChanged.connect(this._setEnginesSelectionSearchMode, this);
67
65
  }
68
66
 
69
- private _onNotebookStateChanged(_: Notebook, args: IChangedArgs<any>) {
67
+ private _onNotebookStateChanged(_: Notebook, args: IChangedArgs<unknown>) {
70
68
  if (args.name === 'mode') {
71
69
  // Delay the update to ensure that `document.activeElement` settled.
72
70
  window.setTimeout(() => {