From 139925da399186cc30c162df8b8176c00d6329eb Mon Sep 17 00:00:00 2001 From: Jessica Schilling Date: Tue, 27 Oct 2020 15:34:33 -0600 Subject: [PATCH] feat: icon in browser action menu upon version update (#935) Co-authored-by: Marcin Rataj --- add-on/_locales/en/messages.json | 4 ++++ add-on/src/lib/ipfs-companion.js | 16 ++-------------- add-on/src/lib/on-installed.js | 15 ++++++--------- add-on/src/lib/options.js | 11 ++++++++++- add-on/src/popup/browser-action/header.js | 8 +++++++- .../src/popup/browser-action/options-icon.js | 2 +- add-on/src/popup/browser-action/page.js | 3 ++- add-on/src/popup/browser-action/power-icon.js | 2 +- add-on/src/popup/browser-action/store.js | 14 ++++++++++++++ .../browser-action/version-update-icon.js | 18 ++++++++++++++++++ test/functional/lib/ipfs-companion.test.js | 1 + 11 files changed, 66 insertions(+), 28 deletions(-) create mode 100644 add-on/src/popup/browser-action/version-update-icon.js diff --git a/add-on/_locales/en/messages.json b/add-on/_locales/en/messages.json index 04ca4121d..6c14c05f6 100644 --- a/add-on/_locales/en/messages.json +++ b/add-on/_locales/en/messages.json @@ -7,6 +7,10 @@ "message": "IPFS Companion", "description": "A label for IPFS icon (panel_headerIpfsNodeIconLabel)" }, + "panel_headerNewVersionTitle": { + "message": "IPFS Companion was updated to a new version! Click for details.", + "description": "A label in the Browser Action pop-up for icon appearing on first load of new version (panel_headerNewVersionTitle)" + }, "panel_headerActiveToggleTitle": { "message": "Toggle all IPFS integrations", "description": "A label for an embedded IPFS node (panel_headerActiveToggleTitle)" diff --git a/add-on/src/lib/ipfs-companion.js b/add-on/src/lib/ipfs-companion.js index 2ef04a551..406705f54 100644 --- a/add-on/src/lib/ipfs-companion.js +++ b/add-on/src/lib/ipfs-companion.js @@ -260,6 +260,7 @@ module.exports = async function init () { redirect: state.redirect, enabledOn: state.enabledOn, disabledOn: state.disabledOn, + showUpdateIndicator: state.dismissedUpdate !== browser.runtime.getManifest().version, currentTab } try { @@ -687,20 +688,7 @@ module.exports = async function init () { shouldReloadExtension = true state[key] = localStorage.debug = change.newValue break - case 'recoverFailedHttpRequests': - case 'importDir': - case 'linkify': - case 'catchUnhandledProtocols': - case 'displayNotifications': - case 'displayReleaseNotes': - case 'automaticMode': - case 'detectIpfsPathHeader': - case 'preloadAtPublicGateway': - case 'openViaWebUI': - case 'useLatestWebUI': - case 'enabledOn': - case 'disabledOn': - case 'dnslinkRedirect': + default: state[key] = change.newValue break } diff --git a/add-on/src/lib/on-installed.js b/add-on/src/lib/on-installed.js index b55a599e9..bd299a13b 100644 --- a/add-on/src/lib/on-installed.js +++ b/add-on/src/lib/on-installed.js @@ -2,6 +2,7 @@ /* eslint-env browser */ const browser = require('webextension-polyfill') +const { version } = browser.runtime.getManifest() exports.welcomePage = '/dist/landing-pages/welcome/index.html' exports.updatePage = 'https://github.com/ipfs-shipyard/ipfs-companion/releases/tag/v' @@ -16,11 +17,8 @@ exports.onInstalled = async (details) => { } exports.showPendingLandingPages = async () => { - const hint = await browser.storage.local.get([ - 'showLandingPage', - 'displayReleaseNotes' - ]) - switch (hint.showLandingPage) { + const { showLandingPage, displayReleaseNotes } = await browser.storage.local.get(['showLandingPage', 'displayReleaseNotes']) + switch (showLandingPage) { case 'onInstallWelcome': await browser.storage.local.remove('showLandingPage') return browser.tabs.create({ @@ -28,9 +26,8 @@ exports.showPendingLandingPages = async () => { }) case 'onVersionUpdate': await browser.storage.local.remove('showLandingPage') - if (!hint.displayReleaseNotes) return - return browser.tabs.create({ - url: exports.updatePage + browser.runtime.getManifest().version - }) + if (!displayReleaseNotes) return + await browser.storage.local.set({ dismissedUpdate: version }) + return browser.tabs.create({ url: exports.updatePage + version }) } } diff --git a/add-on/src/lib/options.js b/add-on/src/lib/options.js index aa42b8a7d..deef514d9 100644 --- a/add-on/src/lib/options.js +++ b/add-on/src/lib/options.js @@ -26,7 +26,7 @@ exports.optionDefaults = Object.freeze({ preloadAtPublicGateway: true, catchUnhandledProtocols: true, displayNotifications: true, - displayReleaseNotes: true, + displayReleaseNotes: false, customGatewayUrl: buildCustomGatewayUrl(), ipfsApiUrl: buildIpfsApiUrl(), ipfsApiPollMs: 3000, @@ -34,6 +34,7 @@ exports.optionDefaults = Object.freeze({ logNamespaces: 'jsipfs*,ipfs*,libp2p:mdns*,libp2p-delegated*,-*:ipns*,-ipfs:preload*,-ipfs-http-client:request*,-ipfs:http-api*', importDir: '/ipfs-companion-imports/%Y-%M-%D_%h%m%s/', useLatestWebUI: false, + dismissedUpdate: null, openViaWebUI: true }) @@ -213,4 +214,12 @@ exports.migrateOptions = async (storage, debug) => { await storage.set({ disabledOn }) } } + + { // ~v2.15.1: change displayReleaseNotes opt-out flag to opt-in + const { displayReleaseNotes, dismissedUpdate } = await storage.get(['displayReleaseNotes', 'dismissedUpdate']) + if (!dismissedUpdate && displayReleaseNotes) { + log('converting displayReleaseNotes from out-out to opt-in') + await storage.set({ displayReleaseNotes: false }) + } + } } diff --git a/add-on/src/popup/browser-action/header.js b/add-on/src/popup/browser-action/header.js index e5fcbfe04..259287924 100644 --- a/add-on/src/popup/browser-action/header.js +++ b/add-on/src/popup/browser-action/header.js @@ -3,13 +3,14 @@ const html = require('choo/html') const logo = require('../logo') +const versionUpdateIcon = require('./version-update-icon') const powerIcon = require('./power-icon') const optionsIcon = require('./options-icon') const ipfsVersion = require('./ipfs-version') const gatewayStatus = require('./gateway-status') module.exports = function header (props) { - const { ipfsNodeType, active, onToggleActive, onOpenPrefs, isIpfsOnline, onOpenWelcomePage } = props + const { ipfsNodeType, active, onToggleActive, onOpenPrefs, onOpenReleaseNotes, isIpfsOnline, onOpenWelcomePage, showUpdateIndicator } = props return html`
@@ -35,6 +36,11 @@ module.exports = function header (props) {
+ ${showUpdateIndicator ? versionUpdateIcon({ + active, + title: 'panel_headerNewVersionTitle', + action: onOpenReleaseNotes + }) : null} ${powerIcon({ active, title: 'panel_headerActiveToggleTitle', diff --git a/add-on/src/popup/browser-action/options-icon.js b/add-on/src/popup/browser-action/options-icon.js index a7d6abc4d..07e0c3b31 100644 --- a/add-on/src/popup/browser-action/options-icon.js +++ b/add-on/src/popup/browser-action/options-icon.js @@ -6,7 +6,7 @@ const icon = require('./icon') function optionsIcon ({ active, title, action, size = '1.8rem' }) { const svg = html` - diff --git a/add-on/src/popup/browser-action/page.js b/add-on/src/popup/browser-action/page.js index 1b6b9174d..a84e58003 100644 --- a/add-on/src/popup/browser-action/page.js +++ b/add-on/src/popup/browser-action/page.js @@ -19,11 +19,12 @@ module.exports = function browserActionPage (state, emit) { const onOpenWebUi = () => emit('openWebUi', '/') const onOpenWelcomePage = () => emit('openWelcomePage') const onOpenPrefs = () => emit('openPrefs') + const onOpenReleaseNotes = () => emit('openReleaseNotes') const onToggleGlobalRedirect = () => emit('toggleGlobalRedirect') const onToggleSiteIntegrations = () => emit('toggleSiteIntegrations') const onToggleActive = () => emit('toggleActive') - const headerProps = Object.assign({ onToggleActive, onOpenPrefs, onOpenWelcomePage }, state) + const headerProps = Object.assign({ onToggleActive, onOpenPrefs, onOpenReleaseNotes, onOpenWelcomePage }, state) const activeTabActionsProps = Object.assign({ onViewOnGateway, onToggleSiteIntegrations, onCopy, onPin, onUnPin }, state) const opsProps = Object.assign({ onQuickImport, onOpenWebUi, onToggleGlobalRedirect }, state) diff --git a/add-on/src/popup/browser-action/power-icon.js b/add-on/src/popup/browser-action/power-icon.js index 672c9e230..07ccce8fc 100644 --- a/add-on/src/popup/browser-action/power-icon.js +++ b/add-on/src/popup/browser-action/power-icon.js @@ -6,7 +6,7 @@ const icon = require('./icon') function powerIcon ({ active, title, action, size = '1.8rem' }) { const svg = html` - diff --git a/add-on/src/popup/browser-action/store.js b/add-on/src/popup/browser-action/store.js index 6fa955ed1..800e22307 100644 --- a/add-on/src/popup/browser-action/store.js +++ b/add-on/src/popup/browser-action/store.js @@ -155,6 +155,20 @@ module.exports = (state, emitter) => { } }) + emitter.on('openReleaseNotes', async () => { + const { version } = browser.runtime.getManifest() + const url = `https://github.com/ipfs-shipyard/ipfs-companion/releases/tag/v${version}` + try { + await browser.storage.local.set({ dismissedUpdate: version }) + // Note: opening tab needs to happen after storage.local.set because in Chromium 86 + // it triggers a premature window.close, which aborts storage update + await browser.tabs.create({ url }) + window.close() + } catch (error) { + console.error(`Unable to open release notes (${url})`, error) + } + }) + emitter.on('openPrefs', () => { browser.runtime.openOptionsPage() .then(() => window.close()) diff --git a/add-on/src/popup/browser-action/version-update-icon.js b/add-on/src/popup/browser-action/version-update-icon.js new file mode 100644 index 000000000..d8b79a261 --- /dev/null +++ b/add-on/src/popup/browser-action/version-update-icon.js @@ -0,0 +1,18 @@ +'use strict' +/* eslint-env browser, webextensions */ + +const html = require('choo/html') +const icon = require('./icon') + +function versionUpdateIcon ({ active, title, action, size = '1.8rem' }) { + const svg = html` + + + + ` + return icon({ svg, title, active, action }) +} + +module.exports = versionUpdateIcon diff --git a/test/functional/lib/ipfs-companion.test.js b/test/functional/lib/ipfs-companion.test.js index c482bb78b..4d78e0647 100644 --- a/test/functional/lib/ipfs-companion.test.js +++ b/test/functional/lib/ipfs-companion.test.js @@ -14,6 +14,7 @@ describe('init', function () { global.browser = browser global.URL = URL global.screen = {} + browser.runtime.getManifest.returns({ version: '0.0.0' }) // on-installed.js init = require('../../../add-on/src/lib/ipfs-companion') })