feat: add append prop to ReportWidget, add top routes table

This commit is contained in:
TzeYiing committed 2023-05-02 18:31:33 +09:00
1 parent f3722bd9b7
commit a2e72a503e
4 files changed
+125 -16

No files matched your search

@@ -15,14 +15,15 @@ export interface ReportWidgetProps<T = any> {
tooltip?: string
className?: string
renderer: (props: ReportWidgetRendererProps) => React.ReactNode
expandable?: (props: ReportWidgetRendererProps) => React.ReactNode
expandableText?: string
append?: (props: ReportWidgetRendererProps) => React.ReactNode
// for overriding props, such as data
appendProps?: Partial<ReportWidgetRendererProps>
// omitting params will hide the "View in logs explorer" button
params?: BaseReportParams | LogsEndpointParams
isLoading: boolean
}
export interface ReportWidgetRendererProps extends ReportWidgetProps {
export interface ReportWidgetRendererProps<T = any> extends ReportWidgetProps<T> {
router: NextRouter
projectRef: string
}
@@ -99,7 +100,7 @@ const ReportWidget: React.FC<ReportWidgetProps> = (props) => {
</div>
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip.Root>
</Tooltip.Root>
)}
</div>
@@ -107,16 +108,8 @@ const ReportWidget: React.FC<ReportWidgetProps> = (props) => {
{props.data === undefined ? null : props.renderer({ ...props, router, projectRef })}
</LoadingOpacity>
{props.expandable && (
<Collapsible>
<Collapsible.Trigger asChild>
<Button>{props.expandableText || 'Expand'}</Button>
</Collapsible.Trigger>
<Collapsible.Content>
{props.expandable && props.expandable({ ...props, router, projectRef })}
</Collapsible.Content>
</Collapsible>
)}
{props.append &&
props.append({ ...props, ...(props.appendProps || {}), router, projectRef })}
</Panel.Content>
</Panel>
)
@@ -74,6 +74,28 @@ export const PRESET_CONFIG: Record<Presets, PresetConfig> = {
ORDER BY
timestamp ASC`,
},
topRoutes: {
queryType: "logs",
sql: (filters)=> `
select
request.path as path,
request.method as method,
request.search as search,
count(t.id) as count
from edge_logs t
cross join unnest(metadata) as m
cross join unnest(m.response) as response
cross join unnest(m.request) as request
cross join unnest(request.headers) as headers
${generateRexepWhere(filters)}
group by
request.path, request.method, request.search
order by
count desc
limit
5
`
},
errorCounts: {
queryType: 'logs',
sql: (filters) => `
@@ -1,5 +1,12 @@
import { ReportWidgetProps } from '../ReportWidget'
import { ReportWidgetProps, ReportWidgetRendererProps } from '../ReportWidget'
import BarChart from 'components/ui/Charts/BarChart'
import Table from 'components/to-be-cleaned/Table'
import {
jsonSyntaxHighlight,
TextFormatter,
} from 'components/interfaces/Settings/Logs/LogsFormatters'
import { Button, Collapsible, IconChevronRight } from 'ui'
import { queryParamsToObject } from '../Reports.utils'
export const renderTotalRequests = (
props: ReportWidgetProps<{
@@ -24,6 +31,46 @@ export const renderTotalRequests = (
)
}
export const renderTopApiRoutes = (
props: ReportWidgetRendererProps<{
method: string
path: string
search: string
count: number
}>
) => {
const headerClasses = '!text-xs !py-2 p-0 font-bold !bg-scale-400'
const cellClasses = '!text-xs !py-2 truncate'
return (
<>
<Table
head={
<>
<Table.th className={headerClasses}>Request</Table.th>
<Table.th className={headerClasses + ' text-right'}>Count</Table.th>
</>
}
body={
<>
{props.data.map((datum) => (
<>
<Table.tr className="p-0">
<Table.td className={[cellClasses].join(' ')}>
<RouteTdContent {...datum} />
</Table.td>
<Table.td className={[cellClasses, 'text-right align-top'].join(' ')}>
{datum.count}
</Table.td>
</Table.tr>
</>
))}
</>
}
/>
</>
)
}
export const renderErrorCounts = (
props: ReportWidgetProps<{
timestamp: string
@@ -74,3 +121,41 @@ export const renderResponseSpeed = (
/>
)
}
interface RouteTdContentProps {
method: string
path: string
search: string
}
const RouteTdContent = (datum: RouteTdContentProps) => (
<Collapsible>
<Collapsible.Trigger asChild>
<div className="flex gap-2">
<Button type="text" className=" !py-0 !p-1" title="Show more route details">
<IconChevronRight
size={14}
className="transition data-open-parent:rotate-90 data-closed-parent:rotate-0"
/>
</Button>
<TextFormatter className="w-10 h-4 text-center rounded bg-scale-500" value={datum.method} />
<div>
<TextFormatter className="text-scale-1100" value={datum.path} />
<TextFormatter
className="max-w-sm text-scale-900"
value={decodeURIComponent(datum.search || '')}
/>
</div>
</div>
</Collapsible.Trigger>
<Collapsible.Content className="pt-2">
<pre className={`syntax-highlight overflow-auto rounded bg-scale-300 p-2 !text-xs`}>
<div
className="text-wrap"
dangerouslySetInnerHTML={{
__html: jsonSyntaxHighlight(queryParamsToObject(datum.search)),
}}
/>
</pre>
</Collapsible.Content>
</Collapsible>
)
@@ -12,6 +12,7 @@ import {
renderTotalRequests,
renderErrorCounts,
renderResponseSpeed,
renderTopApiRoutes,
} from 'components/interfaces/Reports/renderers/ApiRenderers'
import { useState, useEffect } from 'react'
import ReportHeader from 'components/interfaces/Reports/ReportHeader'
@@ -64,6 +65,8 @@ export const ApiReport: NextPageWithLayout = () => {
title="Total Requests"
data={report.data.totalRequests || []}
renderer={renderTotalRequests}
append={renderTopApiRoutes}
appendProps={{data: report.data.topRoutes || [] }}
/>
<ReportWidget
isLoading={report.isLoading}
@@ -94,9 +97,10 @@ const useApiReport = () => {
projectRef ?? 'default'
)
const totalRequests = queryHooks.totalRequests()
const topRoutes = queryHooks.topRoutes()
const errorCounts = queryHooks.errorCounts()
const responseSpeed = queryHooks.responseSpeed()
const activeHooks = [totalRequests, errorCounts, responseSpeed]
const activeHooks = [totalRequests, topRoutes, errorCounts, responseSpeed]
const [filters, setFilters] = useState<ReportFilterItem[]>([])
const addFilter = (filter: ReportFilterItem) => {
// use a deep equal when comparing objects.
@@ -127,6 +131,9 @@ const useApiReport = () => {
if (totalRequests[1].changeQuery) {
totalRequests[1].changeQuery(PRESET_CONFIG.api.queries.totalRequests.sql(filters))
}
if (topRoutes[1].changeQuery) {
topRoutes[1].changeQuery(PRESET_CONFIG.api.queries.topRoutes.sql(filters))
}
if (errorCounts[1].changeQuery) {
errorCounts[1].changeQuery(PRESET_CONFIG.api.queries.errorCounts.sql(filters))
}
@@ -151,11 +158,13 @@ const useApiReport = () => {
totalRequests: totalRequests[0].logData,
errorCounts: errorCounts[0].logData,
responseSpeed: responseSpeed[0].logData,
topRoutes: topRoutes[0].logData,
},
params: {
totalRequests: totalRequests[0].params,
errorCounts: errorCounts[0].params,
responseSpeed: responseSpeed[0].params,
topRoutes: topRoutes[0].params,
},
mergeParams: handleSetParams,
filters,