Skip to content

Move alerts to project settings#507

Merged
Blaumaus merged 5 commits intomainfrom
improvement/alerts-in-settings
Apr 7, 2026
Merged

Move alerts to project settings#507
Blaumaus merged 5 commits intomainfrom
improvement/alerts-in-settings

Conversation

@Blaumaus
Copy link
Copy Markdown
Member

@Blaumaus Blaumaus commented Apr 7, 2026

Changes

#505

Community Edition support

  • Your feature is implemented for the Swetrix Community Edition
  • This PR only updates the Cloud (Enterprise) Edition code (e.g. Paddle webhooks, blog, payouts, etc.)

Database migrations

  • Clickhouse / MySQL migrations added for this PR
  • No table schemas changed in this PR

Documentation

  • You have updated the documentation according to your PR
  • This PR did not change any publicly documented endpoints

Summary by CodeRabbit

  • Documentation

    • Updated guides: Alerts are accessed via Project Settings → Alerts; re-added embed dashboard query-parameter docs.
  • New Features / UI

    • Added an Alerts settings tab inside Project Settings (visible to owners).
  • Bug Fixes / Behavior

    • Alerts removed from the main project tab bar and keyboard shortcuts; alerts list loading and pagination flows simplified.
  • Localization

    • Added i18n entries for Alerts tab and description.

@Blaumaus Blaumaus self-assigned this Apr 7, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 7, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9d8f1e72-ff36-415e-9b46-5d27a8585214

📥 Commits

Reviewing files that changed from the base of the PR and between f7ad064 and 6fddf9d.

📒 Files selected for processing (1)
  • web/app/api/api.server.ts

📝 Walkthrough

Walkthrough

Alerts were removed from the main project tabs and added as a Project Settings → Alerts tab. Documentation and i18n were updated. Alerts UI was refactored from loader/deferred/Suspense to a fetcher-driven, prop-based component; route loader fetching, API exports for alerts, and keyboard shortcut handling for alerts were removed.

Changes

Cohort / File(s) Summary
Documentation
docs/content/docs/analytics-dashboard/alerts.mdx, docs/content/docs/sitesettings/get-traffic-alerts.mdx, docs/content/docs/sitesettings/embed-your-analytics-dashboard-into-your-website.mdx
Redirected user instructions to Project Settings → Alerts; re-added tab/tabs query param descriptions in embed docs.
Settings UI & Alerts Components
web/app/pages/Project/Settings/ProjectSettings.tsx, web/app/pages/Project/Settings/Alerts/ProjectAlertsSettings.tsx, web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx
Added an alerts settings tab and i18n keys; moved header markup in settings UI; refactored alerts view to a prop-driven ProjectAlertsInner using fetcher-based loading (removed loader/Suspense/deferred), changed props to accept projectId and optional projectRole, and adjusted pagination/delete/save flows and loading/empty-state logic.
Main Project View Removal
web/app/pages/Project/View/ViewProject.tsx, web/app/pages/Project/View/ViewProject.helpers.tsx, web/app/pages/Project/View/components/ProjectSidebar.tsx
Removed alerts tab from main project tabs, removed sidebar grouping/color for alerts, and removed keyboard shortcut (shift+a) bindings and related tab entries.
Route, API & Constants
web/app/routes/projects.$id.tsx, web/app/api/api.server.ts, web/app/lib/constants/index.ts
Removed alerts data fetching and deferred alerts field from project route; removed exported Alerts API and AlertsResponse type; removed alerts entry from production project tabs constant (runtime tab set reduced).
Localization
web/public/locales/en.json
Added project.settings.tabs.alerts and project.settings.tabs.alertsDesc i18n entries.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant User as User
  participant SettingsUI as Project Settings UI
  participant AlertsComp as ProjectAlerts Component
  participant API as Server API
  Note over SettingsUI,AlertsComp: Flow: Settings → Alerts tab (prop-driven, fetcher)
  User->>SettingsUI: Click "Settings" → select "Alerts"
  SettingsUI->>AlertsComp: Mount with props (projectId, projectRole)
  AlertsComp->>API: GET /projects/:id/alerts (fetcher)
  API-->>AlertsComp: 200 OK + alerts list
  AlertsComp-->>SettingsUI: Render alerts list, pagination controls
  User->>AlertsComp: Delete or Save alert
  AlertsComp->>API: DELETE/POST /projects/:id/alerts
  API-->>AlertsComp: 200 OK
  AlertsComp->>API: Re-fetch alerts (fetcher) to refresh list
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 I hopped from tabs to settings, light and spry,

