Skip to content

Commit

Permalink
Category dashboard with collapsible filters (#934)
Browse files Browse the repository at this point in the history
* custom techreport header

* add prototype categories page

* add filters in sidebar and change page based on amount of techs

* add new nav and filter structure (wip

* responsive filters prototype

* wip: add collapsible filter sidebar

* fix bug with double close button

* add aria

* add checkboxes on category page, update texts, minor bugfixes

* select correct technology in comparison view, remove category selector, minor bugfixes

* fix css linting

* fix linting

* fix linting

* fix sorting order multi apps

* sort table alternative correctly

* close <nav>

* update tests

* format tests

* Update src/js/techreport/tableLinked.js

Co-authored-by: Rick Viscomi <[email protected]>

* fix geo/rank bug, long category list bug, adoption bug, add category summary, improve landing page card interaction

* add technologies to summary in category page

* add timestamp to category page and format large numbers

* remove console.log

* select correct technology in comparison view filters

* make menu responsive on mobile + track aria-expanded status

* give remove button icon alt that matches the label

* filter out data with empty content

* fix linting

* add width and height to close filter button

* remove placeholder texts

* use client filter for origins in category page

---------

Co-authored-by: Rick Viscomi <[email protected]>
  • Loading branch information
sarahfossheim and rviscomi authored Feb 13, 2025
1 parent 9840299 commit a82b3bc
Show file tree
Hide file tree
Showing 31 changed files with 1,359 additions and 412 deletions.
151 changes: 133 additions & 18 deletions config/techreport.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
"name": "Technology Report",
"summary": "The Core Web Vitals Technology Report is a dashboard combining the powers of real-user experiences in the [Chrome User Experience Report (CrUX)](https://developers.google.com/web/tools/chrome-user-experience-report/) dataset with web technology detections available in HTTP Archive, to allow analysis of the way websites are both built and experienced.",
"config": {
"default_apps": {
"drilldown": [ "ALL" ],
"comparison": [ "ALL", "WordPress", "Wix", "Next.js" ]
},
"default_category": "CMS",
"cwv_subcategories": [
"CLS",
"LCP",
Expand Down Expand Up @@ -39,7 +44,7 @@
"id": "landing",
"title": "Technology Report",
"subtitle": "Report",
"description": "This is placeholder text about how the report works",
"description": "",
"data": {},
"filters": {
"technologies": ["WordPress", "Squarespace", "Drupal"]
Expand Down Expand Up @@ -82,7 +87,7 @@
"id": "drilldown",
"title": "Drilldown",
"subtitle": "Technology Report",
"description": "Drilldown placeholder",
"description": "View detailed information about one technology and compare mobile and desktop data over time.",
"config": {
"default": {
"app": ["ALL"],
Expand Down Expand Up @@ -151,7 +156,7 @@
"table": {
"param": "",
"default": "adoption",
"caption": "Usage placeholder",
"caption": "Amount of origins a technology has over time.",
"columns": [
{
"key": "date",
Expand Down Expand Up @@ -263,7 +268,7 @@
},
"good_cwv_timeseries": {
"title": "Good Core Web Vitals over time",
"description": "Placeholder - combination of several metrics",
"description": "The percentage of origins passing all three Core Web Vitals (LCP, INP, CLS) with a good experience. Note that if an origin is missing INP data, it's assessed based on the performance of the remaining metrics.",
"id": "good_cwv_timeseries",
"endpoint": "vitals",
"metric": "good_pct",
Expand Down Expand Up @@ -425,7 +430,7 @@
},
"lighthouse_timeseries": {
"title": "Lighthouse over time",
"description": "Placeholder text",
"description": "",
"id": "lighthouse_timeseries",
"endpoint": "lighthouse",
"metric": "median_score_pct",
Expand Down Expand Up @@ -557,7 +562,7 @@
},
"weight_timeseries": {
"title": "Weight over time",
"description": "Placeholder text",
"description": "",
"id": "weight_timeseries",
"summary": true,
"endpoint": "pageWeight",
Expand Down Expand Up @@ -695,7 +700,8 @@
"#E24070"
],
"overrides": {
"WordPress": "#fff000"
"WordPress": "#3858e9",
"ALL": "#69797e"
}
},
"default": {
Expand Down Expand Up @@ -750,7 +756,7 @@
},
"good_cwv_timeseries": {
"title": "Good Core Web Vitals over time",
"description": "Placeholder - combination of several metrics",
"description": "Comparison of the percentage of origins passing all three Core Web Vitals (LCP, INP, CLS) with a good experience. Note that if an origin is missing INP data, it's assessed based on the performance of the remaining metrics.",
"id": "good_cwv_timeseries",
"endpoint": "vitals",
"metric": "good_pct",
Expand Down Expand Up @@ -789,7 +795,7 @@
"table": {
"param": "good-cwv-over-time",
"default": "overall",
"caption": "Good Core Web Vitals placeholder",
"caption": "Comparison of the percentage of origins of the different technologies passing all three Core Web Vitals (LCP, INP, CLS), visualized over time.",
"columns": [
{
"key": "date",
Expand Down Expand Up @@ -857,7 +863,7 @@
},
"lighthouse_timeseries": {
"title": "Lighthouse over time",
"description": "Placeholder text",
"description": "Lighthouse has audits for performance, accessibility, progressive web apps, SEO, and more. Based on the audits, a score is calculated. Currently, this section visualizes median scores, but in the future you'll also be able to explore the details of the audits here.",
"id": "lighthouse_timeseries",
"endpoint": "lighthouse",
"metric": "median_score_pct",
Expand Down Expand Up @@ -887,7 +893,7 @@
"table": {
"param": "median-lighthouse-over-time",
"default": "performance",
"caption": "Lighthouse placeholder",
"caption": "Comparing the Lighthouse scores of the different selected technologies over time.",
"columns": [
{
"key": "date",
Expand Down Expand Up @@ -952,7 +958,7 @@
},
"weight_timeseries": {
"title": "Page weight over time",
"description": "Placeholder text",
"description": "",
"id": "weight_timeseries",
"endpoint": "pageWeight",
"metric": "median_bytes",
Expand Down Expand Up @@ -1047,7 +1053,7 @@
},
"adoption_timeseries": {
"title": "Origins over time",
"description": "Placeholder text",
"description": "",
"id": "adoption_timeseries",
"endpoint": "adoption",
"metric": "origins",
Expand Down Expand Up @@ -1117,7 +1123,107 @@
}
}
},
"description": "Comparison placeholder"
"description": "Get a detailed comparison for 2 to 10 technologies."
},
"category": {
"id": "category",
"title": "Categories",
"subtitle": "Technology Report",
"config": {
"default": {
"category": "CMS",
"app": ["ALL", "WordPress", "Drupal"],
"series": {
"breakdown": "app"
}
},
"summary": [
{
"endpoint": "category",
"metric": "origins",
"label": "Origins",
"description": "Origins analyzed in this category.",
"key": "info"
},
{
"endpoint": "category",
"metric": "technologies",
"label": "Technologies",
"description": "Amount of technologies in this category.",
"key": "info"
}
],
"tech_comparison_summary": {
"id": "tech_comparison_summary",
"table": {
"caption": "Summary",
"key": "technologies",
"columns": [
{
"key": "selectTech",
"name": "Select technology",
"hiddenName": true,
"type": "checkbox"
},
{
"key": "technology",
"name": "Tech",
"type": "heading"
},
{
"key": "origins",
"name": "Origins",
"breakdown": "subcategory",
"subcategory": "adoption",
"endpoint": "adoption",
"metric": "origins"
},
{
"key": "good_pct",
"name": "Good CWV",
"breakdown": "subcategory",
"subcategory": "overall",
"suffix": "%",
"className": "main-cell pct-value",
"endpoint": "vitals",
"metric": "good_pct"
},
{
"key": "good_pct",
"name": "LCP",
"breakdown": "subcategory",
"subcategory": "LCP",
"suffix": "%",
"endpoint": "vitals",
"metric": "good_pct"
},
{
"key": "good_pct",
"name": "INP",
"breakdown": "subcategory",
"subcategory": "INP",
"suffix": "%",
"endpoint": "vitals",
"metric": "good_pct"
},
{
"key": "good_pct",
"name": "CLS",
"breakdown": "subcategory",
"subcategory": "CLS",
"suffix": "%",
"endpoint": "vitals",
"metric": "good_pct"
},
{
"key": "client",
"name": "Client",
"className": "client"
}
]
}
}
}
}
},

Expand Down Expand Up @@ -1145,6 +1251,9 @@
}
},
"vitals": {
"general": {
"description": "Each of the Core Web Vitals represents a distinct facet of the user experience, is measurable in the field, and reflects the real-world experience of a critical user-centric outcome. A good threshold to measure is the 75th percentile of page loads, segmented across mobile and desktop devices."
},
"overall": {
"label": "Overall Core Web Vitals",
"title": "Passes Core Web Vitals",
Expand Down Expand Up @@ -1178,23 +1287,29 @@
}
},
"pageWeight": {
"general": {
"description": ""
},
"images": {
"title": "Image Weight",
"description": "todo"
"description": ""
},
"js": {
"title": "JavaScript Transfer Size",
"description": "todo"
"description": ""
},
"total": {
"title": "Total Page Weight",
"description": "todo"
"description": ""
}
},
"adoption": {
"general": {
"description": ""
},
"adoption": {
"title": "Adoption",
"description": "Todo"
"description": "The amount of origins using this technology over time."
}
}
},
Expand Down
68 changes: 67 additions & 1 deletion server/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def reports():


@app.route("/reports/techreport/<page_id>", strict_slashes=False)
def techreport(page_id):
def techreportlanding(page_id):
# Needed for the header dropdown
all_reports = report_util.get_reports()

Expand All @@ -85,26 +85,92 @@ def techreport(page_id):
"app"
) or ["ALL"]

# Get the filters
requested_geo = request.args.get("geo") or "ALL"
requested_rank = request.args.get("rank") or "ALL"
requested_category = request.args.get("category") or "ALL"
filters = {
"geo": requested_geo,
"rank": requested_rank,
"app": requested_technologies,
"category": requested_category,
}
params = {
"geo": requested_geo.replace(" ", "+"),
"rank": requested_rank.replace(" ", "+"),
}

active_tech_report["filters"] = filters
active_tech_report["params"] = params

return render_template(
"techreport/%s.html" % page_id,
active_page=page_id,
tech_report_labels=tech_report.get("labels"),
tech_report_config=tech_report.get("config"),
tech_report_page=active_tech_report,
custom_navigation=True,
reports=all_reports,
)


@app.route("/reports/techreport/tech", strict_slashes=False)
def techreport():
# Needed for the header dropdown
all_reports = report_util.get_reports()

# Get the configuration for the tech report
tech_report = tech_report_util.get_report()

# Get the current page_id
requested_technologies = ["ALL"]
if request.args.get("tech"):
requested_technologies = request.args.get("tech").split(",")

if len(requested_technologies) > 1:
page_id = "comparison"
else:
page_id = "drilldown"

# Get the settings for the current page
active_tech_report = tech_report.get("pages").get(page_id)

# Add the technologies requested in the URL to the filters
# Use the default configured techs as fallback
# Use ["ALL"] if there is nothing configured
requested_technologies = active_tech_report.get("config").get("default").get(
"app"
) or ["ALL"]

if request.args.get("tech"):
requested_technologies = request.args.get("tech").split(",")

# Get the filters
requested_geo = request.args.get("geo") or "ALL"
requested_rank = request.args.get("rank") or "ALL"
requested_category = request.args.get("category") or "ALL"
filters = {
"geo": requested_geo,
"rank": requested_rank,
"app": requested_technologies,
"category": requested_category,
}
params = {
"geo": requested_geo.replace(" ", "+"),
"rank": requested_rank.replace(" ", "+"),
}

active_tech_report["filters"] = filters
active_tech_report["params"] = params

return render_template(
"techreport/%s.html" % page_id,
active_page=page_id,
requested_page="technology",
tech_report_labels=tech_report.get("labels"),
tech_report_config=tech_report.get("config"),
tech_report_page=active_tech_report,
custom_navigation=True,
reports=all_reports,
)

Expand Down
Loading

0 comments on commit a82b3bc

Please sign in to comment.