agentlytics 0.0.7 → 0.0.10

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.
@@ -1,12 +1,14 @@
1
1
  import { useState, useEffect, useMemo, useRef, useCallback } from 'react'
2
- import { useNavigate, useSearchParams } from 'react-router-dom'
2
+ import { useSearchParams } from 'react-router-dom'
3
3
  import { Search, Filter, List, FolderOpen, ChevronDown, ChevronRight, X } from 'lucide-react'
4
4
  import { Chart as ChartJS, CategoryScale, LinearScale, PointElement, LineElement, Tooltip, Legend, Filler } from 'chart.js'
5
5
  import { Line } from 'react-chartjs-2'
6
6
  import { fetchChats } from '../lib/api'
7
- import { editorColor, editorLabel, formatDate } from '../lib/constants'
7
+ import { editorColor, editorLabel, formatDate, dateRangeToApiParams } from '../lib/constants'
8
8
  import { useTheme } from '../lib/theme'
9
9
  import EditorDot from '../components/EditorDot'
10
+ import DateRangePicker from '../components/DateRangePicker'
11
+ import ChatSidebar from '../components/ChatSidebar'
10
12
 
11
13
  ChartJS.register(CategoryScale, LinearScale, PointElement, LineElement, Tooltip, Legend, Filler)
12
14
 
