@@ -2,26 +2,13 @@ import {
22 JupyterFrontEnd ,
33 JupyterFrontEndPlugin
44} from '@jupyterlab/application' ;
5- import { NotebookActions } from '@jupyterlab/notebook' ;
6- import { IObservableJSON } from '@jupyterlab/observables ' ;
5+ import { KernelError , Notebook , NotebookActions } from '@jupyterlab/notebook' ;
6+ import { Cell } from '@jupyterlab/cells ' ;
77import { ISettingRegistry } from '@jupyterlab/settingregistry' ;
88import { ICodeCellModel } from '@jupyterlab/cells' ;
99
1010import { checkBrowserNotificationSettings } from './settings' ;
1111
12- /**
13- * Extracts Code Cell Start and End Time
14- */
15- function extractExecutionMetadata ( metadata : IObservableJSON ) : [ Date , Date ] {
16- const executionMetadata = Object . assign ( { } , metadata . get ( 'execution' ) as any ) ;
17- const cellStartTime = new Date (
18- executionMetadata [ 'shell.execute_reply.started' ] ||
19- executionMetadata [ 'iopub.execute_input' ]
20- ) ;
21- const cellEndTime = new Date ( executionMetadata [ 'shell.execute_reply' ] ) ;
22- return [ cellStartTime , cellEndTime ] ;
23- }
24-
2512/**
2613 * Constructs notification message and displays it.
2714 */
@@ -30,14 +17,22 @@ function displayNotification(
3017 cellNumber : number ,
3118 notebookName : string ,
3219 reportCellNumber : boolean ,
33- reportCellExecutionTime : boolean
20+ reportCellExecutionTime : boolean ,
21+ failedExecution : boolean ,
22+ error : KernelError | null
3423) : void {
3524 const notificationPayload = {
3625 icon : '/static/favicon.ico' ,
3726 body : ''
3827 } ;
28+ const title = failedExecution
29+ ? `${ notebookName } Failed!`
30+ : `${ notebookName } Completed!` ;
3931 let message = '' ;
40- if ( reportCellNumber && reportCellExecutionTime ) {
32+
33+ if ( failedExecution ) {
34+ message = error ? `${ error . errorName } ${ error . errorValue } ` : '' ;
35+ } else if ( reportCellNumber && reportCellExecutionTime ) {
4136 message = `Cell[${ cellNumber } ] Duration: ${ cellDuration } ` ;
4237 } else if ( reportCellNumber ) {
4338 message = `Cell Number: ${ cellNumber } ` ;
@@ -46,20 +41,62 @@ function displayNotification(
4641 }
4742
4843 notificationPayload . body = message ;
49- new Notification ( `${ notebookName } ` , notificationPayload ) ;
44+ new Notification ( title , notificationPayload ) ;
45+ }
46+
47+ /**
48+ * Trigger notification.
49+ */
50+ function triggerNotification (
51+ cell : Cell ,
52+ notebook : Notebook ,
53+ cellStartTime : Date ,
54+ cellEndTime : Date ,
55+ minimumCellExecutionTime : number ,
56+ reportCellNumber : boolean ,
57+ reportCellExecutionTime : boolean ,
58+ cellNumberType : string ,
59+ failedExecution : boolean ,
60+ error : KernelError | null
61+ ) {
62+ const codeCell = cell . model . type === 'code' ;
63+ const nonEmptyCell = cell . model . value . text . length > 0 ;
64+ if ( codeCell && nonEmptyCell ) {
65+ const codeCellModel = cell . model as ICodeCellModel ;
66+ const diff = new Date ( < any > cellEndTime - < any > cellStartTime ) ;
67+ const diffSeconds = Math . floor ( diff . getTime ( ) / 1000 ) ;
68+ if ( diffSeconds >= minimumCellExecutionTime ) {
69+ const cellDuration = diff . toISOString ( ) . substr ( 11 , 8 ) ;
70+ const cellNumber =
71+ cellNumberType === 'cell_index'
72+ ? notebook . activeCellIndex
73+ : codeCellModel . executionCount ;
74+ const notebookName = notebook . title . label . replace ( / \. [ ^ / . ] + $ / , '' ) ;
75+ displayNotification (
76+ cellDuration ,
77+ cellNumber ,
78+ notebookName ,
79+ reportCellNumber ,
80+ reportCellExecutionTime ,
81+ failedExecution ,
82+ error
83+ ) ;
84+ }
85+ }
5086}
5187
5288const extension : JupyterFrontEndPlugin < void > = {
5389 id : 'jupyterlab-notifications:plugin' ,
5490 autoStart : true ,
55- optional : [ ISettingRegistry ] ,
91+ requires : [ ISettingRegistry ] ,
5692 activate : async ( app : JupyterFrontEnd , settingRegistry : ISettingRegistry ) => {
5793 checkBrowserNotificationSettings ( ) ;
5894 let enabled = true ;
5995 let minimumCellExecutionTime = 60 ;
6096 let reportCellExecutionTime = true ;
6197 let reportCellNumber = true ;
6298 let cellNumberType = 'cell_index' ;
99+
63100 if ( settingRegistry ) {
64101 const setting = await settingRegistry . load ( extension . id ) ;
65102 const updateSettings = ( ) : void => {
@@ -76,45 +113,30 @@ const extension: JupyterFrontEndPlugin<void> = {
76113 setting . changed . connect ( updateSettings ) ;
77114 }
78115
116+ let cellStartTime = new Date ( ) ;
117+
118+ NotebookActions . executionScheduled . connect ( ( _ , args ) => {
119+ if ( enabled ) {
120+ cellStartTime = new Date ( ) ;
121+ }
122+ } ) ;
123+
79124 NotebookActions . executed . connect ( ( _ , args ) => {
80125 if ( enabled ) {
81- const { cell, notebook } = args ;
82- const codeCell = cell . model . type === 'code' ;
83- const nonEmptyCell = cell . model . value . text . length > 0 ;
84- const metadata = cell . model . metadata ;
85- if ( codeCell && nonEmptyCell ) {
86- const codeCellModel = cell . model as ICodeCellModel ;
87- if ( metadata . has ( 'execution' ) ) {
88- const [ cellStartTime , cellEndTime ] = extractExecutionMetadata (
89- metadata
90- ) ;
91- const diff = new Date ( < any > cellEndTime - < any > cellStartTime ) ;
92- const diffSeconds = Math . floor ( diff . getTime ( ) / 1000 ) ;
93- if ( diffSeconds >= minimumCellExecutionTime ) {
94- const cellDuration = diff . toISOString ( ) . substr ( 11 , 8 ) ;
95- const cellNumber =
96- cellNumberType === 'cell_index'
97- ? notebook . activeCellIndex
98- : codeCellModel . executionCount ;
99- const notebookName = notebook . title . label . replace (
100- / \. [ ^ / . ] + $ / ,
101- ''
102- ) ;
103- displayNotification (
104- cellDuration ,
105- cellNumber ,
106- notebookName ,
107- reportCellNumber ,
108- reportCellExecutionTime
109- ) ;
110- }
111- } else {
112- alert (
113- 'Notebook Cell Timing needs to be enabled for Jupyterlab Notifications to work. ' +
114- 'Please go to Settings -> Advanced Settings Editor -> Notebook and update setting to {"recordTiming": true}'
115- ) ;
116- }
117- }
126+ const { cell, notebook, success, error } = args ;
127+ const cellEndTime = new Date ( ) ;
128+ triggerNotification (
129+ cell ,
130+ notebook ,
131+ cellStartTime ,
132+ cellEndTime ,
133+ minimumCellExecutionTime ,
134+ reportCellNumber ,
135+ reportCellExecutionTime ,
136+ cellNumberType ,
137+ ! success ,
138+ error
139+ ) ;
118140 }
119141 } ) ;
120142 }
0 commit comments