@acarmisc/backstage-plugin-litellm 0.35.0 → 0.36.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 CHANGED
@@ -257,6 +257,10 @@ var init_api = __esm({
257
257
  async listModels() {
258
258
  return this.get("/models");
259
259
  }
260
+ /** Mints (or rotates) the caller's connect-flow key, optionally bound to one of their teams. */
261
+ async connectLocalClient(redirectUri, team) {
262
+ return this.post("/opencode/connect", { redirect_uri: redirectUri, team });
263
+ }
260
264
  async getTeams() {
261
265
  return this.get("/teams");
262
266
  }
@@ -6730,6 +6734,131 @@ var init_LiteLLMPage = __esm({
6730
6734
  }
6731
6735
  });
6732
6736
 
6737
+ // src/connect.ts
6738
+ function isLoopbackCallback(uri) {
6739
+ if (!uri) return false;
6740
+ try {
6741
+ const url = new URL(uri);
6742
+ return url.protocol === "http:" && (url.hostname === "localhost" || url.hostname === "127.0.0.1") && url.pathname === "/callback" && url.search === "" && url.hash === "";
6743
+ } catch {
6744
+ return false;
6745
+ }
6746
+ }
6747
+ function postToLoopback(redirectUri, fields) {
6748
+ const form = document.createElement("form");
6749
+ form.method = "POST";
6750
+ form.action = redirectUri;
6751
+ for (const [name, value] of fields) {
6752
+ const input = document.createElement("input");
6753
+ input.type = "hidden";
6754
+ input.name = name;
6755
+ input.value = value;
6756
+ form.appendChild(input);
6757
+ }
6758
+ document.body.appendChild(form);
6759
+ form.submit();
6760
+ }
6761
+ var init_connect = __esm({
6762
+ "src/connect.ts"() {
6763
+ "use strict";
6764
+ }
6765
+ });
6766
+
6767
+ // src/components/ConnectPage.tsx
6768
+ var ConnectPage_exports = {};
6769
+ __export(ConnectPage_exports, {
6770
+ ConnectPage: () => ConnectPage
6771
+ });
6772
+ var import_react14, import_Alert7, import_Box18, import_Button8, import_Checkbox3, import_FormControlLabel3, import_FormGroup, import_Paper9, import_Typography16, import_react_router_dom2, import_react_use3, import_core_plugin_api6, import_core_components4, import_jsx_runtime19, ConnectPage;
6773
+ var init_ConnectPage = __esm({
6774
+ "src/components/ConnectPage.tsx"() {
6775
+ "use strict";
6776
+ import_react14 = require("react");
6777
+ import_Alert7 = __toESM(require("@mui/material/Alert"));
6778
+ import_Box18 = __toESM(require("@mui/material/Box"));
6779
+ import_Button8 = __toESM(require("@mui/material/Button"));
6780
+ import_Checkbox3 = __toESM(require("@mui/material/Checkbox"));
6781
+ import_FormControlLabel3 = __toESM(require("@mui/material/FormControlLabel"));
6782
+ import_FormGroup = __toESM(require("@mui/material/FormGroup"));
6783
+ import_Paper9 = __toESM(require("@mui/material/Paper"));
6784
+ import_Typography16 = __toESM(require("@mui/material/Typography"));
6785
+ import_react_router_dom2 = require("react-router-dom");
6786
+ import_react_use3 = require("react-use");
6787
+ import_core_plugin_api6 = require("@backstage/core-plugin-api");
6788
+ import_core_components4 = require("@backstage/core-components");
6789
+ init_api();
6790
+ init_connect();
6791
+ import_jsx_runtime19 = require("react/jsx-runtime");
6792
+ ConnectPage = () => {
6793
+ const api = (0, import_core_plugin_api6.useApi)(liteLlmApiRef);
6794
+ const [params] = (0, import_react_router_dom2.useSearchParams)();
6795
+ const redirectUri = params.get("redirect_uri");
6796
+ const state = params.get("state") ?? "";
6797
+ const client = params.get("client") || "a local application";
6798
+ const teams = (0, import_react_use3.useAsync)(() => api.getTeams(), [api]);
6799
+ const [selected, setSelected] = (0, import_react14.useState)();
6800
+ const [busy, setBusy] = (0, import_react14.useState)(false);
6801
+ const [error, setError] = (0, import_react14.useState)();
6802
+ if (!isLoopbackCallback(redirectUri)) {
6803
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_core_components4.Content, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_Alert7.default, { severity: "error", children: "Invalid connection link: redirect_uri must be http://localhost:<port>/callback." }) });
6804
+ }
6805
+ if (teams.loading) return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_core_components4.Progress, {});
6806
+ const all = teams.value ?? [];
6807
+ const chosen = selected ?? new Set(all.map((t) => t.team_id));
6808
+ const toggle = (id) => {
6809
+ const next = new Set(chosen);
6810
+ if (!next.delete(id)) next.add(id);
6811
+ setSelected(next);
6812
+ };
6813
+ const connect = async () => {
6814
+ setBusy(true);
6815
+ setError(void 0);
6816
+ try {
6817
+ const ids = all.length ? all.filter((t) => chosen.has(t.team_id)).map((t) => t.team_id) : [void 0];
6818
+ const keys = [];
6819
+ for (const id of ids) keys.push(["key", (await api.connectLocalClient(redirectUri, id)).key]);
6820
+ postToLoopback(redirectUri, [["state", state], ...keys]);
6821
+ } catch (e) {
6822
+ setError(e instanceof Error ? e.message : String(e));
6823
+ setBusy(false);
6824
+ }
6825
+ };
6826
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_core_components4.Content, { children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_Box18.default, { maxWidth: 520, mx: "auto", mt: 4, children: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_Paper9.default, { sx: { p: 3 }, children: [
6827
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_Typography16.default, { variant: "h5", gutterBottom: true, children: [
6828
+ "Connect ",
6829
+ client
6830
+ ] }),
6831
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_Typography16.default, { variant: "body2", color: "text.secondary", paragraph: true, children: [
6832
+ client,
6833
+ " will receive an API key for each selected team. Connecting again replaces the keys created by a previous connection."
6834
+ ] }),
6835
+ teams.error && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_Alert7.default, { severity: "error", children: [
6836
+ "Could not load your teams: ",
6837
+ teams.error.message
6838
+ ] }),
6839
+ all.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_FormGroup.default, { sx: { mb: 2 }, children: all.map((t) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
6840
+ import_FormControlLabel3.default,
6841
+ {
6842
+ control: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_Checkbox3.default, { checked: chosen.has(t.team_id), onChange: () => toggle(t.team_id) }),
6843
+ label: t.team_alias ?? t.team_id
6844
+ },
6845
+ t.team_id
6846
+ )) }),
6847
+ error && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_Alert7.default, { severity: "error", sx: { mb: 2 }, children: error }),
6848
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
6849
+ import_Button8.default,
6850
+ {
6851
+ variant: "contained",
6852
+ onClick: connect,
6853
+ disabled: busy || !!teams.error || all.length > 0 && chosen.size === 0,
6854
+ children: busy ? "Connecting\u2026" : "Connect"
6855
+ }
6856
+ )
6857
+ ] }) }) });
6858
+ };
6859
+ }
6860
+ });
6861
+
6733
6862
  // src/index.ts
