@acarmisc/backstage-plugin-litellm 0.9.0 → 0.10.0
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/index.cjs.js +62 -6
- package/dist/index.cjs.js.map +2 -2
- package/dist/index.esm.js +66 -8
- package/dist/index.esm.js.map +3 -3
- package/dist/types.d.ts +6 -0
- package/package.json +1 -1
package/dist/index.cjs.js
CHANGED
|
@@ -236,6 +236,21 @@ function fmtCost(perToken) {
|
|
|
236
236
|
const per1k = perToken * 1e3;
|
|
237
237
|
return per1k < 0.01 ? `$${(perToken * 1e6).toFixed(2)}/M` : `$${per1k.toFixed(3)}/1K`;
|
|
238
238
|
}
|
|
239
|
+
function formatContextWindow(maxInput, maxOutput) {
|
|
240
|
+
if (!maxInput && !maxOutput) return null;
|
|
241
|
+
const fmt = (n) => {
|
|
242
|
+
if (!n) return null;
|
|
243
|
+
if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
|
|
244
|
+
if (n >= 1e3) return `${Math.round(n / 1e3)}K`;
|
|
245
|
+
return String(n);
|
|
246
|
+
};
|
|
247
|
+
const inPart = fmt(maxInput);
|
|
248
|
+
const outPart = fmt(maxOutput);
|
|
249
|
+
if (inPart && outPart) return `ctx ${inPart} in / ${outPart} out`;
|
|
250
|
+
if (inPart) return `ctx ${inPart}`;
|
|
251
|
+
if (outPart) return `ctx ${outPart} out`;
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
239
254
|
function trimSlash(url) {
|
|
240
255
|
return url.replace(/\/+$/, "");
|
|
241
256
|
}
|
|
@@ -296,7 +311,9 @@ var init_KeysTable = __esm({
|
|
|
296
311
|
tpm_limit: void 0,
|
|
297
312
|
rpm_limit: void 0,
|
|
298
313
|
team_id: void 0,
|
|
299
|
-
key_type: "llm_api"
|
|
314
|
+
key_type: "llm_api",
|
|
315
|
+
auto_rotate: false,
|
|
316
|
+
rotation_interval_days: void 0
|
|
300
317
|
});
|
|
301
318
|
keyToEditForm = (k) => ({
|
|
302
319
|
key_alias: k.key_alias ?? "",
|
|
@@ -479,7 +496,8 @@ var init_KeysTable = __esm({
|
|
|
479
496
|
const modelOption = (m) => {
|
|
480
497
|
const inCost = fmtCost(m.input_cost_per_token);
|
|
481
498
|
const outCost = fmtCost(m.output_cost_per_token);
|
|
482
|
-
|
|
499
|
+
const ctx = formatContextWindow(m.max_input_tokens, m.max_output_tokens);
|
|
500
|
+
return /* @__PURE__ */ import_react2.default.createElement(import_material2.Box, null, /* @__PURE__ */ import_react2.default.createElement("span", null, m.model_name), m.supports_function_calling && " \u{1F527}", m.supports_vision && " \u{1F441}\uFE0F", ctx && /* @__PURE__ */ import_react2.default.createElement(import_material2.Typography, { variant: "caption", color: "text.secondary", sx: { ml: 1 } }, ctx), (inCost || outCost) && /* @__PURE__ */ import_react2.default.createElement(import_material2.Typography, { variant: "caption", color: "text.secondary", sx: { ml: 1 } }, inCost, " in \xB7 ", outCost, " out"));
|
|
483
501
|
};
|
|
484
502
|
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Paper, { sx: { mb: 2 } }, /* @__PURE__ */ import_react2.default.createElement(import_material2.Box, { display: "flex", justifyContent: "space-between", alignItems: "center", p: 2, gap: 2 }, /* @__PURE__ */ import_react2.default.createElement(import_material2.Typography, { variant: "h6" }, "Virtual Keys"), /* @__PURE__ */ import_react2.default.createElement(import_material2.Box, { display: "flex", gap: 1, alignItems: "center", flex: 1, justifyContent: "flex-end" }, /* @__PURE__ */ import_react2.default.createElement(
|
|
485
503
|
import_material2.TextField,
|
|
@@ -698,6 +716,35 @@ var init_KeysTable = __esm({
|
|
|
698
716
|
onChange: (e) => setFormData({ ...formData, rpm_limit: e.target.value ? Number(e.target.value) : void 0 }),
|
|
699
717
|
fullWidth: true
|
|
700
718
|
}
|
|
719
|
+
), /* @__PURE__ */ import_react2.default.createElement(
|
|
720
|
+
import_material2.FormControlLabel,
|
|
721
|
+
{
|
|
722
|
+
control: /* @__PURE__ */ import_react2.default.createElement(
|
|
723
|
+
import_material2.Checkbox,
|
|
724
|
+
{
|
|
725
|
+
checked: !!formData.auto_rotate,
|
|
726
|
+
onChange: (e) => setFormData({
|
|
727
|
+
...formData,
|
|
728
|
+
auto_rotate: e.target.checked,
|
|
729
|
+
rotation_interval_days: e.target.checked ? formData.rotation_interval_days ?? 90 : void 0
|
|
730
|
+
})
|
|
731
|
+
}
|
|
732
|
+
),
|
|
733
|
+
label: "Auto-rotate (LiteLLM rotates the secret on a schedule)"
|
|
734
|
+
}
|
|
735
|
+
), formData.auto_rotate && /* @__PURE__ */ import_react2.default.createElement(
|
|
736
|
+
import_material2.TextField,
|
|
737
|
+
{
|
|
738
|
+
label: "Rotate every (days)",
|
|
739
|
+
type: "number",
|
|
740
|
+
value: formData.rotation_interval_days ?? "",
|
|
741
|
+
onChange: (e) => setFormData({
|
|
742
|
+
...formData,
|
|
743
|
+
rotation_interval_days: e.target.value ? Number(e.target.value) : void 0
|
|
744
|
+
}),
|
|
745
|
+
helperText: "LiteLLM enforces this interval server-side; the old secret stops working the moment it rotates.",
|
|
746
|
+
fullWidth: true
|
|
747
|
+
}
|
|
701
748
|
))), /* @__PURE__ */ import_react2.default.createElement(import_material2.DialogActions, null, /* @__PURE__ */ import_react2.default.createElement(import_material2.Button, { onClick: handleCloseModal }, newKeyValue ? "Done" : "Cancel"), !newKeyValue && /* @__PURE__ */ import_react2.default.createElement(
|
|
702
749
|
import_material2.Button,
|
|
703
750
|
{
|
|
@@ -896,8 +943,14 @@ var init_UsageStats = __esm({
|
|
|
896
943
|
loading,
|
|
897
944
|
userInfo
|
|
898
945
|
}) => {
|
|
946
|
+
const theme = (0, import_material3.useTheme)();
|
|
899
947
|
const [selectedModel, setSelectedModel] = (0, import_react3.useState)("all");
|
|
900
948
|
const [tab, setTab] = (0, import_react3.useState)("costs");
|
|
949
|
+
const gridStroke = theme.palette.divider;
|
|
950
|
+
const tickFill = theme.palette.text.secondary;
|
|
951
|
+
const tickStyle = { fontSize: 12, fill: tickFill };
|
|
952
|
+
const tickStyleSmall = { fontSize: 11, fill: tickFill };
|
|
953
|
+
const tickStyleTiny = { fontSize: 10, fill: tickFill };
|
|
901
954
|
const selectedPreset = (0, import_react3.useMemo)(() => {
|
|
902
955
|
if (dateRange.start.toDateString() === dateRange.end.toDateString()) return "today";
|
|
903
956
|
const diffMs = dateRange.end.getTime() - dateRange.start.getTime();
|
|
@@ -1032,7 +1085,7 @@ var init_UsageStats = __esm({
|
|
|
1032
1085
|
value: fmtInt(usage?.total_tokens ?? 0),
|
|
1033
1086
|
hint: `${fmtInt(usage?.prompt_tokens ?? 0)} in \xB7 ${fmtInt(usage?.completion_tokens ?? 0)} out`
|
|
1034
1087
|
}
|
|
1035
|
-
))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Tabs, { value: tab, onChange: (_, v) => setTab(v), sx: { mb: 2 } }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Tab, { value: "costs", label: "Costs" }), /* @__PURE__ */ import_react3.default.createElement(import_material3.Tab, { value: "models", label: "Model Activity" }), /* @__PURE__ */ import_react3.default.createElement(import_material3.Tab, { value: "keys", label: "Key Activity" })), tab === "costs" && /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { container: true, spacing: 3 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Daily Spend by Model"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : modelSpendByDate.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: 260 }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.AreaChart, { data: modelSpendByDate }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { dataKey: "date", tick:
|
|
1088
|
+
))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Tabs, { value: tab, onChange: (_, v) => setTab(v), sx: { mb: 2 } }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Tab, { value: "costs", label: "Costs" }), /* @__PURE__ */ import_react3.default.createElement(import_material3.Tab, { value: "models", label: "Model Activity" }), /* @__PURE__ */ import_react3.default.createElement(import_material3.Tab, { value: "keys", label: "Key Activity" })), tab === "costs" && /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { container: true, spacing: 3 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Daily Spend by Model"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : modelSpendByDate.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: 260 }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.AreaChart, { data: modelSpendByDate }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { dataKey: "date", tick: tickStyle }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { tick: tickStyle, tickFormatter: (v) => `$${v.toFixed(2)}` }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, { formatter: (v) => [`$${v.toFixed(4)}`, void 0] }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Legend, null), topSpendModels.map((m) => /* @__PURE__ */ import_react3.default.createElement(
|
|
1036
1089
|
import_recharts.Area,
|
|
1037
1090
|
{
|
|
1038
1091
|
key: m,
|
|
@@ -1043,14 +1096,14 @@ var init_UsageStats = __esm({
|
|
|
1043
1096
|
fill: modelColor(m),
|
|
1044
1097
|
fillOpacity: 0.6
|
|
1045
1098
|
}
|
|
1046
|
-
)))))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Daily Token Usage"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : dailyData.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: 260 }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.AreaChart, { data: dailyData }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { dataKey: "date", tick: { fontSize: 12 } }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { tick: { fontSize: 12 }, tickFormatter: fmtInt }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, { formatter: (v) => [fmtInt(v), void 0] }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Legend, null), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Area, { type: "monotone", dataKey: "promptTokens", name: "Input (prompt)", stackId: "tok", stroke: "#8884d8", fill: "#8884d8", fillOpacity: 0.5 }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Area, { type: "monotone", dataKey: "completionTokens", name: "Output (completion)", stackId: "tok", stroke: "#82ca9d", fill: "#82ca9d", fillOpacity: 0.5 }))))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Daily Requests"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : dailyData.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: 260 }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.BarChart, { data: dailyData }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { dataKey: "date", tick: { fontSize: 12 } }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { tick: { fontSize: 12 } }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, null), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Legend, null), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Bar, { dataKey: "successfulRequests", name: "Successful", fill: "#82ca9d", stackId: "r" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Bar, { dataKey: "failedRequests", name: "Failed", fill: "#e57373", stackId: "r" }))))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Daily Success Rate"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : successRateData.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: 260 }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.LineChart, { data: successRateData }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { dataKey: "date", tick: { fontSize: 12 } }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { domain: [0, 100], tick: { fontSize: 12 }, tickFormatter: (v) => `${v}%` }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, { formatter: (v) => [`${v}%`, "Success rate"] }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.ReferenceLine, { y: 100, stroke: "#82ca9d", strokeDasharray: "4 2" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Line, { type: "monotone", dataKey: "successRate", name: "Success rate", stroke: "#8884d8", dot: { r: 3 } }))))), (maxBudget > 0 || cumulativeData.length > 0) && /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Cumulative Spend", maxBudget > 0 ? ` vs Budget (${fmtUsd(maxBudget)})` : "", maxBudget > 0 && /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { component: "span", variant: "caption", color: "text.secondary", sx: { ml: 1 } }, fmtUsd(totalCumSpend), " used \xB7 ", fmtUsd(Math.max(0, maxBudget - totalCumSpend)), " remaining")), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, { height: 180 }) : cumulativeData.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, { height: 180 }) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: 180 }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.AreaChart, { data: cumulativeData }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { dataKey: "date", tick: { fontSize: 12 } }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { tick: { fontSize: 12 }, tickFormatter: (v) => `$${v.toFixed(2)}` }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, { formatter: (v) => [`$${v.toFixed(4)}`, "Cumulative spend"] }), maxBudget > 0 && /* @__PURE__ */ import_react3.default.createElement(import_recharts.ReferenceLine, { y: maxBudget, stroke: "#e57373", strokeDasharray: "6 3", label: { value: `Budget ${fmtUsd(maxBudget)}`, position: "insideTopRight", fontSize: 11 } }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Area, { type: "monotone", dataKey: "cumulative", name: "Cumulative spend", stroke: "#ffc658", fill: "#ffc658", fillOpacity: 0.3 })))))), tab === "models" && /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { container: true, spacing: 3 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Spend by Model"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : topModelSpendBars.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: Math.max(200, topModelSpendBars.length * 36) }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.BarChart, { data: topModelSpendBars, layout: "vertical", margin: { left: 20 } }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { type: "number", tick: { fontSize: 12 }, tickFormatter: (v) => `$${v.toFixed(2)}` }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { type: "category", dataKey: "model", tick: { fontSize: 11 }, width: 200 }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, { formatter: (v) => [fmtUsd(v), "Spend"] }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Bar, { dataKey: "spend", name: "Spend", radius: [0, 4, 4, 0] }, topModelSpendBars.map((r) => /* @__PURE__ */ import_react3.default.createElement("rect", { key: r.model, fill: modelColor(r.model) }))))))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Tokens by Model"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : modelRows.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: 260 }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.BarChart, { data: modelRows }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { dataKey: "model", tick: { fontSize: 10 }, interval: 0, angle: -15, textAnchor: "end", height: 60 }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { tick: { fontSize: 12 } }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, null), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Legend, null), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Bar, { dataKey: "promptTokens", name: "Prompt", fill: "#8884d8", stackId: "t" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Bar, { dataKey: "completionTokens", name: "Completion", fill: "#82ca9d", stackId: "t" }))))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableContainer, { component: import_material3.Paper, variant: "outlined" }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Table, { size: "small" }, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableHead, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableRow, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, null, "Model"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Spend"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Requests"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Success"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Failed"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Prompt"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Completion"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { sx: { minWidth: 120 } }, "Success rate"))), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableBody, null, loading ? /* @__PURE__ */ import_react3.default.createElement(import_material3.TableRow, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { colSpan: 8 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.LinearProgress, null))) : modelRows.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(import_material3.TableRow, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { colSpan: 8, align: "center" }, "No model activity")) : [...modelRows].sort((a, b) => b.spend - a.spend || b.totalTokens - a.totalTokens).map((r) => /* @__PURE__ */ import_react3.default.createElement(import_material3.TableRow, { key: r.model }, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { display: "flex", alignItems: "center", gap: 0.75 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { sx: { width: 10, height: 10, borderRadius: "50%", bgcolor: modelColor(r.model), flexShrink: 0 } }), r.model)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.successfulRequests)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.promptTokens)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.completionTokens)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, null, r.apiRequests > 0 ? /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ import_react3.default.createElement(
|
|
1099
|
+
)))))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Daily Token Usage"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : dailyData.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: 260 }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.AreaChart, { data: dailyData }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { dataKey: "date", tick: tickStyle }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { tick: tickStyle, tickFormatter: fmtInt }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, { formatter: (v) => [fmtInt(v), void 0] }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Legend, null), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Area, { type: "monotone", dataKey: "promptTokens", name: "Input (prompt)", stackId: "tok", stroke: "#8884d8", fill: "#8884d8", fillOpacity: 0.5 }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Area, { type: "monotone", dataKey: "completionTokens", name: "Output (completion)", stackId: "tok", stroke: "#82ca9d", fill: "#82ca9d", fillOpacity: 0.5 }))))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Daily Requests"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : dailyData.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: 260 }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.BarChart, { data: dailyData }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { dataKey: "date", tick: tickStyle }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { tick: tickStyle }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, null), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Legend, null), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Bar, { dataKey: "successfulRequests", name: "Successful", fill: "#82ca9d", stackId: "r" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Bar, { dataKey: "failedRequests", name: "Failed", fill: "#e57373", stackId: "r" }))))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12, md: 6 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Daily Success Rate"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : successRateData.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: 260 }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.LineChart, { data: successRateData }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { dataKey: "date", tick: tickStyle }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { domain: [0, 100], tick: tickStyle, tickFormatter: (v) => `${v}%` }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, { formatter: (v) => [`${v}%`, "Success rate"] }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.ReferenceLine, { y: 100, stroke: "#82ca9d", strokeDasharray: "4 2" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Line, { type: "monotone", dataKey: "successRate", name: "Success rate", stroke: "#8884d8", dot: { r: 3 } }))))), (maxBudget > 0 || cumulativeData.length > 0) && /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Cumulative Spend", maxBudget > 0 ? ` vs Budget (${fmtUsd(maxBudget)})` : "", maxBudget > 0 && /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { component: "span", variant: "caption", color: "text.secondary", sx: { ml: 1 } }, fmtUsd(totalCumSpend), " used \xB7 ", fmtUsd(Math.max(0, maxBudget - totalCumSpend)), " remaining")), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, { height: 180 }) : cumulativeData.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, { height: 180 }) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: 180 }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.AreaChart, { data: cumulativeData }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { dataKey: "date", tick: tickStyle }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { tick: tickStyle, tickFormatter: (v) => `$${v.toFixed(2)}` }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, { formatter: (v) => [`$${v.toFixed(4)}`, "Cumulative spend"] }), maxBudget > 0 && /* @__PURE__ */ import_react3.default.createElement(import_recharts.ReferenceLine, { y: maxBudget, stroke: "#e57373", strokeDasharray: "6 3", label: { value: `Budget ${fmtUsd(maxBudget)}`, position: "insideTopRight", fontSize: 11 } }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Area, { type: "monotone", dataKey: "cumulative", name: "Cumulative spend", stroke: "#ffc658", fill: "#ffc658", fillOpacity: 0.3 })))))), tab === "models" && /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { container: true, spacing: 3 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Spend by Model"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : topModelSpendBars.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: Math.max(200, topModelSpendBars.length * 36) }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.BarChart, { data: topModelSpendBars, layout: "vertical", margin: { left: 20 } }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { type: "number", tick: tickStyle, tickFormatter: (v) => `$${v.toFixed(2)}` }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { type: "category", dataKey: "model", tick: tickStyleSmall, width: 200 }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, { formatter: (v) => [fmtUsd(v), "Spend"] }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Bar, { dataKey: "spend", name: "Spend", radius: [0, 4, 4, 0] }, topModelSpendBars.map((r) => /* @__PURE__ */ import_react3.default.createElement("rect", { key: r.model, fill: modelColor(r.model) }))))))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Tokens by Model"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : modelRows.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(EmptyChart, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: 260 }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.BarChart, { data: modelRows }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { dataKey: "model", tick: tickStyleTiny, interval: 0, angle: -15, textAnchor: "end", height: 60 }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { tick: tickStyle }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, null), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Legend, null), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Bar, { dataKey: "promptTokens", name: "Prompt", fill: "#8884d8", stackId: "t" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Bar, { dataKey: "completionTokens", name: "Completion", fill: "#82ca9d", stackId: "t" }))))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableContainer, { component: import_material3.Paper, variant: "outlined" }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Table, { size: "small" }, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableHead, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableRow, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, null, "Model"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Spend"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Requests"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Success"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Failed"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Prompt"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Completion"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { sx: { minWidth: 120 } }, "Success rate"))), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableBody, null, loading ? /* @__PURE__ */ import_react3.default.createElement(import_material3.TableRow, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { colSpan: 8 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.LinearProgress, null))) : modelRows.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(import_material3.TableRow, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { colSpan: 8, align: "center" }, "No model activity")) : [...modelRows].sort((a, b) => b.spend - a.spend || b.totalTokens - a.totalTokens).map((r) => /* @__PURE__ */ import_react3.default.createElement(import_material3.TableRow, { key: r.model }, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { display: "flex", alignItems: "center", gap: 0.75 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { sx: { width: 10, height: 10, borderRadius: "50%", bgcolor: modelColor(r.model), flexShrink: 0 } }), r.model)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.successfulRequests)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.promptTokens)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.completionTokens)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, null, r.apiRequests > 0 ? /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ import_react3.default.createElement(
|
|
1047
1100
|
import_material3.LinearProgress,
|
|
1048
1101
|
{
|
|
1049
1102
|
variant: "determinate",
|
|
1050
1103
|
value: r.successRate * 100,
|
|
1051
1104
|
sx: { flex: 1, height: 6, borderRadius: 3 }
|
|
1052
1105
|
}
|
|
1053
|
-
), /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "caption" }, fmtPct(r.successRate))) : "\u2014")))))))), tab === "keys" && /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { container: true, spacing: 3 }, (loading || topKeySpendBars.length > 0) && /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Spend by Key"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: Math.max(160, topKeySpendBars.length * 36) }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.BarChart, { data: topKeySpendBars, layout: "vertical", margin: { left: 20 } }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3" }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { type: "number", tick:
|
|
1106
|
+
), /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "caption" }, fmtPct(r.successRate))) : "\u2014")))))))), tab === "keys" && /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { container: true, spacing: 3 }, (loading || topKeySpendBars.length > 0) && /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Spend by Key"), loading ? /* @__PURE__ */ import_react3.default.createElement(ChartSkeleton, null) : /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { height: Math.max(160, topKeySpendBars.length * 36) }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.BarChart, { data: topKeySpendBars, layout: "vertical", margin: { left: 20 } }, /* @__PURE__ */ import_react3.default.createElement(import_recharts.CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.XAxis, { type: "number", tick: tickStyle, tickFormatter: (v) => `$${v.toFixed(2)}` }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.YAxis, { type: "category", dataKey: "keyAlias", tick: tickStyleSmall, width: 160 }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Tooltip, { formatter: (v) => [fmtUsd(v), "Spend"] }), /* @__PURE__ */ import_react3.default.createElement(import_recharts.Bar, { dataKey: "spend", name: "Spend", fill: "#8884d8", radius: [0, 4, 4, 0] }))))), /* @__PURE__ */ import_react3.default.createElement(import_material3.Grid, { item: true, xs: 12 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableContainer, { component: import_material3.Paper, variant: "outlined" }, /* @__PURE__ */ import_react3.default.createElement(import_material3.Table, { size: "small" }, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableHead, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableRow, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, null, "Key"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, null, "Models"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Spend"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Requests"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Tokens"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, "Failed"), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { sx: { minWidth: 120 } }, "Success rate"))), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableBody, null, loading ? /* @__PURE__ */ import_react3.default.createElement(import_material3.TableRow, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { colSpan: 7 }, /* @__PURE__ */ import_react3.default.createElement(import_material3.LinearProgress, null))) : keyRows.length === 0 ? /* @__PURE__ */ import_react3.default.createElement(import_material3.TableRow, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { colSpan: 7, align: "center" }, "No key activity")) : [...keyRows].sort((a, b) => b.spend - a.spend || b.apiRequests - a.apiRequests).map((r) => /* @__PURE__ */ import_react3.default.createElement(import_material3.TableRow, { key: r.keyHash }, /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "body2" }, r.keyAlias), r.teamId ? /* @__PURE__ */ import_react3.default.createElement(import_material3.Typography, { variant: "caption", color: "text.secondary" }, "team: ", r.teamId) : null), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, null, /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { display: "flex", gap: 0.5, flexWrap: "wrap" }, r.models.map((m) => /* @__PURE__ */ import_react3.default.createElement(import_material3.Chip, { key: m, label: m, size: "small", variant: "outlined" })))), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtUsd(r.spend)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.apiRequests)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.totalTokens)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, { align: "right" }, fmtInt(r.failedRequests)), /* @__PURE__ */ import_react3.default.createElement(import_material3.TableCell, null, r.apiRequests > 0 ? /* @__PURE__ */ import_react3.default.createElement(import_material3.Box, { display: "flex", alignItems: "center", gap: 1 }, /* @__PURE__ */ import_react3.default.createElement(
|
|
1054
1107
|
import_material3.LinearProgress,
|
|
1055
1108
|
{
|
|
1056
1109
|
variant: "determinate",
|
|
@@ -1074,6 +1127,9 @@ var init_TeamUsage = __esm({
|
|
|
1074
1127
|
Stat = ({ label, value }) => /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, null, /* @__PURE__ */ import_react4.default.createElement(import_material4.Typography, { variant: "caption", color: "text.secondary", display: "block" }, label), /* @__PURE__ */ import_react4.default.createElement(import_material4.Typography, { variant: "body2", fontWeight: 600, sx: { fontFamily: "monospace" } }, value));
|
|
1075
1128
|
TeamCard = ({ team, usage, usageLoading }) => {
|
|
1076
1129
|
const [expanded, setExpanded] = (0, import_react4.useState)(false);
|
|
1130
|
+
const theme = (0, import_material4.useTheme)();
|
|
1131
|
+
const gridStroke = theme.palette.divider;
|
|
1132
|
+
const tickFill = theme.palette.text.secondary;
|
|
1077
1133
|
const budget = team.max_budget ?? 0;
|
|
1078
1134
|
const spend = team.spend ?? 0;
|
|
1079
1135
|
const budgetPct = budget > 0 ? Math.min(spend / budget * 100, 100) : 0;
|
|
@@ -1124,7 +1180,7 @@ var init_TeamUsage = __esm({
|
|
|
1124
1180
|
color: isOver ? "error" : isNear ? "warning" : "primary",
|
|
1125
1181
|
sx: { height: 6, borderRadius: 1 }
|
|
1126
1182
|
}
|
|
1127
|
-
)), /* @__PURE__ */ import_react4.default.createElement(import_material4.Collapse, { in: expanded }, /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, { mt: 2 }, /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, { display: "flex", alignItems: "center", gap: 1, mb: 1 }, /* @__PURE__ */ import_react4.default.createElement(import_icons_material2.Speed, { fontSize: "small", color: "action" }), /* @__PURE__ */ import_react4.default.createElement(import_material4.Typography, { variant: "subtitle2", color: "text.secondary" }, "Rate limits")), /* @__PURE__ */ import_react4.default.createElement(import_material4.Stack, { direction: "row", spacing: 3, flexWrap: "wrap", useFlexGap: true, gap: 1.5, mb: 2 }, /* @__PURE__ */ import_react4.default.createElement(Stat, { label: "TPM limit", value: team.tpm_limit != null && team.tpm_limit > 0 ? String(team.tpm_limit) : "Unlimited" }), /* @__PURE__ */ import_react4.default.createElement(Stat, { label: "RPM limit", value: team.rpm_limit != null && team.rpm_limit > 0 ? String(team.rpm_limit) : "Unlimited" }), /* @__PURE__ */ import_react4.default.createElement(Stat, { label: "Max budget", value: budget > 0 ? `$${budget.toFixed(2)}` : "Unlimited" })), /* @__PURE__ */ import_react4.default.createElement(import_material4.Divider, { sx: { mb: 2 } }), /* @__PURE__ */ import_react4.default.createElement(import_material4.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Models"), team.models?.length ? /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, { display: "flex", gap: 0.5, flexWrap: "wrap", mb: 2 }, team.models.map((m) => /* @__PURE__ */ import_react4.default.createElement(import_material4.Chip, { key: m, label: m, size: "small", variant: "outlined" }))) : /* @__PURE__ */ import_react4.default.createElement(import_material4.Typography, { variant: "body2", color: "text.secondary", mb: 2 }, "All models allowed"), /* @__PURE__ */ import_react4.default.createElement(import_material4.Divider, { sx: { mb: 2 } }), usageLoading ? /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, { display: "flex", justifyContent: "center", p: 2 }, /* @__PURE__ */ import_react4.default.createElement(import_material4.CircularProgress, { size: 24 })) : dailyData.length > 0 ? /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(import_material4.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Daily Spend"), /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, { height: 160, mb: 2 }, /* @__PURE__ */ import_react4.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts2.AreaChart, { data: dailyData }, /* @__PURE__ */ import_react4.default.createElement(import_recharts2.CartesianGrid, { strokeDasharray: "3 3" }), /* @__PURE__ */ import_react4.default.createElement(import_recharts2.XAxis, { dataKey: "date", tick: { fontSize: 11 } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts2.YAxis, { tick: { fontSize: 11 }, tickFormatter: (v) => `$${v.toFixed(2)}` }), /* @__PURE__ */ import_react4.default.createElement(import_recharts2.Tooltip, { formatter: (v) => [`$${v.toFixed(4)}`, "Spend"] }), /* @__PURE__ */ import_react4.default.createElement(import_recharts2.Area, { type: "monotone", dataKey: "spend", stroke: "#8884d8", fill: "#8884d8", fillOpacity: 0.3 })))), /* @__PURE__ */ import_react4.default.createElement(import_material4.Divider, { sx: { mb: 2 } })) : null, /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, { display: "flex", alignItems: "center", gap: 1, mb: 1 }, /* @__PURE__ */ import_react4.default.createElement(import_icons_material2.Memory, { fontSize: "small", color: "action" }), /* @__PURE__ */ import_react4.default.createElement(import_material4.Typography, { variant: "subtitle2", color: "text.secondary" }, "Members")), team.members_with_roles?.length ? /* @__PURE__ */ import_react4.default.createElement(import_material4.TableContainer, null, /* @__PURE__ */ import_react4.default.createElement(import_material4.Table, { size: "small" }, /* @__PURE__ */ import_react4.default.createElement(import_material4.TableHead, null, /* @__PURE__ */ import_react4.default.createElement(import_material4.TableRow, null, /* @__PURE__ */ import_react4.default.createElement(import_material4.TableCell, null, "User"), /* @__PURE__ */ import_react4.default.createElement(import_material4.TableCell, null, "Role"))), /* @__PURE__ */ import_react4.default.createElement(import_material4.TableBody, null, team.members_with_roles.map((m) => /* @__PURE__ */ import_react4.default.createElement(import_material4.TableRow, { key: m.user_id }, /* @__PURE__ */ import_react4.default.createElement(import_material4.TableCell, { sx: { fontFamily: "monospace", fontSize: 12 } }, m.user_id), /* @__PURE__ */ import_react4.default.createElement(import_material4.TableCell, null, /* @__PURE__ */ import_react4.default.createElement(
|
|
1183
|
+
)), /* @__PURE__ */ import_react4.default.createElement(import_material4.Collapse, { in: expanded }, /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, { mt: 2 }, /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, { display: "flex", alignItems: "center", gap: 1, mb: 1 }, /* @__PURE__ */ import_react4.default.createElement(import_icons_material2.Speed, { fontSize: "small", color: "action" }), /* @__PURE__ */ import_react4.default.createElement(import_material4.Typography, { variant: "subtitle2", color: "text.secondary" }, "Rate limits")), /* @__PURE__ */ import_react4.default.createElement(import_material4.Stack, { direction: "row", spacing: 3, flexWrap: "wrap", useFlexGap: true, gap: 1.5, mb: 2 }, /* @__PURE__ */ import_react4.default.createElement(Stat, { label: "TPM limit", value: team.tpm_limit != null && team.tpm_limit > 0 ? String(team.tpm_limit) : "Unlimited" }), /* @__PURE__ */ import_react4.default.createElement(Stat, { label: "RPM limit", value: team.rpm_limit != null && team.rpm_limit > 0 ? String(team.rpm_limit) : "Unlimited" }), /* @__PURE__ */ import_react4.default.createElement(Stat, { label: "Max budget", value: budget > 0 ? `$${budget.toFixed(2)}` : "Unlimited" })), /* @__PURE__ */ import_react4.default.createElement(import_material4.Divider, { sx: { mb: 2 } }), /* @__PURE__ */ import_react4.default.createElement(import_material4.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Models"), team.models?.length ? /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, { display: "flex", gap: 0.5, flexWrap: "wrap", mb: 2 }, team.models.map((m) => /* @__PURE__ */ import_react4.default.createElement(import_material4.Chip, { key: m, label: m, size: "small", variant: "outlined" }))) : /* @__PURE__ */ import_react4.default.createElement(import_material4.Typography, { variant: "body2", color: "text.secondary", mb: 2 }, "All models allowed"), /* @__PURE__ */ import_react4.default.createElement(import_material4.Divider, { sx: { mb: 2 } }), usageLoading ? /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, { display: "flex", justifyContent: "center", p: 2 }, /* @__PURE__ */ import_react4.default.createElement(import_material4.CircularProgress, { size: 24 })) : dailyData.length > 0 ? /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement(import_material4.Typography, { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "Daily Spend"), /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, { height: 160, mb: 2 }, /* @__PURE__ */ import_react4.default.createElement(import_recharts2.ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ import_react4.default.createElement(import_recharts2.AreaChart, { data: dailyData }, /* @__PURE__ */ import_react4.default.createElement(import_recharts2.CartesianGrid, { strokeDasharray: "3 3", stroke: gridStroke }), /* @__PURE__ */ import_react4.default.createElement(import_recharts2.XAxis, { dataKey: "date", tick: { fontSize: 11, fill: tickFill } }), /* @__PURE__ */ import_react4.default.createElement(import_recharts2.YAxis, { tick: { fontSize: 11, fill: tickFill }, tickFormatter: (v) => `$${v.toFixed(2)}` }), /* @__PURE__ */ import_react4.default.createElement(import_recharts2.Tooltip, { formatter: (v) => [`$${v.toFixed(4)}`, "Spend"] }), /* @__PURE__ */ import_react4.default.createElement(import_recharts2.Area, { type: "monotone", dataKey: "spend", stroke: "#8884d8", fill: "#8884d8", fillOpacity: 0.3 })))), /* @__PURE__ */ import_react4.default.createElement(import_material4.Divider, { sx: { mb: 2 } })) : null, /* @__PURE__ */ import_react4.default.createElement(import_material4.Box, { display: "flex", alignItems: "center", gap: 1, mb: 1 }, /* @__PURE__ */ import_react4.default.createElement(import_icons_material2.Memory, { fontSize: "small", color: "action" }), /* @__PURE__ */ import_react4.default.createElement(import_material4.Typography, { variant: "subtitle2", color: "text.secondary" }, "Members")), team.members_with_roles?.length ? /* @__PURE__ */ import_react4.default.createElement(import_material4.TableContainer, null, /* @__PURE__ */ import_react4.default.createElement(import_material4.Table, { size: "small" }, /* @__PURE__ */ import_react4.default.createElement(import_material4.TableHead, null, /* @__PURE__ */ import_react4.default.createElement(import_material4.TableRow, null, /* @__PURE__ */ import_react4.default.createElement(import_material4.TableCell, null, "User"), /* @__PURE__ */ import_react4.default.createElement(import_material4.TableCell, null, "Role"))), /* @__PURE__ */ import_react4.default.createElement(import_material4.TableBody, null, team.members_with_roles.map((m) => /* @__PURE__ */ import_react4.default.createElement(import_material4.TableRow, { key: m.user_id }, /* @__PURE__ */ import_react4.default.createElement(import_material4.TableCell, { sx: { fontFamily: "monospace", fontSize: 12 } }, m.user_id), /* @__PURE__ */ import_react4.default.createElement(import_material4.TableCell, null, /* @__PURE__ */ import_react4.default.createElement(
|
|
1128
1184
|
import_material4.Chip,
|
|
1129
1185
|
{
|
|
1130
1186
|
label: m.role,
|