chore: better ipv6 migration notices (#20817)

* chore: better ipv6 migration notices

* adds multiple dismisses

* add migration for ipv6_active_status rpc

* fix sql syntax

* use rpc

* Fix NoticeBanner acknowledged logic

* ci: Autofix updates from GitHub workflow

* Remove console log

* Lint

* Fix logic

* Update pgbouncer and vercel notices to be project specific

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: github-tidy-bot <github-tidy-bot@supabase.com>
This commit is contained in:
authored and GitHub committed 2024-01-30 13:54:22 +07:00
1 parent 6a820cb6b2
commit f74294612c
4 files changed
+165 -20

No files matched your search

@@ -3,38 +3,75 @@ import { PropsWithChildren, createContext, useContext, useEffect, useState } fro
import { LOCAL_STORAGE_KEYS } from 'lib/constants'
const NOTICE_BANNER_KEY = LOCAL_STORAGE_KEYS.PGBOUNCER_DEPRECATION_WARNING
const PGBOUNCER_BANNER_KEY = LOCAL_STORAGE_KEYS.PGBOUNCER_IPV6_DEPRECATION_WARNING
const VERCEL_BANNER_KEY = LOCAL_STORAGE_KEYS.VERCEL_IPV6_DEPRECATION_WARNING
const DEFAULT_NOTICE_BANNER_KEY = LOCAL_STORAGE_KEYS.PGBOUNCER_DEPRECATION_WARNING
// [Joshen] Update this as and when we need to use the NoticeBanner
type AppBannerContextType = {
acknowledged: boolean
onUpdateAcknowledged: (value: boolean) => void
ipv6BannerAcknowledged: boolean
pgbouncerBannerAcknowledged: string[]
vercelBannerAcknowledged: string[]
onUpdateAcknowledged: (key: 'ipv6' | 'pgbouncer' | 'vercel', value: boolean | string) => void
}
const AppBannerContext = createContext<AppBannerContextType>({
acknowledged: false,
ipv6BannerAcknowledged: false,
pgbouncerBannerAcknowledged: [],
vercelBannerAcknowledged: [],
onUpdateAcknowledged: noop,
})
export const useAppBannerContext = () => useContext(AppBannerContext)
export const AppBannerContextProvider = ({ children }: PropsWithChildren<{}>) => {
const [acknowledged, setAcknowledged] = useState(false)
const [ipv6BannerAcknowledged, setIpv6BannerAcknowledged] = useState(false)
// [Joshen] These will take a list of refs instead since they are project specific
// Comma separated strings, no spaces
const [pgbouncerBannerAcknowledged, setPgbouncerBannerAcknowledged] = useState<string[]>([])
const [vercelBannerAcknowledged, setVercelBannerAcknowledged] = useState<string[]>([])
useEffect(() => {
if (typeof window !== 'undefined') {
setAcknowledged(localStorage.getItem(NOTICE_BANNER_KEY) === 'true')
setIpv6BannerAcknowledged(localStorage.getItem(DEFAULT_NOTICE_BANNER_KEY) === 'true')
const acknowledgedPbBouncerRefs = localStorage.getItem(PGBOUNCER_BANNER_KEY)?.split(',') ?? []
setPgbouncerBannerAcknowledged(acknowledgedPbBouncerRefs)
const acknowledgedVercelRefs = localStorage.getItem(VERCEL_BANNER_KEY)?.split(',') ?? []
setVercelBannerAcknowledged(acknowledgedVercelRefs)
}
}, [])
const value = {
acknowledged,
onUpdateAcknowledged: (value: boolean) => {
if (typeof window !== 'undefined') {
window.localStorage.setItem(NOTICE_BANNER_KEY, value.toString())
ipv6BannerAcknowledged,
pgbouncerBannerAcknowledged,
vercelBannerAcknowledged,
onUpdateAcknowledged: (key: 'ipv6' | 'pgbouncer' | 'vercel', value: boolean | string) => {
if (key === 'ipv6' && typeof value === 'boolean') {
if (typeof window !== 'undefined') {
window.localStorage.setItem(DEFAULT_NOTICE_BANNER_KEY, value.toString())
}
setIpv6BannerAcknowledged(value)
}
if (key === 'pgbouncer' && typeof value === 'string' && value.length > 0) {
const updatedRefs = pgbouncerBannerAcknowledged.concat([value])
if (typeof window !== 'undefined') {
window.localStorage.setItem(PGBOUNCER_BANNER_KEY, updatedRefs.join(','))
}
setPgbouncerBannerAcknowledged(updatedRefs)
}
if (key === 'vercel' && typeof value === 'string' && value.length > 0) {
const updatedRefs = pgbouncerBannerAcknowledged.concat([value])
if (typeof window !== 'undefined') {
window.localStorage.setItem(VERCEL_BANNER_KEY, updatedRefs.join(','))
}
setVercelBannerAcknowledged(updatedRefs)
}
setAcknowledged(value)
},
}
@@ -42,6 +79,7 @@ export const AppBannerContextProvider = ({ children }: PropsWithChildren<{}>) =>
}
export const useIsNoticeBannerShown = () => {
const { acknowledged } = useAppBannerContext()
return acknowledged
const { ipv6BannerAcknowledged, pgbouncerBannerAcknowledged, vercelBannerAcknowledged } =
useAppBannerContext()
return ipv6BannerAcknowledged && pgbouncerBannerAcknowledged && vercelBannerAcknowledged
}
@@ -1,6 +1,10 @@
import { useSupabaseClient } from '@supabase/auth-helpers-react'
import { useQuery } from '@tanstack/react-query'
import { useRouter } from 'next/router'
import { useParams } from 'common'
import { useAppBannerContext } from 'components/interfaces/App/AppBannerWrapperContext'
import { useProfile } from 'lib/profile'
import { useRouter } from 'next/router'
import { Button, IconExternalLink } from 'ui'
// [Joshen] For this notice specifically, just FYI
@@ -9,12 +13,74 @@ import { Button, IconExternalLink } from 'ui'
export const NoticeBanner = () => {
const router = useRouter()
const { isLoading } = useProfile()
const { isLoading: isLoadingProfile } = useProfile()
const appBannerContext = useAppBannerContext()
const { acknowledged, onUpdateAcknowledged } = appBannerContext
const {
ipv6BannerAcknowledged,
pgbouncerBannerAcknowledged,
vercelBannerAcknowledged,
onUpdateAcknowledged,
} = appBannerContext
if (isLoading || router.pathname.includes('sign-in') || acknowledged) return null
const supabase = useSupabaseClient()
const { ref: projectRef } = useParams()
// [Alaister]: using inline queries here since this is temporary
const { data, isLoading: isLoadingIpv6Enabled } = useQuery(
['projects', projectRef, 'pgbouncer-enabled'],
async ({ signal }) => {
let query = supabase.rpc('ipv6_active_status', { project_ref: projectRef }).returns<
{
pgbouncer_active: boolean
vercel_active: boolean
}[]
>()
if (signal) {
query = query.abortSignal(signal)
}
const result = await query
if (result.data === null) {
return {
pgbouncer_active: false,
vercel_active: false,
}
}
return result.data[0]
},
{ enabled: Boolean(projectRef) }
)
const pgbouncerEnabled = data?.pgbouncer_active ?? false
const vercelWithoutSupavisorEnabled = data?.vercel_active ?? false
// [Joshen] Pgbouncer list and vercel list are mutually exclusive
const pgbouncerProjectAcknowledged = pgbouncerBannerAcknowledged.includes(projectRef ?? '')
const vercelProjectAcknowledged = vercelBannerAcknowledged.includes(projectRef ?? '')
const allAcknowledged =
(!pgbouncerEnabled && !vercelWithoutSupavisorEnabled && ipv6BannerAcknowledged) ||
(ipv6BannerAcknowledged && pgbouncerEnabled && pgbouncerProjectAcknowledged) ||
(ipv6BannerAcknowledged && vercelWithoutSupavisorEnabled && vercelProjectAcknowledged)
if (
isLoadingProfile ||
isLoadingIpv6Enabled ||
router.pathname.includes('sign-in') ||
allAcknowledged
) {
return null
}
const currentlyViewing =
pgbouncerEnabled && !pgbouncerProjectAcknowledged
? ('pgbouncer' as const)
: vercelWithoutSupavisorEnabled && !vercelProjectAcknowledged
? ('vercel' as const)
: ('ipv6' as const)
return (
<div
@@ -22,19 +88,37 @@ export const NoticeBanner = () => {
style={{ height: '44px' }}
>
<p className="text-sm">
Prepare for the PgBouncer and IPv4 deprecations on 26th January 2024
{currentlyViewing === 'pgbouncer' &&
'Our logs on 26th Jan show that you have accessed PgBouncer. Please migrate now. You can ignore this warning if you have already migrated.'}
{currentlyViewing === 'vercel' &&
"To prepare for the IPv4 migration, please redeploy your Vercel application to detect the updated environment variables if it hasn't been deployed since 27th January."}
{currentlyViewing === 'ipv6' &&
'We are migrating our infrastructure from IPv4 to IPv6. Please migrate now. You can ignore this warning if you have already migrated.'}
</p>
<div className="flex items-center gap-x-1">
<Button asChild type="link" iconRight={<IconExternalLink />}>
<a
href="https://github.com/orgs/supabase/discussions/17817"
href={
currentlyViewing === 'vercel'
? 'https://supabase.com/partners/integrations/vercel'
: 'https://github.com/orgs/supabase/discussions/17817'
}
target="_blank"
rel="noreferrer"
>
Learn more
</a>
</Button>
<Button type="text" className="opacity-75" onClick={() => onUpdateAcknowledged(true)}>
<Button
type="text"
className="opacity-75"
onClick={() =>
onUpdateAcknowledged(
currentlyViewing,
currentlyViewing === 'ipv6' ? true : projectRef ?? ''
)
}
>
Dismiss
</Button>
</div>
+2
View File
@@ -39,6 +39,8 @@ export const LOCAL_STORAGE_KEYS = {
GRAPHIQL_RLS_BYPASS_WARNING: 'graphiql-rls-bypass-warning-dismissed',
CLS_DIFF_WARNING: 'cls-diff-warning-dismissed',
CLS_SELECT_STAR_WARNING: 'cls-select-star-warning-dismissed',
PGBOUNCER_IPV6_DEPRECATION_WARNING: 'pgbouncer-ipv6-deprecation-warning-dismissed',
VERCEL_IPV6_DEPRECATION_WARNING: 'vercel-ipv6-deprecation-warning-dismissed',
PGBOUNCER_DEPRECATION_WARNING: 'pgbouncer-deprecation-warning-dismissed',
}
@@ -0,0 +1,21 @@
create
or replace function ipv6_active_status (project_ref text) returns table (pgbouncer_active boolean, vercel_active boolean) as $$
declare
pgbouncer_active boolean;
vercel_active boolean;
begin
select exists (
select 1
from active_pgbouncer_projects ap
where ap.project_ref = $1
) into pgbouncer_active;
select exists (
select 1
from vercel_project_connections_without_supavisor vp
where vp.project_ref = $1
) into vercel_active;
return query select pgbouncer_active, vercel_active;
end;
$$ language plpgsql security definer;