Reports clean ups (#37248)

* use similar ui styles for different charts

* fix naming

* use similar styles, fix height

* rm year from tooltip timestamp

* remove unnecessary code in useChartData
This commit is contained in:
Jordi Enric authored and GitHub committed 2025-07-17 16:08:22 +02:00
1 parent 5e15856d13
commit dfacfd5137
9 files changed
+23 -139

No files matched your search

@@ -49,7 +49,6 @@ const ReportChart = ({
const {
data,
isLoading: isLoadingChart,
chartAttributes,
highlightedValue,
} = useChartData({
attributes: chart.attributes,
@@ -72,9 +71,7 @@ const ReportChart = ({
const { data: filledData, isError: isFillError } = useFillTimeseriesSorted(
chartDataArray,
'period_start',
(chartAttributes.length > 0 ? chartAttributes : chart.attributes).map(
(attr: any) => attr.attribute
),
chart.attributes.map((attr: any) => attr.attribute),
0,
startDate,
endDate,
@@ -159,9 +156,7 @@ const ReportChart = ({
return (
<LogChartHandler
{...chart}
attributes={
(chartAttributes.length > 0 ? chartAttributes : chart.attributes) as MultiAttribute[]
}
attributes={chart.attributes as MultiAttribute[]}
data={finalData}
isLoading={isLoadingChart || isLoading}
highlightedValue={highlightedValue as any}
@@ -82,6 +82,6 @@ export const DEFAULT_STACK_COLORS: ValidStackColor[] = [
export enum DateTimeFormats {
FULL = 'MMM D, YYYY, hh:mma',
FULL_SECONDS = 'MMM D, YYYY, hh:mm:ssa',
FULL_SECONDS = 'MMM D, hh:mm:ssa',
DATE_ONLY = 'MMM D, YYYY',
}
@@ -238,7 +238,7 @@ const ComposedChartHandler = ({
return (
<Panel
className={cn(
'flex min-h-[320px] w-full flex-col items-center justify-center gap-y-2',
'flex min-h-[280px] w-full flex-col items-center justify-center gap-y-2',
className
)}
wrapWithLoading={false}
@@ -112,23 +112,6 @@ const LogChartHandler = ({
const [chartStyle, setChartStyle] = useState<string>(defaultChartStyle)
const chartHighlight = useChartHighlight()
if (isLoading) {
return (
<Panel
className={cn(
'flex min-h-[280px] w-full flex-col items-center justify-center gap-y-2',
className
)}
wrapWithLoading={false}
noMargin
noHideOverflow
>
<Loader2 size={18} className="animate-spin text-border-strong" />
<p className="text-xs text-foreground-lighter">Loading data for {label}</p>
</Panel>
)
}
if (!data) {
return (
<div className="flex h-52 w-full flex-col items-center justify-center gap-y-2">
@@ -143,10 +126,16 @@ const LogChartHandler = ({
<Panel
noMargin
noHideOverflow
className={cn('relative w-full scroll-mt-16', className)}
className={cn('relative w-full overflow-hidden scroll-mt-16', className)}
wrapWithLoading={false}
id={id ?? label.toLowerCase().replaceAll(' ', '-')}
>
{isLoading && (
<div className="absolute inset-0 rounded-md flex w-full flex-col items-center justify-center gap-y-2 bg-surface-100 backdrop z-20">
<Loader2 size={18} className="animate-spin text-border-strong" />
<p className="text-xs text-foreground-lighter">Loading data for {label}</p>
</div>
)}
<Panel.Content className="flex flex-col gap-4">
<div className="absolute right-6 z-50 flex justify-between scroll-mt-16">{children}</div>
<ComposedChart
@@ -186,12 +175,8 @@ export const useAttributeQueries = (
data: ChartData | undefined,
isVisible: boolean
) => {
const projectRef = typeof ref === 'string' ? ref : Array.isArray(ref) ? ref[0] : ''
const infraAttributes = attributes.filter((attr) => attr.provider === 'infra-monitoring')
const dailyStatsAttributes = attributes.filter((attr) => attr.provider === 'daily-stats')
const mockAttributes = attributes.filter((attr) => attr.provider === 'mock')
const referenceLineAttributes = attributes.filter((attr) => attr.provider === 'reference-line')
const infraQueries = useInfraMonitoringQueries(
infraAttributes.map((attr) => attr.attribute as InfraMonitoringAttribute),
@@ -307,6 +307,7 @@ export function useAuthLogsReport({
data: rawData,
error,
isLoading,
isFetching,
} = useQuery(
['auth-logs-report', projectRef, logsMetric, startDate, endDate, interval, sql],
async () => {
@@ -339,5 +340,6 @@ export function useAuthLogsReport({
attributes: chartAttributes,
isLoading,
error,
isFetching,
}
}
+4 -97
View File
@@ -11,15 +11,11 @@
import { useMemo } from 'react'
import { useRouter } from 'next/router'
import { useDatabaseSelectorStateSnapshot } from 'state/database-selector'
import type { AnalyticsInterval, DataPoint } from 'data/analytics/constants'
import { useAuthLogsReport } from 'data/reports/auth-report-query'
import type { ChartData } from 'components/ui/Charts/Charts.types'
import type { MultiAttribute } from 'components/ui/Charts/ComposedChart.utils'
import { useAttributeQueries } from 'components/ui/Charts/LogChartHandler'
import { useEdgeFunctionReport } from 'data/reports/edgefn-query'
import { useInfraMonitoringQuery } from 'data/analytics/infra-monitoring-query'
import type { InfraMonitoringAttribute } from 'data/analytics/infra-monitoring-query'
export const useChartData = ({
attributes,
@@ -42,10 +38,8 @@ export const useChartData = ({
}) => {
const router = useRouter()
const { ref } = router.query
const state = useDatabaseSelectorStateSnapshot()
const logsAttributes = attributes.filter((attr) => attr.provider === 'logs')
const nonLogsAttributes = attributes.filter((attr) => attr.provider !== 'logs')
const isEdgeFunctionRoute = router.asPath.includes('/reports/edge-functions')
@@ -76,66 +70,15 @@ export const useChartData = ({
functionIds,
})
const {
data: infraData,
error: infraError,
isLoading: isInfraLoading,
} = useInfraMonitoringQuery(
{
projectRef: ref as string,
attribute: nonLogsAttributes[0]?.attribute as InfraMonitoringAttribute,
interval: interval as AnalyticsInterval,
startDate,
endDate,
databaseIdentifier: state.selectedDatabaseId,
},
{ enabled: enabled && nonLogsAttributes.length > 0 }
)
const logsData = isEdgeFunctionRoute ? edgeFunctionData : authData
const logsChartAttributes = isEdgeFunctionRoute
? edgeFunctionChartAttributes
: authChartAttributes
const isLogsLoading = isEdgeFunctionRoute ? isEdgeFunctionLoading : isAuthLoading
const chartAttributes = useMemo(
() => nonLogsAttributes.concat(logsChartAttributes || []),
[nonLogsAttributes, logsChartAttributes]
)
const databaseIdentifier = state.selectedDatabaseId
// Use the custom hook at the top level of the component
const attributeQueries = useAttributeQueries(
attributes,
ref,
startDate,
endDate,
interval as AnalyticsInterval,
databaseIdentifier,
data,
true
)
// Combine all the data into a single dataset
const combinedData = useMemo(() => {
if (data) return data
const regularAttributeQueries = attributeQueries.filter(
(q) => q.data?.provider !== 'logs' && q.data?.provider !== 'reference-line'
)
const isLoading =
(logsAttributes.length > 0 && isLogsLoading) ||
regularAttributeQueries.some((query: any) => query.isLoading)
if (isLoading) {
return undefined
}
const hasError = regularAttributeQueries.some((query: any) => !query.data)
if (hasError) {
return undefined
}
// Get all unique timestamps from all datasets
const timestamps = new Set<string>()
if (logsData) {
@@ -145,17 +88,6 @@ export const useChartData = ({
}
})
}
regularAttributeQueries.forEach((query: any) => {
query.data?.data?.forEach((point: any) => {
if (point?.period_start) {
timestamps.add(point.period_start)
}
})
})
const referenceLineQueries = attributeQueries.filter(
(q) => q.data?.provider === 'reference-line'
)
// Combine data points for each timestamp
const combined = Array.from(timestamps)
@@ -166,44 +98,20 @@ export const useChartData = ({
const logPoint = logsData?.find((p: any) => p.period_start === timestamp) || {}
Object.assign(point, logPoint)
chartAttributes.forEach((attr) => {
if (!attr) return
if (attr.provider === 'logs') return
if (attr.provider === 'reference-line') return
if (attr.customValue !== undefined) {
point[attr.attribute] = attr.customValue
return
}
const query = regularAttributeQueries.find((q) => q.data?.attribute === attr.attribute)
const matchingPoint = query?.data?.data?.find((p: any) => p.period_start === timestamp)
point[attr.attribute] = matchingPoint?.[attr.attribute] ?? 0
})
// Add reference line values for each timestamp
referenceLineQueries.forEach((query: any) => {
const attr = query.data.attribute
const value = query.data.total
point[attr] = value
})
return point as DataPoint
})
return combined as DataPoint[]
}, [data, attributeQueries, attributes, chartAttributes, isLogsLoading, logsData, logsAttributes])
}, [data, attributes, isLogsLoading, logsData, logsAttributes])
const loading =
(logsAttributes.length > 0 && isLogsLoading) ||
attributeQueries.some((query: any) => query.isLoading)
const loading = logsAttributes.length > 0 && isLogsLoading
// Calculate highlighted value based on the first attribute's data
const _highlightedValue = useMemo(() => {
if (highlightedValue !== undefined) return highlightedValue
const firstAttr = attributes[0]
const firstQuery = attributeQueries[0]
const firstData = firstQuery?.data
const firstData = logsChartAttributes.find((p: any) => p.attribute === firstAttr.attribute)
if (!firstData) return undefined
@@ -222,12 +130,11 @@ export const useChartData = ({
: shouldHighlightTotalGroupedValue
? firstData.totalGrouped?.[firstAttr.attribute as keyof typeof firstData.totalGrouped]
: (firstData.data?.[firstData.data?.length - 1] as any)?.[firstAttr.attribute]
}, [highlightedValue, attributes, attributeQueries])
}, [highlightedValue, attributes])
return {
data: combinedData,
isLoading: loading,
chartAttributes,
highlightedValue: _highlightedValue,
}
}
@@ -82,14 +82,7 @@ const AuthUsage = () => {
setIsRefreshing(true)
AUTH_REPORT_ATTRIBUTES.forEach((attr) => {
attr.attributes.forEach((subAttr) => {
queryClient.invalidateQueries([
'auth-metrics',
ref,
subAttr.attribute,
selectedDateRange.period_start.date,
selectedDateRange.period_end.date,
selectedDateRange.interval,
])
queryClient.invalidateQueries(['auth-logs-report', 'auth-metrics'])
})
})
refetch()
@@ -150,6 +143,7 @@ const AuthUsage = () => {
endDate={selectedDateRange?.period_end?.date}
updateDateRange={updateDateRange}
orgPlanId={orgPlan?.id}
isLoading={isRefreshing}
/>
))}
<div>
@@ -1,5 +1,5 @@
import React from 'react'
import { Loader } from 'lucide-react'
import { Loader2 } from 'lucide-react'
import styleHandler from '../../lib/theme/styleHandler'
@@ -23,7 +23,7 @@ export default function Loading({ children, active }: Props) {
return (
<div className={classNames.join(' ')}>
<div className={contentClasses.join(' ')}>{children}</div>
{active && <Loader size={24} className={spinnerClasses.join(' ')} />}
{active && <Loader2 size={24} className={spinnerClasses.join(' ')} />}
</div>
)
}
+2 -1
View File
@@ -1417,8 +1417,9 @@ export default {
},
spinner: `
absolute
text-brand animate-spin
text-foreground-lighter animate-spin
inset-0
size-5
m-auto
`,
},