6734
6863
  var index_exports = {};
6735
6864
  __export(index_exports, {
@@ -6761,7 +6890,7 @@ var import_icons_material10 = require("@mui/icons-material");
6761
6890
  var import_frontend_plugin_api4 = require("@backstage/frontend-plugin-api");
6762
6891
  init_api();
6763
6892
  init_routes();
6764
- var import_jsx_runtime19 = require("react/jsx-runtime");
6893
+ var import_jsx_runtime20 = require("react/jsx-runtime");
6765
6894
  var liteLlmApi = import_frontend_plugin_api4.ApiBlueprint.make({
6766
6895
  params: (defineParams) => defineParams({
6767
6896
  api: liteLlmApiRef,
@@ -6773,11 +6902,21 @@ var liteLlmPage = import_frontend_plugin_api4.PageBlueprint.make({
6773
6902
  params: {
6774
6903
  path: "/litellm",
6775
6904
  title: "LiteLLM",
6776
- icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_icons_material10.TrendingUp, {}),
6905
+ icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_icons_material10.TrendingUp, {}),
6777
6906
  routeRef: rootRouteRef,
6778
6907
  loader: async () => {
6779
6908
  const { LiteLLMPage: LiteLLMPage2 } = await Promise.resolve().then(() => (init_LiteLLMPage(), LiteLLMPage_exports));
6780
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(LiteLLMPage2, {});
6909
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LiteLLMPage2, {});
6910
+ }
6911
+ }
6912
+ });
6913
+ var liteLlmConnectPage = import_frontend_plugin_api4.PageBlueprint.make({
6914
+ name: "connect",
6915
+ params: {
6916
+ path: "/litellm/connect",
6917
+ loader: async () => {
6918
+ const { ConnectPage: ConnectPage2 } = await Promise.resolve().then(() => (init_ConnectPage(), ConnectPage_exports));
6919
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ConnectPage2, {});
6781
6920
  }
6782
6921
  }
6783
6922
  });
@@ -6786,7 +6925,7 @@ var litellmPlugin = (0, import_frontend_plugin_api4.createFrontendPlugin)({
6786
6925
  routes: {
6787
6926
  root: rootRouteRef
6788
6927
  },
6789
- extensions: [liteLlmApi, liteLlmPage]
6928
+ extensions: [liteLlmApi, liteLlmPage, liteLlmConnectPage]
6790
6929
  });
6791
6930
 
6792
6931
  // src/index.ts
@@ -6797,18 +6936,18 @@ init_UsageStats();
6797
6936
  init_TeamUsage();
6798
6937
 
6799
6938
  // src/components/LiteLLMHomeWidget.tsx
6800
- var import_react14 = require("react");
6801
- var import_Paper9 = __toESM(require("@mui/material/Paper"));
6802
- var import_Box18 = __toESM(require("@mui/material/Box"));
6803
- var import_Typography16 = __toESM(require("@mui/material/Typography"));
6939
+ var import_react15 = require("react");
6940
+ var import_Paper10 = __toESM(require("@mui/material/Paper"));
6941
+ var import_Box19 = __toESM(require("@mui/material/Box"));
6942
+ var import_Typography17 = __toESM(require("@mui/material/Typography"));
6804
6943
  var import_FormControl2 = __toESM(require("@mui/material/FormControl"));
6805
6944
  var import_Select2 = __toESM(require("@mui/material/Select"));
6806
6945
  var import_MenuItem6 = __toESM(require("@mui/material/MenuItem"));
6807
6946
  var import_Skeleton7 = __toESM(require("@mui/material/Skeleton"));
6808
6947
  var import_recharts3 = require("recharts");
6809
- var import_core_plugin_api6 = require("@backstage/core-plugin-api");
6948
+ var import_core_plugin_api7 = require("@backstage/core-plugin-api");
6810
6949
  var import_frontend_plugin_api5 = require("@backstage/frontend-plugin-api");
6811
- var import_core_components4 = require("@backstage/core-components");
6950
+ var import_core_components5 = require("@backstage/core-components");
6812
6951
  init_useLiteLLMProfile();
6813
6952
  init_api();
6814
6953
  init_routes();
@@ -6860,7 +6999,7 @@ function usageSummary(usage) {
6860
6999
  }
6861
7000
 
6862
7001
  // src/components/LiteLLMHomeWidget.tsx
6863
- var import_jsx_runtime20 = require("react/jsx-runtime");
7002
+ var import_jsx_runtime21 = require("react/jsx-runtime");
6864
7003
  function presetToDateRange(preset) {
6865
7004
  const end = /* @__PURE__ */ new Date();
6866
7005
  const start = /* @__PURE__ */ new Date();
@@ -6878,14 +7017,14 @@ var LiteLLMHomeWidget = ({
6878
7017
  title = "LiteLLM Usage",
6879
7018
  bare = false
6880
7019
  }) => {
6881
- const api = (0, import_core_plugin_api6.useApi)(liteLlmApiRef);
7020
+ const api = (0, import_core_plugin_api7.useApi)(liteLlmApiRef);
6882
7021
  const moduleRouteRef = (0, import_frontend_plugin_api5.useRouteRef)(rootRouteRef);
6883
7022
  const { userInfo, keys, loading: profileLoading, error: profileError } = useLiteLLMProfile();
6884
- const [period, setPeriod] = (0, import_react14.useState)(defaultPeriod);
6885
- const [usageLoading, setUsageLoading] = (0, import_react14.useState)(true);
6886
- const [usageError, setUsageError] = (0, import_react14.useState)(null);
6887
- const [usage, setUsage] = (0, import_react14.useState)(null);
6888
- (0, import_react14.useEffect)(() => {
7023
+ const [period, setPeriod] = (0, import_react15.useState)(defaultPeriod);
7024
+ const [usageLoading, setUsageLoading] = (0, import_react15.useState)(true);
7025
+ const [usageError, setUsageError] = (0, import_react15.useState)(null);
7026
+ const [usage, setUsage] = (0, import_react15.useState)(null);
7027
+ (0, import_react15.useEffect)(() => {
6889
7028
  let cancelled = false;
6890
7029
  setUsageLoading(true);
6891
7030
  setUsageError(null);
@@ -6907,7 +7046,7 @@ var LiteLLMHomeWidget = ({
6907
7046
  cancelled = true;
6908
7047
  };
6909
7048
  }, [api, period]);
6910
- const viewState = (0, import_react14.useMemo)(
7049
+ const viewState = (0, import_react15.useMemo)(
6911
7050
  () => widgetViewState({
6912
7051
  loading: profileLoading || usageLoading,
6913
7052
  error: profileError,
@@ -6917,7 +7056,7 @@ var LiteLLMHomeWidget = ({
6917
7056
  }),
6918
7057
  [profileLoading, usageLoading, profileError, userInfo, usageError, keys]
6919
7058
  );
6920
- const Wrapper = bare ? import_Box18.default : import_Paper9.default;
7059
+ const Wrapper = bare ? import_Box19.default : import_Paper10.default;
6921
7060
  const partialFailure = !usageLoading && usageError && usage;
6922
7061
  const dailyData = (usage?.daily_usage ?? []).map((d) => ({
6923
7062
  date: d.date,
@@ -6929,10 +7068,10 @@ var LiteLLMHomeWidget = ({
6929
7068
  const endDate = toLocalDay(end);
6930
7069
  const dateRangeCaption = rangeCaption(startDate, endDate);
6931
7070
  const sparklineAriaLabelText = sparklineAriaLabel(dailyData);
6932
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(Wrapper, { sx: bare ? { height: "100%" } : { p: 2, height: "100%" }, children: [
6933
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_Box18.default, { display: "flex", justifyContent: bare ? "flex-end" : "space-between", alignItems: "center", mb: 1.5, children: [
6934
- !bare && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_Typography16.default, { variant: "h6", children: title }),
6935
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_FormControl2.default, { size: "small", sx: { minWidth: 90 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
7071
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Wrapper, { sx: bare ? { height: "100%" } : { p: 2, height: "100%" }, children: [
7072
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { display: "flex", justifyContent: bare ? "flex-end" : "space-between", alignItems: "center", mb: 1.5, children: [
7073
+ !bare && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Typography17.default, { variant: "h6", children: title }),
7074
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_FormControl2.default, { size: "small", sx: { minWidth: 90 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
6936
7075
  import_Select2.default,
6937
7076
  {
6938
7077
  value: period,
@@ -6940,23 +7079,23 @@ var LiteLLMHomeWidget = ({
6940
7079
  displayEmpty: true,
6941
7080
  inputProps: { "aria-label": "Usage period" },
6942
7081
  children: [
6943
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_MenuItem6.default, { value: "today", children: "Today" }),
6944
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_MenuItem6.default, { value: "7d", children: "7d" }),
6945
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_MenuItem6.default, { value: "30d", children: "30d" })
7082
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_MenuItem6.default, { value: "today", children: "Today" }),
7083
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_MenuItem6.default, { value: "7d", children: "7d" }),
7084
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_MenuItem6.default, { value: "30d", children: "30d" })
6946
7085
  ]
6947
7086
  }
6948
7087
  ) })
6949
7088
  ] }),
6950
- viewState.kind === "loading" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_Box18.default, { sx: { minHeight: 120 }, children: [
6951
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_Skeleton7.default, { variant: "text", width: "60%", height: 20, sx: { mb: 1 } }),
6952
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_Skeleton7.default, { variant: "rectangular", width: "100%", height: 100 })
7089
+ viewState.kind === "loading" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { sx: { minHeight: 120 }, children: [
7090
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Skeleton7.default, { variant: "text", width: "60%", height: 20, sx: { mb: 1 } }),
7091
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Skeleton7.default, { variant: "rectangular", width: "100%", height: 100 })
6953
7092
  ] }),
6954
- viewState.kind === "error" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_Typography16.default, { variant: "body2", color: "text.secondary", sx: { mt: 1 }, children: viewState.message }),
6955
- viewState.kind === "unprovisioned" && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_Typography16.default, { variant: "body2", color: "text.secondary", sx: { mt: 1 }, children: UNPROVISIONED_MSG }),
6956
- viewState.kind === "ready" && partialFailure && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_Box18.default, { sx: { mt: 1, mb: 1, p: 1, backgroundColor: "action.hover", borderRadius: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_Typography16.default, { variant: "body2", color: "text.secondary", children: USAGE_UNAVAILABLE_MSG }) }),
6957
- viewState.kind === "ready" && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
6958
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6959
- import_Typography16.default,
7093
+ viewState.kind === "error" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Typography17.default, { variant: "body2", color: "text.secondary", sx: { mt: 1 }, children: viewState.message }),
7094
+ viewState.kind === "unprovisioned" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Typography17.default, { variant: "body2", color: "text.secondary", sx: { mt: 1 }, children: UNPROVISIONED_MSG }),
7095
+ viewState.kind === "ready" && partialFailure && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Box19.default, { sx: { mt: 1, mb: 1, p: 1, backgroundColor: "action.hover", borderRadius: 1 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Typography17.default, { variant: "body2", color: "text.secondary", children: USAGE_UNAVAILABLE_MSG }) }),
7096
+ viewState.kind === "ready" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
7097
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7098
+ import_Typography17.default,
6960
7099
  {
6961
7100
  variant: "body2",
6962
7101
  sx: {
@@ -6967,18 +7106,18 @@ var LiteLLMHomeWidget = ({
6967
7106
  children: viewState.usageUnavailable ? USAGE_UNAVAILABLE_MSG : usageSummary(usage)
6968
7107
  }
6969
7108
  ),
6970
- hasSparkline && !viewState.usageUnavailable && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
6971
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
6972
- import_Box18.default,
7109
+ hasSparkline && !viewState.usageUnavailable && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
7110
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7111
+ import_Box19.default,
6973
7112
  {
6974
7113
  height: 80,
6975
7114
  role: "img",
6976
7115
  "aria-label": sparklineAriaLabelText,
6977
7116
  sx: { mb: 0.5 },
6978
- children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_recharts3.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_recharts3.AreaChart, { data: dailyData, margin: { top: 4, right: 0, bottom: 0, left: 0 }, children: [
6979
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_recharts3.XAxis, { dataKey: "date", hide: true }),
6980
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_recharts3.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ChartTooltip, { valueFormatter: fmtUsd }) }),
6981
- /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
7117
+ children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_recharts3.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_recharts3.AreaChart, { data: dailyData, margin: { top: 4, right: 0, bottom: 0, left: 0 }, children: [
7118
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_recharts3.XAxis, { dataKey: "date", hide: true }),
7119
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_recharts3.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ChartTooltip, { valueFormatter: fmtUsd }) }),
7120
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6982
7121
  import_recharts3.Area,
6983
7122
  {
6984
7123
  type: "monotone",
@@ -6994,13 +7133,13 @@ var LiteLLMHomeWidget = ({
6994
7133
  ] }) })
6995
7134
  }
6996
7135
  ),
6997
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_Typography16.default, { variant: "caption", color: "text.secondary", sx: { display: "block", mb: 1 }, children: [
7136
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Typography17.default, { variant: "caption", color: "text.secondary", sx: { display: "block", mb: 1 }, children: [
6998
7137
  "daily spend (",
6999
7138
  dateRangeCaption,
7000
7139
  ")"
7001
7140
  ] })
7002
7141
  ] }),
