Skip to content

Commit e0fa7fc

Browse files
committed
add filters
1 parent 43494ce commit e0fa7fc

16 files changed

+500
-57
lines changed

apps/web/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
"@radix-ui/react-label": "^2.1.1",
1414
"@radix-ui/react-popover": "^1.1.4",
1515
"@radix-ui/react-scroll-area": "^1.2.2",
16+
"@radix-ui/react-select": "^2.1.4",
17+
"@radix-ui/react-separator": "^1.1.1",
1618
"@radix-ui/react-slot": "^1.1.1",
1719
"@radix-ui/react-tooltip": "^1.1.6",
1820
"@shadcn/ui": "^0.0.4",

apps/web/pnpm-lock.yaml

Lines changed: 95 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/web/src/components/tools/auth0/dashboard.tsx

Lines changed: 136 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,16 @@ import { AuthMechChart, AuthMechDataPoint } from './auth-mech-chart'
99
import { DailySignupsChart, DailySignupsDataPoint } from './daily-signups-chart'
1010
import { DailyLoginFailsChart, DailyLoginFailsDataPoint } from './daily-login-fails-chart'
1111
import { DateRangePicker, DateRange } from '@/components/ui/date-range-picker'
12-
import { startOfDay, endOfDay, format } from 'date-fns'
12+
import { startOfDay, endOfDay, format, subDays } from 'date-fns'
13+
import {
14+
Select,
15+
SelectContent,
16+
SelectItem,
17+
SelectTrigger,
18+
SelectValue,
19+
} from "@/components/ui/select"
20+
import { Separator } from "@/components/ui/separator"
21+
import { Card, CardContent } from "@/components/ui/card"
1322

