Files
supabase/apps/studio/components/interfaces/Settings/Database/DatabaseSettings/ResetDbPassword.tsx
T
Danny White 0a96a5d0ce chore(studio): polish database settings (#42970)
## What kind of change does this PR introduce?

UI update

## What is the current behavior?

- Database settings uses an older, much wider, layout
- This will become problematic later on as more complex elements are
added to the page
- Titles and descriptions are inconsistently formatted

## What is the new behavior?

| Before | After |
| --- | --- |
| <img width="1728" height="994" alt="Oldie 2 Toolshed
Supabase-EE998752-3696-45E4-A842-9666049153D8"
src="https://github.com/user-attachments/assets/8f0004cf-3bb4-4b00-900a-b116b80371a6"
/> | <img width="1728" height="994" alt="Oldie 2 Toolshed
Supabase-7E86FD58-35BB-4912-8B2F-8C7AAA03B462"
src="https://github.com/user-attachments/assets/606b51b4-21a0-4b7b-870b-ac92ed363f3c"
/> |
2026-02-27 11:16:02 +11:00

185 lines
6.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { PermissionAction } from '@supabase/shared-types/out/constants'
import { useParams } from 'common'
import { ButtonTooltip } from 'components/ui/ButtonTooltip'
import { PasswordStrengthBar } from 'components/ui/PasswordStrengthBar'
import { useDatabasePasswordResetMutation } from 'data/database/database-password-reset-mutation'
import { useAsyncCheckPermissions } from 'hooks/misc/useCheckPermissions'
import { useIsProjectActive, useSelectedProjectQuery } from 'hooks/misc/useSelectedProject'
import { DEFAULT_MINIMUM_PASSWORD_STRENGTH } from 'lib/constants'
import { passwordStrength, PasswordStrengthScore } from 'lib/password-strength'
import { generateStrongPassword } from 'lib/project'
import { useEffect, useState } from 'react'
import { toast } from 'sonner'
import { Button, Card, CardContent, CardDescription, CardHeader, CardTitle, Input, Modal } from 'ui'
import {
PageSection,
PageSectionContent,
PageSectionMeta,
PageSectionSummary,
PageSectionDescription,
PageSectionTitle,
} from 'ui-patterns/PageSection'
const ResetDbPassword = ({ disabled = false }) => {
const { ref } = useParams()
const isProjectActive = useIsProjectActive()
const { data: project } = useSelectedProjectQuery()
const { can: canResetDbPassword } = useAsyncCheckPermissions(
PermissionAction.UPDATE,
'projects',
{
resource: {
project_id: project?.id,
},
}
)
const [showResetDbPass, setShowResetDbPass] = useState<boolean>(false)
const [password, setPassword] = useState<string>('')
const [passwordStrengthMessage, setPasswordStrengthMessage] = useState<string>('')
const [passwordStrengthWarning, setPasswordStrengthWarning] = useState<string>('')
const [passwordStrengthScore, setPasswordStrengthScore] = useState(0)
const { mutate: resetDatabasePassword, isPending: isUpdatingPassword } =
useDatabasePasswordResetMutation({
onSuccess: async () => {
toast.success('Successfully updated database password')
setShowResetDbPass(false)
},
})
useEffect(() => {
if (showResetDbPass) {
setPassword('')
setPasswordStrengthMessage('')
setPasswordStrengthWarning('')
setPasswordStrengthScore(0)
}
}, [showResetDbPass])
async function checkPasswordStrength(value: any) {
const { message, warning, strength } = await passwordStrength(value)
setPasswordStrengthScore(strength)
setPasswordStrengthWarning(warning)
setPasswordStrengthMessage(message)
}
const onDbPassChange = (e: any) => {
const value = e.target.value
setPassword(value)
if (value == '') {
setPasswordStrengthScore(-1)
setPasswordStrengthMessage('')
} else checkPasswordStrength(value)
}
const confirmResetDbPass = async () => {
if (!ref) return console.error('Project ref is required')
if (passwordStrengthScore >= DEFAULT_MINIMUM_PASSWORD_STRENGTH) {
resetDatabasePassword({ ref, password })
}
}
function generatePassword() {
const password = generateStrongPassword()
setPassword(password)
checkPasswordStrength(password)
}
return (
<>
<PageSection id="database-password">
<PageSectionMeta>
<PageSectionSummary>
<PageSectionTitle>Database password</PageSectionTitle>
<PageSectionDescription>Used for direct Postgres connections</PageSectionDescription>
</PageSectionSummary>
</PageSectionMeta>
<PageSectionContent>
<Card>
<CardContent className="flex flex-row items-center gap-x-2 justify-between">
<div className="space-y-0.5">
<h3 className="text-sm text-foreground">Reset database password</h3>
<p className="text-sm text-foreground-light text-balance">
The database password isn’t viewable after creation. Resetting it will break any
existing connections.
</p>
</div>
<ButtonTooltip
type="default"
disabled={!canResetDbPassword || !isProjectActive || disabled}
onClick={() => setShowResetDbPass(true)}
tooltip={{
content: {
side: 'bottom',
text: !canResetDbPassword
? 'You need additional permissions to reset the database password'
: !isProjectActive
? 'Unable to reset database password as project is not active'
: undefined,
},
}}
>
Reset password
</ButtonTooltip>
</CardContent>
</Card>
</PageSectionContent>
</PageSection>
<Modal
hideFooter
header="Reset database password"
confirmText="Reset password"
size="medium"
visible={showResetDbPass}
loading={isUpdatingPassword}
onCancel={() => setShowResetDbPass(false)}
>
<Modal.Content className="w-full space-y-8">
<Input
type="password"
value={password}
copy={password.length > 0}
onChange={onDbPassChange}
error={passwordStrengthWarning}
// @ts-ignore
descriptionText={
<PasswordStrengthBar
passwordStrengthScore={passwordStrengthScore as PasswordStrengthScore}
passwordStrengthMessage={passwordStrengthMessage}
password={password}
generateStrongPassword={generatePassword}
/>
}
/>
</Modal.Content>
<Modal.Separator />
<Modal.Content className="flex items-center justify-end space-x-2">
<Button
type="default"
disabled={isUpdatingPassword}
onClick={() => setShowResetDbPass(false)}
>
Cancel
</Button>
<Button
type="primary"
loading={isUpdatingPassword}
disabled={isUpdatingPassword}
onClick={() => confirmResetDbPass()}
>
Reset password
</Button>
</Modal.Content>
</Modal>
</>
)
}
export default ResetDbPassword