Premium Analytics: port the Average items per order widget#49505
Conversation
|
Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.
Interested in more tips and information?
|
|
Thank you for your PR! When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:
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:
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. |
Code Coverage SummaryThis PR did not change code coverage! That could be good or bad, depending on the situation. Everything covered before, and still is? Great! Nothing was covered before? Not so great. 🤷 |
d922903 to
74722f2
Compare
91aa9fb to
909996e
Compare
74722f2 to
4538b65
Compare
Follow-up: the
|
909996e to
d060b2d
Compare
d060b2d to
5bb6dd9
Compare
4538b65 to
bbf93fc
Compare
9607ed8 to
9461614
Compare
5bb6dd9 to
7ff7f71
Compare
32820ab to
11af3a3
Compare
adamwoodnz
left a comment
There was a problem hiding this comment.
I rebased this on trunk and tested in storybook. Generally looks good.
Left a comment on the storybook setup.
adamwoodnz
left a comment
There was a problem hiding this comment.
Looks great! I'll update #49679 based on these stories.
…cations to AGENTS.md Add a new ## Widgets section anchored to the widget layout introduced in #49505 (Average items per order): documents the required widgets/<name>/{package.json,widget.json,widget.ts,render.tsx,stories/} folder structure, the WidgetDashboardWithWidget-based story template, the Packages/Premium Analytics/Widgets/<WidgetName> title path, registerReportMocks() / autodocs requirements, the projects/js-packages/storybook/storybook/projects.js registration step, and widget-specific pitfalls (including avoiding the legacy packages/widgets-toolkit/src/widgets/* path and the legacy withWidgetRoot() decorator). Also restructure the existing ## Overview into a bulleted list with more detail on each consolidated surface (Odyssey dashboard / apps/odyssey-stats / email stats, and a link to the private woocommerce/woocommerce-analytics repo). Co-authored-by: Jasper Kang <kangzjnet@gmail.com>
| min-height: 0; | ||
| flex: 1 1 auto; | ||
| display: flex; | ||
| flex-direction: column; |
There was a problem hiding this comment.
We should replace the regular div with the chart class with a Stack component. It's acting like a part of the component layout.
There was a problem hiding this comment.
Actually, I'm not sure what the purpose of these styles is. I guess we're trying to force the widget to take the whole height, but I thought that height: 100% should be enough?
There was a problem hiding this comment.
I see, it's needed to stretch its immediate children. Below:
> div {
flex: 1 1 auto;
min-height: 0;
}Using this > div class doesn't look good .
There was a problem hiding this comment.
Good points, I've replaced with Stack, but it looks like here are still some style tweaks needed. This particular component is in the widgets-toolkit package and is one of the ones that should be migrated to @automattic/charts as a part of the composite chart components. So I think this can help inform that eventual migration (and further SCSS edits can happen as a part of that).
retrofox
left a comment
There was a problem hiding this comment.
Nice PR. It works very nicely 💯
I have my reservations, though, about merging it 😅
The implementation mitigates the lack of a proper process for adjusting the chart's visualization based on its size by adding CSS that should be handled by the Chart library.
This is something we should avoid from now, IMO.
I prefer discarding this part, merging the PR without it, and handling the auto-resize in the Chart library, or eventually in a wrapper.
This is fair feedback, and I believe we should handle it upstream. The widget inserter is part of WidgetDashboard's area of responsibility. |
…tions Address PR #49568 review feedback: * Collapse the widget into render.tsx (matching the canonical hello-world reference). Remove top-posts-widget.tsx, index.ts and types.ts; rename the presentational TopPostsWidget component to TopPostsLeaderboard and keep it internal. A widget is the block-level abstraction (widget.json + widget.ts + render.tsx), so render.tsx is the component itself, like a block's edit.js. * Stop exporting TopPostsAttributes / TopPostRow (used only here). * Rename top-posts-widget.module.css -> top-posts.module.css. * i18n: wrap widget.ts title and attribute labels in __(). * Replace the native anchor with the @wordpress/ui Link component (openInNewTab + unstyled variant to preserve the leaderboard row styling). * Defer the Storybook story to the #49505 follow-up; drop its stale changelog. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9fmCCXRxMgNf9whczP122
@retrofox I agree with this generally, however it's important to note that currently this component is not in the @automattic/charts library - changes here can inform what is missing for implementation when migrating these composite components there. I left a comment about this in reply to your inline review comment (along with implementing Stack like you suggested 😄). |
retrofox
left a comment
There was a problem hiding this comment.
Thanks, Darren, for addressing all feedback 💯 I think it can be shipped and follow-ups can continue.
From nerrad's review (#4524224327): - Note widgets-toolkit primitives are built on @automattic/charts, and flag the toolkit as an interim layer whose module paths are provisional. - Drop the explicit #49505 link from the legacy note so it can't go stale. - Trim the widget pitfalls to the two non-obvious legacy traps; the rest just restated the REQUIRED folder-structure / story rules above. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P2vY2GxKEJurnaod7phrFo
…d Overview clarifications (#49679) * Premium Analytics: Add widget Storybook guidance and Overview clarifications to AGENTS.md Add a new ## Widgets section anchored to the widget layout introduced in #49505 (Average items per order): documents the required widgets/<name>/{package.json,widget.json,widget.ts,render.tsx,stories/} folder structure, the WidgetDashboardWithWidget-based story template, the Packages/Premium Analytics/Widgets/<WidgetName> title path, registerReportMocks() / autodocs requirements, the projects/js-packages/storybook/storybook/projects.js registration step, and widget-specific pitfalls (including avoiding the legacy packages/widgets-toolkit/src/widgets/* path and the legacy withWidgetRoot() decorator). Also restructure the existing ## Overview into a bulleted list with more detail on each consolidated surface (Odyssey dashboard / apps/odyssey-stats / email stats, and a link to the private woocommerce/woocommerce-analytics repo). Co-authored-by: Jasper Kang <kangzjnet@gmail.com> * Premium Analytics: make widget story guidance a self-contained template Rework the AGENTS.md story guidance so an agent can build all three required stories from the doc alone, without copying a specific widget's story file (which can drift). Inline snippets for each story — Default and WithComparison close-ups plus the WidgetDashboardWithWidget harness story — share one setup block. Reconcile the surrounding requirements: the dashboard story proves the in-product render while the close-ups use a plain canvas decorator, and the legacy note no longer points at an example widget as the thing to copy. Also corrects the WidgetRenderProps import, which pointed at a non-existent @automattic/jetpack-widget-primitives package; the real type comes from @wordpress/widget-primitives. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P2vY2GxKEJurnaod7phrFo * Premium Analytics: address review feedback on widget AGENTS.md From nerrad's review (#4524224327): - Note widgets-toolkit primitives are built on @automattic/charts, and flag the toolkit as an interim layer whose module paths are provisional. - Drop the explicit #49505 link from the legacy note so it can't go stale. - Trim the widget pitfalls to the two non-obvious legacy traps; the rest just restated the REQUIRED folder-structure / story rules above. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01P2vY2GxKEJurnaod7phrFo --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Jasper Kang <kangzjnet@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tions Address PR #49568 review feedback: * Collapse the widget into render.tsx (matching the canonical hello-world reference). Remove top-posts-widget.tsx, index.ts and types.ts; rename the presentational TopPostsWidget component to TopPostsLeaderboard and keep it internal. A widget is the block-level abstraction (widget.json + widget.ts + render.tsx), so render.tsx is the component itself, like a block's edit.js. * Stop exporting TopPostsAttributes / TopPostRow (used only here). * Rename top-posts-widget.module.css -> top-posts.module.css. * i18n: wrap widget.ts title and attribute labels in __(). * Replace the native anchor with the @wordpress/ui Link component (openInNewTab + unstyled variant to preserve the leaderboard row styling). * Defer the Storybook story to the #49505 follow-up; drop its stale changelog. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T9fmCCXRxMgNf9whczP122
* Premium Analytics: wire Top posts & pages widget to the designated stats hooks
Rebased onto trunk. The presentational TopPostsWidget, the stats proxy data
layer, and the designated useStatsTopPosts traffic hook have all since landed in
trunk, so this is reduced to the widget glue that connects them:
* widgets/top-posts/{widget.json,widget.ts,package.json} — register the
`jpa/stats-top-posts` framed widget with range/num attributes.
* widgets/top-posts/render.tsx — fetch via the designated `useStatsTopPosts`
hook, resolve the range preset to an absolute window, adapt the normalized
report items to the `TopPostRow[]` the presentational widget expects, and
filter by post type client-side.
* widgets/top-posts/__tests__/top-posts.test.tsx — render/empty/post-type tests
driven through the stats proxy (apiFetch mocked).
* packages/data: re-export `computeDateRangeFromPreset` from the package root.
* tests: stub CSS imports so widget render tests can pull in widgets-toolkit.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017bmLMW4mTLBLuLtMaNvUca
* Premium Analytics: link widgets-toolkit, icons & init internal packages
The top-posts widget imports @jetpack-premium-analytics/widgets-toolkit,
which transitively imports @jetpack-premium-analytics/icons. These bare
specifiers resolve via Node module resolution to the link: symlinks in
node_modules, but the package only declared 7 of the 10 internal packages.
Add the missing link: entries (icons, init, widgets-toolkit) so the widget
builds.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Nz61RCPHjp2tot41TskF12
* Premium Analytics: fix ESLint issues in top-posts widget
Re-apply lint fixes after rebase:
- Wrap the type-guard arrow in render.tsx's toTopPostRows (prettier/prettier).
- Order the @jetpack-premium-analytics/widgets-toolkit import before the
@WordPress imports in top-posts-widget.tsx (import/order).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LNH44m2sKKhtnU4yNmvFqj
* Premium Analytics: align Top posts widget structure with block conventions
Address PR #49568 review feedback:
* Collapse the widget into render.tsx (matching the canonical hello-world
reference). Remove top-posts-widget.tsx, index.ts and types.ts; rename the
presentational TopPostsWidget component to TopPostsLeaderboard and keep it
internal. A widget is the block-level abstraction (widget.json + widget.ts +
render.tsx), so render.tsx is the component itself, like a block's edit.js.
* Stop exporting TopPostsAttributes / TopPostRow (used only here).
* Rename top-posts-widget.module.css -> top-posts.module.css.
* i18n: wrap widget.ts title and attribute labels in __().
* Replace the native anchor with the @wordpress/ui Link component
(openInNewTab + unstyled variant to preserve the leaderboard row styling).
* Defer the Storybook story to the #49505 follow-up; drop its stale changelog.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T9fmCCXRxMgNf9whczP122
* Premium Analytics: type Top posts render export as WidgetRenderProps
Use the host-provided `WidgetRenderProps<TopPostsAttributes>` from
@wordpress/widget-primitives for the widget's render entry point instead of a
hand-rolled props type — this matches the contract the widget dashboard invokes
render modules with (`ComponentType<WidgetRenderProps<unknown>>`). Add the
package to the widget's dependencies.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T9fmCCXRxMgNf9whczP122
* Premium Analytics: restore Top posts Storybook story; inline link label
* Re-add the prop-driven Top posts & pages story (stories/top-posts.stories.tsx)
targeting the now-exported presentational `TopPostsLeaderboard`. Storybook has
no analytics backend, so the data-connected entry point would only show empty
chrome — driving the presentational layer with fixture rows is the only way to
show populated, comparison, and long-label states.
* Export `TopPostsLeaderboard` and the `TopPostRow` type for the story.
* Inline the small `TopPostLabel` component into `buildLeaderboardData`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T9fmCCXRxMgNf9whczP122
* Premium Analytics: address Top posts widget review feedback
- package.json: use link: for internal @jetpack-premium-analytics/* deps
(they are not pnpm workspace members)
- widget.ts: drop redundant `presentation` (owned by widget.json); add the
`postType` attribute so the widget redefinition is complete
- render.tsx: rename the `name` attribute to `postType`; treat empty as "all
types"; collapse the duplicated TopPostsLeaderboard JSDoc to @param {Type}
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AuSeh4kAoQvoKeXQbV2SLw
* Premium Analytics: move TopPostsAttributes type into widget.ts
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Why?
This ports the WooCommerce Analytics "Average items per order" widget into Premium Analytics, validates it in the dashboard shell through Storybook, and fixes compact dashboard rendering issues found while testing one-column widget layouts.
Proposed changes
jpa/average-items-per-orderwidget metadata, render module, package entry, and changelog entry.Packages/Premium Analytics/Widgets/AverageItemsPerOrder / WidgetDashboardWithWidget.grid,widget-dashboard, andwidget-primitives.Related product discussion/links
Does this pull request change what data or activity we track or use?
No.
Testing instructions
Requires pnpm ^11.5 and Node ^24.15.
pnpm --filter @automattic/jetpack-premium-analytics build.pnpm --filter @automattic/jetpack-widget-dashboard typecheckpnpm --filter @automattic/jetpack-widget-primitives typecheckpnpm --filter @automattic/jetpack-premium-analytics typecheckpnpm --filter @automattic/jetpack-storybook storybook:build.Packages/Premium Analytics/Widgets/AverageItemsPerOrder / WidgetDashboardWithWidget.