jupyterlab_notifications_extension 1.1.26 → 1.1.27

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/README.md CHANGED
@@ -29,7 +29,7 @@ Interactive dialog with message input, type selection, auto-close timing, and ac
29
29
  - Programmatic command API for extensions and automation
30
30
  - Five notification types (info, success, warning, error, in-progress)
31
31
  - Configurable auto-close with millisecond precision or manual dismiss
32
- - Optional action buttons (currently dismiss only)
32
+ - Action buttons with optional JupyterLab command execution
33
33
  - Broadcast delivery via 30-second polling
34
34
  - In-memory queue cleared after delivery
35
35
 
@@ -77,13 +77,15 @@ Send notifications to JupyterLab. Requires authentication via `Authorization: to
77
77
 
78
78
  **Action Button Schema**:
79
79
 
80
- | Field | Type | Required | Default | Description |
81
- | ------------- | ------ | -------- | ----------- | ------------------------------------------------- |
82
- | `label` | string | Yes | - | Button text |
83
- | `caption` | string | No | `""` | Tooltip text |
84
- | `displayType` | string | No | `"default"` | Visual style: `default`, `accent`, `warn`, `link` |
80
+ | Field | Type | Required | Default | Description |
81
+ | ------------- | ------ | -------- | ----------- | ---------------------------------------------------------------- |
82
+ | `label` | string | Yes | - | Button text |
83
+ | `caption` | string | No | `""` | Tooltip text |
84
+ | `displayType` | string | No | `"default"` | Visual style: `default`, `accent`, `warn`, `link` |
85
+ | `commandId` | string | No | - | JupyterLab command ID to execute (e.g., `filebrowser:open-path`) |
86
+ | `args` | object | No | `{}` | Arguments passed to the command |
85
87
 
86
- Note: Action buttons are purely visual. Clicking any button dismisses the notification using JupyterLab's native behavior. Buttons do not trigger custom callbacks or actions.
88
+ Note: Clicking any button dismisses the notification. If `commandId` is provided, the specified JupyterLab command executes before dismissal.
87
89
 
88
90
  **Response** (200 OK):
89
91
 
@@ -119,12 +121,27 @@ await app.commands.execute('jupyterlab-notifications:send', {
119
121
  autoClose: 3000
120
122
  });
121
123
 
122
- // With action button
124
+ // With dismiss button
123
125
  await app.commands.execute('jupyterlab-notifications:send', {
124
126
  message: 'Error processing data',
125
127
  type: 'error',
126
128
  autoClose: false,
127
- actions: [{ label: 'View Details', displayType: 'accent' }]
129
+ actions: [{ label: 'Dismiss', displayType: 'default' }]
130
+ });
131
+
132
+ // Action button that executes a JupyterLab command
133
+ await app.commands.execute('jupyterlab-notifications:send', {
134
+ message: 'New notebook available',
135
+ type: 'info',
136
+ autoClose: false,
137
+ actions: [
138
+ {
139
+ label: 'Open Notebook',
140
+ commandId: 'filebrowser:open-path',
141
+ args: { path: '/notebooks/example.ipynb' },
142
+ displayType: 'accent'
143
+ }
144
+ ]
128
145
  });
129
146
  ```
130
147
 
@@ -135,8 +152,6 @@ The `jupyterlab-notify` command is installed with the extension:
135
152
  ```bash
136
153
  # Basic notification (auto-detects URL from running servers)
137
154
  jupyterlab-notify -m "Deployment complete" -t success
138
- # Output: URL: http://127.0.0.1:8888/jupyterhub/user/alice | Type: success
139
- # Notification sent: notif_1765552893662_0
140
155
 
141
156
  # With explicit URL (e.g., JupyterHub)
142
157
  jupyterlab-notify --url "http://127.0.0.1:8888/jupyterhub/user/alice" -m "Hello"
@@ -144,6 +159,13 @@ jupyterlab-notify --url "http://127.0.0.1:8888/jupyterhub/user/alice" -m "Hello"
144
159
  # Persistent warning (no auto-close)
145
160
  jupyterlab-notify -m "System maintenance in 1 hour" -t warning --no-auto-close
146
161
 
162
+ # With dismiss button
163
+ jupyterlab-notify -m "Task complete" --action "Dismiss"
164
+
165
+ # Action button that executes a JupyterLab command
166
+ jupyterlab-notify -m "New file available" --action "Open File" \
167
+ --cmd "filebrowser:open-path" --command-args '{"path": "/notebooks/example.ipynb"}'
168
+
147
169
  # Silent mode (notification center only, no toast)
148
170
  jupyterlab-notify -m "Background task finished" --auto-close 0
149
171
  ```
package/lib/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { ICommandPalette, Dialog } from '@jupyterlab/apputils';
1
+ import { ICommandPalette, Dialog, Notification } from '@jupyterlab/apputils';
2
2
  import { Widget } from '@lumino/widgets';
3
3
  import { requestAPI } from './request';
