@jupyterlab/notebook-extension 4.6.2 → 4.7.0-alpha.1

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/lib/index.d.ts CHANGED
@@ -3,6 +3,20 @@
3
3
  * @module notebook-extension
4
4
  */
5
5
  import type { JupyterFrontEndPlugin } from '@jupyterlab/application';
6
+ import { Token } from '@lumino/coreutils';
7
+ /**
8
+ * An interface describing how export guidance is presented to users.
9
+ */
10
+ export interface INotebookExportGuidance {
11
+ /**
12
+ * Show guidance for enabling notebook exports.
13
+ */
14
+ showExportHelp(): Promise<void>;
15
+ }
16
+ /**
17
+ * A token describing a service for showing notebook export guidance.
18
+ */
19
+ export declare const INotebookExportGuidance: Token<INotebookExportGuidance>;
6
20
  /**
7
21
  * A plugin providing a CommandEdit status item.
8
22
  */
@@ -19,6 +33,10 @@ export declare const executionIndicator: JupyterFrontEndPlugin<void>;
19
33
  * A plugin providing export commands in the main menu and command palette
20
34
  */
21
35
  export declare const exportPlugin: JupyterFrontEndPlugin<void>;
36
+ /**
37
+ * A plugin providing the default notebook export guidance service.
38
+ */
39
+ export declare const exportGuidanceDialogPlugin: JupyterFrontEndPlugin<INotebookExportGuidance>;
22
40
  /**
23
41
  * A plugin that adds a notebook trust status item to the status bar.
24
42
  */
