Skip to content

Overview dashboard, backup check_records, UTC timezone alignment#51

Merged
rafia9005 merged 34 commits into
mainfrom
dev
Jul 10, 2026
Merged

Overview dashboard, backup check_records, UTC timezone alignment#51
rafia9005 merged 34 commits into
mainfrom
dev

Conversation

@rafia9005

@rafia9005 rafia9005 commented Jul 10, 2026

Copy link
Copy Markdown
Member

Summary

4 commits on dev, grouped by subsystem:

fix(analytics): strip 'localtime' from strftime, align timestamps to UTC

  • Remove SQLite localtime modifier from all date grouping queries
  • Use UTC for startTime and now references
  • Fix unchecked db.Scan error in GetMonitorStats

fix(monitors): use UTC for CheckRecord timestamp and queries

  • NewCheckRecord uses time.Now().UTC()
  • Daily failure queries drop localtime modifier

feat(backup): include check_records, add user_id remapping on import

  • Export/import check_records table
  • Import accepts importUserID parameter to remap ownership
  • Tables without user_id (settings, tags, ssl_certs, etc.) skip remap

feat(web): add Overview dashboard page with sidebar and route

  • New /app/overview route with composable-driven dashboard
  • Sidebar entry under Analytics group with GalleryVerticalEnd icon
  • Displays monitors, SSL certs, incidents, resource summaries

Summary by CodeRabbit

  • New Features

    • Added an Overview dashboard with health metrics, trends, incidents, SSL status, endpoint analytics, and quick navigation.
    • Added Overview to the Status & Reports navigation.
    • Backup exports and imports now preserve check records and correctly associate imported records with the authenticated user.
  • Bug Fixes

    • Improved chart and monitoring reports by using consistent UTC timestamps and date grouping.
    • Database errors during monitor statistics loading are now surfaced properly.
  • Tests

    • Expanded coverage for authentication, users, backups, stores, composables, validation, and monitoring workflows.

rafia9005 and others added 30 commits July 7, 2026 16:21
Backend:
- Add ResetToken + ResetTokenExpiry fields to User entity
- RequestPasswordReset generates crypto token, stores with 1hr expiry
- ResetPassword validates token and updates bcrypt hash
- ForgotPassword handler reads SMTP from settings table, sends reset email
- ResetPassword handler accepts token + new password
- Public routes: POST /api/auth/forgot-password, POST /api/auth/reset-password

Frontend:
- ForgotPassword.vue — email form with GSAP animations, ambient orbs
- ResetPassword.vue — password + confirm form with token from query param
- Routes: /forgot-password, /reset-password (both guestOnly)
- Forgot password link below password field on login form

Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
Annotate 18 handler files with @summary, @Param, @success, @router tags.
Add SuccessResponseModel/ErrorResponseModel types for swagger references.
Add global API info and security definitions in main.go.
Add [Admin] prefix to admin-only endpoint summaries.

Co-Authored-By: Claude <noreply@anthropic.com>
Install swaggo/swag and echo-swagger packages for OpenAPI spec generation.

Co-Authored-By: Claude <noreply@anthropic.com>
Serve Scalar API reference at /api/docs/ instead of Swagger UI.
Use wildcard route that serves openapi.json spec or Scalar HTML.
Remove echo-swagger dependency import.

Co-Authored-By: Claude <noreply@anthropic.com>
Add swag init step before build in build-testing, build-release workflows,
and Dockerfile to ensure docs are always up-to-date.

Co-Authored-By: Claude <noreply@anthropic.com>
…oint

Add API Docs button in API Tokens page (links to Scalar UI).
Remove broken status filter dropdown.
Proxy /api/docs through Vite dev server.

Co-Authored-By: Claude <noreply@anthropic.com>
Cast onSubmit to any to avoid GenericObject type mismatch in template.

Co-Authored-By: Claude <noreply@anthropic.com>
Previously swagger.json was read from disk at runtime, causing empty
API docs in binary-only deployments (Docker). Now embedded via
//go:embed and served from embedded filesystem.

Generated with Claude Code
Co-Authored-By: Claude <noreply@anthropic.com>
* CodeRabbit Generated Unit Tests: Add unit tests for PR changes

