better-auth-studio 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +8 -1
- package/frontend/index.html +0 -13
- package/frontend/package-lock.json +0 -4675
- package/frontend/package.json +0 -52
- package/frontend/pnpm-lock.yaml +0 -4020
- package/frontend/postcss.config.js +0 -6
- package/frontend/src/App.tsx +0 -36
- package/frontend/src/components/CommandPalette.tsx +0 -219
- package/frontend/src/components/Layout.tsx +0 -159
- package/frontend/src/components/ui/badge.tsx +0 -40
- package/frontend/src/components/ui/button.tsx +0 -53
- package/frontend/src/components/ui/card.tsx +0 -78
- package/frontend/src/components/ui/input.tsx +0 -20
- package/frontend/src/components/ui/label.tsx +0 -19
- package/frontend/src/components/ui/select.tsx +0 -71
- package/frontend/src/index.css +0 -130
- package/frontend/src/lib/utils.ts +0 -6
- package/frontend/src/main.tsx +0 -10
- package/frontend/src/pages/Dashboard.tsx +0 -231
- package/frontend/src/pages/OrganizationDetails.tsx +0 -1281
- package/frontend/src/pages/Organizations.tsx +0 -874
- package/frontend/src/pages/Sessions.tsx +0 -623
- package/frontend/src/pages/Settings.tsx +0 -1019
- package/frontend/src/pages/TeamDetails.tsx +0 -666
- package/frontend/src/pages/Users.tsx +0 -728
- package/frontend/tailwind.config.js +0 -75
- package/frontend/tsconfig.json +0 -31
- package/frontend/tsconfig.node.json +0 -10
- package/frontend/vite.config.ts +0 -31
- package/src/auth-adapter.ts +0 -473
- package/src/cli.ts +0 -51
- package/src/config.ts +0 -320
- package/src/data.ts +0 -351
- package/src/routes.ts +0 -1585
- package/src/studio.ts +0 -86
- package/test-project/README.md +0 -0
- package/test-project/better-auth.db +0 -0
- package/test-project/better-auth_migrations/2025-08-27T15-55-04.099Z.sql +0 -7
- package/test-project/better-auth_migrations/2025-09-04T02-33-19.422Z.sql +0 -7
- package/test-project/package.json +0 -29
- package/test-project/pnpm-lock.yaml +0 -1728
- package/test-project/src/auth.ts +0 -47
- package/test-project/src/index.ts +0 -40
- package/tsconfig.json +0 -21
|
@@ -1,623 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect } from 'react'
|
|
2
|
-
import {
|
|
3
|
-
Database,
|
|
4
|
-
Search,
|
|
5
|
-
Filter,
|
|
6
|
-
Edit,
|
|
7
|
-
Trash2,
|
|
8
|
-
Plus,
|
|
9
|
-
Eye,
|
|
10
|
-
X,
|
|
11
|
-
User
|
|
12
|
-
} from 'lucide-react'
|
|
13
|
-
import { Button } from '../components/ui/button'
|
|
14
|
-
import { Input } from '../components/ui/input'
|
|
15
|
-
import { Label } from '../components/ui/label'
|
|
16
|
-
import { Select, SelectItem } from '../components/ui/select'
|
|
17
|
-
|
|
18
|
-
interface Session {
|
|
19
|
-
id: string
|
|
20
|
-
userId: string
|
|
21
|
-
expiresAt: string
|
|
22
|
-
createdAt: string
|
|
23
|
-
updatedAt: string
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export default function Sessions() {
|
|
27
|
-
const [sessions, setSessions] = useState<Session[]>([])
|
|
28
|
-
const [loading, setLoading] = useState(true)
|
|
29
|
-
const [searchTerm, setSearchTerm] = useState('')
|
|
30
|
-
const [filter, setFilter] = useState('all')
|
|
31
|
-
const [showCreateModal, setShowCreateModal] = useState(false)
|
|
32
|
-
const [showEditModal, setShowEditModal] = useState(false)
|
|
33
|
-
const [showDeleteModal, setShowDeleteModal] = useState(false)
|
|
34
|
-
const [showViewModal, setShowViewModal] = useState(false)
|
|
35
|
-
const [showSeedModal, setShowSeedModal] = useState(false)
|
|
36
|
-
const [selectedSession, setSelectedSession] = useState<Session | null>(null)
|
|
37
|
-
const [seedingLogs, setSeedingLogs] = useState<string[]>([])
|
|
38
|
-
|
|
39
|
-
useEffect(() => {
|
|
40
|
-
fetchSessions()
|
|
41
|
-
}, [])
|
|
42
|
-
|
|
43
|
-
const fetchSessions = async () => {
|
|
44
|
-
try {
|
|
45
|
-
const response = await fetch('/api/sessions')
|
|
46
|
-
const data = await response.json()
|
|
47
|
-
setSessions(data.sessions || [])
|
|
48
|
-
} catch (error) {
|
|
49
|
-
console.error('Failed to fetch sessions:', error)
|
|
50
|
-
} finally {
|
|
51
|
-
setLoading(false)
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
const handleSeedSessions = async (count: number) => {
|
|
56
|
-
setSeedingLogs([])
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
const response = await fetch('/api/seed/sessions', {
|
|
60
|
-
method: 'POST',
|
|
61
|
-
headers: { 'Content-Type': 'application/json' },
|
|
62
|
-
body: JSON.stringify({ count })
|
|
63
|
-
})
|
|
64
|
-
|
|
65
|
-
const result = await response.json()
|
|
66
|
-
|
|
67
|
-
if (result.success) {
|
|
68
|
-
setSeedingLogs(result.results.map((r: any) =>
|
|
69
|
-
`✅ Created session: ${r.session.id}`
|
|
70
|
-
))
|
|
71
|
-
// Refresh the sessions list to show updated count
|
|
72
|
-
await fetchSessions()
|
|
73
|
-
} else {
|
|
74
|
-
setSeedingLogs([`❌ Error: ${result.error || 'Failed to seed sessions'}`])
|
|
75
|
-
}
|
|
76
|
-
} catch (error) {
|
|
77
|
-
setSeedingLogs([`❌ Error: ${error}`])
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const handleSeedAccounts = async (count: number) => {
|
|
82
|
-
setSeedingLogs([])
|
|
83
|
-
|
|
84
|
-
try {
|
|
85
|
-
const response = await fetch('/api/seed/accounts', {
|
|
86
|
-
method: 'POST',
|
|
87
|
-
headers: { 'Content-Type': 'application/json' },
|
|
88
|
-
body: JSON.stringify({ count })
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
const result = await response.json()
|
|
92
|
-
|
|
93
|
-
if (result.success) {
|
|
94
|
-
setSeedingLogs(result.results.map((r: any) =>
|
|
95
|
-
`✅ Created account: ${r.account.provider}`
|
|
96
|
-
))
|
|
97
|
-
// Refresh the sessions list to show updated count
|
|
98
|
-
await fetchSessions()
|
|
99
|
-
} else {
|
|
100
|
-
setSeedingLogs([`❌ Error: ${result.error || 'Failed to seed accounts'}`])
|
|
101
|
-
}
|
|
102
|
-
} catch (error) {
|
|
103
|
-
setSeedingLogs([`❌ Error: ${error}`])
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const openViewModal = (session: Session) => {
|
|
108
|
-
setSelectedSession(session)
|
|
109
|
-
setShowViewModal(true)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const openEditModal = (session: Session) => {
|
|
113
|
-
setSelectedSession(session)
|
|
114
|
-
setShowEditModal(true)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const openDeleteModal = (session: Session) => {
|
|
118
|
-
setSelectedSession(session)
|
|
119
|
-
setShowDeleteModal(true)
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const handleCreateSession = async (sessionData: any) => {
|
|
123
|
-
// Implementation for creating session
|
|
124
|
-
console.log('Creating session:', sessionData)
|
|
125
|
-
setShowCreateModal(false)
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const handleUpdateSession = async (sessionData: any) => {
|
|
129
|
-
// Implementation for updating session
|
|
130
|
-
console.log('Updating session:', sessionData)
|
|
131
|
-
setShowEditModal(false)
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const handleDeleteSession = async () => {
|
|
135
|
-
// Implementation for deleting session
|
|
136
|
-
console.log('Deleting session:', selectedSession?.id)
|
|
137
|
-
setShowDeleteModal(false)
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
const filteredSessions = sessions.filter(session => {
|
|
141
|
-
const matchesSearch = session.id.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
142
|
-
session.userId.toLowerCase().includes(searchTerm.toLowerCase())
|
|
143
|
-
const matchesFilter = filter === 'all' ||
|
|
144
|
-
(filter === 'active' && new Date(session.expiresAt) > new Date()) ||
|
|
145
|
-
(filter === 'expired' && new Date(session.expiresAt) <= new Date())
|
|
146
|
-
return matchesSearch && matchesFilter
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
if (loading) {
|
|
150
|
-
return (
|
|
151
|
-
<div className="flex items-center justify-center h-64">
|
|
152
|
-
<div className="text-white">Loading sessions...</div>
|
|
153
|
-
</div>
|
|
154
|
-
)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return (
|
|
158
|
-
<div className="space-y-6">
|
|
159
|
-
{/* Header */}
|
|
160
|
-
<div className="flex items-center justify-between">
|
|
161
|
-
<div>
|
|
162
|
-
<h1 className="text-2xl text-white font-light">Sessions ({sessions.length})</h1>
|
|
163
|
-
<p className="text-gray-400 mt-1">Manage user sessions and accounts</p>
|
|
164
|
-
</div>
|
|
165
|
-
<div className="flex items-center space-x-3">
|
|
166
|
-
<Button
|
|
167
|
-
className="border border-dashed border-white/20 text-white hover:bg-white/10 rounded-none"
|
|
168
|
-
onClick={() => setShowSeedModal(true)}
|
|
169
|
-
>
|
|
170
|
-
<Database className="w-4 h-4 mr-2" />
|
|
171
|
-
Seed
|
|
172
|
-
</Button>
|
|
173
|
-
<Button
|
|
174
|
-
className="bg-white hover:bg-white/90 text-black border border-white/20 rounded-none"
|
|
175
|
-
onClick={() => setShowCreateModal(true)}
|
|
176
|
-
>
|
|
177
|
-
<Plus className="w-4 h-4 mr-2" />
|
|
178
|
-
Add Session
|
|
179
|
-
</Button>
|
|
180
|
-
</div>
|
|
181
|
-
</div>
|
|
182
|
-
|
|
183
|
-
{/* Filters */}
|
|
184
|
-
<div className="flex items-center space-x-4">
|
|
185
|
-
<div className="flex-1 relative">
|
|
186
|
-
<Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 w-4 h-4" />
|
|
187
|
-
<Input
|
|
188
|
-
placeholder="Search sessions..."
|
|
189
|
-
value={searchTerm}
|
|
190
|
-
onChange={(e) => setSearchTerm(e.target.value)}
|
|
191
|
-
className="pl-10 border border-dashed border-white/20 bg-black/30 text-white rounded-none"
|
|
192
|
-
/>
|
|
193
|
-
</div>
|
|
194
|
-
|
|
195
|
-
<div className="flex items-center space-x-2">
|
|
196
|
-
<Filter className="w-4 h-4 text-gray-400" />
|
|
197
|
-
<Select value={filter} onChange={(e) => setFilter(e.target.value)}>
|
|
198
|
-
<SelectItem value="all">All</SelectItem>
|
|
199
|
-
<SelectItem value="active">Active</SelectItem>
|
|
200
|
-
<SelectItem value="expired">Expired</SelectItem>
|
|
201
|
-
</Select>
|
|
202
|
-
</div>
|
|
203
|
-
</div>
|
|
204
|
-
|
|
205
|
-
{/* Sessions Table */}
|
|
206
|
-
<div className="bg-black/30 border border-dashed border-white/20 rounded-none">
|
|
207
|
-
<div className="overflow-x-auto">
|
|
208
|
-
<table className="w-full">
|
|
209
|
-
<thead>
|
|
210
|
-
<tr className="border-b border-dashed border-white/10">
|
|
211
|
-
<th className="text-left py-4 px-4 text-white font-light">Session</th>
|
|
212
|
-
<th className="text-left py-4 px-4 text-white font-light">User ID</th>
|
|
213
|
-
<th className="text-left py-4 px-4 text-white font-light">Status</th>
|
|
214
|
-
<th className="text-left py-4 px-4 text-white font-light">Expires</th>
|
|
215
|
-
<th className="text-right py-4 px-4 text-white font-light">Actions</th>
|
|
216
|
-
</tr>
|
|
217
|
-
</thead>
|
|
218
|
-
<tbody>
|
|
219
|
-
{filteredSessions.map((session) => (
|
|
220
|
-
<tr key={session.id} className="border-b border-dashed border-white/5 hover:bg-white/5">
|
|
221
|
-
<td className="py-4 px-4">
|
|
222
|
-
<div className="flex items-center space-x-3">
|
|
223
|
-
<div className="w-10 h-10 rounded-none border border-dashed border-white/20 bg-white/10 flex items-center justify-center">
|
|
224
|
-
<Database className="w-5 h-5 text-white" />
|
|
225
|
-
</div>
|
|
226
|
-
<div>
|
|
227
|
-
<div className="text-white font-light">Session {session.id.slice(0, 8)}...</div>
|
|
228
|
-
<div className="text-sm text-gray-400">ID: {session.id}</div>
|
|
229
|
-
</div>
|
|
230
|
-
</div>
|
|
231
|
-
</td>
|
|
232
|
-
<td className="py-4 px-4 text-white">{session.userId}</td>
|
|
233
|
-
<td className="py-4 px-4">
|
|
234
|
-
<div className="flex items-center space-x-2">
|
|
235
|
-
{new Date(session.expiresAt) > new Date() ? (
|
|
236
|
-
<div className="w-2 h-2 bg-green-400 rounded-full"></div>
|
|
237
|
-
) : (
|
|
238
|
-
<div className="w-2 h-2 bg-red-400 rounded-full"></div>
|
|
239
|
-
)}
|
|
240
|
-
<span className="text-sm text-gray-400">
|
|
241
|
-
{new Date(session.expiresAt) > new Date() ? 'Active' : 'Expired'}
|
|
242
|
-
</span>
|
|
243
|
-
</div>
|
|
244
|
-
</td>
|
|
245
|
-
<td className="py-4 px-4 text-sm text-gray-400">
|
|
246
|
-
{new Date(session.expiresAt).toLocaleDateString()}
|
|
247
|
-
</td>
|
|
248
|
-
<td className="py-4 px-4 text-right">
|
|
249
|
-
<div className="flex items-center justify-end space-x-2">
|
|
250
|
-
<Button
|
|
251
|
-
variant="ghost"
|
|
252
|
-
size="sm"
|
|
253
|
-
className="text-gray-400 hover:text-white rounded-none"
|
|
254
|
-
onClick={() => openViewModal(session)}
|
|
255
|
-
>
|
|
256
|
-
<Eye className="w-4 h-4" />
|
|
257
|
-
</Button>
|
|
258
|
-
<Button
|
|
259
|
-
variant="ghost"
|
|
260
|
-
size="sm"
|
|
261
|
-
className="text-gray-400 hover:text-white rounded-none"
|
|
262
|
-
onClick={() => openEditModal(session)}
|
|
263
|
-
>
|
|
264
|
-
<Edit className="w-4 h-4" />
|
|
265
|
-
</Button>
|
|
266
|
-
<Button
|
|
267
|
-
variant="ghost"
|
|
268
|
-
size="sm"
|
|
269
|
-
className="text-red-400 hover:text-red-300 rounded-none"
|
|
270
|
-
onClick={() => openDeleteModal(session)}
|
|
271
|
-
>
|
|
272
|
-
<Trash2 className="w-4 h-4" />
|
|
273
|
-
</Button>
|
|
274
|
-
</div>
|
|
275
|
-
</td>
|
|
276
|
-
</tr>
|
|
277
|
-
))}
|
|
278
|
-
</tbody>
|
|
279
|
-
</table>
|
|
280
|
-
</div>
|
|
281
|
-
</div>
|
|
282
|
-
|
|
283
|
-
{/* Seed Modal */}
|
|
284
|
-
{showSeedModal && (
|
|
285
|
-
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
|
286
|
-
<div className="bg-black/90 border border-dashed border-white/20 p-6 w-full max-w-lg rounded-none">
|
|
287
|
-
<div className="flex items-center justify-between mb-6">
|
|
288
|
-
<h3 className="text-lg text-white font-light">Seed Data</h3>
|
|
289
|
-
<Button
|
|
290
|
-
variant="ghost"
|
|
291
|
-
size="sm"
|
|
292
|
-
onClick={() => setShowSeedModal(false)}
|
|
293
|
-
className="text-gray-400 hover:text-white rounded-none"
|
|
294
|
-
>
|
|
295
|
-
<X className="w-4 h-4" />
|
|
296
|
-
</Button>
|
|
297
|
-
</div>
|
|
298
|
-
<div className="space-y-6">
|
|
299
|
-
{/* Session Seeding */}
|
|
300
|
-
<div className="space-y-4">
|
|
301
|
-
<div className="flex items-center space-x-2">
|
|
302
|
-
<Database className="w-5 h-5 text-white" />
|
|
303
|
-
<h4 className="text-white font-light">Seed Sessions</h4>
|
|
304
|
-
</div>
|
|
305
|
-
<div className="flex items-center space-x-3">
|
|
306
|
-
<div className="flex-1">
|
|
307
|
-
<Label htmlFor="session-count" className="text-sm text-gray-400 font-light">Number of sessions</Label>
|
|
308
|
-
<Input
|
|
309
|
-
id="session-count"
|
|
310
|
-
type="number"
|
|
311
|
-
min="1"
|
|
312
|
-
max="100"
|
|
313
|
-
defaultValue="5"
|
|
314
|
-
className="mt-1 border border-dashed border-white/20 bg-black/30 text-white rounded-none"
|
|
315
|
-
/>
|
|
316
|
-
</div>
|
|
317
|
-
<Button
|
|
318
|
-
onClick={() => {
|
|
319
|
-
const count = parseInt((document.getElementById('session-count') as HTMLInputElement)?.value || '5')
|
|
320
|
-
handleSeedSessions(count)
|
|
321
|
-
}}
|
|
322
|
-
className="bg-white hover:bg-white/90 text-black border border-white/20 rounded-none mt-6"
|
|
323
|
-
>
|
|
324
|
-
Seed Sessions
|
|
325
|
-
</Button>
|
|
326
|
-
</div>
|
|
327
|
-
</div>
|
|
328
|
-
|
|
329
|
-
{/* Account Seeding */}
|
|
330
|
-
<div className="space-y-4">
|
|
331
|
-
<div className="flex items-center space-x-2">
|
|
332
|
-
<User className="w-5 h-5 text-white" />
|
|
333
|
-
<h4 className="text-white font-light">Seed Accounts</h4>
|
|
334
|
-
</div>
|
|
335
|
-
<div className="flex items-center space-x-3">
|
|
336
|
-
<div className="flex-1">
|
|
337
|
-
<Label htmlFor="account-count" className="text-sm text-gray-400 font-light">Number of accounts</Label>
|
|
338
|
-
<Input
|
|
339
|
-
id="account-count"
|
|
340
|
-
type="number"
|
|
341
|
-
min="1"
|
|
342
|
-
max="100"
|
|
343
|
-
defaultValue="5"
|
|
344
|
-
className="mt-1 border border-dashed border-white/20 bg-black/30 text-white rounded-none"
|
|
345
|
-
/>
|
|
346
|
-
</div>
|
|
347
|
-
<Button
|
|
348
|
-
onClick={() => {
|
|
349
|
-
const count = parseInt((document.getElementById('account-count') as HTMLInputElement)?.value || '5')
|
|
350
|
-
handleSeedAccounts(count)
|
|
351
|
-
}}
|
|
352
|
-
className="bg-white hover:bg-white/90 text-black border border-white/20 rounded-none mt-6"
|
|
353
|
-
>
|
|
354
|
-
Seed Accounts
|
|
355
|
-
</Button>
|
|
356
|
-
</div>
|
|
357
|
-
</div>
|
|
358
|
-
|
|
359
|
-
{/* Seeding Logs */}
|
|
360
|
-
{seedingLogs.length > 0 && (
|
|
361
|
-
<div className="mt-6">
|
|
362
|
-
<div className="flex items-center flex-col mb-3">
|
|
363
|
-
<h5 className="text-sm text-white font-light">Seeding Logs</h5>
|
|
364
|
-
<br />
|
|
365
|
-
<details className="group">
|
|
366
|
-
<summary className="cursor-pointer text-sm text-gray-400 font-light hover:text-white">
|
|
367
|
-
View Details ({seedingLogs.length} items)
|
|
368
|
-
</summary>
|
|
369
|
-
<div className="mt-3 p-4 bg-black/50 border border-dashed border-white/20 rounded-none">
|
|
370
|
-
<div className="space-y-2 max-h-48 overflow-y-auto">
|
|
371
|
-
{seedingLogs.map((log, index) => (
|
|
372
|
-
<div key={index} className="text-xs font-mono text-gray-300 flex items-start space-x-2">
|
|
373
|
-
<span className="text-green-400">✓</span>
|
|
374
|
-
<span>{log}</span>
|
|
375
|
-
</div>
|
|
376
|
-
))}
|
|
377
|
-
</div>
|
|
378
|
-
</div>
|
|
379
|
-
</details>
|
|
380
|
-
</div>
|
|
381
|
-
</div>
|
|
382
|
-
)}
|
|
383
|
-
</div>
|
|
384
|
-
<div className="flex justify-end mt-6 pt-6 border-t border-dashed border-white/10">
|
|
385
|
-
<Button
|
|
386
|
-
variant="outline"
|
|
387
|
-
onClick={() => setShowSeedModal(false)}
|
|
388
|
-
className="border border-dashed border-white/20 text-white hover:bg-white/10 rounded-none"
|
|
389
|
-
>
|
|
390
|
-
Close
|
|
391
|
-
</Button>
|
|
392
|
-
</div>
|
|
393
|
-
</div>
|
|
394
|
-
</div>
|
|
395
|
-
)}
|
|
396
|
-
|
|
397
|
-
{/* Create Session Modal */}
|
|
398
|
-
{showCreateModal && (
|
|
399
|
-
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
|
400
|
-
<div className="bg-black/90 border border-dashed border-white/20 p-6 w-full max-w-md rounded-none">
|
|
401
|
-
<div className="flex items-center justify-between mb-4">
|
|
402
|
-
<h3 className="text-lg text-white font-light">Create Session</h3>
|
|
403
|
-
<Button
|
|
404
|
-
variant="ghost"
|
|
405
|
-
size="sm"
|
|
406
|
-
onClick={() => setShowCreateModal(false)}
|
|
407
|
-
className="text-gray-400 hover:text-white rounded-none"
|
|
408
|
-
>
|
|
409
|
-
<X className="w-4 h-4" />
|
|
410
|
-
</Button>
|
|
411
|
-
</div>
|
|
412
|
-
<div className="space-y-4">
|
|
413
|
-
<div>
|
|
414
|
-
<Label htmlFor="create-user-id" className="text-sm text-gray-400 font-light">User ID</Label>
|
|
415
|
-
<Input
|
|
416
|
-
id="create-user-id"
|
|
417
|
-
className="mt-1 border border-dashed border-white/20 bg-black/30 text-white rounded-none"
|
|
418
|
-
/>
|
|
419
|
-
</div>
|
|
420
|
-
<div>
|
|
421
|
-
<Label htmlFor="create-expires" className="text-sm text-gray-400 font-light">Expires At</Label>
|
|
422
|
-
<Input
|
|
423
|
-
id="create-expires"
|
|
424
|
-
type="datetime-local"
|
|
425
|
-
className="mt-1 border border-dashed border-white/20 bg-black/30 text-white rounded-none"
|
|
426
|
-
/>
|
|
427
|
-
</div>
|
|
428
|
-
</div>
|
|
429
|
-
<div className="flex justify-end space-x-3 mt-6">
|
|
430
|
-
<Button
|
|
431
|
-
variant="outline"
|
|
432
|
-
onClick={() => setShowCreateModal(false)}
|
|
433
|
-
className="border border-dashed border-white/20 text-white hover:bg-white/10 rounded-none"
|
|
434
|
-
>
|
|
435
|
-
Cancel
|
|
436
|
-
</Button>
|
|
437
|
-
<Button
|
|
438
|
-
onClick={() => handleCreateSession({})}
|
|
439
|
-
className="bg-white hover:bg-white/90 text-black border border-white/20 rounded-none"
|
|
440
|
-
>
|
|
441
|
-
Create
|
|
442
|
-
</Button>
|
|
443
|
-
</div>
|
|
444
|
-
</div>
|
|
445
|
-
</div>
|
|
446
|
-
)}
|
|
447
|
-
|
|
448
|
-
{/* Edit Session Modal */}
|
|
449
|
-
{showEditModal && selectedSession && (
|
|
450
|
-
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
|
451
|
-
<div className="bg-black/90 border border-dashed border-white/20 p-6 w-full max-w-md rounded-none">
|
|
452
|
-
<div className="flex items-center justify-between mb-4">
|
|
453
|
-
<h3 className="text-lg text-white font-light">Edit Session</h3>
|
|
454
|
-
<Button
|
|
455
|
-
variant="ghost"
|
|
456
|
-
size="sm"
|
|
457
|
-
onClick={() => setShowEditModal(false)}
|
|
458
|
-
className="text-gray-400 hover:text-white rounded-none"
|
|
459
|
-
>
|
|
460
|
-
<X className="w-4 h-4" />
|
|
461
|
-
</Button>
|
|
462
|
-
</div>
|
|
463
|
-
<div className="space-y-4">
|
|
464
|
-
<div className="flex items-center space-x-3">
|
|
465
|
-
<div className="w-16 h-16 rounded-none border border-dashed border-white/20 bg-white/10 flex items-center justify-center">
|
|
466
|
-
<Database className="w-8 h-8 text-white" />
|
|
467
|
-
</div>
|
|
468
|
-
<div>
|
|
469
|
-
<div className="text-white font-light">Session {selectedSession.id.slice(0, 8)}...</div>
|
|
470
|
-
<div className="text-sm text-gray-400">{selectedSession.userId}</div>
|
|
471
|
-
</div>
|
|
472
|
-
</div>
|
|
473
|
-
<div>
|
|
474
|
-
<Label htmlFor="edit-user-id" className="text-sm text-gray-400 font-light">User ID</Label>
|
|
475
|
-
<Input
|
|
476
|
-
id="edit-user-id"
|
|
477
|
-
defaultValue={selectedSession.userId}
|
|
478
|
-
className="mt-1 border border-dashed border-white/20 bg-black/30 text-white rounded-none"
|
|
479
|
-
/>
|
|
480
|
-
</div>
|
|
481
|
-
<div>
|
|
482
|
-
<Label htmlFor="edit-expires" className="text-sm text-gray-400 font-light">Expires At</Label>
|
|
483
|
-
<Input
|
|
484
|
-
id="edit-expires"
|
|
485
|
-
type="datetime-local"
|
|
486
|
-
defaultValue={new Date(selectedSession.expiresAt).toISOString().slice(0, 16)}
|
|
487
|
-
className="mt-1 border border-dashed border-white/20 bg-black/30 text-white rounded-none"
|
|
488
|
-
/>
|
|
489
|
-
</div>
|
|
490
|
-
</div>
|
|
491
|
-
<div className="flex justify-end space-x-3 mt-6">
|
|
492
|
-
<Button
|
|
493
|
-
variant="outline"
|
|
494
|
-
onClick={() => setShowEditModal(false)}
|
|
495
|
-
className="border border-dashed border-white/20 text-white hover:bg-white/10 rounded-none"
|
|
496
|
-
>
|
|
497
|
-
Cancel
|
|
498
|
-
</Button>
|
|
499
|
-
<Button
|
|
500
|
-
onClick={() => handleUpdateSession({})}
|
|
501
|
-
className="bg-white hover:bg-white/90 text-black border border-white/20 rounded-none"
|
|
502
|
-
>
|
|
503
|
-
Update
|
|
504
|
-
</Button>
|
|
505
|
-
</div>
|
|
506
|
-
</div>
|
|
507
|
-
</div>
|
|
508
|
-
)}
|
|
509
|
-
|
|
510
|
-
{/* Delete Session Modal */}
|
|
511
|
-
{showDeleteModal && selectedSession && (
|
|
512
|
-
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
|
513
|
-
<div className="bg-black/90 border border-dashed border-white/20 p-6 w-full max-w-md rounded-none">
|
|
514
|
-
<div className="flex items-center justify-between mb-4">
|
|
515
|
-
<h3 className="text-lg text-white font-light">Delete Session</h3>
|
|
516
|
-
<Button
|
|
517
|
-
variant="ghost"
|
|
518
|
-
size="sm"
|
|
519
|
-
onClick={() => setShowDeleteModal(false)}
|
|
520
|
-
className="text-gray-400 hover:text-white rounded-none"
|
|
521
|
-
>
|
|
522
|
-
<X className="w-4 h-4" />
|
|
523
|
-
</Button>
|
|
524
|
-
</div>
|
|
525
|
-
<div className="space-y-4">
|
|
526
|
-
<div className="flex items-center space-x-3">
|
|
527
|
-
<div className="w-16 h-16 rounded-none border border-dashed border-white/20 bg-white/10 flex items-center justify-center">
|
|
528
|
-
<Database className="w-8 h-8 text-white" />
|
|
529
|
-
</div>
|
|
530
|
-
<div>
|
|
531
|
-
<div className="text-white font-light">Session {selectedSession.id.slice(0, 8)}...</div>
|
|
532
|
-
<div className="text-sm text-gray-400">{selectedSession.userId}</div>
|
|
533
|
-
</div>
|
|
534
|
-
</div>
|
|
535
|
-
<p className="text-gray-400">Are you sure you want to delete this session? This action cannot be undone.</p>
|
|
536
|
-
</div>
|
|
537
|
-
<div className="flex justify-end space-x-3 mt-6">
|
|
538
|
-
<Button
|
|
539
|
-
variant="outline"
|
|
540
|
-
onClick={() => setShowDeleteModal(false)}
|
|
541
|
-
className="border border-dashed border-white/20 text-white hover:bg-white/10 rounded-none"
|
|
542
|
-
>
|
|
543
|
-
Cancel
|
|
544
|
-
</Button>
|
|
545
|
-
<Button
|
|
546
|
-
onClick={handleDeleteSession}
|
|
547
|
-
className="bg-red-600 hover:bg-red-700 text-white border border-red-600 rounded-none"
|
|
548
|
-
>
|
|
549
|
-
Delete
|
|
550
|
-
</Button>
|
|
551
|
-
</div>
|
|
552
|
-
</div>
|
|
553
|
-
</div>
|
|
554
|
-
)}
|
|
555
|
-
|
|
556
|
-
{/* View Session Modal */}
|
|
557
|
-
{showViewModal && selectedSession && (
|
|
558
|
-
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
|
|
559
|
-
<div className="bg-black/90 border border-dashed border-white/20 p-6 w-full max-w-md rounded-none">
|
|
560
|
-
<div className="flex items-center justify-between mb-4">
|
|
561
|
-
<h3 className="text-lg text-white font-light">Session Details</h3>
|
|
562
|
-
<Button
|
|
563
|
-
variant="ghost"
|
|
564
|
-
size="sm"
|
|
565
|
-
onClick={() => setShowViewModal(false)}
|
|
566
|
-
className="text-gray-400 hover:text-white rounded-none"
|
|
567
|
-
>
|
|
568
|
-
<X className="w-4 h-4" />
|
|
569
|
-
</Button>
|
|
570
|
-
</div>
|
|
571
|
-
<div className="space-y-4">
|
|
572
|
-
<div className="flex items-center space-x-3">
|
|
573
|
-
<div className="w-16 h-16 rounded-none border border-dashed border-white/20 bg-white/10 flex items-center justify-center">
|
|
574
|
-
<Database className="w-8 h-8 text-white" />
|
|
575
|
-
</div>
|
|
576
|
-
<div>
|
|
577
|
-
<div className="text-white font-light">Session {selectedSession.id.slice(0, 8)}...</div>
|
|
578
|
-
<div className="text-sm text-gray-400">{selectedSession.userId}</div>
|
|
579
|
-
</div>
|
|
580
|
-
</div>
|
|
581
|
-
<div className="space-y-2">
|
|
582
|
-
<div className="flex justify-between">
|
|
583
|
-
<span className="text-gray-400">ID:</span>
|
|
584
|
-
<span className="text-white text-sm">{selectedSession.id}</span>
|
|
585
|
-
</div>
|
|
586
|
-
<div className="flex justify-between">
|
|
587
|
-
<span className="text-gray-400">User ID:</span>
|
|
588
|
-
<span className="text-white text-sm">{selectedSession.userId}</span>
|
|
589
|
-
</div>
|
|
590
|
-
<div className="flex justify-between">
|
|
591
|
-
<span className="text-gray-400">Status:</span>
|
|
592
|
-
<span className="text-white text-sm">
|
|
593
|
-
{new Date(selectedSession.expiresAt) > new Date() ? 'Active' : 'Expired'}
|
|
594
|
-
</span>
|
|
595
|
-
</div>
|
|
596
|
-
<div className="flex justify-between">
|
|
597
|
-
<span className="text-gray-400">Expires:</span>
|
|
598
|
-
<span className="text-white text-sm">{new Date(selectedSession.expiresAt).toLocaleString()}</span>
|
|
599
|
-
</div>
|
|
600
|
-
<div className="flex justify-between">
|
|
601
|
-
<span className="text-gray-400">Created:</span>
|
|
602
|
-
<span className="text-white text-sm">{new Date(selectedSession.createdAt).toLocaleString()}</span>
|
|
603
|
-
</div>
|
|
604
|
-
<div className="flex justify-between">
|
|
605
|
-
<span className="text-gray-400">Updated:</span>
|
|
606
|
-
<span className="text-white text-sm">{new Date(selectedSession.updatedAt).toLocaleString()}</span>
|
|
607
|
-
</div>
|
|
608
|
-
</div>
|
|
609
|
-
</div>
|
|
610
|
-
<div className="flex justify-end mt-6">
|
|
611
|
-
<Button
|
|
612
|
-
onClick={() => setShowViewModal(false)}
|
|
613
|
-
className="bg-white hover:bg-white/90 text-black border border-white/20 rounded-none"
|
|
614
|
-
>
|
|
615
|
-
Close
|
|
616
|
-
</Button>
|
|
617
|
-
</div>
|
|
618
|
-
</div>
|
|
619
|
-
</div>
|
|
620
|
-
)}
|
|
621
|
-
</div>
|
|
622
|
-
)
|
|
623
|
-
}
|