diff --git a/.gitignore b/.gitignore index 7eafe5c..7a1c2ec 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,4 @@ .tmp .tb_error* tinybird/fixtures - +tinybird/tests diff --git a/apps/web/package-lock.json b/apps/web/package-lock.json index 873f939..adc74a9 100644 --- a/apps/web/package-lock.json +++ b/apps/web/package-lock.json @@ -20,6 +20,7 @@ "@radix-ui/react-separator": "^1.1.1", "@radix-ui/react-slot": "^1.1.1", "@radix-ui/react-tooltip": "^1.1.6", + "@tinybirdco/charts": "^0.2.4", "ai": "^4.0.22", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", @@ -1531,6 +1532,20 @@ "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20" } }, + "node_modules/@tinybirdco/charts": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@tinybirdco/charts/-/charts-0.2.4.tgz", + "integrity": "sha512-0N8fYPY8uxO5KcBkW5Dgmapj4AqcWgyCmWnZBYsugXnnbx4/yg//f3/9oMWnM3RZ6ltt9moltYIzF/95NO2zNg==", + "license": "MIT", + "dependencies": { + "echarts": "^5.5.0", + "swr": "^2.2.5" + }, + "peerDependencies": { + "react": "^18.0.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/@types/d3-array": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.1.tgz", @@ -3087,6 +3102,22 @@ "dev": true, "license": "MIT" }, + "node_modules/echarts": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.6.0.tgz", + "integrity": "sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.6.1" + } + }, + "node_modules/echarts/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -8382,6 +8413,21 @@ "zod": "^3.24.1" } }, + "node_modules/zrender": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.6.1.tgz", + "integrity": "sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==", + "license": "BSD-3-Clause", + "dependencies": { + "tslib": "2.3.0" + } + }, + "node_modules/zrender/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", + "license": "0BSD" + }, "node_modules/zwitch": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", diff --git a/apps/web/package.json b/apps/web/package.json index 8095457..f0aae56 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -22,6 +22,7 @@ "@radix-ui/react-separator": "^1.1.1", "@radix-ui/react-slot": "^1.1.1", "@radix-ui/react-tooltip": "^1.1.6", + "@tinybirdco/charts": "^0.2.4", "ai": "^4.0.22", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/apps/web/pnpm-lock.yaml b/apps/web/pnpm-lock.yaml index 1538433..1f83d91 100644 --- a/apps/web/pnpm-lock.yaml +++ b/apps/web/pnpm-lock.yaml @@ -44,6 +44,9 @@ importers: '@radix-ui/react-tooltip': specifier: ^1.1.6 version: 1.1.6(@types/react-dom@19.0.2(@types/react@19.0.2))(@types/react@19.0.2)(react-dom@19.0.0(react@19.0.0))(react@19.0.0) + '@tinybirdco/charts': + specifier: ^0.2.4 + version: 0.2.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0) ai: specifier: ^4.0.22 version: 4.0.22(react@19.0.0)(zod@3.24.1) @@ -837,6 +840,12 @@ packages: peerDependencies: tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20' + '@tinybirdco/charts@0.2.4': + resolution: {integrity: sha512-0N8fYPY8uxO5KcBkW5Dgmapj4AqcWgyCmWnZBYsugXnnbx4/yg//f3/9oMWnM3RZ6ltt9moltYIzF/95NO2zNg==} + peerDependencies: + react: ^18.0.0 + react-dom: '>=16.6.0' + '@types/d3-array@3.2.1': resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} @@ -1330,6 +1339,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + echarts@5.6.0: + resolution: {integrity: sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -2583,6 +2595,9 @@ packages: tsconfig-paths@3.15.0: resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + tslib@2.3.0: + resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -2726,6 +2741,9 @@ packages: zod@3.24.1: resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} + zrender@5.6.1: + resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==} + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -3376,6 +3394,13 @@ snapshots: postcss-selector-parser: 6.0.10 tailwindcss: 3.4.17 + '@tinybirdco/charts@0.2.4(react-dom@19.0.0(react@19.0.0))(react@19.0.0)': + dependencies: + echarts: 5.6.0 + react: 19.0.0 + react-dom: 19.0.0(react@19.0.0) + swr: 2.3.0(react@19.0.0) + '@types/d3-array@3.2.1': {} '@types/d3-color@3.1.3': {} @@ -3901,6 +3926,11 @@ snapshots: eastasianwidth@0.2.0: {} + echarts@5.6.0: + dependencies: + tslib: 2.3.0 + zrender: 5.6.1 + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -5545,6 +5575,8 @@ snapshots: minimist: 1.2.8 strip-bom: 3.0.0 + tslib@2.3.0: {} + tslib@2.8.1: {} type-check@0.4.0: @@ -5748,4 +5780,8 @@ snapshots: zod@3.24.1: {} + zrender@5.6.1: + dependencies: + tslib: 2.3.0 + zwitch@2.0.4: {} diff --git a/apps/web/src/components/tools/auth0/auth-mech-chart.tsx b/apps/web/src/components/tools/auth0/auth-mech-chart.tsx index 7205b8a..4d9e653 100644 --- a/apps/web/src/components/tools/auth0/auth-mech-chart.tsx +++ b/apps/web/src/components/tools/auth0/auth-mech-chart.tsx @@ -1,88 +1,36 @@ -"use client" +'use client' -import { - Card, - CardContent, - CardHeader, - CardTitle, -} from "@/components/ui/card" -import { - ChartContainer, - ChartTooltip, - ChartConfig, - ChartTooltipContent -} from "@/components/ui/chart" -import { Bar, BarChart, XAxis, YAxis } from "recharts" +import { BarList } from '@tinybirdco/charts' -export interface AuthMechDataPoint { - mech: string - logins: number -} - -export interface AuthMechChartData { - data: AuthMechDataPoint[] - className?: string -} - -const chartConfig = { - logins: { - color: "hsl(var(--chart-1))", - label: "Logins", - }, -} satisfies ChartConfig - -function transformData(data: AuthMechDataPoint[]): (AuthMechDataPoint & { fill: string })[] { - return data.map((item, index) => ({ - ...item, - fill: `hsl(var(--chart-${(index % 12) + 1}))` - })); -} - -export function AuthMechChart({ data, className }: AuthMechChartData) { - const sortedData = transformData([...data].sort((a, b) => b.logins - a.logins)) - - return ( - - - Authentication Methods - - - - - - - } - cursor={{ fill: "hsl(var(--muted))", opacity: 0.2 }} - /> - - - - - - ) -} +export function Auth0TopAuth(params: { + client_id?: string + connection_id?: string + tenant_name?: string + token?: string + date_from?: string + date_to?: string +}) { + return ( + {label} + ) + }} + options={{ + tooltip: { + backgroundColor: '#fff', + textStyle: { + color: '#333' + } + } + }} + /> +} \ No newline at end of file diff --git a/apps/web/src/components/tools/auth0/cumulative-signups-chart.tsx b/apps/web/src/components/tools/auth0/cumulative-signups-chart.tsx index 1d99cc7..715c0f3 100644 --- a/apps/web/src/components/tools/auth0/cumulative-signups-chart.tsx +++ b/apps/web/src/components/tools/auth0/cumulative-signups-chart.tsx @@ -1,73 +1,23 @@ -import { BarChart, Bar, XAxis, YAxis } from 'recharts' -import { ChartContainer, ChartTooltip, ChartConfig, ChartTooltipContent } from '@/components/ui/chart' +'use client' -interface SignupData { - day: string - new_users: number - cumulative_users: number -} +import { BarChart } from '@tinybirdco/charts' -interface CumulativeSignupsChartProps { - data: SignupData[] - isLoading: boolean - className?: string -} - -const chartConfig = { - cumulative_users: { - color: "hsl(var(--chart-1))", - label: "Total Users", - }, - new_users: { - color: "hsl(var(--chart-2))", - label: "New Users", - }, -} satisfies ChartConfig - -export function CumulativeSignupsChart({ data, isLoading, className }: CumulativeSignupsChartProps) { - if (isLoading) return
Loading...
- if (!data.length) return
No data available
- - return ( - - - - - } - cursor={{ fill: "hsl(var(--muted))", opacity: 0.2 }} - /> - - - - - ) -} \ No newline at end of file +export function Auth0CumulativeSignups(params: { + client_id?: string + connection_id?: string + tenant_name?: string + token?: string + date_from?: string + date_to?: string +}) { + return +} \ No newline at end of file diff --git a/apps/web/src/components/tools/auth0/daily-login-fails-chart.tsx b/apps/web/src/components/tools/auth0/daily-login-fails-chart.tsx index 964e4a2..60c2c08 100644 --- a/apps/web/src/components/tools/auth0/daily-login-fails-chart.tsx +++ b/apps/web/src/components/tools/auth0/daily-login-fails-chart.tsx @@ -1,106 +1,23 @@ "use client" -import { - Card, - CardContent, - CardHeader, - CardTitle, -} from "@/components/ui/card" -import { - ChartContainer, - ChartConfig, - ChartTooltip, - ChartTooltipContent -} from "@/components/ui/chart" -import { Line, LineChart, XAxis, YAxis, CartesianGrid } from "recharts" -import { format } from "date-fns" +import { AreaChart } from '@tinybirdco/charts' -export interface DailyLoginFailsDataPoint { - day: string - fails: number -} - -export interface DailyLoginFailsChartData { - data: DailyLoginFailsDataPoint[] - timeRange: 'hourly' | 'daily' | 'monthly' - className?: string -} - -const chartConfig = { - fails: { - color: "hsl(var(--chart-1))", - label: "Login Fails", - }, -} satisfies ChartConfig - -export function DailyLoginFailsChart({ data, timeRange, className }: DailyLoginFailsChartData) { - return ( - - - Login Failures - - - - - - { - const date = new Date(value) - return timeRange === 'monthly' - ? format(date, 'MMM yyyy') - : value.split('-')[2] - }} - label={{ - value: timeRange === 'monthly' ? "Month of Year" : "Day of Month", - position: "bottom", - offset: 20 - }} - /> - - } - /> - - - - - - ) -} +export function Auth0DailyLoginFails(params: { + client_id?: string + connection_id?: string + tenant_name?: string + token?: string + date_from?: string + date_to?: string + time_range?: string +}) { + return +} \ No newline at end of file diff --git a/apps/web/src/components/tools/auth0/daily-signups-chart.tsx b/apps/web/src/components/tools/auth0/daily-signups-chart.tsx index f006342..80527ec 100644 --- a/apps/web/src/components/tools/auth0/daily-signups-chart.tsx +++ b/apps/web/src/components/tools/auth0/daily-signups-chart.tsx @@ -1,106 +1,23 @@ "use client" -import { - Card, - CardContent, - CardHeader, - CardTitle, -} from "@/components/ui/card" -import { - ChartContainer, - ChartTooltip, - ChartConfig, - ChartTooltipContent -} from "@/components/ui/chart" -import { Line, LineChart, XAxis, YAxis, CartesianGrid } from "recharts" -import { format } from "date-fns" +import { AreaChart } from '@tinybirdco/charts' -export interface DailySignupsDataPoint { - day: string - signups: number -} - -export interface DailySignupsChartData { - data: DailySignupsDataPoint[] - timeRange: 'hourly' | 'daily' | 'monthly' - className?: string -} - -const chartConfig = { - signups: { - color: "hsl(var(--chart-1))", - label: "Signups", - }, -} satisfies ChartConfig - -export function DailySignupsChart({ data, timeRange, className }: DailySignupsChartData) { - return ( - - - Signups - - - - - - { - const date = new Date(value) - return timeRange === 'monthly' - ? format(date, 'MMM yyyy') - : value.split('-')[2] - }} - label={{ - value: timeRange === 'monthly' ? "Month of Year" : "Day of Month", - position: "bottom", - offset: 20 - }} - /> - - } - /> - - - - - - ) -} +export function Auth0DailySignups(params: { + client_id?: string + connection_id?: string + tenant_name?: string + token?: string + date_from?: string + date_to?: string + time_range?: string +}) { + return +} \ No newline at end of file diff --git a/apps/web/src/components/tools/auth0/dashboard.tsx b/apps/web/src/components/tools/auth0/dashboard.tsx index 0c00358..0464eab 100644 --- a/apps/web/src/components/tools/auth0/dashboard.tsx +++ b/apps/web/src/components/tools/auth0/dashboard.tsx @@ -4,10 +4,12 @@ import { useQueryState } from 'nuqs' import { useEffect, useState, useCallback } from 'react' import { pipe } from '@/lib/tinybird' import MetricCard from '@/components/metric-card' -import { DauChart, DauDataPoint } from './dau-chart' -import { AuthMechChart, AuthMechDataPoint } from './auth-mech-chart' -import { DailySignupsChart, DailySignupsDataPoint } from './daily-signups-chart' -import { DailyLoginFailsChart, DailyLoginFailsDataPoint } from './daily-login-fails-chart' +import { Auth0Dau } from './dau-chart' +import { Auth0TopAuth } from './auth-mech-chart' +import { Auth0TopBrowsers } from './top-browsers-chart' +import { Auth0TopDevices } from './top-devices-chart' +import { Auth0DailySignups } from './daily-signups-chart' +import { Auth0DailyLoginFails } from './daily-login-fails-chart' import { DateRangePicker, DateRange } from '@/components/ui/date-range-picker' import { startOfDay, endOfDay, format } from 'date-fns' import { @@ -20,18 +22,16 @@ import { import { Separator } from "@/components/ui/separator" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { Button } from "@/components/ui/button" -import { UserRetentionChart, UserRetentionDataPoint } from './user-retention-chart' +import { Auth0UserRetention } from './user-retention-chart' import { LogsTable } from './logs-table' -import { TopBrowsersChart } from './top-browsers-chart' -import { TopDevicesChart } from './top-devices-chart' -import { TopDomainsChart } from './top-domains-chart' +import { Auth0TopDomains } from './top-domains-chart' import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible" import { ChevronDown, ChevronUp } from "lucide-react" -import { CumulativeSignupsChart } from './cumulative-signups-chart' +import { Auth0CumulativeSignups } from './cumulative-signups-chart' interface SummaryMetrics { total_users: number @@ -55,7 +55,7 @@ interface LogEntry { export default function Auth0Dashboard() { const [token] = useQueryState('token') const [dateRange, setDateRange] = useState({ - from: startOfDay(new Date(new Date().setDate(new Date().getDate() - 7))), + from: startOfDay(new Date(new Date().setDate(new Date().getDate() - 30))), to: endOfDay(new Date()) }) const [summaryMetrics, setSummaryMetrics] = useState({ @@ -67,16 +67,11 @@ export default function Auth0Dashboard() { monthly_active_users: 0, conversion_rate: 0 }) - const [dauData, setDauData] = useState([]) - const [authMechData, setAuthMechData] = useState([]) - const [dailySignupsData, setDailySignupsData] = useState([]) - const [dailyLoginFailsData, setDailyLoginFailsData] = useState([]) const [selectedApp, setSelectedApp] = useState('all') const [selectedConnection, setSelectedConnection] = useState('all') const [applications, setApplications] = useState>([]) const [connections, setConnections] = useState>([]) const [timeRange, setTimeRange] = useState<'hourly' | 'daily' | 'monthly'>('daily') - const [userRetentionData, setUserRetentionData] = useState([]) const [logs, setLogs] = useState([]) const [logsPage, setLogsPage] = useState(0) const [isLoading, setIsLoading] = useState(false) @@ -92,21 +87,7 @@ export default function Auth0Dashboard() { }) const [selectedTenant, setSelectedTenant] = useState('all') const [tenants, setTenants] = useState>([]) - const [topBrowsers, setTopBrowsers] = useState>([]) - const [topDevices, setTopDevices] = useState>([]) - const [topDomains, setTopDomains] = useState>([]) const [isDomainsOpen, setIsDomainsOpen] = useState(false) - const [cumulativeSignupsData, setCumulativeSignupsData] = useState>([]) useEffect(() => { async function fetchInitialData() { @@ -164,14 +145,6 @@ export default function Auth0Dashboard() { monthlySignupsResult, monthlyActiveUsersResult, conversionRateResult, - userRetentionTimeSeriesResult, - dauResult, - authMechResult, - dailySignupsResult, - dailyLoginFailsResult, - topBrowsersResult, - topDevicesResult, - topDomainsResult, logsResult ] = await Promise.all([ pipe(token, 'auth0_users_total', baseParams), @@ -181,14 +154,6 @@ export default function Auth0Dashboard() { pipe(token, 'auth0_signups', baseParams), pipe(token, 'auth0_mau', baseParams), pipe(token, 'auth0_conversion_rate', baseParams), - pipe<{ data: UserRetentionDataPoint[] }>(token, 'auth0_user_retention_ts', baseParams), - pipe<{ data: DauDataPoint[] }>(token, 'auth0_dau_ts', baseParams), - pipe<{ data: AuthMechDataPoint[] }>(token, 'auth0_mech_usage', baseParams), - pipe<{ data: DailySignupsDataPoint[] }>(token, 'auth0_daily_signups', baseParams), - pipe<{ data: DailyLoginFailsDataPoint[] }>(token, 'auth0_daily_login_fails', baseParams), - pipe(token, 'auth0_top_browsers', baseParams), - pipe(token, 'auth0_top_devices', baseParams), - pipe(token, 'auth0_top_domains', baseParams), pipe<{ data: LogEntry[] }>(token, 'auth0_logs', { ...baseParams, page: logsPage, @@ -208,29 +173,7 @@ export default function Auth0Dashboard() { monthly_active_users: monthlyActiveUsersResult?.data?.[0]?.active ?? 0, conversion_rate: conversionRateResult?.data?.[0]?.conversion_rate ?? 0 }) - - setDauData(dauResult?.data ?? []) - setAuthMechData(authMechResult?.data ?? []) - setDailySignupsData(dailySignupsResult?.data ?? []) - setDailyLoginFailsData(dailyLoginFailsResult?.data ?? []) - setUserRetentionData(userRetentionTimeSeriesResult?.data as UserRetentionDataPoint[] ?? []) - setTopBrowsers(topBrowsersResult?.data as Array<{ - browser: string - request_count: number - }> ?? []) - setTopDevices(topDevicesResult?.data as Array<{ - device: string - request_count: number - }> ?? []) - setTopDomains(topDomainsResult?.data as Array<{ - domain: string - request_count: number - unique_emails: number - }> ?? []) setLogs(logsResult?.data ?? []) - - const cumulativeSignupsResult = await pipe<{ data: Array<{ day: string; new_users: number; cumulative_users: number }> }>(token, 'auth0_cumulative_users', baseParams) - setCumulativeSignupsData(cumulativeSignupsResult?.data ?? []) } catch (error) { console.error('Failed to fetch metrics:', error) } finally { @@ -359,10 +302,13 @@ export default function Auth0Dashboard() { Cumulative Signups - @@ -401,38 +347,85 @@ export default function Auth0Dashboard() { {/* Charts Grid */}
- + + + Active Users + + + + +
- - + + + User Retention + + + + + + + + Daily Signups + + + + +
- + + + Top Auth Methods + + + + + Top Browsers - @@ -441,10 +434,13 @@ export default function Auth0Dashboard() { Top Devices - @@ -463,21 +459,35 @@ export default function Auth0Dashboard() { -
- - + + + Daily Login Fails + + + + +
diff --git a/apps/web/src/components/tools/auth0/dau-chart.tsx b/apps/web/src/components/tools/auth0/dau-chart.tsx index bfb4139..a4f0ee0 100644 --- a/apps/web/src/components/tools/auth0/dau-chart.tsx +++ b/apps/web/src/components/tools/auth0/dau-chart.tsx @@ -1,109 +1,23 @@ "use client" -import { - Card, - CardContent, - CardHeader, - CardTitle, -} from "@/components/ui/card" -import { - ChartContainer, - ChartTooltip, - ChartConfig, - ChartTooltipContent -} from "@/components/ui/chart" -import { Line, LineChart, XAxis, YAxis, CartesianGrid } from "recharts" -import { format } from "date-fns" +import { AreaChart } from '@tinybirdco/charts' -export interface DauDataPoint { - day: string - active: number -} - -export interface DauChartData { - data: DauDataPoint[] - comparisonData?: DauDataPoint[] - timeRange: 'hourly' | 'daily' | 'monthly' - className?: string -} - -const chartConfig = { - active: { - color: "hsl(var(--chart-1))", - label: "Active Users", - }, -} satisfies ChartConfig - -export function DauChart({ data, timeRange, className }: DauChartData) { - return ( - - - Active Users - - - - - - { - const date = new Date(value) - return timeRange === 'monthly' - ? format(date, 'MMM yyyy') - : value.split('-')[2] - }} - label={{ - value: timeRange === 'monthly' ? "Month of Year" : "Day of Month", - position: "bottom", - offset: 20 - }} - /> - - } - /> - - - - - - ) -} +export function Auth0Dau(params: { + client_id?: string + connection_id?: string + tenant_name?: string + token?: string + date_from?: string + date_to?: string + time_range?: string +}) { + return +} \ No newline at end of file diff --git a/apps/web/src/components/tools/auth0/top-browsers-chart.tsx b/apps/web/src/components/tools/auth0/top-browsers-chart.tsx index 959be5c..76f2ddb 100644 --- a/apps/web/src/components/tools/auth0/top-browsers-chart.tsx +++ b/apps/web/src/components/tools/auth0/top-browsers-chart.tsx @@ -1,72 +1,33 @@ -import { BarChart, Bar, XAxis, YAxis } from 'recharts' -import { ChartContainer, ChartTooltip, ChartConfig, ChartTooltipContent } from '@/components/ui/chart' +'use client' -interface Browser { - browser: string - request_count: number -} +import { BarList } from '@tinybirdco/charts' -interface TopBrowsersChartProps { - data: Browser[] - isLoading: boolean - className?: string -} - -const chartConfig = { - request_count: { - color: "hsl(var(--primary))", - label: "Requests", - }, -} satisfies ChartConfig - -function transformData(data: Browser[]): (Browser & { fill: string })[] { - return data.map((item, index) => ({ - ...item, - fill: `hsl(var(--chart-${(index % 12) + 1}))` - })); -} - -export function TopBrowsersChart({ data, isLoading, className }: TopBrowsersChartProps) { - if (isLoading) return
Loading...
- if (!data.length) return
No data available
- - data = transformData(data) - - return ( - - - - - } - cursor={{ fill: "hsl(var(--muted))", opacity: 0.2 }} - /> - - - - ) -} \ No newline at end of file +export function Auth0TopBrowsers(params: { + client_id?: string + connection_id?: string + tenant_name?: string + token?: string + date_from?: string + date_to?: string +}) { + return ( + {label} + ) + }} + categoryConfig={{ + request_count: { + label: Requests + } + }} + /> +} \ No newline at end of file diff --git a/apps/web/src/components/tools/auth0/top-devices-chart.tsx b/apps/web/src/components/tools/auth0/top-devices-chart.tsx index 5c608e2..bc4c5ee 100644 --- a/apps/web/src/components/tools/auth0/top-devices-chart.tsx +++ b/apps/web/src/components/tools/auth0/top-devices-chart.tsx @@ -1,72 +1,33 @@ -import { BarChart, Bar, XAxis, YAxis } from 'recharts' -import { ChartConfig, ChartTooltip, ChartTooltipContent, ChartContainer } from '@/components/ui/chart' -interface Device { - device: string - request_count: number -} +'use client' -interface TopDevicesChartProps { - data: Device[] - isLoading: boolean - className?: string -} +import { BarList } from '@tinybirdco/charts' -const chartConfig = { - request_count: { - color: "hsl(var(--chart-1))", - label: "Requests", - }, -} satisfies ChartConfig - -function transformData(data: Device[]): (Device & { fill: string })[] { - return data.map((item, index) => ({ - ...item, - fill: `hsl(var(--chart-${(index % 12) + 1}))` - })); -} - -export function TopDevicesChart({ data, isLoading, className }: TopDevicesChartProps) { - if (isLoading) return
Loading...
- if (!data.length) return
No data available
- - data = transformData(data) - - return ( - - - - - } - cursor={{ fill: "hsl(var(--muted))", opacity: 0.2 }} - /> - - - - ) -} \ No newline at end of file +export function Auth0TopDevices(params: { + client_id?: string + connection_id?: string + tenant_name?: string + token?: string + date_from?: string + date_to?: string +}) { + return ( + {label} + ) + }} + categoryConfig={{ + request_count: { + label: Requests + } + }} + /> +} \ No newline at end of file diff --git a/apps/web/src/components/tools/auth0/top-domains-chart.tsx b/apps/web/src/components/tools/auth0/top-domains-chart.tsx index d514577..dc94a7e 100644 --- a/apps/web/src/components/tools/auth0/top-domains-chart.tsx +++ b/apps/web/src/components/tools/auth0/top-domains-chart.tsx @@ -1,75 +1,33 @@ -import { BarChart, Bar, XAxis, YAxis } from 'recharts' -import { ChartConfig, ChartTooltip, ChartTooltipContent, ChartContainer } from '@/components/ui/chart' +'use client' -interface Domain { - domain: string - request_count: number - unique_emails: number -} +import { BarList } from '@tinybirdco/charts' -interface TopDomainsChartProps { - data: Domain[] - isLoading: boolean - className?: string -} - -const chartConfig = { - unique_emails: { - color: "hsl(var(--chart-1))", - label: "Users", - }, -} satisfies ChartConfig - -function transformData(data: Domain[]): (Domain & { fill: string })[] { - return data.map((item, index) => ({ - ...item, - fill: `hsl(var(--chart-${(index % 12) + 1}))` - })); -} - -export function TopDomainsChart({ data, isLoading, className }: TopDomainsChartProps) { - if (isLoading) return
Loading...
- if (!data.length) return
No data available
- - data = transformData(data) - - return ( - - - - - } - cursor={{ fill: "hsl(var(--muted))", opacity: 0.2 }} - /> - - - - ) -} \ No newline at end of file +export function Auth0TopDomains(params: { + client_id?: string + connection_id?: string + tenant_name?: string + token?: string + date_from?: string + date_to?: string +}) { + return ( + {label} + ) + }} + categoryConfig={{ + unique_emails: { + label: Unique Users + } + }} + /> +} \ No newline at end of file diff --git a/apps/web/src/components/tools/auth0/user-retention-chart.tsx b/apps/web/src/components/tools/auth0/user-retention-chart.tsx index 419a045..de42f6c 100644 --- a/apps/web/src/components/tools/auth0/user-retention-chart.tsx +++ b/apps/web/src/components/tools/auth0/user-retention-chart.tsx @@ -1,107 +1,23 @@ -import { - Card, - CardContent, - CardHeader, - CardTitle, -} from "@/components/ui/card" -import { - ChartContainer, - ChartConfig, - ChartTooltip, - ChartTooltipContent -} from "@/components/ui/chart" -import { Line, LineChart, XAxis, YAxis, CartesianGrid } from "recharts" -import { format } from "date-fns" +'use client' -export interface UserRetentionDataPoint { - day: string - user_retention: number -} +import { AreaChart } from '@tinybirdco/charts' -export interface UserRetentionChartData { - data: UserRetentionDataPoint[] - timeRange: 'hourly' | 'daily' | 'monthly' - className?: string -} - -const chartConfig = { - user_retention: { - color: "hsl(var(--chart-1))", - label: "User Retention", - }, -} satisfies ChartConfig - -export function UserRetentionChart({ data, timeRange, className }: UserRetentionChartData) { - return ( - - - User Retention - - - - - - { - const date = new Date(value) - return timeRange === 'monthly' - ? format(date, 'MMM yyyy') - : value.split('-')[2] - }} - label={{ - value: timeRange === 'monthly' ? "Month of Year" : "Day of Month", - position: "bottom", - offset: 20 - }} - /> - `${value}%`} - label={{ - value: "User Retention", - angle: -90, - position: "left", - offset: 32 - }} - /> - } - /> - - - - - - ) -} \ No newline at end of file +export function Auth0UserRetention(params: { + client_id?: string + connection_id?: string + tenant_name?: string + token?: string + date_from?: string + date_to?: string + time_range?: string +}) { + return +} \ No newline at end of file diff --git a/tinybird/pipes/auth0_top_browsers.pipe b/tinybird/pipes/auth0_top_browsers.pipe index 415c28c..0cb5184 100644 --- a/tinybird/pipes/auth0_top_browsers.pipe +++ b/tinybird/pipes/auth0_top_browsers.pipe @@ -25,18 +25,16 @@ SQL > AND event_time >= {{DateTime(date_from, '2024-01-01 00:00:00')}} AND event_time <= {{DateTime(date_to, '2025-01-01 23:59:59')}} AND event.data.user_agent IS NOT NULL - {% if defined(event_type) %} - AND event_type = {{String(event_type)}} - {% end %} - {% if defined(client_name) %} + {% if defined(client_name) and client_name != 'all' %} AND event.data.client_name::String = {{String(client_name)}} {% end %} - {% if defined(connection_id) %} + {% if defined(connection_id) and connection_id != 'all' %} AND event.data.connection_id::String = {{String(connection_id)}} {% end %} - {% if defined(tenant_name) %} + {% if defined(tenant_name) and tenant_name != 'all' %} AND event.data.tenant_name::String = {{String(tenant_name)}} {% end %} + AND browser != 'Unknown' GROUP BY browser ORDER BY request_count DESC LIMIT 10 diff --git a/tinybird/pipes/auth0_top_devices.pipe b/tinybird/pipes/auth0_top_devices.pipe index 8ba2fdc..f3d253c 100644 --- a/tinybird/pipes/auth0_top_devices.pipe +++ b/tinybird/pipes/auth0_top_devices.pipe @@ -21,18 +21,16 @@ SQL > AND event_time >= {{DateTime(date_from, '2024-01-01 00:00:00')}} AND event_time <= {{DateTime(date_to, '2024-01-01 23:59:59')}} AND event.data.user_agent IS NOT NULL - {% if defined(event_type) %} - AND event_type = {{String(event_type)}} - {% end %} - {% if defined(client_name) %} + {% if defined(client_name) and client_name != 'all' %} AND event.data.client_name::String = {{String(client_name)}} {% end %} - {% if defined(connection_id) %} + {% if defined(connection_id) and connection_id != 'all' %} AND event.data.connection_id::String = {{String(connection_id)}} {% end %} - {% if defined(tenant_name) %} + {% if defined(tenant_name) and tenant_name != 'all' %} AND event.data.tenant_name::String = {{String(tenant_name)}} {% end %} + AND device != 'Bot' GROUP BY device ORDER BY request_count DESC LIMIT 10 diff --git a/tinybird/pipes/auth0_top_domains.pipe b/tinybird/pipes/auth0_top_domains.pipe index dfff7fc..95c304f 100644 --- a/tinybird/pipes/auth0_top_domains.pipe +++ b/tinybird/pipes/auth0_top_domains.pipe @@ -9,26 +9,20 @@ SQL > splitByChar('@', event.data.user_name::String)[2] as domain SELECT domain, - count(*) as request_count, - countDistinct(event.data.user_name) as unique_emails, - min(event_time) as first_seen, - max(event_time) as last_seen + countDistinct(event.data.user_name) as unique_emails FROM auth0 WHERE 1 AND event.data.user_name::String like '%@%' AND event_time >= {{DateTime(date_from, '2024-01-01 00:00:00')}} AND event_time <= {{DateTime(date_to, '2024-01-01 23:59:59')}} AND event.data.user_name IS NOT NULL - {% if defined(event_type) %} - AND event_type = {{String(event_type)}} + {% if defined(client_id) and client_id != 'all' %} + AND event.data.client_id::String = {{String(client_id)}} {% end %} - {% if defined(client_name) %} - AND event.data.client_name::String = {{String(client_name)}} - {% end %} - {% if defined(connection_id) %} + {% if defined(connection_id) and connection_id != 'all' %} AND event.data.connection_id::String = {{String(connection_id)}} {% end %} - {% if defined(tenant_name) %} + {% if defined(tenant_name) and tenant_name != 'all' %} AND event.data.tenant_name::String = {{String(tenant_name)}} {% end %} GROUP BY domain diff --git a/tinybird/pipes/auth0_user_retention_ts.pipe b/tinybird/pipes/auth0_user_retention_ts.pipe index 710b042..4b3baba 100644 --- a/tinybird/pipes/auth0_user_retention_ts.pipe +++ b/tinybird/pipes/auth0_user_retention_ts.pipe @@ -14,10 +14,10 @@ SQL > {% else %} toStartOfDay(event_time)::Date as day, {% end %} - uniqIf(event.data.user_id, event_type = 's' AND event_time >= {{DateTime(date_from, '2024-01-01 00:00:00')}} AND event_time <= {{DateTime(date_to, '2024-12-31 23:59:59')}}) as new_signups, + uniqIf(event.data.user_id, event_type = 's' AND event_time >= {{DateTime(date_from, '2024-01-01 00:00:00')}} AND event_time <= {{DateTime(date_to, '2024-12-31 23:59:59')}}) as uniq_logins, total_users, ROUND( - new_signups / total_users * 100, 1 + uniq_logins / total_users * 100, 1 ) as user_retention FROM auth0 WHERE 1 @@ -30,6 +30,7 @@ SQL > {% if defined(tenant_name) and tenant_name != 'all' %} AND event.data.tenant_name::String = {{String(tenant_name)}} {% end %} + AND event_time >= {{DateTime(date_from, '2024-01-01 00:00:00')}} AND event_time <= {{DateTime(date_to, '2024-12-31 23:59:59')}} GROUP BY day ORDER BY day