Skip to content

Premium Analytics: port Stats File Downloads widget - #50050

Merged
dognose24 merged 24 commits into
trunkfrom
add/wooa7s-1498-port-stats-module-file-downloads
Jul 2, 2026
Merged

dognose24 merged 24 commits into
trunkfrom
add/wooa7s-1498-port-stats-module-file-downloads

Conversation

@dognose24

@dognose24 dognose24 commented Jun 29, 2026 •

Copy link
Copy Markdown
Contributor

Fixes WOOA7S-1498

Proposed changes

Ports the Jetpack Stats File Downloads module into Premium Analytics as the jpa/file-downloads widget.

  • Adds the File Downloads widget as a self-contained registered widget.
  • Renders file-download stats with the shared leaderboard UI.
  • Supports previous-period comparison row deltas when comparison is enabled.
  • Includes loading, empty, and error states aligned with the current widget guidelines.
  • Shows a Jetpack-sites-specific message when file-download stats are unavailable.
  • Adds Storybook stats mocks for primary and comparison file-download data.
  • Adds Default, WithComparison, and WidgetDashboardWithWidget Storybook stories.
  • Seeds jpa/file-downloads into the default dashboard layout at 1x2.
  • Adds a changelog entry for the new widget.

Related product discussion/links

Does this pull request change what data or activity we track or use?

No. This reads existing Jetpack Stats file-download data through the existing Premium Analytics stats data layer.

Testing instructions

Run:

pnpm --dir projects/packages/premium-analytics run typecheck
pnpm --dir projects/packages/premium-analytics run build:wp-build

In Storybook:

  1. Open Packages/Premium Analytics/Widgets/FileDownloads.
  2. Confirm Default, WithComparison, and WidgetDashboardWithWidget render correctly.
  3. Confirm comparison deltas appear in WithComparison.

On a Jetpack-connected test site with file-download stats:

  1. Open Premium Analytics.
  2. Confirm File Downloads appears in the dashboard widget picker.
  3. Add the widget and confirm downloaded files render as ranked rows with download counts.
  4. Enable a comparison date range and confirm row deltas are shown.
  5. Select a date range with no file-download data and confirm the empty state appears.
  6. On a Jetpack site where file-download stats are unavailable, confirm the widget shows "File download stats are not available for Jetpack sites."
截圖 2026-07-02 凌晨2 54 34

@github-actions

github-actions Bot commented Jun 29, 2026 •

Copy link
Copy Markdown
Contributor

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!


Premium Analytics plugin:

No scheduled milestone found for this plugin.

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.