1423
interface ConversionData {
1524
new_signups: number
@@ -74,14 +83,56 @@ export default function Auth0Dashboard() {
7483
const [authMechData, setAuthMechData] = useState<AuthMechDataPoint[]>([])
7584
const [dailySignupsData, setDailySignupsData] = useState<DailySignupsDataPoint[]>([])
7685
const [dailyLoginFailsData, setDailyLoginFailsData] = useState<DailyLoginFailsDataPoint[]>([])
86+
const [selectedApp, setSelectedApp] = useState<string>('all')
87+
const [selectedConnection, setSelectedConnection] = useState<string>('all')
88+
const [applications, setApplications] = useState<Array<{ client_id: string, client_name: string }>>([])
89+
const [connections, setConnections] = useState<Array<{ connection_id: string, connection_name: string }>>([])
7790

7891
useEffect(() => {
92+
async function fetchInitialData() {
93+
if (!token) return
94+
try {
95+
const [appsResult, connsResult] = await Promise.all([
96+
pipe<{ data: Array<{ client_id: string, client_name: string }> }>(
97+
token,
98+
'auth0_applications'
99+
),
100+
pipe<{ data: Array<{ id: string, connection_name: string }> }>(
101+
token,
102+
'auth0_connections'
103+
)
104+
])
105+
setApplications(appsResult.data ?? [])
106+
setConnections(connsResult.data ?? [])
107+
} catch (error) {
108+
console.error('Failed to fetch initial data:', error)
109+
}
110+
}
111+
fetchInitialData()
112+
}, [token])
113+
114+
useEffect(() => {
115+
let mounted = true
116+
79117
async function fetchMetrics() {
80118
if (!token) return
81119

82120
const fromDate = format(dateRange.from, "yyyy-MM-dd HH:mm:ss")
83121
const toDate = format(dateRange.to, "yyyy-MM-dd HH:mm:ss")
84-
const thirtyDaysAgo = format(new Date(Date.now() - 30 * 24 * 60 * 60 * 1000), "yyyy-MM-dd HH:mm:ss")
122+
const thirtyDaysAgo = format(subDays(new Date(), 30), "yyyy-MM-dd HH:mm:ss")
123+
124+
const params = {
125+
date_from: fromDate,
126+
date_to: toDate,
127+
...(selectedApp !== 'all' && { client_id: selectedApp }),
128+
...(selectedConnection !== 'all' && { connection_id: selectedConnection })
129+
}
130+
131+
const thirtyDayParams = {
132+
date_from: thirtyDaysAgo,
133+
...(selectedApp !== 'all' && { client_id: selectedApp }),
134+
...(selectedConnection !== 'all' && { connection_id: selectedConnection })
135+
}
85136

86137
try {
87138
const [
@@ -93,39 +144,30 @@ export default function Auth0Dashboard() {
93144
monthlyActiveUsersResult,
94145
conversionRateResult,
95146
dauResult,
147+
dauComparisonResult,
96148
authMechResult,
97149
dailySignupsResult,
98150
dailyLoginFailsResult
99151
] = await Promise.all([
100-
pipe<UsersResult>(token, 'auth0_users_total'),
152+
pipe<UsersResult>(token, 'auth0_users_total', selectedApp !== 'all' || selectedConnection !== 'all' ? {
153+
...(selectedApp !== 'all' && { client_id: selectedApp }),
154+
...(selectedConnection !== 'all' && { connection_id: selectedConnection })
155+
} : undefined),
101156
pipe(token, 'auth0_applications'),
102157
pipe(token, 'auth0_apis'),
103158
pipe(token, 'auth0_connections'),
104-
pipe(token, 'auth0_signups', {
105-
date_from: thirtyDaysAgo
106-
}),
107-
pipe(token, 'auth0_mau', {
108-
date_from: thirtyDaysAgo
109-
}),
110-
pipe<ConversionRateResult>(token, 'auth0_conversion_rate', {
111-
date_from: thirtyDaysAgo
112-
}),
113-
pipe<{ data: DauDataPoint[] }>(token, 'auth0_dau_ts', {
114-
date_from: fromDate,
115-
date_to: toDate
116-
}),
117-
pipe<{ data: AuthMechDataPoint[] }>(token, 'auth0_mech_usage', {
118-
date_from: fromDate,
119-
date_to: toDate
120-
}),
121-
pipe<{ data: DailySignupsDataPoint[] }>(token, 'auth0_daily_signups', {
122-
date_from: fromDate,
123-
date_to: toDate
124-
}),
125-
pipe<{ data: DailyLoginFailsDataPoint[] }>(token, 'auth0_daily_login_fails', {
126-
date_from: fromDate,
127-
date_to: toDate
128-
})
159+
pipe(token, 'auth0_signups', thirtyDayParams),
160+
pipe(token, 'auth0_mau', thirtyDayParams),
161+
pipe<ConversionRateResult>(token, 'auth0_conversion_rate', thirtyDayParams),
162+
pipe<{ data: DauDataPoint[] }>(token, 'auth0_dau_ts', params),
163+
dateRange.compareMode ? pipe<{ data: DauDataPoint[] }>(token, 'auth0_dau_ts', {
164+
...params,
165+
date_from: comparisonFromDate,
166+
date_to: comparisonToDate
167+
}) : Promise.resolve({ data: [] }),
168+
pipe<{ data: AuthMechDataPoint[] }>(token, 'auth0_mech_usage', params),
169+
pipe<{ data: DailySignupsDataPoint[] }>(token, 'auth0_daily_signups', params),
170+
pipe<{ data: DailyLoginFailsDataPoint[] }>(token, 'auth0_daily_login_fails', params)
129171
])
130172

131173
setSummaryMetrics({
@@ -148,30 +190,70 @@ export default function Auth0Dashboard() {
148190
}
149191

150192
fetchMetrics()
151-
}, [token, dateRange])
193+
return () => {
194+
mounted = false
195+
}
196+
}, [token, dateRange.from, dateRange.to, dateRange.compareMode, selectedApp, selectedConnection])
152197

153198
return (
154199
<div className="space-y-8">
155-
{/* Top row - Total metrics */}
156-
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
157-
<MetricCard
158-
title="Total Users"
159-
value={summaryMetrics.total_users}
160-
/>
161-
<MetricCard
162-
title="Applications"
163-
value={summaryMetrics.total_applications}
164-
/>
165-
<MetricCard
166-
title="APIs"
167-
value={summaryMetrics.total_apis}
168-
/>
169-
<MetricCard
170-
title="Connections"
171-
value={summaryMetrics.total_connections}
172-
/>
200+
<div className="flex justify-between items-center gap-4">
201+
<div className="flex gap-2">
202+
<Select value={selectedApp} onValueChange={setSelectedApp}>
203+
<SelectTrigger className="w-[200px]">
204+
<SelectValue placeholder="Select application" />
205+
</SelectTrigger>
206+
<SelectContent>
207+
<SelectItem value="all">All Applications</SelectItem>
208+
{applications.map((app) => (
209+
<SelectItem key={app.client_id} value={app.client_id}>
210+
{app.client_name}
211+
</SelectItem>
212+
))}
213+
</SelectContent>
214+
</Select>
215+
216+
<Select value={selectedConnection} onValueChange={setSelectedConnection}>
217+
<SelectTrigger className="w-[200px]">
218+
<SelectValue placeholder="Select connection" />
219+
</SelectTrigger>
220+
<SelectContent>
221+
<SelectItem value="all">All Connections</SelectItem>
222+
{connections.map((conn) => (
223+
<SelectItem key={conn.connection_id} value={conn.connection_id}>
224+
{conn.connection_name}
225+
</SelectItem>
226+
))}
227+
</SelectContent>
228+
</Select>
229+
</div>
173230
</div>
174231

232+
{/* Top row - Total metrics */}
233+
<Card>
234+
<CardContent className="pt-6">
235+
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
236+
<div className="flex flex-col">
237+
<span className="text-sm font-medium">Total Users</span>
238+
<span className="text-2xl font-bold">{summaryMetrics.total_users}</span>
239+
</div>
240+
<div className="flex flex-col">
241+
<span className="text-sm font-medium">Applications</span>
242+
<span className="text-2xl font-bold">{summaryMetrics.total_applications}</span>
243+
</div>
244+
<div className="flex flex-col">
245+
<span className="text-sm font-medium">APIs</span>
246+
<span className="text-2xl font-bold">{summaryMetrics.total_apis}</span>
247+
</div>
248+
<div className="flex flex-col">
249+
<span className="text-sm font-medium">Connections</span>
250+
<span className="text-2xl font-bold">{summaryMetrics.total_connections}</span>
251+
</div>
252+
</div>
253+
</CardContent>
254+
</Card>
255+
256+
175257
{/* Second row - Monthly metrics */}
176258
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
177259
<MetricCard
@@ -191,14 +273,20 @@ export default function Auth0Dashboard() {
191273
/>
192274
</div>
193275

194-
{/* Date Range Picker */}
276+
<Separator className="my-6" />
277+
195278
<div className="flex justify-end">
196279
<DateRangePicker
197280
initialDateRange={dateRange}
198281
onChange={(newRange) => setDateRange(newRange)}
199282
/>
200283
</div>
201284

285+
<DauChart
286+
data={dauData}
287+
comparisonData={dateRange.compareMode ? dauComparisonData : undefined}
288+
/>
289+
202290
{/* Charts Grid */}
203291
<div className="grid gap-4 grid-cols-1">
204292
<DauChart data={dauData} />

0 commit comments

Comments
 (0)