Add jszip dependency and implement standalone fetch functions for ana…#756
Add jszip dependency and implement standalone fetch functions for ana…#756
Conversation
…lytics and GSC data - Added jszip as a dependency in package.json and package-lock.json. - Implemented standalone fetch functions for metric data, overview bucketed data, event names, outbound links, and GSC data to facilitate exports. - Enhanced the ShareSite component with tooltip support for improved user experience. - Refactored various components for better UI consistency and accessibility.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
…ters - Changed all instances of the common parameters reference in the API documentation from '/docs/api/stats/reference#common-parameters' to '/docs/api/stats/getting-started#common-parameters' for consistency and clarity.
WalkthroughAdds jszip dependency and introduces standalone fetch functions across analytics and GSC APIs for data retrieval. Implements ExportButton component that concurrently fetches multiple metric datasets, aggregates results, and downloads as a ZIP file. Updates documentation links and exports CSV/ZIP generation utilities. Changes
Sequence DiagramsequenceDiagram
participant User
participant ExportButton
participant FetchFunctions as Fetch Functions<br/>(metrics, events,<br/>GSC, etc.)
participant CSV as CSV Generator
participant JSZip
participant Browser
User->>ExportButton: Click export
ExportButton->>ExportButton: Validate site
par Concurrent Fetches
ExportButton->>FetchFunctions: fetchMetric (referrers, pages, devices, countries, network*)
ExportButton->>FetchFunctions: fetchOverviewBucketed
ExportButton->>FetchFunctions: fetchWeekdayHeatmap
ExportButton->>FetchFunctions: fetchEventNames
ExportButton->>FetchFunctions: fetchOutboundLinks
ExportButton->>FetchFunctions: checkGSCConnection → fetchGSCData (conditional)
end
FetchFunctions-->>ExportButton: Return data (with fallback to [] on error)
ExportButton->>ExportButton: Filter non-empty datasets
alt Data exists
ExportButton->>CSV: generateCSV (for each dataset)
CSV-->>ExportButton: CSV strings
ExportButton->>JSZip: Create ZIP, add CSV files
JSZip-->>ExportButton: ZIP blob
ExportButton->>Browser: Create download link & trigger
Browser->>User: Download ZIP file
ExportButton->>User: Toast: Success
else No data
ExportButton->>User: Toast: "No data to export"
end
opt Error occurred
ExportButton->>User: Toast: Error message
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (8)
client/src/api/gsc/useGSCData.ts (1)
2-52:fetchGSCDataimplementation looks correct; consider reusing it in the hookThe standalone
fetchGSCDatacorrectly:
- Uses the shared
Timetype for strict typing.- Reuses
getQueryParams(time)andauthedFetch<{ data: GSCData[] }>with the same URL and params shape asuseGSCData.To avoid duplication and keep the endpoint contract in one place, you could have the hook delegate to this helper, e.g.:
queryFn: () => fetchGSCData(site, dimension, time),so any future changes to the fetch shape only need to be done once.
As per coding guidelines, this keeps the TypeScript typing strict while reducing duplication.
client/src/api/gsc/useGSCConnection.ts (1)
64-71: Standalone GSC status fetcher is correct and matches the hook behavior
fetchGSCConnectionStatusis a straightforward wrapper aroundauthedFetchwith the same URL and typing asuseGSCConnection, which is ideal for reuse in non-hook contexts like exports. You might optionally haveuseGSCConnectioncall this helper to keep the endpoint path and typing in one place, but it’s not required.client/src/app/[site]/components/SubHeader/ShareSite.tsx (1)
1-3: Tooltip-wrapped share trigger looks good; drop the no-op onClickThe Tooltip +
DropdownMenuTrigger asChildcomposition around the shareButtonis sound and keeps the interaction clear. The only nit isonClick={() => {}}on the trigger button, which doesn’t do anything and can be removed to reduce noise.Also applies to: 9-12, 16-16, 22-31
client/src/api/analytics/events/useGetOutboundLinks.ts (1)
20-31: Align filters behavior between hook and standalone fetch
useGetOutboundLinksusesgetFilteredFilters(EVENT_FILTERS), whilefetchOutboundLinkstakes a rawFilter[]and forwards it directly. When callers passuseStore().filters(e.g., from the export flow), they may be applying a different filter set than the hook. Consider either:
- documenting that
filtersis expected to be pre-filtered for outbound events, or- internally applying the same
getFilteredFilters(EVENT_FILTERS)logic (or reusing the hook’s helper) to keep behavior consistent.You could also have the hook call
fetchOutboundLinks(site, time, filteredFilters)to centralize the URL/params construction and reduce duplication.Also applies to: 37-51
client/src/lib/export.ts (1)
22-46: Optional: short-circuitdownloadZipwhen there are no non-empty filesRight now
downloadZipwill still generate and download an empty ZIP if it’s called with only emptydataarrays. The current caller filters non-empty files before invoking it, but if this utility is reused elsewhere, you might want to early-return when everyfile.data.length === 0to avoid downloading an empty archive.client/src/app/[site]/main/components/ExportButton.tsx (2)
23-75: Metric-to-filename mappings are clear; consider centralizing for reuseThe
REFERRER_METRICS,PAGE_METRICS,DEVICE_METRICS,COUNTRY_METRICS,NETWORK_METRICS, andGSC_DIMENSIONSconstants nicely document the export surface. If other parts of the app (tables, filters, legends) rely on the same groupings, moving these into a shared config module would help avoid drift and keep things consistent.
89-188: Consider surfacing partial export failures to usersEach dataset fetch (
fetchMetric,fetchOverviewBucketed, events, outbound, GSC) swallows errors and logs a warning while still treating the export as a success as long as at least one file has data. That means users can see a “Exported N files” toast without realizing some CSVs are missing or empty because of failed requests.You might want to track whether any of these inner
try/catchblocks hit an error and:
- include that in the success toast (e.g. “Exported N files (M failed)”); or
- show a separate warning toast when there were partial failures.
This keeps the export resilient while making failures more transparent.
client/src/api/analytics/events/useGetEventNames.ts (1)
36-50: Clarify how filters should be passed tofetchEventNames
useGetEventNamesrelies ongetFilteredFilters(EVENT_FILTERS), butfetchEventNamestakes a rawFilter[]and sends it directly. When callers passuseStore().filters(as in the export flow), they may be applying a broader filter set than the hook does.Consider either:
- documenting that
filtersshould already be constrained to the event filter group, or- applying the same
getFilteredFilters(EVENT_FILTERS)logic (or similar normalization) inside this helper so the hook and standalone function behave consistently.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
client/package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (22)
client/package.json(1 hunks)client/src/api/analytics/events/useGetEventNames.ts(2 hunks)client/src/api/analytics/events/useGetOutboundLinks.ts(2 hunks)client/src/api/analytics/useGetMetric.ts(1 hunks)client/src/api/analytics/useGetOverviewBucketed.ts(2 hunks)client/src/api/gsc/useGSCConnection.ts(1 hunks)client/src/api/gsc/useGSCData.ts(2 hunks)client/src/app/[site]/components/SubHeader/ShareSite.tsx(1 hunks)client/src/app/[site]/main/components/ExportButton.tsx(1 hunks)client/src/app/[site]/main/components/MainSection/MainSection.tsx(2 hunks)client/src/components/BucketSelection.tsx(1 hunks)client/src/components/ui/tooltip.tsx(1 hunks)client/src/lib/export.ts(1 hunks)docs/content/docs/api/stats/errors.mdx(3 hunks)docs/content/docs/api/stats/events.mdx(4 hunks)docs/content/docs/api/stats/funnels.mdx(2 hunks)docs/content/docs/api/stats/goals.mdx(2 hunks)docs/content/docs/api/stats/misc.mdx(1 hunks)docs/content/docs/api/stats/overview.mdx(3 hunks)docs/content/docs/api/stats/performance.mdx(3 hunks)docs/content/docs/api/stats/sessions.mdx(2 hunks)docs/content/docs/api/stats/users.mdx(2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Use TypeScript with strict typing throughout both client and server
Use camelCase for variables and functions
Use PascalCase for components and types
Group imports by external, then internal (alphabetical within groups)
Error handling: Use try/catch blocks with specific error types
Files:
client/src/api/gsc/useGSCConnection.tsclient/src/app/[site]/main/components/ExportButton.tsxclient/src/api/analytics/useGetOverviewBucketed.tsclient/src/app/[site]/main/components/MainSection/MainSection.tsxclient/src/components/BucketSelection.tsxclient/src/api/analytics/useGetMetric.tsclient/src/lib/export.tsclient/src/api/gsc/useGSCData.tsclient/src/components/ui/tooltip.tsxclient/src/app/[site]/components/SubHeader/ShareSite.tsxclient/src/api/analytics/events/useGetEventNames.tsclient/src/api/analytics/events/useGetOutboundLinks.ts
client/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Client: React functional components with minimal useEffect and inline functions
Files:
client/src/api/gsc/useGSCConnection.tsclient/src/app/[site]/main/components/ExportButton.tsxclient/src/api/analytics/useGetOverviewBucketed.tsclient/src/app/[site]/main/components/MainSection/MainSection.tsxclient/src/components/BucketSelection.tsxclient/src/api/analytics/useGetMetric.tsclient/src/lib/export.tsclient/src/api/gsc/useGSCData.tsclient/src/components/ui/tooltip.tsxclient/src/app/[site]/components/SubHeader/ShareSite.tsxclient/src/api/analytics/events/useGetEventNames.tsclient/src/api/analytics/events/useGetOutboundLinks.ts
docs/content/{docs,blog}/**/*.{md,mdx}
📄 CodeRabbit inference engine (docs/CLAUDE.md)
Configure content files in
content/docs/andcontent/blog/to be processed by Fumadocs MDX
Files:
docs/content/docs/api/stats/errors.mdxdocs/content/docs/api/stats/performance.mdxdocs/content/docs/api/stats/funnels.mdxdocs/content/docs/api/stats/goals.mdxdocs/content/docs/api/stats/sessions.mdxdocs/content/docs/api/stats/overview.mdxdocs/content/docs/api/stats/misc.mdxdocs/content/docs/api/stats/events.mdxdocs/content/docs/api/stats/users.mdx
client/**/*.{css,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Dark mode is default theme
Files:
client/src/app/[site]/main/components/ExportButton.tsxclient/src/app/[site]/main/components/MainSection/MainSection.tsxclient/src/components/BucketSelection.tsxclient/src/components/ui/tooltip.tsxclient/src/app/[site]/components/SubHeader/ShareSite.tsx
🧠 Learnings (7)
📚 Learning: 2025-11-25T02:34:42.365Z
Learnt from: CR
Repo: rybbit-io/rybbit PR: 0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-11-25T02:34:42.365Z
Learning: Applies to docs/app/(home)/tools/**/*.{ts,tsx} : Place tool components and API routes in `app/(home)/tools/` directory for analytics and SEO tools
Applied to files:
client/src/app/[site]/main/components/ExportButton.tsx
📚 Learning: 2025-11-25T02:34:42.365Z
Learnt from: CR
Repo: rybbit-io/rybbit PR: 0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-11-25T02:34:42.365Z
Learning: Applies to docs/src/lib/trackAdEvent.ts : Track analytics events via `src/lib/trackAdEvent.ts` for monitoring tool usage and analytics
Applied to files:
client/src/app/[site]/main/components/ExportButton.tsxclient/src/api/analytics/events/useGetEventNames.tsclient/src/api/analytics/events/useGetOutboundLinks.ts
📚 Learning: 2025-11-25T02:34:24.979Z
Learnt from: CR
Repo: rybbit-io/rybbit PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T02:34:24.979Z
Learning: Frontend: Use Next.js with Turbopack, Tailwind CSS, Shadcn UI, Tanstack Query, Zustand, Luxon, Nivo, and react-hook-form
Applied to files:
client/src/app/[site]/main/components/MainSection/MainSection.tsxclient/src/api/gsc/useGSCData.ts
📚 Learning: 2025-11-25T02:34:24.979Z
Learnt from: CR
Repo: rybbit-io/rybbit PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T02:34:24.979Z
Learning: Applies to client/**/*.{ts,tsx} : Client: React functional components with minimal useEffect and inline functions
Applied to files:
client/src/app/[site]/main/components/MainSection/MainSection.tsx
📚 Learning: 2025-11-25T02:34:59.895Z
Learnt from: CR
Repo: rybbit-io/rybbit PR: 0
File: docs/src/app/(home)/tools/CLAUDE.md:0-0
Timestamp: 2025-11-25T02:34:59.895Z
Learning: Applies to docs/src/app/(home)/tools/**/tools/**/*.{tsx,ts} : Use primary color `bg-emerald-600 hover:bg-emerald-500`, success `bg-emerald-50 dark:bg-emerald-900/20 border-emerald-200 dark:border-emerald-800`, error `bg-red-50 dark:bg-red-900/20 border-red-200 dark:border-red-800` for tool components
Applied to files:
client/src/components/ui/tooltip.tsx
📚 Learning: 2025-11-25T02:34:42.365Z
Learnt from: CR
Repo: rybbit-io/rybbit PR: 0
File: docs/CLAUDE.md:0-0
Timestamp: 2025-11-25T02:34:42.365Z
Learning: Applies to docs/app/layout.config.tsx : Define shared navigation and links in `app/layout.config.tsx` for Fumadocs
Applied to files:
client/src/app/[site]/components/SubHeader/ShareSite.tsx
📚 Learning: 2025-11-25T02:34:59.895Z
Learnt from: CR
Repo: rybbit-io/rybbit PR: 0
File: docs/src/app/(home)/tools/CLAUDE.md:0-0
Timestamp: 2025-11-25T02:34:59.895Z
Learning: Applies to docs/src/app/(home)/tools/**/tools/**/page.tsx : Use optional ToolPageLayout props: `badge` (default 'Free Tool' or 'AI-Powered Tool'), `ctaButtonText` (default 'Start tracking for free'), and `structuredData` (JSON-LD object)
Applied to files:
client/src/app/[site]/components/SubHeader/ShareSite.tsx
🧬 Code graph analysis (7)
client/src/api/analytics/useGetOverviewBucketed.ts (6)
client/src/components/DateSelector/types.ts (1)
Time(44-44)server/src/api/analytics/types.ts (2)
TimeBucket(5-5)Filter(5-5)shared/src/time.ts (1)
TimeBucket(1-10)shared/src/filters.ts (1)
Filter(50-54)client/src/api/utils.ts (2)
getQueryParams(36-52)authedFetch(54-96)client/src/api/types.ts (1)
APIResponse(1-4)
client/src/app/[site]/main/components/MainSection/MainSection.tsx (2)
client/src/app/[site]/main/components/ExportButton.tsx (1)
ExportButton(76-258)client/src/components/BucketSelection.tsx (1)
BucketSelection(156-170)
client/src/api/analytics/useGetMetric.ts (1)
client/src/api/utils.ts (2)
getQueryParams(36-52)authedFetch(54-96)
client/src/api/gsc/useGSCData.ts (2)
client/src/components/DateSelector/types.ts (1)
Time(44-44)client/src/api/utils.ts (2)
getQueryParams(36-52)authedFetch(54-96)
client/src/app/[site]/components/SubHeader/ShareSite.tsx (4)
client/src/api/admin/privateLink.ts (3)
useGetPrivateLinkConfig(13-25)useGeneratePrivateLinkKey(28-50)useRevokePrivateLinkKey(53-75)client/src/components/ui/dropdown-menu.tsx (2)
DropdownMenu(183-183)DropdownMenuTrigger(184-184)client/src/components/ui/tooltip.tsx (3)
Tooltip(34-34)TooltipTrigger(34-34)TooltipContent(34-34)client/src/components/ui/button.tsx (1)
Button(60-60)
client/src/api/analytics/events/useGetEventNames.ts (2)
client/src/components/DateSelector/types.ts (1)
Time(44-44)client/src/api/utils.ts (2)
getQueryParams(36-52)authedFetch(54-96)
client/src/api/analytics/events/useGetOutboundLinks.ts (2)
client/src/components/DateSelector/types.ts (1)
Time(44-44)client/src/api/utils.ts (2)
getQueryParams(36-52)authedFetch(54-96)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Merge & Push Multi-arch Manifests
🔇 Additional comments (17)
client/src/components/BucketSelection.tsx (1)
161-165: TimerReset icon size change is fineThis is a purely visual tweak inside the trigger; no behavior or accessibility issues are introduced as the clickable area is still defined by the trigger, not the icon size.
client/package.json (1)
60-64: Newjszipdependency – confirm version and bundle impactAdding
jszipfor ZIP export is reasonable. Please double‑check that:
- The chosen version (
^3.10.1) matches your intended API usage.- It’s only pulled into client bundles where needed (e.g., via a small helper module or lazy import) so it doesn’t unnecessarily bloat initial pages.
docs/content/docs/api/stats/misc.mdx (1)
329-332: Common Parameters link now targets getting-started – looks consistentThe updated link to
/docs/api/stats/getting-started#common-parametersfor Get Journeys query params matches the new docs structure and keeps the copy accurate.docs/content/docs/api/stats/goals.mdx (2)
62-65: Updated Common Parameters link for Get GoalsThe query-parameters line now correctly references
/docs/api/stats/getting-started#common-parameters, aligning with the shared “getting started” section.
422-425: Updated Common Parameters link for Get Goal SessionsSame link update here keeps the docs consistent and avoids pointing to the old reference anchor.
client/src/components/ui/tooltip.tsx (1)
24-27: Tooltipshadow-lgaddition is safeAdding
shadow-lgtoTooltipContentis a purely stylistic enhancement; it doesn’t alter behavior or dark‑mode handling and remains compatible with the existing Radix/React wrapper.docs/content/docs/api/stats/performance.mdx (1)
68-69: Performance endpoints now consistently reference getting-started Common ParametersAll three “Accepts all Common Parameters …” lines now target
/docs/api/stats/getting-started#common-parameters, which keeps the Performance docs in sync with the rest of the Stats API documentation.Also applies to: 290-291, 521-522
docs/content/docs/api/stats/sessions.mdx (1)
56-57: Sessions docs Common Parameters links updated correctlyBoth the Get Sessions and Get Session Locations query-parameter sections now point to
/docs/api/stats/getting-started#common-parameters, matching the new canonical location for shared time/filter parameters.Also applies to: 656-657
docs/content/docs/api/stats/users.mdx (1)
60-61: Common-parameters link target looks correct and consistentBoth query-parameter sections now point to
/docs/api/stats/getting-started#common-parameters, which matches the updated pattern elsewhere. No issues.Also applies to: 377-378
client/src/app/[site]/main/components/MainSection/MainSection.tsx (1)
7-8: Export button integration into main header looks cleanAdding
ExportButtonalongsideBucketSelectionin the header, plus the corresponding imports, keeps concerns separated and UI structure straightforward. No functional or accessibility concerns from this change.Also applies to: 12-12, 86-89
docs/content/docs/api/stats/overview.mdx (1)
60-61: Updated Common-parameters links are consistent across sectionsAll three Overview-related endpoints now reference
/docs/api/stats/getting-started#common-parameters, which keeps the docs aligned with the centralized “Common Parameters” section.Also applies to: 256-257, 501-502
client/src/api/analytics/useGetOverviewBucketed.ts (1)
2-2: fetchOverviewBucketed helper is well-typed and consistent with the hookThe new
fetchOverviewBucketedcorrectly reusesgetQueryParams, preservesFilter[]handling, calls the same/overview-bucketed/:siteendpoint as the hook, and returns the unwrappedGetOverviewBucketedResponse. The addedTimeimport is appropriate for strict typing. No issues.Also applies to: 87-101
docs/content/docs/api/stats/funnels.mdx (1)
298-299: Funnels Common-parameters references now aligned with getting-startedBoth the Analyze Funnel and Funnel Step Sessions sections now use
/docs/api/stats/getting-started#common-parameters, matching the rest of the Stats API docs. Looks good.Also applies to: 713-714
docs/content/docs/api/stats/errors.mdx (1)
56-57: Error stats docs now reference centralized Common ParametersAll three error endpoints correctly point to
/docs/api/stats/getting-started#common-parameters, keeping behavior docs DRY and consistent. No further changes needed.Also applies to: 287-288, 560-561
docs/content/docs/api/stats/events.mdx (1)
60-60: Updated Common Parameters links look consistentAll references now target
/docs/api/stats/getting-started#common-parameters, which keeps the events docs aligned with the getting-started section. No issues from a docs/UX standpoint.Also applies to: 344-344, 543-543, 766-766
client/src/api/analytics/useGetMetric.ts (1)
183-200: Clarify defaultlimitforfetchMetricvsuseMetric
useMetricdefaultslimitto1000, butfetchMetricdefaults it to100, and the export code callsfetchMetricwithout overriding this. If exports are expected to contain the same number of rows as the in-app metrics, consider aligning these defaults or passing an explicit limit from the caller; if exports should be intentionally smaller, it might be worth documenting that difference.client/src/app/[site]/main/components/ExportButton.tsx (1)
80-87: Export flow, loading state, and tooltip wiring look solidGuarding on
site, disabling the button whileisExportingis true, and wrapping the icon button with a tooltip provide a good UX with minimal surface area. The async handler is correctly awaited in the click callback, and state cleanup infinallyensures the spinner resets even on errors.Also applies to: 237-255
…lytics and GSC data
Summary by CodeRabbit
New Features
Improvements
Documentation
Chores
✏️ Tip: You can customize this high-level summary in your review settings.