diff --git a/.eslintrc b/.eslintrc
deleted file mode 100644
index 5c166c7..0000000
--- a/.eslintrc
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "plugins": ["prettier"],
- "extends": [
- "semistandard"
- ],
- "env": {
- "node": true,
- "jest": true
- },
- "rules": {
- "space-before-function-paren": 0,
- "no-control-regex": 0,
- "no-console": 1,
- "no-var": 2,
- "prefer-const": 1,
- "no-prototype-builtins": 0,
- "no-useless-escape": 1,
- "comma-dangle": 0,
- "keyword-spacing": ["error", { "before": true, "after": true }],
- "comma-spacing": ["error", { "before": false, "after": true }],
- "indent": 0,
- "prefer-spread": 1,
- "no-mixed-operators": 1,
- "prettier/prettier": 1,
- "camelcase": ["error", {
- "allow": ["^UNSAFE_"],
- "properties": "never",
- "ignoreGlobals": true
- }],
- "quotes": [
- "error", "single", {
- "avoidEscape": true,
- "allowTemplateLiterals": true
- }
- ],
- }
-}
diff --git a/.prettierrc b/.prettierrc
index d9c33d2..0dc3fc7 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -49,7 +49,7 @@ useTabs: false
# @default : true
# @ref : https://prettier.io/docs/en/options.html#semicolons
# --------------------------------------------------------------------------------------
-semi: true
+semi: false
# --------------------------------------------------------------------------------------
# Use single quotes instead of double quotes.
diff --git a/index.js b/index.js
index cc71c54..c789e9b 100644
--- a/index.js
+++ b/index.js
@@ -1,10 +1,12 @@
-const { app, BrowserWindow, Tray, Menu, MenuItem } = require('electron');
-const electronShell = require('electron').shell;
-const toasted = require('toasted-notifier');
-const process = require('process');
-const path = require('path');
-const moment = require('moment');
-const Store = require('./store.js');
+/* eslint-disable no-unused-vars */
+/* eslint-disable no-console */
+const { app, BrowserWindow, Tray, Menu, MenuItem } = require( 'electron' )
+const electronShell = require( 'electron' ).shell
+const toasted = require( 'toasted-notifier' )
+const process = require( 'process' )
+const path = require( 'path' )
+const moment = require( 'moment' )
+const Storage = require( './app/Storage.js' )
/*
Declare > Prompt
@@ -12,32 +14,34 @@ const Store = require('./store.js');
@docs : https://araxeus.github.io/custom-electron-prompt/
*/
-const prompt = require('custom-electron-prompt');
+const prompt = require( 'custom-electron-prompt' )
/*
Debug > Print args
*/
-console.log(process.argv);
+console.log( 'env' )
+console.log( process.env.ENV )
+console.log( process.argv )
/*
Declare > Package
*/
-const packageJson = require('./package.json');
-const appVer = packageJson.version;
-const appName = packageJson.name;
-const appAuthor = packageJson.author;
-const appElectron = process.versions.electron;
-const appRepo = packageJson.repository;
-const appIcon = app.getAppPath() + '/assets/icons/ntfy.png';
+const pkgJson = require( './package.json' )
+const appVer = pkgJson.version
+const appName = pkgJson.name
+const appAuthor = pkgJson.author
+const appElectron = process.versions.electron
+const appRepo = pkgJson.repository
+const appIcon = app.getAppPath() + '/assets/icons/ntfy.png'
/*
Declare > Window
*/
-let winMain, winAbout, timerPollrate, tray;
+let winMain, winAbout, timerPollrate, tray
/*
Declare > CLI State
@@ -48,19 +52,19 @@ let winMain, winAbout, timerPollrate, tray;
bQuitOnClose --quit when pressing top-right close button, app exits instead of going to tray
*/
-let bDevTools = 0;
-let bHotkeysEnabled = 0;
-let bQuitOnClose = 0;
-let bStartHidden = 0;
-let bWinHidden = 0;
+let bDevTools = 0
+let bHotkeysEnabled = 0
+let bQuitOnClose = 0
+const bStartHidden = 0
+let bWinHidden = 0
/*
Declare > Status
*/
-let statusHasError = false;
-let statusBadURL = false;
-let statusMessage;
+let statusHasError = false
+let statusBadURL = false
+let statusMessage
/*
Declare > Fallback
@@ -68,9 +72,9 @@ let statusMessage;
fallback values in case a user does something unforseen to cause an index error
*/
-const _Instance = 'https://ntfy.sh/app';
-const _Datetime = 'YYYY-MM-DD hh:mm a';
-const _Pollrate = 5;
+const _Instance = 'https://ntfy.sh/app'
+const _Datetime = 'YYYY-MM-DD hh:mm a'
+const _Pollrate = 5
/*
Declare > Store Values
@@ -79,7 +83,7 @@ const _Pollrate = 5;
storage: AppData\Roaming\ntfy-desktop
*/
-const store = new Store({
+const store = new Storage( {
configName: 'prefs',
defaults: {
instanceURL: _Instance,
@@ -92,25 +96,31 @@ const store = new Store({
bPersistentNoti: 0,
datetime: _Datetime
}
-});
+} )
/*
Validate instance url
*/
-function validateUrl(uri, tries, delay) {
- return new Promise((success, reject) => {
- (function rec(i) {
- fetch(uri, {mode: 'no-cors'}).then((r) => {
- success(r); // success: resolve promise
- }).catch( err => {
- if (tries === 0) // num of tries reached
- return reject(err);
-
- setTimeout(() => rec(--tries), delay ) // retry
- }); // retries exceeded
- })(tries);
- });
+function validateUrl( uri, tries, delay )
+{
+ return new Promise( ( success, reject ) =>
+ {
+ ( function rec( _i )
+ {
+ fetch( uri, { mode: 'no-cors' } ).then( ( r ) =>
+ {
+ success( r ) // success: resolve promise
+ }
+ ).catch( ( err ) =>
+ {
+ if ( tries === 0 ) // num of tries reached
+ return reject( err )
+
+ setTimeout( () => rec( --tries ), delay ) // retry
+ } ) // retries exceeded
+ } )( tries )
+ } )
}
/*
@@ -122,15 +132,17 @@ function validateUrl(uri, tries, delay) {
API Token can be specified in app.
*/
-async function GetMessageData(uri) {
- const cfgApiToken = store.get('apiToken');
- let req = await fetch(uri, {
- method: 'GET',
- headers: {
- 'Accept': 'application/json',
- Authorization: `Bearer ${cfgApiToken}`
- }
- });
+async function GetMessageData( uri )
+{
+ const cfgApiToken = store.get( 'apiToken' )
+ const req = await fetch( uri,
+ {
+ method: 'GET',
+ headers: {
+ Accept: 'application/json',
+ Authorization: `Bearer ${ cfgApiToken }`
+ }
+ } )
/*
ntfy has the option to output message results as json, however the structure of that json
@@ -140,22 +152,24 @@ async function GetMessageData(uri) {
array.
*/
- const json = await req.text();
- let jsonArr = [];
- const entries = json.split('\n');
- for (let i = 0; i < entries.length; i++) {
- jsonArr.push(entries[i]);
+ const json = await req.text()
+ const jsonArr = []
+ const entries = json.split( '\n' )
+ for ( let i = 0; i < entries.length; i++ )
+ {
+ jsonArr.push( entries[ i ] )
}
/*
Filter out empty entry in array which was caused by the last newline
*/
- const jsonResult = jsonArr.filter(function (el) {
- return el != null && el != '';
- });
+ const jsonResult = jsonArr.filter( function ( el )
+ {
+ return el != null && el != ''
+ } )
- return jsonResult;
+ return jsonResult
}
/*
@@ -165,114 +179,120 @@ async function GetMessageData(uri) {
@ref : https://docs.ntfy.sh/subscribe/api/#poll-for-messages
*/
-const msgHistory = [];
-async function GetMessages() {
+const msgHistory = []
+async function GetMessages()
+{
- const cfgPollrate = store.get('pollrate') || _Pollrate;
- const cfgTopics = store.get('topics');
- const cfgInstanceURL = store.get('instanceURL');
+ const cfgPollrate = store.get( 'pollrate' ) || _Pollrate
+ const cfgTopics = store.get( 'topics' )
+ const cfgInstanceURL = store.get( 'instanceURL' )
- if (cfgInstanceURL === '' || cfgInstanceURL === null) {
- console.log(`URL Missing, skipping GetMessages(): ${uri}`);
- return;
+ if ( cfgInstanceURL === '' || cfgInstanceURL === null )
+ {
+ console.log( `URL Missing, skipping GetMessages(): ${ uri }` )
+ return
}
- let uri = `${cfgInstanceURL}/${cfgTopics}/json?since=${cfgPollrate}s&poll=1`;
- console.log(`URL: ${uri}`);
+ let uri = `${ cfgInstanceURL }/${ cfgTopics }/json?since=${ cfgPollrate }s&poll=1`
+ console.log( `URL: ${ uri }` )
/*
For the official ntfy.sh API, url must be changed internally
https://ntfy.sh/app/ -> https://ntfy.sh/
*/
- if (uri.includes('ntfy.sh/app')) {
- uri = uri.replace("ntfy.sh/app", 'ntfy.sh');
+ if ( uri.includes( 'ntfy.sh/app' ) )
+ {
+ uri = uri.replace( 'ntfy.sh/app', 'ntfy.sh' )
}
/*
Bad URL detected, skip polling
*/
- if ( statusBadURL == true ) {
- console.error(`Invalid instance URL specified, skipping polling`);
- return;
+ if ( statusBadURL == true )
+ {
+ console.error( `Invalid instance URL specified, skipping polling` )
+ return
}
- const json = await GetMessageData(uri);
+ const json = await GetMessageData( uri )
- console.log(`CHECKING FOR NEW MESSAGES`);
- console.log(`---------------------------------------------------------`);
- console.log(`InstanceURL ........... ${cfgInstanceURL}`);
- console.log(`Query ................. ${uri}`);
- console.log(`Topics ................ ${cfgTopics}`);
+ console.log( `CHECKING FOR NEW MESSAGES` )
+ console.log( `---------------------------------------------------------` )
+ console.log( `InstanceURL ........... ${ cfgInstanceURL }` )
+ console.log( `Query ................. ${ uri }` )
+ console.log( `Topics ................ ${ cfgTopics }` )
/*
Loop ntfy api results.
only items with event = 'message' will be allowed through to display in a notification.
*/
- console.log(`---------------------------------------------------------`);
- console.log(`History ............... ${msgHistory}`);
- console.log(`Messages .............. ${JSON.stringify(json)}`);
- console.log(`---------------------------------------------------------\n`);
+ console.log( `---------------------------------------------------------` )
+ console.log( `History ............... ${ msgHistory }` )
+ console.log( `Messages .............. ${ JSON.stringify( json ) }` )
+ console.log( `---------------------------------------------------------\n` )
- for (let i = 0; i < json.length; i++) {
- const object = JSON.parse(json[i]);
- const id = object.id;
- const type = object.event;
- const time = object.time;
- const expires = object.expires;
- const message = object.message;
- const topic = object.topic;
+ for ( let i = 0; i < json.length; i++ )
+ {
+ const object = JSON.parse( json[ i ] )
+ const id = object.id
+ const type = object.event
+ const time = object.time
+ const expires = object.expires
+ const message = object.message
+ const topic = object.topic
- const cfgPersistent = store.get('bPersistentNoti') == 0 ? false : true;
- const cfgInstanceURL = store.get('instanceURL');
+ const cfgPersistent = store.get( 'bPersistentNoti' ) == 0 ? false : true
+ const cfgInstanceURL = store.get( 'instanceURL' )
- if (type != 'message')
- continue;
+ if ( type != 'message' )
+ continue
/*
convert unix timestamp into human readable
*/
- const dateHuman = moment.unix(time).format(store.get('datetime' || _Datetime));
+ const dateHuman = moment.unix( time ).format( store.get( 'datetime' || _Datetime ) )
/*
debugging to console to show the status of messages
*/
- const msgStatus = msgHistory.includes(id) === true ? 'already sent, skipping' : 'pending send';
- console.log(`Messages .............. ${type}:${id} ${msgStatus}`);
+ const msgStatus = msgHistory.includes( id ) === true ? 'already sent, skipping' : 'pending send'
+ console.log( `Messages .............. ${ type }:${ id } ${ msgStatus }` )
/*
@ref : https://github.com/Aetherinox/toasted-notifier
*/
- if (!msgHistory.includes(id)) {
- toasted.notify({
- title: `${topic} - ${dateHuman}`,
- subtitle: `${dateHuman}`,
- message: `${message}`,
+ if ( !msgHistory.includes( id ) )
+ {
+ toasted.notify( {
+ title: `${ topic } - ${ dateHuman }`,
+ subtitle: `${ dateHuman }`,
+ message: `${ message }`,
sound: 'Pop',
open: cfgInstanceURL,
persistent: cfgPersistent,
sticky: cfgPersistent
- });
+ } )
- msgHistory.push(id);
+ msgHistory.push( id )
- console.log(` Topic .............. ${type}:${id} ${topic}`);
- console.log(` Date ............... ${type}:${id} ${dateHuman}`);
- console.log(` InstanceURL ........ ${type}:${id} ${cfgInstanceURL}`);
- console.log(` Persistent ......... ${type}:${id} ${cfgPersistent}`);
+ console.log( ` Topic .............. ${ type }:${ id } ${ topic }` )
+ console.log( ` Date ............... ${ type }:${ id } ${ dateHuman }` )
+ console.log( ` InstanceURL ........ ${ type }:${ id } ${ cfgInstanceURL }` )
+ console.log( ` Persistent ......... ${ type }:${ id } ${ cfgPersistent }` )
}
- console.log(`Messages .............. ${type}:${id} sent`);
+ console.log( `Messages .............. ${ type }:${ id } sent` )
}
- console.log(`\n\n`);
+ console.log( `\n\n` )
- return json;
+ return json
}
/*
@@ -284,255 +304,276 @@ async function GetMessages() {
*/
const menu_Main = [
-{
- label: '&App',
- id: 'app',
- submenu: [
- {
- label: 'Quit',
- id: 'quit',
- accelerator: (bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) ? 'CTRL+Q' : '',
- click: function () {
- app.isQuiting = true;
- app.quit();
+ {
+ label: '&App',
+ id: 'app',
+ submenu: [
+ {
+ label: 'Quit',
+ id: 'quit',
+ accelerator: ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) ? 'CTRL+Q' : '',
+ click: function ()
+ {
+ app.isQuiting = true
+ app.quit()
+ }
}
- }
- ]
-},
-{
- label: '&Configure',
- id: 'configure',
- submenu: [
- {
- label: 'General',
- id: 'general',
- accelerator: (bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) ? 'CTRL+G' : '',
- click: function () {
- prompt(
- {
- title: 'General Settings',
- label: 'General Settings
Change the overall functionality of the app.
',
- useHtmlLabel: true,
- alwaysOnTop: true,
- type: 'multiInput',
- resizable: false,
- customStylesheet: path.join(__dirname, `pages`, `css`, `prompt.css`),
- height: 480,
- icon: appIcon,
- multiInputOptions:
+ ]
+ },
+ {
+ label: '&Configure',
+ id: 'configure',
+ submenu: [
+ {
+ label: 'General',
+ id: 'general',
+ accelerator: ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) ? 'CTRL+G' : '',
+ click: function ()
+ {
+ prompt(
+ {
+ title: 'General Settings',
+ label: 'General SettingsChange the overall functionality of the app.
',
+ useHtmlLabel: true,
+ alwaysOnTop: true,
+ type: 'multiInput',
+ resizable: false,
+ customStylesheet: path.join( __dirname, `pages`, `css`, `prompt.css` ),
+ height: 480,
+ icon: appIcon,
+ multiInputOptions:
[
{
label: 'Developer tools in app menu',
selectOptions: { 0: 'Disabled', 1: 'Enabled' },
- value: store.get('bDevTools'),
+ value: store.get( 'bDevTools' )
},
{
label: 'Allow usage of hotkeys to navigate',
selectOptions: { 0: 'Disabled', 1: 'Enabled' },
- value: store.get('bHotkeys'),
+ value: store.get( 'bHotkeys' )
},
{
label: 'Quit app instead of send-to-tray for close button',
selectOptions: { 0: 'Disabled', 1: 'Enabled' },
- value: store.get('bQuitOnClose'),
+ value: store.get( 'bQuitOnClose' )
},
{
label: 'Start app minimized in tray',
selectOptions: { 0: 'Disabled', 1: 'Enabled' },
- value: store.get('bStartHidden'),
+ value: store.get( 'bStartHidden' )
}
- ],
- },
- winMain
- )
- .then((response) => {
- if (response !== null) {
- // do not update dev tools if value hasn't changed
- if ( store.get('bDevTools') !== response[0])
+ ]
+ },
+ winMain
+ )
+ .then( ( response ) =>
{
- store.set('bDevTools', response[0]);
- activeDevTools();
- }
+ if ( response !== null )
+ {
+ // do not update dev tools if value hasn't changed
+ if ( store.get( 'bDevTools' ) !== response[ 0 ] )
+ {
+ store.set( 'bDevTools', response[ 0 ] )
+ activeDevTools()
+ }
- store.set('bHotkeys', response[1]);
- store.set('bQuitOnClose', response[2]);
- store.set('bStartHidden', response[3]);
- }
- })
- .catch((response) => {
- console.error
- })
+ store.set( 'bHotkeys', response[ 1 ] )
+ store.set( 'bQuitOnClose', response[ 2 ] )
+ store.set( 'bStartHidden', response[ 3 ] )
+ }
+ } )
+ .catch( ( _response ) =>
+ {
+ console.error
+ } )
/*
setTimeout(function (){
BrowserWindow.getFocusedWindow().webContents.openDevTools();
}, 3000);
*/
- }
- },
- {
- label: 'URL',
- accelerator: (bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) ? 'CTRL+U' : '',
- click: function () {
- prompt(
- {
- title: 'Set Server Instance',
- label: 'Server URLThis can either be the URL to the official ntfy.sh server, or your own self-hosted domain / ip.
Remove everything to set back to official ntfy.sh server.
',
- useHtmlLabel: true,
- value: store.get('instanceURL') || _Instance,
- alwaysOnTop: true,
- type: 'input',
- customStylesheet: path.join(__dirname, `pages`, `css`, `prompt.css`),
- height: 290,
- icon: appIcon,
- inputAttrs: {
- type: 'url'
- }
- },
- winMain
- )
- .then((response) => {
- if (response !== null) {
- const newUrl = (response === "" ? _Instance : response);
- store.set('instanceURL', newUrl);
-
- /*
+ }
+ },
+ {
+ label: 'URL',
+ accelerator: ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) ? 'CTRL+U' : '',
+ click: function ()
+ {
+ prompt(
+ {
+ title: 'Set Server Instance',
+ label: 'Server URLThis can either be the URL to the official ntfy.sh server, or your own self-hosted domain / ip.
Remove everything to set back to official ntfy.sh server.
',
+ useHtmlLabel: true,
+ value: store.get( 'instanceURL' ) || _Instance,
+ alwaysOnTop: true,
+ type: 'input',
+ customStylesheet: path.join( __dirname, `pages`, `css`, `prompt.css` ),
+ height: 290,
+ icon: appIcon,
+ inputAttrs: {
+ type: 'url'
+ }
+ },
+ winMain
+ )
+ .then( ( response ) =>
+ {
+ if ( response !== null )
+ {
+ const newUrl = ( response === '' ? _Instance : response )
+ store.set( 'instanceURL', newUrl )
+
+ /*
Validate URL.
Invalid URLs should not perform polling.
load default _Instance url
*/
- validateUrl(store.get('instanceURL'), 3, 1000).then( item => {
- statusBadURL = false;
- console.log(`Successfully resolved `+ store.get('instanceURL'));
- winMain.loadURL(store.get('instanceURL'));
- }).catch( err => {
- statusBadURL = true;
- const msg = `Failed to resolve `+ store.get('instanceURL') + ` - defaulting to ${_Instance}`;
- statusMessage = `${msg}`;
- console.error(`${msg}`);
- store.set('instanceURL', _Instance);
- winMain.loadURL(_Instance);
- });
- }
- })
- .catch((response) => {
- console.error
- })
+ validateUrl( store.get( 'instanceURL' ), 3, 1000 ).then( ( _item ) =>
+ {
+ statusBadURL = false
+ console.log( `Successfully resolved ` + store.get( 'instanceURL' ) )
+ winMain.loadURL( store.get( 'instanceURL' ) )
+ } ).catch( ( _err ) =>
+ {
+ statusBadURL = true
+ const msg = `Failed to resolve ` + store.get( 'instanceURL' ) + ` - defaulting to ${ _Instance }`
+ statusMessage = `${ msg }`
+ console.error( `${ msg }` )
+ store.set( 'instanceURL', _Instance )
+ winMain.loadURL( _Instance )
+ } )
+ }
+ } )
+ .catch( ( _response ) =>
+ {
+ console.error
+ } )
/*
setTimeout(function (){
BrowserWindow.getFocusedWindow().webContents.openDevTools();
}, 3000);
*/
- }
- },
- {
- label: 'API Token',
- accelerator: (bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) ? 'CTRL+T' : '',
- click: function () {
- prompt(
- {
- title: 'Set API Token',
- label: 'API TokenGenerate an API token within ntfy.sh or your self-hosted instance and provide it below to receive desktop push notifications.
',
- useHtmlLabel: true,
- value: store.get('apiToken'),
- alwaysOnTop: true,
- type: 'input',
- customStylesheet: path.join(__dirname, `pages`, `css`, `prompt.css`),
- height: 265,
- icon: appIcon,
- inputAttrs: {
- type: 'text'
- }
- },
- winMain
- )
- .then((response) => {
- if (response !== null) {
- store.set('apiToken', response);
- }
- })
- .catch((response) => {
- console.error
- })
- }
- },
- {
- label: 'Topics',
- accelerator: (bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) ? 'CTRL+SHIFT+T' : '',
- click: function () {
- prompt(
- {
- title: 'Set Subscribed Topics',
- label: 'Subscribed TopicsSpecify a list of topics you would like to receive push notifications for, separated by commas.
Ex: Meetings,Personal,Urgent
',
- useHtmlLabel: true,
- value: store.get('topics'),
- alwaysOnTop: true,
- type: 'input',
- customStylesheet: path.join(__dirname, `pages`, `css`, `prompt.css`),
- height: 290,
- icon: appIcon,
- inputAttrs: {
- type: 'text'
- }
- },
- winMain
- )
- .then((response) => {
- if (response !== null) {
- // do not update topics unless values differ from original, since we need to reload the page
- if ( store.get('topics') !== response)
+ }
+ },
+ {
+ label: 'API Token',
+ accelerator: ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) ? 'CTRL+T' : '',
+ click: function ()
+ {
+ prompt(
{
- store.set('topics', response);
-
- if (typeof (store.get('instanceURL')) !== 'string' || store.get('instanceURL') === '' || store.get('instanceURL') === null ) {
- store.set('instanceURL', _Instance);
+ title: 'Set API Token',
+ label: 'API TokenGenerate an API token within ntfy.sh or your self-hosted instance and provide it below to receive desktop push notifications.
',
+ useHtmlLabel: true,
+ value: store.get( 'apiToken' ),
+ alwaysOnTop: true,
+ type: 'input',
+ customStylesheet: path.join( __dirname, `pages`, `css`, `prompt.css` ),
+ height: 265,
+ icon: appIcon,
+ inputAttrs: {
+ type: 'text'
+ }
+ },
+ winMain
+ )
+ .then( ( response ) =>
+ {
+ if ( response !== null )
+ {
+ store.set( 'apiToken', response )
+ }
+ } )
+ .catch( ( _response ) =>
+ {
+ console.error
+ } )
+ }
+ },
+ {
+ label: 'Topics',
+ accelerator: ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) ? 'CTRL+SHIFT+T' : '',
+ click: function ()
+ {
+ prompt(
+ {
+ title: 'Set Subscribed Topics',
+ label: 'Subscribed TopicsSpecify a list of topics you would like to receive push notifications for, separated by commas.
Ex: Meetings,Personal,Urgent
',
+ useHtmlLabel: true,
+ value: store.get( 'topics' ),
+ alwaysOnTop: true,
+ type: 'input',
+ customStylesheet: path.join( __dirname, `pages`, `css`, `prompt.css` ),
+ height: 290,
+ icon: appIcon,
+ inputAttrs: {
+ type: 'text'
}
+ },
+ winMain
+ )
+ .then( ( response ) =>
+ {
+ if ( response !== null )
+ {
+ // do not update topics unless values differ from original, since we need to reload the page
+ if ( store.get( 'topics' ) !== response )
+ {
+ store.set( 'topics', response )
- winMain.loadURL(store.get('instanceURL'));
- }
- }
- })
- .catch((response) => {
- console.error
- })
- }
- },
- {
- label: 'Notifications',
- accelerator: (bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) ? 'CTRL+N' : '',
- click: function () {
- prompt(
- {
- title: 'Notifications',
- label: 'Notification SettingsDetermines how notifications will behave
',
- useHtmlLabel: true,
- alwaysOnTop: true,
- type: 'multiInput',
- resizable: false,
- customStylesheet: path.join(__dirname, `pages`, `css`, `prompt.css`),
- height: 400,
- icon: appIcon,
- multiInputOptions:
+ if ( typeof ( store.get( 'instanceURL' ) ) !== 'string' || store.get( 'instanceURL' ) === '' || store.get( 'instanceURL' ) === null )
+ {
+ store.set( 'instanceURL', _Instance )
+ }
+
+ winMain.loadURL( store.get( 'instanceURL' ) )
+ }
+ }
+ } )
+ .catch( ( _response ) =>
+ {
+ console.error
+ } )
+ }
+ },
+ {
+ label: 'Notifications',
+ accelerator: ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) ? 'CTRL+N' : '',
+ click: function ()
+ {
+ prompt(
+ {
+ title: 'Notifications',
+ label: 'Notification SettingsDetermines how notifications will behave
',
+ useHtmlLabel: true,
+ alwaysOnTop: true,
+ type: 'multiInput',
+ resizable: false,
+ customStylesheet: path.join( __dirname, `pages`, `css`, `prompt.css` ),
+ height: 400,
+ icon: appIcon,
+ multiInputOptions:
[
{
label: 'Stay on screen until dismissed',
selectOptions: { 0: 'Disabled', 1: 'Enabled' },
- value: store.get('bPersistentNoti'),
+ value: store.get( 'bPersistentNoti' )
},
{
label: 'Datetime format for notification title',
- value: store.get('datetime') || _Datetime,
+ value: store.get( 'datetime' ) || _Datetime,
inputAttrs:
{
- placeholder: `${_Datetime}`,
+ placeholder: `${ _Datetime }`,
required: true
}
},
{
label: 'Polling rate / fetch messages (seconds)',
- value: store.get('pollrate') || _Pollrate,
+ value: store.get( 'pollrate' ) || _Pollrate,
inputAttrs: {
type: 'number',
required: true,
@@ -541,120 +582,129 @@ const menu_Main = [
}
}
]
- },
- winMain
- )
- .then((response) => {
- if (response !== null) {
- store.set('bPersistentNoti', response[0])
- store.set('datetime', response[1])
- store.set('pollrate', response[2])
-
- const cfgPollrate = (store.get('pollrate') || _Pollrate);
- const fetchInterval = (cfgPollrate * 1000) + 600;
- clearInterval(timerPollrate);
- timerPollrate = setInterval(GetMessages, fetchInterval);
- }
- })
- .catch((response) => {
- console.error
- })
+ },
+ winMain
+ )
+ .then( ( response ) =>
+ {
+ if ( response !== null )
+ {
+ store.set( 'bPersistentNoti', response[ 0 ] )
+ store.set( 'datetime', response[ 1 ] )
+ store.set( 'pollrate', response[ 2 ] )
+
+ const cfgPollrate = ( store.get( 'pollrate' ) || _Pollrate )
+ const fetchInterval = ( cfgPollrate * 1000 ) + 600
+ clearInterval( timerPollrate )
+ timerPollrate = setInterval( GetMessages, fetchInterval )
+ }
+ } )
+ .catch( ( _response ) =>
+ {
+ console.error
+ } )
- /*
+ /*
setTimeout(function (){
BrowserWindow.getFocusedWindow().webContents.openDevTools();
}, 3000);
*/
+ }
}
- }
- ]
-},
-{
- label: '&Help',
- id: 'help',
- submenu: [
- {
- id: 'about',
- label: 'About',
- click() {
- const aboutTitle = `About`;
- winAbout = new BrowserWindow({
- width: 480,
- height: 440,
- title: `${aboutTitle}`,
- icon: appIcon,
- parent: winMain,
- center: true,
- resizable: false,
- fullscreenable: false,
- minimizable: false,
- maximizable: false,
- modal: true,
- backgroundColor: '#212121',
- webPreferences: {
- nodeIntegration: true,
- contextIsolation: false,
- enableRemoteModule: true
- }
- });
-
- winAbout.loadFile(path.join(__dirname, `pages`, `about.html`)).then(() => {
- winAbout.webContents
- .executeJavaScript(
- `
- setTitle('${aboutTitle}');
- setAppInfo('${appRepo}', '${appName}', '${appVer}', '${appAuthor}', '${appElectron}');`,
- true
- )
- .then((result) => {})
- .catch(console.error);
- });
-
- winAbout.webContents.on('new-window', function (e, url) {
- e.preventDefault();
- require('electron').shell.openExternal(url);
- });
+ ]
+ },
+ {
+ label: '&Help',
+ id: 'help',
+ submenu: [
+ {
+ id: 'about',
+ label: 'About',
+ click()
+ {
+ const aboutTitle = `About`
+ winAbout = new BrowserWindow( {
+ width: 480,
+ height: 440,
+ title: `${ aboutTitle }`,
+ icon: appIcon,
+ parent: winMain,
+ center: true,
+ resizable: false,
+ fullscreenable: false,
+ minimizable: false,
+ maximizable: false,
+ modal: true,
+ backgroundColor: '#212121',
+ webPreferences: {
+ nodeIntegration: true,
+ contextIsolation: false,
+ enableRemoteModule: true
+ }
+ } )
- // Remove menubar from about window
- winAbout.setMenu(null);
- }
- },
- {
- label: 'View New Releases',
- click() {
- electronShell.openExternal(`${packageJson.homepage}`);
+ winAbout.loadFile( path.join( __dirname, `pages`, `about.html` ) ).then( () =>
+ {
+ winAbout.webContents
+ .executeJavaScript(
+ `
+ setTitle('${ aboutTitle }');
+ setAppInfo('${ appRepo }', '${ appName }', '${ appVer }', '${ appAuthor }', '${ appElectron }');`,
+ true
+ )
+ .then( ( _result ) => {} )
+ .catch( console.error )
+ } )
+
+ winAbout.webContents.on( 'new-window', function ( e, url )
+ {
+ e.preventDefault()
+ require( 'electron' ).shell.openExternal( url )
+ } )
+
+ // Remove menubar from about window
+ winAbout.setMenu( null )
+ }
+ },
+ {
+ label: 'View New Releases',
+ click()
+ {
+ electronShell.openExternal( `${ pkgJson.homepage }` )
+ }
}
- }
- ]
-}];
+ ]
+ }]
/*
Tray > Context Menu
*/
-const contextMenu = Menu.buildFromTemplate([
+const contextMenu = Menu.buildFromTemplate( [
{
label: 'Show App',
- click: function () {
- winMain.show();
+ click: function ()
+ {
+ winMain.show()
}
},
{
label: 'Quit',
- click: function () {
- app.isQuiting = true;
- app.quit();
+ click: function ()
+ {
+ app.isQuiting = true
+ app.quit()
}
}
-]);
+] )
/*
Main Menu > Set
*/
-const header_menu = Menu.buildFromTemplate(menu_Main);
-Menu.setApplicationMenu(header_menu);
+const header_menu = Menu.buildFromTemplate( menu_Main )
+Menu.setApplicationMenu( header_menu )
/*
Main Menu > Developer Tools
@@ -665,24 +715,27 @@ Menu.setApplicationMenu(header_menu);
App | Configure | Help
*/
-function activeDevTools() {
- const header_menu = Menu.buildFromTemplate(menu_Main);
- Menu.setApplicationMenu(header_menu);
-
- if (bDevTools == 1 || store.get('bDevTools') == 1) {
- let menuItem = header_menu.getMenuItemById('app')
+function activeDevTools()
+{
+ const header_menu = Menu.buildFromTemplate( menu_Main )
+ Menu.setApplicationMenu( header_menu )
- menuItem.submenu.insert(0, new MenuItem(
- {
- label: 'Toggle Dev Tools',
- accelerator: process.platform === 'darwin' ? 'ALT+CMD+I' : 'CTRL+SHIFT+I',
- click: () => {
- winMain.webContents.toggleDevTools();
- }
- },
- {
- type: 'separator'
- }))
+ if ( bDevTools == 1 || store.get( 'bDevTools' ) == 1 )
+ {
+ const menuItem = header_menu.getMenuItemById( 'app' )
+
+ menuItem.submenu.insert( 0, new MenuItem(
+ {
+ label: 'Toggle Dev Tools',
+ accelerator: process.platform === 'darwin' ? 'ALT+CMD+I' : 'CTRL+SHIFT+I',
+ click: () =>
+ {
+ winMain.webContents.toggleDevTools()
+ }
+ },
+ {
+ type: 'separator'
+ } ) )
}
}
@@ -690,19 +743,20 @@ function activeDevTools() {
App > Ready
*/
-function ready() {
+function ready()
+{
/*
New Window
*/
- winMain = new BrowserWindow({
- title: `${appName}`,
+ winMain = new BrowserWindow( {
+ title: `${ appName }`,
width: 1280,
height: 720,
icon: appIcon,
backgroundColor: '#212121'
- });
+ } )
/*
Load default url to main window
@@ -711,11 +765,12 @@ function ready() {
otherwise app will return invalid index and stop loading.
*/
- if (typeof (store.get('instanceURL')) !== 'string' || store.get('instanceURL') === '' || store.get('instanceURL') === null ) {
- store.set('instanceURL', _Instance);
+ if ( typeof ( store.get( 'instanceURL' ) ) !== 'string' || store.get( 'instanceURL' ) === '' || store.get( 'instanceURL' ) === null )
+ {
+ store.set( 'instanceURL', _Instance )
- statusHasError = true;
- statusMessage = `Invalid instance URL specified; defaulting to ${_Instance}`;
+ statusHasError = true
+ statusMessage = `Invalid instance URL specified; defaulting to ${ _Instance }`
}
/*
@@ -724,26 +779,29 @@ function ready() {
load default _Instance url
*/
- validateUrl(store.get('instanceURL'), 3, 1000).then( item => {
- statusBadURL = false;
- console.log(`Successfully resolved `+ store.get('instanceURL'));
- winMain.loadURL(store.get('instanceURL'));
- }).catch( err => {
- statusBadURL = true;
- const msg = `Failed to resolve `+ store.get('instanceURL') + ` - defaulting to ${_Instance}`;
- statusMessage = `${msg}`;
- console.error(`${msg}`);
- store.set('instanceURL', _Instance);
- winMain.loadURL(_Instance);
- });
+ validateUrl( store.get( 'instanceURL' ), 3, 1000 ).then( ( _item ) =>
+ {
+ statusBadURL = false
+ console.log( `Successfully resolved ` + store.get( 'instanceURL' ) )
+ winMain.loadURL( store.get( 'instanceURL' ) )
+ } ).catch( ( _err ) =>
+ {
+ statusBadURL = true
+ const msg = `Failed to resolve ` + store.get( 'instanceURL' ) + ` - defaulting to ${ _Instance }`
+ statusMessage = `${ msg }`
+ console.error( `${ msg }` )
+ store.set( 'instanceURL', _Instance )
+ winMain.loadURL( _Instance )
+ } )
/*
Event > Page Title Update
*/
- winMain.on('page-title-updated', (e) => {
- e.preventDefault();
- });
+ winMain.on( 'page-title-updated', ( e ) =>
+ {
+ e.preventDefault()
+ } )
/*
Event > Close
@@ -752,27 +810,33 @@ function ready() {
otherwise; app will hide
*/
- winMain.on('close', function (e) {
- if (!app.isQuiting) {
- e.preventDefault();
- if (bQuitOnClose == 1 || store.get('bQuitOnClose') == 1) {
- app.isQuiting = true;
- app.quit();
- } else {
- winMain.hide();
+ winMain.on( 'close', function ( e )
+ {
+ if ( !app.isQuiting )
+ {
+ e.preventDefault()
+ if ( bQuitOnClose == 1 || store.get( 'bQuitOnClose' ) == 1 )
+ {
+ app.isQuiting = true
+ app.quit()
+ }
+ else
+ {
+ winMain.hide()
}
}
- return false;
- });
+ return false
+ } )
/*
Event > Closed
*/
- winMain.on('closed', () => {
- winMain = null;
- });
+ winMain.on( 'closed', () =>
+ {
+ winMain = null
+ } )
/*
Event > New Window
@@ -780,21 +844,24 @@ function ready() {
buttons leading to external websites should open in user browser
*/
- winMain.webContents.on('new-window', (e, url) => {
- e.preventDefault();
- require('electron').shell.openExternal(url);
- });
+ winMain.webContents.on( 'new-window', ( e, url ) =>
+ {
+ e.preventDefault()
+ require( 'electron' ).shell.openExternal( url )
+ } )
/*
Display footer div on website if something has gone wrong.
user shouldn't see this unless its something serious
*/
- winMain.webContents.on('did-finish-load', (e, url)=> {
- if ((statusHasError === true || statusBadURL == true) && statusMessage !== '') {
+ winMain.webContents.on( 'did-finish-load', ( _e, _url ) =>
+ {
+ if ( ( statusHasError === true || statusBadURL == true ) && statusMessage !== '' )
+ {
winMain.webContents
.executeJavaScript(
- `
+ `
const div = document.createElement("div");
div.style.position = "sticky";
div.style.height = "34px";
@@ -811,79 +878,89 @@ function ready() {
const span = document.createElement("span");
span.setAttribute("class","ntfy-notify error");
- span.textContent = '${statusMessage}';
+ span.textContent = '${ statusMessage }';
div.appendChild(span);
document.body.appendChild(div);
- `)
- }
+ ` )
}
- );
+ }
+ )
/*
Event > Input
*/
- winMain.webContents.on('before-input-event', (e, input) => {
+ winMain.webContents.on( 'before-input-event', ( _e, input ) =>
+ {
/*
Input > Refresh Page (CTRL + r)
*/
- if ((bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) && input.type === 'keyDown' && input.control && input.key === 'r') {
- winMain.webContents.reload();
+ if ( ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) && input.type === 'keyDown' && input.control && input.key === 'r' )
+ {
+ winMain.webContents.reload()
}
/*
Input > Zoom In (CTRL + =)
*/
- if ((bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) && input.type === 'keyDown' && input.control && input.key === '=') {
- winMain.webContents.zoomFactor += 0.1;
+ if ( ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) && input.type === 'keyDown' && input.control && input.key === '=' )
+ {
+ winMain.webContents.zoomFactor += 0.1
}
/*
Input > Zoom Out (CTRL + -)
*/
- if ((bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) && input.type === 'keyDown' && input.control && input.key === '-') {
- winMain.webContents.zoomFactor -= 0.1;
+ if ( ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) && input.type === 'keyDown' && input.control && input.key === '-' )
+ {
+ winMain.webContents.zoomFactor -= 0.1
}
/*
Input > Zoom Reset (CTRL + 0)
*/
- if ((bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) && input.type === 'keyDown' && input.control && input.key === '0') {
- winMain.webContents.zoomFactor = 1;
+ if ( ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) && input.type === 'keyDown' && input.control && input.key === '0' )
+ {
+ winMain.webContents.zoomFactor = 1
}
/*
Input > Quit (CTRL + q)
*/
- if ((bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) && input.type === 'keyDown' && input.control && input.key === 'q') {
- app.isQuiting = true;
- app.quit();
+ if ( ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) && input.type === 'keyDown' && input.control && input.key === 'q' )
+ {
+ app.isQuiting = true
+ app.quit()
}
/*
Input > Minimize to tray (CTRL + m)
*/
- if ((bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) && input.type === 'keyDown' && input.control && input.key === 'm') {
- bWinHidden = 1;
- winMain.hide();
+ if ( ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) && input.type === 'keyDown' && input.control && input.key === 'm' )
+ {
+ bWinHidden = 1
+ winMain.hide()
}
/*
Input > Dev Tools (CTRL + SHIFT + I || F12)
*/
- if (((bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) && input.control && input.shift) || input.key === 'F12') {
- if (input.type === 'keyDown' && (input.key === 'I' || input.key === 'F12')) {
- winMain.webContents.toggleDevTools();
- winMain.webContents.on('devtools-opened', () => {
+ if ( ( ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) && input.control && input.shift ) || input.key === 'F12' )
+ {
+ if ( input.type === 'keyDown' && ( input.key === 'I' || input.key === 'F12' ) )
+ {
+ winMain.webContents.toggleDevTools()
+ winMain.webContents.on( 'devtools-opened', () =>
+ {
winMain.webContents.devToolsWebContents
.executeJavaScript(
`
@@ -909,13 +986,14 @@ function ready() {
})
`
)
- .then(() => {
- winMain.webContents.toggleDevTools();
- });
- });
+ .then( () =>
+ {
+ winMain.webContents.toggleDevTools()
+ } )
+ } )
}
}
- });
+ } )
/*
Tray
@@ -924,18 +1002,22 @@ function ready() {
Linux : left and right click have same functionality
*/
- tray = new Tray(appIcon);
- tray.setToolTip(`${appName}`);
- tray.setContextMenu(contextMenu);
- tray.on('click', function () {
- if (bWinHidden) {
- bWinHidden = 0;
- winMain.show();
- } else {
- bWinHidden = 1;
- winMain.hide();
+ tray = new Tray( appIcon )
+ tray.setToolTip( `${ appName }` )
+ tray.setContextMenu( contextMenu )
+ tray.on( 'click', function ()
+ {
+ if ( bWinHidden )
+ {
+ bWinHidden = 0
+ winMain.show()
+ }
+ else
+ {
+ bWinHidden = 1
+ winMain.hide()
}
- });
+ } )
/*
Loop args
@@ -945,16 +1027,24 @@ function ready() {
--quit : quit app when close button pressed
*/
- for (let i = 0; i < process.argv.length; i++) {
- if (process.argv[i] === '--hidden') {
- bWinHidden = 1;
- } else if (process.argv[i] === '--dev') {
- bDevTools = 1;
+ for ( let i = 0; i < process.argv.length; i++ )
+ {
+ if ( process.argv[ i ] === '--hidden' )
+ {
+ bWinHidden = 1
+ }
+ else if ( process.argv[ i ] === '--dev' )
+ {
+ bDevTools = 1
activeDevTools()
- } else if (process.argv[i] === '--quit') {
- bQuitOnClose = 1;
- } else if (process.argv[i] === '--hotkeys') {
- bHotkeysEnabled = 1;
+ }
+ else if ( process.argv[ i ] === '--quit' )
+ {
+ bQuitOnClose = 1
+ }
+ else if ( process.argv[ i ] === '--hotkeys' )
+ {
+ bHotkeysEnabled = 1
}
}
@@ -962,8 +1052,8 @@ function ready() {
Run timer every X seconds to check for new messages
*/
- const fetchInterval = ((store.get('pollrate') || _Pollrate) * 1000) + 600;
- timerPollrate = setInterval(GetMessages, fetchInterval);
+ const fetchInterval = ( ( store.get( 'pollrate' ) || _Pollrate ) * 1000 ) + 600
+ timerPollrate = setInterval( GetMessages, fetchInterval )
/*
Check stored setting for developer tools and set state when
@@ -976,12 +1066,12 @@ function ready() {
Start minimized in tray
*/
- if( store.get('bStartHidden') == 1 || bWinHidden == 1)
- winMain.hide();
+ if ( store.get( 'bStartHidden' ) == 1 || bStartHidden == 1 || bWinHidden == 1 )
+ winMain.hide()
}
/*
App > Ready
*/
-app.on('ready', ready);
+app.on( 'ready', ready )
diff --git a/package-lock.json b/package-lock.json
index 0320347..4f3f7f2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -24,6 +24,8 @@
"devDependencies": {
"@aetherinox/noxenv": "^1.0.0",
"@playwright/test": "^1.45.3",
+ "@stylistic/eslint-plugin-js": "^2.3.0",
+ "@stylistic/eslint-plugin-plus": "^2.3.0",
"@testing-library/jest-dom": "^6.4.8",
"@types/node": "^20.14.11",
"@types/testing-library__jest-dom": "^5.14.9",
@@ -945,6 +947,70 @@
"url": "https://github.com/sindresorhus/is?sponsor=1"
}
},
+ "node_modules/@stylistic/eslint-plugin-js": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-2.3.0.tgz",
+ "integrity": "sha512-lQwoiYb0Fs6Yc5QS3uT8+T9CPKK2Eoxc3H8EnYJgM26v/DgtW+1lvy2WNgyBflU+ThShZaHm3a6CdD9QeKx23w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/eslint": "^8.56.10",
+ "acorn": "^8.11.3",
+ "eslint-visitor-keys": "^4.0.0",
+ "espree": "^10.0.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=8.40.0"
+ }
+ },
+ "node_modules/@stylistic/eslint-plugin-js/node_modules/eslint-visitor-keys": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
+ "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@stylistic/eslint-plugin-js/node_modules/espree": {
+ "version": "10.1.0",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.1.0.tgz",
+ "integrity": "sha512-M1M6CpiE6ffoigIOWYO9UDP8TMUw9kqb21tf+08IgDYjCsOvCuDt4jQcZmoYxx+w7zlKw9/N0KXfto+I8/FrXA==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^8.12.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^4.0.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@stylistic/eslint-plugin-plus": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-2.3.0.tgz",
+ "integrity": "sha512-xboPWGUU5yaPlR+WR57GwXEuY4PSlPqA0C3IdNA/+1o2MuBi95XgDJcZiJ9N+aXsqBXAPIpFFb+WQ7QEHo4f7g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/eslint": "^8.56.10",
+ "@typescript-eslint/utils": "^7.12.0"
+ },
+ "peerDependencies": {
+ "eslint": "*"
+ }
+ },
"node_modules/@szmarczak/http-timer": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz",
@@ -1012,6 +1078,24 @@
"@types/responselike": "^1.0.0"
}
},
+ "node_modules/@types/eslint": {
+ "version": "8.56.11",
+ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.11.tgz",
+ "integrity": "sha512-sVBpJMf7UPo/wGecYOpk2aQya2VUGeHhe38WG7/mN5FufNSubf5VT9Uh9Uyp8/eLJpu1/tuhJ/qTo4mhSB4V4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "*",
+ "@types/json-schema": "*"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
+ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/http-cache-semantics": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
@@ -1056,6 +1140,13 @@
"pretty-format": "^29.0.0"
}
},
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -1142,6 +1233,134 @@
"@types/node": "*"
}
},
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "7.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.17.0.tgz",
+ "integrity": "sha512-0P2jTTqyxWp9HiKLu/Vemr2Rg1Xb5B7uHItdVZ6iAenXmPo4SZ86yOPCJwMqpCyaMiEHTNqizHfsbmCFT1x9SA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "7.17.0",
+ "@typescript-eslint/visitor-keys": "7.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "7.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.17.0.tgz",
+ "integrity": "sha512-a29Ir0EbyKTKHnZWbNsrc/gqfIBqYPwj3F2M+jWE/9bqfEHg0AMtXzkbUkOG6QgEScxh2+Pz9OXe11jHDnHR7A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "7.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.17.0.tgz",
+ "integrity": "sha512-72I3TGq93t2GoSBWI093wmKo0n6/b7O4j9o8U+f65TVD0FS6bI2180X5eGEr8MA8PhKMvYe9myZJquUT2JkCZw==",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@typescript-eslint/types": "7.17.0",
+ "@typescript-eslint/visitor-keys": "7.17.0",
+ "debug": "^4.3.4",
+ "globby": "^11.1.0",
+ "is-glob": "^4.0.3",
+ "minimatch": "^9.0.4",
+ "semver": "^7.6.0",
+ "ts-api-utils": "^1.3.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@typescript-eslint/utils": {
+ "version": "7.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.17.0.tgz",
+ "integrity": "sha512-r+JFlm5NdB+JXc7aWWZ3fKSm1gn0pkswEwIYsrGPdsT2GjsRATAKXiNtp3vgAAO1xZhX8alIOEQnNMl3kbTgJw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.4.0",
+ "@typescript-eslint/scope-manager": "7.17.0",
+ "@typescript-eslint/types": "7.17.0",
+ "@typescript-eslint/typescript-estree": "7.17.0"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^8.56.0"
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "7.17.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.17.0.tgz",
+ "integrity": "sha512-RVGC9UhPOCsfCdI9pU++K4nD7to+jTcMIbXTSOcrLqUEW6gF2pU1UUbYJKc9cvcRSK1UDeMJ7pdMxf4bhMpV/A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "7.17.0",
+ "eslint-visitor-keys": "^3.4.3"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
"node_modules/@ungap/structured-clone": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
@@ -1279,6 +1498,16 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
+ "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/array.prototype.findlastindex": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
@@ -1864,6 +2093,19 @@
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
}
},
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
+ "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/doctrine": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@@ -2706,6 +2948,36 @@
"dev": true,
"license": "Apache-2.0"
},
+ "node_modules/fast-glob": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
+ "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.2",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.4"
+ },
+ "engines": {
+ "node": ">=8.6.0"
+ }
+ },
+ "node_modules/fast-glob/node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@@ -3093,6 +3365,27 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/globby": {
+ "version": "11.1.0",
+ "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
+ "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.2.9",
+ "ignore": "^5.2.0",
+ "merge2": "^1.4.1",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/gopd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
@@ -3989,6 +4282,16 @@
"node": ">=10"
}
},
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+ "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
"node_modules/micromatch": {
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
@@ -4386,6 +4689,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/peek-readable": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
@@ -5377,6 +5690,19 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/ts-api-utils": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
+ "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ },
+ "peerDependencies": {
+ "typescript": ">=4.2.0"
+ }
+ },
"node_modules/tsconfig-paths": {
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
@@ -5505,6 +5831,21 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/typescript": {
+ "version": "5.5.4",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
+ "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "peer": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
"node_modules/unbox-primitive": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
diff --git a/package.json b/package.json
index 143a18c..39bba16 100644
--- a/package.json
+++ b/package.json
@@ -52,7 +52,7 @@
"scripts": {
"test": "npx playwright test",
"pretest": "npm run lint",
- "lint": "eslint index.js",
+ "lint": "eslint .",
"start": "electron .",
"package-win": "electron-packager . ntfy-electron --asar --platform=win32 --arch=all --icon=ntfy.ico --overwrite --ignore=\"^/dist|/build|/.github*|/test-*|/tests*|/playwright*|.all-contributorsrc|.editorconfig|.eslintrc|/.git*|.git*|.npm*|.prettier*\" --prune=true --out=build --appCopyright=\"Copyright (c) 2024\" --win32metadata.FileDescription=\"ntfy desktop client with Electron wrapper\" --win32metadata.ProductName=\"ntfy desktop\" --win32metadata.OriginalFilename=\"ntfy-desktop.exe\" --win32metadata.CompanyName=\"https://github.com/xdpirate/ntfy-electron\"",
"package-linux": "electron-packager . ntfy-electron --asar --platform=linux --arch=all --icon=ntfy.png --overwrite --ignore=\"^/dist|/build|/.github*|/test-*|/tests*|/playwright*|.all-contributorsrc|.editorconfig|.eslintrc|/.git*|.git*|.npm*|.prettier*\" --prune=true --out=build --appCopyright=\"Copyright (c) 2024\" --win32metadata.FileDescription=\"ntfy desktop client with Electron wrapper\" --win32metadata.ProductName=\"ntfy desktop\" --win32metadata.OriginalFilename=\"ntfy-desktop.exe\" --win32metadata.CompanyName=\"https://github.com/xdpirate/ntfy-electron\"",
@@ -79,6 +79,8 @@
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prettier": "^5.2.1",
"eslint-plugin-promise": "^6.4.0",
+ "@stylistic/eslint-plugin-js": "^2.3.0",
+ "@stylistic/eslint-plugin-plus": "^2.3.0",
"jimp": "^0.22.12",
"prettier": "^3.3.3"
},
diff --git a/playwright.config.js b/playwright.config.js
index bcb5aa3..2072cf0 100644
--- a/playwright.config.js
+++ b/playwright.config.js
@@ -1,62 +1,62 @@
// @ts-check
-const { defineConfig, devices } = require('@playwright/test');
+const { defineConfig, devices } = require( '@playwright/test' )
-/**
- * Read environment variables from file.
- * https://github.com/motdotla/dotenv
+/*
+ Read environment variables from file.
+ https://github.com/motdotla/dotenv
*/
+
// require('dotenv').config({ path: path.resolve(__dirname, '.env') });
-/**
- * @see https://playwright.dev/docs/test-configuration
- */
-module.exports = defineConfig({
- testDir: './tests',
- /* Run tests in files in parallel */
- fullyParallel: false,
- /* Fail the build on CI if you accidentally left test.only in the source code. */
- forbidOnly: !!process.env.CI,
- /* Retry on CI only */
- retries: process.env.CI ? 2 : 0,
- /* Opt out of parallel tests on CI. */
- workers: process.env.CI ? 1 : undefined,
- /* Reporter to use. See https://playwright.dev/docs/test-reporters */
- reporter: 'html',
- /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
- use: {
+/*
+ @see https://playwright.dev/docs/test-configuration
+*/
+
+module.exports = defineConfig( {
+ testDir: './tests',
+ /* Run tests in files in parallel */
+ fullyParallel: false,
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
+ forbidOnly: !!process.env.CI,
+ /* Retry on CI only */
+ retries: process.env.CI ? 2 : 0,
+ /* Opt out of parallel tests on CI. */
+ workers: process.env.CI ? 1 : undefined,
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
+ reporter: 'html',
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
+ use: {
/* Base URL to use in actions like `await page.goto('/')`. */
// baseURL: 'http://127.0.0.1:3000',
- /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
- trace: 'on-first-retry',
- },
-
- /* Configure projects for major browsers */
- projects: [
- {
- name: 'chromium',
- use: { ...devices['Desktop Chrome'] },
- },
-
- {
- name: 'firefox',
- use: { ...devices['Desktop Firefox'] },
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
+ trace: 'on-first-retry'
},
- {
- name: 'webkit',
- use: { ...devices['Desktop Safari'] },
- },
+ /* Configure projects for major browsers */
+ projects: [
+ {
+ name: 'chromium',
+ use: { ...devices[ 'Desktop Chrome' ] }
+ },
+ {
+ name: 'firefox',
+ use: { ...devices[ 'Desktop Firefox' ] }
+ },
+ {
+ name: 'webkit',
+ use: { ...devices[ 'Desktop Safari' ] }
+ }
- /* Test against mobile viewports. */
- // {
- // name: 'Mobile Chrome',
- // use: { ...devices['Pixel 5'] },
- // },
- // {
- // name: 'Mobile Safari',
- // use: { ...devices['iPhone 12'] },
- // },
+ /* Test against mobile viewports. */
+ // {
+ // name: 'Mobile Chrome',
+ // use: { ...devices['Pixel 5'] },
+ // },
+ // {
+ // name: 'Mobile Safari',
+ // use: { ...devices['iPhone 12'] },
+ // },
/* Test against branded browsers. */
// {
@@ -67,13 +67,13 @@ module.exports = defineConfig({
// name: 'Google Chrome',
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
// },
- ],
+ ]
- /* Run your local dev server before starting the tests */
- // webServer: {
- // command: 'npm run start',
- // url: 'http://127.0.0.1:3000',
- // reuseExistingServer: !process.env.CI,
- // },
-});
+ /* Run your local dev server before starting the tests */
+ // webServer: {
+ // command: 'npm run start',
+ // url: 'http://127.0.0.1:3000',
+ // reuseExistingServer: !process.env.CI,
+ // },
+} )
diff --git a/store.js b/store.js
deleted file mode 100644
index d34bc32..0000000
--- a/store.js
+++ /dev/null
@@ -1,45 +0,0 @@
-// Respectfully stolen from Cameron Nokes @ Medium:
-// https://medium.com/cameron-nokes/how-to-store-user-data-in-electron-3ba6bf66bc1e
-const electron = require('electron');
-const path = require('path');
-const fs = require('fs');
-
-class Store {
- constructor(opts) {
- // Renderer process has to get `app` module via `remote`, whereas the main process can get it directly
- // app.getPath('userData') will return a string of the user's app data directory path.
- const userDataPath = (electron.app || electron.remote.app).getPath('userData');
- // We'll use the `configName` property to set the file name and path.join to bring it all together as a string
- this.path = path.join(userDataPath, opts.configName + '.json');
- console.log(`User Config: ${this.path}`);
- this.data = parseDataFile(this.path, opts.defaults);
- }
-
- // This will just return the property on the `data` object
- get(key) {
- return this.data[key];
- }
-
- set(key, val) {
- this.data[key] = val;
- // Wait, I thought using the node.js' synchronous APIs was bad form?
- // We're not writing a server so there's not nearly the same IO demand on the process
- // Also if we used an async API and our app was quit before the asynchronous write had a chance to complete,
- // we might lose that data. Note that in a real app, we would try/catch this.
- fs.writeFileSync(this.path, JSON.stringify(this.data));
- }
-}
-
-function parseDataFile(filePath, defaults) {
- // We'll try/catch it in case the file doesn't exist yet, which will be the case on the first application run.
- // `fs.readFileSync` will return a JSON string which we then parse into a Javascript object
- try {
- return JSON.parse(fs.readFileSync(filePath));
- } catch(error) {
- // if there was some kind of error, return the passed in defaults instead.
- return defaults;
- }
-}
-
-// expose the class
-module.exports = Store;
diff --git a/tests/main.spec.js b/tests/main.spec.js
index 7b6d2da..d93715b 100644
--- a/tests/main.spec.js
+++ b/tests/main.spec.js
@@ -1,3 +1,5 @@
+/* eslint-disable no-unused-vars */
+/* eslint-disable no-console */
// @ts-check
/*
@@ -14,25 +16,26 @@
Examples available at: https://github.com/spaceagetv/electron-playwright-example
*/
-const { test, expect, _electron: electron } = require('@playwright/test')
-const eph = require('electron-playwright-helpers')
+const { test, expect, _electron: electron } = require( '@playwright/test' )
+const eph = require( 'electron-playwright-helpers' )
import jimp from 'jimp'
/*
Test > ensure ntfy-desktop launches
*/
-test('launch ntfy-desktop', async () => {
- const app = await electron.launch({
+test( 'launch ntfy-desktop', async () =>
+{
+ const app = await electron.launch( {
args: [
'index.js',
'--quit'
],
env: {
...process.env,
- NODE_ENV: 'development',
- },
- });
+ NODE_ENV: 'development'
+ }
+ } )
/*
const appInfo = eph.parseElectronApp('./build/ntfy-electron-win32-x64')
@@ -40,122 +43,125 @@ test('launch ntfy-desktop', async () => {
*/
await app.close()
-})
+} )
/*
Test > full loadup and screenshot
*/
-test('full load', async () => {
+test( 'full load', async () =>
+{
/*
Initialize
*/
- const app = await electron.launch({
+ const app = await electron.launch( {
args: [
'index.js',
'--quit'
],
env: {
...process.env,
- NODE_ENV: 'development',
- },
- });
+ NODE_ENV: 'development'
+ }
+ } )
- const timestamp = Date.now().toString();
+ const timestamp = Date.now().toString()
- const appPath = await app.evaluate(async ({ app }) => {
- return app.getAppPath();
- });
+ const appPath = await app.evaluate( async ( { app } ) =>
+ {
+ return app.getAppPath()
+ } )
- console.log(appPath);
+ console.log( appPath )
const window = await app.firstWindow()
- console.log(await window.title());
- window.on('console', console.log);
+ console.log( await window.title() )
+ window.on( 'console', console.log )
/*
wait for #root div before taking screenshot
*/
- await window.waitForSelector('#root', { state: 'visible' });
+ await window.waitForSelector( '#root', { state: 'visible' } )
/*
path: `e2e/screenshots/test-${timestamp}.png`,
*/
- const ss1 = await window.screenshot({ path: './test-results/1.png' })
+ const ss1 = await window.screenshot( { path: './test-results/1.png' } )
/*
Since the close button minimizes to tray, activate the menu and select quit
*/
- await eph.clickMenuItemById(app, 'quit');
+ await eph.clickMenuItemById( app, 'quit' )
await app.close()
-})
+} )
/*
Test functionality
*/
-test('app usage', async () => {
+test( 'app usage', async () =>
+{
/*
Initialize
*/
- const app = await electron.launch({
+ const app = await electron.launch( {
args: [
'index.js',
'--quit'
],
env: {
...process.env,
- NODE_ENV: 'development',
- },
- });
+ NODE_ENV: 'development'
+ }
+ } )
/*
test functionality through app
*/
const page = await app.firstWindow()
- await page.getByLabel('Sign in').click();
- await page.getByLabel('Username *').click();
- await page.getByLabel('Username *').fill('testuser');
- await page.getByLabel('Password *').click();
- await page.getByLabel('Password *').fill('123456789');
- await page.getByRole('button', { name: 'Sign in' }).click();
- await page.getByText('Login failed: Invalid').click();
+ await page.getByLabel( 'Sign in' ).click()
+ await page.getByLabel( 'Username *' ).click()
+ await page.getByLabel( 'Username *' ).fill( 'testuser' )
+ await page.getByLabel( 'Password *' ).click()
+ await page.getByLabel( 'Password *' ).fill( '123456789' )
+ await page.getByRole( 'button', { name: 'Sign in' } ).click()
+ await page.getByText( 'Login failed: Invalid' ).click()
/*
get expectation
*/
- expect(page.getByText("Login failed: Invalid")).toBeVisible();
+ expect( page.getByText( 'Login failed: Invalid' ) ).toBeVisible()
const window = await app.firstWindow()
- console.log(await window.title());
- window.on('console', console.log);
+ console.log( await window.title() )
+ window.on( 'console', console.log )
/*
wait for #root div before taking screenshot
*/
- await window.waitForSelector('#root', { state: 'visible' });
+ await window.waitForSelector( '#root', { state: 'visible' } )
/*
path: `e2e/screenshots/test-${timestamp}.png`,
*/
- const ss1 = await window.screenshot({ path: './test-results/3.png' })
+ const ss1 = await window.screenshot( { path: './test-results/3.png' } )
/*
Since the close button minimizes to tray, activate the menu and select quit
*/
- await eph.clickMenuItemById(app, 'quit');
+ await eph.clickMenuItemById( app, 'quit' )
await app.close()
-});
+} )