@ottocode/web-sdk 0.1.277 → 0.1.279
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.
- package/dist/components/dashboard/UsageDashboard.d.ts +6 -0
- package/dist/components/dashboard/UsageDashboard.d.ts.map +1 -0
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.d.ts.map +1 -1
- package/dist/components/index.js +1042 -5
- package/dist/components/index.js.map +10 -8
- package/dist/components/settings/SettingsSidebar.d.ts +11 -1
- package/dist/components/settings/SettingsSidebar.d.ts.map +1 -1
- package/dist/hooks/index.js +43 -3
- package/dist/hooks/index.js.map +7 -6
- package/dist/hooks/usePreferences.d.ts +1 -0
- package/dist/hooks/usePreferences.d.ts.map +1 -1
- package/dist/index.js +1088 -39
- package/dist/index.js.map +11 -8
- package/dist/lib/api-client/index.d.ts +2 -0
- package/dist/lib/api-client/index.d.ts.map +1 -1
- package/dist/lib/api-client/usage.d.ts +8 -0
- package/dist/lib/api-client/usage.d.ts.map +1 -0
- package/dist/lib/index.js +37 -1
- package/dist/lib/index.js.map +6 -5
- package/dist/lib/platform.d.ts +1 -0
- package/dist/lib/platform.d.ts.map +1 -1
- package/dist/stores/index.d.ts +1 -0
- package/dist/stores/index.d.ts.map +1 -1
- package/dist/stores/index.js +12 -1
- package/dist/stores/index.js.map +5 -4
- package/dist/stores/rightRailStore.d.ts +20 -0
- package/dist/stores/rightRailStore.d.ts.map +1 -0
- package/package.json +3 -3
package/dist/components/index.js
CHANGED
|
@@ -326,6 +326,15 @@ function hasPlatformOpenUrl() {
|
|
|
326
326
|
function hasPlatformSystemFonts() {
|
|
327
327
|
return !!getPlatformWindow()?.OTTO_LIST_SYSTEM_FONTS;
|
|
328
328
|
}
|
|
329
|
+
function isPlatformDesktop() {
|
|
330
|
+
if (typeof window === "undefined")
|
|
331
|
+
return false;
|
|
332
|
+
try {
|
|
333
|
+
return "__TAURI__" in window || "__TAURI_INTERNALS__" in window || "__TAURI_METADATA__" in window;
|
|
334
|
+
} catch {
|
|
335
|
+
return false;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
329
338
|
|
|
330
339
|
// src/lib/open-url.ts
|
|
331
340
|
function openUrl(url) {
|
|
@@ -1941,6 +1950,30 @@ var skillsMixin = {
|
|
|
1941
1950
|
}
|
|
1942
1951
|
};
|
|
1943
1952
|
|
|
1953
|
+
// src/lib/api-client/usage.ts
|
|
1954
|
+
import {
|
|
1955
|
+
getUsageStats as apiGetUsageStats,
|
|
1956
|
+
getGlobalUsageStats as apiGetGlobalUsageStats
|
|
1957
|
+
} from "@ottocode/api";
|
|
1958
|
+
var usageMixin = {
|
|
1959
|
+
async getUsageStats() {
|
|
1960
|
+
const { data, error } = await apiGetUsageStats();
|
|
1961
|
+
if (error)
|
|
1962
|
+
throw new Error(extractErrorMessage(error));
|
|
1963
|
+
if (!data)
|
|
1964
|
+
throw new Error("Empty response from /v1/usage/stats");
|
|
1965
|
+
return data;
|
|
1966
|
+
},
|
|
1967
|
+
async getGlobalUsageStats() {
|
|
1968
|
+
const { data, error } = await apiGetGlobalUsageStats();
|
|
1969
|
+
if (error)
|
|
1970
|
+
throw new Error(extractErrorMessage(error));
|
|
1971
|
+
if (!data)
|
|
1972
|
+
throw new Error("Empty response from /v1/usage/stats/global");
|
|
1973
|
+
return data;
|
|
1974
|
+
}
|
|
1975
|
+
};
|
|
1976
|
+
|
|
1944
1977
|
// src/lib/api-client/index.ts
|
|
1945
1978
|
class ApiClient {
|
|
1946
1979
|
getSessions = sessionsMixin.getSessions;
|
|
@@ -2031,6 +2064,8 @@ class ApiClient {
|
|
|
2031
2064
|
getSkillFileContent = skillsMixin.getSkillFileContent;
|
|
2032
2065
|
getSkillsConfig = skillsMixin.getSkillsConfig;
|
|
2033
2066
|
updateSkillsConfig = skillsMixin.updateSkillsConfig;
|
|
2067
|
+
getUsageStats = usageMixin.getUsageStats;
|
|
2068
|
+
getGlobalUsageStats = usageMixin.getGlobalUsageStats;
|
|
2034
2069
|
}
|
|
2035
2070
|
var apiClient = new ApiClient;
|
|
2036
2071
|
|
|
@@ -2092,7 +2127,8 @@ var DEFAULT_FONT_FAMILY = "IBM Plex Mono";
|
|
|
2092
2127
|
var DEFAULT_STORED_PREFERENCES = {
|
|
2093
2128
|
vimMode: false,
|
|
2094
2129
|
compactThread: true,
|
|
2095
|
-
fontFamily: DEFAULT_FONT_FAMILY
|
|
2130
|
+
fontFamily: DEFAULT_FONT_FAMILY,
|
|
2131
|
+
smartEdges: true
|
|
2096
2132
|
};
|
|
2097
2133
|
function cssFontFamily(fontFamily) {
|
|
2098
2134
|
const trimmed = fontFamily.trim();
|
|
@@ -2125,7 +2161,8 @@ function resolveInitialPreferences() {
|
|
|
2125
2161
|
return {
|
|
2126
2162
|
vimMode: typeof parsed.vimMode === "boolean" ? parsed.vimMode : DEFAULT_STORED_PREFERENCES.vimMode,
|
|
2127
2163
|
compactThread: typeof parsed.compactThread === "boolean" ? parsed.compactThread : DEFAULT_STORED_PREFERENCES.compactThread,
|
|
2128
|
-
fontFamily: typeof parsed.fontFamily === "string" && parsed.fontFamily.trim() ? parsed.fontFamily.trim() : DEFAULT_STORED_PREFERENCES.fontFamily
|
|
2164
|
+
fontFamily: typeof parsed.fontFamily === "string" && parsed.fontFamily.trim() ? parsed.fontFamily.trim() : DEFAULT_STORED_PREFERENCES.fontFamily,
|
|
2165
|
+
smartEdges: typeof parsed.smartEdges === "boolean" ? parsed.smartEdges : DEFAULT_STORED_PREFERENCES.smartEdges
|
|
2129
2166
|
};
|
|
2130
2167
|
}
|
|
2131
2168
|
} catch (error) {
|
|
@@ -2180,6 +2217,9 @@ function usePreferences() {
|
|
|
2180
2217
|
if (updates.fontFamily !== undefined) {
|
|
2181
2218
|
localUpdates.fontFamily = updates.fontFamily.trim() || DEFAULT_FONT_FAMILY;
|
|
2182
2219
|
}
|
|
2220
|
+
if (updates.smartEdges !== undefined) {
|
|
2221
|
+
localUpdates.smartEdges = updates.smartEdges;
|
|
2222
|
+
}
|
|
2183
2223
|
if (Object.keys(localUpdates).length > 0) {
|
|
2184
2224
|
updateStore(localUpdates);
|
|
2185
2225
|
}
|
|
@@ -23748,7 +23788,8 @@ import {
|
|
|
23748
23788
|
Check as Check11,
|
|
23749
23789
|
Key,
|
|
23750
23790
|
Type,
|
|
23751
|
-
Sparkles as Sparkles6
|
|
23791
|
+
Sparkles as Sparkles6,
|
|
23792
|
+
BarChart3
|
|
23752
23793
|
} from "lucide-react";
|
|
23753
23794
|
import { QRCodeSVG } from "qrcode.react";
|
|
23754
23795
|
|
|
@@ -24580,6 +24621,7 @@ function PreferencesModal({ isOpen, onClose }) {
|
|
|
24580
24621
|
const { data: config2 } = useConfig();
|
|
24581
24622
|
const { preferences: preferences2, updatePreferences } = usePreferences();
|
|
24582
24623
|
const updateDefaults = useUpdateDefaults();
|
|
24624
|
+
const isDesktop = isPlatformDesktop();
|
|
24583
24625
|
return /* @__PURE__ */ jsx96(Modal, {
|
|
24584
24626
|
isOpen,
|
|
24585
24627
|
onClose,
|
|
@@ -24609,6 +24651,11 @@ function PreferencesModal({ isOpen, onClose }) {
|
|
|
24609
24651
|
checked: preferences2.fullWidthContent,
|
|
24610
24652
|
onChange: (checked) => updatePreferences({ fullWidthContent: checked })
|
|
24611
24653
|
}),
|
|
24654
|
+
isDesktop ? /* @__PURE__ */ jsx96(ToggleRow, {
|
|
24655
|
+
label: "Smart Sidebar Edges",
|
|
24656
|
+
checked: preferences2.smartEdges,
|
|
24657
|
+
onChange: (checked) => updatePreferences({ smartEdges: checked })
|
|
24658
|
+
}) : null,
|
|
24612
24659
|
/* @__PURE__ */ jsx96(FontPickerRow, {
|
|
24613
24660
|
value: preferences2.fontFamily,
|
|
24614
24661
|
onChange: (fontFamily) => updatePreferences({ fontFamily })
|
|
@@ -24693,7 +24740,9 @@ function PreferencesModal({ isOpen, onClose }) {
|
|
|
24693
24740
|
})
|
|
24694
24741
|
});
|
|
24695
24742
|
}
|
|
24696
|
-
var SettingsSidebar = memo34(function SettingsSidebar2(
|
|
24743
|
+
var SettingsSidebar = memo34(function SettingsSidebar2({
|
|
24744
|
+
onOpenDashboard
|
|
24745
|
+
} = {}) {
|
|
24697
24746
|
const isExpanded = useSettingsStore((state) => state.isExpanded);
|
|
24698
24747
|
const collapseSidebar = useSettingsStore((state) => state.collapseSidebar);
|
|
24699
24748
|
const [isPreferencesOpen, setIsPreferencesOpen] = useState43(false);
|
|
@@ -24850,6 +24899,35 @@ var SettingsSidebar = memo34(function SettingsSidebar2() {
|
|
|
24850
24899
|
/* @__PURE__ */ jsx96(OttoRouterTopupModal, {})
|
|
24851
24900
|
]
|
|
24852
24901
|
}),
|
|
24902
|
+
/* @__PURE__ */ jsxs84("button", {
|
|
24903
|
+
type: "button",
|
|
24904
|
+
onClick: () => {
|
|
24905
|
+
if (onOpenDashboard) {
|
|
24906
|
+
onOpenDashboard();
|
|
24907
|
+
return;
|
|
24908
|
+
}
|
|
24909
|
+
if (typeof window === "undefined")
|
|
24910
|
+
return;
|
|
24911
|
+
const basePathRaw = globalThis.OTTO_ROUTER_BASEPATH ?? "/";
|
|
24912
|
+
const basePath = basePathRaw.replace(/\/+$/, "");
|
|
24913
|
+
const target = `${basePath}/dashboard`.replace(/\/+/g, "/");
|
|
24914
|
+
window.location.assign(target || "/dashboard");
|
|
24915
|
+
},
|
|
24916
|
+
title: "Open usage dashboard",
|
|
24917
|
+
className: "group shrink-0 w-full h-12 px-3 flex items-center gap-2 bg-muted/20 hover:bg-muted/60 border-t border-border transition-colors text-left cursor-pointer",
|
|
24918
|
+
children: [
|
|
24919
|
+
/* @__PURE__ */ jsx96(BarChart3, {
|
|
24920
|
+
className: "w-4 h-4 text-muted-foreground group-hover:text-foreground transition-colors"
|
|
24921
|
+
}),
|
|
24922
|
+
/* @__PURE__ */ jsx96("span", {
|
|
24923
|
+
className: "text-sm flex-1 text-muted-foreground group-hover:text-foreground transition-colors",
|
|
24924
|
+
children: "Usage Dashboard"
|
|
24925
|
+
}),
|
|
24926
|
+
/* @__PURE__ */ jsx96(ChevronRight13, {
|
|
24927
|
+
className: "w-4 h-4 text-muted-foreground group-hover:text-foreground group-hover:translate-x-0.5 transition-all"
|
|
24928
|
+
})
|
|
24929
|
+
]
|
|
24930
|
+
}),
|
|
24853
24931
|
/* @__PURE__ */ jsxs84("button", {
|
|
24854
24932
|
type: "button",
|
|
24855
24933
|
onClick: () => setIsPreferencesOpen(true),
|
|
@@ -31497,11 +31575,970 @@ var OnboardingModal = memo52(function OnboardingModal2({
|
|
|
31497
31575
|
]
|
|
31498
31576
|
});
|
|
31499
31577
|
});
|
|
31578
|
+
// src/components/dashboard/UsageDashboard.tsx
|
|
31579
|
+
import { useCallback as useCallback35, useEffect as useEffect58, useMemo as useMemo31, useState as useState51 } from "react";
|
|
31580
|
+
import { AlertTriangle as AlertTriangle3, ArrowLeft as ArrowLeft2, Globe2 as Globe22, RefreshCw as RefreshCw12 } from "lucide-react";
|
|
31581
|
+
import { jsx as jsx116, jsxs as jsxs103, Fragment as Fragment44 } from "react/jsx-runtime";
|
|
31582
|
+
function formatNumber(n) {
|
|
31583
|
+
if (!Number.isFinite(n) || n === 0)
|
|
31584
|
+
return "0";
|
|
31585
|
+
if (Math.abs(n) >= 1e9)
|
|
31586
|
+
return `${(n / 1e9).toFixed(1)}B`;
|
|
31587
|
+
if (Math.abs(n) >= 1e6)
|
|
31588
|
+
return `${(n / 1e6).toFixed(1)}M`;
|
|
31589
|
+
if (Math.abs(n) >= 1000)
|
|
31590
|
+
return `${(n / 1000).toFixed(1)}k`;
|
|
31591
|
+
return n.toLocaleString();
|
|
31592
|
+
}
|
|
31593
|
+
function formatUsd(n) {
|
|
31594
|
+
if (!Number.isFinite(n) || n === 0)
|
|
31595
|
+
return "$0";
|
|
31596
|
+
if (n < 0.01)
|
|
31597
|
+
return `$${n.toFixed(4)}`;
|
|
31598
|
+
if (n < 1)
|
|
31599
|
+
return `$${n.toFixed(3)}`;
|
|
31600
|
+
if (n < 100)
|
|
31601
|
+
return `$${n.toFixed(2)}`;
|
|
31602
|
+
return `$${n.toFixed(0)}`;
|
|
31603
|
+
}
|
|
31604
|
+
function authLabel(t) {
|
|
31605
|
+
if (t === "oauth")
|
|
31606
|
+
return "oauth";
|
|
31607
|
+
if (t === "subscription")
|
|
31608
|
+
return "sub";
|
|
31609
|
+
if (t === "wallet")
|
|
31610
|
+
return "wallet";
|
|
31611
|
+
if (t === "api")
|
|
31612
|
+
return "api";
|
|
31613
|
+
return "—";
|
|
31614
|
+
}
|
|
31615
|
+
function authColor(t) {
|
|
31616
|
+
if (t === "oauth")
|
|
31617
|
+
return "text-emerald-400";
|
|
31618
|
+
if (t === "subscription")
|
|
31619
|
+
return "text-violet-400";
|
|
31620
|
+
if (t === "wallet")
|
|
31621
|
+
return "text-fuchsia-400";
|
|
31622
|
+
if (t === "api")
|
|
31623
|
+
return "text-sky-400";
|
|
31624
|
+
return "text-muted-foreground";
|
|
31625
|
+
}
|
|
31626
|
+
function DailyChart({ data }) {
|
|
31627
|
+
const [tab, setTab] = useState51("cost");
|
|
31628
|
+
const [hover, setHover] = useState51(null);
|
|
31629
|
+
const max = useMemo31(() => {
|
|
31630
|
+
if (tab === "tokens") {
|
|
31631
|
+
return data.reduce((m, d) => Math.max(m, d.inputTokens + d.outputTokens), 0);
|
|
31632
|
+
}
|
|
31633
|
+
return data.reduce((m, d) => Math.max(m, d.notionalCostUsd), 0);
|
|
31634
|
+
}, [data, tab]);
|
|
31635
|
+
if (data.length === 0) {
|
|
31636
|
+
return /* @__PURE__ */ jsx116("div", {
|
|
31637
|
+
className: "h-44 flex items-center justify-center text-xs text-muted-foreground",
|
|
31638
|
+
children: "No activity yet"
|
|
31639
|
+
});
|
|
31640
|
+
}
|
|
31641
|
+
const focus = hover != null ? data[hover] : data[data.length - 1];
|
|
31642
|
+
const focusValue = tab === "tokens" ? formatNumber(focus.inputTokens + focus.outputTokens) : formatUsd(focus.notionalCostUsd);
|
|
31643
|
+
const focusSub = tab === "tokens" ? `${formatNumber(focus.inputTokens)} in · ${formatNumber(focus.outputTokens)} out` : focus.costUsd > 0 ? `${formatUsd(focus.costUsd)} pay-as-you-go · ${formatUsd(focus.notionalCostUsd - focus.costUsd)} via plans` : `${formatUsd(focus.notionalCostUsd)} via plans`;
|
|
31644
|
+
return /* @__PURE__ */ jsxs103("div", {
|
|
31645
|
+
children: [
|
|
31646
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
31647
|
+
className: "flex items-baseline justify-between gap-4 mb-4",
|
|
31648
|
+
children: [
|
|
31649
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
31650
|
+
className: "min-w-0",
|
|
31651
|
+
children: [
|
|
31652
|
+
/* @__PURE__ */ jsx116("div", {
|
|
31653
|
+
className: "text-[10px] uppercase tracking-[0.12em] text-muted-foreground",
|
|
31654
|
+
children: focus.date
|
|
31655
|
+
}),
|
|
31656
|
+
/* @__PURE__ */ jsx116("div", {
|
|
31657
|
+
className: "text-xl font-semibold tabular-nums mt-0.5 truncate",
|
|
31658
|
+
children: focusValue
|
|
31659
|
+
}),
|
|
31660
|
+
/* @__PURE__ */ jsx116("div", {
|
|
31661
|
+
className: "text-[11px] text-muted-foreground tabular-nums mt-0.5 truncate",
|
|
31662
|
+
children: focusSub
|
|
31663
|
+
})
|
|
31664
|
+
]
|
|
31665
|
+
}),
|
|
31666
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
31667
|
+
className: "shrink-0 inline-flex p-0.5 rounded-md border border-border bg-muted/30 text-[11px]",
|
|
31668
|
+
children: [
|
|
31669
|
+
/* @__PURE__ */ jsx116("button", {
|
|
31670
|
+
type: "button",
|
|
31671
|
+
onClick: () => setTab("cost"),
|
|
31672
|
+
className: `px-2.5 py-1 rounded transition-colors ${tab === "cost" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
31673
|
+
children: "Cost"
|
|
31674
|
+
}),
|
|
31675
|
+
/* @__PURE__ */ jsx116("button", {
|
|
31676
|
+
type: "button",
|
|
31677
|
+
onClick: () => setTab("tokens"),
|
|
31678
|
+
className: `px-2.5 py-1 rounded transition-colors ${tab === "tokens" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
31679
|
+
children: "Tokens"
|
|
31680
|
+
})
|
|
31681
|
+
]
|
|
31682
|
+
})
|
|
31683
|
+
]
|
|
31684
|
+
}),
|
|
31685
|
+
tab === "cost" ? /* @__PURE__ */ jsx116(CostChart, {
|
|
31686
|
+
data,
|
|
31687
|
+
max,
|
|
31688
|
+
hover,
|
|
31689
|
+
onHover: setHover
|
|
31690
|
+
}) : /* @__PURE__ */ jsx116(TokenChart, {
|
|
31691
|
+
data,
|
|
31692
|
+
max,
|
|
31693
|
+
hover,
|
|
31694
|
+
onHover: setHover
|
|
31695
|
+
}),
|
|
31696
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
31697
|
+
className: "mt-3 flex items-center justify-between text-[10px] text-muted-foreground font-mono",
|
|
31698
|
+
children: [
|
|
31699
|
+
/* @__PURE__ */ jsx116("span", {
|
|
31700
|
+
children: data[0]?.date
|
|
31701
|
+
}),
|
|
31702
|
+
tab === "cost" ? /* @__PURE__ */ jsxs103("span", {
|
|
31703
|
+
className: "flex items-center gap-3",
|
|
31704
|
+
children: [
|
|
31705
|
+
/* @__PURE__ */ jsx116(Dot, {
|
|
31706
|
+
color: "bg-sky-400",
|
|
31707
|
+
label: "api"
|
|
31708
|
+
}),
|
|
31709
|
+
/* @__PURE__ */ jsx116(Dot, {
|
|
31710
|
+
color: "bg-emerald-400/70",
|
|
31711
|
+
label: "oauth"
|
|
31712
|
+
}),
|
|
31713
|
+
/* @__PURE__ */ jsx116(Dot, {
|
|
31714
|
+
color: "bg-violet-400/70",
|
|
31715
|
+
label: "sub"
|
|
31716
|
+
})
|
|
31717
|
+
]
|
|
31718
|
+
}) : /* @__PURE__ */ jsxs103("span", {
|
|
31719
|
+
className: "flex items-center gap-3",
|
|
31720
|
+
children: [
|
|
31721
|
+
/* @__PURE__ */ jsx116(Dot, {
|
|
31722
|
+
color: "bg-muted-foreground/60",
|
|
31723
|
+
label: "input"
|
|
31724
|
+
}),
|
|
31725
|
+
/* @__PURE__ */ jsx116(Dot, {
|
|
31726
|
+
color: "bg-foreground/80",
|
|
31727
|
+
label: "output"
|
|
31728
|
+
})
|
|
31729
|
+
]
|
|
31730
|
+
}),
|
|
31731
|
+
/* @__PURE__ */ jsx116("span", {
|
|
31732
|
+
children: data[data.length - 1]?.date
|
|
31733
|
+
})
|
|
31734
|
+
]
|
|
31735
|
+
})
|
|
31736
|
+
]
|
|
31737
|
+
});
|
|
31738
|
+
}
|
|
31739
|
+
function CostChart({ data, max, hover, onHover }) {
|
|
31740
|
+
return /* @__PURE__ */ jsx116("div", {
|
|
31741
|
+
role: "img",
|
|
31742
|
+
"aria-label": "Daily cost chart",
|
|
31743
|
+
className: "flex items-end gap-[3px] h-44 select-none",
|
|
31744
|
+
onMouseLeave: () => onHover(null),
|
|
31745
|
+
children: data.map((d, i) => {
|
|
31746
|
+
const notional = d.notionalCostUsd;
|
|
31747
|
+
const heightPct = max > 0 ? Math.max(2, notional / max * 100) : 2;
|
|
31748
|
+
const apiPct = notional > 0 ? d.notionalByAuth.api / notional * 100 : 0;
|
|
31749
|
+
const oauthPct = notional > 0 ? d.notionalByAuth.oauth / notional * 100 : 0;
|
|
31750
|
+
const subPct = notional > 0 ? d.notionalByAuth.subscription / notional * 100 : 0;
|
|
31751
|
+
const active = hover === i;
|
|
31752
|
+
return /* @__PURE__ */ jsx116("button", {
|
|
31753
|
+
type: "button",
|
|
31754
|
+
onMouseEnter: () => onHover(i),
|
|
31755
|
+
onFocus: () => onHover(i),
|
|
31756
|
+
className: "flex-1 h-full flex flex-col justify-end min-w-0 group cursor-default",
|
|
31757
|
+
children: /* @__PURE__ */ jsxs103("div", {
|
|
31758
|
+
className: `w-full rounded-sm overflow-hidden flex flex-col-reverse transition-all ${active ? "opacity-100" : "opacity-90 group-hover:opacity-100"}`,
|
|
31759
|
+
style: { height: `${heightPct}%` },
|
|
31760
|
+
children: [
|
|
31761
|
+
apiPct > 0 && /* @__PURE__ */ jsx116("div", {
|
|
31762
|
+
className: "bg-sky-400",
|
|
31763
|
+
style: { height: `${apiPct}%` }
|
|
31764
|
+
}),
|
|
31765
|
+
oauthPct > 0 && /* @__PURE__ */ jsx116("div", {
|
|
31766
|
+
className: "bg-emerald-400/70",
|
|
31767
|
+
style: {
|
|
31768
|
+
height: `${oauthPct}%`,
|
|
31769
|
+
backgroundImage: "repeating-linear-gradient(45deg, rgba(255,255,255,0.08) 0 2px, transparent 2px 4px)"
|
|
31770
|
+
}
|
|
31771
|
+
}),
|
|
31772
|
+
subPct > 0 && /* @__PURE__ */ jsx116("div", {
|
|
31773
|
+
className: "bg-violet-400/70",
|
|
31774
|
+
style: {
|
|
31775
|
+
height: `${subPct}%`,
|
|
31776
|
+
backgroundImage: "repeating-linear-gradient(45deg, rgba(255,255,255,0.08) 0 2px, transparent 2px 4px)"
|
|
31777
|
+
}
|
|
31778
|
+
}),
|
|
31779
|
+
notional === 0 && d.messages > 0 && /* @__PURE__ */ jsx116("div", {
|
|
31780
|
+
className: "bg-muted-foreground/30 h-full"
|
|
31781
|
+
})
|
|
31782
|
+
]
|
|
31783
|
+
})
|
|
31784
|
+
}, d.date);
|
|
31785
|
+
})
|
|
31786
|
+
});
|
|
31787
|
+
}
|
|
31788
|
+
function TokenChart({ data, max, hover, onHover }) {
|
|
31789
|
+
return /* @__PURE__ */ jsx116("div", {
|
|
31790
|
+
role: "img",
|
|
31791
|
+
"aria-label": "Daily tokens chart",
|
|
31792
|
+
className: "flex items-end gap-[3px] h-44 select-none",
|
|
31793
|
+
onMouseLeave: () => onHover(null),
|
|
31794
|
+
children: data.map((d, i) => {
|
|
31795
|
+
const total = d.inputTokens + d.outputTokens;
|
|
31796
|
+
const heightPct = max > 0 ? Math.max(2, total / max * 100) : 2;
|
|
31797
|
+
const inputPct = total > 0 ? d.inputTokens / total * 100 : 0;
|
|
31798
|
+
const outputPct = total > 0 ? d.outputTokens / total * 100 : 0;
|
|
31799
|
+
const active = hover === i;
|
|
31800
|
+
return /* @__PURE__ */ jsx116("button", {
|
|
31801
|
+
type: "button",
|
|
31802
|
+
onMouseEnter: () => onHover(i),
|
|
31803
|
+
onFocus: () => onHover(i),
|
|
31804
|
+
className: "flex-1 h-full flex flex-col justify-end min-w-0 group cursor-default",
|
|
31805
|
+
children: /* @__PURE__ */ jsxs103("div", {
|
|
31806
|
+
className: `w-full rounded-sm overflow-hidden flex flex-col-reverse transition-all ${active ? "opacity-100" : "opacity-90 group-hover:opacity-100"}`,
|
|
31807
|
+
style: { height: `${heightPct}%` },
|
|
31808
|
+
children: [
|
|
31809
|
+
inputPct > 0 && /* @__PURE__ */ jsx116("div", {
|
|
31810
|
+
className: "bg-muted-foreground/60",
|
|
31811
|
+
style: { height: `${inputPct}%` }
|
|
31812
|
+
}),
|
|
31813
|
+
outputPct > 0 && /* @__PURE__ */ jsx116("div", {
|
|
31814
|
+
className: "bg-foreground/80",
|
|
31815
|
+
style: { height: `${outputPct}%` }
|
|
31816
|
+
})
|
|
31817
|
+
]
|
|
31818
|
+
})
|
|
31819
|
+
}, d.date);
|
|
31820
|
+
})
|
|
31821
|
+
});
|
|
31822
|
+
}
|
|
31823
|
+
function Dot({ color, label }) {
|
|
31824
|
+
return /* @__PURE__ */ jsxs103("span", {
|
|
31825
|
+
className: "flex items-center gap-1",
|
|
31826
|
+
children: [
|
|
31827
|
+
/* @__PURE__ */ jsx116("span", {
|
|
31828
|
+
className: `size-1.5 rounded-full ${color}`
|
|
31829
|
+
}),
|
|
31830
|
+
/* @__PURE__ */ jsx116("span", {
|
|
31831
|
+
children: label
|
|
31832
|
+
})
|
|
31833
|
+
]
|
|
31834
|
+
});
|
|
31835
|
+
}
|
|
31836
|
+
function SplitRow({
|
|
31837
|
+
color,
|
|
31838
|
+
label,
|
|
31839
|
+
msgs,
|
|
31840
|
+
value,
|
|
31841
|
+
total
|
|
31842
|
+
}) {
|
|
31843
|
+
const pct = total > 0 ? msgs / total * 100 : 0;
|
|
31844
|
+
return /* @__PURE__ */ jsxs103("div", {
|
|
31845
|
+
className: "flex items-center gap-3 py-2",
|
|
31846
|
+
children: [
|
|
31847
|
+
/* @__PURE__ */ jsx116("span", {
|
|
31848
|
+
className: "text-xs text-muted-foreground w-20 shrink-0",
|
|
31849
|
+
children: label
|
|
31850
|
+
}),
|
|
31851
|
+
/* @__PURE__ */ jsx116("div", {
|
|
31852
|
+
className: "flex-1 h-1.5 rounded-full bg-muted/40 overflow-hidden",
|
|
31853
|
+
children: /* @__PURE__ */ jsx116("div", {
|
|
31854
|
+
className: `h-full ${color} transition-all duration-500`,
|
|
31855
|
+
style: { width: `${pct}%` }
|
|
31856
|
+
})
|
|
31857
|
+
}),
|
|
31858
|
+
/* @__PURE__ */ jsxs103("span", {
|
|
31859
|
+
className: "text-[11px] text-muted-foreground tabular-nums w-20 text-right shrink-0",
|
|
31860
|
+
children: [
|
|
31861
|
+
formatNumber(msgs),
|
|
31862
|
+
" msgs"
|
|
31863
|
+
]
|
|
31864
|
+
}),
|
|
31865
|
+
/* @__PURE__ */ jsx116("span", {
|
|
31866
|
+
className: "text-sm font-medium tabular-nums w-20 text-right shrink-0 text-foreground",
|
|
31867
|
+
children: formatUsd(value)
|
|
31868
|
+
})
|
|
31869
|
+
]
|
|
31870
|
+
});
|
|
31871
|
+
}
|
|
31872
|
+
function AuthSplit({ stats }) {
|
|
31873
|
+
const total = stats.totals.messagesByAuth.api + stats.totals.messagesByAuth.oauth + stats.totals.messagesByAuth.subscription;
|
|
31874
|
+
if (total === 0)
|
|
31875
|
+
return /* @__PURE__ */ jsx116("div", {
|
|
31876
|
+
className: "text-xs text-muted-foreground",
|
|
31877
|
+
children: "No activity yet."
|
|
31878
|
+
});
|
|
31879
|
+
const notionalByAuth = { oauth: 0, api: 0, subscription: 0 };
|
|
31880
|
+
for (const p of stats.providers) {
|
|
31881
|
+
if (p.authType === "oauth")
|
|
31882
|
+
notionalByAuth.oauth += p.notionalCostUsd;
|
|
31883
|
+
else if (p.authType === "subscription" || p.authType === "wallet")
|
|
31884
|
+
notionalByAuth.subscription += p.notionalCostUsd;
|
|
31885
|
+
else if (p.authType === "api")
|
|
31886
|
+
notionalByAuth.api += p.notionalCostUsd;
|
|
31887
|
+
}
|
|
31888
|
+
const rows = [
|
|
31889
|
+
{
|
|
31890
|
+
key: "api",
|
|
31891
|
+
color: "bg-sky-400",
|
|
31892
|
+
label: "API key",
|
|
31893
|
+
msgs: stats.totals.messagesByAuth.api,
|
|
31894
|
+
value: notionalByAuth.api
|
|
31895
|
+
},
|
|
31896
|
+
{
|
|
31897
|
+
key: "oauth",
|
|
31898
|
+
color: "bg-emerald-400",
|
|
31899
|
+
label: "OAuth",
|
|
31900
|
+
msgs: stats.totals.messagesByAuth.oauth,
|
|
31901
|
+
value: notionalByAuth.oauth
|
|
31902
|
+
},
|
|
31903
|
+
{
|
|
31904
|
+
key: "subscription",
|
|
31905
|
+
color: "bg-violet-400",
|
|
31906
|
+
label: "Subscription",
|
|
31907
|
+
msgs: stats.totals.messagesByAuth.subscription,
|
|
31908
|
+
value: notionalByAuth.subscription
|
|
31909
|
+
}
|
|
31910
|
+
].sort((a, b) => b.value - a.value || b.msgs - a.msgs);
|
|
31911
|
+
return /* @__PURE__ */ jsx116("div", {
|
|
31912
|
+
className: "space-y-0.5",
|
|
31913
|
+
children: rows.map((r) => /* @__PURE__ */ jsx116(SplitRow, {
|
|
31914
|
+
total,
|
|
31915
|
+
color: r.color,
|
|
31916
|
+
label: r.label,
|
|
31917
|
+
msgs: r.msgs,
|
|
31918
|
+
value: r.value
|
|
31919
|
+
}, r.key))
|
|
31920
|
+
});
|
|
31921
|
+
}
|
|
31922
|
+
function ProviderList({ providers }) {
|
|
31923
|
+
if (providers.length === 0) {
|
|
31924
|
+
return /* @__PURE__ */ jsx116("div", {
|
|
31925
|
+
className: "py-10 text-center text-xs text-muted-foreground",
|
|
31926
|
+
children: "No usage yet"
|
|
31927
|
+
});
|
|
31928
|
+
}
|
|
31929
|
+
return /* @__PURE__ */ jsx116("div", {
|
|
31930
|
+
className: "divide-y divide-border/60",
|
|
31931
|
+
children: providers.map((p) => /* @__PURE__ */ jsxs103("div", {
|
|
31932
|
+
className: "flex items-center gap-3 py-2.5 px-1 hover:bg-muted/20 transition-colors",
|
|
31933
|
+
children: [
|
|
31934
|
+
/* @__PURE__ */ jsx116("div", {
|
|
31935
|
+
className: "size-7 shrink-0 rounded-md bg-muted/30 flex items-center justify-center text-muted-foreground",
|
|
31936
|
+
children: /* @__PURE__ */ jsx116(ProviderLogo, {
|
|
31937
|
+
provider: p.provider,
|
|
31938
|
+
size: 16
|
|
31939
|
+
})
|
|
31940
|
+
}),
|
|
31941
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
31942
|
+
className: "flex-1 min-w-0",
|
|
31943
|
+
children: [
|
|
31944
|
+
/* @__PURE__ */ jsx116("div", {
|
|
31945
|
+
className: "text-sm text-foreground truncate capitalize",
|
|
31946
|
+
children: p.provider
|
|
31947
|
+
}),
|
|
31948
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
31949
|
+
className: "text-[10px] text-muted-foreground tabular-nums",
|
|
31950
|
+
children: [
|
|
31951
|
+
formatNumber(p.messages),
|
|
31952
|
+
" msgs ·",
|
|
31953
|
+
" ",
|
|
31954
|
+
/* @__PURE__ */ jsx116("span", {
|
|
31955
|
+
className: authColor(p.authType),
|
|
31956
|
+
children: authLabel(p.authType)
|
|
31957
|
+
})
|
|
31958
|
+
]
|
|
31959
|
+
})
|
|
31960
|
+
]
|
|
31961
|
+
}),
|
|
31962
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
31963
|
+
className: "text-right tabular-nums shrink-0",
|
|
31964
|
+
children: [
|
|
31965
|
+
/* @__PURE__ */ jsx116("div", {
|
|
31966
|
+
className: "text-sm font-medium text-foreground",
|
|
31967
|
+
children: formatUsd(p.notionalCostUsd)
|
|
31968
|
+
}),
|
|
31969
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
31970
|
+
className: "text-[10px] text-muted-foreground",
|
|
31971
|
+
children: [
|
|
31972
|
+
formatNumber(p.inputTokens + p.outputTokens),
|
|
31973
|
+
" tok"
|
|
31974
|
+
]
|
|
31975
|
+
})
|
|
31976
|
+
]
|
|
31977
|
+
})
|
|
31978
|
+
]
|
|
31979
|
+
}, p.provider))
|
|
31980
|
+
});
|
|
31981
|
+
}
|
|
31982
|
+
function ModelList({ models }) {
|
|
31983
|
+
if (models.length === 0) {
|
|
31984
|
+
return /* @__PURE__ */ jsx116("div", {
|
|
31985
|
+
className: "py-10 text-center text-xs text-muted-foreground",
|
|
31986
|
+
children: "No model usage yet"
|
|
31987
|
+
});
|
|
31988
|
+
}
|
|
31989
|
+
return /* @__PURE__ */ jsx116("div", {
|
|
31990
|
+
className: "divide-y divide-border/60",
|
|
31991
|
+
children: models.slice(0, 12).map((m) => /* @__PURE__ */ jsxs103("div", {
|
|
31992
|
+
className: "flex items-center gap-3 py-2.5 px-1 hover:bg-muted/20 transition-colors",
|
|
31993
|
+
children: [
|
|
31994
|
+
/* @__PURE__ */ jsx116("div", {
|
|
31995
|
+
className: "size-7 shrink-0 rounded-md bg-muted/30 flex items-center justify-center text-muted-foreground",
|
|
31996
|
+
children: /* @__PURE__ */ jsx116(ProviderLogo, {
|
|
31997
|
+
provider: m.provider,
|
|
31998
|
+
size: 14
|
|
31999
|
+
})
|
|
32000
|
+
}),
|
|
32001
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32002
|
+
className: "flex-1 min-w-0",
|
|
32003
|
+
children: [
|
|
32004
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32005
|
+
className: "text-sm text-foreground truncate font-mono",
|
|
32006
|
+
children: m.model
|
|
32007
|
+
}),
|
|
32008
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32009
|
+
className: "text-[10px] text-muted-foreground tabular-nums",
|
|
32010
|
+
children: [
|
|
32011
|
+
formatNumber(m.messages),
|
|
32012
|
+
" msgs ·",
|
|
32013
|
+
" ",
|
|
32014
|
+
formatNumber(m.inputTokens + m.outputTokens),
|
|
32015
|
+
" tok"
|
|
32016
|
+
]
|
|
32017
|
+
})
|
|
32018
|
+
]
|
|
32019
|
+
}),
|
|
32020
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32021
|
+
className: "text-right tabular-nums shrink-0",
|
|
32022
|
+
children: [
|
|
32023
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32024
|
+
className: "text-sm font-medium text-foreground",
|
|
32025
|
+
children: formatUsd(m.notionalCostUsd)
|
|
32026
|
+
}),
|
|
32027
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32028
|
+
className: `text-[10px] ${authColor(m.authType)}`,
|
|
32029
|
+
children: authLabel(m.authType)
|
|
32030
|
+
})
|
|
32031
|
+
]
|
|
32032
|
+
})
|
|
32033
|
+
]
|
|
32034
|
+
}, `${m.provider}-${m.model}`))
|
|
32035
|
+
});
|
|
32036
|
+
}
|
|
32037
|
+
function ProjectList({
|
|
32038
|
+
projects
|
|
32039
|
+
}) {
|
|
32040
|
+
if (projects.included.length === 0 && projects.unavailable.length === 0) {
|
|
32041
|
+
return /* @__PURE__ */ jsx116("div", {
|
|
32042
|
+
className: "py-10 text-center text-xs text-muted-foreground",
|
|
32043
|
+
children: "No projects registered yet"
|
|
32044
|
+
});
|
|
32045
|
+
}
|
|
32046
|
+
return /* @__PURE__ */ jsxs103("div", {
|
|
32047
|
+
className: "divide-y divide-border/60",
|
|
32048
|
+
children: [
|
|
32049
|
+
projects.included.map((p) => /* @__PURE__ */ jsxs103("div", {
|
|
32050
|
+
className: "flex items-center gap-3 py-2.5 px-1 hover:bg-muted/20 transition-colors",
|
|
32051
|
+
children: [
|
|
32052
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32053
|
+
className: "flex-1 min-w-0",
|
|
32054
|
+
children: [
|
|
32055
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32056
|
+
className: "text-sm text-foreground truncate",
|
|
32057
|
+
children: p.name
|
|
32058
|
+
}),
|
|
32059
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32060
|
+
className: "text-[10px] text-muted-foreground tabular-nums truncate font-mono",
|
|
32061
|
+
children: p.path
|
|
32062
|
+
})
|
|
32063
|
+
]
|
|
32064
|
+
}),
|
|
32065
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32066
|
+
className: "text-right tabular-nums shrink-0",
|
|
32067
|
+
children: [
|
|
32068
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32069
|
+
className: "text-sm font-medium text-foreground",
|
|
32070
|
+
children: formatUsd(p.notionalCostUsd)
|
|
32071
|
+
}),
|
|
32072
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32073
|
+
className: "text-[10px] text-muted-foreground",
|
|
32074
|
+
children: [
|
|
32075
|
+
formatNumber(p.messages),
|
|
32076
|
+
" msgs"
|
|
32077
|
+
]
|
|
32078
|
+
})
|
|
32079
|
+
]
|
|
32080
|
+
})
|
|
32081
|
+
]
|
|
32082
|
+
}, p.id)),
|
|
32083
|
+
projects.unavailable.map((p) => /* @__PURE__ */ jsxs103("div", {
|
|
32084
|
+
className: "flex items-center gap-3 py-2.5 px-1 opacity-60",
|
|
32085
|
+
title: p.reason,
|
|
32086
|
+
children: [
|
|
32087
|
+
/* @__PURE__ */ jsx116(AlertTriangle3, {
|
|
32088
|
+
className: "size-3.5 text-amber-400 shrink-0"
|
|
32089
|
+
}),
|
|
32090
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32091
|
+
className: "flex-1 min-w-0",
|
|
32092
|
+
children: [
|
|
32093
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32094
|
+
className: "text-sm text-foreground/80 truncate",
|
|
32095
|
+
children: p.name
|
|
32096
|
+
}),
|
|
32097
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32098
|
+
className: "text-[10px] text-muted-foreground truncate font-mono",
|
|
32099
|
+
children: [
|
|
32100
|
+
p.path,
|
|
32101
|
+
" · ",
|
|
32102
|
+
p.reason
|
|
32103
|
+
]
|
|
32104
|
+
})
|
|
32105
|
+
]
|
|
32106
|
+
}),
|
|
32107
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32108
|
+
className: "text-[10px] text-amber-400 shrink-0",
|
|
32109
|
+
children: "unavailable"
|
|
32110
|
+
})
|
|
32111
|
+
]
|
|
32112
|
+
}, p.id))
|
|
32113
|
+
]
|
|
32114
|
+
});
|
|
32115
|
+
}
|
|
32116
|
+
function Section({
|
|
32117
|
+
title,
|
|
32118
|
+
subtitle,
|
|
32119
|
+
right,
|
|
32120
|
+
children,
|
|
32121
|
+
className = ""
|
|
32122
|
+
}) {
|
|
32123
|
+
return /* @__PURE__ */ jsxs103("section", {
|
|
32124
|
+
className: `rounded-2xl border border-border bg-card/60 backdrop-blur-sm ${className}`,
|
|
32125
|
+
children: [
|
|
32126
|
+
(title || right) && /* @__PURE__ */ jsxs103("header", {
|
|
32127
|
+
className: "px-5 pt-4 pb-3 flex items-center justify-between gap-3",
|
|
32128
|
+
children: [
|
|
32129
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32130
|
+
className: "min-w-0",
|
|
32131
|
+
children: [
|
|
32132
|
+
title && /* @__PURE__ */ jsx116("h2", {
|
|
32133
|
+
className: "text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground",
|
|
32134
|
+
children: title
|
|
32135
|
+
}),
|
|
32136
|
+
subtitle && /* @__PURE__ */ jsx116("p", {
|
|
32137
|
+
className: "text-xs text-muted-foreground/70 mt-0.5",
|
|
32138
|
+
children: subtitle
|
|
32139
|
+
})
|
|
32140
|
+
]
|
|
32141
|
+
}),
|
|
32142
|
+
right
|
|
32143
|
+
]
|
|
32144
|
+
}),
|
|
32145
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32146
|
+
className: "px-5 pb-5",
|
|
32147
|
+
children
|
|
32148
|
+
})
|
|
32149
|
+
]
|
|
32150
|
+
});
|
|
32151
|
+
}
|
|
32152
|
+
function UsageDashboard({ onBack }) {
|
|
32153
|
+
const [stats, setStats] = useState51(null);
|
|
32154
|
+
const [loading, setLoading] = useState51(false);
|
|
32155
|
+
const [error, setError] = useState51(null);
|
|
32156
|
+
const [scope, setScope] = useState51("project");
|
|
32157
|
+
const fetchStats = useCallback35(async () => {
|
|
32158
|
+
setLoading(true);
|
|
32159
|
+
setError(null);
|
|
32160
|
+
try {
|
|
32161
|
+
const data = scope === "global" ? await apiClient.getGlobalUsageStats() : await apiClient.getUsageStats();
|
|
32162
|
+
setStats(data);
|
|
32163
|
+
} catch (e) {
|
|
32164
|
+
setError(e instanceof Error ? e.message : "Failed to load usage stats");
|
|
32165
|
+
} finally {
|
|
32166
|
+
setLoading(false);
|
|
32167
|
+
}
|
|
32168
|
+
}, [scope]);
|
|
32169
|
+
useEffect58(() => {
|
|
32170
|
+
fetchStats();
|
|
32171
|
+
}, [fetchStats]);
|
|
32172
|
+
const handleBack = useCallback35(() => {
|
|
32173
|
+
if (onBack)
|
|
32174
|
+
return onBack();
|
|
32175
|
+
if (typeof window === "undefined")
|
|
32176
|
+
return;
|
|
32177
|
+
if (window.history.length > 1)
|
|
32178
|
+
window.history.back();
|
|
32179
|
+
else
|
|
32180
|
+
window.location.assign("/");
|
|
32181
|
+
}, [onBack]);
|
|
32182
|
+
const projectName = useMemo31(() => {
|
|
32183
|
+
if (scope === "global") {
|
|
32184
|
+
const included = stats?.projects?.included.length ?? 0;
|
|
32185
|
+
const unavailable = stats?.projects?.unavailable.length ?? 0;
|
|
32186
|
+
const total = included + unavailable;
|
|
32187
|
+
if (total === 0)
|
|
32188
|
+
return "all projects";
|
|
32189
|
+
return unavailable > 0 ? `${included} of ${total} projects` : `${total} project${total === 1 ? "" : "s"}`;
|
|
32190
|
+
}
|
|
32191
|
+
if (!stats?.project)
|
|
32192
|
+
return "";
|
|
32193
|
+
const parts = stats.project.split("/").filter(Boolean);
|
|
32194
|
+
return parts[parts.length - 1] ?? stats.project;
|
|
32195
|
+
}, [scope, stats?.project, stats?.projects]);
|
|
32196
|
+
const totalSpend = stats?.totals.costUsd ?? 0;
|
|
32197
|
+
const totalMessages = stats?.totals.messages ?? 0;
|
|
32198
|
+
const totalTokens = (stats?.totals.inputTokens ?? 0) + (stats?.totals.outputTokens ?? 0);
|
|
32199
|
+
return /* @__PURE__ */ jsxs103("div", {
|
|
32200
|
+
className: "fixed inset-0 flex flex-col bg-background text-foreground",
|
|
32201
|
+
children: [
|
|
32202
|
+
/* @__PURE__ */ jsx116("header", {
|
|
32203
|
+
className: "shrink-0 h-10 border-b border-border/60 bg-background/80 backdrop-blur",
|
|
32204
|
+
children: /* @__PURE__ */ jsxs103("div", {
|
|
32205
|
+
className: "h-full max-w-5xl mx-auto px-6 flex items-center justify-between gap-3",
|
|
32206
|
+
children: [
|
|
32207
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32208
|
+
className: "flex items-center gap-2 min-w-0",
|
|
32209
|
+
children: [
|
|
32210
|
+
/* @__PURE__ */ jsx116("button", {
|
|
32211
|
+
type: "button",
|
|
32212
|
+
onClick: handleBack,
|
|
32213
|
+
className: "inline-flex items-center justify-center size-6 rounded text-muted-foreground hover:text-foreground hover:bg-muted/40 transition-colors",
|
|
32214
|
+
title: "Back",
|
|
32215
|
+
"aria-label": "Back",
|
|
32216
|
+
children: /* @__PURE__ */ jsx116(ArrowLeft2, {
|
|
32217
|
+
className: "size-3.5"
|
|
32218
|
+
})
|
|
32219
|
+
}),
|
|
32220
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32221
|
+
className: "min-w-0 flex items-baseline gap-1.5 text-xs",
|
|
32222
|
+
children: [
|
|
32223
|
+
/* @__PURE__ */ jsx116("span", {
|
|
32224
|
+
className: "text-muted-foreground/70 uppercase tracking-[0.1em] text-[10px]",
|
|
32225
|
+
children: "Usage"
|
|
32226
|
+
}),
|
|
32227
|
+
/* @__PURE__ */ jsx116("span", {
|
|
32228
|
+
className: "text-muted-foreground/40",
|
|
32229
|
+
children: "/"
|
|
32230
|
+
}),
|
|
32231
|
+
/* @__PURE__ */ jsx116("span", {
|
|
32232
|
+
className: "font-medium truncate text-foreground",
|
|
32233
|
+
children: projectName || "—"
|
|
32234
|
+
})
|
|
32235
|
+
]
|
|
32236
|
+
})
|
|
32237
|
+
]
|
|
32238
|
+
}),
|
|
32239
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32240
|
+
className: "flex items-center gap-1.5",
|
|
32241
|
+
children: [
|
|
32242
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32243
|
+
className: "inline-flex p-0.5 rounded-md border border-border bg-muted/30 text-[11px]",
|
|
32244
|
+
children: [
|
|
32245
|
+
/* @__PURE__ */ jsx116("button", {
|
|
32246
|
+
type: "button",
|
|
32247
|
+
onClick: () => setScope("project"),
|
|
32248
|
+
className: `px-2 py-0.5 rounded transition-colors ${scope === "project" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
32249
|
+
children: "Project"
|
|
32250
|
+
}),
|
|
32251
|
+
/* @__PURE__ */ jsxs103("button", {
|
|
32252
|
+
type: "button",
|
|
32253
|
+
onClick: () => setScope("global"),
|
|
32254
|
+
className: `px-2 py-0.5 rounded transition-colors inline-flex items-center gap-1 ${scope === "global" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground"}`,
|
|
32255
|
+
children: [
|
|
32256
|
+
/* @__PURE__ */ jsx116(Globe22, {
|
|
32257
|
+
className: "size-3"
|
|
32258
|
+
}),
|
|
32259
|
+
"Global"
|
|
32260
|
+
]
|
|
32261
|
+
})
|
|
32262
|
+
]
|
|
32263
|
+
}),
|
|
32264
|
+
/* @__PURE__ */ jsx116("button", {
|
|
32265
|
+
type: "button",
|
|
32266
|
+
onClick: () => void fetchStats(),
|
|
32267
|
+
disabled: loading,
|
|
32268
|
+
className: "inline-flex items-center justify-center size-6 rounded text-muted-foreground hover:text-foreground hover:bg-muted/40 transition-colors disabled:opacity-50",
|
|
32269
|
+
title: "Refresh",
|
|
32270
|
+
"aria-label": "Refresh",
|
|
32271
|
+
children: /* @__PURE__ */ jsx116(RefreshCw12, {
|
|
32272
|
+
className: `size-3.5 ${loading ? "animate-spin" : ""}`
|
|
32273
|
+
})
|
|
32274
|
+
})
|
|
32275
|
+
]
|
|
32276
|
+
})
|
|
32277
|
+
]
|
|
32278
|
+
})
|
|
32279
|
+
}),
|
|
32280
|
+
/* @__PURE__ */ jsx116("main", {
|
|
32281
|
+
className: "flex-1 min-h-0 overflow-y-auto overscroll-contain",
|
|
32282
|
+
children: /* @__PURE__ */ jsxs103("div", {
|
|
32283
|
+
className: "max-w-5xl mx-auto px-6 py-8 space-y-5",
|
|
32284
|
+
children: [
|
|
32285
|
+
error && /* @__PURE__ */ jsx116("div", {
|
|
32286
|
+
className: "rounded-xl border border-destructive/40 bg-destructive/10 p-3 text-xs text-destructive",
|
|
32287
|
+
children: error
|
|
32288
|
+
}),
|
|
32289
|
+
loading && !stats && /* @__PURE__ */ jsx116("div", {
|
|
32290
|
+
className: "py-24 text-center text-xs text-muted-foreground",
|
|
32291
|
+
children: "loading…"
|
|
32292
|
+
}),
|
|
32293
|
+
stats && /* @__PURE__ */ jsxs103(Fragment44, {
|
|
32294
|
+
children: [
|
|
32295
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32296
|
+
className: "rounded-2xl border border-border bg-gradient-to-br from-card to-card/40 px-6 py-7",
|
|
32297
|
+
children: [
|
|
32298
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32299
|
+
className: "grid grid-cols-1 md:grid-cols-[1.4fr_1fr_1fr] gap-6 md:gap-10 items-center",
|
|
32300
|
+
children: [
|
|
32301
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32302
|
+
children: [
|
|
32303
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32304
|
+
className: "text-[10px] uppercase tracking-[0.18em] text-muted-foreground",
|
|
32305
|
+
children: "Token value · API rates"
|
|
32306
|
+
}),
|
|
32307
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32308
|
+
className: "mt-2 text-5xl font-semibold tabular-nums tracking-tight",
|
|
32309
|
+
children: formatUsd(stats.totals.notionalCostUsd)
|
|
32310
|
+
}),
|
|
32311
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32312
|
+
className: "mt-2 text-[11px] text-muted-foreground tabular-nums",
|
|
32313
|
+
children: [
|
|
32314
|
+
"all ",
|
|
32315
|
+
formatNumber(stats.totals.messages),
|
|
32316
|
+
" msgs valued at catalog API pricing"
|
|
32317
|
+
]
|
|
32318
|
+
})
|
|
32319
|
+
]
|
|
32320
|
+
}),
|
|
32321
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32322
|
+
className: "md:border-l md:border-border/60 md:pl-6",
|
|
32323
|
+
children: [
|
|
32324
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32325
|
+
className: "text-[10px] uppercase tracking-[0.18em] text-muted-foreground",
|
|
32326
|
+
children: "API spend"
|
|
32327
|
+
}),
|
|
32328
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32329
|
+
className: "mt-2 text-3xl font-semibold tabular-nums tracking-tight",
|
|
32330
|
+
children: formatUsd(totalSpend)
|
|
32331
|
+
}),
|
|
32332
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32333
|
+
className: "mt-2 text-[11px] text-muted-foreground tabular-nums",
|
|
32334
|
+
children: [
|
|
32335
|
+
formatNumber(stats.totals.messagesByAuth.api),
|
|
32336
|
+
" ",
|
|
32337
|
+
"pay-as-you-go msgs"
|
|
32338
|
+
]
|
|
32339
|
+
})
|
|
32340
|
+
]
|
|
32341
|
+
}),
|
|
32342
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32343
|
+
className: "md:border-l md:border-border/60 md:pl-6",
|
|
32344
|
+
children: [
|
|
32345
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32346
|
+
className: "text-[10px] uppercase tracking-[0.18em] text-emerald-400/80",
|
|
32347
|
+
children: "OAuth · plan value"
|
|
32348
|
+
}),
|
|
32349
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32350
|
+
className: "mt-2 text-3xl font-semibold tabular-nums tracking-tight text-emerald-400",
|
|
32351
|
+
children: formatUsd(stats.providers.filter((p) => p.authType === "oauth").reduce((s, p) => s + p.notionalCostUsd, 0))
|
|
32352
|
+
}),
|
|
32353
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32354
|
+
className: "mt-2 text-[11px] text-muted-foreground tabular-nums",
|
|
32355
|
+
children: [
|
|
32356
|
+
formatNumber(stats.totals.messagesByAuth.oauth),
|
|
32357
|
+
" msgs via plan subscriptions"
|
|
32358
|
+
]
|
|
32359
|
+
})
|
|
32360
|
+
]
|
|
32361
|
+
})
|
|
32362
|
+
]
|
|
32363
|
+
}),
|
|
32364
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32365
|
+
className: "mt-6 pt-5 border-t border-border/40 grid grid-cols-3 gap-6 text-[11px] text-muted-foreground",
|
|
32366
|
+
children: [
|
|
32367
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32368
|
+
children: [
|
|
32369
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32370
|
+
className: "uppercase tracking-[0.14em] text-muted-foreground/70",
|
|
32371
|
+
children: "Messages"
|
|
32372
|
+
}),
|
|
32373
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32374
|
+
className: "mt-1 text-sm text-foreground tabular-nums",
|
|
32375
|
+
children: [
|
|
32376
|
+
formatNumber(totalMessages),
|
|
32377
|
+
" ",
|
|
32378
|
+
/* @__PURE__ */ jsxs103("span", {
|
|
32379
|
+
className: "text-muted-foreground/70",
|
|
32380
|
+
children: [
|
|
32381
|
+
"· ",
|
|
32382
|
+
formatNumber(stats.totals.sessions),
|
|
32383
|
+
" sessions"
|
|
32384
|
+
]
|
|
32385
|
+
})
|
|
32386
|
+
]
|
|
32387
|
+
})
|
|
32388
|
+
]
|
|
32389
|
+
}),
|
|
32390
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32391
|
+
children: [
|
|
32392
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32393
|
+
className: "uppercase tracking-[0.14em] text-muted-foreground/70",
|
|
32394
|
+
children: "Tokens"
|
|
32395
|
+
}),
|
|
32396
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32397
|
+
className: "mt-1 text-sm text-foreground tabular-nums",
|
|
32398
|
+
children: [
|
|
32399
|
+
formatNumber(totalTokens),
|
|
32400
|
+
" ",
|
|
32401
|
+
/* @__PURE__ */ jsxs103("span", {
|
|
32402
|
+
className: "text-muted-foreground/70",
|
|
32403
|
+
children: [
|
|
32404
|
+
"· ",
|
|
32405
|
+
formatNumber(stats.totals.inputTokens),
|
|
32406
|
+
" in /",
|
|
32407
|
+
" ",
|
|
32408
|
+
formatNumber(stats.totals.outputTokens),
|
|
32409
|
+
" out"
|
|
32410
|
+
]
|
|
32411
|
+
})
|
|
32412
|
+
]
|
|
32413
|
+
})
|
|
32414
|
+
]
|
|
32415
|
+
}),
|
|
32416
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32417
|
+
children: [
|
|
32418
|
+
/* @__PURE__ */ jsx116("div", {
|
|
32419
|
+
className: "uppercase tracking-[0.14em] text-muted-foreground/70",
|
|
32420
|
+
children: "Mix"
|
|
32421
|
+
}),
|
|
32422
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32423
|
+
className: "mt-1 text-sm tabular-nums",
|
|
32424
|
+
children: [
|
|
32425
|
+
/* @__PURE__ */ jsxs103("span", {
|
|
32426
|
+
className: authColor("api"),
|
|
32427
|
+
children: [
|
|
32428
|
+
formatNumber(stats.totals.messagesByAuth.api),
|
|
32429
|
+
" api"
|
|
32430
|
+
]
|
|
32431
|
+
}),
|
|
32432
|
+
stats.totals.messagesByAuth.oauth > 0 && /* @__PURE__ */ jsxs103(Fragment44, {
|
|
32433
|
+
children: [
|
|
32434
|
+
/* @__PURE__ */ jsx116("span", {
|
|
32435
|
+
className: "text-muted-foreground/40",
|
|
32436
|
+
children: " · "
|
|
32437
|
+
}),
|
|
32438
|
+
/* @__PURE__ */ jsxs103("span", {
|
|
32439
|
+
className: authColor("oauth"),
|
|
32440
|
+
children: [
|
|
32441
|
+
formatNumber(stats.totals.messagesByAuth.oauth),
|
|
32442
|
+
" ",
|
|
32443
|
+
"oauth"
|
|
32444
|
+
]
|
|
32445
|
+
})
|
|
32446
|
+
]
|
|
32447
|
+
}),
|
|
32448
|
+
stats.totals.messagesByAuth.subscription > 0 && /* @__PURE__ */ jsxs103(Fragment44, {
|
|
32449
|
+
children: [
|
|
32450
|
+
/* @__PURE__ */ jsx116("span", {
|
|
32451
|
+
className: "text-muted-foreground/40",
|
|
32452
|
+
children: " · "
|
|
32453
|
+
}),
|
|
32454
|
+
/* @__PURE__ */ jsxs103("span", {
|
|
32455
|
+
className: authColor("subscription"),
|
|
32456
|
+
children: [
|
|
32457
|
+
formatNumber(stats.totals.messagesByAuth.subscription),
|
|
32458
|
+
" ",
|
|
32459
|
+
"sub"
|
|
32460
|
+
]
|
|
32461
|
+
})
|
|
32462
|
+
]
|
|
32463
|
+
})
|
|
32464
|
+
]
|
|
32465
|
+
})
|
|
32466
|
+
]
|
|
32467
|
+
})
|
|
32468
|
+
]
|
|
32469
|
+
})
|
|
32470
|
+
]
|
|
32471
|
+
}),
|
|
32472
|
+
/* @__PURE__ */ jsx116(Section, {
|
|
32473
|
+
title: "How you're paying",
|
|
32474
|
+
subtitle: "OAuth & Subscription are flat-rate · not per-token",
|
|
32475
|
+
children: /* @__PURE__ */ jsx116(AuthSplit, {
|
|
32476
|
+
stats
|
|
32477
|
+
})
|
|
32478
|
+
}),
|
|
32479
|
+
/* @__PURE__ */ jsx116(Section, {
|
|
32480
|
+
title: "Daily activity",
|
|
32481
|
+
children: /* @__PURE__ */ jsx116(DailyChart, {
|
|
32482
|
+
data: stats.daily
|
|
32483
|
+
})
|
|
32484
|
+
}),
|
|
32485
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32486
|
+
className: "grid grid-cols-1 md:grid-cols-2 gap-5",
|
|
32487
|
+
children: [
|
|
32488
|
+
/* @__PURE__ */ jsx116(Section, {
|
|
32489
|
+
title: "By provider",
|
|
32490
|
+
children: /* @__PURE__ */ jsx116(ProviderList, {
|
|
32491
|
+
providers: stats.providers
|
|
32492
|
+
})
|
|
32493
|
+
}),
|
|
32494
|
+
/* @__PURE__ */ jsx116(Section, {
|
|
32495
|
+
title: "Top models",
|
|
32496
|
+
subtitle: stats.models.length > 12 ? `Showing 12 of ${stats.models.length}` : undefined,
|
|
32497
|
+
children: /* @__PURE__ */ jsx116(ModelList, {
|
|
32498
|
+
models: stats.models
|
|
32499
|
+
})
|
|
32500
|
+
})
|
|
32501
|
+
]
|
|
32502
|
+
}),
|
|
32503
|
+
scope === "global" && stats.projects && /* @__PURE__ */ jsx116(Section, {
|
|
32504
|
+
title: "Projects",
|
|
32505
|
+
subtitle: stats.projects.unavailable.length > 0 ? `${stats.projects.included.length} included · ${stats.projects.unavailable.length} unavailable` : `${stats.projects.included.length} included`,
|
|
32506
|
+
children: /* @__PURE__ */ jsx116(ProjectList, {
|
|
32507
|
+
projects: stats.projects
|
|
32508
|
+
})
|
|
32509
|
+
}),
|
|
32510
|
+
stats.notes.missingPricing.length > 0 && /* @__PURE__ */ jsxs103("div", {
|
|
32511
|
+
className: "text-[10px] text-muted-foreground/70 text-center font-mono py-2",
|
|
32512
|
+
children: [
|
|
32513
|
+
"pricing missing for ",
|
|
32514
|
+
stats.notes.missingPricing.length,
|
|
32515
|
+
" model",
|
|
32516
|
+
stats.notes.missingPricing.length === 1 ? "" : "s",
|
|
32517
|
+
" · cost shown as $0"
|
|
32518
|
+
]
|
|
32519
|
+
}),
|
|
32520
|
+
/* @__PURE__ */ jsxs103("div", {
|
|
32521
|
+
className: "text-[10px] text-muted-foreground/60 text-center pt-2 pb-4",
|
|
32522
|
+
children: [
|
|
32523
|
+
"estimated from catalog pricing · generated",
|
|
32524
|
+
" ",
|
|
32525
|
+
new Date(stats.generatedAt).toLocaleString()
|
|
32526
|
+
]
|
|
32527
|
+
})
|
|
32528
|
+
]
|
|
32529
|
+
})
|
|
32530
|
+
]
|
|
32531
|
+
})
|
|
32532
|
+
})
|
|
32533
|
+
]
|
|
32534
|
+
});
|
|
32535
|
+
}
|
|
31500
32536
|
export {
|
|
31501
32537
|
ViewerTabs,
|
|
31502
32538
|
UserMessageGroup,
|
|
31503
32539
|
UsageRing,
|
|
31504
32540
|
UsageModal,
|
|
32541
|
+
UsageDashboard,
|
|
31505
32542
|
TunnelSidebarToggle,
|
|
31506
32543
|
TunnelSidebar,
|
|
31507
32544
|
ToolResultRenderer,
|
|
@@ -31573,4 +32610,4 @@ export {
|
|
|
31573
32610
|
AssistantMessageGroup
|
|
31574
32611
|
};
|
|
31575
32612
|
|
|
31576
|
-
//# debugId=
|
|
32613
|
+
//# debugId=4C1FF6CB288F864964756E2164756E21
|