package/lib/index.js CHANGED
@@ -21,16 +21,17 @@ import { ILSPCodeExtractorsManager, ILSPDocumentConnectionManager, ILSPFeatureMa
21
21
  import { IMainMenu } from '@jupyterlab/mainmenu';
22
22
  import { IMetadataFormProvider } from '@jupyterlab/metadataform';
23
23
  import { CellCounterStatus, CommandEditStatus, ExecutionIndicator, INotebookCellExecutor, INotebookTools, INotebookTracker, INotebookWidgetFactory, NotebookActions, NotebookAdapter, NotebookModelFactory, NotebookPanel, NotebookSearchProvider, NotebookToCFactory, NotebookTools, NotebookTracker, NotebookTrustStatus, NotebookWidgetFactory, setCellExecutor, StaticNotebook, ToolbarItems } from '@jupyterlab/notebook';
24
+ import { IPageHandler } from '@jupyterlab/outputarea';
24
25
  import { IPropertyInspectorProvider } from '@jupyterlab/property-inspector';
25
- import { IMarkdownParser, IRenderMimeRegistry } from '@jupyterlab/rendermime';
26
+ import { IMarkdownParser, IRenderMimeRegistry, MimeModel } from '@jupyterlab/rendermime';
26
27
  import { ISettingRegistry } from '@jupyterlab/settingregistry';
27
28
  import { IStateDB } from '@jupyterlab/statedb';
28
29
  import { IStatusBar } from '@jupyterlab/statusbar';
29
30
  import { ITableOfContentsRegistry } from '@jupyterlab/toc';
30
31
  import { ITranslator, nullTranslator } from '@jupyterlab/translation';
31
- import { addAboveIcon, addBelowIcon, buildIcon, copyIcon, cutIcon, duplicateIcon, fastForwardIcon, IFormRendererRegistry, moveDownIcon, moveUpIcon, notebookIcon, pasteIcon, refreshIcon, runIcon, stopIcon } from '@jupyterlab/ui-components';
32
+ import { addAboveIcon, addBelowIcon, buildIcon, copyIcon, cutIcon, duplicateIcon, fastForwardIcon, IFormRendererRegistry, infoIcon, moveDownIcon, moveUpIcon, notebookIcon, pasteIcon, refreshIcon, runIcon, stopIcon } from '@jupyterlab/ui-components';
32
33
  import { ArrayExt } from '@lumino/algorithm';
33
- import { JSONExt, UUID } from '@lumino/coreutils';
34
+ import { JSONExt, Token, UUID } from '@lumino/coreutils';
34
35
  import { DisposableSet } from '@lumino/disposable';
35
36
  import { MessageLoop } from '@lumino/messaging';
36
37
  import { Panel } from '@lumino/widgets';
@@ -61,6 +62,7 @@ var CommandIDs;
61
62
  CommandIDs.closeAndShutdown = 'notebook:close-and-shutdown';
62
63
  CommandIDs.trust = 'notebook:trust';
63
64
  CommandIDs.exportToFormat = 'notebook:export-to-format';
65
+ CommandIDs.showExportGuidance = 'notebook:show-export-guidance';
64
66
  CommandIDs.run = 'notebook:run-cell';
65
67
  CommandIDs.runAndAdvance = 'notebook:run-cell-and-select-next';
66
68
  CommandIDs.runAndInsert = 'notebook:run-cell-and-insert-below';
@@ -155,6 +157,14 @@ const FACTORY = 'Notebook';
155
157
  * (returned from nbconvert's export list)
156
158
  */
157
159
  const FORMAT_EXCLUDE = ['notebook', 'python', 'custom'];
160
+ /**
161
+ * Documentation page describing notebook export support.
162
+ */
163
+ const NOTEBOOK_EXPORT_DOCS_URL = 'https://jupyterlab.readthedocs.io/en/stable/user/export.html';
164
+ /**
165
+ * A token describing a service for showing notebook export guidance.
166
+ */
167
+ export const INotebookExportGuidance = new Token('@jupyterlab/notebook-extension:INotebookExportGuidance', 'A service for showing notebook export guidance.');
158
168
  /**
159
169
  * Setting Id storing the customized toolbar definition.
160
170
  */
@@ -377,9 +387,8 @@ export const exportPlugin = {
377
387
  description: 'Adds the export notebook commands.',
378
388
  autoStart: true,
379
389
  requires: [ITranslator, INotebookTracker],
380
- optional: [IMainMenu, ICommandPalette],
381
- activate: (app, translator, tracker, mainMenu, palette) => {
382
- var _a;
390
+ optional: [IMainMenu, ICommandPalette, INotebookExportGuidance],
391
+ activate: (app, translator, tracker, mainMenu, palette, exportGuidance) => {
383
392
  const trans = translator.load('jupyterlab');
384
393
  const { commands, shell } = app;
385
394
  const services = app.serviceManager;
@@ -454,63 +463,153 @@ export const exportPlugin = {
454
463
  }
455
464
  }
456
465
  });
466
+ commands.addCommand(CommandIDs.showExportGuidance, {
467
+ label: trans.__('Enable notebook exports'),
468
+ execute: () => {
469
+ if (exportGuidance) {
470
+ return exportGuidance.showExportHelp();
471
+ }
472
+ window.open(NOTEBOOK_EXPORT_DOCS_URL, '_blank', 'noopener,noreferrer');
473
+ return undefined;
474
+ },
475
+ describedBy: {
476
+ args: {
477
+ type: 'object',
478
+ properties: {}
479
+ }
480
+ }
481
+ });
457
482
  // Add a notebook group to the File menu.
458
- let exportTo;
459
- if (mainMenu) {
460
- exportTo = (_a = mainMenu.fileMenu.items.find(item => {
483
+ const fileMenu = mainMenu === null || mainMenu === void 0 ? void 0 : mainMenu.fileMenu;
484
+ const getExportMenu = () => {
485
+ var _a, _b;
486
+ return ((_b = (_a = fileMenu === null || fileMenu === void 0 ? void 0 : fileMenu.items.find(item => {
461
487
  var _a;
462
488
  return item.type === 'submenu' &&
463
489
  ((_a = item.submenu) === null || _a === void 0 ? void 0 : _a.id) === 'jp-mainmenu-file-notebookexport';
464
- })) === null || _a === void 0 ? void 0 : _a.submenu;
465
- }
490
+ })) === null || _a === void 0 ? void 0 : _a.submenu) !== null && _b !== void 0 ? _b : undefined);
491
+ };
466
492
  let formatsInitialized = false;
493
+ let paletteInitialized = false;
494
+ let exportFormats = null;
495
+ const updateExportMenu = () => {
496
+ const exportTo = getExportMenu();
497
+ if (!exportTo || !exportFormats) {
498
+ return;
499
+ }
500
+ exportTo.clearItems();
501
+ if (exportFormats.length === 0) {
502
+ exportTo.addItem({
503
+ command: CommandIDs.showExportGuidance
504
+ });
505
+ return;
506
+ }
507
+ exportFormats.forEach(({ format, label }) => {
508
+ exportTo.addItem({
509
+ command: CommandIDs.exportToFormat,
510
+ args: {
511
+ format,
512
+ label,
513
+ isPalette: false
514
+ }
515
+ });
516
+ });
517
+ if (palette && !paletteInitialized) {
518
+ const category = trans.__('Notebook Operations');
519
+ exportFormats.forEach(({ format, label }) => {
520
+ palette.addItem({
521
+ command: CommandIDs.exportToFormat,
522
+ category,
523
+ args: {
524
+ format,
525
+ label,
526
+ isPalette: true
527
+ }
528
+ });
529
+ });
530
+ paletteInitialized = true;
531
+ }
532
+ };
467
533
  /** Request formats only when a notebook might use them. */
468
534
  const maybeInitializeFormats = async () => {
469
535
  if (formatsInitialized) {
536
+ updateExportMenu();
537
+ return;
538
+ }
539
+ if (tracker.size === 0) {
470
540
  return;
471
541
  }
472
542
  tracker.widgetAdded.disconnect(maybeInitializeFormats);
473
543
  formatsInitialized = true;
474
- const response = await services.nbconvert.getExportFormats(false);
475
- if (!response) {
476
- return;
544
+ let response = null;
545
+ try {
546
+ response = await services.nbconvert.getExportFormats(false);
547
+ }
548
+ catch (_a) {
549
+ // Ignore fetch errors and fallback to export guidance.
477
550
  }
478
551
  const formatLabels = Private.getFormatLabels(translator);
479
- // Convert export list to palette and menu items.
480
- const formatList = Object.keys(response);
481
- formatList.forEach(function (key) {
552
+ // Convert export list to menu and palette items.
553
+ exportFormats = Object.keys(response !== null && response !== void 0 ? response : {})
554
+ .filter(key => !FORMAT_EXCLUDE.includes(key))
555
+ .map(key => {
482
556
  const formattedKey = key[0].toLocaleUpperCase() + key.slice(1);
483
557
  const capCaseKey = trans.__(formattedKey);
484
558
  const labelStr = formatLabels[key] ? formatLabels[key] : capCaseKey;
485
- let args = {
559
+ return {
486
560
  format: key,
487
- label: labelStr,
488
- isPalette: false
561
+ label: labelStr
489
562
  };
490
- if (FORMAT_EXCLUDE.indexOf(key) === -1) {
491
- if (exportTo) {
492
- exportTo.addItem({
493
- command: CommandIDs.exportToFormat,
494
- args: args
495
- });
496
- }
497
- if (palette) {
498
- args = {
499
- format: key,
500
- label: labelStr,
501
- isPalette: true
502
- };
503
- const category = trans.__('Notebook Operations');
504
- palette.addItem({
505
- command: CommandIDs.exportToFormat,
506
- category,
507
- args
508
- });
509
- }
510
- }
511
563
  });
564
+ updateExportMenu();
512
565
  };
513
566
  tracker.widgetAdded.connect(maybeInitializeFormats);
567
+ if (tracker.size > 0) {
568
+ void maybeInitializeFormats();
569
+ }
570
+ void app.restored.then(() => {
571
+ void maybeInitializeFormats();
572
+ });
573
+ }
574
+ };
575
+ /**
576
+ * A plugin providing the default notebook export guidance service.
577
+ */
578
+ export const exportGuidanceDialogPlugin = {
579
+ id: '@jupyterlab/notebook-extension:export-guidance-dialog',
580
+ description: 'Provides the default notebook export guidance shown when no exporters are available.',
581
+ provides: INotebookExportGuidance,
582
+ autoStart: true,
583
+ requires: [ITranslator],
584
+ activate: (app, translator) => {
585
+ const trans = translator.load('jupyterlab');
586
+ const { commands } = app;
587
+ const openExportDocs = (url, docsLabel) => {
588
+ if (commands.hasCommand('help:open')) {
589
+ return commands.execute('help:open', {
590
+ url,
591
+ text: docsLabel,
592
+ newBrowserTab: true
593
+ });
594
+ }
595
+ window.open(url, '_blank', 'noopener,noreferrer');
596
+ return undefined;
597
+ };
598
+ return {
599
+ showExportHelp: async () => {
600
+ const result = await showDialog({
601
+ title: trans.__('Notebook exports are unavailable'),
602
+ body: trans.__('No notebook export formats are currently available. To enable exports, install nbconvert in the server environment or use another exporter supported by your deployment.'),
603
+ buttons: [
604
+ Dialog.cancelButton({ label: trans.__('Close') }),
605
+ Dialog.okButton({ label: trans.__('Open Documentation') })
606
+ ]
607
+ });
608
+ if (result.button.accept) {
609
+ void openExportDocs(NOTEBOOK_EXPORT_DOCS_URL, trans.__('Notebook Export Documentation'));
610
+ }
611
+ }
612
+ };
514
613
  }
515
614
  };
516
615
  /**
@@ -557,10 +656,27 @@ const widgetFactoryPlugin = {
557
656
  IRenderMimeRegistry,
558
657
  IToolbarWidgetRegistry
559
658
  ],
560
- optional: [ISettingRegistry, ISessionContextDialogs, ITranslator],
659
+ optional: [
660
+ ISettingRegistry,
661
+ ISessionContextDialogs,
662
+ ITranslator,
663
+ IPageHandler
664
+ ],
561
665
  activate: activateWidgetFactory,
562
666
  autoStart: true
563
667
  };
668
+ /**
669
+ * The pager output handler provider.
670
+ */
671
+ const pageHandlerPlugin = {
672
+ id: '@jupyterlab/notebook-extension:page-handler',
673
+ description: 'Provides a handler for pager output payloads.',
674
+ autoStart: true,
675
+ provides: IPageHandler,
676
+ requires: [IRenderMimeRegistry],
677
+ optional: [ISettingRegistry, ITranslator],
678
+ activate: activatePageHandler
679
+ };
564
680
  /**
565
681
  * The cloned output provider.
566
682
  */
@@ -882,7 +998,9 @@ const plugins = [
882
998
  cellExecutor,
883
999
  factory,
884
1000
  trackerPlugin,
1001
+ pageHandlerPlugin,
885
1002
  executionIndicator,
1003
+ exportGuidanceDialogPlugin,
886
1004
  exportPlugin,
887
1005
  tools,
888
1006
  cellCounterItem,
@@ -943,10 +1061,72 @@ function activateNotebookTools(app, tracker, editorServices, languages, state, t
943
1061
  }
944
1062
  return notebookTools;
945
1063
  }
1064
+ /**
1065
+ * Activate the pager output handler provider.
1066
+ */
1067
+ function activatePageHandler(app, rendermime, settingRegistry, translator_) {
1068
+ const translator = translator_ !== null && translator_ !== void 0 ? translator_ : nullTranslator;
1069
+ const trans = translator.load('jupyterlab');
1070
+ let helpInBottomPanel = false;
1071
+ let helpWidget = null;
1072
+ const fetchSettings = settingRegistry
1073
+ ? settingRegistry.load(trackerPlugin.id)
1074
+ : Promise.reject(new Error(`No setting registry for ${trackerPlugin.id}`));
1075
+ const updateConfig = (settings) => {
1076
+ helpInBottomPanel = settings.get('helpInBottomPanel').composite;
1077
+ };
1078
+ void fetchSettings
1079
+ .then(settings => {
1080
+ updateConfig(settings);
1081
+ settings.changed.connect(() => {
1082
+ updateConfig(settings);
1083
+ });
1084
+ })
1085
+ .catch((reason) => {
1086
+ console.warn(reason.message);
1087
+ });
1088
+ return {
1089
+ handlePage: payload => {
1090
+ var _a;
1091
+ if (!helpInBottomPanel) {
1092
+ return false;
1093
+ }
1094
+ const data = payload['data'];
1095
+ if (!data || typeof data !== 'object') {
1096
+ return false;
1097
+ }
1098
+ const mimeData = data;
1099
+ const metadata = ((_a = payload['metadata']) !== null && _a !== void 0 ? _a : {});
1100
+ const mimeType = rendermime.preferredMimeType(mimeData, 'any');
1101
+ if (!mimeType) {
1102
+ return false;
1103
+ }
1104
+ if (!helpWidget || helpWidget.isDisposed) {
1105
+ const content = new Panel();
1106
+ content.addClass('jp-HelpPanel');
1107
+ helpWidget = new MainAreaWidget({ content });
1108
+ helpWidget.id = 'jp-help-panel';
1109
+ helpWidget.title.label = trans.__('Help');
1110
+ helpWidget.title.icon = infoIcon;
1111
+ helpWidget.title.closable = true;
1112
+ }
1113
+ const content = helpWidget.content;
1114
+ content.widgets.forEach(widget => widget.dispose());
1115
+ const renderer = rendermime.createRenderer(mimeType);
1116
+ void renderer.renderModel(new MimeModel({ data: mimeData, metadata, trusted: true }));
1117
+ content.addWidget(renderer);
1118
+ if (!helpWidget.isAttached) {
1119
+ app.shell.add(helpWidget, 'down');
1120
+ }
1121
+ app.shell.activateById(helpWidget.id);
1122
+ return true;
1123
+ }
1124
+ };
1125
+ }
946
1126
  /**
947
1127
  * Activate the notebook widget factory.
948
1128
  */
949
- function activateWidgetFactory(app, contentFactory, editorServices, rendermime, toolbarRegistry, settingRegistry, sessionContextDialogs_, translator_) {
1129
+ function activateWidgetFactory(app, contentFactory, editorServices, rendermime, toolbarRegistry, settingRegistry, sessionContextDialogs_, translator_, pageHandler) {
950
1130
  const translator = translator_ !== null && translator_ !== void 0 ? translator_ : nullTranslator;
951
1131
  const sessionContextDialogs = sessionContextDialogs_ !== null && sessionContextDialogs_ !== void 0 ? sessionContextDialogs_ : new SessionContextDialogs({ translator });
952
1132
  const preferKernelOption = PageConfig.getOption('notebookStartsKernel');
@@ -985,6 +1165,7 @@ function activateWidgetFactory(app, contentFactory, editorServices, rendermime,
985
1165
  contentFactory,
986
1166
  editorConfig: StaticNotebook.defaultEditorConfig,
987
1167
  notebookConfig: StaticNotebook.defaultNotebookConfig,
1168
+ pageHandler: pageHandler !== null && pageHandler !== void 0 ? pageHandler : undefined,
988
1169
  mimeTypeService: editorServices.mimeTypeService,
989
1170
  toolbarFactory,
990
1171
  translator