4
4
  /**
@@ -14,7 +14,7 @@ async function fetchAndDisplayNotifications(app) {
14
14
  if (response.notifications && response.notifications.length > 0) {
15
15
  console.log(`Received ${response.notifications.length} notification(s) from server`);
16
16
  response.notifications.forEach(notif => {
17
- // Build options object
17
+ // Build options object with explicit type
18
18
  const options = {
19
19
  autoClose: notif.autoClose
20
20
  };
@@ -22,27 +22,27 @@ async function fetchAndDisplayNotifications(app) {
22
22
  if (notif.data !== undefined) {
23
23
  options.data = notif.data;
24
24
  }
25
- // Build actions array if present (actions are passed as part of options)
25
+ // Build actions array if present
26
26
  if (notif.actions && notif.actions.length > 0) {
27
27
  options.actions = notif.actions.map(action => ({
28
28
  label: action.label,
29
29
  caption: action.caption || '',
30
30
  displayType: action.displayType || 'default',
31
31
  callback: () => {
32
- console.log(`Action clicked: ${action.label}`);
32
+ // If commandId provided, execute the command
33
+ if (action.commandId) {
34
+ app.commands
35
+ .execute(action.commandId, action.args)
36
+ .catch(err => {
37
+ console.error(`Failed to execute command '${action.commandId}':`, err);
38
+ });
39
+ }
40
+ // Default: button click dismisses notification (built-in behavior)
33
41
  }
34
42
  }));
35
43
  }
36
- // Display notification using JupyterLab's command
37
- app.commands
38
- .execute('apputils:notify', {
39
- message: notif.message,
40
- type: notif.type,
41
- options: options
42
- })
43
- .catch(err => {
44
- console.error('Failed to display notification:', err);
45
- });
44
+ // Display notification using Notification manager directly
45
+ Notification.manager.notify(notif.message, notif.type, options);
46
46
  });
47
47
  }
48
48
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jupyterlab_notifications_extension",
3
- "version": "1.1.26",
3
+ "version": "1.1.27",
4
4
  "description": "Jupyterlab extension to receive and display notifications in the main panel. Those can be from the jupyterjub administrator or from other places.",
5
5
  "keywords": [
6
6
  "jupyter",
package/src/index.ts CHANGED
@@ -3,11 +3,26 @@ import {
3
3
  JupyterFrontEndPlugin
4
4
  } from '@jupyterlab/application';
5
5
 
6
- import { ICommandPalette, Dialog } from '@jupyterlab/apputils';
6
+ import { ICommandPalette, Dialog, Notification } from '@jupyterlab/apputils';
7
7
  import { Widget } from '@lumino/widgets';
8
+ import {
9
+ ReadonlyJSONValue,
10
+ ReadonlyPartialJSONObject
11
+ } from '@lumino/coreutils';
8
12
 
9
13
  import { requestAPI } from './request';
10
14
 
15
+ /**
16
+ * Action interface for notifications
17
+ */
18
+ interface INotificationAction {
19
+ label: string;
20
+ caption?: string;
21
+ displayType?: 'default' | 'accent' | 'warn' | 'link';
22
+ commandId?: string;
23
+ args?: ReadonlyPartialJSONObject;
24
+ }
25
+
11
26
  /**
12
27
  * Notification interface matching backend payload
13
28
  */
@@ -17,12 +32,8 @@ interface INotificationData {
17
32
  type: 'default' | 'info' | 'success' | 'warning' | 'error' | 'in-progress';
18
33
  autoClose: number | false;
19
34
  createdAt: number;
20
- actions?: Array<{
21
- label: string;
22
- caption?: string;
23
- displayType?: 'default' | 'accent' | 'warn' | 'link';
24
- }>;
25
- data?: any;
35
+ actions?: INotificationAction[];
36
+ data?: ReadonlyJSONValue;
26
37
  }
27
38
 
28
39
  /**
@@ -47,8 +58,8 @@ async function fetchAndDisplayNotifications(
47
58
  );
48
59
 
49
60
  response.notifications.forEach(notif => {
50
- // Build options object
51
- const options: any = {
61
+ // Build options object with explicit type
62
+ const options: Notification.IOptions<ReadonlyJSONValue> = {
52
63
  autoClose: notif.autoClose
53
64
  };
54
65
 
@@ -57,28 +68,31 @@ async function fetchAndDisplayNotifications(
57
68
  options.data = notif.data;
58
69
  }
59
70
 
60
- // Build actions array if present (actions are passed as part of options)
71
+ // Build actions array if present
61
72
  if (notif.actions && notif.actions.length > 0) {
62
73
  options.actions = notif.actions.map(action => ({
63
74
  label: action.label,
64
75
  caption: action.caption || '',
65
76
  displayType: action.displayType || 'default',
66
77
  callback: () => {
67
- console.log(`Action clicked: ${action.label}`);
78
+ // If commandId provided, execute the command
79
+ if (action.commandId) {
80
+ app.commands
81
+ .execute(action.commandId, action.args)
82
+ .catch(err => {
83
+ console.error(
84
+ `Failed to execute command '${action.commandId}':`,
85
+ err
86
+ );
87
+ });
88
+ }
89
+ // Default: button click dismisses notification (built-in behavior)
68
90
  }
69
91
  }));
70
92
  }
71
93
 
72
- // Display notification using JupyterLab's command
73
- app.commands
74
- .execute('apputils:notify', {
75
- message: notif.message,
76
- type: notif.type,
77
- options: options
78
- })
79
- .catch(err => {
80
- console.error('Failed to display notification:', err);
81
- });
94
+ // Display notification using Notification manager directly
95
+ Notification.manager.notify(notif.message, notif.type, options);
82
96
  });
83
97
  }
84
98
  } catch (reason) {