* 📝 CodeRabbit Chat: Fix response test types and password form handlers (#37)

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Ahmad Rafi'i <70046808+rafia9005@users.noreply.github.com>
- Replace 'Get Started' with 'Live Demo' link to demo-ping.terarush.dev
- Add 'API Docs' button linking to /api/docs/ Scalar endpoint
- Insert CtaSection component between TeamSection and ContactSection
- Ignore landing/ changes in build-release workflow
- Add useUpdateChecker composable fetching latest GitHub release
- Compare with current version (v0.1.25)
- Show amber 'X available' banner in sidebar footer when update found
- Update siteConfig with repo metadata
- Use git describe --tags --always at build time via Vite define
- Expose as __APP_VERSION__ global (typed in env.d.ts)
- Remove hardcoded currentVersion from siteConfig
- useUpdateChecker compares against injected version
* test: add web unit coverage

* test: cover all web composables

* chore: enable CodeRabbit reviews on dev

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
* test: clean web unit runner output

* test: address web unit runner review

* test: configure vitest worker warnings

* build: suppress DEP0205 in web scripts

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
SQLite strftime with 'localtime' modifier caused inconsistent date
grouping across server timezones. Remove modifier, use UTC for all
startTime calculations. Also fix unchecked db.Scan error in
GetMonitorStats.
Align check_records table with UTC-based timestamps. Remove
'localtime' from DATE() calls in monitor dashboard queries.
Export check_records table alongside existing tables. Import now
accepts importUserID to remap user_id ownership — tables with no
user_id (check_records, settings, tags, etc.) skip remap.
New /app/overview route with composable-based dashboard showing
monitors, SSL certs, incidents, analytics, and resource summaries.
Add GalleryVerticalEnd icon to sidebar under Analytics group.
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Ignoring CodeRabbit configuration file changes. For security, only the configuration from the base branch is applied for open source repositories.

📝 Walkthrough

Walkthrough

Changes

The PR adds an authenticated overview dashboard, updates backup imports and UTC-based chart handling, and introduces broad Go and frontend test coverage for services, middleware, stores, composables, validations, and utilities.

Overview dashboard

Layer / File(s) Summary
Overview route and dashboard
web/src/router/index.ts, web/src/content/sidebar.ts, web/src/views/App.Overview.vue
Adds the overview route, sidebar entry, aggregated dashboard metrics, charts, navigation, incident timeline, and endpoint analytics.

Backend consistency and backup restoration

Layer / File(s) Summary
Backup payload and restoration
modules/backup/domain/service/backup_service.go, modules/backup/domain/service/backup_service_test.go, modules/backup/handler/backup_handler.go
Exports and restores check records, accepts an import user ID, and remaps selected restored records.
UTC metrics and timestamps
modules/analytics/..., modules/monitors/...
Uses UTC for chart windows, date grouping, and check-record timestamps, while propagating monitor scan errors.

Automated behavior coverage

Layer / File(s) Summary
Go security and service tests
internal/pkg/jwt/jwt_test.go, internal/pkg/middleware/auth_test.go, modules/auth/..., modules/users/...
Tests JWT behavior, middleware authorization, authentication workflows, password handling, and service error mapping.
Frontend composable and validation tests
web/src/composables/__tests__/*, web/src/lib/__tests__/*, web/src/validations/__tests__/*
Tests composable bindings and helpers, utility class merging, update checking, and schema validation defaults and errors.
Frontend store tests
web/src/stores/__tests__/*
Tests Pinia authentication, backup, data, realtime, SSE, CRUD, and local state behavior.
Test runtime configuration
.coderabbit.yaml, web/package.json, web/vitest.config.ts
Configures automated review scope, explicit local test binaries, and Node warning suppression.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.35% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the three main change areas in the pull request and is specific enough for history scanning.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@rafia9005 rafia9005 left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

work on testing implementation

Commented in CodeRabbit Change Stack

@rafia9005 rafia9005 merged commit bc192f1 into main Jul 10, 2026
2 checks passed

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🧹 Nitpick comments (1)
web/vitest.config.ts (1)

12-12: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider using targeted --disable-warning=DEP0205 instead of --no-warnings for consistency.

The package.json scripts use the targeted --disable-warning=DEP0205 flag, but the vitest config uses the broader --no-warnings, which suppresses all Node.js process warnings in worker processes. Using --disable-warning=DEP0205 here would be consistent and still surface other potentially important warnings (e.g., deprecations, security advisories) during test development.

♻️ Suggested alignment
-      execArgv: ['--no-warnings'],
+      execArgv: ['--disable-warning=DEP0205'],
🤖 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 `@web/vitest.config.ts` at line 12, Replace the broad --no-warnings value in
the Vitest configuration’s execArgv with the targeted --disable-warning=DEP0205
flag, matching the package scripts while preserving other Node.js warnings.
🤖 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 `@modules/backup/domain/service/backup_service.go`:
- Around line 64-92: The integrations restore currently passes user ID 0,
leaving imported records associated with the backup owner. In the restore flow
of the backup service, update the integrations restoreTable call to pass
importUserID, while leaving tags and ssl_certs unchanged.

In `@web/src/views/App.Overview.vue`:
- Around line 447-523: Make every quick-navigation tile currently implemented as
a clickable div keyboard accessible, including the elements using navigateTo for
monitors, ssl-monitors, status-pages, incidents, maintenances,
settings/notifications, integrations, tags, api-tokens, users, and teams.
Replace each with a semantic button or router link, preserving styling and
conditional isAdmin rendering, and ensure activation invokes the existing
navigateTo destination for both keyboard and pointer users.

---

Nitpick comments:
In `@web/vitest.config.ts`:
- Line 12: Replace the broad --no-warnings value in the Vitest configuration’s
execArgv with the targeted --disable-warning=DEP0205 flag, matching the package
scripts while preserving other Node.js warnings.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3d611182-bda7-4a78-9757-000918e52ddd

📥 Commits

Reviewing files that changed from the base of the PR and between 364ac29 and dd9835c.

📒 Files selected for processing (29)
  • .coderabbit.yaml
  • internal/pkg/jwt/jwt_test.go
  • internal/pkg/middleware/auth_test.go
  • modules/analytics/domain/repository/analytics_repository_impl.go
  • modules/auth/domain/service/auth_service_test.go
  • modules/backup/domain/service/backup_service.go
  • modules/backup/domain/service/backup_service_test.go
  • modules/backup/handler/backup_handler.go
  • modules/monitors/domain/entity/check_record.go
  • modules/monitors/domain/repository/monitor_repository_impl.go
  • modules/users/domain/service/user_service_test.go
  • web/package.json
  • web/src/composables/__tests__/storeBindings.test.ts
  • web/src/composables/__tests__/useApiTokens.test.ts
  • web/src/composables/__tests__/useAppTitle.test.ts
  • web/src/composables/__tests__/useIncidents.test.ts
  • web/src/composables/__tests__/useNotificationLogs.test.ts
  • web/src/composables/__tests__/useSslMonitors.test.ts
  • web/src/composables/__tests__/useUpdateChecker.test.ts
  • web/src/content/sidebar.ts
  • web/src/lib/__tests__/utils.test.ts
  • web/src/router/index.ts
  • web/src/stores/__tests__/authStore.test.ts
  • web/src/stores/__tests__/backupStore.test.ts
  • web/src/stores/__tests__/dataStores.test.ts
  • web/src/stores/__tests__/realtimeStores.test.ts
  • web/src/validations/__tests__/schemas.test.ts
  • web/src/views/App.Overview.vue
  • web/vitest.config.ts

Comment on lines +64 to +92
if err := s.restoreTable(ctx, "monitors", backup.Data.Monitors, importUserID); err != nil {
return fmt.Errorf("restore monitors: %w", err)
}
if err := s.restoreTable(ctx, "incidents", backup.Data.Incidents); err != nil {
// check_records has no user_id; monitor_id preserved, so no remap.
if err := s.restoreTable(ctx, "check_records", backup.Data.CheckRecords, 0); err != nil {
return fmt.Errorf("restore check_records: %w", err)
}
if err := s.restoreTable(ctx, "incidents", backup.Data.Incidents, importUserID); err != nil {
return fmt.Errorf("restore incidents: %w", err)
}
if err := s.restoreTable(ctx, "status_pages", backup.Data.StatusPages); err != nil {
if err := s.restoreTable(ctx, "status_pages", backup.Data.StatusPages, importUserID); err != nil {
return fmt.Errorf("restore status_pages: %w", err)
}
if err := s.restoreTable(ctx, "settings", backup.Data.Settings); err != nil {
if err := s.restoreTable(ctx, "settings", backup.Data.Settings, 0); err != nil {
return fmt.Errorf("restore settings: %w", err)
}
if err := s.restoreTable(ctx, "notification_channels", backup.Data.NotificationChannels); err != nil {
if err := s.restoreTable(ctx, "notification_channels", backup.Data.NotificationChannels, importUserID); err != nil {
return fmt.Errorf("restore notification_channels: %w", err)
}
if err := s.restoreTable(ctx, "tags", backup.Data.Tags); err != nil {
if err := s.restoreTable(ctx, "tags", backup.Data.Tags, 0); err != nil {
return fmt.Errorf("restore tags: %w", err)
}
if err := s.restoreTable(ctx, "integrations", backup.Data.Integrations); err != nil {
if err := s.restoreTable(ctx, "integrations", backup.Data.Integrations, 0); err != nil {
return fmt.Errorf("restore integrations: %w", err)
}
if err := s.restoreTable(ctx, "ssl_certs", backup.Data.SSLCerts); err != nil {
if err := s.restoreTable(ctx, "ssl_certs", backup.Data.SSLCerts, 0); err != nil {
return fmt.Errorf("restore ssl_certs: %w", err)
}
if err := s.restoreTable(ctx, "api_tokens", backup.Data.ApiTokens); err != nil {
if err := s.restoreTable(ctx, "api_tokens", backup.Data.ApiTokens, importUserID); err != nil {

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.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect ownership columns for the no-remap tables
rg -nP -C2 'user_id|UserID' -g '*ssl*' -g '*integration*' -g '*tag*' --type=go

Repository: terarush/ping-uptime

Length of output: 158


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find model/migration/schema definitions for the suspected tables
printf '\n== matching files ==\n'
git ls-files | rg '(^|/)(ssl_certs|integrations|tags)(/|\.|$)|backup_service\.go|migration|schema|model|models|entity|entities'

printf '\n== search for table names and ownership fields ==\n'
rg -n --hidden -S 'ssl_certs|integrations|tags|user_id|UserID|owner_id|OwnerID|account_id|AccountID' .

printf '\n== file outlines (if present) ==\n'
for f in $(git ls-files | rg '(^|/)(ssl_certs|integrations|tags)(/|\.|$)'); do
  echo "\n--- $f ---"
  wc -l "$f"
  sed -n '1,220p' "$f" | cat -n | sed -n '1,220p'
done

Repository: terarush/ping-uptime

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

for f in \
  modules/integrations/domain/entity/integration.go \
  modules/tags/domain/entity/tag.go \
  modules/ssl_monitors/domain/entity/ssl_cert.go \
  modules/backup/domain/service/backup_service.go
do
  echo "===== $f ====="
  wc -l "$f"
  cat -n "$f" | sed -n '1,220p'
  echo
done

Repository: terarush/ping-uptime

Length of output: 10725


Remap integrations here. modules/integrations/domain/entity/integration.go has a UserID, so 0 leaves imported rows tied to the backup owner instead of the importing account. tags and ssl_certs don’t carry ownership fields, so those are fine.

🤖 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 `@modules/backup/domain/service/backup_service.go` around lines 64 - 92, The
integrations restore currently passes user ID 0, leaving imported records
associated with the backup owner. In the restore flow of the backup service,
update the integrations restoreTable call to pass importUserID, while leaving
tags and ssl_certs unchanged.

Comment on lines +447 to +523
<div @click="navigateTo('monitors')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
<div class="p-1.5 rounded-md shrink-0 bg-emerald-500/10"><Activity class="w-3.5 h-3.5 text-emerald-500" /></div>
<div class="min-w-0">
<p class="text-[11px] font-bold truncate">Monitors</p>
<p class="text-[9px] text-muted-foreground">{{ monitors.length }}</p>
</div>
</div>
<div @click="navigateTo('ssl-monitors')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
<div class="p-1.5 rounded-md shrink-0 bg-blue-500/10"><ShieldCheck class="w-3.5 h-3.5 text-blue-500" /></div>
<div class="min-w-0">
<p class="text-[11px] font-bold truncate">SSL</p>
<p class="text-[9px] text-muted-foreground">{{ certs.length }}</p>
</div>
</div>
<div @click="navigateTo('status-pages')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
<div class="p-1.5 rounded-md shrink-0 bg-indigo-500/10"><Globe class="w-3.5 h-3.5 text-indigo-500" /></div>
<div class="min-w-0">
<p class="text-[11px] font-bold truncate">Status Pages</p>
<p class="text-[9px] text-muted-foreground">{{ statusPages.length }}</p>
</div>
</div>
<div @click="navigateTo('incidents')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
<div class="p-1.5 rounded-md shrink-0 bg-rose-500/10"><AlertCircle class="w-3.5 h-3.5 text-rose-500" /></div>
<div class="min-w-0">
<p class="text-[11px] font-bold truncate">Incidents</p>
<p class="text-[9px] text-muted-foreground">{{ incidents.length }}</p>
</div>
</div>
<div @click="navigateTo('maintenances')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
<div class="p-1.5 rounded-md shrink-0 bg-amber-500/10"><Wrench class="w-3.5 h-3.5 text-amber-500" /></div>
<div class="min-w-0">
<p class="text-[11px] font-bold truncate">Maintenances</p>
<p class="text-[9px] text-muted-foreground">{{ maintenances.length }}</p>
</div>
</div>
<div @click="navigateTo('settings/notifications')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
<div class="p-1.5 rounded-md shrink-0 bg-purple-500/10"><Bell class="w-3.5 h-3.5 text-purple-500" /></div>
<div class="min-w-0">
<p class="text-[11px] font-bold truncate">Channels</p>
<p class="text-[9px] text-muted-foreground">{{ channels.length }}</p>
</div>
</div>
<div @click="navigateTo('integrations')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
<div class="p-1.5 rounded-md shrink-0 bg-cyan-500/10"><Link class="w-3.5 h-3.5 text-cyan-500" /></div>
<div class="min-w-0">
<p class="text-[11px] font-bold truncate">Integrations</p>
<p class="text-[9px] text-muted-foreground">{{ integrations.length }}</p>
</div>
</div>
<div @click="navigateTo('tags')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
<div class="p-1.5 rounded-md shrink-0 bg-pink-500/10"><Tag class="w-3.5 h-3.5 text-pink-500" /></div>
<div class="min-w-0">
<p class="text-[11px] font-bold truncate">Tags</p>
<p class="text-[9px] text-muted-foreground">{{ tags.length }}</p>
</div>
</div>
<div @click="navigateTo('api-tokens')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
<div class="p-1.5 rounded-md shrink-0 bg-orange-500/10"><KeyRound class="w-3.5 h-3.5 text-orange-500" /></div>
<div class="min-w-0">
<p class="text-[11px] font-bold truncate">API Tokens</p>
<p class="text-[9px] text-muted-foreground">{{ tokens.length }}</p>
</div>
</div>
<div v-if="isAdmin" @click="navigateTo('users')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
<div class="p-1.5 rounded-md shrink-0 bg-sky-500/10"><Users class="w-3.5 h-3.5 text-sky-500" /></div>
<div class="min-w-0">
<p class="text-[11px] font-bold truncate">Users</p>
<p class="text-[9px] text-muted-foreground">{{ users.length }}</p>
</div>
</div>
<div v-if="isAdmin" @click="navigateTo('teams')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
<div class="p-1.5 rounded-md shrink-0 bg-violet-500/10"><UsersRound class="w-3.5 h-3.5 text-violet-500" /></div>
<div class="min-w-0">
<p class="text-[11px] font-bold truncate">Teams</p>
<p class="text-[9px] text-muted-foreground">{{ teams.length }} ({{ teams.reduce((s, t) => s + (t.member_count || 0), 0) }} members)</p>
</div>
</div>

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Quick-navigation tiles are not keyboard accessible.

These tiles use <div @click="navigateTo(...)"> with no role, tabindex, or key handler, so keyboard and screen-reader users cannot focus or activate them. Use a semantic interactive element (e.g., <button> or a router link) so navigation works without a pointer.

♿ Example fix for one tile (apply the pattern to all)
-            <div `@click`="navigateTo('monitors')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors">
+            <button type="button" `@click`="navigateTo('monitors')" class="flex items-center gap-2 p-2.5 rounded-lg border border-border/30 bg-muted/10 hover:bg-muted/20 cursor-pointer transition-colors text-left w-full">
               <div class="p-1.5 rounded-md shrink-0 bg-emerald-500/10"><Activity class="w-3.5 h-3.5 text-emerald-500" /></div>
               <div class="min-w-0">
                 <p class="text-[11px] font-bold truncate">Monitors</p>
                 <p class="text-[9px] text-muted-foreground">{{ monitors.length }}</p>
               </div>
-            </div>
+            </button>
🤖 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 `@web/src/views/App.Overview.vue` around lines 447 - 523, Make every
quick-navigation tile currently implemented as a clickable div keyboard
accessible, including the elements using navigateTo for monitors, ssl-monitors,
status-pages, incidents, maintenances, settings/notifications, integrations,
tags, api-tokens, users, and teams. Replace each with a semantic button or
router link, preserving styling and conditional isAdmin rendering, and ensure
activation invokes the existing navigateTo destination for both keyboard and
pointer users.

@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 2 file(s) based on 2 unresolved review comments.

A stacked PR containing fixes has been created.

  • Stacked PR: #52
  • Files modified:
  • modules/backup/domain/service/backup_service.go
  • web/src/views/App.Overview.vue

Time taken: 5m 11s

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant