Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clients(extension): always show settings, add psi frontend #15526

Merged
merged 5 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 47 additions & 42 deletions clients/extension/popup.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,54 +19,59 @@
<img class="header__icon" src="images/lh_logo.svg" width="75" height="75"></svg>
<!-- <object data="images/lh_logo.svg" type="image/svg+xml"></object> -->
<button class="button button--generate">Generate report</button>
<button class="button button--configure">
<svg class="gear__icon" width="25" height="25" viewBox="0 0 14 15">
<path fill="#fff" d="M-1-1h16v17H-1z" />
<path fill="currentColor" d="M12.526 8.07c.029-.224.05-.448.05-.686 0-.238-.021-.462-.05-.686l1.518-1.155a.347.347 0 0 0 .087-.448l-1.44-2.422a.367.367 0 0 0-.439-.154l-1.791.7a5.295 5.295 0 0 0-1.217-.686L8.971.678a.348.348 0 0 0-.353-.294H5.74a.348.348 0 0 0-.353.294l-.273 1.855a5.568 5.568 0 0 0-1.216.686l-1.792-.7a.356.356 0 0 0-.44.154L.228 5.095a.339.339 0 0 0 .087.448l1.518 1.155c-.029.224-.05.455-.05.686 0 .23.021.462.05.686L.314 9.225a.347.347 0 0 0-.087.448l1.44 2.422c.086.154.28.21.439.154l1.792-.7c.374.28.777.51 1.216.686l.273 1.855a.348.348 0 0 0 .353.294h2.878c.18 0 .331-.126.353-.294l.273-1.855a5.568 5.568 0 0 0 1.217-.686l1.792.7c.165.063.352 0 .438-.154l1.44-2.422a.347.347 0 0 0-.087-.448L12.526 8.07zM7.179 9.834c-1.389 0-2.519-1.1-2.519-2.45 0-1.351 1.13-2.45 2.52-2.45 1.388 0 2.518 1.099 2.518 2.45 0 1.35-1.13 2.45-2.519 2.45z" />
</svg>
</button>
<span class="psi-disclaimer"><a href="https://developers.google.com/speed/docs/insights/v5/get-started?utm_source=lh-chrome-ext" title="https://developers.google.com/speed/docs/insights/v5/get-started" target="_blank" rel="noopener nofollow">Uses the PSI API</a></span>
<div class="errormsg"></div>
</div>
<div class="section section--secondary-panel">
<div class="hidden browser-brand browser-brand--chrome">
<h2 class="section--header">Chrome DevTools</h2>
<span class="section--description">
You can also run Lighthouse via the DevTools Lighthouse panel.
<br><br>
Shortcut to open DevTools: <span class="devtools-shortcut"><!-- filled dynamically --></span>
</span>
</div>
<div class="hidden browser-brand browser-brand--firefox">
<h2 class="section--header">Node CLI</h2>
<span class="section--description">
You can also run Lighthouse via the <a href="https://github.com/GoogleChrome/lighthouse#using-the-node-cli">Node CLI</a>.
</span>
</div>
<div class="section section--options">
<form class="options__form">
<div class="options__group">
<h3 class="options__title">Show results in:</h3>
<ul class="options__list options__backend">
<!-- filled dynamically -->
</ul>
</div>

<div class="options__group">
<h3 class="options__title">Device</h2>
<ul class="options__list options__device">
<li>
<label>
<input type="radio" name="device" value="mobile"></input><span>Mobile</span>
</label>
</li>
<li>
<label>
<input type="radio" name="device" value="desktop"></input><span>Desktop</span>
</label>
</li>
</ul>
</div>

<div class="options__group">
<h3 class="options__title">Categories</h3>
<ul class="options__list options__categories">
<!-- filled dynamically -->
</ul>
</div>
</form>
</div>
</main>

<aside class="section section--options">
<form class="options__form">
<h3 class="options__title">Categories</h3>
<ul class="options__list options__categories">
<!-- filled dynamically -->
</ul>

