feat: Add Visits and Unique Users cards to overview
Visits counts total conversations created in the timeframe (from conversations collection). Unique Users counts distinct users who created at least one conversation in the period. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e74f21d57e
commit
3d3c8a1a54
4 changed files with 21 additions and 1 deletions
|
|
@ -268,6 +268,8 @@ body {
|
|||
.stat-icon.tokens { background: rgba(255, 196, 7, 0.08); color: #FFD54F; }
|
||||
.stat-icon.users { background: rgba(192, 132, 252, 0.1); color: var(--accent-purple); }
|
||||
.stat-icon.convos { background: rgba(255, 196, 7, 0.06); color: #FFAB00; }
|
||||
.stat-icon.visits { background: rgba(74, 222, 128, 0.1); color: var(--accent-green); }
|
||||
.stat-icon.unique { background: rgba(248, 113, 113, 0.1); color: var(--accent-red); }
|
||||
|
||||
.stat-label {
|
||||
display: block;
|
||||
|
|
|
|||
|
|
@ -94,6 +94,14 @@
|
|||
<div class="stat-icon convos"><i data-lucide="message-square"></i></div>
|
||||
<div><span class="stat-label">Conversations</span><span class="stat-value" id="conversations">--</span></div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon visits"><i data-lucide="log-in"></i></div>
|
||||
<div><span class="stat-label">Visits</span><span class="stat-value" id="visits">--</span></div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-icon unique"><i data-lucide="user-check"></i></div>
|
||||
<div><span class="stat-label">Unique Users</span><span class="stat-value" id="uniqueUsers">--</span></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="charts-grid">
|
||||
<div class="chart-container chart-wide">
|
||||
|
|
|
|||
|
|
@ -176,6 +176,8 @@ async function loadSummary() {
|
|||
document.getElementById('totalTokens').textContent = fmtTokens(d.totalTokens);
|
||||
document.getElementById('activeUsers').textContent = fmtNum(d.activeUsers);
|
||||
document.getElementById('conversations').textContent = fmtNum(d.conversations);
|
||||
document.getElementById('visits').textContent = fmtNum(d.visits);
|
||||
document.getElementById('uniqueUsers').textContent = fmtNum(d.uniqueUsers);
|
||||
} catch (e) { console.error('Summary:', e); }
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ async function getSummary(db, query) {
|
|||
await refreshAgentsCache(db);
|
||||
const { startDate, endDate } = getDateRange(query);
|
||||
|
||||
const [tokenResult, userCount, convCount] = await Promise.all([
|
||||
const [tokenResult, userCount, convCount, visits, uniqueUsers] = await Promise.all([
|
||||
db.collection('transactions').aggregate([
|
||||
{ $match: { createdAt: { $gte: startDate, $lte: endDate } } },
|
||||
{
|
||||
|
|
@ -69,6 +69,12 @@ async function getSummary(db, query) {
|
|||
db.collection('transactions').distinct('conversationId', {
|
||||
createdAt: { $gte: startDate, $lte: endDate }
|
||||
}),
|
||||
db.collection('conversations').countDocuments({
|
||||
createdAt: { $gte: startDate, $lte: endDate }
|
||||
}),
|
||||
db.collection('conversations').distinct('user', {
|
||||
createdAt: { $gte: startDate, $lte: endDate }
|
||||
}),
|
||||
]);
|
||||
|
||||
const t = tokenResult[0] || { totalTokens: 0, totalCost: 0 };
|
||||
|
|
@ -77,6 +83,8 @@ async function getSummary(db, query) {
|
|||
totalCost: t.totalCost / 1_000_000,
|
||||
activeUsers: userCount.length,
|
||||
conversations: convCount.length,
|
||||
visits: visits,
|
||||
uniqueUsers: uniqueUsers.length,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue