diff options
author | 2023-05-04 17:52:33 +0800 | |
---|---|---|
committer | 2023-05-04 09:52:33 +0000 | |
commit | 0f0d7435a649466084fab40bb7fe0481b0c73dba (patch) | |
tree | 8f78f48062c8d2599a6850c3c74b18957108f44b | |
parent | b3e7358daa453481574a796bd8b3c2238701a2bc (diff) | |
download | refined-github-0f0d7435a649466084fab40bb7fe0481b0c73dba.tar.gz refined-github-0f0d7435a649466084fab40bb7fe0481b0c73dba.tar.zst refined-github-0f0d7435a649466084fab40bb7fe0481b0c73dba.zip |
Meta: Include information about storage in options (#6595)
-rw-r--r-- | package-lock.json | 61 | ||||
-rw-r--r-- | package.json | 3 | ||||
-rw-r--r-- | source/background.ts | 11 | ||||
-rw-r--r-- | source/helpers/types.d.ts | 5 | ||||
-rw-r--r-- | source/helpers/used-storage.ts | 10 | ||||
-rw-r--r-- | source/options.css | 4 | ||||
-rw-r--r-- | source/options.html | 7 | ||||
-rw-r--r-- | source/options.tsx | 49 |
8 files changed, 103 insertions, 47 deletions
diff --git a/package-lock.json b/package-lock.json index 789e7eec..962fdf42 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,6 +32,7 @@ "one-mutation": "^2.0.0", "onetime": "^6.0.0", "p-retry": "^5.1.2", + "pretty-bytes": "^6.1.0", "push-form": "^1.0.1", "regex-join": "^2.0.0", "select-dom": "^7.1.1", @@ -53,9 +54,9 @@ "devDependencies": { "@sindresorhus/tsconfig": "^3.0.1", "@types/codemirror": "^5.60.7", - "@types/firefox-webext-browser": "^109.0.0", "@types/jsdom": "^21.1.0", "@types/react": "^17.0.52", + "@types/webextension-polyfill": "^0.10.0", "copy-webpack-plugin": "^11.0.0", "cross-env": "^7.0.3", "css-loader": "^6.7.3", @@ -893,12 +894,6 @@ "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, - "node_modules/@types/firefox-webext-browser": { - "version": "109.0.0", - "resolved": "https://registry.npmjs.org/@types/firefox-webext-browser/-/firefox-webext-browser-109.0.0.tgz", - "integrity": "sha512-tkEjBP/zZxaS5bv8MH/0kUs3WeUm8KU3Ew1B9BtQQdq5PwtG23SXvAbjxjMSQpoIzbxyWG4Yu4mi1uB2S8W7ng==", - "dev": true - }, "node_modules/@types/jsdom": { "version": "21.1.0", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.0.tgz", @@ -986,6 +981,12 @@ "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", "dev": true }, + "node_modules/@types/webextension-polyfill": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", + "integrity": "sha512-If4EcaHzYTqcbNMp/FdReVdRmLL/Te42ivnJII551bYjhX19bWem5m14FERCqdJA732OloGuxCRvLBvcMGsn4A==", + "dev": true + }, "node_modules/@vitest/expect": { "version": "0.28.4", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.28.4.tgz", @@ -7497,12 +7498,11 @@ } }, "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.0.tgz", + "integrity": "sha512-Rk753HI8f4uivXi4ZCIYdhmG1V+WKzvRMg/X+M42a6t7D07RcmopXJMDNk6N++7Bl75URRGsb40ruvg7Hcp2wQ==", "engines": { - "node": ">=6" + "node": "^14.13.1 || >=16.0.0" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -8362,6 +8362,18 @@ "node": ">=4" } }, + "node_modules/size-plugin/node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/size-plugin/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -11708,12 +11720,6 @@ "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", "dev": true }, - "@types/firefox-webext-browser": { - "version": "109.0.0", - "resolved": "https://registry.npmjs.org/@types/firefox-webext-browser/-/firefox-webext-browser-109.0.0.tgz", - "integrity": "sha512-tkEjBP/zZxaS5bv8MH/0kUs3WeUm8KU3Ew1B9BtQQdq5PwtG23SXvAbjxjMSQpoIzbxyWG4Yu4mi1uB2S8W7ng==", - "dev": true - }, "@types/jsdom": { "version": "21.1.0", "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-21.1.0.tgz", @@ -11801,6 +11807,12 @@ "integrity": "sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw==", "dev": true }, + "@types/webextension-polyfill": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.10.0.tgz", + "integrity": "sha512-If4EcaHzYTqcbNMp/FdReVdRmLL/Te42ivnJII551bYjhX19bWem5m14FERCqdJA732OloGuxCRvLBvcMGsn4A==", + "dev": true + }, "@vitest/expect": { "version": "0.28.4", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.28.4.tgz", @@ -16469,10 +16481,9 @@ } }, "pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-6.1.0.tgz", + "integrity": "sha512-Rk753HI8f4uivXi4ZCIYdhmG1V+WKzvRMg/X+M42a6t7D07RcmopXJMDNk6N++7Bl75URRGsb40ruvg7Hcp2wQ==" }, "pretty-format": { "version": "27.5.1", @@ -17097,6 +17108,12 @@ "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", "dev": true }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", diff --git a/package.json b/package.json index bc2deaf4..a25e8f11 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "one-mutation": "^2.0.0", "onetime": "^6.0.0", "p-retry": "^5.1.2", + "pretty-bytes": "^6.1.0", "push-form": "^1.0.1", "regex-join": "^2.0.0", "select-dom": "^7.1.1", @@ -89,9 +90,9 @@ "devDependencies": { "@sindresorhus/tsconfig": "^3.0.1", "@types/codemirror": "^5.60.7", - "@types/firefox-webext-browser": "^109.0.0", "@types/jsdom": "^21.1.0", "@types/react": "^17.0.52", + "@types/webextension-polyfill": "^0.10.0", "copy-webpack-plugin": "^11.0.0", "cross-env": "^7.0.3", "css-loader": "^6.7.3", diff --git a/source/background.ts b/source/background.ts index 6d559273..e2ac0e04 100644 --- a/source/background.ts +++ b/source/background.ts @@ -1,3 +1,4 @@ +import {type Runtime} from 'webextension-polyfill'; import 'webext-dynamic-content-scripts'; import cache from 'webext-storage-cache'; // Also needed to regularly clear the cache import {isSafari} from 'webext-detect-page'; @@ -7,6 +8,7 @@ import addDomainPermissionToggle from 'webext-domain-permission-toggle'; import optionsStorage, {isBrowserActionAPopup} from './options-storage'; import {getRghIssueUrl} from './helpers/rgh-issue-link'; import isDevelopmentVersion from './helpers/is-development-version'; +import getStorageBytesInUse from './helpers/used-storage'; // GHE support addDomainPermissionToggle(); @@ -17,7 +19,7 @@ if (isBrowserActionAPopup) { } const messageHandlers = { - openUrls(urls: string[], {tab}: browser.runtime.MessageSender) { + openUrls(urls: string[], {tab}: Runtime.MessageSender) { for (const [i, url] of urls.entries()) { void browser.tabs.create({ url, @@ -26,7 +28,7 @@ const messageHandlers = { }); } }, - closeTab(_: any, {tab}: browser.runtime.MessageSender) { + closeTab(_: any, {tab}: Runtime.MessageSender) { void browser.tabs.remove(tab!.id!); }, async fetch(url: string) { @@ -60,9 +62,8 @@ browser.browserAction.onClicked.addListener(async tab => { async function hasUsedStorage(): Promise<boolean> { return ( - await browser.storage.sync.getBytesInUse() > 0 - // Note: Not available in Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1385832 - || Number(await browser.storage.local.getBytesInUse?.()) > 0 + await getStorageBytesInUse('sync') > 0 + || Number(await getStorageBytesInUse('local')) > 0 ); } diff --git a/source/helpers/types.d.ts b/source/helpers/types.d.ts index 06f4cb80..e3224b49 100644 --- a/source/helpers/types.d.ts +++ b/source/helpers/types.d.ts @@ -15,4 +15,9 @@ declare global { closest<S extends string>(selector: S | readonly S[]): StrictlyParseSelector<S, HTMLElement> | null; matches(selectors: string | readonly string[]): boolean; } + + // This cannot be a regular import because it turns `globals.d.ts` in a "module definition", which it isn't + type Browser = import('webextension-polyfill').Browser; + const browser: Browser; + } diff --git a/source/helpers/used-storage.ts b/source/helpers/used-storage.ts new file mode 100644 index 00000000..8a95bf18 --- /dev/null +++ b/source/helpers/used-storage.ts @@ -0,0 +1,10 @@ +/** `getBytesInUse` polyfill */ +export default async function getStorageBytesInUse(area: 'local' | 'sync'): Promise<any> { + const storage = browser.storage[area]; + // From https://bugzilla.mozilla.org/show_bug.cgi?id=1385832#c20 + return 'getBytesInUse' in storage ? storage.getBytesInUse() : new TextEncoder().encode( + Object.entries(await storage.get()) + .map(([key, value]) => key + JSON.stringify(value)) + .join(''), + ).length; +} diff --git a/source/options.css b/source/options.css index c6b7972d..f8001c89 100644 --- a/source/options.css +++ b/source/options.css @@ -47,6 +47,10 @@ details { margin-bottom: 1em; } +output { + font-style: italic; +} + details[open] { --border-left: 4px; border-left: solid var(--border-left) #aaa4; diff --git a/source/options.html b/source/options.html index c5925a53..62fb6727 100644 --- a/source/options.html +++ b/source/options.html @@ -1,6 +1,7 @@ <!doctype html> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"> +<base target="_blank"> <title>Refined GitHub options</title> <link rel="stylesheet" href="options.css"> <form id="options-form" class="detail-view-container"> @@ -41,6 +42,8 @@ <summary><strong>💅 Custom CSS</strong></summary> <p>Like a userstyle, useful to undo unwanted style changes</p> <p><textarea name="customCSS" rows="2" spellcheck="false"></textarea></p> + <p>CSS is limited to 100KB, after which the options <a href="https://github.com/fregante/webext-options-sync/issues/27">will stop being saved</a>.</p> + <p>Options storage: <output class="storage-sync">unknown</output></p> </details> <details id="action"> @@ -77,6 +80,10 @@ </label> </p> <p> + Options storage: <output class="storage-sync">unknown</output><br> + Cache storage: <output class="storage-local">unknown</output> + </p> + <p> <button id="clear-cache">Clear cache</button> </p> diff --git a/source/options.tsx b/source/options.tsx index 9a763615..2d8b56e5 100644 --- a/source/options.tsx +++ b/source/options.tsx @@ -5,16 +5,18 @@ import cache from 'webext-storage-cache'; import domify from 'doma'; import select from 'select-dom'; import fitTextarea from 'fit-textarea'; +import prettyBytes from 'pretty-bytes'; import {assertError} from 'ts-extras'; import * as indentTextarea from 'indent-textarea'; import delegate, {DelegateEvent} from 'delegate-it'; -import {isChrome, isFirefox, isSafari} from 'webext-detect-page'; +import {isChrome, isFirefox} from 'webext-detect-page'; import featureLink from './helpers/feature-link'; import clearCacheHandler from './helpers/clear-cache-handler'; import {getLocalHotfixes} from './helpers/hotfix'; import {createRghIssueLink} from './helpers/rgh-issue-link'; import {importedFeatures, featuresMeta} from '../readme.md'; +import getStorageBytesInUse from './helpers/used-storage'; import {isBrowserActionAPopup, perDomainOptions} from './options-storage'; type Status = { @@ -74,6 +76,19 @@ function expandTokenSection(): void { select('details#token')!.open = true; } +async function updateStorageUsage(area: 'sync' | 'local'): Promise<void> { + const storage = browser.storage[area]; + const used = await getStorageBytesInUse(area); + const available = storage.QUOTA_BYTES - used; + for (const output of select.all(`.storage-${area}`)) { + output.textContent = available < 1000 + ? 'FULL!' + : (available < 100_000 + ? `Only ${prettyBytes(available)} available` + : `${prettyBytes(used)} used`); + } +} + async function validateToken(): Promise<void> { reportStatus({}); const tokenField = select('input[name="personalToken"]')!; @@ -241,6 +256,15 @@ async function generateDom(): Promise<void> { // Update rate link if necessary updateRateLink(); + + // Update storage usage info + void updateStorageUsage('local'); + void updateStorageUsage('sync'); + + // Hide non-applicable "Button link" section + if (isBrowserActionAPopup) { + select('#action')!.hidden = true; + } } function addEventListeners(): void { @@ -260,6 +284,11 @@ function addEventListeners(): void { location.reload(); }); + // Update storage usage info + browser.storage.onChanged.addListener((_, areaName) => { + void updateStorageUsage(areaName as 'sync' | 'local'); + }); + // Improve textareas editing fitTextarea.watch('textarea'); indentTextarea.watch('textarea'); @@ -281,19 +310,6 @@ function addEventListeners(): void { // Add token validation select('[name="personalToken"]')!.addEventListener('input', validateToken); - - // Ensure all links open in a new tab #3181 - delegate('a[href^="http"]', 'click', event => { - if (!event.defaultPrevented) { - event.preventDefault(); - window.open(event.delegateTarget.href); - } - }); - - // Hide non-applicable "Button link" section - if (isBrowserActionAPopup) { - select('#action')!.hidden = true; - } } async function init(): Promise<void> { @@ -302,11 +318,6 @@ async function init(): Promise<void> { // TODO: Storage cleanup #6421, Drop in June 2023 void browser.storage.local.remove('featuresAlreadySeen'); - - // Safari’s storage is inexplicably limited #4823 - if (isSafari()) { - void cache.clear(); - } } void init(); |