mirror of
https://github.com/supabase/supabase.git
synced 2026-10-15 06:09:08 +03:00
update auth charts
This commit is contained in:
1 parent
37187462a4
commit
69205d6a30
5 files changed
+436
-78
No files matched your search
@@ -1,5 +1,5 @@
|
||||
import { Button, Tooltip, TooltipContent, TooltipTrigger } from 'ui'
|
||||
import { Activity, BarChartIcon, GitCommitHorizontalIcon } from 'lucide-react'
|
||||
import { Activity, BarChartIcon, GitCommitHorizontalIcon, InfoIcon } from 'lucide-react'
|
||||
|
||||
export interface ChartHeaderProps {
|
||||
title?: string
|
||||
@@ -14,6 +14,7 @@ export interface ChartHeaderProps {
|
||||
onChartStyleChange?: (style: string) => void
|
||||
showMaxValue?: boolean
|
||||
setShowMaxValue?: (value: boolean) => void
|
||||
titleTooltip?: string
|
||||
}
|
||||
|
||||
const ChartHeader = ({
|
||||
@@ -27,10 +28,24 @@ const ChartHeader = ({
|
||||
onChartStyleChange,
|
||||
showMaxValue = false,
|
||||
setShowMaxValue,
|
||||
titleTooltip,
|
||||
}: ChartHeaderProps) => {
|
||||
const chartTitle = (
|
||||
<h3 className={'text-foreground-lighter ' + (minimalHeader ? 'text-xs' : 'text-sm')}>
|
||||
{title}
|
||||
<h3
|
||||
className={
|
||||
'text-foreground-lighter flex gap-2 flex-wrap items-center' +
|
||||
(minimalHeader ? 'text-xs' : 'text-sm')
|
||||
}
|
||||
>
|
||||
{title}{' '}
|
||||
{titleTooltip && (
|
||||
<Tooltip>
|
||||
<TooltipTrigger>
|
||||
<InfoIcon className="w-3 h-3" />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent>{titleTooltip}</TooltipContent>
|
||||
</Tooltip>
|
||||
)}
|
||||
</h3>
|
||||
)
|
||||
|
||||
@@ -61,7 +76,7 @@ const ChartHeader = ({
|
||||
|
||||
return (
|
||||
<div className="flex-grow flex justify-between items-start min-h-16">
|
||||
<div className="flex flex-col">
|
||||
<div className="flex flex-col min-h-20">
|
||||
{title && chartTitle}
|
||||
{highlightedValue !== undefined && highlighted}
|
||||
{label}
|
||||
|
||||
@@ -32,9 +32,9 @@ import {
|
||||
CustomTooltip,
|
||||
formatBytes,
|
||||
} from './ComposedChart.utils'
|
||||
import { MultiAttribute } from './ComposedChartHandler'
|
||||
import NoDataPlaceholder from './NoDataPlaceholder'
|
||||
import { ChartHighlight } from './useChartHighlight'
|
||||
import NoDataPlaceholder from './NoDataPlaceholder'
|
||||
import { MultiAttribute } from './ComposedChartHandler'
|
||||
|
||||
export interface BarChartProps<D = Datum> extends CommonChartProps<D> {
|
||||
attributes: MultiAttribute[]
|
||||
@@ -56,6 +56,7 @@ export interface BarChartProps<D = Datum> extends CommonChartProps<D> {
|
||||
chartStyle?: string
|
||||
onChartStyleChange?: (style: string) => void
|
||||
updateDateRange: any
|
||||
titleTooltip?: string
|
||||
}
|
||||
|
||||
export default function ComposedChart({
|
||||
@@ -88,6 +89,7 @@ export default function ComposedChart({
|
||||
chartStyle,
|
||||
onChartStyleChange,
|
||||
updateDateRange,
|
||||
titleTooltip,
|
||||
}: BarChartProps) {
|
||||
const { resolvedTheme } = useTheme()
|
||||
const [_activePayload, setActivePayload] = useState<any>(null)
|
||||
@@ -151,10 +153,17 @@ export default function ComposedChart({
|
||||
att.name !== maxAttribute?.attribute &&
|
||||
attributes.some((attr) => attr.attribute === att.name && attr.enabled !== false)
|
||||
)
|
||||
.map((att, index) => ({
|
||||
...att,
|
||||
color: STACKED_CHART_COLORS[index % STACKED_CHART_COLORS.length],
|
||||
}))
|
||||
.map((att, index) => {
|
||||
const attribute = attributes.find((attr) => attr.attribute === att.name)
|
||||
return {
|
||||
...att,
|
||||
color: attribute?.color
|
||||
? resolvedTheme?.includes('dark')
|
||||
? attribute.color.dark
|
||||
: attribute.color.light
|
||||
: STACKED_CHART_COLORS[index % STACKED_CHART_COLORS.length],
|
||||
}
|
||||
})
|
||||
: []
|
||||
|
||||
const lastDataPoint = !!data[data.length - 1]
|
||||
@@ -239,6 +248,7 @@ export default function ComposedChart({
|
||||
onChartStyleChange={onChartStyleChange}
|
||||
showMaxValue={_showMaxValue}
|
||||
setShowMaxValue={maxAttribute ? setShowMaxValue : undefined}
|
||||
titleTooltip={titleTooltip}
|
||||
/>
|
||||
<Container className="relative z-10">
|
||||
<RechartComposedChart
|
||||
|
||||
@@ -203,7 +203,7 @@ const CustomLabel = ({ payload, attributes, showMaxValue, onLabelHover }: Custom
|
||||
<div
|
||||
key={entry.name}
|
||||
className="inline-flex md:flex-col gap-1 md:gap-0 w-fit text-foreground"
|
||||
onMouseEnter={() => handleMouseEnter(entry.name)}
|
||||
onMouseOver={() => handleMouseEnter(entry.name)}
|
||||
onMouseOutCapture={handleMouseLeave}
|
||||
>
|
||||
{!!attribute?.tooltip ? (
|
||||
|
||||
@@ -24,7 +24,6 @@ export type MultiAttribute = {
|
||||
attribute: string
|
||||
provider: Provider
|
||||
label?: string
|
||||
color?: string
|
||||
format?: 'percent' | 'number'
|
||||
description?: string
|
||||
docsLink?: string
|
||||
@@ -33,6 +32,10 @@ export type MultiAttribute = {
|
||||
omitFromTotal?: boolean
|
||||
tooltip?: string
|
||||
enabled?: boolean
|
||||
color?: {
|
||||
light: string
|
||||
dark: string
|
||||
}
|
||||
}
|
||||
|
||||
interface ComposedChartHandlerProps {
|
||||
@@ -57,6 +60,7 @@ interface ComposedChartHandlerProps {
|
||||
updateDateRange: UpdateDateRange
|
||||
valuePrecision?: number
|
||||
isVisible?: boolean
|
||||
titleTooltip?: string
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -126,6 +130,7 @@ const ComposedChartHandler = ({
|
||||
updateDateRange,
|
||||
valuePrecision,
|
||||
isVisible = true,
|
||||
titleTooltip,
|
||||
}: PropsWithChildren<ComposedChartHandlerProps>) => {
|
||||
const router = useRouter()
|
||||
const { ref } = router.query
|
||||
@@ -284,6 +289,7 @@ const ComposedChartHandler = ({
|
||||
updateDateRange={updateDateRange}
|
||||
valuePrecision={valuePrecision}
|
||||
hideChartType={hideChartType}
|
||||
titleTooltip={titleTooltip}
|
||||
/>
|
||||
</Panel.Content>
|
||||
</Panel>
|
||||
|
||||
@@ -2,7 +2,7 @@ export const getAuthReportAttributes = (isFreePlan: boolean) => [
|
||||
// User Authentication Metrics
|
||||
{
|
||||
id: 'signups-by-provider',
|
||||
label: 'Total Sign Ups',
|
||||
label: 'Sign Ups',
|
||||
valuePrecision: 0,
|
||||
hide: false,
|
||||
showTooltip: true,
|
||||
@@ -10,6 +10,7 @@ export const getAuthReportAttributes = (isFreePlan: boolean) => [
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'bar',
|
||||
titleTooltip: 'The total number of sign ups by provider.',
|
||||
attributes: [
|
||||
{ attribute: 'Email', provider: 'mock', label: 'Email', enabled: true },
|
||||
{ attribute: 'Phone', provider: 'mock', label: 'Phone', enabled: false },
|
||||
@@ -36,20 +37,21 @@ export const getAuthReportAttributes = (isFreePlan: boolean) => [
|
||||
],
|
||||
},
|
||||
// Active Users - Only DAU
|
||||
{
|
||||
id: 'active-users',
|
||||
label: 'Active Users',
|
||||
valuePrecision: 0,
|
||||
hide: false,
|
||||
showTooltip: false,
|
||||
showLegend: false,
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'bar',
|
||||
attributes: [
|
||||
{ attribute: 'DAU', provider: 'mock', label: 'Daily Active Users', enabled: true },
|
||||
],
|
||||
},
|
||||
// {
|
||||
// id: 'active-users',
|
||||
// label: 'Active Users',
|
||||
// valuePrecision: 0,
|
||||
// hide: false,
|
||||
// showTooltip: false,
|
||||
// showLegend: false,
|
||||
// showMaxValue: false,
|
||||
// hideChartType: false,
|
||||
// defaultChartStyle: 'bar',
|
||||
// titleTooltip: 'The total number of active users by provider.',
|
||||
// attributes: [
|
||||
// { attribute: 'DAU', provider: 'mock', label: 'Daily Active Users', enabled: true },
|
||||
// ],
|
||||
// },
|
||||
// New vs Returning
|
||||
// {
|
||||
// id: 'user-types',
|
||||
@@ -67,22 +69,109 @@ export const getAuthReportAttributes = (isFreePlan: boolean) => [
|
||||
// ],
|
||||
// },
|
||||
// Authentication Sessions
|
||||
// {
|
||||
// id: 'auth-sessions',
|
||||
// label: 'Auth Sessions',
|
||||
// valuePrecision: 0,
|
||||
// hide: false,
|
||||
// showTooltip: false,
|
||||
// showLegend: false,
|
||||
// showMaxValue: false,
|
||||
// hideChartType: false,
|
||||
// defaultChartStyle: 'bar',
|
||||
// titleTooltip: 'The total number of active users by provider.',
|
||||
// attributes: [
|
||||
// { attribute: 'TotalSessions', provider: 'mock', label: 'Total Active Sessions' },
|
||||
// // { attribute: 'WebSessions', provider: 'mock', label: 'Web Sessions' },
|
||||
// // { attribute: 'MobileSessions', provider: 'mock', label: 'Mobile Sessions' },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
id: 'auth-sessions',
|
||||
label: 'Auth Sessions',
|
||||
label: 'Sessions',
|
||||
valuePrecision: 0,
|
||||
hide: false,
|
||||
showTooltip: false,
|
||||
showLegend: false,
|
||||
showTooltip: true,
|
||||
showLegend: true,
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'bar',
|
||||
titleTooltip: 'The total number of auth sessions by provider.',
|
||||
attributes: [
|
||||
{ attribute: 'TotalSessions', provider: 'mock', label: 'Total Active Sessions' },
|
||||
// { attribute: 'WebSessions', provider: 'mock', label: 'Web Sessions' },
|
||||
// { attribute: 'MobileSessions', provider: 'mock', label: 'Mobile Sessions' },
|
||||
{ attribute: 'EmailSessions', provider: 'mock', label: 'Email', enabled: true },
|
||||
{ attribute: 'PhoneSessions', provider: 'mock', label: 'Phone', enabled: false },
|
||||
{ attribute: 'SAMLSessions', provider: 'mock', label: 'SAML 2.0', enabled: false },
|
||||
{ attribute: 'AppleSessions', provider: 'mock', label: 'Apple', enabled: false },
|
||||
{ attribute: 'AzureSessions', provider: 'mock', label: 'Azure', enabled: false },
|
||||
{ attribute: 'BitbucketSessions', provider: 'mock', label: 'Bitbucket', enabled: false },
|
||||
{ attribute: 'DiscordSessions', provider: 'mock', label: 'Discord', enabled: false },
|
||||
{ attribute: 'FacebookSessions', provider: 'mock', label: 'Facebook', enabled: false },
|
||||
{ attribute: 'FigmaSessions', provider: 'mock', label: 'Figma', enabled: false },
|
||||
{ attribute: 'GitHubSessions', provider: 'mock', label: 'GitHub', enabled: true },
|
||||
{ attribute: 'GitLabSessions', provider: 'mock', label: 'GitLab', enabled: false },
|
||||
{ attribute: 'GoogleSessions', provider: 'mock', label: 'Google', enabled: true },
|
||||
{ attribute: 'KakaoSessions', provider: 'mock', label: 'Kakao', enabled: false },
|
||||
{ attribute: 'KeyCloakSessions', provider: 'mock', label: 'KeyCloak', enabled: false },
|
||||
{ attribute: 'LinkedInSessions', provider: 'mock', label: 'LinkedIn (OIDC)', enabled: false },
|
||||
{ attribute: 'NotionSessions', provider: 'mock', label: 'Notion', enabled: false },
|
||||
{ attribute: 'TwitchSessions', provider: 'mock', label: 'Twitch', enabled: false },
|
||||
{ attribute: 'TwitterSessions', provider: 'mock', label: 'Twitter', enabled: false },
|
||||
{ attribute: 'SlackSessions', provider: 'mock', label: 'Slack (OIDC)', enabled: false },
|
||||
{ attribute: 'SpotifySessions', provider: 'mock', label: 'Spotify', enabled: false },
|
||||
{ attribute: 'WorkOSSessions', provider: 'mock', label: 'WorkOS', enabled: false },
|
||||
{ attribute: 'ZoomSessions', provider: 'mock', label: 'Zoom', enabled: false },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'churn',
|
||||
label: 'Churn',
|
||||
valuePrecision: 0,
|
||||
hide: false,
|
||||
showTooltip: true,
|
||||
showLegend: true,
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'bar',
|
||||
titleTooltip: 'The number of users who have deleted their account.',
|
||||
attributes: [
|
||||
{ attribute: 'EmailChurn', provider: 'mock', label: 'Email', enabled: true },
|
||||
{ attribute: 'PhoneChurn', provider: 'mock', label: 'Phone', enabled: false },
|
||||
{ attribute: 'SAMLChurn', provider: 'mock', label: 'SAML 2.0', enabled: false },
|
||||
{ attribute: 'AppleChurn', provider: 'mock', label: 'Apple', enabled: false },
|
||||
{ attribute: 'AzureChurn', provider: 'mock', label: 'Azure', enabled: false },
|
||||
{ attribute: 'BitbucketChurn', provider: 'mock', label: 'Bitbucket', enabled: false },
|
||||
{ attribute: 'DiscordChurn', provider: 'mock', label: 'Discord', enabled: false },
|
||||
{ attribute: 'FacebookChurn', provider: 'mock', label: 'Facebook', enabled: false },
|
||||
{ attribute: 'FigmaChurn', provider: 'mock', label: 'Figma', enabled: false },
|
||||
{ attribute: 'GitHubChurn', provider: 'mock', label: 'GitHub', enabled: true },
|
||||
{ attribute: 'GitLabChurn', provider: 'mock', label: 'GitLab', enabled: false },
|
||||
{ attribute: 'GoogleChurn', provider: 'mock', label: 'Google', enabled: true },
|
||||
{ attribute: 'KakaoChurn', provider: 'mock', label: 'Kakao', enabled: false },
|
||||
{ attribute: 'KeyCloakChurn', provider: 'mock', label: 'KeyCloak', enabled: false },
|
||||
{ attribute: 'LinkedInChurn', provider: 'mock', label: 'LinkedIn (OIDC)', enabled: false },
|
||||
{ attribute: 'NotionChurn', provider: 'mock', label: 'Notion', enabled: false },
|
||||
{ attribute: 'TwitchChurn', provider: 'mock', label: 'Twitch', enabled: false },
|
||||
{ attribute: 'TwitterChurn', provider: 'mock', label: 'Twitter', enabled: false },
|
||||
{ attribute: 'SlackChurn', provider: 'mock', label: 'Slack (OIDC)', enabled: false },
|
||||
{ attribute: 'SpotifyChurn', provider: 'mock', label: 'Spotify', enabled: false },
|
||||
{ attribute: 'WorkOSChurn', provider: 'mock', label: 'WorkOS', enabled: false },
|
||||
{ attribute: 'ZoomChurn', provider: 'mock', label: 'Zoom', enabled: false },
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'churn-rate',
|
||||
label: 'Churn Rate',
|
||||
valuePrecision: 1,
|
||||
hide: false,
|
||||
showTooltip: true,
|
||||
showLegend: true,
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'bar',
|
||||
format: '%',
|
||||
titleTooltip: 'The percentage of users who have deleted their account.',
|
||||
attributes: [{ attribute: 'ChurnRate', provider: 'mock', label: 'Churn Rate', enabled: true }],
|
||||
},
|
||||
// Session Duration
|
||||
// {
|
||||
// id: 'session-duration',
|
||||
@@ -111,6 +200,7 @@ export const getAuthReportAttributes = (isFreePlan: boolean) => [
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'bar',
|
||||
titleTooltip: 'The total number of password resets.',
|
||||
attributes: [
|
||||
{ attribute: 'PasswordResetRequests', provider: 'mock', label: 'Reset Requests' },
|
||||
{ attribute: 'PasswordResetCompleted', provider: 'mock', label: 'Completed Resets' },
|
||||
@@ -191,11 +281,44 @@ export const getAuthReportAttributes = (isFreePlan: boolean) => [
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'bar',
|
||||
titleTooltip: 'The total number of auth errors.',
|
||||
attributes: [
|
||||
{ attribute: 'Status403', provider: 'mock', label: '403 Forbidden' },
|
||||
{ attribute: 'Status422', provider: 'mock', label: '422 Unprocessable Entity' },
|
||||
{ attribute: 'Status429', provider: 'mock', label: '429 Too Many Requests' },
|
||||
{ attribute: 'Status500', provider: 'mock', label: '500 Internal Server Error' },
|
||||
{
|
||||
attribute: 'Status403',
|
||||
provider: 'mock',
|
||||
label: '403 Forbidden',
|
||||
color: {
|
||||
light: '#FFB74D', // Orange 300
|
||||
dark: '#FFCC80', // Orange 200
|
||||
},
|
||||
},
|
||||
{
|
||||
attribute: 'Status422',
|
||||
provider: 'mock',
|
||||
label: '422 Unprocessable Entity',
|
||||
color: {
|
||||
light: '#FF9800', // Orange 500
|
||||
dark: '#FFB74D', // Orange 300
|
||||
},
|
||||
},
|
||||
{
|
||||
attribute: 'Status429',
|
||||
provider: 'mock',
|
||||
label: '429 Too Many Requests',
|
||||
color: {
|
||||
light: '#E65100', // Orange 900
|
||||
dark: '#F57C00', // Orange 700
|
||||
},
|
||||
},
|
||||
{
|
||||
attribute: 'Status500',
|
||||
provider: 'mock',
|
||||
label: '500 Internal Server Error',
|
||||
color: {
|
||||
light: '#B71C1C', // Red 900
|
||||
dark: '#D32F2F', // Red 700
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// Error Rate by Provider
|
||||
@@ -216,27 +339,6 @@ export const getAuthReportAttributes = (isFreePlan: boolean) => [
|
||||
// { attribute: 'FacebookErrorRate', provider: 'mock', label: 'Facebook' },
|
||||
// ],
|
||||
// },
|
||||
// Rate Limiting
|
||||
{
|
||||
id: 'rate-limiting',
|
||||
label: 'Rate Limiting Events',
|
||||
valuePrecision: 0,
|
||||
hide: false,
|
||||
showTooltip: true,
|
||||
showLegend: true,
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'bar',
|
||||
attributes: [
|
||||
{ attribute: 'IPRateLimited', provider: 'mock', label: 'IP Address Rate Limited' },
|
||||
{ attribute: 'UserRateLimited', provider: 'mock', label: 'User Account Rate Limited' },
|
||||
{
|
||||
attribute: 'BruteForceAttempts',
|
||||
provider: 'mock',
|
||||
label: 'Potential Brute Force Attempts',
|
||||
},
|
||||
],
|
||||
},
|
||||
// API Latency
|
||||
{
|
||||
id: 'auth-latency',
|
||||
@@ -248,12 +350,35 @@ export const getAuthReportAttributes = (isFreePlan: boolean) => [
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'bar',
|
||||
titleTooltip: 'The average latency of auth API requests.',
|
||||
attributes: [
|
||||
{ attribute: 'SignInLatency', provider: 'mock', label: 'Sign In' },
|
||||
{ attribute: 'SignUpLatency', provider: 'mock', label: 'Sign Up' },
|
||||
{ attribute: 'TokenRefreshLatency', provider: 'mock', label: 'Token Refresh' },
|
||||
],
|
||||
},
|
||||
// Rate Limiting
|
||||
{
|
||||
id: 'rate-limiting',
|
||||
label: 'Rate Limiting Events',
|
||||
valuePrecision: 0,
|
||||
hide: false,
|
||||
showTooltip: true,
|
||||
showLegend: true,
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'bar',
|
||||
titleTooltip: 'The total number of rate limiting events.',
|
||||
attributes: [
|
||||
{ attribute: 'IPRateLimited', provider: 'mock', label: 'IP Address Rate Limited' },
|
||||
{ attribute: 'UserRateLimited', provider: 'mock', label: 'User Account Rate Limited' },
|
||||
{
|
||||
attribute: 'BruteForceAttempts',
|
||||
provider: 'mock',
|
||||
label: 'Potential Brute Force Attempts',
|
||||
},
|
||||
],
|
||||
},
|
||||
// Security Events
|
||||
// {
|
||||
// id: 'security-events',
|
||||
@@ -276,22 +401,23 @@ export const getAuthReportAttributes = (isFreePlan: boolean) => [
|
||||
// ],
|
||||
// },
|
||||
// Token Usage
|
||||
// {
|
||||
// id: 'token-usage',
|
||||
// label: 'Token Activity',
|
||||
// valuePrecision: 0,
|
||||
// hide: false,
|
||||
// showTooltip: true,
|
||||
// showLegend: true,
|
||||
// showMaxValue: false,
|
||||
// hideChartType: false,
|
||||
// defaultChartStyle: 'bar',
|
||||
// attributes: [
|
||||
// { attribute: 'TokenIssuance', provider: 'mock', label: 'Tokens Issued' },
|
||||
// { attribute: 'TokenRefresh', provider: 'mock', label: 'Token Refreshes' },
|
||||
// { attribute: 'TokenRevocation', provider: 'mock', label: 'Token Revocations' },
|
||||
// ],
|
||||
// },
|
||||
{
|
||||
id: 'token-usage',
|
||||
label: 'Token Activity',
|
||||
valuePrecision: 0,
|
||||
hide: false,
|
||||
showTooltip: true,
|
||||
showLegend: true,
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'bar',
|
||||
titleTooltip: 'The total number of token activity.',
|
||||
attributes: [
|
||||
{ attribute: 'TokenIssuance', provider: 'mock', label: 'Tokens Issued' },
|
||||
{ attribute: 'TokenRefresh', provider: 'mock', label: 'Token Refreshes' },
|
||||
{ attribute: 'TokenRevocation', provider: 'mock', label: 'Token Revocations' },
|
||||
],
|
||||
},
|
||||
|
||||
// Conversion Metrics
|
||||
// Auth Conversion Funnel
|
||||
@@ -443,6 +569,109 @@ export const getAuthRequestsMockData = (provider: string) => {
|
||||
}
|
||||
}
|
||||
|
||||
// Add new mock data generator for provider-specific sessions
|
||||
export const getProviderSessionsMockData = (provider: string) => {
|
||||
let values: number[] = []
|
||||
|
||||
// Generate higher base values for sessions compared to signups
|
||||
if (provider === 'EmailSessions') {
|
||||
values = generatePatternedValues(DEFAULT_TIME_POINTS.length, 15, 8, 0.1, 2)
|
||||
} else if (provider === 'GoogleSessions') {
|
||||
values = generatePatternedValues(DEFAULT_TIME_POINTS.length, 12, 6, 0.1, 2.5)
|
||||
} else if (provider === 'GitHubSessions') {
|
||||
values = generatePatternedValues(DEFAULT_TIME_POINTS.length, 10, 5, 0.1, 2.2)
|
||||
} else {
|
||||
// For other providers, generate lower values
|
||||
values = generatePatternedValues(DEFAULT_TIME_POINTS.length, 5, 3, 0.1, 2)
|
||||
}
|
||||
|
||||
const data = DEFAULT_TIME_POINTS.map((time, index) => ({
|
||||
period_start: time,
|
||||
[provider]: values[index],
|
||||
}))
|
||||
|
||||
const total = values.reduce((sum, val) => sum + val, 0)
|
||||
const totalAverage = total / values.length
|
||||
|
||||
return {
|
||||
data,
|
||||
yAxisLimit: Math.max(...values) * 1.2,
|
||||
format: '',
|
||||
totalAverage: parseFloat(totalAverage.toFixed(2)),
|
||||
total,
|
||||
}
|
||||
}
|
||||
|
||||
// Add new mock data generator for provider-specific churn rates
|
||||
export const getProviderChurnMockData = (provider: string) => {
|
||||
let values: number[] = []
|
||||
|
||||
// Generate realistic churn rates (typically between 2-15%)
|
||||
if (provider === 'EmailChurn') {
|
||||
// Email typically has higher churn
|
||||
values = generatePatternedValues(DEFAULT_TIME_POINTS.length, 2, 10, 0.1, 5.2).map((v) =>
|
||||
Math.min(v, 20)
|
||||
)
|
||||
} else if (provider === 'GoogleChurn') {
|
||||
// Google typically has lower churn due to account persistence
|
||||
values = generatePatternedValues(DEFAULT_TIME_POINTS.length, 8, 2, 0.1, 1.3).map((v) =>
|
||||
Math.min(v, 15)
|
||||
)
|
||||
} else if (provider === 'GitHubChurn') {
|
||||
// GitHub has moderate churn
|
||||
values = generatePatternedValues(DEFAULT_TIME_POINTS.length, 10, 2.5, 0.1, 1.2).map((v) =>
|
||||
Math.min(v, 18)
|
||||
)
|
||||
} else {
|
||||
// Other providers have varying churn rates
|
||||
values = generatePatternedValues(DEFAULT_TIME_POINTS.length, 9, 3, 0.1, 1.4).map((v) =>
|
||||
Math.min(v, 20)
|
||||
)
|
||||
}
|
||||
|
||||
const data = DEFAULT_TIME_POINTS.map((time, index) => ({
|
||||
period_start: time,
|
||||
[provider]: values[index],
|
||||
}))
|
||||
|
||||
const total = values.reduce((sum, val) => sum + val, 0)
|
||||
const totalAverage = total / values.length
|
||||
|
||||
return {
|
||||
data,
|
||||
yAxisLimit: 20, // Max 20% churn rate
|
||||
format: '%',
|
||||
totalAverage: parseFloat(totalAverage.toFixed(1)),
|
||||
total,
|
||||
}
|
||||
}
|
||||
|
||||
// Add new mock data generator for churn rates
|
||||
export const getChurnRateMockData = (attribute: string) => {
|
||||
let values: number[] = []
|
||||
|
||||
// Overall churn rate with some variance
|
||||
values = generatePatternedValues(DEFAULT_TIME_POINTS.length, 0.6, 2, 0.15, 2.6)
|
||||
.map((v) => Math.max(0, v - 0.25)) // Allow some values to go to 0
|
||||
.map((v) => Math.min(v, 3.2))
|
||||
|
||||
const data = DEFAULT_TIME_POINTS.map((time, index) => ({
|
||||
period_start: time,
|
||||
[attribute]: values[index],
|
||||
}))
|
||||
|
||||
const total = values.reduce((sum, val) => sum + val, 0)
|
||||
const totalAverage = total / values.length
|
||||
|
||||
return {
|
||||
data,
|
||||
yAxisLimit: 1.5, // Max 1.5% churn rate
|
||||
format: '%',
|
||||
totalAverage: parseFloat(totalAverage.toFixed(1)),
|
||||
total,
|
||||
}
|
||||
}
|
||||
|
||||
// Mock data generators for new charts
|
||||
export const getActiveUsersMockData = (metric: string) => {
|
||||
const length = DEFAULT_TIME_POINTS.length
|
||||
@@ -744,11 +973,44 @@ export const getErrorSecurityChartAttributes = () => [
|
||||
showMaxValue: false,
|
||||
hideChartType: false,
|
||||
defaultChartStyle: 'bar',
|
||||
titleTooltip: 'The total number of auth errors.',
|
||||
attributes: [
|
||||
{ attribute: 'Status403', provider: 'mock', label: '403 Forbidden' },
|
||||
{ attribute: 'Status422', provider: 'mock', label: '422 Unprocessable Entity' },
|
||||
{ attribute: 'Status429', provider: 'mock', label: '429 Too Many Requests' },
|
||||
{ attribute: 'Status500', provider: 'mock', label: '500 Internal Server Error' },
|
||||
{
|
||||
attribute: 'Status403',
|
||||
provider: 'mock',
|
||||
label: '403 Forbidden',
|
||||
color: {
|
||||
light: '#FFB74D', // Orange 300
|
||||
dark: '#FFCC80', // Orange 200
|
||||
},
|
||||
},
|
||||
{
|
||||
attribute: 'Status422',
|
||||
provider: 'mock',
|
||||
label: '422 Unprocessable Entity',
|
||||
color: {
|
||||
light: '#FF9800', // Orange 500
|
||||
dark: '#FFB74D', // Orange 300
|
||||
},
|
||||
},
|
||||
{
|
||||
attribute: 'Status429',
|
||||
provider: 'mock',
|
||||
label: '429 Too Many Requests',
|
||||
color: {
|
||||
light: '#E65100', // Orange 900
|
||||
dark: '#F57C00', // Orange 700
|
||||
},
|
||||
},
|
||||
{
|
||||
attribute: 'Status500',
|
||||
provider: 'mock',
|
||||
label: '500 Internal Server Error',
|
||||
color: {
|
||||
light: '#B71C1C', // Red 900
|
||||
dark: '#D32F2F', // Red 700
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
// Error Rate by Provider
|
||||
@@ -1271,6 +1533,71 @@ export const getMockDataForAttribute = (attribute: string) => {
|
||||
return getAuthRequestsMockData(attribute)
|
||||
}
|
||||
|
||||
// Provider-specific sessions
|
||||
if (
|
||||
[
|
||||
'EmailSessions',
|
||||
'PhoneSessions',
|
||||
'SAMLSessions',
|
||||
'AppleSessions',
|
||||
'AzureSessions',
|
||||
'BitbucketSessions',
|
||||
'DiscordSessions',
|
||||
'FacebookSessions',
|
||||
'FigmaSessions',
|
||||
'GitHubSessions',
|
||||
'GitLabSessions',
|
||||
'GoogleSessions',
|
||||
'KakaoSessions',
|
||||
'KeyCloakSessions',
|
||||
'LinkedInSessions',
|
||||
'NotionSessions',
|
||||
'TwitchSessions',
|
||||
'TwitterSessions',
|
||||
'SlackSessions',
|
||||
'SpotifySessions',
|
||||
'WorkOSSessions',
|
||||
'ZoomSessions',
|
||||
].includes(attribute)
|
||||
) {
|
||||
return getProviderSessionsMockData(attribute)
|
||||
}
|
||||
|
||||
// Provider-specific churn
|
||||
if (
|
||||
[
|
||||
'EmailChurn',
|
||||
'PhoneChurn',
|
||||
'SAMLChurn',
|
||||
'AppleChurn',
|
||||
'AzureChurn',
|
||||
'BitbucketChurn',
|
||||
'DiscordChurn',
|
||||
'FacebookChurn',
|
||||
'FigmaChurn',
|
||||
'GitHubChurn',
|
||||
'GitLabChurn',
|
||||
'GoogleChurn',
|
||||
'KakaoChurn',
|
||||
'KeyCloakChurn',
|
||||
'LinkedInChurn',
|
||||
'NotionChurn',
|
||||
'TwitchChurn',
|
||||
'TwitterChurn',
|
||||
'SlackChurn',
|
||||
'SpotifyChurn',
|
||||
'WorkOSChurn',
|
||||
'ZoomChurn',
|
||||
].includes(attribute)
|
||||
) {
|
||||
return getProviderChurnMockData(attribute)
|
||||
}
|
||||
|
||||
// Overall churn rate
|
||||
if (attribute === 'ChurnRate') {
|
||||
return getChurnRateMockData(attribute)
|
||||
}
|
||||
|
||||
// Active Users charts
|
||||
if (['DAU', 'WAU', 'MAU'].includes(attribute)) {
|
||||
return getActiveUsersMockData(attribute)
|
||||
|
||||
Reference in new issue
Block a user