diff --git a/studio/components/layouts/AuthLayout/AuthLayout.utils.ts b/studio/components/layouts/AuthLayout/AuthLayout.utils.ts
index 37272a7c9f9..17de5da94ea 100644
--- a/studio/components/layouts/AuthLayout/AuthLayout.utils.ts
+++ b/studio/components/layouts/AuthLayout/AuthLayout.utils.ts
@@ -10,7 +10,6 @@ export const generateAuthMenu = (ref: string): ProductMenuGroup[] => {
items: [
{ name: 'Users', key: 'users', url: `/project/${ref}/auth/users`, items: [] },
{ name: 'Policies', key: 'policies', url: `/project/${ref}/auth/policies`, items: [] },
- { name: 'Templates', key: 'templates', url: `/project/${ref}/auth/templates`, items: [] },
...(IS_PLATFORM && logsAuth
? [
{
@@ -28,18 +27,16 @@ export const generateAuthMenu = (ref: string): ProductMenuGroup[] => {
{
title: 'Configuration',
items: [
- {
- name: 'Settings',
- key: 'settings',
- url: `/project/${ref}/auth/settings`,
- items: [],
- },
- {
- name: 'Settings new',
- key: 'settings-new',
- url: `/project/${ref}/auth/settings-new`,
- items: [],
- },
+ ...(IS_PLATFORM && logsAuth
+ ? [
+ {
+ name: 'Settings',
+ key: 'settings',
+ url: `/project/${ref}/auth/settings`,
+ items: [],
+ },
+ ]
+ : []),
{
name: 'Templates',
key: 'settings-templates',
diff --git a/studio/pages/project/[ref]/auth/settings-new.tsx b/studio/pages/project/[ref]/auth/settings-new.tsx
deleted file mode 100644
index 7b94774a78d..00000000000
--- a/studio/pages/project/[ref]/auth/settings-new.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { AuthProvidersForm } from 'components/interfaces'
-import RedirectDomains from 'components/interfaces/Auth/RedirectDomains'
-import { AuthLayout } from 'components/layouts'
-import { AutoSchemaForm, FormsContainer } from 'components/ui/Forms'
-import { useStore } from 'hooks'
-import { observer } from 'mobx-react-lite'
-import React, { useEffect } from 'react'
-import { NextPageWithLayout } from 'types'
-
-const PageLayout: NextPageWithLayout = () => {
- const { ui, authConfig } = useStore()
-
- useEffect(() => {
- // temporary store loader
- authConfig.load()
- }, [ui.selectedProjectRef])
-
- if (authConfig)
- return (
-
-
-
-
-
- )
-}
-
-PageLayout.getLayout = (page) => {
- return {page}
-}
-
-export default observer(PageLayout)
diff --git a/studio/pages/project/[ref]/auth/settings-old.tsx b/studio/pages/project/[ref]/auth/settings-old.tsx
new file mode 100644
index 00000000000..e32e1f4cfd8
--- /dev/null
+++ b/studio/pages/project/[ref]/auth/settings-old.tsx
@@ -0,0 +1,1132 @@
+import useSWR from 'swr'
+import { observer } from 'mobx-react-lite'
+import { useState, useEffect } from 'react'
+import { useRouter } from 'next/router'
+import { AutoField, NumField } from 'uniforms-bootstrap4'
+import { Button, Typography, Toggle as UIToggle } from '@supabase/ui'
+import Divider from 'components/ui/Divider'
+
+import { API_URL } from 'lib/constants'
+import { useStore } from 'hooks'
+import { authConfig } from 'stores/jsonSchema'
+import { get, patch } from 'lib/common/fetch'
+import { pluckJsonSchemaFields } from 'lib/helpers'
+import { AuthLayout } from 'components/layouts'
+import Table from 'components/to-be-cleaned/Table'
+import Panel from 'components/ui/Panel'
+import ToggleField from 'components/to-be-cleaned/forms/ToggleField'
+import SecretField from 'components/to-be-cleaned/forms/SecretField'
+import SchemaFormPanel from 'components/to-be-cleaned/forms/SchemaFormPanel'
+import { NextPageWithLayout } from 'types'
+
+const Auth: NextPageWithLayout = () => {
+ return (
+
+
+
+ )
+}
+
+Auth.getLayout = (page) => {page}
+
+export default observer(Auth)
+
+const Settings = () => {
+ const router = useRouter()
+ const { ui } = useStore()
+
+ const [model, setModel] = useState({})
+ const [smsProviderModel, setSmsProviderModel] = useState({})
+ const [externalProvidersModel, setExternalProvidersModel] = useState({})
+ const [isCustomSMTPEnabled, setCustomSMTP] = useState(false)
+ const URL = `${API_URL}/auth/${router.query.ref}/config`
+ const { data: config, error }: any = useSWR(URL, get)
+ const { ref: projectRef } = router.query
+
+ if (error) {
+ return (
+
+ Error connecting to API
+ {`${error}`}
+
+ )
+ }
+
+ useEffect(() => {
+ if (config) {
+ const temp =
+ config.SMTP_ADMIN_EMAIL ||
+ config.SMTP_HOST ||
+ config.SMTP_PORT ||
+ config.SMTP_USER ||
+ config.SMTP_PASS
+ setCustomSMTP(temp)
+ }
+ setModel({ ...config })
+ setExternalProvidersModel({ ...config })
+ }, [config])
+
+ const onFormSubmit = async (model: any) => {
+ for (const [key, value] of Object.entries(model)) {
+ // remove any whitespaces in OAuth or Sms provider credentials
+ if ((key.includes('EXTERNAL') || key.includes('SMS')) && typeof value === 'string') {
+ model[key] = value.replace(/\s/g, '')
+ }
+ }
+ const response = await patch(URL, model)
+ if (response.error) {
+ ui.setNotification({
+ category: 'error',
+ message: `Update config failed: ${response.error.message}`,
+ })
+ } else {
+ const updates = response
+ setModel({ ...updates })
+ ui.setNotification({ category: 'success', message: 'Settings saved' })
+ }
+ }
+
+ /*
+ * handleToggle
+ *
+ * This can be used for toggles that are not in a schema form
+ */
+ const handleToggle = async (key: any, value?: any) => {
+ const payload = {
+ [key]: value ? value : !model[key],
+ }
+
+ try {
+ const response = await patch(URL, payload)
+ if (response.error) throw response.error
+ const updates = response
+ setModel({ ...updates })
+ ui.setNotification({ category: 'success', message: 'Settings saved' })
+ } catch (error: any) {
+ ui.setNotification({ category: 'error', message: `Update config failed: ${error.message}` })
+ }
+ }
+
+ const onFormReset = () => {
+ setExternalProvidersModel({ ...config })
+ }
+
+ return (
+
+
+
onFormSubmit(model)}
+ >
+
+
+
+
+
+
+
+
+
+
+
+ onFormSubmit({
+ ...model,
+ })
+ }
+ >
+ {
+ handleToggle('EXTERNAL_EMAIL_ENABLED', value)
+ }}
+ checked={model.EXTERNAL_EMAIL_ENABLED}
+ descriptionText={authConfig.properties.EXTERNAL_EMAIL_ENABLED.help}
+ />
+
+ {
+ handleToggle('MAILER_SECURE_EMAIL_CHANGE_ENABLED', value)
+ }}
+ checked={model.MAILER_SECURE_EMAIL_CHANGE_ENABLED}
+ descriptionText={authConfig.properties.MAILER_SECURE_EMAIL_CHANGE_ENABLED.help}
+ />
+
+ {
+ // If MAILER_AUTOCONFIRM is set to true, it means we are disabling email confirmations.
+ // "Enable email confirmations" should be toggled off.
+ handleToggle('MAILER_AUTOCONFIRM', !value)
+ }}
+ checked={!model.MAILER_AUTOCONFIRM}
+ descriptionText={authConfig.properties.MAILER_AUTOCONFIRM.help}
+ />
+
+ {
+ /*
+ * temporary solution
+ * clear the values of SMTP when toggling
+ */
+ if (!value) {
+ onFormSubmit({
+ SMTP_ADMIN_EMAIL: '',
+ SMTP_HOST: '',
+ SMTP_PORT: '',
+ SMTP_USER: '',
+ SMTP_PASS: '',
+ SMTP_SENDER_NAME: '',
+ RATE_LIMIT_EMAIL_SENT: 30,
+ })
+ }
+ setCustomSMTP(!isCustomSMTPEnabled)
+ }}
+ />
+ {isCustomSMTPEnabled && (
+ <>
+
+
+
+
+
+
+
+ >
+ )}
+
+
+
+
+
setSmsProviderModel(model)}
+ onSubmit={(model: any) => onFormSubmit(model)}
+ >
+ <>
+ {
+ handleToggle('EXTERNAL_PHONE_ENABLED')
+ }}
+ checked={model.EXTERNAL_PHONE_ENABLED}
+ descriptionText={authConfig.properties.EXTERNAL_PHONE_ENABLED.help}
+ />
+
+ {model.EXTERNAL_PHONE_ENABLED && (
+ <>
+
+
+
+ {smsProviderModel?.SMS_PROVIDER === 'messagebird' ? (
+ <>
+
+
+ >
+ ) : smsProviderModel?.SMS_PROVIDER === 'textlocal' ? (
+ <>
+
+
+ >
+ ) : smsProviderModel?.SMS_PROVIDER === 'vonage' ? (
+ <>
+
+
+
+ >
+ ) : (
+ <>
+
+
+
+ >
+ )}
+ >
+ )}
+ {
+ // If SMS_AUTOCONFIRM is set to true, it means we are disabling phone confirmations.
+ // "Enable phone confirmations" should be toggled off.
+ handleToggle('SMS_AUTOCONFIRM', !value)
+ }}
+ //
+ checked={!model.SMS_AUTOCONFIRM}
+ descriptionText={authConfig.properties.SMS_AUTOCONFIRM.help}
+ />
+ >
+
+
+
+
setExternalProvidersModel(model)}
+ onReset={() => onFormReset()}
+ onSubmit={(model: any) => onFormSubmit(model)}
+ >
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_APPLE_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_AZURE_ENABLED && (
+ <>
+
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_BITBUCKET_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_DISCORD_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_FACEBOOK_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_GITHUB_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_GITLAB_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_GOOGLE_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_KEYCLOAK_ENABLED && (
+ <>
+
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_LINKEDIN_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_NOTION_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_TWITCH_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_TWITTER_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_SLACK_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_SPOTIFY_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_WORKOS_ENABLED && (
+ <>
+
+
+
+ >
+ )}
+
+
+ Create new credentials
+
+ )
+ }
+ />
+ {externalProvidersModel.EXTERNAL_ZOOM_ENABLED && (
+ <>
+
+
+ >
+ )}
+
+
+
+
+
+ )
+}
+
+const AuditLog = ({ interval, projectRef }: any) => {
+ const { meta } = useStore()
+ const [logs, setLogs] = useState([])
+ const [isLoading, setIsLoading] = useState(false)
+
+ const refreshLogs = async () => {
+ setIsLoading(true)
+ try {
+ let query = `
+ SELECT
+ *
+ FROM
+ auth.audit_log_entries
+ WHERE
+ created_at > CURRENT_TIMESTAMP - interval '${interval}'
+ ORDER BY
+ created_at DESC
+ LIMIT 1000;
+ `
+ const response = await meta.query(query)
+ if (response.error) throw response.error
+ setLogs(response)
+ } catch (error) {
+ console.error('Refresh logs error:', error)
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ useEffect(() => {
+ refreshLogs()
+ }, [])
+
+ if (!logs.length) return
+ const cellCss = 'table-cell px-4 py-3 text-gray-200 font-mono text-xs'
+ return (
+
+
+ Audit Trail
+
+
+
+
+
+ }
+ >
+
+ Time
+ Action
+ User ID
+ Identity
+ >
+ }
+ body={logs.map((x: any, i: number) => (
+
+
+ {x.payload.timestamp.replace('T', ' ')}
+
+
+ {x.payload.action}
+
+
+ {x.payload.actor_id || x.payload.traits?.user_id}
+
+
+
+ {x.payload.actor_username || x.payload.traits?.user_email}
+
+
+
+ ))}
+ />
+
+ )
+}
diff --git a/studio/pages/project/[ref]/auth/settings.tsx b/studio/pages/project/[ref]/auth/settings.tsx
index e32e1f4cfd8..7b94774a78d 100644
--- a/studio/pages/project/[ref]/auth/settings.tsx
+++ b/studio/pages/project/[ref]/auth/settings.tsx
@@ -1,1132 +1,32 @@
-import useSWR from 'swr'
-import { observer } from 'mobx-react-lite'
-import { useState, useEffect } from 'react'
-import { useRouter } from 'next/router'
-import { AutoField, NumField } from 'uniforms-bootstrap4'
-import { Button, Typography, Toggle as UIToggle } from '@supabase/ui'
-import Divider from 'components/ui/Divider'
-
-import { API_URL } from 'lib/constants'
-import { useStore } from 'hooks'
-import { authConfig } from 'stores/jsonSchema'
-import { get, patch } from 'lib/common/fetch'
-import { pluckJsonSchemaFields } from 'lib/helpers'
+import { AuthProvidersForm } from 'components/interfaces'
+import RedirectDomains from 'components/interfaces/Auth/RedirectDomains'
import { AuthLayout } from 'components/layouts'
-import Table from 'components/to-be-cleaned/Table'
-import Panel from 'components/ui/Panel'
-import ToggleField from 'components/to-be-cleaned/forms/ToggleField'
-import SecretField from 'components/to-be-cleaned/forms/SecretField'
-import SchemaFormPanel from 'components/to-be-cleaned/forms/SchemaFormPanel'
+import { AutoSchemaForm, FormsContainer } from 'components/ui/Forms'
+import { useStore } from 'hooks'
+import { observer } from 'mobx-react-lite'
+import React, { useEffect } from 'react'
import { NextPageWithLayout } from 'types'
-const Auth: NextPageWithLayout = () => {
- return (
-
-
-
- )
-}
+const PageLayout: NextPageWithLayout = () => {
+ const { ui, authConfig } = useStore()
-Auth.getLayout = (page) => {page}
+ useEffect(() => {
+ // temporary store loader
+ authConfig.load()
+ }, [ui.selectedProjectRef])
-export default observer(Auth)
-
-const Settings = () => {
- const router = useRouter()
- const { ui } = useStore()
-
- const [model, setModel] = useState({})
- const [smsProviderModel, setSmsProviderModel] = useState({})
- const [externalProvidersModel, setExternalProvidersModel] = useState({})
- const [isCustomSMTPEnabled, setCustomSMTP] = useState(false)
- const URL = `${API_URL}/auth/${router.query.ref}/config`
- const { data: config, error }: any = useSWR(URL, get)
- const { ref: projectRef } = router.query
-
- if (error) {
+ if (authConfig)
return (
-
- Error connecting to API
- {`${error}`}
-
+
+
+
+
+
)
- }
-
- useEffect(() => {
- if (config) {
- const temp =
- config.SMTP_ADMIN_EMAIL ||
- config.SMTP_HOST ||
- config.SMTP_PORT ||
- config.SMTP_USER ||
- config.SMTP_PASS
- setCustomSMTP(temp)
- }
- setModel({ ...config })
- setExternalProvidersModel({ ...config })
- }, [config])
-
- const onFormSubmit = async (model: any) => {
- for (const [key, value] of Object.entries(model)) {
- // remove any whitespaces in OAuth or Sms provider credentials
- if ((key.includes('EXTERNAL') || key.includes('SMS')) && typeof value === 'string') {
- model[key] = value.replace(/\s/g, '')
- }
- }
- const response = await patch(URL, model)
- if (response.error) {
- ui.setNotification({
- category: 'error',
- message: `Update config failed: ${response.error.message}`,
- })
- } else {
- const updates = response
- setModel({ ...updates })
- ui.setNotification({ category: 'success', message: 'Settings saved' })
- }
- }
-
- /*
- * handleToggle
- *
- * This can be used for toggles that are not in a schema form
- */
- const handleToggle = async (key: any, value?: any) => {
- const payload = {
- [key]: value ? value : !model[key],
- }
-
- try {
- const response = await patch(URL, payload)
- if (response.error) throw response.error
- const updates = response
- setModel({ ...updates })
- ui.setNotification({ category: 'success', message: 'Settings saved' })
- } catch (error: any) {
- ui.setNotification({ category: 'error', message: `Update config failed: ${error.message}` })
- }
- }
-
- const onFormReset = () => {
- setExternalProvidersModel({ ...config })
- }
-
- return (
-
-
-
onFormSubmit(model)}
- >
-
-
-
-
-
-
-
-
-
-
-
- onFormSubmit({
- ...model,
- })
- }
- >
- {
- handleToggle('EXTERNAL_EMAIL_ENABLED', value)
- }}
- checked={model.EXTERNAL_EMAIL_ENABLED}
- descriptionText={authConfig.properties.EXTERNAL_EMAIL_ENABLED.help}
- />
-
- {
- handleToggle('MAILER_SECURE_EMAIL_CHANGE_ENABLED', value)
- }}
- checked={model.MAILER_SECURE_EMAIL_CHANGE_ENABLED}
- descriptionText={authConfig.properties.MAILER_SECURE_EMAIL_CHANGE_ENABLED.help}
- />
-
- {
- // If MAILER_AUTOCONFIRM is set to true, it means we are disabling email confirmations.
- // "Enable email confirmations" should be toggled off.
- handleToggle('MAILER_AUTOCONFIRM', !value)
- }}
- checked={!model.MAILER_AUTOCONFIRM}
- descriptionText={authConfig.properties.MAILER_AUTOCONFIRM.help}
- />
-
- {
- /*
- * temporary solution
- * clear the values of SMTP when toggling
- */
- if (!value) {
- onFormSubmit({
- SMTP_ADMIN_EMAIL: '',
- SMTP_HOST: '',
- SMTP_PORT: '',
- SMTP_USER: '',
- SMTP_PASS: '',
- SMTP_SENDER_NAME: '',
- RATE_LIMIT_EMAIL_SENT: 30,
- })
- }
- setCustomSMTP(!isCustomSMTPEnabled)
- }}
- />
- {isCustomSMTPEnabled && (
- <>
-
-
-
-
-
-
-
- >
- )}
-
-
-
-
-
setSmsProviderModel(model)}
- onSubmit={(model: any) => onFormSubmit(model)}
- >
- <>
- {
- handleToggle('EXTERNAL_PHONE_ENABLED')
- }}
- checked={model.EXTERNAL_PHONE_ENABLED}
- descriptionText={authConfig.properties.EXTERNAL_PHONE_ENABLED.help}
- />
-
- {model.EXTERNAL_PHONE_ENABLED && (
- <>
-
-
-
- {smsProviderModel?.SMS_PROVIDER === 'messagebird' ? (
- <>
-
-
- >
- ) : smsProviderModel?.SMS_PROVIDER === 'textlocal' ? (
- <>
-
-
- >
- ) : smsProviderModel?.SMS_PROVIDER === 'vonage' ? (
- <>
-
-
-
- >
- ) : (
- <>
-
-
-
- >
- )}
- >
- )}
- {
- // If SMS_AUTOCONFIRM is set to true, it means we are disabling phone confirmations.
- // "Enable phone confirmations" should be toggled off.
- handleToggle('SMS_AUTOCONFIRM', !value)
- }}
- //
- checked={!model.SMS_AUTOCONFIRM}
- descriptionText={authConfig.properties.SMS_AUTOCONFIRM.help}
- />
- >
-
-
-
-
setExternalProvidersModel(model)}
- onReset={() => onFormReset()}
- onSubmit={(model: any) => onFormSubmit(model)}
- >
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_APPLE_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_AZURE_ENABLED && (
- <>
-
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_BITBUCKET_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_DISCORD_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_FACEBOOK_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_GITHUB_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_GITLAB_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_GOOGLE_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_KEYCLOAK_ENABLED && (
- <>
-
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_LINKEDIN_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_NOTION_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_TWITCH_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_TWITTER_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_SLACK_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_SPOTIFY_ENABLED && (
- <>
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_WORKOS_ENABLED && (
- <>
-
-
-
- >
- )}
-
-
- Create new credentials
-
- )
- }
- />
- {externalProvidersModel.EXTERNAL_ZOOM_ENABLED && (
- <>
-
-
- >
- )}
-
-
-
-
-
- )
}
-const AuditLog = ({ interval, projectRef }: any) => {
- const { meta } = useStore()
- const [logs, setLogs] = useState([])
- const [isLoading, setIsLoading] = useState(false)
-
- const refreshLogs = async () => {
- setIsLoading(true)
- try {
- let query = `
- SELECT
- *
- FROM
- auth.audit_log_entries
- WHERE
- created_at > CURRENT_TIMESTAMP - interval '${interval}'
- ORDER BY
- created_at DESC
- LIMIT 1000;
- `
- const response = await meta.query(query)
- if (response.error) throw response.error
- setLogs(response)
- } catch (error) {
- console.error('Refresh logs error:', error)
- } finally {
- setIsLoading(false)
- }
- }
-
- useEffect(() => {
- refreshLogs()
- }, [])
-
- if (!logs.length) return
- const cellCss = 'table-cell px-4 py-3 text-gray-200 font-mono text-xs'
- return (
-
-
- Audit Trail
-
-
-
-
-
- }
- >
-
- Time
- Action
- User ID
- Identity
- >
- }
- body={logs.map((x: any, i: number) => (
-
-
- {x.payload.timestamp.replace('T', ' ')}
-
-
- {x.payload.action}
-
-
- {x.payload.actor_id || x.payload.traits?.user_id}
-
-
-
- {x.payload.actor_username || x.payload.traits?.user_email}
-
-
-
- ))}
- />
-
- )
+PageLayout.getLayout = (page) => {
+ return {page}
}
+
+export default observer(PageLayout)