From 76d9739ed558e07b994e62a570395373ded99706 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 13 Jun 2024 17:25:11 +0200 Subject: [PATCH 01/16] exporting helper function garanteeSemverFormat --- lib/utils.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/utils.js b/lib/utils.js index fe4b164..0f366d1 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -539,6 +539,8 @@ function garanteeSemverFormat(version) { return version; } +module.exports.garanteeSemverFormat = garanteeSemverFormat; + function sanitizeNotifuTypeArgument(type) { if (typeof type === 'string' || type instanceof String) { if (type.toLowerCase() === 'info') return 'info'; From 9fe9ac54b4ee210769368b9f1427e19ec7b51f6e Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 13 Jun 2024 17:27:20 +0200 Subject: [PATCH 02/16] added 'action' arg for notify-send --- lib/utils.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/utils.js b/lib/utils.js index 0f366d1..9c2ab51 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -45,7 +45,10 @@ const notifySendFlags = { h: 'hint', hint: 'hint', a: 'app-name', - 'app-name': 'app-name' + 'app-name': 'app-name', + action: 'action', + A: 'action', + actions: 'action' }; module.exports.command = function (notifier, options, cb) { From d6e74d877131c57a64645b26c530bb45fe0a0330 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 13 Jun 2024 17:34:46 +0200 Subject: [PATCH 03/16] with notify-send several actions are defined by repeating "--action" args several times. Changed constructArgumentList to split array arguments when requested by extra options. --- lib/utils.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/utils.js b/lib/utils.js index 9c2ab51..ce8c1df 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -300,6 +300,7 @@ module.exports.constructArgumentList = function (options, extra) { const explicitTrue = !!extra.explicitTrue; const keepNewlines = !!extra.keepNewlines; const wrapper = extra.wrapper === undefined ? '"' : extra.wrapper; + const arrayArgToMultipleArgs = extra.arrayArgToMultipleArgs || false; const escapeFn = function escapeFn(arg) { if (isArray(arg)) { @@ -326,7 +327,13 @@ module.exports.constructArgumentList = function (options, extra) { if (explicitTrue && options[key] === true) { args.push('-' + keyExtra + key); } else if (explicitTrue && options[key] === false) continue; - else args.push('-' + keyExtra + key, escapeFn(options[key])); + else { + if (arrayArgToMultipleArgs && isArray(options[key])) { + for (const val of options[key]) { + args.push('-' + keyExtra + key, escapeFn(val)); + } + } else args.push('-' + keyExtra + key, escapeFn(options[key])); + } } } return args; From b28ba5d09ef4270fa5e3c80601717336f5c00754 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 13 Jun 2024 17:35:32 +0200 Subject: [PATCH 04/16] Added test cases for splitting notify-send action arguments. --- test/notify-send.js | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/test/notify-send.js b/test/notify-send.js index 190fbfa..3b4c39e 100644 --- a/test/notify-send.js +++ b/test/notify-send.js @@ -130,4 +130,58 @@ describe('notify-send', function () { tullball: 'notValid' }); }); + + it('should add one action option per action entry', function (done) { + const expected = [ + '"title"', + '"body"', + '--icon', + '"icon-string"', + '--action', + '"Yes"', + '--action', + '"No"', + '--action', + '"May\\`be\\`"', + '--expire-time', + '"10000"' + ]; + + expectArgsListToBe(expected, done); + const notifier = new Notify({ suppressOsdCheck: true }); + notifier.notify({ + title: 'title', + message: 'body', + icon: 'icon-string', + tullball: 'notValid', + action: ['Yes', 'No', 'May`be`'] + }); + }); + + it('should add one action option per actionS entry', function (done) { + const expected = [ + '"title"', + '"body"', + '--icon', + '"icon-string"', + '--action', + '"Yes"', + '--action', + '"No"', + '--action', + '"May\\`be\\`"', + '--expire-time', + '"10000"' + ]; + + expectArgsListToBe(expected, done); + const notifier = new Notify({ suppressOsdCheck: true }); + notifier.notify({ + title: 'title', + message: 'body', + icon: 'icon-string', + tullball: 'notValid', + actions: ['Yes', 'No', 'May`be`'] + }); + }); }); From f7a24de633d68d47d084e3d8d4008de073e95730 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 13 Jun 2024 17:39:46 +0200 Subject: [PATCH 05/16] notifysend now satisfies new test cases for actions --- notifiers/notifysend.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/notifiers/notifysend.js b/notifiers/notifysend.js index 68dfbf6..f05bfe1 100644 --- a/notifiers/notifysend.js +++ b/notifiers/notifysend.js @@ -73,13 +73,21 @@ function notifyRaw(options, callback) { } Object.defineProperty(NotifySend.prototype, 'notify', { - get: function() { + get: function () { if (!this._notify) this._notify = notifyRaw.bind(this); return this._notify; } }); -const allowedArguments = ['urgency', 'expire-time', 'icon', 'category', 'hint', 'app-name']; +const allowedArguments = [ + 'action', + 'urgency', + 'expire-time', + 'icon', + 'category', + 'hint', + 'app-name' +]; function doNotification(options, callback) { options = utils.mapToNotifySend(options); @@ -89,9 +97,15 @@ function doNotification(options, callback) { delete options.title; delete options.message; + if ('actions' in options) { + options.action = options.actions; + delete options.actions; + } + const argsList = utils.constructArgumentList(options, { initial: initial, keyExtra: '-', + arrayArgToMultipleArgs: true, allowedArguments: allowedArguments }); From 0f08a9c4c99021f56cfd3539ba37da26ac512079 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 13 Jun 2024 17:56:10 +0200 Subject: [PATCH 06/16] added decorator to rewrite result of notify-send call, replacing index of selected action with action name. Use example/toaster-with-actions.js to test. --- notifiers/notifysend.js | 44 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/notifiers/notifysend.js b/notifiers/notifysend.js index f05bfe1..cd317f5 100644 --- a/notifiers/notifysend.js +++ b/notifiers/notifysend.js @@ -79,6 +79,41 @@ Object.defineProperty(NotifySend.prototype, 'notify', { } }); +const NotifySendActionJackerDecorator = function ( + emitter, + options, + fn, + mapper +) { + options = utils.clone(options); + fn = fn || noop; + if (typeof fn !== 'function') { + throw new TypeError( + 'The second argument must be a function callback. You have passed ' + + typeof fn + ); + } + + return function (err, data) { + let resultantData = data; + let metadata = {}; + // Allow for extra data if resultantData is an object + if (resultantData && typeof resultantData === 'object') { + metadata = resultantData; + resultantData = resultantData.activationType; + } + + // Sanitize the data + if (resultantData) { + resultantData = resultantData.trim(); + const index = Number(resultantData); + resultantData = options.action[index].toLowerCase(); + } + + fn.apply(emitter, [err, resultantData, metadata]); + }; +}; + const allowedArguments = [ 'action', 'urgency', @@ -109,5 +144,12 @@ function doNotification(options, callback) { allowedArguments: allowedArguments }); - utils.command(notifier, argsList, callback); + const actionJackedCallback = NotifySendActionJackerDecorator( + this, + options, + callback, + null + ); + + utils.command(notifier, argsList, actionJackedCallback); } From f623e62bfbbc2e810b90312e2f9708bee93a17c8 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 13 Jun 2024 18:13:24 +0200 Subject: [PATCH 07/16] added event emits as they should be, but EventEmitter inheritance seems to be broken. --- notifiers/notifysend.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/notifiers/notifysend.js b/notifiers/notifysend.js index cd317f5..e4fb428 100644 --- a/notifiers/notifysend.js +++ b/notifiers/notifysend.js @@ -111,6 +111,17 @@ const NotifySendActionJackerDecorator = function ( } fn.apply(emitter, [err, resultantData, metadata]); + if (!resultantData && !err) { + emitter.emit('activate', emitter, options, metadata); + return; + } + if (!err) { + emitter.emit(resultantData, emitter, options, metadata); + return; + } + if (err) { + emitter.emit('error', emitter, options, err); + } }; }; From 9cfe1a2724a7995e10d374e51a2e2160e052489a Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 13 Jun 2024 18:49:52 +0200 Subject: [PATCH 08/16] refactored NotifySend into an ES6 class, so event emitting works. Use example/toaster-with-actions.js for testing. --- notifiers/notifysend.js | 193 +++++++++++++++++++--------------------- 1 file changed, 90 insertions(+), 103 deletions(-) diff --git a/notifiers/notifysend.js b/notifiers/notifysend.js index e4fb428..c764747 100644 --- a/notifiers/notifysend.js +++ b/notifiers/notifysend.js @@ -6,78 +6,11 @@ const which = require('which'); const utils = require('../lib/utils'); const EventEmitter = require('events').EventEmitter; -const util = require('util'); const notifier = 'notify-send'; let hasNotifier; -module.exports = NotifySend; - -function NotifySend(options) { - options = utils.clone(options || {}); - if (!(this instanceof NotifySend)) { - return new NotifySend(options); - } - - this.options = options; - - EventEmitter.call(this); -} -util.inherits(NotifySend, EventEmitter); - function noop() {} -function notifyRaw(options, callback) { - options = utils.clone(options || {}); - callback = callback || noop; - - if (typeof callback !== 'function') { - throw new TypeError( - 'The second argument must be a function callback. You have passed ' + - typeof callback - ); - } - - if (typeof options === 'string') { - options = { title: 'node-notifier', message: options }; - } - - if (!options.message) { - callback(new Error('Message is required.')); - return this; - } - - if (os.type() !== 'Linux' && !os.type().match(/BSD$/)) { - callback(new Error('Only supported on Linux and *BSD systems')); - return this; - } - - if (hasNotifier === false) { - callback(new Error('notify-send must be installed on the system.')); - return this; - } - - if (hasNotifier || !!this.options.suppressOsdCheck) { - doNotification(options, callback); - return this; - } - - try { - hasNotifier = !!which.sync(notifier); - doNotification(options, callback); - } catch (err) { - hasNotifier = false; - return callback(err); - } - - return this; -} - -Object.defineProperty(NotifySend.prototype, 'notify', { - get: function () { - if (!this._notify) this._notify = notifyRaw.bind(this); - return this._notify; - } -}); const NotifySendActionJackerDecorator = function ( emitter, @@ -125,42 +58,96 @@ const NotifySendActionJackerDecorator = function ( }; }; -const allowedArguments = [ - 'action', - 'urgency', - 'expire-time', - 'icon', - 'category', - 'hint', - 'app-name' -]; - -function doNotification(options, callback) { - options = utils.mapToNotifySend(options); - options.title = options.title || 'Node Notification:'; - - const initial = [options.title, options.message]; - delete options.title; - delete options.message; - - if ('actions' in options) { - options.action = options.actions; - delete options.actions; +class NotifySend extends EventEmitter { + constructor(options) { + super(); + this.options = utils.clone(options || {}); } - const argsList = utils.constructArgumentList(options, { - initial: initial, - keyExtra: '-', - arrayArgToMultipleArgs: true, - allowedArguments: allowedArguments - }); - - const actionJackedCallback = NotifySendActionJackerDecorator( - this, - options, - callback, - null - ); - - utils.command(notifier, argsList, actionJackedCallback); + notify(options, callback) { + options = utils.clone(options || {}); + callback = callback || noop; + if (typeof callback !== 'function') { + throw new TypeError( + 'The second argument must be a function callback. You have passed ' + + typeof callback + ); + } + + if (typeof options === 'string') { + options = { title: 'node-notifier', message: options }; + } + + if (!options.message) { + callback(new Error('Message is required.')); + return this; + } + + if (os.type() !== 'Linux' && !os.type().match(/BSD$/)) { + callback(new Error('Only supported on Linux and *BSD systems')); + return this; + } + + if (hasNotifier === false) { + callback(new Error('notify-send must be installed on the system.')); + return this; + } + + if (hasNotifier || !!this.options.suppressOsdCheck) { + this._doNotification(options, callback); + return this; + } + + try { + hasNotifier = !!which.sync(notifier); + this._doNotification(options, callback); + } catch (err) { + hasNotifier = false; + return callback(err); + } + + return this; + } + + _doNotification(options, callback) { + options = utils.mapToNotifySend(options); + options.title = options.title || 'Node Notification:'; + + const initial = [options.title, options.message]; + delete options.title; + delete options.message; + + if ('actions' in options) { + options.action = options.actions; + delete options.actions; + } + + const allowedArguments = [ + 'action', + 'urgency', + 'expire-time', + 'icon', + 'category', + 'hint', + 'app-name' + ]; + + const argsList = utils.constructArgumentList(options, { + initial: initial, + keyExtra: '-', + arrayArgToMultipleArgs: true, + allowedArguments: allowedArguments + }); + + const actionJackedCallback = NotifySendActionJackerDecorator( + this, + options, + callback, + null + ); + + utils.command(notifier, argsList, actionJackedCallback); + } } + +module.exports = NotifySend; From 8eb5af378567ef16e9c553c209172bc2ee582d08 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 13 Jun 2024 19:01:09 +0200 Subject: [PATCH 09/16] Added actions to NotifySend usage desc and example snippet. --- README.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 44885fa..7c26cca 100644 --- a/README.md +++ b/README.md @@ -344,13 +344,25 @@ See full usage on the [project homepage: **`notifu`**](http://www.paralint.com/p ### Usage: `NotifySend` -**Note:** `notify-send` doesn't support the `wait` flag. +**Note:** `notify-send` <0.8.2 doesn't support the `wait` flag. + +**Note:** `notify-send` >=0.8.2 supports actions. ```javascript const NotifySend = require('node-notifier').NotifySend; var notifier = new NotifySend(); +notifier.on('ok', () => { + console.log('"OK" was pressed'); +}); +notifier.on('cancel', () => { + console.log('"Cancel" was pressed'); +}); +notifier.on('activate', () => { + console.log('notification was clicked'); +}); + notifier.notify({ title: 'Foo', message: 'Hello World', @@ -363,12 +375,15 @@ notifier.notify({ 'app-name': 'node-notifier', urgency: undefined, category: undefined, - hint: undefined + hint: undefined, + actions: ['OK', 'Cancel'] // Name of action in lowercase will be used as event name }); ``` See flags and options on the man page [`notify-send(1)`](http://manpages.ubuntu.com/manpages/gutsy/man1/notify-send.1.html) +Run `example/toaster-with-actions` to see handling of action response. + ## Thanks to OSS `node-notifier` is made possible through Open Source Software. From 185ead4cffba3cf7de3ca661c057c04c549136b8 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 13 Jun 2024 19:43:31 +0200 Subject: [PATCH 10/16] added check of notify-send version before trying to use actions. --- notifiers/notifysend.js | 42 +++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/notifiers/notifysend.js b/notifiers/notifysend.js index c764747..afebcfe 100644 --- a/notifiers/notifysend.js +++ b/notifiers/notifysend.js @@ -4,11 +4,13 @@ const os = require('os'); const which = require('which'); const utils = require('../lib/utils'); - const EventEmitter = require('events').EventEmitter; +const execSync = require('child_process').execSync; +const semver = require('semver'); const notifier = 'notify-send'; let hasNotifier; +let hasActionsCapability; function noop() {} @@ -62,6 +64,7 @@ class NotifySend extends EventEmitter { constructor(options) { super(); this.options = utils.clone(options || {}); + this.checkActionCapability(); } notify(options, callback) { @@ -99,7 +102,6 @@ class NotifySend extends EventEmitter { } try { - hasNotifier = !!which.sync(notifier); this._doNotification(options, callback); } catch (err) { hasNotifier = false; @@ -109,6 +111,30 @@ class NotifySend extends EventEmitter { return this; } + checkActionCapability() { + hasActionsCapability = false; + hasNotifier = !!which.sync(notifier); + + if (!hasNotifier) return; + + const notifierVersion = execSync(notifier + ' --version'); + const notifierVersionNumber = notifierVersion + .toString() + .trim() + .split(' ')[1]; + + if ( + semver.satisfies( + utils.garanteeSemverFormat(notifierVersionNumber), + '>=0.8.2' + ) + ) { + hasActionsCapability = true; + } else { + // throw new Error('notify-send version ' + notifierVersionNumber + ' does not support "actions". Upgrade to a newer version >=0.8.2'); + } + } + _doNotification(options, callback) { options = utils.mapToNotifySend(options); options.title = options.title || 'Node Notification:'; @@ -122,23 +148,27 @@ class NotifySend extends EventEmitter { delete options.actions; } - const allowedArguments = [ - 'action', + let allowedArguments = [ 'urgency', 'expire-time', 'icon', 'category', 'hint', - 'app-name' + 'app-name', + 'action' ]; + if (!hasActionsCapability) allowedArguments.pop(); const argsList = utils.constructArgumentList(options, { initial: initial, keyExtra: '-', - arrayArgToMultipleArgs: true, + arrayArgToMultipleArgs: hasActionsCapability, allowedArguments: allowedArguments }); + if (!hasActionsCapability) + return utils.command(notifier, argsList, callback); + const actionJackedCallback = NotifySendActionJackerDecorator( this, options, From 130656b320810cc535251e1c0eff693842326238 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Thu, 13 Jun 2024 19:47:06 +0200 Subject: [PATCH 11/16] fixed eslint problem --- notifiers/notifysend.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/notifiers/notifysend.js b/notifiers/notifysend.js index afebcfe..f42ab84 100644 --- a/notifiers/notifysend.js +++ b/notifiers/notifysend.js @@ -148,16 +148,15 @@ class NotifySend extends EventEmitter { delete options.actions; } - let allowedArguments = [ + const allowedArguments = [ 'urgency', 'expire-time', 'icon', 'category', 'hint', - 'app-name', - 'action' + 'app-name' ]; - if (!hasActionsCapability) allowedArguments.pop(); + if (hasActionsCapability) allowedArguments.push('action'); const argsList = utils.constructArgumentList(options, { initial: initial, @@ -166,8 +165,9 @@ class NotifySend extends EventEmitter { allowedArguments: allowedArguments }); - if (!hasActionsCapability) + if (!hasActionsCapability) { return utils.command(notifier, argsList, callback); + } const actionJackedCallback = NotifySendActionJackerDecorator( this, From f17672e74e91fce300710ab36669294a37f24427 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 14 Jun 2024 10:56:16 +0200 Subject: [PATCH 12/16] added --wait flag for notify-send --- lib/utils.js | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/utils.js b/lib/utils.js index ce8c1df..07618a4 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -48,7 +48,9 @@ const notifySendFlags = { 'app-name': 'app-name', action: 'action', A: 'action', - actions: 'action' + actions: 'action', + w: 'wait', + wait: 'wait' }; module.exports.command = function (notifier, options, cb) { @@ -59,14 +61,13 @@ module.exports.command = function (notifier, options, cb) { console.info('[notifier options]', options.join(' ')); } - return cp.exec(notifier + ' ' + options.join(' '), function ( - error, - stdout, - stderr - ) { - if (error) return cb(error); - cb(stderr, stdout); - }); + return cp.exec( + notifier + ' ' + options.join(' '), + function (error, stdout, stderr) { + if (error) return cb(error); + cb(stderr, stdout); + } + ); }; module.exports.fileCommand = function (notifier, options, cb) { From ea1f4b2d854749682dd97d63697e7b8e1dabc59b Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 14 Jun 2024 10:56:54 +0200 Subject: [PATCH 13/16] added --wait flag for notify-send --- notifiers/notifysend.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/notifiers/notifysend.js b/notifiers/notifysend.js index f42ab84..79f14ab 100644 --- a/notifiers/notifysend.js +++ b/notifiers/notifysend.js @@ -156,12 +156,16 @@ class NotifySend extends EventEmitter { 'hint', 'app-name' ]; - if (hasActionsCapability) allowedArguments.push('action'); + if (hasActionsCapability) { + allowedArguments.push('action'); + allowedArguments.push('wait'); + } const argsList = utils.constructArgumentList(options, { initial: initial, keyExtra: '-', arrayArgToMultipleArgs: hasActionsCapability, + explicitTrue: true, allowedArguments: allowedArguments }); From ded73eff1c56d24b8f750ade17b13e59ff605240 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 14 Jun 2024 10:57:14 +0200 Subject: [PATCH 14/16] added test case for --wait flag for notify-send --- example/notify-send.js | 84 ++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 30 ++++++++++----- test/notify-send.js | 12 ++++++ 3 files changed, 116 insertions(+), 10 deletions(-) create mode 100644 example/notify-send.js diff --git a/example/notify-send.js b/example/notify-send.js new file mode 100644 index 0000000..a8c25fb --- /dev/null +++ b/example/notify-send.js @@ -0,0 +1,84 @@ +const notifier = require('../index'); +const path = require('path'); + +notifier.on('activate', function (notifierObject, options, event) { + console.log( + 'clicked:', + JSON.stringify(notifierObject, null, 2), + JSON.stringify(options, null, 2), + JSON.stringify(event, null, 2) + ); +}); + +notifier.on('timeout', function (notifierObject, options) { + // does not work for notify-send + console.log( + 'timeout:', + JSON.stringify(notifierObject, null, 2), + JSON.stringify(options, null, 2) + ); +}); + +notifier.on('yes', (nn, options, x) => { + console.log( + 'YES', + JSON.stringify(options, null, 2), + JSON.stringify(x, null, 2) + ); +}); +notifier.on('no', (nn, options) => { + console.log('NO', JSON.stringify(options, null, 2)); +}); +notifier.on('ok', (nn, options) => { + console.log('OK', JSON.stringify(options, null, 2)); +}); + +const testNotificationWithoutActions = () => { + notifier.notify( + { + title: 'My awesome title', + message: 'Hello from node, Mr. User!', + icon: path.resolve(path.join(__dirname, 'coulson.jpg')), // Absolute path (doesn't work on balloons) + sound: true, // Only Notification Center or Windows Toasters + wait: true // Wait with callback, until user action is taken against notification, does not apply to Windows Toasters as they always wait or notify-send as it does not support the wait option + // actions: ['OK'] + }, + function (err, response, metadata) { + // Response (is response from notification + // Metadata contains activationType, activationAt, deliveredAt + console.log( + 'cb:', + JSON.stringify(err, null, 2), + JSON.stringify(response, null, 2), + JSON.stringify(metadata, null, 2) + ); + } + ); +}; + +const testNotificationWithActions = () => { + notifier.notify( + { + title: 'My awesome title', + message: 'Hello from node, Mr. User!', + icon: path.resolve(path.join(__dirname, 'coulson.jpg')), // Absolute path (doesn't work on balloons) + sound: true, // Only Notification Center or Windows Toasters + actions: ['Yes', 'No'] + }, + function (err, response, metadata) { + // Response is response from notification + // Metadata contains activationType, activationAt, deliveredAt + console.log( + 'cb:', + JSON.stringify(err, null, 2), + JSON.stringify(response, null, 2), + JSON.stringify(metadata, null, 2) + ); + } + ); +}; + +if (require.main === module) { + setTimeout(testNotificationWithActions, 10); + setTimeout(testNotificationWithoutActions, 10000); +} diff --git a/package-lock.json b/package-lock.json index 1674acd..61299d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1854,14 +1854,24 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001228", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz", - "integrity": "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==", + "version": "1.0.30001634", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001634.tgz", + "integrity": "sha512-fbBYXQ9q3+yp1q1gBk86tOFs4pyn/yxFm5ZNP18OXJDfA3txImOY9PhfxVggZ4vRHDqoU8NrKU81eN0OtzOgRA==", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] }, "node_modules/capture-exit": { "version": "2.0.0", @@ -11926,9 +11936,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001228", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz", - "integrity": "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==", + "version": "1.0.30001634", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001634.tgz", + "integrity": "sha512-fbBYXQ9q3+yp1q1gBk86tOFs4pyn/yxFm5ZNP18OXJDfA3txImOY9PhfxVggZ4vRHDqoU8NrKU81eN0OtzOgRA==", "dev": true }, "capture-exit": { diff --git a/test/notify-send.js b/test/notify-send.js index 3b4c39e..c47164f 100644 --- a/test/notify-send.js +++ b/test/notify-send.js @@ -184,4 +184,16 @@ describe('notify-send', function () { actions: ['Yes', 'No', 'May`be`'] }); }); + + it('should keep wait switch (and add expire-time option)', function (done) { + const expected = ['"title"', '"body"', '--wait', '--expire-time', '"5000"']; + + expectArgsListToBe(expected, done); + const notifier = new Notify({ suppressOsdCheck: true }); + notifier.notify({ + title: 'title', + message: 'body', + wait: true + }); + }); }); From 41d008e083208a1b87b4ec5db0901a39993d57d0 Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 14 Jun 2024 11:11:52 +0200 Subject: [PATCH 15/16] making sure options received in event callback have title and message of notification --- notifiers/notifysend.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/notifiers/notifysend.js b/notifiers/notifysend.js index 79f14ab..9d571ba 100644 --- a/notifiers/notifysend.js +++ b/notifiers/notifysend.js @@ -136,6 +136,12 @@ class NotifySend extends EventEmitter { } _doNotification(options, callback) { + if ('actions' in options) { + // rename actions to action + options.action = options.actions; + delete options.actions; + } + const originalOptions = utils.clone(options); // nearly original options options = utils.mapToNotifySend(options); options.title = options.title || 'Node Notification:'; @@ -143,11 +149,6 @@ class NotifySend extends EventEmitter { delete options.title; delete options.message; - if ('actions' in options) { - options.action = options.actions; - delete options.actions; - } - const allowedArguments = [ 'urgency', 'expire-time', @@ -175,7 +176,7 @@ class NotifySend extends EventEmitter { const actionJackedCallback = NotifySendActionJackerDecorator( this, - options, + originalOptions, callback, null ); From cfb75793434fe8e1ecafc96fe969ae67e64dfb5d Mon Sep 17 00:00:00 2001 From: Martin Mueller Date: Fri, 14 Jun 2024 11:16:23 +0200 Subject: [PATCH 16/16] clarifying notify-send section --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 7c26cca..02d743c 100644 --- a/README.md +++ b/README.md @@ -346,7 +346,7 @@ See full usage on the [project homepage: **`notifu`**](http://www.paralint.com/p **Note:** `notify-send` <0.8.2 doesn't support the `wait` flag. -**Note:** `notify-send` >=0.8.2 supports actions. +**Note:** `notify-send` >=0.8.2 supports `action` and `wait` flags. ```javascript const NotifySend = require('node-notifier').NotifySend; @@ -376,13 +376,13 @@ notifier.notify({ urgency: undefined, category: undefined, hint: undefined, - actions: ['OK', 'Cancel'] // Name of action in lowercase will be used as event name + actions: ['OK', 'Cancel'] // Name of action in lowercase will be used as event name; implicitly adds '--wait' as well. }); ``` See flags and options on the man page [`notify-send(1)`](http://manpages.ubuntu.com/manpages/gutsy/man1/notify-send.1.html) -Run `example/toaster-with-actions` to see handling of action response. +Run `example/notify-send.js` to see handling of action response. **You must run this example from a real terminal, it doesn't work from inside e.g. VSCode since libnotify will be in `confined` mode then.** ## Thanks to OSS