Skip to content

Commit f00c1e4

Browse files
committed
Fix bug to compute usage metrics
1 parent 343bc0a commit f00c1e4

File tree

4 files changed

+49
-8
lines changed

4 files changed

+49
-8
lines changed

services/analytics/app/components/templates-table.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export function TemplatesTable({ templates }: TemplatesTableProps) {
5252
</Tooltip>
5353
</th>
5454
<th className="px-6 py-4 text-right text-xs font-semibold text-slate-700 dark:text-slate-300 uppercase tracking-wider">
55-
<Tooltip content="Sum of all workspace lifetime hours (from creation to now) for this template" position="right">
55+
<Tooltip content="Sum of workspace usage hours (time from first connection to last connection) for this template" position="right">
5656
Total Hours
5757
</Tooltip>
5858
</th>

services/analytics/app/template/[templateName]/template-teams-content.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ export default function TemplateTeamsContent({ user, templateName }: TemplateTea
215215
</Tooltip>
216216
</th>
217217
<th className="px-6 py-4 text-right text-xs font-semibold text-slate-700 dark:text-slate-300 uppercase tracking-wider">
218-
<Tooltip content="Sum of all workspace lifetime hours for this team">
218+
<Tooltip content="Sum of workspace usage hours (time from first connection to last connection) for this team">
219219
Total Hours
220220
</Tooltip>
221221
</th>

services/analytics/lib/metrics.ts

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,47 @@ function hoursBetween(date1: Date, date2: Date): number {
3838
return Math.floor(diffTime / (1000 * 60 * 60));
3939
}
4040

41+
/**
42+
* Calculate workspace usage hours based on agent connection window
43+
* Uses first_connected_at to last_connected_at for more accurate usage tracking
44+
*/
45+
function calculateWorkspaceUsageHours(workspace: CoderWorkspace): number {
46+
try {
47+
const resources = workspace.latest_build?.resources || [];
48+
let earliestConnection: Date | null = null;
49+
let latestConnection: Date | null = null;
50+
51+
for (const resource of resources) {
52+
const agents = resource.agents || [];
53+
for (const agent of agents) {
54+
if (agent.first_connected_at) {
55+
const firstConnected = new Date(agent.first_connected_at);
56+
if (!earliestConnection || firstConnected < earliestConnection) {
57+
earliestConnection = firstConnected;
58+
}
59+
}
60+
if (agent.last_connected_at) {
61+
const lastConnected = new Date(agent.last_connected_at);
62+
if (!latestConnection || lastConnected > latestConnection) {
63+
latestConnection = lastConnected;
64+
}
65+
}
66+
}
67+
}
68+
69+
// If we have both connection timestamps, calculate the usage window
70+
if (earliestConnection && latestConnection) {
71+
return hoursBetween(earliestConnection, latestConnection);
72+
}
73+
74+
// Fallback: if no connections yet, workspace has 0 usage hours
75+
return 0;
76+
} catch (error) {
77+
console.warn(`Error calculating usage hours for workspace ${workspace.id}:`, error);
78+
return 0;
79+
}
80+
}
81+
4182
/**
4283
* Classify activity status based on days since last active
4384
*/
@@ -161,7 +202,7 @@ export function enrichWorkspaceData(
161202
const lastActive = getLastActiveTimestamp(workspace);
162203
const daysSinceActive = daysBetween(new Date(lastActive), now);
163204
const daysSinceCreated = daysBetween(new Date(workspace.created_at), now);
164-
const workspaceHours = hoursBetween(new Date(workspace.created_at), now);
205+
const workspaceHours = calculateWorkspaceUsageHours(workspace);
165206

166207
// Determine full name
167208
let ownerName = workspace.owner_name;

services/analytics/lib/types.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ export interface WorkspaceMetrics {
123123
last_build_at: string;
124124
days_since_created: number;
125125
days_since_active: number;
126-
workspace_hours: number; // Total lifetime hours (from creation to now)
126+
workspace_hours: number; // Total usage hours (from first connection to last connection)
127127

128128
// Build metrics
129129
total_builds: number;
@@ -141,8 +141,8 @@ export interface TeamMetrics {
141141
unique_active_users: number; // Number of unique users with activity in last 7 days
142142

143143
// Time-based metrics
144-
total_workspace_hours: number; // Sum of all workspace lifetime hours
145-
avg_workspace_hours: number; // Average workspace lifetime hours
144+
total_workspace_hours: number; // Sum of all workspace usage hours (first to last connection)
145+
avg_workspace_hours: number; // Average workspace usage hours (first to last connection)
146146
active_days: number; // Number of unique days with workspace activity
147147

148148
// Template breakdown
@@ -189,8 +189,8 @@ export interface TemplateMetrics {
189189
total_workspaces: number;
190190
active_workspaces: number;
191191
unique_active_users: number; // Number of unique users with activity in last 7 days
192-
total_workspace_hours: number; // Sum of all workspace lifetime hours for this template
193-
avg_workspace_hours: number; // Average workspace lifetime hours
192+
total_workspace_hours: number; // Sum of workspace usage hours (first to last connection) for this template
193+
avg_workspace_hours: number; // Average workspace usage hours (first to last connection)
194194
team_distribution: Record<string, number>;
195195
}
196196

0 commit comments

Comments
 (0)