fix: prevent inconsistent demo data display across dashboard charts#1402
Conversation
|
Warning Rate limit exceeded@riderx has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 12 minutes and 50 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughAdds a new AppNotFoundModal component and TypeScript declaration; refactors dashboard demo-mode gating to use Changes
Sequence DiagramsequenceDiagram
actor User
participant Page as App Detail Page
participant Store as DashboardAppsStore
participant Modal as AppNotFoundModal
participant Router as Vue Router
User->>Page: Navigate to app URL
Page->>Store: ensure apps loaded / check isLoaded & apps.length
Page->>Page: loadAppInfo()
alt fetch succeeds
Page->>User: Render app content (no blur)
else fetch fails
Page->>Page: set appNotFound = true, clear app
Page->>User: Blur content and show AppNotFoundModal
User->>Modal: Click "Back to Apps"
Modal->>Router: router.push('/app') via goToApps()
Router->>User: Navigate to apps list
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b9c53a96e9
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| :title="t('active_users_by_version')" | ||
| :is-loading="isLoading" | ||
| :has-data="hasData" | ||
| :is-demo-data="isDemoMode" | ||
| > |
There was a problem hiding this comment.
Guard demo rendering when chart data is null
When the devices chart fails to load (e.g., API error or empty response), rawChartData stays null, which makes isDemoMode true once loading finishes, so ChartCard renders the slot as “demo data.” However processedChartData is still null, and the <Line :data="processedChartData!"> call now executes under that demo branch, which can throw or render a broken chart while showing the demo overlay. Consider only passing is-demo-data when demo data was actually loaded (e.g., forceDemo) or guarding the slot render on processedChartData being non-null.
Useful? React with 👍 / 👎.
- Remove auto-demo mode that was incorrectly showing fake data when real data exists - Demo data now ONLY shows when forceDemo is true (payment failed modal state) - Users with apps will see their real data (even if empty) instead of fake demo data - Show blurred demo view with modal when navigating to non-existent app 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
b9c53a9 to
3135ff9
Compare
Demo data now only shows when: 1. forceDemo is true (payment failed), OR 2. User has no apps (dashboardAppsStore.apps.length === 0) If user has apps, ALWAYS show real data (even if empty). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/dashboard/UpdateStatsCard.vue (1)
351-351: Remove erroneous standalone "text" class.The class list contains a duplicate "text" token between
dark:text-whiteandtext-slate-600. Tailwind has no standalonetextutility—it should be removed.🧹 Proposed fix
- <h2 class="flex-1 min-w-0 text-2xl font-semibold leading-tight dark:text-white text text-slate-600"> + <h2 class="flex-1 min-w-0 text-2xl font-semibold leading-tight dark:text-white text-slate-600">
🧹 Nitpick comments (1)
src/components/dashboard/DeploymentStatsCard.vue (1)
107-117: Consider extracting isDemoMode to a shared composable.The identical isDemoMode logic is duplicated across DeploymentStatsCard.vue, DevicesStats.vue, and UsageCard.vue. Extracting this to a composable like
useDemoMode(forceDemo)would improve maintainability and ensure consistency.♻️ Example composable structure
Create
src/composables/useDemoMode.ts:import { computed } from 'vue' import { useDashboardAppsStore } from '~/stores/dashboardApps' export function useDemoMode(forceDemo: Ref<boolean> | boolean) { const dashboardAppsStore = useDashboardAppsStore() return computed(() => { const force = unref(forceDemo) if (force) return true if (dashboardAppsStore.apps.length > 0) return false return dashboardAppsStore.isLoaded }) }Then in components:
-const isDemoMode = computed(() => { - if (props.forceDemo) - return true - if (dashboardAppsStore.apps.length > 0) - return false - return dashboardAppsStore.isLoaded -}) +const isDemoMode = useDemoMode(() => props.forceDemo)
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/DeploymentStatsCard.vuesrc/components/dashboard/DevicesStats.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vue
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/dashboard/BundleUploadsCard.vue
🧰 Additional context used
📓 Path-based instructions (10)
src/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
src/**/*.vue: Use Vue 3 with Composition API and<script setup>syntax for frontend components
Style components using TailwindCSS with DaisyUI components
src/**/*.vue: Use Vue 3<script setup>syntax exclusively for all Vue component scripts
Use Tailwind utility classes for layout and spacing in Vue components
Use DaisyUI components (d-btn,d-input,d-card) for interactive elements in Vue components
Use Konsta components ONLY for safe area helpers (top/bottom insets) in Vue components; avoid other uses
UseuseRoute()fromvue-routerto access route parameters anduseRouter()for programmatic navigation in Vue components
Files:
src/components/dashboard/DeploymentStatsCard.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/DevicesStats.vue
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use single quotes and no semicolons per @antfu/eslint-config
Files:
src/components/dashboard/DeploymentStatsCard.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/DevicesStats.vue
src/components/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
Reusable Vue components should be organized in
src/components/directory
Files:
src/components/dashboard/DeploymentStatsCard.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/DevicesStats.vue
{capacitor.config.{ts,js},src/**/*.{ts,tsx,vue}}
📄 CodeRabbit inference engine (CLAUDE.md)
Mobile apps should use Capacitor with app ID
ee.forgr.capacitor_gofor native mobile functionality
Files:
src/components/dashboard/DeploymentStatsCard.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/DevicesStats.vue
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use
~/alias for imports fromsrc/directory in frontend TypeScript and Vue components
Files:
src/components/dashboard/DeploymentStatsCard.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/DevicesStats.vue
src/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Frontend ESLint must pass before commit; run
bun lint:fixto auto-fix issues in frontend files
Files:
src/components/dashboard/DeploymentStatsCard.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/DevicesStats.vue
**/{src,app}/{components,views,pages}/**/*.{vue,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
The web client is built with Vue.js and Tailwind CSS; lean on utility classes and composition-friendly patterns rather than bespoke CSS.
Files:
src/components/dashboard/DeploymentStatsCard.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/DevicesStats.vue
**/{src,app}/{components,views,pages}/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Use DaisyUI (
d-prefixed classes) for buttons, inputs, and other interactive primitives to keep behavior and spacing consistent.
Files:
src/components/dashboard/DeploymentStatsCard.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/DevicesStats.vue
**/{src,app}/**/*.{vue,ts,tsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Konsta components are reserved for the safe area helpers. Avoid importing
konstaanywhere else in the app.
Files:
src/components/dashboard/DeploymentStatsCard.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/DevicesStats.vue
**/{src,app}/**/*.{css,scss,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Capgo's design uses deep slate bases with the 'Extract' azure highlight (
--color-azure-500: #119eff) and soft radii; mirror the palette fromsrc/styles/style.css(e.g.,--color-primary-500: #515271) when introducing new UI.
Files:
src/components/dashboard/DeploymentStatsCard.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/DevicesStats.vue
🧠 Learnings (1)
📚 Learning: 2025-12-23T01:19:04.593Z
Learnt from: riderx
Repo: Cap-go/capgo PR: 1297
File: src/components/dashboard/DeploymentBanner.vue:77-79
Timestamp: 2025-12-23T01:19:04.593Z
Learning: In the Cap-go codebase, ensure that app permission checks never include the role 'owner'. App-level permissions should be based on the user_min_right enum with values: read, upload, write, admin, super_admin (and NOT owner). This pattern applies across Vue components that perform permission checks; if you find a check referencing 'owner' for app-level access, replace it with the appropriate user_min_right value and keep organization-level owner handling in organization.ts.
Applied to files:
src/components/dashboard/DeploymentStatsCard.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/DevicesStats.vue
⏰ 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: Run tests
🔇 Additional comments (12)
src/components/dashboard/UpdateStatsCard.vue (3)
33-36: LGTM! New forceDemo prop enables parent-controlled demo mode.The prop definition is correct and aligns with the PR objectives to allow Usage.vue to control demo mode for payment failures and non-existent apps.
85-95: Demo mode logic correctly implements the new gating strategy.The logic properly handles:
- Force demo when payment fails or app doesn't exist (forceDemo=true)
- Never show demo when user has apps (even if data is empty)
- Show demo only when user truly has no apps
During initial load when the store is not yet loaded, isDemoMode returns false (showing empty real data with the loading spinner), then updates once the store loads. This provides better UX than flashing demo data during load.
97-113: LGTM! Effective data computed properties cleanly separate demo and real data.The computed properties consistently route display values through the isDemoMode gate, ensuring that either demo or real data is shown, never mixed. This directly addresses the PR objective to prevent inconsistent demo data display.
src/components/dashboard/DeploymentStatsCard.vue (2)
107-117: LGTM! Demo mode logic is clear and well-structured.The new isDemoMode computation cleanly separates the three cases: explicit forceDemo (payment failure), user with apps (show real data only), and new users (show demo). The comments effectively explain the behavior change.
107-117: No issue found. ThedashboardAppsStore.appsis always initialized as an array and every code path in the store (lines 8, 46, 47, 66, 68, 75, 103) ensures it remains an array. The patternapps.value = data || []in the fetch logic (line 74) provides a fallback to an empty array if the Supabase query returns null or undefined. Accessing.lengthonappsis safe.src/components/dashboard/DevicesStats.vue (3)
16-16: LGTM! Store import added correctly.The import follows the project's conventions with the
~/alias and integrates properly with the new isDemoMode logic below.
427-438: LGTM! Consistent demo mode logic.The isDemoMode implementation matches the pattern established in DeploymentStatsCard.vue, ensuring consistent behavior across all dashboard charts. The comments clearly document the three-tier logic.
530-530: LGTM! Helpful contextual comment.The comment explicitly ties
forceDemoto the "payment failed" scenario, which clarifies the intended use case for readers of the code.src/components/dashboard/UsageCard.vue (4)
13-13: LGTM! Store import added correctly.The import follows project conventions and enables the new isDemoMode logic.
50-54: LGTM! Well-documented prop addition.The
forceDemoprop is clearly defined with an appropriate default and a helpful comment explaining its purpose in the payment failed scenario.
85-96: LGTM! Consistent demo mode implementation.The isDemoMode logic matches the pattern in DeploymentStatsCard.vue and DevicesStats.vue, ensuring all dashboard charts behave consistently. The three-tier check (forceDemo → apps.length → isLoaded) provides clear precedence.
97-99: LGTM! Clean separation of demo and real data paths.The effective computed properties provide a clean abstraction that switches between demo and real data based on
isDemoMode, making the downstream logic simpler and easier to reason about.
All charts now show "No Data" text instead of empty charts when: - total/count is 0 AND - not in demo mode This makes the behavior consistent across all dashboard charts. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
src/components/dashboard/UsageCard.vue (1)
85-96: Consider moving store instantiation to module level for consistency.The
useDashboardAppsStore()is called inside the computed property, which differs fromUpdateStatsCard.vuewhere the store is instantiated at the module level (line 59). While functionally correct (Pinia stores are singletons), moving it to the top level improves consistency and avoids the slight overhead of calling the function on each computed evaluation.♻️ Suggested refactor
import { useDashboardAppsStore } from '~/stores/dashboardApps' import ChartCard from './ChartCard.vue' import LineChartStats from './LineChartStats.vue' + +const dashboardAppsStore = useDashboardAppsStore() const props = defineProps({Then update the computed:
// Demo mode: show demo data only when forceDemo is true OR user has no apps // If user has apps, ALWAYS show real data (even if empty) -const dashboardAppsStore = useDashboardAppsStore() const isDemoMode = computed(() => { if (props.forceDemo) return truesrc/components/dashboard/BundleUploadsCard.vue (1)
106-117: Move store instantiation to module level to matchUpdateStatsCard.vuepattern.Same issue as
UsageCard.vue:useDashboardAppsStore()is called inside the computed property (line 112), butUpdateStatsCard.vueinstantiates it at the module level. Additionally, the store is already being called incalculateStats()(line 183), so having a module-level instance would reduce duplication.♻️ Suggested refactor
import { useDashboardAppsStore } from '~/stores/dashboardApps' import { useOrganizationStore } from '~/stores/organization' import BundleUploadsChart from './BundleUploadsChart.vue' import ChartCard from './ChartCard.vue' + +const dashboardAppsStore = useDashboardAppsStore()Then update the computed and function:
const isDemoMode = computed(() => { if (props.forceDemo) return true // If user has apps, never show demo data - const dashboardAppsStore = useDashboardAppsStore() if (dashboardAppsStore.apps.length > 0) return false // No apps and store is loaded = show demo return dashboardAppsStore.isLoaded })else { // Multiple apps mode - use store for shared apps data - const dashboardAppsStore = useDashboardAppsStore() // Force fetch if org changed to ensure we get fresh data await dashboardAppsStore.fetchApps(orgChanged)
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/DevicesStats.vuesrc/components/dashboard/UpdateStatsCard.vuesrc/components/dashboard/UsageCard.vue
🚧 Files skipped from review as they are similar to previous changes (1)
- src/components/dashboard/DevicesStats.vue
🧰 Additional context used
📓 Path-based instructions (10)
src/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
src/**/*.vue: Use Vue 3 with Composition API and<script setup>syntax for frontend components
Style components using TailwindCSS with DaisyUI components
src/**/*.vue: Use Vue 3<script setup>syntax exclusively for all Vue component scripts
Use Tailwind utility classes for layout and spacing in Vue components
Use DaisyUI components (d-btn,d-input,d-card) for interactive elements in Vue components
Use Konsta components ONLY for safe area helpers (top/bottom insets) in Vue components; avoid other uses
UseuseRoute()fromvue-routerto access route parameters anduseRouter()for programmatic navigation in Vue components
Files:
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/UpdateStatsCard.vue
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use single quotes and no semicolons per @antfu/eslint-config
Files:
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/UpdateStatsCard.vue
src/components/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
Reusable Vue components should be organized in
src/components/directory
Files:
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/UpdateStatsCard.vue
{capacitor.config.{ts,js},src/**/*.{ts,tsx,vue}}
📄 CodeRabbit inference engine (CLAUDE.md)
Mobile apps should use Capacitor with app ID
ee.forgr.capacitor_gofor native mobile functionality
Files:
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/UpdateStatsCard.vue
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use
~/alias for imports fromsrc/directory in frontend TypeScript and Vue components
Files:
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/UpdateStatsCard.vue
src/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Frontend ESLint must pass before commit; run
bun lint:fixto auto-fix issues in frontend files
Files:
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/UpdateStatsCard.vue
**/{src,app}/{components,views,pages}/**/*.{vue,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
The web client is built with Vue.js and Tailwind CSS; lean on utility classes and composition-friendly patterns rather than bespoke CSS.
Files:
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/UpdateStatsCard.vue
**/{src,app}/{components,views,pages}/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Use DaisyUI (
d-prefixed classes) for buttons, inputs, and other interactive primitives to keep behavior and spacing consistent.
Files:
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/UpdateStatsCard.vue
**/{src,app}/**/*.{vue,ts,tsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Konsta components are reserved for the safe area helpers. Avoid importing
konstaanywhere else in the app.
Files:
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/UpdateStatsCard.vue
**/{src,app}/**/*.{css,scss,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Capgo's design uses deep slate bases with the 'Extract' azure highlight (
--color-azure-500: #119eff) and soft radii; mirror the palette fromsrc/styles/style.css(e.g.,--color-primary-500: #515271) when introducing new UI.
Files:
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/UpdateStatsCard.vue
🧠 Learnings (1)
📚 Learning: 2025-12-23T01:19:04.593Z
Learnt from: riderx
Repo: Cap-go/capgo PR: 1297
File: src/components/dashboard/DeploymentBanner.vue:77-79
Timestamp: 2025-12-23T01:19:04.593Z
Learning: In the Cap-go codebase, ensure that app permission checks never include the role 'owner'. App-level permissions should be based on the user_min_right enum with values: read, upload, write, admin, super_admin (and NOT owner). This pattern applies across Vue components that perform permission checks; if you find a check referencing 'owner' for app-level access, replace it with the appropriate user_min_right value and keep organization-level owner handling in organization.ts.
Applied to files:
src/components/dashboard/BundleUploadsCard.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/UpdateStatsCard.vue
⏰ 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). (2)
- GitHub Check: Run tests
- GitHub Check: Analyze (java-kotlin)
🔇 Additional comments (4)
src/components/dashboard/UpdateStatsCard.vue (2)
82-95: LGTM! Clean demo mode gating logic.The
isDemoModecomputed property correctly prioritizesforceDemo, then checks for real apps, and falls back to showing demo data only when the store is loaded with no apps. The store is properly instantiated at module level (line 59).
115-115: LGTM!The
hasDatalogic correctly ensures charts display content in demo mode or when there's real data, aligning with the PR objective to show consistent "No Data" text whentotalis 0 and not in demo mode.src/components/dashboard/UsageCard.vue (1)
141-141: LGTM!The
hasDatalogic correctly handles both demo mode and real data scenarios.src/components/dashboard/BundleUploadsCard.vue (1)
126-126: LGTM!The
hasDatalogic aligns with the other dashboard components.
For charts like Storage, the total can be > 0 (cumulative) but there may be no activity in the current period. Now we: - Still show the total value in the header (0.04GB) - Show "No Data" in the chart area when there's no chart activity This is different from other charts where total = sum of chart data. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When chart data has very small values (e.g., 0.04 GB storage), the Y-axis now scales based on actual data max + 20% padding, instead of defaulting to a large range (0-1) that makes the line nearly invisible. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The tooltip was using absolute page coordinates but is appended to the canvas parent element. Now uses tooltip.caretX/Y directly (relative to canvas) and bounds-checks against canvas dimensions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The first vertical and horizontal lines of charts had a different color than other grid lines due to Chart.js axis border styling. Now hiding the axis border lines so all grid lines have consistent appearance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The tooltip now uses the actual label value from the chart's X-axis instead of calculating from cycleStart + dataIndex. This ensures the tooltip date always matches what's shown on the X-axis at that position. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- getDaysBetweenDates now normalizes both dates to midnight before calculating - reloadAllCharts now normalizes date range to start of day - This ensures the first day of the 30-day range includes all data from midnight 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @src/services/chartTooltip.ts:
- Around line 189-217: The local variable tooltipDate is declared only inside
the if/else branches so the click handler can't access it; to fix, declare let
tooltipDate: Date | undefined (and ensure formattedTitle remains) in the outer
scope before the branch that computes it, assign tooltipDate inside both the
"labelAtIndex !== undefined" branch (where you create and adjust tooltipDate)
and in the fallback branch (using getDateFromIndex), then use tooltipDate in the
click handler after guarding for undefined; update references to
formatDateForTooltip(tooltipDate) to only be called when tooltipDate is set and
keep formattedTitle assignment in the same outer scope so both the tooltip
rendering and the click handler can access the computed values.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/components/dashboard/LineChartStats.vuesrc/components/dashboard/Usage.vuesrc/components/dashboard/UsageCard.vuesrc/services/chartConfig.tssrc/services/chartTooltip.tssrc/services/conversion.ts
🧰 Additional context used
📓 Path-based instructions (12)
src/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
src/**/*.vue: Use Vue 3 with Composition API and<script setup>syntax for frontend components
Style components using TailwindCSS with DaisyUI components
src/**/*.vue: Use Vue 3<script setup>syntax exclusively for all Vue component scripts
Use Tailwind utility classes for layout and spacing in Vue components
Use DaisyUI components (d-btn,d-input,d-card) for interactive elements in Vue components
Use Konsta components ONLY for safe area helpers (top/bottom insets) in Vue components; avoid other uses
UseuseRoute()fromvue-routerto access route parameters anduseRouter()for programmatic navigation in Vue components
Files:
src/components/dashboard/Usage.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/LineChartStats.vue
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use single quotes and no semicolons per @antfu/eslint-config
Files:
src/components/dashboard/Usage.vuesrc/components/dashboard/UsageCard.vuesrc/services/chartConfig.tssrc/services/chartTooltip.tssrc/components/dashboard/LineChartStats.vuesrc/services/conversion.ts
src/components/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
Reusable Vue components should be organized in
src/components/directory
Files:
src/components/dashboard/Usage.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/LineChartStats.vue
{capacitor.config.{ts,js},src/**/*.{ts,tsx,vue}}
📄 CodeRabbit inference engine (CLAUDE.md)
Mobile apps should use Capacitor with app ID
ee.forgr.capacitor_gofor native mobile functionality
Files:
src/components/dashboard/Usage.vuesrc/components/dashboard/UsageCard.vuesrc/services/chartConfig.tssrc/services/chartTooltip.tssrc/components/dashboard/LineChartStats.vuesrc/services/conversion.ts
src/**/*.{ts,tsx,vue,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Use
~/alias for imports fromsrc/directory in frontend TypeScript and Vue components
Files:
src/components/dashboard/Usage.vuesrc/components/dashboard/UsageCard.vuesrc/services/chartConfig.tssrc/services/chartTooltip.tssrc/components/dashboard/LineChartStats.vuesrc/services/conversion.ts
src/**/*.{vue,ts,js}
📄 CodeRabbit inference engine (.github/copilot-instructions.md)
Frontend ESLint must pass before commit; run
bun lint:fixto auto-fix issues in frontend files
Files:
src/components/dashboard/Usage.vuesrc/components/dashboard/UsageCard.vuesrc/services/chartConfig.tssrc/services/chartTooltip.tssrc/components/dashboard/LineChartStats.vuesrc/services/conversion.ts
**/{src,app}/{components,views,pages}/**/*.{vue,css,scss}
📄 CodeRabbit inference engine (AGENTS.md)
The web client is built with Vue.js and Tailwind CSS; lean on utility classes and composition-friendly patterns rather than bespoke CSS.
Files:
src/components/dashboard/Usage.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/LineChartStats.vue
**/{src,app}/{components,views,pages}/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Use DaisyUI (
d-prefixed classes) for buttons, inputs, and other interactive primitives to keep behavior and spacing consistent.
Files:
src/components/dashboard/Usage.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/LineChartStats.vue
**/{src,app}/**/*.{vue,ts,tsx,js}
📄 CodeRabbit inference engine (AGENTS.md)
Konsta components are reserved for the safe area helpers. Avoid importing
konstaanywhere else in the app.
Files:
src/components/dashboard/Usage.vuesrc/components/dashboard/UsageCard.vuesrc/services/chartConfig.tssrc/services/chartTooltip.tssrc/components/dashboard/LineChartStats.vuesrc/services/conversion.ts
**/{src,app}/**/*.{css,scss,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Capgo's design uses deep slate bases with the 'Extract' azure highlight (
--color-azure-500: #119eff) and soft radii; mirror the palette fromsrc/styles/style.css(e.g.,--color-primary-500: #515271) when introducing new UI.
Files:
src/components/dashboard/Usage.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/LineChartStats.vue
src/services/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
API clients and external service integrations should be organized in
src/services/directory
Files:
src/services/chartConfig.tssrc/services/chartTooltip.tssrc/services/conversion.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Use TypeScript strict mode with path aliases mapping
~/tosrc/
Files:
src/services/chartConfig.tssrc/services/chartTooltip.tssrc/services/conversion.ts
🧠 Learnings (1)
📚 Learning: 2025-12-23T01:19:04.593Z
Learnt from: riderx
Repo: Cap-go/capgo PR: 1297
File: src/components/dashboard/DeploymentBanner.vue:77-79
Timestamp: 2025-12-23T01:19:04.593Z
Learning: In the Cap-go codebase, ensure that app permission checks never include the role 'owner'. App-level permissions should be based on the user_min_right enum with values: read, upload, write, admin, super_admin (and NOT owner). This pattern applies across Vue components that perform permission checks; if you find a check referencing 'owner' for app-level access, replace it with the appropriate user_min_right value and keep organization-level owner handling in organization.ts.
Applied to files:
src/components/dashboard/Usage.vuesrc/components/dashboard/UsageCard.vuesrc/components/dashboard/LineChartStats.vue
🪛 GitHub Actions: Run tests
src/services/chartTooltip.ts
[error] 318-318: Cannot find name 'tooltipDate'. TS2304. Reported by vue-tsc --noEmit during typecheck.
🔇 Additional comments (10)
src/services/conversion.ts (1)
29-38: LGTM! Date normalization ensures consistent day calculations.The midnight normalization prevents time-of-day variations from affecting the day count calculation. Since
firstDateandsecondDateare local copies, mutating them withsetHoursis safe.src/services/chartTooltip.ts (1)
337-374: LGTM! Canvas-relative positioning with proper bounds checking.The positioning logic correctly:
- Uses
tooltip.caretX/Ywhich are canvas-relative coordinates- Clamps horizontal position to keep tooltip within canvas bounds
- Handles vertical overflow by repositioning above the caret
src/components/dashboard/Usage.vue (2)
183-204: LGTM! Date normalization for consistent chart reloading.The midnight normalization at lines 186-188 ensures consistent 30-day windows when reloading charts, aligning with the
getDaysBetweenDatesnormalization inconversion.ts.
725-752: LGTM! ConsistentforceDemoprop forwarding to all chart components.The
forceDemoprop is correctly passed to allUsageCardinstances and other dashboard stat components, ensuring unified demo mode behavior across the dashboard.src/components/dashboard/LineChartStats.vue (2)
386-412: LGTM! Auto-scaling Y-axis with appropriate padding.The
dataMaxcomputed property correctly:
- Aggregates values from both main data and per-app data
- Filters for valid finite numbers
- Adds 20% padding to prevent data from touching the top edge
- Returns
undefinedwhen no valid data exists, allowing Chart.js defaults
414-439: LGTM! ConditionalsuggestedMaxapplication.The scales are created once and
suggestedMaxis applied only whendataMaxis defined, avoiding unnecessary overrides of Chart.js defaults.src/services/chartConfig.ts (2)
42-64: LGTM! Clean axis configuration with hidden borders.The
border: { display: false }configuration hides the axis border line, creating a cleaner visual appearance that aligns with the grid lines. ThegridColorvariable extraction improves readability.
69-110: LGTM! Consistent Y-axis configuration.The Y-axis configuration mirrors the X-axis pattern with hidden borders and extracted
gridColorvariable.src/components/dashboard/UsageCard.vue (2)
85-99: LGTM! Well-structured demo mode logic.The
isDemoModecomputed property correctly implements the hierarchy:
forceDemoprop takes precedence (for payment-failed/app-not-found states)- Users with apps always see real data (even if empty)
- New users without apps see demo data after store is loaded
This prevents the inconsistent mixed real/demo data display mentioned in the PR objectives.
141-149: LGTM! Correct chart data presence check.The
hasChartDatacomputed properly distinguishes between:
- Demo mode (always has data to show)
- Real data with actual activity (values > 0)
This handles the edge case mentioned in the summary where Storage total > 0 but no period activity.
Set end date to 23:59:59.999 instead of 00:00:00 so today's data is included in the query results. Also fixes TypeScript error where tooltipDate variable was used outside its block scope. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Changed the end date from today (which excludes today's data) to tomorrow at midnight. This ensures the backend query includes all data from today. Fixed in three locations: - organization.ts: initial dashboard load - Usage.vue reloadAllCharts(): manual refresh - Usage.vue getUsages(): data fetching Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
|
…1402) * fix: only show demo data when payment failed (forceDemo=true) - Remove auto-demo mode that was incorrectly showing fake data when real data exists - Demo data now ONLY shows when forceDemo is true (payment failed modal state) - Users with apps will see their real data (even if empty) instead of fake demo data - Show blurred demo view with modal when navigating to non-existent app 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: use dashboardAppsStore to determine demo mode for charts Demo data now only shows when: 1. forceDemo is true (payment failed), OR 2. User has no apps (dashboardAppsStore.apps.length === 0) If user has apps, ALWAYS show real data (even if empty). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: show 'No Data' consistently when chart has no data All charts now show "No Data" text instead of empty charts when: - total/count is 0 AND - not in demo mode This makes the behavior consistent across all dashboard charts. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: show 'No Data' in chart when no activity but total exists (Storage) For charts like Storage, the total can be > 0 (cumulative) but there may be no activity in the current period. Now we: - Still show the total value in the header (0.04GB) - Show "No Data" in the chart area when there's no chart activity This is different from other charts where total = sum of chart data. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: auto-scale Y-axis to make small values visible in charts When chart data has very small values (e.g., 0.04 GB storage), the Y-axis now scales based on actual data max + 20% padding, instead of defaulting to a large range (0-1) that makes the line nearly invisible. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: correct tooltip positioning to use relative canvas coordinates The tooltip was using absolute page coordinates but is appended to the canvas parent element. Now uses tooltip.caretX/Y directly (relative to canvas) and bounds-checks against canvas dimensions. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: hide chart axis border lines for consistent grid appearance The first vertical and horizontal lines of charts had a different color than other grid lines due to Chart.js axis border styling. Now hiding the axis border lines so all grid lines have consistent appearance. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: align tooltip date with actual chart X-axis label The tooltip now uses the actual label value from the chart's X-axis instead of calculating from cycleStart + dataIndex. This ensures the tooltip date always matches what's shown on the X-axis at that position. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: normalize dates to midnight for consistent chart data alignment - getDaysBetweenDates now normalizes both dates to midnight before calculating - reloadAllCharts now normalizes date range to start of day - This ensures the first day of the 30-day range includes all data from midnight 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: include today's data in 30-day chart date range Set end date to 23:59:59.999 instead of 00:00:00 so today's data is included in the query results. Also fixes TypeScript error where tooltipDate variable was used outside its block scope. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: use tomorrow midnight as end date for MAU/storage/bandwidth queries Changed the end date from today (which excludes today's data) to tomorrow at midnight. This ensures the backend query includes all data from today. Fixed in three locations: - organization.ts: initial dashboard load - Usage.vue reloadAllCharts(): manual refresh - Usage.vue getUsages(): data fetching Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>



Summary
hasAnyRealDataprop to coordinate demo mode across sibling charts - if any chart has real data, none will show demo data (prevents mixed real/fake data display)AppNotFoundModalcomponent for consistent UX when app doesn't existTest plan
/app/non-existent-app-idshows blurred demo charts with "App Not Found" modal🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Refactor
UX
✏️ Tip: You can customize this high-level summary in your review settings.