7003
- moduleRouteRef?.() && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_Typography16.default, { variant: "caption", sx: { mt: 1, display: "block" }, children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_core_components4.Link, { to: moduleRouteRef(), color: "primary", children: "Open LiteLLM \u2192" }) })
7142
+ moduleRouteRef?.() && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Typography17.default, { variant: "caption", sx: { mt: 1, display: "block" }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_core_components5.Link, { to: moduleRouteRef(), color: "primary", children: "Open LiteLLM \u2192" }) })
7004
7143
  ] })
7005
7144
  ] });
7006
7145
  };
@@ -7009,20 +7148,20 @@ var LiteLLMHomeWidget = ({
7009
7148
  init_LiteLLMBudgetWidget();
7010
7149
 
7011
7150
  // src/components/LiteLLMBudgetGauges.tsx
7012
- var import_react15 = require("react");
7151
+ var import_react16 = require("react");
7013
7152
  var import_frontend_plugin_api6 = require("@backstage/frontend-plugin-api");
7014
- var import_Paper10 = __toESM(require("@mui/material/Paper"));
7015
- var import_Box19 = __toESM(require("@mui/material/Box"));
7016
- var import_Button8 = __toESM(require("@mui/material/Button"));
7017
- var import_Typography17 = __toESM(require("@mui/material/Typography"));
7153
+ var import_Paper11 = __toESM(require("@mui/material/Paper"));
7154
+ var import_Box20 = __toESM(require("@mui/material/Box"));
7155
+ var import_Button9 = __toESM(require("@mui/material/Button"));
7156
+ var import_Typography18 = __toESM(require("@mui/material/Typography"));
7018
7157
  var import_Skeleton8 = __toESM(require("@mui/material/Skeleton"));
7019
7158
  var import_Collapse4 = __toESM(require("@mui/material/Collapse"));
7020
7159
  var import_styles13 = require("@mui/material/styles");
7021
7160
  var import_useMediaQuery = __toESM(require("@mui/material/useMediaQuery"));
7022
7161
  var import_icons_material11 = require("@mui/icons-material");
7023
7162
  var import_recharts4 = require("recharts");
7024
- var import_core_plugin_api7 = require("@backstage/core-plugin-api");
7025
- var import_core_components5 = require("@backstage/core-components");
7163
+ var import_core_plugin_api8 = require("@backstage/core-plugin-api");
7164
+ var import_core_components6 = require("@backstage/core-components");
7026
7165
  init_useLiteLLMProfile();
7027
7166
  init_api();
7028
7167
  init_format();
@@ -7053,7 +7192,7 @@ init_GenerateKeyButton();
7053
7192
  init_BudgetLimitList();
7054
7193
  init_budget();
7055
7194
  init_routes();
7056
- var import_jsx_runtime21 = require("react/jsx-runtime");
7195
+ var import_jsx_runtime22 = require("react/jsx-runtime");
7057
7196
  var LEVEL = {
7058
7197
  key: { name: "Key", none: "No cap (unlimited)" },
7059
7198
  user: { name: "User", none: "No personal budget" },
@@ -7077,8 +7216,8 @@ function resetLabel(limit) {
7077
7216
  const window2 = fmtBudgetDuration(limit.budgetDuration);
7078
7217
  return window2 ? `resets ${window2}` : "never resets";
7079
7218
  }
7080
- var Tag = ({ children, tone, title }) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7081
- import_Typography17.default,
7219
+ var Tag = ({ children, tone, title }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7220
+ import_Typography18.default,
7082
7221
  {
7083
7222
  title,
7084
7223
  sx: (theme) => ({
@@ -7095,10 +7234,10 @@ var Tag = ({ children, tone, title }) => /* @__PURE__ */ (0, import_jsx_runtime2
7095
7234
  children
7096
7235
  }
7097
7236
  );
7098
- var InlineStat = ({ label, value, hint, tone = "accent", title }) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { sx: { minWidth: 0, flex: 1 }, children: [
7099
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { sx: { display: "flex", alignItems: "center", gap: 0.625, minWidth: 0 }, children: [
7100
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7101
- import_Box19.default,
7237
+ var InlineStat = ({ label, value, hint, tone = "accent", title }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { minWidth: 0, flex: 1 }, children: [
7238
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { display: "flex", alignItems: "center", gap: 0.625, minWidth: 0 }, children: [
7239
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7240
+ import_Box20.default,
7102
7241
  {
7103
7242
  sx: (theme) => ({
7104
7243
  width: 6,
@@ -7109,10 +7248,10 @@ var InlineStat = ({ label, value, hint, tone = "accent", title }) => /* @__PURE_
7109
7248
  })
7110
7249
  }
7111
7250
  ),
7112
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Tag, { children: label })
7251
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Tag, { children: label })
7113
7252
  ] }),
7114
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7115
- import_Typography17.default,
7253
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7254
+ import_Typography18.default,
7116
7255
  {
7117
7256
  title,
7118
7257
  sx: {
@@ -7128,8 +7267,8 @@ var InlineStat = ({ label, value, hint, tone = "accent", title }) => /* @__PURE_
7128
7267
  children: value
7129
7268
  }
7130
7269
  ),
7131
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7132
- import_Typography17.default,
7270
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7271
+ import_Typography18.default,
7133
7272
  {
7134
7273
  variant: "caption",
7135
7274
  color: "text.secondary",
@@ -7159,10 +7298,10 @@ var LevelRow = ({
7159
7298
  const subNote = () => {
7160
7299
  if (overCap) return "Over cap";
7161
7300
  if (extra > 0 && keysHref) {
7162
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7163
- import_Typography17.default,
7301
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
7302
+ import_Typography18.default,
7164
7303
  {
7165
- component: import_core_components5.Link,
7304
+ component: import_core_components6.Link,
7166
7305
  to: keysHref,
7167
7306
  variant: "caption",
7168
7307
  sx: {
@@ -7182,8 +7321,8 @@ var LevelRow = ({
7182
7321
  return limit?.sublabel ?? null;
7183
7322
  };
7184
7323
  const gaugeAriaLabel = limit ? `${name} budget used: ${Math.round(limit.pct)}%` : `${name} \u2014 no cap`;
7185
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7186
- import_Box19.default,
7324
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
7325
+ import_Box20.default,
7187
7326
  {
7188
7327
  sx: {
7189
7328
  display: "grid",
@@ -7194,7 +7333,7 @@ var LevelRow = ({
7194
7333
  minWidth: 0
7195
7334
  },
7196
7335
  children: [
7197
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7336
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7198
7337
  Gauge,
7199
7338
  {
7200
7339
  value: limit?.pct ?? 0,
@@ -7204,11 +7343,11 @@ var LevelRow = ({
7204
7343
  ariaLabel: gaugeAriaLabel
7205
7344
  }
7206
7345
  ),
7207
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { sx: { minWidth: 0 }, children: [
7208
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Tag, { tone: tone === "warning" || tone === "danger" ? tone : void 0, children: name }),
7209
- limit ? /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
7210
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7211
- import_Typography17.default,
7346
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { minWidth: 0 }, children: [
7347
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Tag, { tone: tone === "warning" || tone === "danger" ? tone : void 0, children: name }),
7348
+ limit ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
7349
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7350
+ import_Typography18.default,
7212
7351
  {
7213
7352
  variant: "caption",
7214
7353
  title: limit.sublabel ? `${limit.label} \xB7 ${limit.sublabel}` : limit.label,
@@ -7224,8 +7363,8 @@ var LevelRow = ({
7224
7363
  children: limit.label
7225
7364
  }
7226
7365
  ),
7227
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7228
- import_Typography17.default,
7366
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7367
+ import_Typography18.default,
7229
7368
  {
7230
7369
  variant: "caption",
7231
7370
  color: overCap ? "error" : "text.secondary",
@@ -7241,8 +7380,8 @@ var LevelRow = ({
7241
7380
  children: subNote()
7242
7381
  }
7243
7382
  )
7244
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7245
- import_Typography17.default,
7383
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7384
+ import_Typography18.default,
7246
7385
  {
7247
7386
  variant: "caption",
7248
7387
  color: "text.secondary",
@@ -7258,9 +7397,9 @@ var LevelRow = ({
7258
7397
  }
7259
7398
  )
7260
7399
  ] }),
7261
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { sx: { minWidth: 0, textAlign: "right" }, children: [
7262
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7263
- import_Typography17.default,
7400
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { minWidth: 0, textAlign: "right" }, children: [
7401
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7402
+ import_Typography18.default,
7264
7403
  {
7265
7404
  title: limit ? `${fmtUsd(limit.spend)} of ${fmtUsd(limit.budget)}` : void 0,
7266
7405
  sx: {
@@ -7277,8 +7416,8 @@ var LevelRow = ({
7277
7416
  children: amountCaption(limit)
7278
7417
  }
7279
7418
  ),
7280
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7281
- import_Typography17.default,
7419
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7420
+ import_Typography18.default,
7282
7421
  {
7283
7422
  variant: "caption",
7284
7423
  color: "text.secondary",
@@ -7309,11 +7448,11 @@ function amountNote(limit) {
7309
7448
  var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, maxBudget }) => {
7310
7449
  const renderPlot = () => {
7311
7450
  if (loading) {
7312
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Skeleton8.default, { variant: "rectangular", width: "100%", height: "100%" });
7451
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Skeleton8.default, { variant: "rectangular", width: "100%", height: "100%" });
7313
7452
  }
7314
7453
  if (data.length === 0) {
7315
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7316
- import_Box19.default,
7454
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7455
+ import_Box20.default,
7317
7456
  {
7318
7457
  display: "flex",
7319
7458
  justifyContent: "center",
@@ -7324,10 +7463,10 @@ var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, m
7324
7463
  }
7325
7464
  );
7326
7465
  }
7327
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_recharts4.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_recharts4.AreaChart, { data, margin: { top: 4, right: 0, bottom: 0, left: 0 }, children: [
7328
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_recharts4.XAxis, { dataKey: "date", hide: true }),
7329
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_recharts4.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ChartTooltip, { valueFormatter: fmtUsd }) }),
7330
- maxBudget !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7466
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_recharts4.ResponsiveContainer, { width: "100%", height: "100%", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_recharts4.AreaChart, { data, margin: { top: 4, right: 0, bottom: 0, left: 0 }, children: [
7467
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_recharts4.XAxis, { dataKey: "date", hide: true }),
7468
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_recharts4.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ChartTooltip, { valueFormatter: fmtUsd }) }),
7469
+ maxBudget !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7331
7470
  import_recharts4.ReferenceLine,
7332
7471
  {
7333
7472
  y: maxBudget,
@@ -7336,7 +7475,7 @@ var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, m
7336
7475
  strokeWidth: 1
7337
7476
  }
7338
7477
  ),
7339
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7478
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7340
7479
  import_recharts4.Area,
7341
7480
  {
7342
7481
  type: "monotone",
@@ -7358,10 +7497,10 @@ var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, m
7358
7497
  if (data.length === 0) return "No spend this month";
7359
7498
  return mtdCaption();
7360
7499
  })();
7361
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { role: "img", "aria-label": sparklineAriaLabel(data), sx: { minWidth: 0 }, children: [
7362
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Box19.default, { sx: { height, width: "100%" }, children: renderPlot() }),
7363
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7364
- import_Box19.default,
7500
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { role: "img", "aria-label": sparklineAriaLabel(data), sx: { minWidth: 0 }, children: [
7501
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Box20.default, { sx: { height, width: "100%" }, children: renderPlot() }),
7502
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
7503
+ import_Box20.default,
7365
7504
  {
7366
7505
  sx: {
7367
7506
  display: "flex",
@@ -7372,10 +7511,10 @@ var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, m
7372
7511
  minWidth: 0
7373
7512
  },
7374
7513
  children: [
7375
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { sx: { display: "flex", alignItems: "baseline", gap: 0.75, minWidth: 0 }, children: [
7376
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Tag, { children: "Spent (mtd)" }),
7377
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7378
- import_Typography17.default,
7514
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { display: "flex", alignItems: "baseline", gap: 0.75, minWidth: 0 }, children: [
7515
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Tag, { children: "Spent (mtd)" }),
7516
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7517
+ import_Typography18.default,
7379
7518
  {
7380
7519
  variant: "caption",
7381
7520
  color: "text.secondary",
@@ -7384,8 +7523,8 @@ var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, m
7384
7523
  }
7385
7524
  )
7386
7525
  ] }),
7387
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7388
- import_Typography17.default,
7526
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7527
+ import_Typography18.default,
7389
7528
  {
7390
7529
  title: loading || usageUnavailable ? void 0 : `${fmtUsd(mtdSpend)} spent month to date`,
7391
7530
  sx: {
@@ -7429,33 +7568,33 @@ var LiteLLMBudgetGauges = ({
7429
7568
  teams: propTeams,
7430
7569
  keys: propKeys
7431
7570
  }) => {
7432
- const api = (0, import_core_plugin_api7.useApi)(liteLlmApiRef);
7571
+ const api = (0, import_core_plugin_api8.useApi)(liteLlmApiRef);
7433
7572
  const theme = (0, import_styles13.useTheme)();
7434
7573
  const isSmallScreen = (0, import_useMediaQuery.default)(theme.breakpoints.down("sm"));
7435
7574
  const gaugeSize = isSmallScreen ? Math.min(48, size) : size;
7436
- const expandedRegionId = (0, import_react15.useId)();
7575
+ const expandedRegionId = (0, import_react16.useId)();
7437
7576
  const moduleRouteRef = (0, import_frontend_plugin_api6.useRouteRef)(rootRouteRef);
7438
7577
  const moduleHref = propModuleHref ?? moduleRouteRef?.();
7439
7578
  const { userInfo: hookUserInfo, teams: hookTeams, keys: hookKeys, loading: profileLoading, error: profileError } = useLiteLLMProfile();
7440
- const [usageLoading, setUsageLoading] = (0, import_react15.useState)(true);
7441
- const [usageError, setUsageError] = (0, import_react15.useState)(null);
7442
- const [dailySpend, setDailySpend] = (0, import_react15.useState)([]);
7443
- const [mtdSpend, setMtdSpend] = (0, import_react15.useState)(0);
7579
+ const [usageLoading, setUsageLoading] = (0, import_react16.useState)(true);
7580
+ const [usageError, setUsageError] = (0, import_react16.useState)(null);
7581
+ const [dailySpend, setDailySpend] = (0, import_react16.useState)([]);
7582
+ const [mtdSpend, setMtdSpend] = (0, import_react16.useState)(0);
7444
7583
  const user = propUserInfo !== void 0 ? propUserInfo : hookUserInfo;
7445
7584
  const teams = propTeams !== void 0 ? propTeams : hookTeams;
7446
7585
  const keys = propKeys !== void 0 ? propKeys : hookKeys;
7447
7586
  const loading = propUserInfo === void 0 ? profileLoading : usageLoading;
7448
7587
  const error = propUserInfo === void 0 ? profileError : usageError;
7449
7588
  const isControlled = expanded !== void 0;
7450
- const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react15.useState)(defaultExpanded);
7589
+ const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react16.useState)(defaultExpanded);
7451
7590
  const isExpanded = isControlled ? expanded : uncontrolledExpanded;
7452
- const toggleExpanded = (0, import_react15.useCallback)(() => {
7591
+ const toggleExpanded = (0, import_react16.useCallback)(() => {
7453
7592
  const next = !isExpanded;
7454
7593
  if (!isControlled) setUncontrolledExpanded(next);
7455
7594
  onExpandedChange?.(next);
7456
7595
  }, [isControlled, isExpanded, onExpandedChange]);
7457
7596
  const keysTabHref = keysHref ?? (moduleHref ? `${moduleHref}?tab=keys` : void 0);
7458
- (0, import_react15.useEffect)(() => {
7597
+ (0, import_react16.useEffect)(() => {
7459
7598
  let cancelled = false;
7460
7599
  setUsageLoading(true);
7461
7600
  setUsageError(null);
@@ -7483,21 +7622,21 @@ var LiteLLMBudgetGauges = ({
7483
7622
  cancelled = true;
7484
7623
  };
7485
7624
  }, [api]);
7486
- const summary = (0, import_react15.useMemo)(
7625
+ const summary = (0, import_react16.useMemo)(
7487
7626
  () => buildBudgetSummary(user, teams, keys, keys.length),
7488
7627
  [user, teams, keys]
7489
7628
  );
7490
- const gauges = (0, import_react15.useMemo)(() => buildBudgetGauges(summary), [summary]);
7491
- const headline = (0, import_react15.useMemo)(() => budgetHeadline(summary), [summary]);
7492
- const expandedSummary = (0, import_react15.useMemo)(
7629
+ const gauges = (0, import_react16.useMemo)(() => buildBudgetGauges(summary), [summary]);
7630
+ const headline = (0, import_react16.useMemo)(() => budgetHeadline(summary), [summary]);
7631
+ const expandedSummary = (0, import_react16.useMemo)(
7493
7632
  () => buildBudgetSummary(user, teams, keys, maxExpandedKeys),
7494
7633
  [user, teams, keys, maxExpandedKeys]
7495
7634
  );
7496
- const expandedLimits = (0, import_react15.useMemo)(
7635
+ const expandedLimits = (0, import_react16.useMemo)(
7497
7636
  () => allBudgetLimits(expandedSummary),
7498
7637
  [expandedSummary]
7499
7638
  );
7500
- const viewState = (0, import_react15.useMemo)(
7639
+ const viewState = (0, import_react16.useMemo)(
7501
7640
  () => widgetViewState({
7502
7641
  loading,
7503
7642
  error: profileError,
@@ -7514,7 +7653,7 @@ var LiteLLMBudgetGauges = ({
7514
7653
  const yesterdaySpend = dailySpend.some((d) => d.date === toLocalDay(yesterday)) ? spendOnDay(dailySpend, yesterday) : null;
7515
7654
  const todayHint = yesterdaySpend === null ? void 0 : `vs ${fmtUsd(yesterdaySpend)} yesterday`;
7516
7655
  const summaryText = headline.count === 0 ? "no limits apply" : `${headline.count} limit${headline.count === 1 ? "" : "s"}`;
7517
- const resolvedCtas = (0, import_react15.useMemo)(() => {
7656
+ const resolvedCtas = (0, import_react16.useMemo)(() => {
7518
7657
  return resolveCtas({
7519
7658
  ctas,
7520
7659
  hasKeys: (keys?.length ?? 0) > 0,
@@ -7528,20 +7667,20 @@ var LiteLLMBudgetGauges = ({
7528
7667
  switch (cta.kind) {
7529
7668
  case "new-key":
7530
7669
  if (!onCreateKey && !moduleHref) return null;
7531
- return onCreateKey ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(GenerateKeyButton, { size: "small", label, onClick: onCreateKey }, key) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(GenerateKeyButton, { size: "small", label, to: `${moduleHref}?generate=1` }, key);
7670
+ return onCreateKey ? /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GenerateKeyButton, { size: "small", label, onClick: onCreateKey }, key) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(GenerateKeyButton, { size: "small", label, to: `${moduleHref}?generate=1` }, key);
7532
7671
  case "module":
7533
7672
  if (!moduleHref) return null;
7534
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Button8.default, { size: "small", variant: "text", component: import_core_components5.Link, to: moduleHref, children: label }, key);
7673
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Button9.default, { size: "small", variant: "text", component: import_core_components6.Link, to: moduleHref, children: label }, key);
7535
7674
  case "all-limits":
7536
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7537
- import_Button8.default,
7675
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7676
+ import_Button9.default,
7538
7677
  {
7539
7678
  size: "small",
7540
7679
  variant: "text",
7541
7680
  onClick: toggleExpanded,
7542
7681
  "aria-expanded": isExpanded,
7543
7682
  "aria-controls": expandedRegionId,
7544
- endIcon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7683
+ endIcon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7545
7684
  import_icons_material11.ExpandMore,
7546
7685
  {
7547
7686
  sx: (muiTheme) => ({
@@ -7560,11 +7699,11 @@ var LiteLLMBudgetGauges = ({
7560
7699
  }
7561
7700
  };
7562
7701
  const hasFooter = resolvedCtas.length > 0 || !!action;
7563
- const Wrapper = bare ? import_Box19.default : import_Paper10.default;
7564
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Wrapper, { sx: bare ? { height: "100%" } : { p: 2, height: "100%" }, children: [
7565
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 1.5, minWidth: 0, justifyContent: bare ? "flex-end" : void 0 }, children: [
7566
- !bare && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Typography17.default, { variant: "h6", lineHeight: 1.2, sx: { minWidth: 0, flex: 1 }, children: title }),
7567
- !loading && !error && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7702
+ const Wrapper = bare ? import_Box20.default : import_Paper11.default;
7703
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Wrapper, { sx: bare ? { height: "100%" } : { p: 2, height: "100%" }, children: [
7704
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { display: "flex", alignItems: "center", gap: 1, mb: 1.5, minWidth: 0, justifyContent: bare ? "flex-end" : void 0 }, children: [
7705
+ !bare && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Typography18.default, { variant: "h6", lineHeight: 1.2, sx: { minWidth: 0, flex: 1 }, children: title }),
7706
+ !loading && !error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7568
7707
  StatusPill,
7569
7708
  {
7570
7709
  label: summaryText,
@@ -7573,19 +7712,19 @@ var LiteLLMBudgetGauges = ({
7573
7712
  }
7574
7713
  )
7575
7714
  ] }),
7576
- viewState.kind === "loading" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Box19.default, { sx: { display: "flex", flexDirection: "column", gap: 1.25, minHeight: size }, children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { sx: { display: "flex", alignItems: "center", gap: 1.25 }, children: [
7577
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Skeleton8.default, { variant: "circular", width: size, height: size }),
7578
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { sx: { flex: 1 }, children: [
7579
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Skeleton8.default, { variant: "text", width: "70%", height: 12, sx: { mb: 0.25 } }),
7580
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Skeleton8.default, { variant: "text", width: "45%", height: 11 })
7715
+ viewState.kind === "loading" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Box20.default, { sx: { display: "flex", flexDirection: "column", gap: 1.25, minHeight: size }, children: [0, 1, 2].map((i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { display: "flex", alignItems: "center", gap: 1.25 }, children: [
7716
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Skeleton8.default, { variant: "circular", width: size, height: size }),
7717
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { flex: 1 }, children: [
7718
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Skeleton8.default, { variant: "text", width: "70%", height: 12, sx: { mb: 0.25 } }),
7719
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Skeleton8.default, { variant: "text", width: "45%", height: 11 })
7581
7720
  ] }),
7582
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Skeleton8.default, { variant: "text", width: 64, height: 12 })
7721
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Skeleton8.default, { variant: "text", width: 64, height: 12 })
7583
7722
  ] }, i)) }),
7584
- viewState.kind === "error" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Typography17.default, { variant: "body2", color: "text.secondary", sx: { mt: 0.5 }, children: viewState.message }),
7585
- viewState.kind === "unprovisioned" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Typography17.default, { variant: "body2", color: "text.secondary", sx: { mt: 0.5 }, children: UNPROVISIONED_MSG }),
7586
- viewState.kind === "ready" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
7587
- /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7588
- import_Box19.default,
7723
+ viewState.kind === "error" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Typography18.default, { variant: "body2", color: "text.secondary", sx: { mt: 0.5 }, children: viewState.message }),
7724
+ viewState.kind === "unprovisioned" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Typography18.default, { variant: "body2", color: "text.secondary", sx: { mt: 0.5 }, children: UNPROVISIONED_MSG }),
7725
+ viewState.kind === "ready" && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
7726
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
7727
+ import_Box20.default,
7589
7728
  {
7590
7729
  sx: {
7591
7730
  display: "flex",
@@ -7595,7 +7734,7 @@ var LiteLLMBudgetGauges = ({
7595
7734
  minWidth: 0
7596
7735
  },
7597
7736
  children: [
7598
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7737
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7599
7738
  InlineStat,
7600
7739
  {
7601
7740
  label: "Today spent",
@@ -7605,8 +7744,8 @@ var LiteLLMBudgetGauges = ({
7605
7744
  title: usageLoading || viewState.usageUnavailable ? void 0 : "Spend since local midnight"
7606
7745
  }
7607
7746
  ),
7608
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Box19.default, { sx: { width: "1px", bgcolor: "divider", flexShrink: 0 } }),
7609
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7747
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Box20.default, { sx: { width: "1px", bgcolor: "divider", flexShrink: 0 } }),
7748
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7610
7749
  InlineStat,
7611
7750
  {
7612
7751
  label: "Month to date",
@@ -7618,15 +7757,15 @@ var LiteLLMBudgetGauges = ({
7618
7757
  ]
7619
7758
  }
7620
7759
  ),
7621
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Box19.default, { sx: { borderTop: "1px solid", borderColor: "divider" }, children: gauges.map((gauge, i) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7622
- import_Box19.default,
7760
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Box20.default, { sx: { borderTop: "1px solid", borderColor: "divider" }, children: gauges.map((gauge, i) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7761
+ import_Box20.default,
7623
7762
  {
7624
7763
  sx: i === 0 ? void 0 : { borderTop: "1px solid", borderColor: "divider" },
7625
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LevelRow, { gauge, size: gaugeSize, keysHref: keysTabHref })
7764
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LevelRow, { gauge, size: gaugeSize, keysHref: keysTabHref })
7626
7765
  },
7627
7766
  gauge.kind
7628
7767
  )) }),
7629
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Box19.default, { sx: { mt: 1.25 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7768
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Box20.default, { sx: { mt: 1.25 }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7630
7769
  SpendStrip,
7631
7770
  {
7632
7771
  data: dailySpend,
@@ -7637,8 +7776,8 @@ var LiteLLMBudgetGauges = ({
7637
7776
  maxBudget: user?.max_budget ?? void 0
7638
7777
  }
7639
7778
  ) }),
7640
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Collapse4.default, { in: isExpanded, unmountOnExit: true, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7641
- import_Box19.default,
7779
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Collapse4.default, { in: isExpanded, unmountOnExit: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7780
+ import_Box20.default,
7642
7781
  {
7643
7782
  id: expandedRegionId,
7644
7783
  sx: {
@@ -7648,7 +7787,7 @@ var LiteLLMBudgetGauges = ({
7648
7787
  maxHeight: 300,
7649
7788
  overflowY: "auto"
7650
7789
  },
7651
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LimitListPanel, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7790
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LimitListPanel, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7652
7791
  BudgetLimitList,
7653
7792
  {
7654
7793
  limits: expandedLimits,
@@ -7659,8 +7798,8 @@ var LiteLLMBudgetGauges = ({
7659
7798
  }
7660
7799
  ) })
7661
7800
  ] }),
7662
- hasFooter && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7663
- import_Box19.default,
7801
+ hasFooter && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
7802
+ import_Box20.default,
7664
7803
  {
7665
7804
  sx: (muiTheme) => ({
7666
7805
  mt: 2,