@@ -107,8 +109,9 @@ export default function Sessions({ overview }) {
107
109
  const [loading, setLoading] = useState(true)
108
110
  const [groupByProject, setGroupByProject] = useState(false)
109
111
  const [collapsedProjects, setCollapsedProjects] = useState(new Set())
110
- const [dateRange, setDateRange] = useState(null) // [startWeek, endWeek]
111
- const navigate = useNavigate()
112
+ const [dateRange, setDateRange] = useState(null) // [startWeek, endWeek] — chart drag-select
113
+ const [apiDateRange, setApiDateRange] = useState(null) // { from, to } — server-side date filter
114
+ const [selectedChatId, setSelectedChatId] = useState(null)
112
115
  const chartRef = useRef(null)
113
116
 
114
117
  const onRangeSelect = useCallback((start, end) => {
@@ -117,12 +120,12 @@ export default function Sessions({ overview }) {
117
120
 
118
121
  useEffect(() => {
119
122
  setLoading(true)
120
- fetchChats({ editor, limit: 1000 }).then(data => {
123
+ fetchChats({ editor, limit: 1000, ...dateRangeToApiParams(apiDateRange) }).then(data => {
121
124
  setChats(data.chats)
122
125
  setTotal(data.total)
123
126
  setLoading(false)
124
127
  })
125
- }, [editor])
128
+ }, [editor, apiDateRange])
126
129
 
127
130
  const searchFiltered = search
128
131
  ? chats.filter(c =>
@@ -212,7 +215,7 @@ export default function Sessions({ overview }) {
212
215
  style={{ borderBottom: '1px solid var(--c-border)' }}
213
216
  onMouseEnter={e => e.currentTarget.style.background = 'var(--c-bg3)'}
214
217
  onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
215
- onClick={() => navigate(`/sessions/${c.id}`)}
218
+ onClick={() => setSelectedChatId(c.id)}
216
219
  >
217
220
  <td className="py-2.5 px-4">
218
221
  <EditorDot source={c.source} showLabel size={7} />
@@ -229,6 +232,9 @@ export default function Sessions({ overview }) {
229
232
  <td className="py-2.5 px-4">
230
233
  <span className="text-xs" style={{ color: 'var(--c-text2)' }}>{c.mode}</span>
231
234
  </td>
235
+ <td className="py-2.5 px-4 text-xs truncate max-w-[180px] font-mono" style={{ color: 'var(--c-text2)' }} title={c.topModel || ''}>
236
+ {c.topModel || ''}
237
+ </td>
232
238
  <td className="py-2.5 px-4 text-xs whitespace-nowrap" style={{ color: 'var(--c-text2)' }}>
233
239
  {formatDate(c.lastUpdatedAt || c.createdAt)}
234
240
  </td>
@@ -283,46 +289,48 @@ export default function Sessions({ overview }) {
283
289
 
284
290
  {/* Filters */}
285
291
  <div className="flex items-center gap-3">
286
- <div className="relative">
287
- <Filter size={13} className="absolute left-3 top-1/2 -translate-y-1/2" style={{ color: 'var(--c-text3)' }} />
288
- <select
289
- value={editor}
290
- onChange={e => setEditor(e.target.value)}
291
- className="pl-8 pr-3 py-2 text-sm outline-none appearance-none cursor-pointer"
292
- style={{ background: 'var(--c-bg3)', color: 'var(--c-text)', border: '1px solid var(--c-border)' }}
292
+ <div className="relative">
293
+ <Filter size={13} className="absolute left-3 top-1/2 -translate-y-1/2" style={{ color: 'var(--c-text3)' }} />
294
+ <select
295
+ value={editor}
296
+ onChange={e => setEditor(e.target.value)}
297
+ className="pl-8 pr-3 py-1 text-[11px] outline-none appearance-none cursor-pointer"
298
+ style={{ background: 'var(--c-bg3)', color: 'var(--c-text)', border: '1px solid var(--c-border)' }}
299
+ >
300
+ <option value="">all editors</option>
301
+ {editors.map(e => (
302
+ <option key={e.id} value={e.id}>{editorLabel(e.id)} ({e.count})</option>
303
+ ))}
304
+ </select>
305
+ </div>
306
+ <div className="relative flex-1 max-w-sm">
307
+ <Search size={13} className="absolute left-3 top-1/2 -translate-y-1/2" style={{ color: 'var(--c-text3)' }} />
308
+ <input
309
+ type="text"
310
+ placeholder="search sessions..."
311
+ value={search}
312
+ onChange={e => setSearch(e.target.value)}
313
+ className="w-full pl-8 pr-3 py-1 text-[11px] outline-none"
314
+ style={{ background: 'var(--c-bg3)', color: 'var(--c-text)', border: '1px solid var(--c-border)' }}
315
+ />
316
+ </div>
317
+ <button
318
+ onClick={() => setGroupByProject(!groupByProject)}
319
+ className="flex items-center gap-1.5 px-3 py-1 text-[11px] transition"
320
+ style={{
321
+ border: groupByProject ? '1px solid var(--c-accent)' : '1px solid var(--c-border)',
322
+ color: groupByProject ? 'var(--c-accent)' : 'var(--c-text2)',
323
+ background: groupByProject ? 'rgba(99,102,241,0.1)' : 'transparent',
324
+ }}
293
325
  >
294
- <option value="">all editors</option>
295
- {editors.map(e => (
296
- <option key={e.id} value={e.id}>{editorLabel(e.id)} ({e.count})</option>
297
- ))}
298
- </select>
299
- </div>
300
- <div className="relative flex-1 max-w-sm">
301
- <Search size={13} className="absolute left-3 top-1/2 -translate-y-1/2" style={{ color: 'var(--c-text3)' }} />
302
- <input
303
- type="text"
304
- placeholder="search sessions..."
305
- value={search}
306
- onChange={e => setSearch(e.target.value)}
307
- className="w-full pl-8 pr-3 py-2 text-sm outline-none"
308
- style={{ background: 'var(--c-bg3)', color: 'var(--c-text)', border: '1px solid var(--c-border)' }}
309
- />
310
- </div>
311
- <button
312
- onClick={() => setGroupByProject(!groupByProject)}
313
- className="flex items-center gap-1.5 px-3 py-2 text-xs transition"
314
- style={{
315
- border: groupByProject ? '1px solid var(--c-accent)' : '1px solid var(--c-border)',
316
- color: groupByProject ? 'var(--c-accent)' : 'var(--c-text2)',
317
- background: groupByProject ? 'rgba(99,102,241,0.1)' : 'transparent',
318
- }}
319
- >
320
- {groupByProject ? <FolderOpen size={13} /> : <List size={13} />}
321
- {groupByProject ? 'grouped' : 'flat'}
322
- </button>
323
- <span className="text-[10px]" style={{ color: 'var(--c-text3)' }}>
324
- {loading ? 'loading...' : `${filtered.length} of ${total}`}
325
- </span>
326
+ {groupByProject ? <FolderOpen size={13} /> : <List size={13} />}
327
+ {groupByProject ? 'grouped' : 'flat'}
328
+ </button>
329
+ <span className="text-[10px]" style={{ color: 'var(--c-text3)' }}>
330
+ {loading ? 'loading...' : `${filtered.length} of ${total}`}
331
+ </span>
332
+ {/* Server-side date range filter */}
333
+ <div className="ml-auto"><DateRangePicker value={apiDateRange} onChange={setApiDateRange} /></div>
326
334
  </div>
327
335
 
328
336
  {/* Session table */}
@@ -335,6 +343,7 @@ export default function Sessions({ overview }) {
335
343
  <th className="text-left py-2.5 px-4 font-medium">name</th>
336
344
  <th className="text-left py-2.5 px-4 font-medium">project</th>
337
345
  <th className="text-left py-2.5 px-4 font-medium">mode</th>
346
+ <th className="text-left py-2.5 px-4 font-medium">model</th>
338
347
  <th className="text-left py-2.5 px-4 font-medium">updated</th>
339
348
  </tr>
340
349
  </thead>
@@ -383,6 +392,9 @@ export default function Sessions({ overview }) {
383
392
  )}
384
393
  </div>
385
394
  )}
395
+
396
+ {/* Chat sidebar */}
397
+ <ChatSidebar chatId={selectedChatId} onClose={() => setSelectedChatId(null)} />
386
398
  </div>
387
399
  )
388
400
  }