mirror of
https://github.com/supabase/supabase.git
synced 2026-10-12 21:05:06 +03:00
Merge remote-tracking branch 'origin/master' into prototype/nav-concept-2
This commit is contained in:
commit
2ab1e8c05f
18 files changed
+204
-91
No files matched your search
@@ -31,7 +31,7 @@ hideToc: true
|
||||
<StepHikeCompact.Details title="Create a Next.js app">
|
||||
|
||||
Use the `create-next-app` command and the `with-supabase` template, to create a Next.js app pre-configured with:
|
||||
- [Cookie-based Auth](docs/guides/auth/server-side/creating-a-client?queryGroups=package-manager&package-manager=npm&queryGroups=framework&framework=nextjs&queryGroups=environment&environment=server)
|
||||
- [Cookie-based Auth](/docs/guides/auth/server-side/creating-a-client?queryGroups=package-manager&package-manager=npm&queryGroups=framework&framework=nextjs&queryGroups=environment&environment=server)
|
||||
- [TypeScript](https://www.typescriptlang.org/)
|
||||
- [Tailwind CSS](https://tailwindcss.com/)
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ hideToc: true
|
||||
<StepHikeCompact.Details title="Create a Next.js app">
|
||||
|
||||
Use the `create-next-app` command and the `with-supabase` template, to create a Next.js app pre-configured with:
|
||||
- [Cookie-based Auth](docs/guides/auth/server-side/creating-a-client?queryGroups=package-manager&package-manager=npm&queryGroups=framework&framework=nextjs&queryGroups=environment&environment=server)
|
||||
- [Cookie-based Auth](/docs/guides/auth/server-side/creating-a-client?queryGroups=package-manager&package-manager=npm&queryGroups=framework&framework=nextjs&queryGroups=environment&environment=server)
|
||||
- [TypeScript](https://www.typescriptlang.org/)
|
||||
- [Tailwind CSS](https://tailwindcss.com/)
|
||||
|
||||
|
||||
@@ -227,9 +227,9 @@ Now, create the associated `src/routes/account/+page.server.ts` file that handle
|
||||
and handle all form actions through the `actions` object.
|
||||
|
||||
<$CodeSample
|
||||
path="/user-management/sveltekit-user-management/src/routes/+page.server.ts"
|
||||
path="/user-management/sveltekit-user-management/src/routes/account/+page.server.ts"
|
||||
lines={[[1, -1]]}
|
||||
meta="name=src/routes/+page.server.ts"
|
||||
meta="name=src/routes/account/+page.server.ts"
|
||||
/>
|
||||
|
||||
### Launch!
|
||||
|
||||
@@ -2,8 +2,7 @@ import { cache } from 'react'
|
||||
import { z } from 'zod'
|
||||
|
||||
import { cache_fullProcess_withDevCacheBust } from '~/features/helpers.fs'
|
||||
import { IS_PLATFORM } from '~/lib/constants'
|
||||
import { supabaseAdmin } from '~/lib/supabaseAdmin'
|
||||
import { supabase } from '~/lib/supabase'
|
||||
import {
|
||||
getAllTroubleshootingEntriesInternal,
|
||||
getArticleSlug as getArticleSlugInternal,
|
||||
@@ -27,10 +26,9 @@ export interface ITroubleshootingEntry {
|
||||
export const getArticleSlug = getArticleSlugInternal
|
||||
|
||||
async function getAllTroubleshootingEntriesTyped() {
|
||||
const result: ITroubleshootingEntry[] = (
|
||||
IS_PLATFORM ? await getAllTroubleshootingEntriesInternal() : []
|
||||
) as ITroubleshootingEntry[]
|
||||
return result
|
||||
const result: ITroubleshootingEntry[] =
|
||||
(await getAllTroubleshootingEntriesInternal()) as ITroubleshootingEntry[]
|
||||
return result ?? []
|
||||
}
|
||||
export const getAllTroubleshootingEntries = cache_fullProcess_withDevCacheBust(
|
||||
getAllTroubleshootingEntriesTyped,
|
||||
@@ -91,15 +89,11 @@ export async function getAllTroubleshootingErrors() {
|
||||
}
|
||||
|
||||
async function getTroubleshootingUpdatedDatesInternal() {
|
||||
if (!IS_PLATFORM) {
|
||||
return new Map<string, Date>()
|
||||
}
|
||||
|
||||
const databaseIds = (await getAllTroubleshootingEntries())
|
||||
.map((entry) => entry.data.database_id)
|
||||
.filter((id) => !id.startsWith('pseudo-'))
|
||||
|
||||
const { data, error } = await supabaseAdmin()
|
||||
const { data, error } = await supabase()
|
||||
.from('troubleshooting_entries')
|
||||
.select('id, date_updated')
|
||||
.in('id', databaseIds)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createClient, type SupabaseClient } from '@supabase/supabase-js'
|
||||
|
||||
import { type Database as DatabaseGenerated } from 'common'
|
||||
|
||||
export type Database = {
|
||||
|
||||
@@ -3,10 +3,20 @@ import {
|
||||
ScaffoldSectionTitle,
|
||||
ScaffoldSectionContent,
|
||||
} from 'components/layouts/Scaffold'
|
||||
import { Card, CardContent, CardHeader, CardTitle, cn, Skeleton } from 'ui'
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
cn,
|
||||
Skeleton,
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from 'ui'
|
||||
import Link from 'next/link'
|
||||
import { useParams } from 'common'
|
||||
import { ChevronRight, ExternalLink } from 'lucide-react'
|
||||
import { ChevronRight, ExternalLink, HelpCircle } from 'lucide-react'
|
||||
import { Reports } from 'icons'
|
||||
import {
|
||||
getChangeColor,
|
||||
@@ -28,6 +38,7 @@ export const StatCard = ({
|
||||
suffix = '',
|
||||
invert = false,
|
||||
href,
|
||||
tooltip,
|
||||
}: {
|
||||
title: string
|
||||
current: number
|
||||
@@ -36,6 +47,7 @@ export const StatCard = ({
|
||||
suffix?: string
|
||||
invert?: boolean
|
||||
href?: string
|
||||
tooltip?: string
|
||||
}) => {
|
||||
const router = useRouter()
|
||||
const isZeroChange = previous === 0
|
||||
@@ -53,7 +65,19 @@ export const StatCard = ({
|
||||
return (
|
||||
<Card className={cn(href, 'mb-0 flex flex-col')}>
|
||||
<CardHeader className="flex flex-row items-center justify-between gap-2 space-y-0 pb-0 border-b-0 relative">
|
||||
<CardTitle className="text-foreground-light">{title}</CardTitle>
|
||||
<CardTitle className="text-foreground-light flex items-center gap-2">
|
||||
{title}
|
||||
{tooltip && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<HelpCircle className="text-foreground-light" size={14} strokeWidth={1.5} />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent className="w-[300px]">
|
||||
<p>{tooltip}</p>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</CardTitle>
|
||||
<ButtonTooltip
|
||||
type="text"
|
||||
size="tiny"
|
||||
@@ -160,11 +184,12 @@ export const OverviewUsage = () => {
|
||||
<ScaffoldSectionContent className="gap-4">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
<StatCard
|
||||
title="Active users"
|
||||
title="Auth Activity" // https://supabase.slack.com/archives/C08N7894QTG/p1761210058358439?thread_ts=1761147906.491599&cid=C08N7894QTG
|
||||
current={metrics.current.activeUsers}
|
||||
previous={activeUsersChange}
|
||||
loading={isLoading}
|
||||
href={`/project/${ref}/reports/auth?its=${startDate}&ite=${endDate}#usage`}
|
||||
tooltip="Users who generated any Auth event in this period. This metric tracks authentication activity, not total product usage. Some active users won't appear here if their session stayed valid."
|
||||
/>
|
||||
<StatCard
|
||||
title="Sign ups"
|
||||
|
||||
@@ -30,9 +30,16 @@ import {
|
||||
import { Row } from 'ui-patterns'
|
||||
import ShimmeringLoader from 'ui-patterns/ShimmeringLoader'
|
||||
|
||||
export const AdvisorSection = () => {
|
||||
export const AdvisorSection = ({ showEmptyState = false }: { showEmptyState?: boolean }) => {
|
||||
const { ref: projectRef } = useParams()
|
||||
const { data: lints, isLoading: isLoadingLints } = useProjectLintsQuery({ projectRef })
|
||||
const { data: lints, isLoading: isLoadingLints } = useProjectLintsQuery(
|
||||
{
|
||||
projectRef,
|
||||
},
|
||||
{
|
||||
enabled: !showEmptyState,
|
||||
}
|
||||
)
|
||||
const snap = useAiAssistantStateSnapshot()
|
||||
const { mutate: sendEvent } = useSendEventMutation()
|
||||
const { data: organization } = useSelectedOrganizationQuery()
|
||||
@@ -93,6 +100,10 @@ export const AdvisorSection = () => {
|
||||
[sendEvent, projectRef, organization]
|
||||
)
|
||||
|
||||
if (showEmptyState) {
|
||||
return <EmptyState />
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoadingLints ? (
|
||||
@@ -199,15 +210,21 @@ export const AdvisorSection = () => {
|
||||
</Sheet>
|
||||
</>
|
||||
) : (
|
||||
<Card className="bg-transparent">
|
||||
<CardContent className="flex flex-col items-center justify-center gap-2 p-16">
|
||||
<Shield size={20} strokeWidth={1.5} className="text-foreground-muted" />
|
||||
<p className="text-sm text-foreground-light text-center">
|
||||
No security or performance errors found
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
<EmptyState />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function EmptyState() {
|
||||
return (
|
||||
<Card className="bg-transparent">
|
||||
<CardContent className="flex flex-col items-center justify-center gap-2 p-16">
|
||||
<Shield size={20} strokeWidth={1.5} className="text-foreground-muted" />
|
||||
<p className="text-sm text-foreground-light text-center">
|
||||
No security or performance errors found
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
}
|
||||
@@ -31,6 +31,7 @@ export const HomeV2 = () => {
|
||||
|
||||
const hasShownEnableBranchingModalRef = useRef(false)
|
||||
const isPaused = project?.status === PROJECT_STATUS.INACTIVE
|
||||
const isComingUp = project?.status === PROJECT_STATUS.COMING_UP
|
||||
|
||||
const [sectionOrder, setSectionOrder] = useLocalStorage<string[]>(
|
||||
`home-section-order-${project?.ref || 'default'}`,
|
||||
@@ -101,9 +102,11 @@ export const HomeV2 = () => {
|
||||
{sectionOrder.map((id) => {
|
||||
if (IS_PLATFORM && id === 'usage') {
|
||||
return (
|
||||
<SortableSection key={id} id={id}>
|
||||
<ProjectUsageSection />
|
||||
</SortableSection>
|
||||
<div key={id} className={cn(isComingUp && 'opacity-60 pointer-events-none')}>
|
||||
<SortableSection id={id}>
|
||||
<ProjectUsageSection />
|
||||
</SortableSection>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if (
|
||||
@@ -123,16 +126,20 @@ export const HomeV2 = () => {
|
||||
}
|
||||
if (id === 'advisor') {
|
||||
return (
|
||||
<SortableSection key={id} id={id}>
|
||||
<AdvisorSection />
|
||||
</SortableSection>
|
||||
<div key={id} className={cn(isComingUp && 'opacity-60 pointer-events-none')}>
|
||||
<SortableSection id={id}>
|
||||
<AdvisorSection showEmptyState={isComingUp} />
|
||||
</SortableSection>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if (id === 'custom-report') {
|
||||
return (
|
||||
<SortableSection key={id} id={id}>
|
||||
<CustomReportSection />
|
||||
</SortableSection>
|
||||
<div key={id} className={cn(isComingUp && 'opacity-60 pointer-events-none')}>
|
||||
<SortableSection id={id}>
|
||||
<CustomReportSection />
|
||||
</SortableSection>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})}
|
||||
|
||||
@@ -254,36 +254,44 @@ export const ServiceStatus = () => {
|
||||
(service) => !service.isHealthy && service.status !== 'COMING_UP'
|
||||
)
|
||||
const anyComingUp = services.some((service) => service.status === 'COMING_UP')
|
||||
const overallStatusLabel = isLoadingChecks
|
||||
? 'Checking...'
|
||||
: anyUnhealthy && !isProjectNew
|
||||
? 'Unhealthy'
|
||||
: anyComingUp || isMigrationLoading || (isProjectNew && !allServicesOperational)
|
||||
? 'Coming up...'
|
||||
: 'Healthy'
|
||||
// Spinner only while the overall project is in COMING_UP; otherwise show 6-dot grid
|
||||
const showSpinnerIcon = project?.status === 'COMING_UP'
|
||||
|
||||
const getOverallStatusLabel = (): string => {
|
||||
if (isLoadingChecks) return 'Checking...'
|
||||
if (anyComingUp) return 'Coming up...'
|
||||
if (anyUnhealthy) return 'Unhealthy'
|
||||
return 'Healthy'
|
||||
}
|
||||
|
||||
const overallStatusLabel = getOverallStatusLabel()
|
||||
|
||||
return (
|
||||
<Popover_Shadcn_>
|
||||
<PopoverTrigger_Shadcn_>
|
||||
<SingleStat
|
||||
icon={
|
||||
<div className="grid grid-cols-3 gap-1">
|
||||
{services.map((service, index) => (
|
||||
<div
|
||||
key={`${service.name}-${index}`}
|
||||
className={cn(
|
||||
'w-1.5 h-1.5 rounded-full',
|
||||
service.isLoading ||
|
||||
service.status === 'COMING_UP' ||
|
||||
(isProjectNew && !service.isHealthy)
|
||||
? 'bg-foreground-lighter animate-pulse'
|
||||
: service.isHealthy
|
||||
? 'bg-brand'
|
||||
: 'bg-selection'
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
showSpinnerIcon ? (
|
||||
<Loader2 className="animate-spin" size={18} />
|
||||
) : (
|
||||
<div className="grid grid-cols-3 gap-1">
|
||||
{services.map((service, index) => (
|
||||
<div
|
||||
key={`${service.name}-${index}`}
|
||||
className={cn(
|
||||
'w-1.5 h-1.5 rounded-full',
|
||||
service.isLoading ||
|
||||
service.status === 'COMING_UP' ||
|
||||
(isProjectNew && !service.isHealthy)
|
||||
? 'bg-foreground-lighter animate-pulse'
|
||||
: service.isHealthy
|
||||
? 'bg-brand'
|
||||
: 'bg-selection'
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
label={<span>Status</span>}
|
||||
value={<span>{overallStatusLabel}</span>}
|
||||
|
||||
+13
-8
@@ -47,12 +47,14 @@ const AwsMarketplaceCreateNewOrg = ({ onboardingInfo }: Props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{onboardingInfo && !onboardingInfo.aws_contract_auto_renewal && (
|
||||
<AwsMarketplaceAutoRenewalWarning
|
||||
awsContractEndDate={onboardingInfo.aws_contract_end_date}
|
||||
awsContractSettingsUrl={onboardingInfo.aws_contract_settings_url}
|
||||
/>
|
||||
)}
|
||||
{onboardingInfo &&
|
||||
!onboardingInfo.aws_contract_auto_renewal &&
|
||||
!onboardingInfo.aws_contract_is_private_offer && (
|
||||
<AwsMarketplaceAutoRenewalWarning
|
||||
awsContractEndDate={onboardingInfo.aws_contract_end_date}
|
||||
awsContractSettingsUrl={onboardingInfo.aws_contract_settings_url}
|
||||
/>
|
||||
)}
|
||||
<ScaffoldSection>
|
||||
<ScaffoldSectionDetail className="text-base">
|
||||
<p>
|
||||
@@ -62,8 +64,11 @@ const AwsMarketplaceCreateNewOrg = ({ onboardingInfo }: Props) => {
|
||||
</p>
|
||||
<p>
|
||||
You can read more on billing through AWS in our {''}
|
||||
{/*TODO(thomas): Update docs link once the new docs exist*/}
|
||||
<Link href={`${DOCS_URL}/guides/platform`} target="_blank" className="underline">
|
||||
<Link
|
||||
href={`${DOCS_URL}/guides/platform/aws-marketplace`}
|
||||
target="_blank"
|
||||
className="underline"
|
||||
>
|
||||
Billing Docs.
|
||||
</Link>
|
||||
</p>
|
||||
|
||||
+13
-8
@@ -118,12 +118,14 @@ export const AwsMarketplaceLinkExistingOrg = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{onboardingInfo && !onboardingInfo.aws_contract_auto_renewal && (
|
||||
<AwsMarketplaceAutoRenewalWarning
|
||||
awsContractEndDate={onboardingInfo.aws_contract_end_date}
|
||||
awsContractSettingsUrl={onboardingInfo.aws_contract_settings_url}
|
||||
/>
|
||||
)}
|
||||
{onboardingInfo &&
|
||||
!onboardingInfo.aws_contract_auto_renewal &&
|
||||
!onboardingInfo.aws_contract_is_private_offer && (
|
||||
<AwsMarketplaceAutoRenewalWarning
|
||||
awsContractEndDate={onboardingInfo.aws_contract_end_date}
|
||||
awsContractSettingsUrl={onboardingInfo.aws_contract_settings_url}
|
||||
/>
|
||||
)}
|
||||
<ScaffoldSection>
|
||||
<ScaffoldSectionDetail className="text-base">
|
||||
<>
|
||||
@@ -136,8 +138,11 @@ export const AwsMarketplaceLinkExistingOrg = ({
|
||||
|
||||
<p>
|
||||
You can read more on billing through AWS in our {''}
|
||||
{/*TODO(thomas): Update docs link once the new docs exist*/}
|
||||
<Link href={`${DOCS_URL}/guides/platform`} target="_blank" className="underline">
|
||||
<Link
|
||||
href={`${DOCS_URL}/guides/platform/aws-marketplace`}
|
||||
target="_blank"
|
||||
className="underline"
|
||||
>
|
||||
Billing Docs.
|
||||
</Link>
|
||||
</p>
|
||||
|
||||
@@ -280,11 +280,14 @@ export const QueryPerformanceGrid = ({
|
||||
}
|
||||
|
||||
if (col.id === 'cache_hit_rate') {
|
||||
const numericValue = typeof value === 'number' ? value : parseFloat(value)
|
||||
return (
|
||||
<div className="w-full flex flex-col justify-center text-xs text-right tabular-nums font-mono">
|
||||
{typeof value === 'number' && !isNaN(value) && isFinite(value) ? (
|
||||
<p className={cn(value.toFixed(2) === '0.00' && 'text-foreground-lighter')}>
|
||||
{value.toLocaleString(undefined, {
|
||||
{typeof numericValue === 'number' &&
|
||||
!isNaN(numericValue) &&
|
||||
isFinite(numericValue) ? (
|
||||
<p className={cn(numericValue.toFixed(2) === '0.00' && 'text-foreground-lighter')}>
|
||||
{numericValue.toLocaleString(undefined, {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
})}
|
||||
|
||||
@@ -3,7 +3,7 @@ import Head from 'next/head'
|
||||
import { useRouter } from 'next/router'
|
||||
import { forwardRef, Fragment, PropsWithChildren, ReactNode, useEffect, useState } from 'react'
|
||||
|
||||
import { LOCAL_STORAGE_KEYS, useParams } from 'common'
|
||||
import { LOCAL_STORAGE_KEYS, useParams, useFlag } from 'common'
|
||||
import { CreateBranchModal } from 'components/interfaces/BranchManagement/CreateBranchModal'
|
||||
import ProjectAPIDocs from 'components/interfaces/ProjectAPIDocs/ProjectAPIDocs'
|
||||
import { AIAssistant } from 'components/ui/AIAssistantPanel/AIAssistant'
|
||||
@@ -318,11 +318,13 @@ const ContentWrapper = ({ isLoading, isBlocking = true, children }: ContentWrapp
|
||||
const { ref } = useParams()
|
||||
const state = useDatabaseSelectorStateSnapshot()
|
||||
const { data: selectedProject } = useSelectedProjectQuery()
|
||||
const isHomeNewFlag = useFlag('homeNew')
|
||||
|
||||
const isBranchesPage = router.pathname.includes('/project/[ref]/branches')
|
||||
const isSettingsPages = router.pathname.includes('/project/[ref]/settings')
|
||||
const isVaultPage = router.pathname === '/project/[ref]/settings/vault'
|
||||
const isBackupsPage = router.pathname.includes('/project/[ref]/database/backups')
|
||||
const isHomePage = router.pathname === '/project/[ref]'
|
||||
|
||||
const requiresDbConnection: boolean =
|
||||
(!isSettingsPages && !routesToIgnoreDBConnection.includes(router.pathname)) || isVaultPage
|
||||
@@ -343,6 +345,20 @@ const ContentWrapper = ({ isLoading, isBlocking = true, children }: ContentWrapp
|
||||
const isProjectPauseFailed = selectedProject?.status === PROJECT_STATUS.PAUSE_FAILED
|
||||
const isProjectOffline = selectedProject?.postgrestStatus === 'OFFLINE'
|
||||
|
||||
// handle redirect to home for building state
|
||||
const shouldRedirectToHomeForBuilding =
|
||||
isHomeNewFlag && requiresDbConnection && isProjectBuilding && !isBranchesPage && !isHomePage
|
||||
|
||||
// We won't be showing the building state with the new home page
|
||||
const shouldShowBuildingState =
|
||||
requiresDbConnection && isProjectBuilding && !isBranchesPage && !(isHomeNewFlag && isHomePage)
|
||||
|
||||
useEffect(() => {
|
||||
if (shouldRedirectToHomeForBuilding && ref) {
|
||||
router.replace(`/project/${ref}`)
|
||||
}
|
||||
}, [shouldRedirectToHomeForBuilding, ref, router])
|
||||
|
||||
useEffect(() => {
|
||||
if (ref) state.setSelectedDatabaseId(ref)
|
||||
}, [ref])
|
||||
@@ -383,7 +399,11 @@ const ContentWrapper = ({ isLoading, isBlocking = true, children }: ContentWrapp
|
||||
return <RestoreFailedState />
|
||||
}
|
||||
|
||||
if (requiresDbConnection && isProjectBuilding && !isBranchesPage) {
|
||||
if (shouldRedirectToHomeForBuilding) {
|
||||
return <Loading />
|
||||
}
|
||||
|
||||
if (shouldShowBuildingState) {
|
||||
return <BuildingState />
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ describe('defaultAuthReportFormatter', () => {
|
||||
const data = { result: [{ timestamp: String(timestamp), count: 1 }] }
|
||||
|
||||
const attributes = [
|
||||
{ attribute: 'ActiveUsers', provider: 'logs', label: 'Active Users', enabled: true },
|
||||
{ attribute: 'ActiveUsers', provider: 'logs', label: 'Auth Activity', enabled: true },
|
||||
]
|
||||
|
||||
const result = defaultAuthReportFormatter(data, attributes)
|
||||
@@ -28,7 +28,7 @@ describe('defaultAuthReportFormatter', () => {
|
||||
}
|
||||
|
||||
const attributes = [
|
||||
{ attribute: 'active_users', label: 'Active Users' },
|
||||
{ attribute: 'active_users', label: 'Auth Activity' },
|
||||
{ attribute: 'sign_in_attempts', label: 'Sign In Attempts' },
|
||||
]
|
||||
|
||||
@@ -47,7 +47,7 @@ describe('defaultAuthReportFormatter', () => {
|
||||
const data = { result: [] }
|
||||
|
||||
const attributes = [
|
||||
{ attribute: 'ActiveUsers', provider: 'logs', label: 'Active Users', enabled: true },
|
||||
{ attribute: 'ActiveUsers', provider: 'logs', label: 'Auth Activity', enabled: true },
|
||||
]
|
||||
|
||||
const result = defaultAuthReportFormatter(data, attributes)
|
||||
|
||||
@@ -513,7 +513,7 @@ export const createUsageReportConfig = ({
|
||||
return [
|
||||
{
|
||||
id: 'active-user',
|
||||
label: 'Active Users',
|
||||
label: 'Auth Activity', // https://supabase.slack.com/archives/C08N7894QTG/p1761210058358439?thread_ts=1761147906.491599&cid=C08N7894QTG
|
||||
valuePrecision: 0,
|
||||
hide: false,
|
||||
showTooltip: true,
|
||||
@@ -521,11 +521,12 @@ export const createUsageReportConfig = ({
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'line',
|
||||
titleTooltip: 'The total number of active users over time.',
|
||||
titleTooltip:
|
||||
"Users who generated any Auth event in this period. This metric tracks authentication activity, not total product usage. Some active users won't appear here if their session stayed valid.",
|
||||
availableIn: ['free', 'pro', 'team', 'enterprise'],
|
||||
dataProvider: async () => {
|
||||
const attributes = [
|
||||
{ attribute: 'ActiveUsers', provider: 'logs', label: 'Active Users', enabled: true },
|
||||
{ attribute: 'ActiveUsers', provider: 'logs', label: 'Auth Activity', enabled: true },
|
||||
]
|
||||
|
||||
const sql = AUTH_REPORT_SQL.ActiveUsers(interval, filters)
|
||||
|
||||
@@ -91,6 +91,8 @@ import ConfirmationModal from 'ui-patterns/Dialogs/ConfirmationModal'
|
||||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||||
import { InfoTooltip } from 'ui-patterns/info-tooltip'
|
||||
|
||||
// [Joshen] This page is getting rather big and complex, let's aim to break this down into smaller components
|
||||
|
||||
const sizes: DesiredInstanceSize[] = ['micro', 'small', 'medium']
|
||||
|
||||
const sizesWithNoCostConfirmationRequired: DesiredInstanceSize[] = ['micro', 'small']
|
||||
@@ -146,6 +148,7 @@ const Wizard: NextPageWithLayout = () => {
|
||||
const projectCreationDisabled = useFlag('disableProjectCreationAndUpdate')
|
||||
const showPostgresVersionSelector = useFlag('showPostgresVersionSelector')
|
||||
const cloudProviderEnabled = useFlag('enableFlyCloudProvider')
|
||||
const isHomeNew = useFlag('homeNew')
|
||||
|
||||
const showAdvancedConfig = useIsFeatureEnabled('project_creation:show_advanced_config')
|
||||
const { infraCloudProviders: validCloudProviders } = useCustomContent(['infra:cloud_providers'])
|
||||
@@ -254,7 +257,7 @@ const Wizard: NextPageWithLayout = () => {
|
||||
organization: res.organization_slug,
|
||||
},
|
||||
})
|
||||
router.push(`/project/${res.ref}/building`)
|
||||
router.push(isHomeNew ? `/project/${res.ref}` : `/project/${res.ref}/building`)
|
||||
},
|
||||
})
|
||||
|
||||
@@ -284,7 +287,7 @@ const Wizard: NextPageWithLayout = () => {
|
||||
useOrganizationAvailableRegionsQuery(
|
||||
{
|
||||
slug: slug,
|
||||
cloudProvider: PROVIDERS[defaultProvider].id,
|
||||
cloudProvider: PROVIDERS[cloudProvider as CloudProvider].id,
|
||||
desiredInstanceSize: instanceSize as DesiredInstanceSize,
|
||||
},
|
||||
{
|
||||
@@ -295,6 +298,9 @@ const Wizard: NextPageWithLayout = () => {
|
||||
refetchOnReconnect: false,
|
||||
}
|
||||
)
|
||||
const recommendedSmartRegion = smartRegionEnabled
|
||||
? availableRegionsData?.recommendations.smartGroup.name
|
||||
: undefined
|
||||
const regionError =
|
||||
smartRegionEnabled && defaultProvider !== 'AWS_NIMBUS'
|
||||
? availableRegionsError
|
||||
@@ -473,6 +479,12 @@ const Wizard: NextPageWithLayout = () => {
|
||||
}
|
||||
}, [regionError])
|
||||
|
||||
useEffect(() => {
|
||||
if (recommendedSmartRegion) {
|
||||
form.setValue('dbRegion', recommendedSmartRegion)
|
||||
}
|
||||
}, [recommendedSmartRegion])
|
||||
|
||||
useEffect(() => {
|
||||
if (watchedInstanceSize !== instanceSize) {
|
||||
form.setValue('instanceSize', instanceSize, {
|
||||
|
||||
+1
@@ -4679,6 +4679,7 @@ export interface components {
|
||||
CloudMarketplaceOnboardingInfoResponse: {
|
||||
aws_contract_auto_renewal: boolean
|
||||
aws_contract_end_date: string
|
||||
aws_contract_is_private_offer: boolean
|
||||
aws_contract_settings_url: string
|
||||
aws_contract_start_date: string
|
||||
organization_linking_eligibility: {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
-- Give anon and authenticated read access to the troubleshooting entries table
|
||||
-- Allows troubleshooting entries to be generated in local dev
|
||||
|
||||
create policy anon_read_troubleshooting_entries
|
||||
on public.troubleshooting_entries
|
||||
for select
|
||||
to anon
|
||||
using (true);
|
||||
|
||||
create policy authenticated_read_troubleshooting_entries
|
||||
on public.troubleshooting_entries
|
||||
for select
|
||||
to authenticated
|
||||
using (true);
|
||||
Reference in new issue
Block a user