Skip to content

Commit

Permalink
Add logs endpoints and admin logs page (#176)
Browse files Browse the repository at this point in the history
  • Loading branch information
byn9826 authored Oct 1, 2024
1 parent 49e044b commit a154e50
Show file tree
Hide file tree
Showing 36 changed files with 2,381 additions and 7 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
- Manage Apps
- Manage Scopes
- Manage Roles
- View Logs
- Localization

### Screenshots
Expand Down
12 changes: 12 additions & 0 deletions admin-panel/app/Setup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,9 @@ const LayoutSetup = ({ children } : PropsWithChildren) => {
const locale = useCurrentLocale()
const { logoutRedirect } = useAuth()

const configs = useSignalValue(configSignal)
const showLogs = configs?.ENABLE_SIGN_IN_LOG || configs?.ENABLE_SMS_LOG || configs?.ENABLE_EMAIL_LOG

useEffect(
() => {
localStorage.setItem(
Expand Down Expand Up @@ -168,6 +171,15 @@ const LayoutSetup = ({ children } : PropsWithChildren) => {
>
{t('layout.scopes')}
</Navbar.Link>
{!!showLogs && (
<Navbar.Link
as={Link}
className='flex items-center h-6'
href={`/${locale}${routeTool.Internal.Logs}`}
>
{t('layout.logs')}
</Navbar.Link>
)}
<Navbar.Link
as={Link}
className='flex items-center h-6'
Expand Down
86 changes: 86 additions & 0 deletions admin-panel/app/[lang]/logs/email/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
'use client'

import { useAuth } from '@melody-auth/react'
import { Table } from 'flowbite-react'
import { useTranslations } from 'next-intl'
import { useParams } from 'next/navigation'
import {
useEffect, useState,
} from 'react'
import { proxyTool } from 'tools'
import PageTitle from 'components/PageTitle'

const Page = () => {
const { id } = useParams()

const t = useTranslations()

const [log, setLog] = useState()
const { acquireToken } = useAuth()

useEffect(
() => {
const getLog = async () => {
const token = await acquireToken()
const data = await proxyTool.sendNextRequest({
endpoint: `/api/logs/email/${id}`,
method: 'GET',
token,
})
setLog(data.log)
}

getLog()
},
[acquireToken, id],
)

if (!log) return null

return (
<section>
<PageTitle
className='mb-6'
title={t('logs.emailLog')}
/>
<section>
<Table>
<Table.Head>
<Table.HeadCell className='max-md:w-24 md:w-48'>{t('common.property')}</Table.HeadCell>
<Table.HeadCell>{t('common.value')}</Table.HeadCell>
</Table.Head>
<Table.Body className='divide-y'>
<Table.Row>
<Table.Cell>{t('logs.receiver')}</Table.Cell>
<Table.Cell>
{log.receiver}
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>{t('logs.response')}</Table.Cell>
<Table.Cell>
{log.response}
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>{t('logs.content')}</Table.Cell>
<Table.Cell>
<div dangerouslySetInnerHTML={{ __html: log.content }} />
</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>{t('common.createdAt')}</Table.Cell>
<Table.Cell>{log.createdAt} UTC</Table.Cell>
</Table.Row>
<Table.Row>
<Table.Cell>{t('common.updatedAt')}</Table.Cell>
<Table.Cell>{log.updatedAt} UTC</Table.Cell>
</Table.Row>
</Table.Body>
</Table>
</section>
</section>
)
}

export default Page
257 changes: 257 additions & 0 deletions admin-panel/app/[lang]/logs/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,257 @@
'use client'

import { useTranslations } from 'next-intl'
import {
Pagination,
Spinner, Table,
} from 'flowbite-react'
import {
useEffect, useMemo, useState,
} from 'react'
import { useAuth } from '@melody-auth/react'
import PageTitle from 'components/PageTitle'
import { configSignal } from 'signals'
import useSignalValue from 'app/useSignalValue'
import { proxyTool } from 'tools'
import ConfigBooleanValue from 'components/ConfigBooleanValue'
import ViewLink from 'components/ViewLink'
import useCurrentLocale from 'hooks/useCurrentLocale'

const PageSize = 10

const Page = () => {
const t = useTranslations()
const locale = useCurrentLocale()

const configs = useSignalValue(configSignal)
const { acquireToken } = useAuth()

const [emailLogs, setEmailLogs] = useState([])
const [emailLogPageNumber, setEmailLogPageNumber] = useState(1)
const [emailLogCount, setEmailLogCount] = useState(0)

const [smsLogs, setSmsLogs] = useState([])
const [smsLogPageNumber, setSmsLogPageNumber] = useState(1)
const [smsLogCount, setSmsLogCount] = useState(0)

const [signInLogs, setSignInLogs] = useState([])
const [signInLogPageNumber, setSignInLogPageNumber] = useState(1)
const [signInLogCount, setSignInLogCount] = useState(0)

const emailLogTotalPages = useMemo(
() => Math.ceil(emailLogCount / PageSize),
[emailLogCount],
)

const smsLogTotalPages = useMemo(
() => Math.ceil(smsLogCount / PageSize),
[smsLogCount],
)

const signInLogTotalPages = useMemo(
() => Math.ceil(signInLogCount / PageSize),
[signInLogCount],
)

useEffect(
() => {
const getEmailLogs = async () => {
const token = await acquireToken()
const baseUrl = `/api/logs/email?page_size=${PageSize}&page_number=${emailLogPageNumber}`
const data = await proxyTool.sendNextRequest({
endpoint: baseUrl,
method: 'GET',
token,
})
setEmailLogs(data.logs)
setEmailLogCount(data.count)
}

getEmailLogs()
},
[acquireToken, emailLogPageNumber],
)

useEffect(
() => {
const getSmsLogs = async () => {
const token = await acquireToken()
const baseUrl = `/api/logs/sms?page_size=${PageSize}&page_number=${smsLogPageNumber}`
const data = await proxyTool.sendNextRequest({
endpoint: baseUrl,
method: 'GET',
token,
})
setSmsLogs(data.logs)
setSmsLogCount(data.count)
}

getSmsLogs()
},
[acquireToken, smsLogPageNumber],
)

useEffect(
() => {
const getSignInLogs = async () => {
const token = await acquireToken()
const baseUrl = `/api/logs/sign-in?page_size=${PageSize}&page_number=${signInLogPageNumber}`
const data = await proxyTool.sendNextRequest({
endpoint: baseUrl,
method: 'GET',
token,
})
setSignInLogs(data.logs)
setSignInLogCount(data.count)
}

getSignInLogs()
},
[acquireToken, signInLogPageNumber],
)

const handleEmailLogPageChange = (page: number) => {
setEmailLogPageNumber(page)
}

const handleSmsLogPageChange = (page: number) => {
setSmsLogPageNumber(page)
}

const handleSignInLogPageChange = (page: number) => {
setSignInLogPageNumber(page)
}

if (!configs) return <Spinner />

return (
<section>
{configs.ENABLE_EMAIL_LOG && (
<>
<PageTitle
className='mt-8 mb-6'
title={t('logs.emailLogs')}
/>
<Table className='break-all'>
<Table.Head>
<Table.HeadCell>{t('logs.receiver')}</Table.HeadCell>
<Table.HeadCell>{t('logs.success')}</Table.HeadCell>
<Table.HeadCell>{t('logs.time')}</Table.HeadCell>
<Table.HeadCell />
</Table.Head>
<Table.Body className='divide-y'>
{emailLogs.map((log) => (
<Table.Row key={log.id}>
<Table.Cell>{log.receiver}</Table.Cell>
<Table.Cell><ConfigBooleanValue config={log.success}/></Table.Cell>
<Table.Cell>{log.createdAt}</Table.Cell>
<Table.Cell>
<ViewLink
href={`/${locale}/logs/email/${log.id}`}
/>
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
{emailLogTotalPages > 1 && (
<Pagination
className='mt-8'
layout='pagination'
currentPage={emailLogPageNumber}
totalPages={emailLogTotalPages}
onPageChange={handleEmailLogPageChange}
previousLabel={t('common.previous')}
nextLabel={t('common.next')}
showIcons
/>
)}
</>
)}
{configs.ENABLE_SMS_LOG && (
<>
<PageTitle
className='mt-8 mb-6'
title={t('logs.smsLogs')}
/>
<Table className='break-all'>
<Table.Head>
<Table.HeadCell>{t('logs.receiver')}</Table.HeadCell>
<Table.HeadCell>{t('logs.success')}</Table.HeadCell>
<Table.HeadCell>{t('logs.time')}</Table.HeadCell>
<Table.HeadCell />
</Table.Head>
<Table.Body className='divide-y'>
{smsLogs.map((log) => (
<Table.Row key={log.id}>
<Table.Cell>{log.receiver}</Table.Cell>
<Table.Cell><ConfigBooleanValue config={log.success}/></Table.Cell>
<Table.Cell>{log.createdAt}</Table.Cell>
<Table.Cell>
<ViewLink
href={`/${locale}/logs/sms/${log.id}`}
/>
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
{smsLogTotalPages > 1 && (
<Pagination
className='mt-8'
layout='pagination'
currentPage={smsLogPageNumber}
totalPages={smsLogTotalPages}
onPageChange={handleSmsLogPageChange}
previousLabel={t('common.previous')}
nextLabel={t('common.next')}
showIcons
/>
)}
</>
)}
{configs.ENABLE_SIGN_IN_LOG && (
<>
<PageTitle
className='mt-8 mb-6'
title={t('logs.signInLogs')}
/>
<Table className='break-all'>
<Table.Head>
<Table.HeadCell>{t('logs.userId')}</Table.HeadCell>
<Table.HeadCell>{t('logs.time')}</Table.HeadCell>
<Table.HeadCell />
</Table.Head>
<Table.Body className='divide-y'>
{signInLogs.map((log) => (
<Table.Row key={log.id}>
<Table.Cell>{log.userId}</Table.Cell>
<Table.Cell>{log.createdAt}</Table.Cell>
<Table.Cell>
<ViewLink
href={`/${locale}/logs/sign-in/${log.id}`}
/>
</Table.Cell>
</Table.Row>
))}
</Table.Body>
</Table>
{signInLogTotalPages > 1 && (
<Pagination
className='mt-8'
layout='pagination'
currentPage={signInLogPageNumber}
totalPages={signInLogTotalPages}
onPageChange={handleSignInLogPageChange}
previousLabel={t('common.previous')}
nextLabel={t('common.next')}
showIcons
/>
)}
</>
)}
</section>
)
}

export default Page
Loading

0 comments on commit a154e50

Please sign in to comment.