@@ -2,13 +2,15 @@ import {
22 JupyterFrontEnd ,
33 JupyterFrontEndPlugin
44} from '@jupyterlab/application' ;
5+ import { ISessionContext , SessionContext } from '@jupyterlab/apputils' ;
56import { KernelError , Notebook , NotebookActions } from '@jupyterlab/notebook' ;
67import { Cell } from '@jupyterlab/cells' ;
78import { ISettingRegistry } from '@jupyterlab/settingregistry' ;
89import { ICodeCellModel } from '@jupyterlab/cells' ;
910import { PageConfig } from '@jupyterlab/coreutils' ;
1011import LRU from 'lru-cache' ;
1112import moment from 'moment' ;
13+ import { issueNtfyNotification } from './ntfy' ;
1214import { checkBrowserNotificationSettings } from './settings' ;
1315
1416interface ICellExecutionMetadata {
@@ -19,16 +21,18 @@ interface ICellExecutionMetadata {
1921/**
2022 * Constructs notification message and displays it.
2123 */
22- function displayNotification (
24+ async function displayNotification (
2325 cellDuration : string ,
2426 cellNumber : number ,
2527 notebookName : string ,
2628 reportCellNumber : boolean ,
2729 reportCellExecutionTime : boolean ,
2830 failedExecution : boolean ,
2931 error : KernelError | null ,
30- lastCellOnly : boolean
31- ) : void {
32+ lastCellOnly : boolean ,
33+ notificationMethods : string [ ] ,
34+ sessionContext : ISessionContext | null ,
35+ ) : Promise < void > {
3236 const base = PageConfig . getBaseUrl ( ) ;
3337 const notificationPayload = {
3438 icon : base + 'static/favicon.ico' ,
@@ -52,13 +56,20 @@ function displayNotification(
5256 }
5357
5458 notificationPayload . body = message ;
55- new Notification ( title , notificationPayload ) ;
59+
60+ if ( notificationMethods . includes ( 'browser' ) ) {
61+ new Notification ( title , notificationPayload ) ;
62+ }
63+ if ( ( notificationMethods . includes ( 'ntfy' ) ) && ( sessionContext ) ) {
64+ await issueNtfyNotification ( title , notificationPayload , sessionContext ) ;
65+ }
66+
5667}
5768
5869/**
5970 * Trigger notification.
6071 */
61- function triggerNotification (
72+ async function triggerNotification (
6273 cell : Cell ,
6374 notebook : Notebook ,
6475 cellExecutionMetadataTable : LRU < string , ICellExecutionMetadata > ,
@@ -69,7 +80,9 @@ function triggerNotification(
6980 cellNumberType : string ,
7081 failedExecution : boolean ,
7182 error : KernelError | null ,
72- lastCellOnly : boolean
83+ lastCellOnly : boolean ,
84+ notificationMethods : string [ ] ,
85+ sessionContext : ISessionContext | null ,
7386) {
7487 const cellEndTime = new Date ( ) ;
7588 const codeCellModel = cell . model as ICodeCellModel ;
@@ -102,15 +115,17 @@ function triggerNotification(
102115 ? cellExecutionMetadata . index
103116 : codeCellModel . executionCount ;
104117 const notebookName = notebook . title . label . replace ( / \. [ ^ / . ] + $ / , '' ) ;
105- displayNotification (
118+ await displayNotification (
106119 cellDuration ,
107120 cellNumber ,
108121 notebookName ,
109122 reportCellNumber ,
110123 reportCellExecutionTime ,
111124 failedExecution ,
112125 error ,
113- lastCellOnly
126+ lastCellOnly ,
127+ notificationMethods ,
128+ sessionContext ,
114129 ) ;
115130 }
116131 }
@@ -128,6 +143,8 @@ const extension: JupyterFrontEndPlugin<void> = {
128143 let reportCellNumber = true ;
129144 let cellNumberType = 'cell_index' ;
130145 let lastCellOnly = false ;
146+ let notificationMethods = [ 'browser' ] ;
147+
131148 const cellExecutionMetadataTable : LRU <
132149 string ,
133150 ICellExecutionMetadata
@@ -138,6 +155,13 @@ const extension: JupyterFrontEndPlugin<void> = {
138155 max : 500
139156 } ) ;
140157
158+ // SessionContext is used for running python codes
159+ const manager = app . serviceManager ;
160+ const sessionContext = new SessionContext ( {
161+ sessionManager : manager . sessions as any ,
162+ specsManager : manager . kernelspecs ,
163+ } ) ;
164+
141165 if ( settingRegistry ) {
142166 const setting = await settingRegistry . load ( extension . id ) ;
143167 const updateSettings = ( ) : void => {
@@ -150,6 +174,7 @@ const extension: JupyterFrontEndPlugin<void> = {
150174 . composite as boolean ;
151175 cellNumberType = setting . get ( 'cell_number_type' ) . composite as string ;
152176 lastCellOnly = setting . get ( 'last_cell_only' ) . composite as boolean ;
177+ notificationMethods = setting . get ( 'notification_methods' ) . composite as string [ ] ;
153178 } ;
154179 updateSettings ( ) ;
155180 setting . changed . connect ( updateSettings ) ;
@@ -165,10 +190,10 @@ const extension: JupyterFrontEndPlugin<void> = {
165190 }
166191 } ) ;
167192
168- NotebookActions . executed . connect ( ( _ , args ) => {
193+ NotebookActions . executed . connect ( async ( _ , args ) => {
169194 if ( enabled && ! lastCellOnly ) {
170195 const { cell, notebook, success, error } = args ;
171- triggerNotification (
196+ await triggerNotification (
172197 cell ,
173198 notebook ,
174199 cellExecutionMetadataTable ,
@@ -179,16 +204,18 @@ const extension: JupyterFrontEndPlugin<void> = {
179204 cellNumberType ,
180205 ! success ,
181206 error ,
182- lastCellOnly
207+ lastCellOnly ,
208+ notificationMethods ,
209+ sessionContext ,
183210 ) ;
184211 }
185212 } ) ;
186213
187- NotebookActions . selectionExecuted . connect ( ( _ , args ) => {
214+ NotebookActions . selectionExecuted . connect ( async ( _ , args ) => {
188215 if ( enabled && lastCellOnly ) {
189216 const { lastCell, notebook } = args ;
190217 const failedExecution = false ;
191- triggerNotification (
218+ await triggerNotification (
192219 lastCell ,
193220 notebook ,
194221 cellExecutionMetadataTable ,
@@ -199,7 +226,9 @@ const extension: JupyterFrontEndPlugin<void> = {
199226 cellNumberType ,
200227 failedExecution ,
201228 null ,
202- lastCellOnly
229+ lastCellOnly ,
230+ notificationMethods ,
231+ sessionContext ,
203232 ) ;
204233 }
205234 } ) ;
0 commit comments