Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(336)

Unified Diff: third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js

Issue 2851213005: DevTools: brush up audits 2 launcher UI, allow multiple audit runs, introduce landing page. (Closed)
Patch Set: for landing Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
diff --git a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
index 603a5c5b2751378bf71057eaf1d8d22b234553e3..4a03dc6eb8f05ebb8d52b524ec3a8ba2f6b24d17 100644
--- a/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
+++ b/third_party/WebKit/Source/devtools/front_end/audits2/Audits2Panel.js
@@ -5,7 +5,7 @@
/**
* @unrestricted
*/
-Audits2.Audits2Panel = class extends UI.Panel {
+Audits2.Audits2Panel = class extends UI.PanelWithSidebar {
constructor() {
super('audits2');
this.setHideOnDetach();
@@ -15,44 +15,100 @@ Audits2.Audits2Panel = class extends UI.Panel {
this._protocolService = new Audits2.ProtocolService();
this._protocolService.registerStatusCallback(msg => this._updateStatus(Common.UIString(msg)));
- this._settings = Audits2.Audits2Panel.Presets.map(preset => {
- const setting = Common.settings.createSetting(preset.id, true);
- setting.setTitle(Common.UIString(preset.description));
- return setting;
- });
+ var toolbar = new UI.Toolbar('', this.panelSidebarElement());
+
+ var newButton = new UI.ToolbarButton(Common.UIString('New audit\u2026'), 'largeicon-add');
+ toolbar.appendToolbarItem(newButton);
+ newButton.addEventListener(UI.ToolbarButton.Events.Click, this._showLauncherUI.bind(this));
+
+ var deleteButton = new UI.ToolbarButton(Common.UIString('Delete audit'), 'largeicon-delete');
+ toolbar.appendToolbarItem(deleteButton);
+ deleteButton.addEventListener(UI.ToolbarButton.Events.Click, this._deleteSelected.bind(this));
+
+ toolbar.appendSeparator();
+
+ var clearButton = new UI.ToolbarButton(Common.UIString('Clear all'), 'largeicon-clear');
+ toolbar.appendToolbarItem(clearButton);
+ clearButton.addEventListener(UI.ToolbarButton.Events.Click, this._clearAll.bind(this));
+
+ this._treeOutline = new UI.TreeOutlineInShadow();
+ this._treeOutline.registerRequiredCSS('audits2/lighthouse/report-styles.css');
+ this._treeOutline.registerRequiredCSS('audits2/audits2Tree.css');
+ this.panelSidebarElement().appendChild(this._treeOutline.element);
+
+ this._dropTarget = new UI.DropTarget(
+ this.contentElement, [UI.DropTarget.Types.Files],
+ Common.UIString('Drop audit file here'), this._handleDrop.bind(this));
- var auditsViewElement = this.contentElement.createChild('div', 'hbox audits2-view');
- this._resultsView = this.contentElement.createChild('div', 'vbox results-view');
- this._createLauncherUI(auditsViewElement);
+ this._showLandingPage();
}
- _reset() {
- this.contentElement.classList.remove('show-results');
- this._resultsView.removeChildren();
+ _clearAll() {
+ this._treeOutline.removeChildren();
+ if (!this._treeOutline.rootElement().childCount())
+ this._showLandingPage();
}
- /**
- * @param {!Element} auditsViewElement
- */
- _createLauncherUI(auditsViewElement) {
- auditsViewElement.createChild('div', 'audits2-logo');
+ _deleteSelected() {
+ var selection = this._treeOutline.selectedTreeElement;
+ if (selection)
+ this._treeOutline.removeChild(selection);
+ if (!this._treeOutline.rootElement().childCount())
+ this._showLandingPage();
+ }
+
+ _showLandingPage() {
+ this.mainElement().removeChildren();
+ var landingPage = this.mainElement().createChild('div', 'vbox audits2-landing-page');
+ var landingCenter = landingPage.createChild('div', 'vbox audits2-landing-center');
+ landingCenter.createChild('div', 'audits2-logo');
+ var text = landingCenter.createChild('div', 'audits2-landing-text');
+ text.createChild('span', 'audits2-landing-bold-text').textContent = Common.UIString('Audits');
+ text.createChild('span').textContent = Common.UIString(' help you identify and fix common problems that affect' +
+ ' your site\'s performance, accessibility, and user experience. ');
+ var link = text.createChild('span', 'link');
+ link.textContent = Common.UIString('Learn more');
+ link.addEventListener(
+ 'click', () => InspectorFrontendHost.openInNewTab('https://developers.google.com/web/tools/lighthouse/'));
+
+ var newButton = UI.createTextButton(
+ Common.UIString('Perform an audit\u2026'), this._showLauncherUI.bind(this), 'material-button default');
+ landingCenter.appendChild(newButton);
+ }
+
+ _showLauncherUI() {
+ this._dialog = new UI.Dialog();
+ this._dialog.setOutsideClickCallback(event => event.consume(true));
+ var root = UI.createShadowRootWithCoreStyles(this._dialog.contentElement, 'audits2/audits2Dialog.css');
+ var auditsViewElement = root.createChild('div', 'audits2-view');
var uiElement = auditsViewElement.createChild('div');
var headerElement = uiElement.createChild('header');
- headerElement.createChild('p').textContent = Common.UIString(
- 'Audits will analyze the page against modern development best practices and collect useful performance metrics and diagnostics. Select audits to collect:');
+ headerElement.createChild('p').textContent = Common.UIString('Audits to perform');
uiElement.appendChild(headerElement);
var auditSelectorForm = uiElement.createChild('form', 'audits2-form');
- this._settings
- .map(setting => new UI.ToolbarSettingCheckbox(setting))
- .forEach(checkbox => auditSelectorForm.appendChild(checkbox.element));
+ for (var preset of Audits2.Audits2Panel.Presets) {
+ preset.setting.setTitle(preset.title);
+ var checkbox = new UI.ToolbarSettingCheckbox(preset.setting);
+ var row = auditSelectorForm.createChild('div', 'vbox audits2-launcher-row');
+ row.appendChild(checkbox.element);
+ row.createChild('span', 'audits2-launcher-description dimmed').textContent = preset.description;
+ }
- this._startButton = UI.createTextButton(
- Common.UIString('Audit this page'), this._startButtonClicked.bind(this), 'run-audit audit-btn');
+ this._startButton =
+ UI.createTextButton(Common.UIString('Run audit'), this._start.bind(this), 'material-button default');
auditSelectorForm.appendChild(this._startButton);
+ this._cancelButton = UI.createTextButton(Common.UIString('Cancel'), this._cancel.bind(this), 'material-button');
+ auditSelectorForm.appendChild(this._cancelButton);
this._statusView = this._createStatusView(uiElement);
+
+ this._dialog.setSizeBehavior(UI.GlassPane.SizeBehavior.SetExactWidthMaxHeight);
+ this._dialog.setMaxContentSize(new UI.Size(600, 400));
+ this._dialog.show(this.mainElement());
+ auditsViewElement.tabIndex = 0;
+ auditsViewElement.focus();
}
/**
@@ -68,45 +124,59 @@ Audits2.Audits2Panel = class extends UI.Panel {
}
_start() {
+ this._dialog.setCloseOnEscape(false);
this._inspectedURL = SDK.targetManager.mainTarget().inspectedURL();
- const categoryIDs = this._settings.map(setting => {
- const preset = Audits2.Audits2Panel.Presets.find(preset => preset.id === setting.name);
- return {configID: preset.configID, value: setting.get()};
- }).filter(agg => !!agg.value).map(agg => agg.configID);
+ var categoryIDs = [];
+ for (var preset of Audits2.Audits2Panel.Presets) {
+ if (preset.setting.get())
+ categoryIDs.push(preset.configID);
+ }
return Promise.resolve()
.then(_ => this._protocolService.attach())
.then(_ => {
this._auditRunning = true;
this._updateButton();
- this._updateStatus(Common.UIString('Loading...'));
+ this._updateStatus(Common.UIString('Loading\u2026'));
})
.then(_ => this._protocolService.startLighthouse(this._inspectedURL, categoryIDs))
.then(lighthouseResult => {
this._finish(lighthouseResult);
return this._stop();
- }).catch(err => {
- if (err instanceof Error) this._renderBugReport(err);
+ })
+ .catch(err => {
+ if (err instanceof Error)
+ this._renderBugReport(err);
});
}
- /**
- * @param {!Event} event
- */
- _startButtonClicked(event) {
+ _hideDialog() {
+ if (!this._dialog)
+ return;
+ this._dialog.hide();
+ delete this._dialog;
+ delete this._statusView;
+ delete this._statusIcon;
+ delete this._statusElement;
+ delete this._startButton;
+ delete this._cancelButton;
+ }
+
+ _cancel() {
if (this._auditRunning) {
- this._updateStatus(Common.UIString('Cancelling...'));
+ this._updateStatus(Common.UIString('Cancelling\u2026'));
this._stop();
- return;
+ } else {
+ this._hideDialog();
}
- this._start();
}
_updateButton() {
- this._startButton.textContent =
- this._auditRunning ? Common.UIString('Cancel audit') : Common.UIString('Audit this page');
- this._startButton.classList.toggle('started', this._auditRunning);
+ if (!this._dialog)
+ return;
+ this._startButton.classList.toggle('default', !this._auditRunning);
+ this._startButton.disabled = this._auditRunning;
this._statusView.classList.toggle('hidden', !this._auditRunning);
}
@@ -114,6 +184,8 @@ Audits2.Audits2Panel = class extends UI.Panel {
* @param {string} statusMessage
*/
_updateStatus(statusMessage) {
+ if (!this._dialog)
+ return;
this._statusElement.textContent = statusMessage;
}
@@ -126,8 +198,9 @@ Audits2.Audits2Panel = class extends UI.Panel {
this._updateButton();
var resourceTreeModel = SDK.targetManager.mainTarget().model(SDK.ResourceTreeModel);
if (resourceTreeModel && this._inspectedURL !== SDK.targetManager.mainTarget().inspectedURL())
- resourceTreeModel.navigate(this._inspectedURL);
-
+ resourceTreeModel.navigate(this._inspectedURL).then(() => this._hideDialog());
+ else
+ this._hideDialog();
});
}
@@ -139,13 +212,11 @@ Audits2.Audits2Panel = class extends UI.Panel {
this._updateStatus(Common.UIString('Auditing failed.'));
return;
}
- this._resultsView.removeChildren();
-
- var url = lighthouseResult.url;
- var timestamp = lighthouseResult.generatedTime;
- this._createResultsBar(this._resultsView, url, timestamp);
- this._renderReport(this._resultsView, lighthouseResult);
- this.contentElement.classList.add('show-results');
+ var treeElement = new Audits2.Audits2Panel.TreeElement(lighthouseResult, this.mainElement());
+ this._treeOutline.appendChild(treeElement);
+ treeElement._populate();
+ treeElement.select();
+ this._hideDialog();
}
/**
@@ -179,55 +250,40 @@ Audits2.Audits2Panel = class extends UI.Panel {
}
/**
- * @param {!Element} resultsView
- * @param {!ReportRenderer.ReportJSON} lighthouseResult
- * @suppressGlobalPropertiesCheck
+ * @param {!DataTransfer} dataTransfer
*/
- _renderReport(resultsView, lighthouseResult) {
- var reportContainer = resultsView.createChild('div', 'report-container lh-root');
-
- var dom = new DOM(document);
- var detailsRenderer = new DetailsRenderer(dom);
- var categoryRenderer = new CategoryRenderer(dom, detailsRenderer);
- var renderer = new Audits2.ReportRenderer(dom, categoryRenderer);
-
- var templatesHTML = Runtime.cachedResources['audits2/lighthouse/templates.html'];
- var templatesDOM = new DOMParser().parseFromString(templatesHTML, 'text/html');
- if (!templatesDOM)
+ _handleDrop(dataTransfer) {
+ var items = dataTransfer.items;
+ if (!items.length)
return;
-
- renderer.setTemplateContext(templatesDOM);
- renderer.renderReport(lighthouseResult, reportContainer);
+ var item = items[0];
+ if (item.kind === 'file') {
+ var entry = items[0].webkitGetAsEntry();
+ if (!entry.isFile)
+ return;
+ entry.file(file => {
+ var reader = new FileReader();
+ reader.onload = () => this._loadedFromFile(/** @type {string} */ (reader.result));
+ reader.readAsText(file);
+ });
+ }
}
/**
- * @param {!Element} resultsView
- * @param {string} url
- * @param {string} timestamp
+ * @param {string} profile
*/
- _createResultsBar(resultsView, url, timestamp) {
- var elem = resultsView.createChild('div', 'results-bar hbox');
- elem.createChild('div', 'audits2-logo audits2-logo-small');
-
- var summaryElem = elem.createChild('div', 'audits2-summary');
- var reportFor = summaryElem.createChild('span');
- reportFor.createTextChild('Report for ');
- var urlElem = reportFor.createChild('b');
- urlElem.textContent = url;
- var timeElem = summaryElem.createChild('span');
- timeElem.textContent =
- `Generated at ${new Date(timestamp).toLocaleDateString()} ${new Date(timestamp).toLocaleTimeString()}`;
-
- var newAuditButton =
- UI.createTextButton(Common.UIString('New Audit'), this._reset.bind(this), 'new-audit audit-btn');
- elem.appendChild(newAuditButton);
+ _loadedFromFile(profile) {
+ var data = JSON.parse(profile);
+ if (!data['lighthouseVersion'])
+ return;
+ this._finish(/** @type {!ReportRenderer.ReportJSON} */(data));
}
};
/**
* @override
*/
-Audits2.ReportRenderer = class extends ReportRenderer {
+Audits2.Audits2Panel.ReportRenderer = class extends ReportRenderer {
/**
* Provides empty element for left nav
* @override
@@ -236,26 +292,55 @@ Audits2.ReportRenderer = class extends ReportRenderer {
_renderReportNav() {
return createDocumentFragment();
}
-};
+ /**
+ * @param {!ReportRenderer.ReportJSON} report
+ * @override
+ * @return {!DocumentFragment}
+ */
+ _renderReportHeader(report) {
+ return createDocumentFragment();
+ }
+};
class ReportUIFeatures {
/**
* @param {!ReportRenderer.ReportJSON} report
*/
- initFeatures(report) {}
+ initFeatures(report) {
+ }
}
-/** @typedef {{id: string, configID: string, description: string}} */
+/** @typedef {{setting: !Common.Setting, configID: string, title: string, description: string}} */
Audits2.Audits2Panel.Preset;
/** @type {!Array.<!Audits2.Audits2Panel.Preset>} */
Audits2.Audits2Panel.Presets = [
// configID maps to Lighthouse's Object.keys(config.categories)[0] value
- {id: 'audits2_cat_pwa', configID: 'pwa', description: 'Progressive Web App'},
- {id: 'audits2_cat_perf', configID: 'performance', description: 'Performance metrics and diagnostics'},
- {id: 'audits2_cat_a11y', configID: 'accessibility', description: 'Accessibility'},
- {id: 'audits2_cat_best_practices', configID: 'best-practices', description: 'Modern best practices'},
+ {
+ setting: Common.settings.createSetting('audits2.cat_pwa', true),
+ configID: 'pwa',
+ title: 'Progressive Web App',
+ description: 'Does this page meet the standard of a Progressive Web App'
+ },
+ {
+ setting: Common.settings.createSetting('audits2.cat_perf', true),
+ configID: 'performance',
+ title: 'Performance',
+ description: 'How long does this app take to show content and become usable'
+ },
+ {
+ setting: Common.settings.createSetting('audits2.cat_best_practices', true),
+ configID: 'best-practices',
+ title: 'Best practices',
+ description: 'Does this page follow best practices for modern web development'
+ },
+ {
+ setting: Common.settings.createSetting('audits2.cat_a11y', true),
+ configID: 'accessibility',
+ title: 'Accessibility',
+ description: 'Is this page usable by people with disabilities or impairments'
+ },
];
Audits2.ProtocolService = class extends Common.Object {
@@ -337,3 +422,117 @@ Audits2.ProtocolService = class extends Common.Object {
return this._backendPromise.then(_ => this._backend.send(method, params));
}
};
+
+Audits2.Audits2Panel.TreeElement = class extends UI.TreeElement {
+ /**
+ * @param {!ReportRenderer.ReportJSON} lighthouseResult
+ * @param {!Element} resultsView
+ */
+ constructor(lighthouseResult, resultsView) {
+ super('', false);
+ this._lighthouseResult = lighthouseResult;
+ this._resultsView = resultsView;
+ /** @type {?Element} */
+ this._reportContainer = null;
+
+ var url = new Common.ParsedURL(lighthouseResult.url);
+ var timestamp = lighthouseResult.generatedTime;
+ var titleElement = this.titleElement();
+ titleElement.classList.add('audits2-report-tree-item');
+ titleElement.createChild('div').textContent = url.domain();
+ titleElement.createChild('span', 'dimmed').textContent = new Date(timestamp).toLocaleString();
+ this.listItemElement.addEventListener('contextmenu', this._handleContextMenuEvent.bind(this), false);
+ }
+
+ _populate() {
+ for (var category of this._lighthouseResult.reportCategories) {
+ var treeElement = new Audits2.Audits2Panel.TreeSubElement(category.id, category.name, category.score);
+ this.appendChild(treeElement);
+ }
+ }
+
+ /**
+ * @override
+ * @param {boolean=} selectedByUser
+ * @return {boolean}
+ */
+ onselect(selectedByUser) {
+ this._renderReport();
+ return true;
+ }
+
+ /**
+ * @param {!Event} event
+ */
+ _handleContextMenuEvent(event) {
+ var contextMenu = new UI.ContextMenu(event);
+ contextMenu.appendItem(Common.UIString('Save as\u2026'), () => {
+ var url = new Common.ParsedURL(this._lighthouseResult.url).domain();
+ var timestamp = this._lighthouseResult.generatedTime;
+ var fileName = `${url}-${new Date(timestamp).toISO8601Compact()}.json`;
+ Workspace.fileManager.save(fileName, JSON.stringify(this._lighthouseResult), true);
+ });
+ contextMenu.show();
+ }
+
+ /**
+ * @override
+ */
+ onunbind() {
+ if (this._reportContainer && this._reportContainer.parentElement)
+ this._reportContainer.remove();
+ }
+
+ _renderReport() {
+ this._resultsView.removeChildren();
+ if (this._reportContainer) {
+ this._resultsView.appendChild(this._reportContainer);
+ return;
+ }
+
+ this._reportContainer = this._resultsView.createChild('div', 'report-container lh-root');
+
+ var dom = new DOM(/** @type {!Document} */(this._resultsView.ownerDocument));
+ var detailsRenderer = new DetailsRenderer(dom);
+ var categoryRenderer = new CategoryRenderer(dom, detailsRenderer);
+ var renderer = new Audits2.Audits2Panel.ReportRenderer(dom, categoryRenderer);
+
+ var templatesHTML = Runtime.cachedResources['audits2/lighthouse/templates.html'];
+ var templatesDOM = new DOMParser().parseFromString(templatesHTML, 'text/html');
+ if (!templatesDOM)
+ return;
+
+ renderer.setTemplateContext(templatesDOM);
+ renderer.renderReport(this._lighthouseResult, this._reportContainer);
+ }
+};
+
+Audits2.Audits2Panel.TreeSubElement = class extends UI.TreeElement {
+ /**
+ * @param {string} id
+ * @param {string} name
+ * @param {number} score
+ */
+ constructor(id, name, score) {
+ super('');
+ this._id = id;
+ this.listItemElement.textContent = name;
+ var label = Util.calculateRating(score);
+ var subtitleElement = this.listItemElement.createChild('span', 'lh-root audits2-tree-subtitle-' + label);
+ subtitleElement.textContent = String(Math.round(score));
+ }
+
+ /**
+ * @override
+ * @return {boolean}
+ */
+ onselect() {
+ this.parent._renderReport();
+ var node = this.parent._resultsView.querySelector('.lh-category[id=' + this._id + ']');
+ if (node) {
+ node.scrollIntoView(true);
+ return true;
+ }
+ return false;
+ }
+};

Powered by Google App Engine
This is Rietveld 408576698