@github-actions github-actions Bot added the [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. label Jun 29, 2026
@dognose24

This comment has been minimized.

@claude

This comment has been minimized.

@jp-launch-control

jp-launch-control Bot commented Jun 29, 2026 •

Copy link
Copy Markdown

Code Coverage Summary

Coverage changed in 1 file.

File Coverage Δ% Δ Uncovered
projects/packages/premium-analytics/src/dashboard-layout.php 64/105 (60.95%) 5.52% 0 💚

Full summary · PHP report

@dognose24

This comment has been minimized.

@claude

This comment has been minimized.

@dognose24

This comment has been minimized.

@dognose24

Copy link
Copy Markdown
Contributor Author

🤖 Review-cycle summary — d9e9c18 → 18b56ca

4 rounds; CI green; 0 inline threads; 1 AI reviewer (claude[bot]) addressed.

What changed during the cycle

Commits added:

  • 18b56ca112 — Address review: fix category to stats, document no-comparison intent
  • 48899fd10a — Fix CI: Storybook tests — wrap LeaderboardChart stories in GlobalChartsProvider
  • feb3ad6e9c — Premium Analytics: changelog for file-downloads widget

Diff summary: 3 files changed, 16 insertions(+), 3 deletions(-)

Review actions taken:

Source Item Resolution
CI Storybook tests failing — LeaderboardChart needs GlobalChartsProvider Added withChartTheme decorator to EmptyState + WithMockRows stories (commit 48899fd)
claude[bot] category "traffic" should match sibling Stats widgets Fixed widget.json category "traffic" → "stats" (commit 18b56ca)
claude[bot] WithComparison story renders identically to Default Added docs note explaining file downloads has no PoP comparison view by design (commit 18b56ca)
claude[bot] storyWidgetType trimmed object vs widgetDefinition Acknowledged — current pattern avoids TS friction; devices widget uses same approach
claude[bot] currentShare relative to max row, not total Acknowledged — intentional, matches Calypso leaderboard behavior
claude[bot] empty Stats mock fallback shape Noted for future additions; no code change needed

Unaddressed human comments: None.

CI: all required checks passing on commit 18b56ca.

@dognose24 dognose24 added [Status] Needs Team Review Obsolete. Use Needs Review instead. and removed [Status] In Progress labels Jun 29, 2026
@dognose24
dognose24 marked this pull request as ready for review June 29, 2026 15:57
@dognose24
dognose24 requested a review from a team June 29, 2026 15:57
@dognose24
dognose24 requested a review from a team as a code owner June 29, 2026 15:57
@dognose24 dognose24 self-assigned this Jun 29, 2026
@dognose24 dognose24 removed the [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. label Jun 29, 2026
@github-actions github-actions Bot added [Status] In Progress [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. labels Jun 29, 2026
@dognose24 dognose24 changed the title Premium Analytics: port Jetpack Stats file-downloads module Premium Analytics: port Stats File Downloads widget Jun 29, 2026
@dognose24 dognose24 added [Status] Needs Review This PR is ready for review. [Status] UI Changes Add this to PRs that change the UI so documentation can be updated. [Tests] Includes Tests [Plugin] Premium Analytics Enhancement Changes to an existing feature — removing, adding, or changing parts of it and removed [Status] Needs Author Reply We need more details from you. This label will be auto-added until the PR meets all requirements. [Status] In Progress [Status] Needs Team Review Obsolete. Use Needs Review instead. labels Jun 29, 2026

@chihsuan chihsuan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dognose24

I noticed that the focus style doesn't looks good. The focus outline gets clipped but I think this would need a general solution instead of fixing it in the widget so we can create a follow-up for it.

Also left a few inline comments but overall looks good.

Image

Comment thread projects/packages/premium-analytics/widgets/file-downloads/render.tsx Outdated
kangzj
kangzj previously approved these changes Jul 1, 2026

@kangzj kangzj left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me!

It seems the existing pattern hide most of these details in widget-toolkit, where it's env agnostic and keep only the essential scafolding in top level widgets. Should we do that?

cc/ @chihsuan

@chihsuan

chihsuan commented Jul 1, 2026

Copy link
Copy Markdown
Member

It seems the existing pattern hide most of these details in widget-toolkit, where it's env agnostic and keep only the essential scafolding in top level widgets. Should we do that?

Thanks! Worth separating the two patterns here, since they're intentionally different:

  • Woo ports: (e.g. SalesByDeviceWidget) live fully inside widgets-toolkit because they're genuinely env-agnostic reports shared by more than one registered widget.
  • Stats module ports (File Downloads, top-posts, visitors-over-time): Follow a different, documented pattern - pull data via the packages/data/ Stats hooks, compose toolkit primitives like LeaderboardChart, and map comparison rows in the widget itself. None of the existing Stats widgets push their logic into widgets-toolkit/src/widgets/. The visitors-over-time keeps its logic in a local components/ folder too.

This also lines up with the direction called out (p1782509121752509-slack-C06FSDTSN82) The goal is to move widget-specific code out of widgets-toolkit and keep only genuinely shared pieces there. the toolkit is flagged as an interim layer expected to shrink over time (folding into @automattic/charts), so moving more into it goes against that grain.

That said. if the leaderboard + comparison-mapping here ends up largely duplicating in many widgets, that's a real signal that we should extract as a toolkit primitive/helper.

@dognose24

Copy link
Copy Markdown
Contributor Author

That said. if the leaderboard + comparison-mapping here ends up largely duplicating in many widgets, that's a real signal that we should extract as a toolkit primitive/helper.

Agree with this. @kangzj @chihsuan Thanks for the feedback!

dognose24 added 3 commits July 1, 2026 12:59
…-stats-module-file-downloads

# Conflicts:
#	projects/packages/premium-analytics/packages/widgets-toolkit/src/stories/mocks/register-stats-mocks.ts
@dognose24
dognose24 requested review from chihsuan and kangzj July 1, 2026 14:01
<span>{ __( 'File downloads', 'jetpack-premium-analytics' ) }</span>
</span>
);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we change the value ofpresentation and remove this so host owns the title/header?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would keep this as-is for now. This widget intentionally uses presentation: "full-bleed" and owns its title/header, matching the direction we have been aligning with Locations/UTM/etc. Having these Stats widgets follow the same composition also gives us better control over consistent spacing, title/icon treatment, and state layouts. If we move title/header ownership back to the host, I think that should be a broader widget-root/guideline change rather than changing only File Downloads here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One extra note: I also expect Top Posts to move toward this same full-bleed/title-owned pattern when we align the remaining Stats widgets. So the intent here is consistent header/title/icon control across Stats widgets rather than File Downloads being a one-off.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, It feels a bit fragile to define a custom title/header here rather than reusing the widget's built-in header. If the core widget header ever changes, these custom header widgets could end up with inconsistent styles.

That said, no worries for now! This looks like an upstream issue that @retrofox is already working on over in WordPress/gutenberg#79246, so we should be in good hands.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said, no worries for now! This looks like an upstream issue that @retrofox is already working on over in WordPress/gutenberg#79246, so we should be in good hands.

Yeah, it should be, and we will figure out a better way to handle it all together.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think It's fragile as well. Using the title to represent the local state doesn't align with the API's design.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WordPress/gutenberg#79735 is the first step in this

.join( ' ' );
}

function getFileDownloadsErrorMessage( error: unknown ) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No other Stats widget carries this error-parsing cluster (toStatusNumber/getErrorStatus/getErrorText). Is this specific required for file downloads widget? Or I'm curious if we should handle this in data level so it can be reused for all Stats widget (maybe a follow-up).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is currently File Downloads-specific. The API returns a 404 for Jetpack sites where file download stats are not available, and we need to surface a more precise message than the generic load failure. I agree this would be better as a reusable data-layer error reason if/when more Stats widgets need it. UTM, Devices, and other advanced Stats features can also have API-side permission/availability controls, so normalizing this in the data layer sounds like a good follow-up.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened a separate Premium Analytics follow-up for normalizing API availability/permission error reasons in the data layer. That should let widgets like File Downloads, UTM, Devices, and Top Platforms render consistent unavailable/error states without each widget parsing raw status/message fields.

rows={ rows }
isLoading={ showLoading }
isError={ isError }
withComparison={ hasComparison }

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

top-posts gates on hasComparison && primaryRows.some(row => previousViewsByHref.has(row.href)), but here it's withComparison={ hasComparison } unconditionally.

When the comparison report has no overlapping rows, every previousValue falls back to 0 and calculateDelta(value, 0) returns 100 , so each row shows a fabricated +100%.

Should this defer comparison the way top-posts does when nothing overlaps?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I updated this to mirror top-posts: the comparison UI is now enabled only when at least one primary row has a matching comparison row, so missing comparison rows are no longer treated as real 0 values. I also checked nearby widgets: top-posts already has this guard, while UTM/Search Terms/Locations appear to have the same missing-comparison-as-zero pattern and should be aligned in their own PRs/follow-up rather than bundled into this File Downloads PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Opened a Premium Analytics follow-up to audit and align this across the remaining Stats widgets. Keeping this PR scoped to File Downloads: Top Posts already has this guard, and the follow-up will cover the other row-level comparison widgets so they do not treat missing comparison rows as real zero values.

dognose24 added 2 commits July 2, 2026 12:31
…-stats-module-file-downloads

# Conflicts:
#	projects/packages/premium-analytics/packages/widgets-toolkit/src/stories/mocks/register-stats-mocks.ts
#	projects/packages/premium-analytics/src/dashboard-layout.php
#	projects/packages/premium-analytics/tests/php/Dashboard_Layout_Test.php
chihsuan
chihsuan previously approved these changes Jul 2, 2026

@chihsuan chihsuan left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dognose24 Looks good. Let's keep iterate this.

@dognose24
dognose24 merged commit 1504c9a into trunk Jul 2, 2026
75 checks passed
@dognose24
dognose24 deleted the add/wooa7s-1498-port-stats-module-file-downloads branch July 2, 2026 05:13
@github-actions github-actions Bot removed the [Status] Needs Review This PR is ready for review. label Jul 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement Changes to an existing feature — removing, adding, or changing parts of it [Package] Premium Analytics [Plugin] Premium Analytics [Status] UI Changes Add this to PRs that change the UI so documentation can be updated. [Tests] Includes Tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants