update auth charts

This commit is contained in:
Francesco Sansalvadore committed 2025-05-07 13:35:53 +02:00
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>
+393 -66
View File
@@ -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)