diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..5c166c7 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,37 @@ +{ + "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/.gitignore b/.gitignore index da2ddde..341584e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,21 +4,31 @@ /* # ---------------------------------------- -# [WL]: NodeJS > Electron +# [WL]: Git Base Folders/Files +# ---------------------------------------- +!/.github +!/.gitea +!*README.md +!*LICENSE.md +!*LICENSE +!*CHANGELOG.md +!*CONTRIBUTE.md +!*CONTRIBUTING.md +!*CODE_OF_CONDUCT.md +!*DECISION_FLOW.md + +# ---------------------------------------- +# [WL]: Electron # ---------------------------------------- !/electron # ---------------------------------------- -# [WL]: Visual Studio +# [WL]: Tests # ---------------------------------------- -!/Classes -!/Controls -!/Forms -!/Materials -!/Properties -!*app.* -!*csproj* -!*sln* +!/Tests +!/test +!/example +!*playwright.config.js # ---------------------------------------- # [WL]: Manifest Folders @@ -31,167 +41,54 @@ !/Tools # ---------------------------------------- -# [WL]: Gitignore File +# [WL]: vendor # ---------------------------------------- -!*.gitignore +!/vendor # ---------------------------------------- -# [WL]: Docs / assets +# [WL]: assets # ---------------------------------------- -!/docs !/assets -!/pages - -# ---------------------------------------- -# [WL]: Source Folder -# ---------------------------------------- -!/src -!/source -!/target -!/lib -!/notifiers # ---------------------------------------- -# [WL]: Dist Folder +# [WL]: Gitignore File # ---------------------------------------- -!/bin -!/release +!.gitignore # ---------------------------------------- -# [WL]: Test Folder +# [WL]: Docs Folder # ---------------------------------------- -!/Tests -!/Test -!/example -!*playwright.config.js +!/docs +!/pages # ---------------------------------------- -# [WL]: Util / vendor +# [WL]: Source Folder # ---------------------------------------- -!/util -!/vendor +!/src +!/lib +!/notifiers # ---------------------------------------- # [WL]: Base Files # ---------------------------------------- +!*.prettierrc +!*.prettierignore +!*.eslintrc +!*.npmignore !*.all-contributorsrc !*.editorconfig +!*ntfy.js +!*index.js !*manifest.json -!*versions.json -!*styles.css - -# ---------------------------------------- -# [WL]: npm release -# ---------------------------------------- -!*package*.json -!*attribution.js -!*jsconfig.json -!*postcss.config.js -!*webpack.config.js - -# ---------------------------------------- -# [WL]: Git Base Folders/Files -# ---------------------------------------- -!*.md -!/.github -!/.gitea -!*LICENSE* -!*README* -!*CHANGELOG* -!*CONTRIBUTE* -!*CONTRIBUTING* -!*CODE_OF_CONDUCT* -!*DEPS-LICENSE* -!*DECISION_FLOW* -!*SECURITY* -!tree* -!*release-notes - -# ---------------------------------------- -# [WL]: Misc -# ---------------------------------------- -!*.js -!*.ts -!*.css -!*.sh -!*.tgz -!*.ico -!*.conf -!*.bat -!*.xml -!*.html - -# ---------------------------------------- -# [WL]: NodeJS > NPM -# ---------------------------------------- -!.nvmrc -!.nvmrc -!.node-version -!.npmignore - -# ---------------------------------------- -# [WL]: NodeJS > Babel -# ---------------------------------------- -!*.babelrc -!*.babel* - -# ---------------------------------------- -# [WL]: NodeJS > Eslint -# ---------------------------------------- -!*eslint.config.js -!*eslintrc.* -!*.eslintrc* - -# ---------------------------------------- -# [WL]: NodeJS > Prettier -# ---------------------------------------- -!*.prettierignore -!*.prettierrc -!*prettier.config.js - -# ---------------------------------------- -# [WL]: NodeJS > Grunt -# ---------------------------------------- -!*gruntfile.* -!*grunt.* -!*Gruntfile* - -# ---------------------------------------- -# [WL]: NodeJS > Jest -# ---------------------------------------- -!*jest.config.js - -# ---------------------------------------- -# [WL]: NodeJS > Wrangler -# ---------------------------------------- -!*wrangler.toml - -# ---------------------------------------- -# [WL]: NodeJS > Typescript -# ---------------------------------------- -!*typescript.js -!*tsconfig.json -vitest.workspace.ts - -# ---------------------------------------- -# [WL]: NodeJS > Rollup -# ---------------------------------------- +!*package.json +!*package-lock.json !*rollup.config.js !*rollup.config.mjs - -# ---------------------------------------- -# [WL]: Github > Development Actions -# ---------------------------------------- -!*action.yml - -# ---------------------------------------- -# [WL]: VSC -# ---------------------------------------- -!*jsconfig.json - -# ---------------------------------------- -# [WL]: Signing -# ---------------------------------------- +!*tsconfig.json +!*versions.json !sign.bat !*SHA*.asc !*SHA*.sig +!*styles.css +!*.sh +!*.bat diff --git a/.prettierrc b/.prettierrc index 0dc3fc7..d9c33d2 100644 --- a/.prettierrc +++ b/.prettierrc @@ -49,7 +49,7 @@ useTabs: false # @default : true # @ref : https://prettier.io/docs/en/options.html#semicolons # -------------------------------------------------------------------------------------- -semi: false +semi: true # -------------------------------------------------------------------------------------- # Use single quotes instead of double quotes. diff --git a/build.sh b/build.sh index da51e3c..c283958 100644 --- a/build.sh +++ b/build.sh @@ -17,7 +17,7 @@ FileDescription='ntfy desktop client with Electron wrapper' ProductName='ntfy desktop' OriginalFilename='ntfy-desktop.exe' CompanyName='https://github.com/xdpirate/ntfy-electron' -IgnorePattern='(^/${dir_dist}|^/${dir_build}|^/.github*|/test-*|/tests*|^/playwright*|.all-contributorsrc|.editorconfig|.eslintrc|^/.git*|^.git*|.npm*|.prettier*|CONTRIBUTING.md|CODE_OF_CONDUCT.md|README|README.md|readme.md|LICENSE|license|LICENSE.md|CHANGELOG|CHANGELOG.md)"' +IgnorePattern='(^/!dir_dist!|^/!dir_build!|^/.github*|/test-*|/tests*|^/playwright*|.all-contributorsrc|.editorconfig|.eslintrc|^/.git*|^.git*|.npm*|.prettier*|CONTRIBUTING.md|CODE_OF_CONDUCT.md|README|README.md|readme.md|LICENSE|license|LICENSE.md|CHANGELOG|CHANGELOG.md)"' IconWindows='assets/icons/ntfy.ico' IconLinux='assets/icons/ntfy.png' IconMacOS='assets/icons/ntfy.icns' diff --git a/index.js b/index.js index f70384a..cc71c54 100644 --- a/index.js +++ b/index.js @@ -1,12 +1,10 @@ -/* 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' ) +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'); /* Declare > Prompt @@ -14,40 +12,32 @@ const Storage = require( './app/Storage.js' ) @docs : https://araxeus.github.io/custom-electron-prompt/ */ -const prompt = require( 'custom-electron-prompt' ) +const prompt = require('custom-electron-prompt'); /* - Args & Env Vars - - argv[0] is the path to the Node. js executable. - argv[1] is the path to the script file. - argv[2] is the first argument passed to the script. - argv[3] is the second argument passed to the script and so on. - - developer env : process.env.NODE_ENV + Debug > Print args */ -const _ENV_MODE = ( process.env.NODE_ENV == `dev` ) || ( process.env.NODE_ENV == `development` ) ? `development` : `production` -const _ENV_PROD = ( _ENV_MODE == `production` ) -const _ENV_DEV = _ENV_MODE == `development` +console.log(process.argv); + /* Declare > Package */ -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' +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'; /* Declare > Window */ -let winMain, winAbout, timerPollrate, tray +let winMain, winAbout, timerPollrate, tray; /* Declare > CLI State @@ -58,20 +48,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 bUrlOverride = 0 -let bStartHidden = 0 -let bWinHidden = 0 +let bDevTools = 0; +let bHotkeysEnabled = 0; +let bQuitOnClose = 0; +let 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 @@ -79,10 +68,9 @@ let statusMessage fallback values in case a user does something unforseen to cause an index error */ -const _Instance = 'https://ntfy.sh/app' -const _InstanceOverride = 'https://domain.com' -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 @@ -91,7 +79,7 @@ const _Pollrate = 5 storage: AppData\Roaming\ntfy-desktop */ -const store = new Storage( { +const store = new Store({ configName: 'prefs', defaults: { instanceURL: _Instance, @@ -104,31 +92,25 @@ const store = new Storage( { 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); + }); } /* @@ -140,17 +122,15 @@ function validateUrl( uri, tries, delay ) API Token can be specified in app. */ -async function GetMessageData( uri ) -{ - const cfgApiToken = store.get( 'apiToken' ) - const req = await fetch( uri, - { - method: 'GET', - headers: { - Accept: 'application/json', - Authorization: `Bearer ${ cfgApiToken }` - } - } ) +async function GetMessageData(uri) { + const cfgApiToken = store.get('apiToken'); + let 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 @@ -160,24 +140,22 @@ async function GetMessageData( uri ) array. */ - const json = await req.text() - const jsonArr = [] - const entries = json.split( '\n' ) - for ( let i = 0; i < entries.length; i++ ) - { - jsonArr.push( entries[ i ] ) + const json = await req.text(); + let 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; } /* @@ -187,135 +165,114 @@ 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 log = [] - 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 ) - { - log.push( `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` - log.push( `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 ) - { - log.push( `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 historyLst = msgHistory.length > 0 ? `${ msgHistory }` : `Empty` - const messageLst = JSON.stringify( json ) !== `[]` ? JSON.stringify( json ) : `Empty` + const json = await GetMessageData(uri); - log.push( `-------------------------------------------------------------------------------` ) - log.push( `Status ................ Checking New Messages` ) - log.push( `InstanceURL ........... ${ cfgInstanceURL }` ) - log.push( `Query ................. ${ uri }` ) - log.push( `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. */ - log.push( `-------------------------------------------------------------------------------` ) - log.push( `History ............... ${ historyLst }` ) - log.push( `Message ............... ${ messageLst }` ) - log.push( `-------------------------------------------------------------------------------\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; - if ( type != 'message' ) - continue + 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; /* 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' - log.push( `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); - log.push( ` Topic .............. ${ type }:${ id } ${ topic }` ) - log.push( ` Date ............... ${ type }:${ id } ${ dateHuman }` ) - log.push( ` InstanceURL ........ ${ type }:${ id } ${ cfgInstanceURL }` ) - log.push( ` 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}`); } - log.push( `Messages .............. ${ type }:${ id } sent` ) + console.log(`Messages .............. ${type}:${id} sent`); } - log.push( `\n\n` ) + console.log(`\n\n`); - /* - Console Output - */ - - if ( _ENV_DEV == true ) - { - for ( let i = 0; i < log.length; i++ ) - { - console.log( log[ i ] ) - } - } - - return json + return json; } /* @@ -327,276 +284,255 @@ 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 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: '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 ) => + ], + }, + winMain + ) + .then((response) => { + if (response !== null) { + // do not update dev tools if value hasn't changed + if ( store.get('bDevTools') !== response[0]) { - 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('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 URL
This 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 URL
This 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( ( bUrlOverride != 1 && bUrlOverride ) || 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 Token
Generate 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 Topics
Specify 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 ) => + } + }, + { + label: 'API Token', + accelerator: (bHotkeysEnabled == 1 || store.get('bHotkeys') == 1) ? 'CTRL+T' : '', + click: function () { + prompt( + { + title: 'Set API Token', + label: 'API Token
Generate 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 Topics
Specify 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) { - 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 ) + store.set('topics', response); - if ( typeof ( store.get( 'instanceURL' ) ) !== 'string' || store.get( 'instanceURL' ) === '' || store.get( 'instanceURL' ) === null ) - { - store.set( 'instanceURL', _Instance ) - } - - winMain.loadURL( ( bUrlOverride != 1 && bUrlOverride ) || store.get( 'instanceURL' ) ) - } + if (typeof (store.get('instanceURL')) !== 'string' || store.get('instanceURL') === '' || store.get('instanceURL') === null ) { + store.set('instanceURL', _Instance); } - } ) - .catch( ( _response ) => - { - console.error - } ) - } - }, - { - label: 'Notifications', - accelerator: ( bHotkeysEnabled == 1 || store.get( 'bHotkeys' ) == 1 ) ? 'CTRL+N' : '', - click: function () - { - prompt( - { - title: 'Notifications', - label: 'Notification Settings
Determines 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: + + 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 Settings
Determines 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, @@ -605,129 +541,120 @@ 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 - } - } ) + } + ] +}, +{ + 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.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 }` ) - } + 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(`${packageJson.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 @@ -738,27 +665,24 @@ Menu.setApplicationMenu( header_menu ) App | Configure | Help */ -function activeDevTools() -{ - const header_menu = Menu.buildFromTemplate( menu_Main ) - Menu.setApplicationMenu( header_menu ) +function activeDevTools() { + const header_menu = Menu.buildFromTemplate(menu_Main); + Menu.setApplicationMenu(header_menu); - 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' - } ) ) + if (bDevTools == 1 || store.get('bDevTools') == 1) { + let 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' + })) } } @@ -766,20 +690,19 @@ 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 @@ -788,12 +711,11 @@ 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}`; } /* @@ -802,29 +724,26 @@ 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( ( bUrlOverride != 1 && bUrlOverride ) || 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 @@ -833,33 +752,27 @@ 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 @@ -867,24 +780,21 @@ 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"; @@ -901,89 +811,79 @@ 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( ` @@ -1009,14 +909,13 @@ function ready() }) ` ) - .then( () => - { - winMain.webContents.toggleDevTools() - } ) - } ) + .then(() => { + winMain.webContents.toggleDevTools(); + }); + }); } } - } ) + }); /* Tray @@ -1025,22 +924,18 @@ 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() + 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(); } - else - { - bWinHidden = 1 - winMain.hide() - } - } ) + }); /* Loop args @@ -1050,29 +945,16 @@ 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 - bStartHidden = 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 ] === '--url' ) - { - bUrlOverride = process.argv[ 3 ] - } - else if ( process.argv[ i ] === '--hotkeys' ) - { - bHotkeysEnabled = 1 + } else if (process.argv[i] === '--quit') { + bQuitOnClose = 1; + } else if (process.argv[i] === '--hotkeys') { + bHotkeysEnabled = 1; } } @@ -1080,8 +962,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 @@ -1094,12 +976,12 @@ function ready() Start minimized in tray */ - if ( store.get( 'bStartHidden' ) == 1 || bStartHidden == 1 || bWinHidden == 1 ) - winMain.hide() + if( store.get('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 034db31..0320347 100644 --- a/package-lock.json +++ b/package-lock.json @@ -283,19 +283,6 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@eslint-community/regexpp": { "version": "4.11.0", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.0.tgz", @@ -330,37 +317,6 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@eslint/eslintrc/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, "node_modules/@eslint/js": { "version": "8.57.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", @@ -1056,28 +1012,6 @@ "@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", - "optional": true, - "peer": true, - "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", - "optional": true, - "peer": true - }, "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", @@ -1122,15 +1056,6 @@ "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", - "optional": true, - "peer": true - }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -2647,7 +2572,7 @@ "node": ">=10" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { + "node_modules/eslint-visitor-keys": { "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", @@ -2660,7 +2585,7 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/espree": { + "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", diff --git a/playwright.config.js b/playwright.config.js index 2072cf0..bcb5aa3 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' + /* 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'] }, }, - /* Configure projects for major browsers */ - projects: [ - { - name: 'chromium', - use: { ...devices[ 'Desktop Chrome' ] } - }, - { - name: 'firefox', - use: { ...devices[ 'Desktop Firefox' ] } - }, - { - name: 'webkit', - use: { ...devices[ 'Desktop Safari' ] } - } + { + 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, + // }, +});