@@ -2,6 +2,8 @@ import { NotebookPanel } from '@jupyterlab/notebook';
22
33import { CodeCell , MarkdownCell , Cell } from '@jupyterlab/cells' ;
44
5+ import { map , toArray , each } from '@lumino/algorithm' ;
6+
57import * as React from 'react' ;
68
79import {
@@ -10,6 +12,7 @@ import {
1012 IWidgetTracker ,
1113 Toolbar ,
1214 ReactWidget ,
15+ // MainAreaWidget,
1316} from '@jupyterlab/apputils' ;
1417
1518import { CommandRegistry } from '@lumino/commands' ;
@@ -26,9 +29,15 @@ import { DashboardLayout } from './layout';
2629
2730import { DashboardWidget } from './widget' ;
2831
29- import { Widgetstore } from './widgetstore' ;
32+ import { WidgetPosition , Widgetstore } from './widgetstore' ;
3033
31- import { addCellId , addNotebookId } from './utils' ;
34+ import {
35+ addCellId ,
36+ addNotebookId ,
37+ getNotebookById ,
38+ getCellId ,
39+ updateMetadata ,
40+ } from './utils' ;
3241
3342import {
3443 DocumentWidget ,
@@ -43,17 +52,19 @@ import { CommandIDs } from './commands';
4352
4453import { HTMLSelect } from '@jupyterlab/ui-components' ;
4554
55+ import { UUID } from '@lumino/coreutils' ;
56+
4657// HTML element classes
4758
48- const DASHBOARD_CLASS = 'pr-JupyterDashboard' ;
59+ export const DASHBOARD_CLASS = 'pr-JupyterDashboard' ;
4960
50- const DROP_TARGET_CLASS = 'pr-DropTarget' ;
61+ export const DROP_TARGET_CLASS = 'pr-DropTarget' ;
5162
52- const TOOLBAR_MODE_SWITCHER_CLASS = 'pr-ToolbarModeSwitcher' ;
63+ export const TOOLBAR_MODE_SWITCHER_CLASS = 'pr-ToolbarModeSwitcher' ;
5364
54- const TOOLBAR_SELECT_CLASS = 'pr-ToolbarSelector' ;
65+ export const TOOLBAR_SELECT_CLASS = 'pr-ToolbarSelector' ;
5566
56- const TOOLBAR_CLASS = 'pr-DashboardToolbar' ;
67+ export const TOOLBAR_CLASS = 'pr-DashboardToolbar' ;
5768
5869export const IDashboardTracker = new Token < IDashboardTracker > (
5970 'jupyterlab-interactive-dashboard-editor'
@@ -70,9 +81,13 @@ export class Dashboard extends Widget {
7081 constructor ( options : Dashboard . IOptions ) {
7182 super ( options ) ;
7283
73- const { outputTracker, model, context } = options ;
84+ this . id = UUID . uuid4 ( ) ;
85+
86+ const { outputTracker, model } = options ;
7487 this . _model = model ;
75- this . _context = context ;
88+ if ( options . context !== undefined ) {
89+ this . _context = options . context ;
90+ }
7691 const { widgetstore, mode } = model ;
7792
7893 this . layout = new DashboardLayout ( {
@@ -141,7 +156,7 @@ export class Dashboard extends Widget {
141156 event . dropAction = 'copy' ;
142157 const source = event . source as DashboardWidget ;
143158 const pos = source ?. pos ;
144- if ( pos ) {
159+ if ( pos && source . mode === 'grid-edit' ) {
145160 pos . left = event . offsetX + this . node . scrollLeft ;
146161 pos . top = event . offsetY + this . node . scrollTop ;
147162 ( this . layout as DashboardLayout ) . drawDropZone ( pos , '#2b98f0' ) ;
@@ -349,6 +364,43 @@ export class Dashboard extends Widget {
349364 return ( this . layout as DashboardLayout ) . createWidget ( info , fit ) ;
350365 }
351366
367+ saveToNotebookMetadata ( ) : void {
368+ // Get a list of all notebookIds used in the dashboard.
369+ const widgets = toArray ( this . model . widgetstore . getWidgets ( ) ) ;
370+
371+ const notebookIds = toArray ( map ( widgets , ( record ) => record . notebookId ) ) ;
372+
373+ if ( ! notebookIds . every ( ( v ) => v === notebookIds [ 0 ] ) ) {
374+ throw new Error (
375+ 'Only single notebook dashboards can be saved to metadata.'
376+ ) ;
377+ }
378+
379+ const notebookId = notebookIds [ 0 ] ;
380+ const notebookTracker = this . model . notebookTracker ;
381+ const notebook = getNotebookById ( notebookId , notebookTracker ) ;
382+
383+ updateMetadata ( notebook , { hasDashboard : true } ) ;
384+
385+ const cells = notebook . content . widgets ;
386+
387+ const widgetMap = new Map < string , WidgetPosition > (
388+ widgets . map ( ( widget ) => [ widget . cellId , widget . pos ] )
389+ ) ;
390+
391+ each ( cells , ( cell ) => {
392+ const cellId = getCellId ( cell ) ;
393+ const pos = widgetMap . get ( cellId ) ;
394+ if ( pos != null ) {
395+ updateMetadata ( cell , { pos, hidden : false } ) ;
396+ } else {
397+ updateMetadata ( cell , { hidden : true } ) ;
398+ }
399+ } ) ;
400+
401+ notebook . context . save ( ) ;
402+ }
403+
352404 get model ( ) : IDashboardModel {
353405 return this . _model ;
354406 }
@@ -367,7 +419,7 @@ export class Dashboard extends Widget {
367419 * Namespace for DashboardArea options.
368420 */
369421export namespace Dashboard {
370- export type Mode = 'edit' | 'present' | 'grid' ;
422+ export type Mode = 'free- edit' | 'present' | 'grid-edit ' ;
371423
372424 export type ScrollMode = 'infinite' | 'constrained' ;
373425
@@ -394,7 +446,7 @@ export namespace Dashboard {
394446
395447 model : IDashboardModel ;
396448
397- context : DocumentRegistry . IContext < DocumentRegistry . IModel > ;
449+ context ? : DocumentRegistry . IContext < DocumentRegistry . IModel > ;
398450 }
399451}
400452
@@ -403,6 +455,7 @@ export class DashboardDocument extends DocumentWidget<Dashboard> {
403455 let { content, reveal } = options ;
404456 const { context, commandRegistry } = options ;
405457 const model = context . model as DashboardModel ;
458+ model . path = context . path ;
406459 content = content || new Dashboard ( { ...options , model, context } ) ;
407460 reveal = Promise . all ( [ reveal , context . ready ] ) ;
408461 super ( {
@@ -416,7 +469,7 @@ export class DashboardDocument extends DocumentWidget<Dashboard> {
416469 this . toolbar . addClass ( TOOLBAR_CLASS ) ;
417470
418471 const commands = commandRegistry ;
419- const { save, undo, redo, cut, copy, paste, runOutput } = CommandIDs ;
472+ const { save, undo, redo, cut, copy, paste } = CommandIDs ;
420473
421474 const args = { toolbar : true , dashboardId : content . id } ;
422475
@@ -438,15 +491,13 @@ export class DashboardDocument extends DocumentWidget<Dashboard> {
438491 paste ,
439492 'Paste outputs from the clipboard'
440493 ) ;
441- const runButton = makeToolbarButton ( runOutput , 'Run the selected outputs' ) ;
442494
443495 this . toolbar . addItem ( save , saveButton ) ;
444496 this . toolbar . addItem ( undo , undoButton ) ;
445497 this . toolbar . addItem ( redo , redoButton ) ;
446498 this . toolbar . addItem ( cut , cutButton ) ;
447499 this . toolbar . addItem ( copy , copyButton ) ;
448500 this . toolbar . addItem ( paste , pasteButton ) ;
449- this . toolbar . addItem ( runOutput , runButton ) ;
450501 this . toolbar . addItem ( 'spacer' , Toolbar . createSpacerItem ( ) ) ;
451502 this . toolbar . addItem (
452503 'switchMode' ,
@@ -473,7 +524,7 @@ export namespace DashboardDocument {
473524 name ?: string ;
474525
475526 /**
476- * Dashboard canvas width (default is 1280) .
527+ * Optional widgetstore to restore from .
477528 */
478529 store ?: Widgetstore ;
479530
@@ -523,8 +574,8 @@ export namespace DashboardDocument {
523574 aria-label = { 'Mode' }
524575 >
525576 < option value = "present" > Present</ option >
526- < option value = "edit" > Free Layout</ option >
527- < option value = "grid" > Tile Layout </ option >
577+ { /* <option value="free- edit">Free Layout</option> */ }
578+ < option value = "grid-edit" > Edit </ option >
528579 </ HTMLSelect >
529580 ) ;
530581 }
0 commit comments