mirror of
https://github.com/supabase/supabase.git
synced 2026-06-12 17:27:58 +08:00
## What kind of change does this PR introduce? Dashboard cleanup and docs update. ## What is the current behaviour? Project Settings > General still shows a legacy "Project usage" section explaining that usage statistics moved to organisation settings. One troubleshooting page also links to the old project billing usage page. ## What is the new behaviour? The legacy Project Settings usage callout is removed, while the existing old usage route redirect remains in place for stale links. The MAU troubleshooting page now points users to the organisation usage page and tells them to select a specific project from the dropdown. | Before | After | | --- | --- | | <img width="1450" height="1314" alt="CleanShot 2026-04-30 at 16 11 16@2x" src="https://github.com/user-attachments/assets/3ad8c41f-2eab-406c-bfd8-f5737ae9a5a3" /> | <img width="1474" height="1004" alt="CleanShot 2026-04-30 at 16 11 04@2x-7CACB175-B6A9-4811-968F-030745F685AE" src="https://github.com/user-attachments/assets/f541ee60-0c24-49e4-9446-3bd58c516797" /> | <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Updated Monthly Active Users (MAU) documentation to reflect accessing usage data from the organization-level page instead of project settings * **Refactor** * Removed project-level usage viewing option from project settings interface <!-- end of auto-generated comment: release notes by coderabbit.ai -->
160 lines
5.1 KiB
TypeScript
160 lines
5.1 KiB
TypeScript
import { render, screen } from '@testing-library/react'
|
|
import type { ReactNode } from 'react'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { Project } from './Project'
|
|
|
|
const { mockUseIsFeatureEnabled, mockUseProjectPauseStatusQuery, mockUseSelectedProjectQuery } =
|
|
vi.hoisted(() => ({
|
|
mockUseIsFeatureEnabled: vi.fn(),
|
|
mockUseProjectPauseStatusQuery: vi.fn(),
|
|
mockUseSelectedProjectQuery: vi.fn(),
|
|
}))
|
|
|
|
vi.mock('next/link', () => ({
|
|
default: ({ href, children }: { href: string; children: ReactNode }) => (
|
|
<a href={href}>{children}</a>
|
|
),
|
|
}))
|
|
|
|
vi.mock('ui', () => ({
|
|
Button: ({
|
|
children,
|
|
asChild,
|
|
type: _type,
|
|
...props
|
|
}: {
|
|
children: ReactNode
|
|
asChild?: boolean
|
|
type?: string
|
|
}) => (asChild ? <>{children}</> : <button {...props}>{children}</button>),
|
|
Card: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
|
CardContent: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
|
}))
|
|
|
|
vi.mock('ui-patterns/PageSection', () => ({
|
|
PageSection: ({ children, id }: { children: ReactNode; id?: string }) => (
|
|
<section id={id}>{children}</section>
|
|
),
|
|
PageSectionContent: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
|
PageSectionDescription: ({ children }: { children: ReactNode }) => <p>{children}</p>,
|
|
PageSectionMeta: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
|
PageSectionSummary: ({ children }: { children: ReactNode }) => <div>{children}</div>,
|
|
PageSectionTitle: ({ children }: { children: ReactNode }) => <h2>{children}</h2>,
|
|
}))
|
|
|
|
vi.mock('@/components/interfaces/Project/ResumeProjectButton', () => ({
|
|
ResumeProjectButton: () => <div>ResumeProjectButton</div>,
|
|
}))
|
|
|
|
vi.mock('./Infrastructure/PauseProjectButton', () => ({
|
|
default: () => <div>PauseProjectButton</div>,
|
|
}))
|
|
|
|
vi.mock('./Infrastructure/RestartServerButton', () => ({
|
|
default: () => <div>RestartServerButton</div>,
|
|
}))
|
|
|
|
vi.mock('@/data/projects/project-pause-status-query', () => ({
|
|
useProjectPauseStatusQuery: mockUseProjectPauseStatusQuery,
|
|
}))
|
|
|
|
vi.mock('@/hooks/misc/useIsFeatureEnabled', () => ({
|
|
useIsFeatureEnabled: mockUseIsFeatureEnabled,
|
|
}))
|
|
|
|
vi.mock('@/hooks/misc/useSelectedProject', () => ({
|
|
useSelectedProjectQuery: mockUseSelectedProjectQuery,
|
|
}))
|
|
|
|
describe('Project settings availability', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
|
|
mockUseIsFeatureEnabled.mockReturnValue({
|
|
projectSettingsRestartProject: true,
|
|
})
|
|
|
|
mockUseProjectPauseStatusQuery.mockReturnValue({
|
|
data: undefined,
|
|
isError: false,
|
|
isSuccess: false,
|
|
})
|
|
})
|
|
|
|
it('shows the restart action for active projects', () => {
|
|
mockUseSelectedProjectQuery.mockReturnValue({
|
|
data: {
|
|
parent_project_ref: null,
|
|
ref: 'active-project',
|
|
status: 'ACTIVE_HEALTHY',
|
|
},
|
|
})
|
|
|
|
render(<Project />)
|
|
|
|
expect(screen.getByText('Restart project')).toBeInTheDocument()
|
|
expect(screen.getByText('RestartServerButton')).toBeInTheDocument()
|
|
expect(screen.getByText('Pause project')).toBeInTheDocument()
|
|
expect(screen.getByText('PauseProjectButton')).toBeInTheDocument()
|
|
expect(screen.queryByText('ResumeProjectButton')).not.toBeInTheDocument()
|
|
})
|
|
|
|
it('shows the shared resume action for paused projects that can still be restored', () => {
|
|
mockUseSelectedProjectQuery.mockReturnValue({
|
|
data: {
|
|
parent_project_ref: null,
|
|
ref: 'paused-project',
|
|
status: 'INACTIVE',
|
|
},
|
|
})
|
|
|
|
mockUseProjectPauseStatusQuery.mockReturnValue({
|
|
data: { can_restore: true },
|
|
isError: false,
|
|
isSuccess: true,
|
|
})
|
|
|
|
render(<Project />)
|
|
|
|
expect(screen.getByText('Resume project')).toBeInTheDocument()
|
|
expect(screen.getByText('Bring your paused project back online.')).toBeInTheDocument()
|
|
expect(screen.getByText('ResumeProjectButton')).toBeInTheDocument()
|
|
expect(screen.queryByText('Pause project')).not.toBeInTheDocument()
|
|
expect(screen.queryByText('PauseProjectButton')).not.toBeInTheDocument()
|
|
expect(screen.queryByText('RestartServerButton')).not.toBeInTheDocument()
|
|
})
|
|
|
|
it('links back to the dashboard when the paused project can no longer be restored', () => {
|
|
mockUseSelectedProjectQuery.mockReturnValue({
|
|
data: {
|
|
parent_project_ref: null,
|
|
ref: 'paused-project',
|
|
status: 'INACTIVE',
|
|
},
|
|
})
|
|
|
|
mockUseProjectPauseStatusQuery.mockReturnValue({
|
|
data: { can_restore: false },
|
|
isError: false,
|
|
isSuccess: true,
|
|
})
|
|
|
|
render(<Project />)
|
|
|
|
expect(screen.getAllByText('View project dashboard')).toHaveLength(2)
|
|
expect(
|
|
screen.getByText(
|
|
'This project can no longer be resumed here. Open the dashboard to download backups and view recovery options.'
|
|
)
|
|
).toBeInTheDocument()
|
|
expect(screen.getByRole('link', { name: 'View project dashboard' })).toHaveAttribute(
|
|
'href',
|
|
'/project/paused-project'
|
|
)
|
|
expect(screen.queryByText('Pause project')).not.toBeInTheDocument()
|
|
expect(screen.queryByText('PauseProjectButton')).not.toBeInTheDocument()
|
|
expect(screen.queryByText('ResumeProjectButton')).not.toBeInTheDocument()
|
|
})
|
|
})
|