mirror of
https://github.com/supabase/supabase.git
synced 2026-10-11 04:15:04 +03:00
Refactors our help sidebar within Studio to include the actual support form itself when contact is selected. This PR also cleans up the initial state of the sidebar and the options within. ## To test: - Open an org and click the help icon top right - Click contact support - Submit a support ticket - Click done to return to support sidebar state <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Support form V3 and support sidebar with status button; direct-email helper and URL prefill * Success screen supports onFinish callback and customizable finish label * AI Assistant and Help options accept optional click callbacks; resource items gain keyboard/accessibility support * **Refactor** * Help panel split into home/support views with back navigation * Support components accept flexible align/className props and layout/styling tweaks * Initial URL params loader added for support form * **Tests** * New/updated tests for support flows, success screen, and help options interactions <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Gildas Garcia <1122076+djhi@users.noreply.github.com>
103 lines
3.8 KiB
TypeScript
103 lines
3.8 KiB
TypeScript
import { AnimatePresence, motion } from 'framer-motion'
|
|
import { ExternalLink } from 'lucide-react'
|
|
import Link from 'next/link'
|
|
import { Button } from 'ui'
|
|
import { Admonition } from 'ui-patterns/admonition'
|
|
|
|
import { useIncidentStatusQuery } from '@/data/platform/incident-status-query'
|
|
import { processIncidentData } from '@/data/platform/incident-status-utils'
|
|
|
|
interface IncidentAdmonitionProps {
|
|
isActive: boolean
|
|
className?: string
|
|
}
|
|
|
|
const STATUS_DESCRIPTION_SIGN_OFF = 'Follow the status page for updates.'
|
|
|
|
const capitalizeFirstLetter = (str: string) => str.charAt(0).toUpperCase() + str.slice(1)
|
|
|
|
const getStatusDescription = (
|
|
status: string,
|
|
hasMultipleIncidents: boolean,
|
|
allSameStatus: boolean
|
|
): string => {
|
|
const isPlural = hasMultipleIncidents
|
|
const issueTerm = isPlural ? 'these issues' : 'this issue'
|
|
|
|
switch (status) {
|
|
case 'investigating':
|
|
if (hasMultipleIncidents && !allSameStatus) {
|
|
return `We are aware of multiple ongoing issues and are investigating. ${STATUS_DESCRIPTION_SIGN_OFF}`
|
|
}
|
|
return `We are investigating ${issueTerm}. ${STATUS_DESCRIPTION_SIGN_OFF}`
|
|
|
|
case 'identified':
|
|
if (hasMultipleIncidents && !allSameStatus) {
|
|
return `We have identified the cause of some of ${issueTerm} and are working on fixes. ${STATUS_DESCRIPTION_SIGN_OFF}`
|
|
}
|
|
return `We have identified the cause of ${issueTerm} and are working on a fix. ${STATUS_DESCRIPTION_SIGN_OFF}`
|
|
|
|
case 'monitoring':
|
|
if (hasMultipleIncidents && !allSameStatus) {
|
|
return `Fixes have been deployed for some of ${issueTerm} and we are monitoring the results. ${STATUS_DESCRIPTION_SIGN_OFF}`
|
|
}
|
|
return `A fix has been deployed and we are monitoring the results. ${STATUS_DESCRIPTION_SIGN_OFF}`
|
|
|
|
case 'resolved':
|
|
if (hasMultipleIncidents && !allSameStatus) {
|
|
return `Some of ${issueTerm} have been resolved, but others may still be ongoing. ${STATUS_DESCRIPTION_SIGN_OFF}`
|
|
}
|
|
return `${capitalizeFirstLetter(issueTerm)} ${isPlural ? 'have' : 'has'} been resolved but may take some time to fully recover. ${STATUS_DESCRIPTION_SIGN_OFF}`
|
|
|
|
default:
|
|
return `We are investigating ${issueTerm}. ${STATUS_DESCRIPTION_SIGN_OFF}`
|
|
}
|
|
}
|
|
|
|
export function IncidentAdmonition({ isActive, className }: IncidentAdmonitionProps) {
|
|
const { data: allStatusPageEvents, isLoading, isError } = useIncidentStatusQuery()
|
|
const { incidents = [] } = allStatusPageEvents ?? {}
|
|
|
|
// Don't render anything while loading, on error, or if no incidents
|
|
if (isLoading || isError || !incidents || incidents.length === 0) {
|
|
return null
|
|
}
|
|
|
|
const { hasMultipleIncidents, mostCriticalIncident, overallStatus, allSameStatus } =
|
|
processIncidentData(incidents)
|
|
|
|
// Show most recent incident name + count if multiple incidents
|
|
const statusTitle =
|
|
(mostCriticalIncident?.name ?? '') +
|
|
(hasMultipleIncidents
|
|
? ` and ${incidents.length - 1} other issue${incidents.length > 2 ? 's' : ''}`
|
|
: '')
|
|
|
|
return (
|
|
<AnimatePresence>
|
|
{isActive && (
|
|
<motion.aside
|
|
initial={{ height: 0, opacity: 0 }}
|
|
animate={{ height: 'auto', opacity: 1 }}
|
|
exit={{ height: 0, opacity: 0 }}
|
|
>
|
|
<Admonition
|
|
type="warning"
|
|
layout="horizontal"
|
|
className={className}
|
|
title={statusTitle}
|
|
description={getStatusDescription(overallStatus, hasMultipleIncidents, allSameStatus)}
|
|
actions={
|
|
<Button asChild type="default" icon={<ExternalLink strokeWidth={1.5} />}>
|
|
<Link href="https://status.supabase.com/" target="_blank" rel="noreferrer">
|
|
Status page
|
|
</Link>
|
|
</Button>
|
|
}
|
|
/>
|
|
</motion.aside>
|
|
)}
|
|
</AnimatePresence>
|
|
)
|
|
}
|