<h3 class="options__title">Device</h2>
<ul class="options__list options__device">
<li>
<label>
<input type="radio" name="device" value="mobile"></input><span>Mobile</span>
</label>
</li>
<li>
<label>
<input type="radio" name="device" value="desktop"></input><span>Desktop</span>
</label>
</li>
</ul>
</form>
<aside class="section section--secondary-panel">
<div class="hidden browser-brand browser-brand--chrome">
<h2 class="section--header">Chrome DevTools</h2>
<span class="section--description">
This extension uses the PSI API, so it cannot be used to test sites hosted locally or behind auth. Instead, you can run Lighthouse via the DevTools Lighthouse panel.
<br><br>
Shortcut to open DevTools: <span class="devtools-shortcut"><!-- filled dynamically --></span>
</span>
</div>
<div class="hidden browser-brand browser-brand--firefox">
<h2 class="section--header">Node CLI</h2>
<span class="section--description">
This extension uses the PSI API, so it cannot be used to test sites hosted locally or behind auth. Instead, you can run Lighthouse via the <a href="https://github.com/GoogleChrome/lighthouse#using-the-node-cli">Node CLI</a>.
</span>
</div>
</aside>

<script src="scripts/popup-bundle.js"></script>
Expand Down
95 changes: 76 additions & 19 deletions clients/extension/scripts/popup.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@

import * as SettingsController from './settings-controller.js';

const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/';
const optionsVisibleClass = 'main--options-visible';
// Replaced with 'chrome' or 'firefox' in the build script.
/** @type {string} */
const BROWSER_BRAND = '___BROWSER_BRAND___';
Expand Down Expand Up @@ -61,17 +59,54 @@ function createOptionItem(text, id, isChecked) {
return listItem;
}

/**
* @param {string} name
* @param {string} text
* @param {string} id
* @param {boolean} isChecked
* @return {HTMLLIElement}
*/
function createRadioItem(name, text, id, isChecked) {
const input = document.createElement('input');
input.setAttribute('type', 'radio');
input.setAttribute('value', id);
input.setAttribute('name', name);
if (isChecked) {
input.setAttribute('checked', 'checked');
}

const label = document.createElement('label');
const span = document.createElement('span');
span.textContent = text;
label.append(input, span);
const listItem = document.createElement('li');
listItem.append(label);

return listItem;
}

