mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-25 12:05:06 +02:00
148 lines
4.2 KiB
TypeScript
148 lines
4.2 KiB
TypeScript
import { keepPreviousData, queryOptions } from "@tanstack/react-query";
|
|
import { api } from "../api";
|
|
|
|
export const dashboardKeys = {
|
|
all: (wsId: string) => ["dashboard", wsId] as const,
|
|
daily: (
|
|
wsId: string,
|
|
days: number,
|
|
projectId: string | null,
|
|
tz: string,
|
|
) => [...dashboardKeys.all(wsId), "daily", days, projectId, tz] as const,
|
|
byAgent: (
|
|
wsId: string,
|
|
days: number,
|
|
projectId: string | null,
|
|
tz: string,
|
|
) => [...dashboardKeys.all(wsId), "by-agent", days, projectId, tz] as const,
|
|
agentRuntime: (
|
|
wsId: string,
|
|
days: number,
|
|
projectId: string | null,
|
|
tz: string,
|
|
) => [...dashboardKeys.all(wsId), "agent-runtime", days, projectId, tz] as const,
|
|
runTimeDaily: (
|
|
wsId: string,
|
|
days: number,
|
|
projectId: string | null,
|
|
tz: string,
|
|
) => [...dashboardKeys.all(wsId), "runtime-daily", days, projectId, tz] as const,
|
|
};
|
|
|
|
// 5-min rollup cadence on the server, 60s background refetch on the client.
|
|
const STALE_TIME = 60 * 1000;
|
|
|
|
// Range changes should keep the previous result mounted so KPI cards and
|
|
// charts transition in place instead of falling back to a full-page skeleton.
|
|
// Scope changes are deliberately excluded: carrying data across workspaces,
|
|
// projects, report kinds, or timezones would briefly display the wrong data.
|
|
function isSameDashboardScope(
|
|
previousKey: readonly unknown[] | undefined,
|
|
nextKey: readonly unknown[],
|
|
): boolean {
|
|
if (!previousKey || previousKey.length !== nextKey.length) return false;
|
|
return previousKey.every(
|
|
(part, index) => index === 3 || Object.is(part, nextKey[index]),
|
|
);
|
|
}
|
|
|
|
// `tz` participates in every dashboard key so a Preferences change
|
|
// repoints the cache. All four series — token rollups and the
|
|
// atq.completed_at-based run-time series — slice their day boundary in
|
|
// the viewer's tz, so the four dashboard tabs always agree.
|
|
export function dashboardUsageDailyOptions(
|
|
wsId: string,
|
|
days: number,
|
|
projectId: string | null,
|
|
tz: string,
|
|
) {
|
|
const queryKey = dashboardKeys.daily(wsId, days, projectId, tz);
|
|
return queryOptions({
|
|
queryKey,
|
|
queryFn: () =>
|
|
api.getDashboardUsageDaily({
|
|
days,
|
|
project_id: projectId ?? undefined,
|
|
tz,
|
|
}),
|
|
enabled: !!wsId,
|
|
staleTime: STALE_TIME,
|
|
placeholderData: (previousData, previousQuery) =>
|
|
isSameDashboardScope(previousQuery?.queryKey, queryKey)
|
|
? keepPreviousData(previousData)
|
|
: undefined,
|
|
});
|
|
}
|
|
|
|
export function dashboardUsageByAgentOptions(
|
|
wsId: string,
|
|
days: number,
|
|
projectId: string | null,
|
|
tz: string,
|
|
) {
|
|
const queryKey = dashboardKeys.byAgent(wsId, days, projectId, tz);
|
|
return queryOptions({
|
|
queryKey,
|
|
queryFn: () =>
|
|
api.getDashboardUsageByAgent({
|
|
days,
|
|
project_id: projectId ?? undefined,
|
|
tz,
|
|
}),
|
|
enabled: !!wsId,
|
|
staleTime: STALE_TIME,
|
|
placeholderData: (previousData, previousQuery) =>
|
|
isSameDashboardScope(previousQuery?.queryKey, queryKey)
|
|
? keepPreviousData(previousData)
|
|
: undefined,
|
|
});
|
|
}
|
|
|
|
export function dashboardAgentRunTimeOptions(
|
|
wsId: string,
|
|
days: number,
|
|
projectId: string | null,
|
|
tz: string,
|
|
) {
|
|
const queryKey = dashboardKeys.agentRuntime(wsId, days, projectId, tz);
|
|
return queryOptions({
|
|
queryKey,
|
|
queryFn: () =>
|
|
api.getDashboardAgentRunTime({
|
|
days,
|
|
project_id: projectId ?? undefined,
|
|
tz,
|
|
}),
|
|
enabled: !!wsId,
|
|
staleTime: STALE_TIME,
|
|
placeholderData: (previousData, previousQuery) =>
|
|
isSameDashboardScope(previousQuery?.queryKey, queryKey)
|
|
? keepPreviousData(previousData)
|
|
: undefined,
|
|
});
|
|
}
|
|
|
|
export function dashboardRunTimeDailyOptions(
|
|
wsId: string,
|
|
days: number,
|
|
projectId: string | null,
|
|
tz: string,
|
|
) {
|
|
const queryKey = dashboardKeys.runTimeDaily(wsId, days, projectId, tz);
|
|
return queryOptions({
|
|
queryKey,
|
|
queryFn: () =>
|
|
api.getDashboardRunTimeDaily({
|
|
days,
|
|
project_id: projectId ?? undefined,
|
|
tz,
|
|
}),
|
|
enabled: !!wsId,
|
|
staleTime: STALE_TIME,
|
|
placeholderData: (previousData, previousQuery) =>
|
|
isSameDashboardScope(previousQuery?.queryKey, queryKey)
|
|
? keepPreviousData(previousData)
|
|
: undefined,
|
|
});
|
|
}
|