diff --git a/src/components/NimbledroidGraph/index.jsx b/src/components/NimbledroidGraph/index.jsx
index f7d27e38..14ae0332 100644
--- a/src/components/NimbledroidGraph/index.jsx
+++ b/src/components/NimbledroidGraph/index.jsx
@@ -4,11 +4,6 @@ import PropTypes from 'prop-types';
import MetricsGraphics from 'react-metrics-graphics';
class NimbledroidGraph extends Component {
- constructor(props) {
- super(props);
- this.legendTarget = null;
- }
-
render() {
const { profile, targetRatio } = this.props;
const labels = Object.keys(profile.data);
@@ -16,22 +11,22 @@ class NimbledroidGraph extends Component {
const target = targetRatio * profile.WV;
return (
-
-
this.legendTarget = ele} />
-
-
+
);
}
}
diff --git a/src/components/StatusWidget/Title.jsx b/src/components/StatusWidget/Title.jsx
new file mode 100644
index 00000000..19d3d1ad
--- /dev/null
+++ b/src/components/StatusWidget/Title.jsx
@@ -0,0 +1,17 @@
+import PropTypes from 'prop-types';
+
+const Title = ({ enrich, hyperlink, text, tooltip }) => {
+ const className = enrich ? 'enrich' : '';
+ const span =
{text};
+ return (hyperlink) ?
+
{span} : span;
+};
+
+Title.propTypes = ({
+ enrich: PropTypes.bool,
+ hyperlink: PropTypes.string,
+ text: PropTypes.string.isRequired,
+ tooltip: PropTypes.string,
+});
+
+export default Title;
diff --git a/src/components/StatusWidget/index.jsx b/src/components/StatusWidget/index.jsx
index c644dae9..07abdfd6 100644
--- a/src/components/StatusWidget/index.jsx
+++ b/src/components/StatusWidget/index.jsx
@@ -1,28 +1,20 @@
import PropTypes from 'prop-types';
+import Title from './Title';
const StatusWidget = ({
children, extraInfo,
title,
- summary, uid,
+ summary, statusColor, uid,
}) => {
- const { bgColor, emphasis, hyperlink, text, tooltip } = title;
- let $title = '';
- if (hyperlink) {
- $title =
{text};
- } else {
- $title =
{text};
- }
- if (emphasis) {
- $title =
{$title};
- }
+ const { bgColor } = title;
return (
- {$title}
+
{summary && {summary}}
{children &&
{children}
}
@@ -34,13 +26,8 @@ const StatusWidget = ({
StatusWidget.propTypes = ({
children: PropTypes.shape({}),
extraInfo: PropTypes.string,
- title: PropTypes.shape({
- text: PropTypes.string.isRequired,
- bgColor: PropTypes.string,
- emphasis: PropTypes.bool,
- hyperlink: PropTypes.string,
- tooltip: PropTypes.string,
- }).isRequired,
+ statusColor: PropTypes.string.isRequired,
+ title: PropTypes.shape().isRequired,
summary: PropTypes.string,
uid: PropTypes.string,
});
diff --git a/src/components/SummaryTable/index.jsx b/src/components/SummaryTable/index.jsx
index 5c2ce9e3..e543eae4 100644
--- a/src/components/SummaryTable/index.jsx
+++ b/src/components/SummaryTable/index.jsx
@@ -4,15 +4,16 @@ import StatusWidget from '../../components/StatusWidget';
const SummaryTable = ({ content, header }) => {
const $rows = content.map(({
- title,
dataPoints = [],
+ title,
+ statusColor,
summary,
uid,
}) => {
return (
-
+
|
{dataPoints.map((datum, index) => (
{datum} |
diff --git a/src/index.css b/src/index.css
index ad68fab5..a8824ea5 100644
--- a/src/index.css
+++ b/src/index.css
@@ -193,10 +193,10 @@ svg path {
}
}
-svg {
+/* svg {
height: 100%;
width: 100%;
-}
+} */
.graphic-details,
.graphic-timeline {
display: flex;
@@ -1060,6 +1060,11 @@ svg {
.status-widget {
display: flex;
justify-content: space-between;
+ white-space: nowrap;
+ .enrich {
+ font-size: 1em;
+ font-weight: bold;
+ }
}
.summary-table {
@@ -1070,13 +1075,21 @@ svg {
padding: 0 0 0 0.7em;
}
.title-container {
- max-width: 360px;
+ max-width: 480px;
overflow: hidden;
padding: 0;
text-align: left;
}
}
+.sites-table {
+ width: 800px;
+}
+.sites-overview {
+ margin: 1em auto 2em auto;
+ width: 480px;
+}
+
.status-red {
background-color: var(--newCoral);
}
@@ -1095,3 +1108,13 @@ svg {
.aligned-center {
margin: 0px auto;
}
+
+.error-message {
+ color: 'red';
+}
+
+.android-view {
+ background-color: white;
+ color: black;
+ padding: 1em;
+}
diff --git a/src/utils/BackendClient/NimbledroidApiHandler.js b/src/utils/BackendClient/NimbledroidApiHandler.js
index 080dde18..ecad4541 100644
--- a/src/utils/BackendClient/NimbledroidApiHandler.js
+++ b/src/utils/BackendClient/NimbledroidApiHandler.js
@@ -5,7 +5,7 @@ const renameProduct = product => (
);
const matchUrl = profileName => profileName
- .replace(/.*http[s]?:\/\/w*\.?(.*?)[/]?[)]/, (match, firstMatch) => firstMatch);
+ .replace(/.*(http[s]?:\/\/w*\.?.*?)[/]?[)]/, (match, firstMatch) => firstMatch);
const matchDomain = url => url
.replace(/([a-zA-Z0-9].*\.[a-z0-9]{1,61})\/.*/, (match, firstMatch) => firstMatch);
diff --git a/src/utils/nimbledroid/index.jsx b/src/utils/nimbledroid/index.jsx
index 84357a3e..f9881c49 100644
--- a/src/utils/nimbledroid/index.jsx
+++ b/src/utils/nimbledroid/index.jsx
@@ -38,7 +38,66 @@ const statusColor = (ratio, targetRatio) => {
export const siteMetrics = (GV, WV, targetRatio) => {
const ratio = ratioWithTarget(GV, WV, targetRatio);
- const symbol = percentageSymbol(GV, WV, targetRatio);
- const color = statusColor(ratio, targetRatio).widgetColor;
- return { ratio, symbol, color };
+ return {
+ ratio,
+ symbol: percentageSymbol(GV, WV, targetRatio),
+ color: statusColor(ratio, targetRatio).widgetColor,
+ };
+};
+
+const generateSitesSummary = (count, numSites) => (
+ [
+ {
+ title: {
+ text: 'GeckoView > 20% slower than WebView',
+ },
+ statusColor: 'red',
+ summary: `${count.red}/${numSites}`,
+ },
+ {
+ title: {
+ text: 'GeckoView > 0% and <= 20% slower than WebView',
+ },
+ statusColor: 'yellow',
+ summary: `${count.yellow}/${numSites}`,
+ },
+ {
+ title: {
+ text: 'GeckoView <= 0% (i.e. faster than) WebView',
+ },
+ statusColor: 'green',
+ summary: `${count.green}/${numSites}`,
+ },
+ ]
+);
+
+export const generateSitesTableContent = (nimbledroidData, targetRatio) => {
+ const numSites = Object.keys(nimbledroidData).length;
+ const sites = (numSites > 0) ?
+ Object.values(nimbledroidData).sort(sortSitesByTargetRatio) : [];
+ const count = {
+ red: 0,
+ yellow: 0,
+ green: 0,
+ };
+ const tableContent = sites.map(({ title, url, GV, WV }) => {
+ const { ratio, symbol, color } = siteMetrics(GV, WV, targetRatio);
+ count[color] += 1;
+ // This matches the format expected by the SummaryTable component
+ return {
+ dataPoints: [GV, WV],
+ statusColor: color,
+ summary: `${symbol}${((1 - ratio) * 100).toFixed(2)}%`,
+ title: {
+ text: url,
+ hyperlink: `android/graph?site=${url}`,
+ tooltip: url,
+ },
+ uid: url,
+ };
+ });
+ return {
+ tableContent,
+ summary: generateSitesSummary(count, numSites),
+ };
};
diff --git a/src/views/Android/SiteDrillDown.jsx b/src/views/Android/SiteDrillDown.jsx
new file mode 100644
index 00000000..198acdf6
--- /dev/null
+++ b/src/views/Android/SiteDrillDown.jsx
@@ -0,0 +1,41 @@
+import PropTypes from 'prop-types';
+import { siteMetrics } from '../../utils/nimbledroid';
+import GenericErrorBoundary from '../../components/genericErrorBoundary';
+import NimbledroidGraph from '../../components/NimbledroidGraph';
+import StatusWidget from '../../components/StatusWidget';
+
+const SiteDrillDown = ({ nimbledroidData, site, targetRatio }) => {
+ const { ratio, symbol, color } = siteMetrics(
+ nimbledroidData[site].GV,
+ nimbledroidData[site].WV,
+ targetRatio);
+ return (
+
+
+
+
+
+ );
+};
+
+SiteDrillDown.propTypes = ({
+ nimbledroidData: PropTypes.shape({
+ GV: PropTypes.string.isRequired,
+ WV: PropTypes.string.isRequired,
+ }).isRequired,
+ site: PropTypes.string.isRequired,
+ targetRatio: PropTypes.number.isRequired,
+});
+
+export default SiteDrillDown;
diff --git a/src/views/Android/SitesTable.jsx b/src/views/Android/SitesTable.jsx
new file mode 100644
index 00000000..88b80966
--- /dev/null
+++ b/src/views/Android/SitesTable.jsx
@@ -0,0 +1,37 @@
+import PropTypes from 'prop-types';
+import {
+ generateSitesTableContent,
+ siteMetrics,
+ sortSitesByTargetRatio,
+} from '../../utils/nimbledroid';
+import GenericErrorBoundary from '../../components/genericErrorBoundary';
+
+import SummaryTable from '../../components/SummaryTable';
+import StatusWidget from '../../components/StatusWidget';
+
+const SitesTable = ({ nimbledroidData, targetRatio }) => {
+ const { tableContent, summary } = generateSitesTableContent(nimbledroidData, targetRatio);
+ return (
+
+
+
+ {summary.map(s => (
+ ))}
+
+
+
+
+
+
+ );
+};
+
+SitesTable.propTypes = {
+ nimbledroidData: PropTypes.shape({}),
+ targetRatio: PropTypes.number.isRequired,
+};
+
+export default SitesTable;
diff --git a/src/views/Android/index.jsx b/src/views/Android/index.jsx
index 6e4caeae..f4ef506c 100644
--- a/src/views/Android/index.jsx
+++ b/src/views/Android/index.jsx
@@ -4,19 +4,9 @@ import propTypes from 'prop-types';
import Raven from 'raven-js';
import BackendClient from '../../utils/BackendClient';
-import {
- percentageSymbol,
- ratioWithTarget,
- siteMetrics,
- sortSitesByTargetRatio,
- statusColor,
-} from '../../utils/nimbledroid';
import Dashboard from '../../dashboard';
-import GenericErrorBoundary from '../../components/genericErrorBoundary';
-import NimbledroidGraph from '../../components/NimbledroidGraph';
-import SummaryTable from '../../components/SummaryTable';
-import StatusWidget from '../../components/StatusWidget';
-import Widget from '../../quantum/widget';
+import SitesTable from './SitesTable';
+import SiteDrillDown from './SiteDrillDown';
export default class Android extends Component {
static propTypes = {
@@ -59,113 +49,33 @@ export default class Android extends Component {
const { errorMessage, nimbledroidData } = this.state;
const numSites = Object.keys(nimbledroidData).length;
const targetRatio = 1.2;
- let $content = null;
- if (numSites > 0) {
- // Using replace instead of query-string's parse() method allow for supporting
- // data for URLs like this "flipkart.com/search?q=moto%20g5%20plus&sid=tyy"
- // parse() would return 'flipkart.com/search?q' instead of the full url.
- const site = this.props.location.search.replace('?site=', '');
- if (site) {
- const siteData = nimbledroidData[site];
- const { ratio, symbol, color } = siteMetrics(siteData.GV, siteData.WV, targetRatio);
- $content = (
-
-
-
-
-
- );
- } else {
- const sites = (numSites > 0) ?
- Object.values(nimbledroidData).sort(sortSitesByTargetRatio) : [];
- const count = {
- red: 0,
- yellow: 0,
- green: 0,
- };
- const summaryTableContent = sites.map(({ title, url, GV, WV }) => {
- const { ratio, symbol, color } = siteMetrics(GV, WV, targetRatio);
- count[color] += 1;
- return {
- title: {
- text: url,
- bgColor: color,
- hyperlink: `android/graph?site=${url}`,
- tooltip: url,
- },
- uid: url,
- dataPoints: [GV, WV],
- summary: `${symbol}${((1 - ratio) * 100).toFixed(2)}%`,
- };
- });
- const summaries = [
- {
- title: {
- text: 'GeckoView > 20% slower than WebView',
- bgColor: 'red',
- },
- summary: `${count.red}/${numSites}`,
- },
- {
- title: {
- text: 'GeckoView > 0% and <= 20% slower than WebView',
- bgColor: 'yellow',
- },
- summary: `${count.yellow}/${numSites}`,
- },
- {
- title: {
- text: 'GeckoView <= 0% (i.e. faster than) WebView',
- bgColor: 'green',
- },
- summary: `${count.green}/${numSites}`,
- },
- ];
- $content = (
-
-
-
- {summaries.map(({ title, summary }) => (
-
- ))}
-
-
-
-
-
- );
- }
- }
- if (errorMessage) {
- $content = {errorMessage}
;
- }
+ // Using replace instead of query-string's parse() method allow for supporting
+ // data for URLs like this "flipkart.com/search?q=moto%20g5%20plus&sid=tyy"
+ // parse() would return 'flipkart.com/search?q' instead of the full url.
+ const site = this.props.location.search.replace('?site=', '');
return (
-
+
+ {/* Needed until the background of the site is not black */}
- {$content}
+ {numSites > 0 && !site && (
+
+ )}
+ {errorMessage &&
{errorMessage}
}
+ {numSites > 0 && site && (
+
+ )}