| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207 |
- import { zodResolver } from '@hookform/resolvers/zod'
- import { PermissionAction } from '@supabase/shared-types/out/constants'
- import { useParams } from 'common'
- import { useEffect } from 'react'
- import { useForm } from 'react-hook-form'
- import { toast } from 'sonner'
- import { Button, Card, CardContent, CardFooter, Form, FormControl, FormField, Switch } from 'ui'
- import { Admonition, GenericSkeletonLoader } from 'ui-patterns'
- import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout'
- import {
- PageSection,
- PageSectionContent,
- PageSectionMeta,
- PageSectionSummary,
- PageSectionTitle,
- } from 'ui-patterns/PageSection'
- 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 as any),
- defaultValues: { AUDIT_LOG_DISABLE_POSTGRES: false },
- })
- const { isDirty } = form.formState
- const { AUDIT_LOG_DISABLE_POSTGRES: formValueDisablePostgres } = form.watch()
- 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 type="default" onClick={() => form.reset()}>
- Cancel
- </Button>
- )}
- <Button
- type="primary"
- htmlType="submit"
- disabled={!canUpdateConfig || isUpdatingConfig || !isDirty}
- loading={isUpdatingConfig}
- >
- Save changes
- </Button>
- </CardFooter>
- </Card>
- </form>
- </Form>
- </PageSectionContent>
- </PageSection>
- )
- }
|