diff --git a/apps/studio/components/layouts/AppLayout/StatusPageBanner.tsx b/apps/studio/components/layouts/AppLayout/StatusPageBanner.tsx index b5ffe723f8c..1254546603c 100644 --- a/apps/studio/components/layouts/AppLayout/StatusPageBanner.tsx +++ b/apps/studio/components/layouts/AppLayout/StatusPageBanner.tsx @@ -1,9 +1,7 @@ -import { LOCAL_STORAGE_KEYS, useFlag } from 'common' -import { HeaderBanner } from 'components/interfaces/Organization/HeaderBanner' -import { InlineLink } from 'components/ui/InlineLink' +import { useFlag } from 'common' -import { useIncidentStatusQuery } from '@/data/platform/incident-status-query' -import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' +import { HeaderBanner } from '@/components/interfaces/Organization/HeaderBanner' +import { InlineLink } from '@/components/ui/InlineLink' const BANNER_DESCRIPTION = ( <> @@ -12,54 +10,18 @@ const BANNER_DESCRIPTION = ( ) /** - * Used to display ongoing incidents or maintenances + * Used to display ongoing incidents */ export const StatusPageBanner = () => { - const { data: allStatusPageEvents } = useIncidentStatusQuery() - const { incidents = [], maintenanceEvents = [] } = allStatusPageEvents ?? {} - - // Only show incident banner for incidents with real impact (not "none") - const highImpactIncident = incidents.find((incident) => incident.impact !== 'none') - const incidentEventId = highImpactIncident?.id ?? '' - - const showIncidentBannerOverride = + const showIncidentBanner = useFlag('ongoingIncident') || process.env.NEXT_PUBLIC_ONGOING_INCIDENT === 'true' - const ongoingMaintenance = maintenanceEvents.length > 0 - const maintenanceEventId = maintenanceEvents[0]?.id ?? '' - - const [dismissedIncident, setDismissedIncident] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.INCIDENT_BANNER_DISMISSED(incidentEventId), - false - ) - - const [dismissedMaintenance, setDismissedMaintenance] = useLocalStorageQuery( - LOCAL_STORAGE_KEYS.MAINTENANCE_BANNER_DISMISSED(maintenanceEventId), - false - ) - - if (showIncidentBannerOverride || (highImpactIncident && !dismissedIncident)) { + if (showIncidentBanner) { return ( setDismissedIncident(true) - } - /> - ) - } - - if (ongoingMaintenance && !dismissedMaintenance) { - return ( - setDismissedMaintenance(true)} /> ) } diff --git a/e2e/studio/features/status-page-banner.spec.ts b/e2e/studio/features/status-page-banner.spec.ts index a1c504e1dfd..28a3ac4d548 100644 --- a/e2e/studio/features/status-page-banner.spec.ts +++ b/e2e/studio/features/status-page-banner.spec.ts @@ -3,172 +3,15 @@ import { expect } from '@playwright/test' import { test } from '../utils/test.js' import { toUrl } from '../utils/to-url.js' -// Mock incident data - impact is "major" (not "none" or "maintenance") -const mockIncident = { - id: 'incident-123', - name: 'Test Incident', - status: 'investigating', - impact: 'major', - active_since: new Date().toISOString(), -} - -// Mock incident with "none" impact - should NOT trigger the incident banner -const mockIncidentNoneImpact = { - id: 'incident-none-456', - name: 'No Impact Incident', - status: 'investigating', - impact: 'none', - active_since: new Date().toISOString(), -} - -// Mock maintenance event - impact is "maintenance" -const mockMaintenance = { - id: 'maintenance-789', - name: 'Scheduled Maintenance', - status: 'in_progress', - impact: 'maintenance', - active_since: new Date().toISOString(), -} - test.describe('StatusPageBanner', () => { - test.describe.configure({ mode: 'serial' }) - - test.beforeEach(async ({ page }) => { - // Clear any dismissed banner state from localStorage before each test - await page.addInitScript(() => { - // Clear all incident/maintenance banner dismissals and test overrides - for (const key of Object.keys(localStorage)) { - if ( - key.startsWith('incident-banner-dismissed-') || - key.startsWith('maintenance-banner-dismissed-') - ) { - localStorage.removeItem(key) - } - } - }) - }) - - test('incident banner shows for incidents with impact not equal to "none"', async ({ - page, - ref, - }) => { - // Mock the incident status API to return an incident with major impact - await page.route('**/api/incident-status', async (route) => { - await route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify([mockIncident]), - }) - }) - - await page.goto(toUrl(`/project/${ref}`)) - - // Wait for the incident banner to be visible - const incidentBanner = page.getByText('We are investigating a technical issue') - await expect(incidentBanner).toBeVisible({ timeout: 15000 }) - - // Verify the dismiss button IS present for real incidents - const dismissButton = page.getByRole('button', { name: 'Dismiss banner' }) - await expect(dismissButton).toBeVisible() - }) - - test('incident banner does NOT show for incidents with impact "none"', async ({ page, ref }) => { - // Mock the incident status API to return an incident with "none" impact - await page.route('**/api/incident-status', async (route) => { - await route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify([mockIncidentNoneImpact]), - }) - }) - + test('incident banner does not show when no incident flag is set', async ({ page, ref }) => { await page.goto(toUrl(`/project/${ref}`)) // Wait for page to load await expect(page.getByRole('heading', { level: 1 })).toBeVisible({ timeout: 15000 }) - // Verify the incident banner is NOT visible + // Verify the incident banner is NOT visible (no flag is set) const incidentBanner = page.getByText('We are investigating a technical issue') await expect(incidentBanner).not.toBeVisible() }) - - test('incident banner takes precedence over maintenance banner', async ({ page, ref }) => { - // Mock the incident status API to return both an incident and a maintenance event - await page.route('**/api/incident-status', async (route) => { - await route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify([mockIncident, mockMaintenance]), - }) - }) - - await page.goto(toUrl(`/project/${ref}`)) - - // Wait for the incident banner to be visible - const incidentBanner = page.getByText('We are investigating a technical issue') - await expect(incidentBanner).toBeVisible({ timeout: 15000 }) - - // Verify the maintenance banner is NOT visible (incident takes precedence) - const maintenanceBanner = page.getByText('Scheduled maintenance is in progress') - await expect(maintenanceBanner).not.toBeVisible() - }) - - test('maintenance banner shows after dismissing incident banner when both exist', async ({ - page, - ref, - }) => { - // Mock the incident status API to return both an incident and a maintenance event - await page.route('**/api/incident-status', async (route) => { - await route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify([mockIncident, mockMaintenance]), - }) - }) - - await page.goto(toUrl(`/project/${ref}`)) - - // Wait for the incident banner to be visible - const incidentBanner = page.getByText('We are investigating a technical issue') - await expect(incidentBanner).toBeVisible({ timeout: 15000 }) - - // Click the dismiss button to dismiss the incident banner - const dismissButton = page.getByRole('button', { name: 'Dismiss banner' }) - await expect(dismissButton).toBeVisible() - await dismissButton.click() - - // Wait for the incident banner to disappear - await expect(incidentBanner).not.toBeVisible({ timeout: 5000 }) - - // Verify the maintenance banner is now visible - const maintenanceBanner = page.getByText('Scheduled maintenance is in progress') - await expect(maintenanceBanner).toBeVisible({ timeout: 5000 }) - }) - - test('maintenance banner is dismissible', async ({ page, ref }) => { - // Mock the incident status API to return only a maintenance event - await page.route('**/api/incident-status', async (route) => { - await route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify([mockMaintenance]), - }) - }) - - await page.goto(toUrl(`/project/${ref}`)) - - // Wait for the maintenance banner to be visible - const maintenanceBanner = page.getByText('Scheduled maintenance is in progress') - await expect(maintenanceBanner).toBeVisible({ timeout: 15000 }) - - // Verify the dismiss button is present - const dismissButton = page.getByRole('button', { name: 'Dismiss banner' }) - await expect(dismissButton).toBeVisible() - - // Dismiss the maintenance banner - await dismissButton.click() - - // Verify the maintenance banner is no longer visible - await expect(maintenanceBanner).not.toBeVisible({ timeout: 5000 }) - }) })