/**
* Click event handler for Generate Report button.
* @param {string} backend
* @param {string} url
* @param {SettingsController.Settings} settings
*/
function onGenerateReportButtonClick(url, settings) {
const apiUrl = new URL(VIEWER_URL);
apiUrl.searchParams.append('psiurl', url);
apiUrl.searchParams.append('strategy', settings.device);
for (const category of settings.selectedCategories) {
apiUrl.searchParams.append('category', category);
function onGenerateReportButtonClick(backend, url, settings) {
let apiUrl;
if (backend === 'psi') {
apiUrl = new URL('https://pagespeed.web.dev/analysis');
apiUrl.searchParams.append('url', url);
apiUrl.searchParams.append('form_factor', settings.device);
for (const category of settings.selectedCategories) {
apiUrl.searchParams.append('category', category);
}
} else {
apiUrl = new URL('https://googlechrome.github.io/lighthouse/viewer/');
apiUrl.searchParams.append('psiurl', url);
apiUrl.searchParams.append('strategy', settings.device);
for (const category of settings.selectedCategories) {
apiUrl.searchParams.append('category', category);
}
}
apiUrl.searchParams.append('utm_source', 'lh-chrome-ext');
window.open(apiUrl.href);
Expand All @@ -82,7 +117,7 @@ function onGenerateReportButtonClick(url, settings) {
* for the categories.
* @param {SettingsController.Settings} settings
*/
function generateOptionsList(settings) {
function generateCategoryOptionsList(settings) {
const frag = document.createDocumentFragment();

SettingsController.DEFAULT_CATEGORIES.forEach(category => {
Expand All @@ -94,6 +129,31 @@ function generateOptionsList(settings) {
optionsCategoriesList.append(frag);
}


/**
* Generates a document fragment containing a list of backends.
* @param {SettingsController.Settings} settings
*/
function generateBackendOptionsList(settings) {
const frag = document.createDocumentFragment();

SettingsController.BACKENDS.forEach(backend => {
const isChecked = settings.backend === backend.id;
frag.append(createRadioItem('backend', backend.title, backend.id, isChecked));
});

const optionsCategoriesList = find('.options__backend');
optionsCategoriesList.append(frag);
}

/**
* @param {SettingsController.Settings} settings
*/
function configureVisibleSettings(settings) {
const optionsCategoriesList = find('.options__categories');
optionsCategoriesList.parentElement?.classList.toggle('hidden', settings.backend === 'psi');
}

function fillDevToolsShortcut() {
const el = find('.devtools-shortcut');
const isMac = /mac/i.test(navigator.platform);
Expand All @@ -107,11 +167,13 @@ function fillDevToolsShortcut() {
function readSettingsFromDomAndPersist() {
const optionsEl = find('.section--options');
// Save settings when options page is closed.
const backend = find('.options__backend input:checked').value;
const checkboxes = optionsEl.querySelectorAll('.options__categories input:checked');
const selectedCategories = Array.from(checkboxes).map(input => input.value);
const device = find('input[name="device"]:checked').value;

const settings = {
backend,
selectedCategories,
device,
};
Expand Down Expand Up @@ -151,10 +213,7 @@ async function initPopup() {
const browserBrandEl = find(`.browser-brand--${BROWSER_BRAND}`);
browserBrandEl.classList.remove('hidden');

const mainEl = find('main');
const optionsEl = find('.button--configure');
const generateReportButton = find('button.button--generate');
const configureButton = find('button.button--configure');
const psiDisclaimerEl = find('.psi-disclaimer');
const errorMessageEl = find('.errormsg');
const optionsFormEl = find('.options__form');
Expand All @@ -171,27 +230,25 @@ async function initPopup() {
// but it's very hard to keep an extension popup alive during a popup
// so we don't need to handle reacting to it.
generateReportButton.disabled = true;
configureButton.disabled = true;
psiDisclaimerEl.remove();
errorMessageEl.textContent = err.message;
return;
}

// Generate checkboxes from saved settings.
generateOptionsList(settings);
generateBackendOptionsList(settings);
generateCategoryOptionsList(settings);
configureVisibleSettings(settings);
const selectedDeviceEl = find(`.options__device input[value="${settings.device}"]`);
selectedDeviceEl.checked = true;

generateReportButton.addEventListener('click', () => {
onGenerateReportButtonClick(siteUrl.href, settings);
});

optionsEl.addEventListener('click', () => {
mainEl.classList.toggle(optionsVisibleClass);
onGenerateReportButtonClick(settings.backend, siteUrl.href, settings);
});

optionsFormEl.addEventListener('change', () => {
settings = readSettingsFromDomAndPersist();
configureVisibleSettings(settings);
});
}

Expand Down
15 changes: 14 additions & 1 deletion clients/extension/scripts/settings-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
* SPDX-License-Identifier: Apache-2.0
*/

const BACKENDS = [{
id: 'psi',
title: 'PSI Frontend (pagespeed.web.dev)',
}, {
id: 'viewer',
title: 'Lighthouse Viewer (googlechrome.github.io)',
}];

// Manually define the default categories, instead of bundling a lot of i18n code.
const DEFAULT_CATEGORIES = [{
id: 'performance',
Expand All @@ -22,7 +30,7 @@ const DEFAULT_CATEGORIES = [{
title: 'PWA',
}];

/** @typedef {{selectedCategories: string[], device: string}} Settings */
/** @typedef {{backend: string, selectedCategories: string[], device: string}} Settings */

const STORAGE_KEYS = {
Categories: 'lighthouse_audits',
Expand Down Expand Up @@ -50,6 +58,9 @@ function saveSettings(settings) {
// Stash device setting.
storage[STORAGE_KEYS.Settings].device = settings.device;

// Stash backend setting.
storage[STORAGE_KEYS.Settings].backend = settings.backend;

// Save object to chrome local storage.
chrome.storage.local.set(storage);
}
Expand Down Expand Up @@ -81,6 +92,7 @@ function loadSettings() {
const savedSettings = {...defaultSettings, ...result[STORAGE_KEYS.Settings]};

resolve({
backend: savedSettings.backend ?? 'psi',
device: savedSettings.device,
selectedCategories: Object.keys(savedCategories).filter(cat => savedCategories[cat]),
});
Expand All @@ -89,6 +101,7 @@ function loadSettings() {
}

export {
BACKENDS,
DEFAULT_CATEGORIES,
STORAGE_KEYS,
saveSettings,
Expand Down
Loading
Loading