mirror of
https://github.com/supabase/supabase.git
synced 2026-10-06 01:45:10 +03:00
## What kind of change does this PR introduce? Mechanical cleanup on top of the Button default-variant change (#50160). ## What is the current behavior? Many callsites still pass `variant="default"` even though that is now the component default. ## What is the new behavior? Removes redundant static `variant="default"` from legacy `Button` and `ButtonTooltip` callsites. Keeps explicit defaults where they document the API: - `button-default.tsx` and `button-sizes.tsx` demos - `DocsButton`, which pins neutral styling at the wrapper boundary ## To test Studio: - [Auth → Rate Limits](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/auth/rate-limits): dirty the form so Cancel appears; Cancel stays neutral, Save stays green - [Project Settings → API Keys](https://studio-staging-2s957kwc4-supabase.vercel.app/dashboard/project/_/settings/api-keys): `DocsButton` in the header actions stays neutral Design system: - [Design system → Button](https://design-system-git-dnywh-dc924ac1-supabase.vercel.app/design-system/docs/components/button): `button-default` / `button-sizes` still show explicit default styling; Primary (green) is restricted to the Primary section (and `asChild`) WWW: - [www → Brand assets](https://zone-www-dot-com-git-dnywh-dc924ac1-supabase.vercel.app/brand-assets): Download logo kit / Download button kit stay neutral
207 lines
7.4 KiB
TypeScript
207 lines
7.4 KiB
TypeScript
import { zodResolver } from '@hookform/resolvers/zod'
|
||
import { PermissionAction } from '@supabase/shared-types/out/constants'
|
||
import { useParams } from 'common'
|
||
import { useEffect } from 'react'
|
||
import { useForm, useWatch } from 'react-hook-form'
|
||
import { toast } from 'sonner'
|
||
import { Button, Card, CardContent, CardFooter, Form, FormControl, FormField, Switch } from 'ui'
|
||
import { Admonition } from 'ui-patterns/Admonition'
|
||
import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
|
||
import {
|
||
PageSection,
|
||
PageSectionContent,
|
||
PageSectionMeta,
|
||
PageSectionSummary,
|
||
PageSectionTitle,
|
||
} from 'ui-patterns/PageSection'
|
||
import { GenericSkeletonLoader } from 'ui-patterns/ShimmeringLoader'
|
||
import * as z from 'zod'
|
||
|
||
import { AlertError } from '@/components/ui/AlertError'
|
||
import { InlineLink } from '@/components/ui/InlineLink'
|
||
import { useAuthConfigQuery } from '@/data/auth/auth-config-query'
|
||
import { useAuthConfigUpdateMutation } from '@/data/auth/auth-config-update-mutation'
|
||
import { useTablesQuery } from '@/data/tables/tables-query'
|
||
import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions'
|
||
import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject'
|
||
|
||
const schema = z.object({
|
||
AUDIT_LOG_DISABLE_POSTGRES: z.boolean(),
|
||
})
|
||
|
||
const AUDIT_LOG_ENTRIES_TABLE = 'audit_log_entries'
|
||
|
||
export const AuditLogsForm = () => {
|
||
const { ref: projectRef } = useParams()
|
||
const { data: project } = useSelectedProjectQuery()
|
||
|
||
const { can: canUpdateConfig } = useAsyncCheckPermissions(
|
||
PermissionAction.UPDATE,
|
||
'custom_config_gotrue'
|
||
)
|
||
|
||
const { data: tables = [] } = useTablesQuery({
|
||
projectRef: project?.ref,
|
||
connectionString: project?.connectionString,
|
||
includeColumns: false,
|
||
schema: 'auth',
|
||
})
|
||
const auditLogTable = tables.find((x) => x.name === AUDIT_LOG_ENTRIES_TABLE)
|
||
|
||
const {
|
||
data: authConfig,
|
||
error: authConfigError,
|
||
isError,
|
||
isPending: isLoading,
|
||
} = useAuthConfigQuery({ projectRef })
|
||
|
||
const { mutate: updateAuthConfig, isPending: isUpdatingConfig } = useAuthConfigUpdateMutation({
|
||
onError: (error) => {
|
||
toast.error(`Failed to update audit logs: ${error?.message}`)
|
||
},
|
||
onSuccess: () => {
|
||
toast.success('Successfully updated audit logs settings')
|
||
},
|
||
})
|
||
|
||
const form = useForm({
|
||
resolver: zodResolver(schema),
|
||
defaultValues: { AUDIT_LOG_DISABLE_POSTGRES: false },
|
||
})
|
||
const { isDirty } = form.formState
|
||
const { AUDIT_LOG_DISABLE_POSTGRES: formValueDisablePostgres } = useWatch({
|
||
control: form.control,
|
||
})
|
||
const currentlyDisabled = authConfig?.AUDIT_LOG_DISABLE_POSTGRES ?? false
|
||
const isDisabling = !currentlyDisabled && formValueDisablePostgres
|
||
|
||
const onSubmitAuditLogs = (values: any) => {
|
||
if (!projectRef) return console.error('Project ref is required')
|
||
updateAuthConfig({ projectRef: projectRef, config: values })
|
||
}
|
||
|
||
useEffect(() => {
|
||
if (authConfig) {
|
||
form.reset({ AUDIT_LOG_DISABLE_POSTGRES: authConfig?.AUDIT_LOG_DISABLE_POSTGRES ?? false })
|
||
}
|
||
}, [authConfig])
|
||
|
||
if (isError) {
|
||
return (
|
||
<PageSection>
|
||
<PageSectionContent>
|
||
<AlertError
|
||
error={authConfigError}
|
||
subject="Failed to retrieve auth configuration for hooks"
|
||
/>
|
||
</PageSectionContent>
|
||
</PageSection>
|
||
)
|
||
}
|
||
|
||
if (isLoading) {
|
||
return (
|
||
<PageSection>
|
||
<PageSectionContent>
|
||
<GenericSkeletonLoader />
|
||
</PageSectionContent>
|
||
</PageSection>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<PageSection>
|
||
<PageSectionMeta>
|
||
<PageSectionSummary>
|
||
<PageSectionTitle>Settings</PageSectionTitle>
|
||
</PageSectionSummary>
|
||
</PageSectionMeta>
|
||
<PageSectionContent>
|
||
<Form {...form}>
|
||
<form onSubmit={form.handleSubmit(onSubmitAuditLogs)} className="space-y-4">
|
||
<Card>
|
||
<CardContent>
|
||
<FormField
|
||
control={form.control}
|
||
name="AUDIT_LOG_DISABLE_POSTGRES"
|
||
render={({ field }) => (
|
||
<FormItemLayout
|
||
layout="flex-row-reverse"
|
||
label="Write audit logs to the database"
|
||
description={
|
||
<p className="text-sm prose text-foreground-lighter max-w-full">
|
||
When enabled, audit logs are written to the{' '}
|
||
<InlineLink
|
||
target="_blank"
|
||
rel="noopener noreferrer"
|
||
href={`/project/${projectRef}/editor/${auditLogTable?.id}`}
|
||
>
|
||
<code className="text-code-inline">{AUDIT_LOG_ENTRIES_TABLE}</code>
|
||
</InlineLink>{' '}
|
||
table.
|
||
<br />
|
||
You can disable this to reduce disk usage while still accessing logs
|
||
through the{' '}
|
||
<InlineLink
|
||
href={`/project/${projectRef}/logs/explorer?q=select%0A++cast(timestamp+as+datetime)+as+timestamp%2C%0A++event_message%2C+metadata+%0Afrom+auth_audit_logs+%0Alimit+10%0A`}
|
||
>
|
||
Auth logs
|
||
</InlineLink>
|
||
.
|
||
</p>
|
||
}
|
||
>
|
||
<FormControl>
|
||
<Switch
|
||
checked={!field.value}
|
||
onCheckedChange={(value) => field.onChange(!value)}
|
||
disabled={!canUpdateConfig}
|
||
/>
|
||
</FormControl>
|
||
</FormItemLayout>
|
||
)}
|
||
/>
|
||
{isDisabling && (
|
||
<Admonition
|
||
type="warning"
|
||
className="mt-4"
|
||
title="Disabling PostgreSQL storage will not automatically migrate or transfer existing audit log data"
|
||
description={
|
||
<p>
|
||
Future audit logs will only appear in the project’s{' '}
|
||
<InlineLink
|
||
href={`/project/${projectRef}/logs/explorer?q=select%0A++cast(timestamp+as+datetime)+as+timestamp%2C%0A++event_message%2C+metadata+%0Afrom+auth_audit_logs+%0Alimit+10%0A`}
|
||
>
|
||
auth logs
|
||
</InlineLink>
|
||
. You are responsible for backing up, copying, or migrating existing data
|
||
from the{' '}
|
||
<code className="text-code-inline break-keep!">
|
||
{AUDIT_LOG_ENTRIES_TABLE}
|
||
</code>{' '}
|
||
table if needed.
|
||
</p>
|
||
}
|
||
/>
|
||
)}
|
||
</CardContent>
|
||
|
||
<CardFooter className="justify-end space-x-2">
|
||
{isDirty && <Button onClick={() => form.reset()}>Cancel</Button>}
|
||
<Button
|
||
variant="primary"
|
||
type="submit"
|
||
disabled={!canUpdateConfig || isUpdatingConfig || !isDirty}
|
||
loading={isUpdatingConfig}
|
||
>
|
||
Save changes
|
||
</Button>
|
||
</CardFooter>
|
||
</Card>
|
||
</form>
|
||
</Form>
|
||
</PageSectionContent>
|
||
</PageSection>
|
||
)
|
||
}
|