Conversation
📝 WalkthroughWalkthroughA new Analytics page is added end-to-end. On the backend, Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (3 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: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@assets/vue/views/AnalyticsView.vue`:
- Around line 71-125: The empty-state sections in AnalyticsView.vue are
rendering before loadAnalytics() finishes, which causes a misleading “no data”
flash on first paint. Update the loading logic in AnalyticsView and the affected
empty-state blocks to stay hidden until the initial fetch completes, either by
introducing a hasLoaded flag or by guarding all “No ... found” branches with
!isLoading. Make sure the fix is applied consistently across the
domainConfirmation view and the other matching empty states so the template only
shows “no data” after the data request has actually finished.
- Around line 306-320: The formatDate helper in AnalyticsView.vue currently
passes date-only strings straight into new Date, which can shift the displayed
day in some time zones. Update formatDate to detect YYYY-MM-DD inputs and
normalize them before formatting, while keeping the existing Unknown date
fallback and Intl.DateTimeFormat output.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 137c0e28-face-46b0-ab9a-c3fa52df4efc
📒 Files selected for processing (6)
assets/router/index.jsassets/vue/api.jsassets/vue/views/AnalyticsView.spec.jsassets/vue/views/AnalyticsView.vuesrc/Controller/AnalyticsController.phptests/Integration/Controller/AnalyticsControllerTest.php
| <div v-if="domainConfirmation" class="space-y-4"> | ||
| <div> | ||
| <p class="text-xs uppercase tracking-wide text-slate-500">Domain</p> | ||
| <p class="mt-1 break-all text-sm font-semibold text-slate-900"> | ||
| {{ domainConfirmation.domain || 'Unknown domain' }} | ||
| </p> | ||
| </div> | ||
|
|
||
| <div class="grid grid-cols-2 gap-3 text-sm"> | ||
| <div class="rounded-lg bg-emerald-50 px-3 py-3"> | ||
| <p class="text-xs uppercase tracking-wide text-emerald-700">Confirmed</p> | ||
| <p class="mt-1 text-lg font-bold text-emerald-900"> | ||
| {{ formatCount(domainConfirmation.confirmed) }} | ||
| </p> | ||
| </div> | ||
| <div class="rounded-lg bg-amber-50 px-3 py-3"> | ||
| <p class="text-xs uppercase tracking-wide text-amber-700">Unconfirmed</p> | ||
| <p class="mt-1 text-lg font-bold text-amber-900"> | ||
| {{ formatCount(domainConfirmation.unconfirmed) }} | ||
| </p> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div> | ||
| <div class="mb-2 flex items-center justify-between text-xs text-slate-500"> | ||
| <span>Confirmation rate</span> | ||
| <span>{{ formatPercentage(domainConfirmation.confirmationRate) }}</span> | ||
| </div> | ||
| <div class="h-2 overflow-hidden rounded-full bg-slate-100"> | ||
| <div | ||
| class="h-full rounded-full bg-emerald-500" | ||
| :style="{ width: `${clampPercentage(domainConfirmation.confirmationRate)}%` }" | ||
| /> | ||
| </div> | ||
| </div> | ||
|
|
||
| <dl class="grid grid-cols-3 gap-3 text-sm"> | ||
| <div class="rounded-lg bg-slate-50 px-3 py-3"> | ||
| <dt class="text-xs uppercase tracking-wide text-slate-500">Total</dt> | ||
| <dd class="mt-1 font-semibold text-slate-900">{{ formatCount(domainConfirmation.total) }}</dd> | ||
| </div> | ||
| <div class="rounded-lg bg-slate-50 px-3 py-3"> | ||
| <dt class="text-xs uppercase tracking-wide text-slate-500">Confirmed</dt> | ||
| <dd class="mt-1 font-semibold text-slate-900">{{ formatCount(domainConfirmation.confirmed) }}</dd> | ||
| </div> | ||
| <div class="rounded-lg bg-slate-50 px-3 py-3"> | ||
| <dt class="text-xs uppercase tracking-wide text-slate-500">Unconfirmed</dt> | ||
| <dd class="mt-1 font-semibold text-slate-900">{{ formatCount(domainConfirmation.unconfirmed) }}</dd> | ||
| </div> | ||
| </dl> | ||
| </div> | ||
|
|
||
| <div v-else class="flex min-h-[260px] items-center justify-center text-sm text-slate-500"> | ||
| No confirmation data found. | ||
| </div> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Avoid the false “no data” flash on first paint.
loadAnalytics() starts in onMounted, so the first render happens with empty refs and isLoading === false. That briefly shows “No ... found” states before any request has finished. A hasLoaded flag, or consistently gating those empty states behind !isLoading, would make the UI truthful.
Also applies to: 152-156, 193-197, 241-245, 287-288, 486-486
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@assets/vue/views/AnalyticsView.vue` around lines 71 - 125, The empty-state
sections in AnalyticsView.vue are rendering before loadAnalytics() finishes,
which causes a misleading “no data” flash on first paint. Update the loading
logic in AnalyticsView and the affected empty-state blocks to stay hidden until
the initial fetch completes, either by introducing a hasLoaded flag or by
guarding all “No ... found” branches with !isLoading. Make sure the fix is
applied consistently across the domainConfirmation view and the other matching
empty states so the template only shows “no data” after the data request has
actually finished.
| const formatDate = (dateValue) => { | ||
| if (!dateValue) { | ||
| return 'Unknown date' | ||
| } | ||
|
|
||
| const date = new Date(dateValue) | ||
| if (Number.isNaN(date.getTime())) { | ||
| return 'Unknown date' | ||
| } | ||
|
|
||
| return new Intl.DateTimeFormat('en-US', { | ||
| year: 'numeric', | ||
| month: 'short', | ||
| day: '2-digit', | ||
| }).format(date) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== outline AnalyticsView.vue ==\n'
ast-grep outline assets/vue/views/AnalyticsView.vue --view expanded || true
printf '\n== relevant slices AnalyticsView.vue ==\n'
sed -n '260,360p' assets/vue/views/AnalyticsView.vue
printf '\n---\n'
sed -n '420,540p' assets/vue/views/AnalyticsView.vue
printf '\n== relevant slices AnalyticsView.spec.js ==\n'
sed -n '1,240p' assets/vue/views/AnalyticsView.spec.js
printf '\n== node date probe ==\n'
node - <<'JS'
const d = new Date('2026-06-01');
console.log('toISOString', d.toISOString());
console.log('en-US default', new Intl.DateTimeFormat('en-US',{year:'numeric',month:'short',day:'2-digit'}).format(d));
console.log('TZ', process.env.TZ || '(default)');
JSRepository: phpList/web-frontend
Length of output: 7721
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== template slice AnalyticsView.vue ==\n'
sed -n '1,260p' assets/vue/views/AnalyticsView.vue
printf '\n== search loading / empty state branches ==\n'
rg -n "isLoading|empty|No|nothing|failed|v-if|v-else" assets/vue/views/AnalyticsView.vueRepository: phpList/web-frontend
Length of output: 12389
Parse date-only strings before formatting. new Date('2026-06-01') is treated as UTC midnight, so local formatting can show the previous day in some time zones. Normalize YYYY-MM-DD values before passing them to Date.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@assets/vue/views/AnalyticsView.vue` around lines 306 - 320, The formatDate
helper in AnalyticsView.vue currently passes date-only strings straight into new
Date, which can shift the displayed day in some time zones. Update formatDate to
detect YYYY-MM-DD inputs and normalize them before formatting, while keeping the
existing Unknown date fallback and Intl.DateTimeFormat output.
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Summary
Provide a general description of the code changes in your pull request …
were there any bugs you had fixed? If so, mention them. If these bugs have open
GitHub issues, be sure to tag them here as well, to keep the conversation
linked together.
Unit test
Are your changes covered with unit tests, and do they not break anything?
You can run the existing unit tests using this command:
Code style
Have you checked that you code is well-documented and follows the PSR-2 coding
style?
You can check for this using this command:
Other Information
If there's anything else that's important and relevant to your pull
request, mention that information here. This could include benchmarks,
or other information.
If you are updating any of the CHANGELOG files or are asked to update the
CHANGELOG files by reviewers, please add the CHANGELOG entry at the top of the file.
Thanks for contributing to phpList!