Bells now rest where the gear sits by.
Fetcher hums, alerts come into view,
Shortcuts silent, pages tidy and new.
A joyful twitch — settings snug and spry.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Move alerts to project settings' accurately and concisely summarizes the primary change: relocating the alerts feature from the project view to project settings, which is fully reflected in the code changes.
Description check ✅ Passed The description addresses the required template sections with appropriate selections: Community Edition scope, database migrations, and documentation updates are all documented. However, the 'Changes' section only provides a GitHub issue link rather than a meaningful description of what was changed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch improvement/alerts-in-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.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx (1)

289-297: ⚠️ Potential issue | 🟠 Major

Clear stale fetch errors on retry or success.

After setError(fetcherError) runs once, nothing resets it. A later successful reload still leaves error truthy, so the component keeps rendering StatusPage until a full page refresh.

Suggested fix
   const loadAlerts = (take: number, skip: number) => {
     if (fetcher.state !== 'idle') return
+    setError(null)
     setIsSearchMode(true)
 
     fetcher.submit(
       { intent: 'get-project-alerts', take: String(take), skip: String(skip) },
       { method: 'POST', action: `/projects/${id}` },
@@
     const { intent, success, data, error: fetcherError } = fetcher.data
 
     if (success) {
+      setError(null)
       if (intent === 'get-project-alerts' && data) {
         const result = data as { results: Alerts[]; total: number }
         setAlerts(result.results)
         setTotal(result.total)

Also applies to: 300-320

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx` around lines 289
- 297, When retrying or after a successful fetch you must clear the stale fetch
error so the component can leave the StatusPage state; update the fetch flows
(e.g., loadAlerts and the other fetcher handlers around lines 300-320) to call
setError(undefined) before submitting a new request and call setError(undefined)
when fetcher.state becomes 'idle' with a successful result. In practice, clear
the error by invoking setError(undefined) immediately before fetcher.submit(...)
in loadAlerts and in the other submit/reload handlers, and also reset error on
successful response handling so previous fetcherError doesn't persist.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx`:
- Around line 261-268: alerts is initialized to [] which conflates "not loaded
yet" with "loaded empty"; change the state to allow a null value (e.g.,
useState<Alerts[] | null>(null)) or add an explicit loaded flag, update all
setters (setAlerts, setTotal, setError) in the fetcher success/error paths to
set alerts to the fetched array (or [] on success) and to null/appropriate value
on start/error, and change render conditions to treat alerts === null (or loaded
flag false) as the loading state (use isLoading OR alerts === null) and only
show the empty-state hero when alerts !== null && alerts.length === 0; update
any other references to alerts (including spots currently rendering based on
alerts length) to follow the same check.
- Around line 312-315: When handling the 'delete-alert' intent in the
ProjectAlertsView, avoid reloading the same offset when the deleted alert was
the only item on the current page; instead calculate a new page: if page > 1 and
the current page will be empty after deletion (e.g., alertsOnPage === 1 or the
loadAlerts result is empty), decrement page by 1, update the page state, and
call loadAlerts with DEFAULT_ALERTS_TAKE and (newPage - 1) *
DEFAULT_ALERTS_TAKE; update references to page and loadAlerts so the UI shows
the previous page instead of an empty onboarding state.

In `@web/app/pages/Project/Settings/ProjectSettings.tsx`:
- Around line 409-416: The Alerts tab is visible to all cloud project members
but the page (ProjectAlertsView) currently only renders for projectRole ===
'owner', causing non-owners to see a dead upsell; either tighten the tab's
visible prop to only show for owners (update the tab entry with id: 'alerts' to
set visible: projectRole === 'owner') or relax the guard inside
ProjectAlertsView (replace the strict projectRole === 'owner' check with a
capability check or include admins/members) so the tab visibility and page
gating are consistent; locate the tab object with id 'alerts' in
ProjectSettings.tsx and the role check inside ProjectAlertsView.tsx to apply the
chosen fix.

---

Outside diff comments:
In `@web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx`:
- Around line 289-297: When retrying or after a successful fetch you must clear
the stale fetch error so the component can leave the StatusPage state; update
the fetch flows (e.g., loadAlerts and the other fetcher handlers around lines
300-320) to call setError(undefined) before submitting a new request and call
setError(undefined) when fetcher.state becomes 'idle' with a successful result.
In practice, clear the error by invoking setError(undefined) immediately before
fetcher.submit(...) in loadAlerts and in the other submit/reload handlers, and
also reset error on successful response handling so previous fetcherError
doesn't persist.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7e6d1566-2cb2-4607-9f5d-1e6e1d00f04f

📥 Commits

Reviewing files that changed from the base of the PR and between 4315479 and 766fbe1.

📒 Files selected for processing (12)
  • docs/content/docs/analytics-dashboard/alerts.mdx
  • docs/content/docs/sitesettings/embed-your-analytics-dashboard-into-your-website.mdx
  • docs/content/docs/sitesettings/get-traffic-alerts.mdx
  • web/app/lib/constants/index.ts
  • web/app/pages/Project/Settings/Alerts/ProjectAlertsSettings.tsx
  • web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx
  • web/app/pages/Project/Settings/ProjectSettings.tsx
  • web/app/pages/Project/View/ViewProject.helpers.tsx
  • web/app/pages/Project/View/ViewProject.tsx
  • web/app/pages/Project/View/components/ProjectSidebar.tsx
  • web/app/routes/projects.$id.tsx
  • web/public/locales/en.json
💤 Files with no reviewable changes (3)
  • web/app/pages/Project/View/ViewProject.tsx
  • web/app/lib/constants/index.ts
  • web/app/routes/projects.$id.tsx

Comment thread web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx
Comment thread web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx
Comment thread web/app/pages/Project/Settings/ProjectSettings.tsx
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx (2)

469-469: Consider showing a loading indicator when alerts === null.

When alerts haven't loaded yet, the component renders nothing (null). Users have no visual feedback that data is being fetched. A simple loading spinner or skeleton would improve the experience, especially on slower connections.

♻️ Example with loading state
       <div className='mt-4'>
-        {alerts === null ? null : alerts.length === 0 ? (
+        {alerts === null ? (
+          <div className='flex justify-center py-8'>
+            {/* Add your preferred loading component here */}
+            <span className='text-gray-500'>{t('common.loading')}</span>
+          </div>
+        ) : alerts.length === 0 ? (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx` at line 469, The
component currently returns null when alerts === null, leaving no feedback while
data is loading; modify the render logic in ProjectAlertsView (the component
handling the alerts variable) to show a loading indicator (e.g., a
LoadingSpinner, Skeleton, or similar UI component) when alerts === null instead
of null, falling back to the existing empty-state UI when alerts.length === 0
and the normal list when alerts is non-empty; locate the conditional around
alerts (the expression starting with "{alerts === null ? null : alerts.length
=== 0 ? (") and replace the null branch with your chosen loading component so
users see visual feedback during fetches.

314-321: Delete pagination fix is correct, but the explicit loadAlerts call is redundant.

The page decrement logic correctly addresses the past review comment. However, since the useEffect at lines 329-336 already triggers loadAlerts when page changes, the explicit call on line 318 creates a redundant invocation pattern—the guard at line 290 prevents actual double fetches, but the intent would be clearer if you relied solely on the effect.

♻️ Suggested simplification
       } else if (intent === 'delete-alert') {
         toast.success(t('alertsSettings.alertDeleted'))

         if (page > 1 && alerts?.length === 1) {
           const newPage = page - 1
           setPage(newPage)
-          loadAlerts(DEFAULT_ALERTS_TAKE, (newPage - 1) * DEFAULT_ALERTS_TAKE)
         } else {
           loadAlerts(DEFAULT_ALERTS_TAKE, (page - 1) * DEFAULT_ALERTS_TAKE)
         }
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx` around lines 314
- 321, Remove the redundant explicit loadAlerts call inside the branch that
decrements the page: when you call setPage(newPage) let the existing useEffect
that depends on page invoke loadAlerts; so in the if (page > 1 && alerts?.length
=== 1) branch only call setPage(newPage) and omit
loadAlerts(DEFAULT_ALERTS_TAKE, (newPage - 1) * DEFAULT_ALERTS_TAKE), leaving
the else branch’s explicit loadAlerts as-is for the case where page doesn’t
change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx`:
- Line 469: The component currently returns null when alerts === null, leaving
no feedback while data is loading; modify the render logic in ProjectAlertsView
(the component handling the alerts variable) to show a loading indicator (e.g.,
a LoadingSpinner, Skeleton, or similar UI component) when alerts === null
instead of null, falling back to the existing empty-state UI when alerts.length
=== 0 and the normal list when alerts is non-empty; locate the conditional
around alerts (the expression starting with "{alerts === null ? null :
alerts.length === 0 ? (") and replace the null branch with your chosen loading
component so users see visual feedback during fetches.
- Around line 314-321: Remove the redundant explicit loadAlerts call inside the
branch that decrements the page: when you call setPage(newPage) let the existing
useEffect that depends on page invoke loadAlerts; so in the if (page > 1 &&
alerts?.length === 1) branch only call setPage(newPage) and omit
loadAlerts(DEFAULT_ALERTS_TAKE, (newPage - 1) * DEFAULT_ALERTS_TAKE), leaving
the else branch’s explicit loadAlerts as-is for the case where page doesn’t
change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6a8dd518-d693-4d7e-807f-dc6536d53c0b

📥 Commits

Reviewing files that changed from the base of the PR and between 766fbe1 and eb7a1f4.

📒 Files selected for processing (1)
  • web/app/pages/Project/Settings/Alerts/ProjectAlertsView.tsx

@Blaumaus Blaumaus merged commit 64823a6 into main Apr 7, 2026
2 of 3 checks passed
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