fix: add getDevice query, fix IN clause, add error handling to getDeviceStats
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
import { query, getRequestEvent } from '$app/server';
|
import { query, getRequestEvent } from '$app/server';
|
||||||
import { db } from '$lib/server/db';
|
import { db } from '$lib/server/db';
|
||||||
import { device, agentSession, agentStep } from '$lib/server/db/schema';
|
import { device, agentSession, agentStep } from '$lib/server/db/schema';
|
||||||
import { eq, desc, and, count, avg, sql } from 'drizzle-orm';
|
import { eq, desc, and, count, avg, sql, inArray } from 'drizzle-orm';
|
||||||
|
|
||||||
export const listDevices = query(async () => {
|
export const listDevices = query(async () => {
|
||||||
const { locals } = getRequestEvent();
|
const { locals } = getRequestEvent();
|
||||||
@@ -25,7 +25,7 @@ export const listDevices = query(async () => {
|
|||||||
startedAt: agentSession.startedAt
|
startedAt: agentSession.startedAt
|
||||||
})
|
})
|
||||||
.from(agentSession)
|
.from(agentSession)
|
||||||
.where(sql`${agentSession.deviceId} IN ${deviceIds}`)
|
.where(inArray(agentSession.deviceId, deviceIds))
|
||||||
.orderBy(desc(agentSession.startedAt))
|
.orderBy(desc(agentSession.startedAt))
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
@@ -59,39 +59,61 @@ export const listDevices = query(async () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const getDevice = query(async (deviceId: string) => {
|
||||||
|
const { locals } = getRequestEvent();
|
||||||
|
if (!locals.user) return null;
|
||||||
|
|
||||||
|
const rows = await db
|
||||||
|
.select()
|
||||||
|
.from(device)
|
||||||
|
.where(and(eq(device.id, deviceId), eq(device.userId, locals.user.id)))
|
||||||
|
.limit(1);
|
||||||
|
|
||||||
|
if (rows.length === 0) return null;
|
||||||
|
|
||||||
|
const d = rows[0];
|
||||||
|
const info = d.deviceInfo as Record<string, unknown> | null;
|
||||||
|
return {
|
||||||
|
deviceId: d.id,
|
||||||
|
name: d.name,
|
||||||
|
status: d.status,
|
||||||
|
model: (info?.model as string) ?? null,
|
||||||
|
manufacturer: (info?.manufacturer as string) ?? null,
|
||||||
|
androidVersion: (info?.androidVersion as string) ?? null,
|
||||||
|
screenWidth: (info?.screenWidth as number) ?? null,
|
||||||
|
screenHeight: (info?.screenHeight as number) ?? null,
|
||||||
|
batteryLevel: (info?.batteryLevel as number) ?? null,
|
||||||
|
isCharging: (info?.isCharging as boolean) ?? false,
|
||||||
|
lastSeen: d.lastSeen?.toISOString() ?? d.createdAt.toISOString()
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
export const getDeviceStats = query(async (deviceId: string) => {
|
export const getDeviceStats = query(async (deviceId: string) => {
|
||||||
const { locals } = getRequestEvent();
|
const { locals } = getRequestEvent();
|
||||||
if (!locals.user) return null;
|
if (!locals.user) return null;
|
||||||
|
|
||||||
const stats = await db
|
try {
|
||||||
.select({
|
const stats = await db
|
||||||
totalSessions: count(agentSession.id),
|
.select({
|
||||||
successCount: count(sql`CASE WHEN ${agentSession.status} = 'completed' THEN 1 END`),
|
totalSessions: count(agentSession.id),
|
||||||
avgSteps: avg(agentSession.stepsUsed)
|
successCount: count(sql`CASE WHEN ${agentSession.status} = 'completed' THEN 1 END`),
|
||||||
})
|
avgSteps: avg(agentSession.stepsUsed)
|
||||||
.from(agentSession)
|
})
|
||||||
.where(and(eq(agentSession.deviceId, deviceId), eq(agentSession.userId, locals.user.id)));
|
.from(agentSession)
|
||||||
|
.where(and(eq(agentSession.deviceId, deviceId), eq(agentSession.userId, locals.user.id)));
|
||||||
|
|
||||||
const lastSession = await db
|
const s = stats[0];
|
||||||
.select({
|
return {
|
||||||
goal: agentSession.goal,
|
totalSessions: Number(s?.totalSessions ?? 0),
|
||||||
status: agentSession.status,
|
successRate: s?.totalSessions
|
||||||
startedAt: agentSession.startedAt
|
? Math.round((Number(s.successCount) / Number(s.totalSessions)) * 100)
|
||||||
})
|
: 0,
|
||||||
.from(agentSession)
|
avgSteps: Math.round(Number(s?.avgSteps ?? 0))
|
||||||
.where(and(eq(agentSession.deviceId, deviceId), eq(agentSession.userId, locals.user.id)))
|
};
|
||||||
.orderBy(desc(agentSession.startedAt))
|
} catch (err) {
|
||||||
.limit(1);
|
console.error('[getDeviceStats] Query failed:', err);
|
||||||
|
return { totalSessions: 0, successRate: 0, avgSteps: 0 };
|
||||||
const s = stats[0];
|
}
|
||||||
return {
|
|
||||||
totalSessions: Number(s?.totalSessions ?? 0),
|
|
||||||
successRate: s?.totalSessions
|
|
||||||
? Math.round((Number(s.successCount) / Number(s.totalSessions)) * 100)
|
|
||||||
: 0,
|
|
||||||
avgSteps: Math.round(Number(s?.avgSteps ?? 0)),
|
|
||||||
lastGoal: lastSession[0] ?? null
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const listDeviceSessions = query(async (deviceId: string) => {
|
export const listDeviceSessions = query(async (deviceId: string) => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
import {
|
import {
|
||||||
listDevices,
|
getDevice,
|
||||||
listDeviceSessions,
|
listDeviceSessions,
|
||||||
listSessionSteps,
|
listSessionSteps,
|
||||||
getDeviceStats
|
getDeviceStats
|
||||||
@@ -15,15 +15,25 @@
|
|||||||
let activeTab = $state<'overview' | 'sessions' | 'run'>('overview');
|
let activeTab = $state<'overview' | 'sessions' | 'run'>('overview');
|
||||||
|
|
||||||
// Device data from DB
|
// Device data from DB
|
||||||
const allDevices = await listDevices();
|
const deviceData = (await getDevice(deviceId)) as {
|
||||||
const deviceData = allDevices.find((d) => d.deviceId === deviceId);
|
deviceId: string;
|
||||||
|
name: string;
|
||||||
|
status: string;
|
||||||
|
model: string | null;
|
||||||
|
manufacturer: string | null;
|
||||||
|
androidVersion: string | null;
|
||||||
|
screenWidth: number | null;
|
||||||
|
screenHeight: number | null;
|
||||||
|
batteryLevel: number | null;
|
||||||
|
isCharging: boolean;
|
||||||
|
lastSeen: string;
|
||||||
|
} | null;
|
||||||
|
|
||||||
// Device stats
|
// Device stats
|
||||||
const stats = (await getDeviceStats(deviceId)) as {
|
const stats = (await getDeviceStats(deviceId)) as {
|
||||||
totalSessions: number;
|
totalSessions: number;
|
||||||
successRate: number;
|
successRate: number;
|
||||||
avgSteps: number;
|
avgSteps: number;
|
||||||
lastGoal: { goal: string; status: string; startedAt: Date } | null;
|
|
||||||
} | null;
|
} | null;
|
||||||
|
|
||||||
// Session history
|
// Session history
|
||||||
|
|||||||
Reference in New Issue
Block a user