@acarmisc/backstage-plugin-litellm 0.35.0 → 0.37.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,136 @@ 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
+ function initialTeams(all, have) {
6762
+ const missing = all.filter((id) => !have.has(id));
6763
+ return new Set(have.size ? missing : all);
6764
+ }
6765
+ var init_connect = __esm({
6766
+ "src/connect.ts"() {
6767
+ "use strict";
6768
+ }
6769
+ });
6770
+
6771
+ // src/components/ConnectPage.tsx
6772
+ var ConnectPage_exports = {};
6773
+ __export(ConnectPage_exports, {
6774
+ ConnectPage: () => ConnectPage
6775
+ });
6776
+ 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;
6777
+ var init_ConnectPage = __esm({
6778
+ "src/components/ConnectPage.tsx"() {
6779
+ "use strict";
6780
+ import_react14 = require("react");
6781
+ import_Alert7 = __toESM(require("@mui/material/Alert"));
6782
+ import_Box18 = __toESM(require("@mui/material/Box"));
6783
+ import_Button8 = __toESM(require("@mui/material/Button"));
6784
+ import_Checkbox3 = __toESM(require("@mui/material/Checkbox"));
6785
+ import_FormControlLabel3 = __toESM(require("@mui/material/FormControlLabel"));
6786
+ import_FormGroup = __toESM(require("@mui/material/FormGroup"));
6787
+ import_Paper9 = __toESM(require("@mui/material/Paper"));
6788
+ import_Typography16 = __toESM(require("@mui/material/Typography"));
6789
+ import_react_router_dom2 = require("react-router-dom");
6790
+ import_react_use3 = require("react-use");
6791
+ import_core_plugin_api6 = require("@backstage/core-plugin-api");
6792
+ import_core_components4 = require("@backstage/core-components");
6793
+ init_api();
6794
+ init_connect();
6795
+ import_jsx_runtime19 = require("react/jsx-runtime");
6796
+ ConnectPage = () => {
6797
+ const api = (0, import_core_plugin_api6.useApi)(liteLlmApiRef);
6798
+ const [params] = (0, import_react_router_dom2.useSearchParams)();
6799
+ const redirectUri = params.get("redirect_uri");
6800
+ const state = params.get("state") ?? "";
6801
+ const client = params.get("client") || "a local application";
6802
+ const have = new Set((params.get("have") ?? "").split(",").filter(Boolean));
6803
+ const teams = (0, import_react_use3.useAsync)(() => api.getTeams(), [api]);
6804
+ const [selected, setSelected] = (0, import_react14.useState)();
6805
+ const [busy, setBusy] = (0, import_react14.useState)(false);
6806
+ const [error, setError] = (0, import_react14.useState)();
6807
+ if (!isLoopbackCallback(redirectUri)) {
6808
+ 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." }) });
6809
+ }
6810
+ if (teams.loading) return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_core_components4.Progress, {});
6811
+ const all = teams.value ?? [];
6812
+ const chosen = selected ?? initialTeams(all.map((t) => t.team_id), have);
6813
+ const toggle = (id) => {
6814
+ const next = new Set(chosen);
6815
+ if (!next.delete(id)) next.add(id);
6816
+ setSelected(next);
6817
+ };
6818
+ const connect = async () => {
6819
+ setBusy(true);
6820
+ setError(void 0);
6821
+ try {
6822
+ const ids = all.length ? all.filter((t) => chosen.has(t.team_id)).map((t) => t.team_id) : [void 0];
6823
+ const keys = [];
6824
+ for (const id of ids) keys.push(["key", (await api.connectLocalClient(redirectUri, id)).key]);
6825
+ postToLoopback(redirectUri, [["state", state], ...keys]);
6826
+ } catch (e) {
6827
+ setError(e instanceof Error ? e.message : String(e));
6828
+ setBusy(false);
6829
+ }
6830
+ };
6831
+ 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: [
6832
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_Typography16.default, { variant: "h5", gutterBottom: true, children: [
6833
+ "Connect ",
6834
+ client
6835
+ ] }),
6836
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_Typography16.default, { variant: "body2", color: "text.secondary", paragraph: true, children: [
6837
+ client,
6838
+ " will receive an API key for each selected team. Selecting a team that is already connected replaces its key, also on your other devices."
6839
+ ] }),
6840
+ teams.error && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_Alert7.default, { severity: "error", children: [
6841
+ "Could not load your teams: ",
6842
+ teams.error.message
6843
+ ] }),
6844
+ 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)(
6845
+ import_FormControlLabel3.default,
6846
+ {
6847
+ control: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_Checkbox3.default, { checked: chosen.has(t.team_id), onChange: () => toggle(t.team_id) }),
6848
+ label: `${t.team_alias ?? t.team_id}${have.has(t.team_id) ? " (already connected)" : ""}`
6849
+ },
6850
+ t.team_id
6851
+ )) }),
6852
+ error && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_Alert7.default, { severity: "error", sx: { mb: 2 }, children: error }),
6853
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
6854
+ import_Button8.default,
6855
+ {
6856
+ variant: "contained",
6857
+ onClick: connect,
6858
+ disabled: busy || !!teams.error || all.length > 0 && chosen.size === 0,
6859
+ children: busy ? "Connecting\u2026" : "Connect"
6860
+ }
6861
+ )
6862
+ ] }) }) });
6863
+ };
6864
+ }
6865
+ });
6866
+
6733
6867
  // src/index.ts
6734
6868
  var index_exports = {};
6735
6869
  __export(index_exports, {
@@ -6761,7 +6895,7 @@ var import_icons_material10 = require("@mui/icons-material");
6761
6895
  var import_frontend_plugin_api4 = require("@backstage/frontend-plugin-api");
6762
6896
  init_api();
6763
6897
  init_routes();
6764
- var import_jsx_runtime19 = require("react/jsx-runtime");
6898
+ var import_jsx_runtime20 = require("react/jsx-runtime");
6765
6899
  var liteLlmApi = import_frontend_plugin_api4.ApiBlueprint.make({
6766
6900
  params: (defineParams) => defineParams({
6767
6901
  api: liteLlmApiRef,
@@ -6773,11 +6907,21 @@ var liteLlmPage = import_frontend_plugin_api4.PageBlueprint.make({
6773
6907
  params: {
6774
6908
  path: "/litellm",
6775
6909
  title: "LiteLLM",
6776
- icon: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_icons_material10.TrendingUp, {}),
6910
+ icon: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_icons_material10.TrendingUp, {}),
6777
6911
  routeRef: rootRouteRef,
6778
6912
  loader: async () => {
6779
6913
  const { LiteLLMPage: LiteLLMPage2 } = await Promise.resolve().then(() => (init_LiteLLMPage(), LiteLLMPage_exports));
6780
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(LiteLLMPage2, {});
6914
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(LiteLLMPage2, {});
6915
+ }
6916
+ }
6917
+ });
6918
+ var liteLlmConnectPage = import_frontend_plugin_api4.PageBlueprint.make({
6919
+ name: "connect",
6920
+ params: {
6921
+ path: "/litellm/connect",
6922
+ loader: async () => {
6923
+ const { ConnectPage: ConnectPage2 } = await Promise.resolve().then(() => (init_ConnectPage(), ConnectPage_exports));
6924
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ConnectPage2, {});
6781
6925
  }
6782
6926
  }
6783
6927
  });
@@ -6786,7 +6930,7 @@ var litellmPlugin = (0, import_frontend_plugin_api4.createFrontendPlugin)({
6786
6930
  routes: {
6787
6931
  root: rootRouteRef
6788
6932
  },
6789
- extensions: [liteLlmApi, liteLlmPage]
6933
+ extensions: [liteLlmApi, liteLlmPage, liteLlmConnectPage]
6790
6934
  });
6791
6935
 
6792
6936
  // src/index.ts
@@ -6797,18 +6941,18 @@ init_UsageStats();
6797
6941
  init_TeamUsage();
6798
6942
 
6799
6943
  // 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"));
6944
+ var import_react15 = require("react");
6945
+ var import_Paper10 = __toESM(require("@mui/material/Paper"));
6946
+ var import_Box19 = __toESM(require("@mui/material/Box"));
6947
+ var import_Typography17 = __toESM(require("@mui/material/Typography"));
6804
6948
  var import_FormControl2 = __toESM(require("@mui/material/FormControl"));
6805
6949
  var import_Select2 = __toESM(require("@mui/material/Select"));
6806
6950
  var import_MenuItem6 = __toESM(require("@mui/material/MenuItem"));
6807
6951
  var import_Skeleton7 = __toESM(require("@mui/material/Skeleton"));
6808
6952
  var import_recharts3 = require("recharts");
6809
- var import_core_plugin_api6 = require("@backstage/core-plugin-api");
6953
+ var import_core_plugin_api7 = require("@backstage/core-plugin-api");
6810
6954
  var import_frontend_plugin_api5 = require("@backstage/frontend-plugin-api");
6811
- var import_core_components4 = require("@backstage/core-components");
6955
+ var import_core_components5 = require("@backstage/core-components");
6812
6956
  init_useLiteLLMProfile();
6813
6957
  init_api();
6814
6958
  init_routes();
@@ -6860,7 +7004,7 @@ function usageSummary(usage) {
6860
7004
  }
6861
7005
 
6862
7006
  // src/components/LiteLLMHomeWidget.tsx
6863
- var import_jsx_runtime20 = require("react/jsx-runtime");
7007
+ var import_jsx_runtime21 = require("react/jsx-runtime");
6864
7008
  function presetToDateRange(preset) {
6865
7009
  const end = /* @__PURE__ */ new Date();
6866
7010
  const start = /* @__PURE__ */ new Date();
@@ -6878,14 +7022,14 @@ var LiteLLMHomeWidget = ({
6878
7022
  title = "LiteLLM Usage",
6879
7023
  bare = false
6880
7024
  }) => {
6881
- const api = (0, import_core_plugin_api6.useApi)(liteLlmApiRef);
7025
+ const api = (0, import_core_plugin_api7.useApi)(liteLlmApiRef);
6882
7026
  const moduleRouteRef = (0, import_frontend_plugin_api5.useRouteRef)(rootRouteRef);
6883
7027
  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)(() => {
7028
+ const [period, setPeriod] = (0, import_react15.useState)(defaultPeriod);
7029
+ const [usageLoading, setUsageLoading] = (0, import_react15.useState)(true);
7030
+ const [usageError, setUsageError] = (0, import_react15.useState)(null);
7031
+ const [usage, setUsage] = (0, import_react15.useState)(null);
7032
+ (0, import_react15.useEffect)(() => {
6889
7033
  let cancelled = false;
6890
7034
  setUsageLoading(true);
6891
7035
  setUsageError(null);
@@ -6907,7 +7051,7 @@ var LiteLLMHomeWidget = ({
6907
7051
  cancelled = true;
6908
7052
  };
6909
7053
  }, [api, period]);
6910
- const viewState = (0, import_react14.useMemo)(
7054
+ const viewState = (0, import_react15.useMemo)(
6911
7055
  () => widgetViewState({
6912
7056
  loading: profileLoading || usageLoading,
6913
7057
  error: profileError,
@@ -6917,7 +7061,7 @@ var LiteLLMHomeWidget = ({
6917
7061
  }),
6918
7062
  [profileLoading, usageLoading, profileError, userInfo, usageError, keys]
6919
7063
  );
6920
- const Wrapper = bare ? import_Box18.default : import_Paper9.default;
7064
+ const Wrapper = bare ? import_Box19.default : import_Paper10.default;
6921
7065
  const partialFailure = !usageLoading && usageError && usage;
6922
7066
  const dailyData = (usage?.daily_usage ?? []).map((d) => ({
6923
7067
  date: d.date,
@@ -6929,10 +7073,10 @@ var LiteLLMHomeWidget = ({
6929
7073
  const endDate = toLocalDay(end);
6930
7074
  const dateRangeCaption = rangeCaption(startDate, endDate);
6931
7075
  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)(
7076
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(Wrapper, { sx: bare ? { height: "100%" } : { p: 2, height: "100%" }, children: [
7077
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { display: "flex", justifyContent: bare ? "flex-end" : "space-between", alignItems: "center", mb: 1.5, children: [
7078
+ !bare && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Typography17.default, { variant: "h6", children: title }),
7079
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_FormControl2.default, { size: "small", sx: { minWidth: 90 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
6936
7080
  import_Select2.default,
6937
7081
  {
6938
7082
  value: period,
@@ -6940,23 +7084,23 @@ var LiteLLMHomeWidget = ({
6940
7084
  displayEmpty: true,
6941
7085
  inputProps: { "aria-label": "Usage period" },
6942
7086
  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" })
7087
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_MenuItem6.default, { value: "today", children: "Today" }),
7088
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_MenuItem6.default, { value: "7d", children: "7d" }),
7089
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_MenuItem6.default, { value: "30d", children: "30d" })
6946
7090
  ]
6947
7091
  }
6948
7092
  ) })
6949
7093
  ] }),
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 })
7094
+ viewState.kind === "loading" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Box19.default, { sx: { minHeight: 120 }, children: [
7095
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Skeleton7.default, { variant: "text", width: "60%", height: 20, sx: { mb: 1 } }),
7096
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Skeleton7.default, { variant: "rectangular", width: "100%", height: 100 })
6953
7097
  ] }),
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,
7098
+ viewState.kind === "error" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Typography17.default, { variant: "body2", color: "text.secondary", sx: { mt: 1 }, children: viewState.message }),
7099
+ viewState.kind === "unprovisioned" && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Typography17.default, { variant: "body2", color: "text.secondary", sx: { mt: 1 }, children: UNPROVISIONED_MSG }),
7100
+ 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 }) }),
7101
+ viewState.kind === "ready" && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
7102
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7103
+ import_Typography17.default,
6960
7104
  {
6961
7105
  variant: "body2",
6962
7106
  sx: {
@@ -6967,18 +7111,18 @@ var LiteLLMHomeWidget = ({
6967
7111
  children: viewState.usageUnavailable ? USAGE_UNAVAILABLE_MSG : usageSummary(usage)
6968
7112
  }
6969
7113
  ),
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,
7114
+ hasSparkline && !viewState.usageUnavailable && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_jsx_runtime21.Fragment, { children: [
7115
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7116
+ import_Box19.default,
6973
7117
  {
6974
7118
  height: 80,
6975
7119
  role: "img",
6976
7120
  "aria-label": sparklineAriaLabelText,
6977
7121
  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)(
7122
+ 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: [
7123
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_recharts3.XAxis, { dataKey: "date", hide: true }),
7124
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_recharts3.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(ChartTooltip, { valueFormatter: fmtUsd }) }),
7125
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
6982
7126
  import_recharts3.Area,
6983
7127
  {
6984
7128
  type: "monotone",
@@ -6994,13 +7138,13 @@ var LiteLLMHomeWidget = ({
6994
7138
  ] }) })
6995
7139
  }
6996
7140
  ),
6997
- /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_Typography16.default, { variant: "caption", color: "text.secondary", sx: { display: "block", mb: 1 }, children: [
7141
+ /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(import_Typography17.default, { variant: "caption", color: "text.secondary", sx: { display: "block", mb: 1 }, children: [
6998
7142
  "daily spend (",
6999
7143
  dateRangeCaption,
7000
7144
  ")"
7001
7145
  ] })
7002
7146
  ] }),
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" }) })
7147
+ 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
7148
  ] })
7005
7149
  ] });
7006
7150
  };
@@ -7009,20 +7153,20 @@ var LiteLLMHomeWidget = ({
7009
7153
  init_LiteLLMBudgetWidget();
7010
7154
 
7011
7155
  // src/components/LiteLLMBudgetGauges.tsx
7012
- var import_react15 = require("react");
7156
+ var import_react16 = require("react");
7013
7157
  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"));
7158
+ var import_Paper11 = __toESM(require("@mui/material/Paper"));
7159
+ var import_Box20 = __toESM(require("@mui/material/Box"));
7160
+ var import_Button9 = __toESM(require("@mui/material/Button"));
7161
+ var import_Typography18 = __toESM(require("@mui/material/Typography"));
7018
7162
  var import_Skeleton8 = __toESM(require("@mui/material/Skeleton"));
7019
7163
  var import_Collapse4 = __toESM(require("@mui/material/Collapse"));
7020
7164
  var import_styles13 = require("@mui/material/styles");
7021
7165
  var import_useMediaQuery = __toESM(require("@mui/material/useMediaQuery"));
7022
7166
  var import_icons_material11 = require("@mui/icons-material");
7023
7167
  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");
7168
+ var import_core_plugin_api8 = require("@backstage/core-plugin-api");
7169
+ var import_core_components6 = require("@backstage/core-components");
7026
7170
  init_useLiteLLMProfile();
7027
7171
  init_api();
7028
7172
  init_format();
@@ -7053,7 +7197,7 @@ init_GenerateKeyButton();
7053
7197
  init_BudgetLimitList();
7054
7198
  init_budget();
7055
7199
  init_routes();
7056
- var import_jsx_runtime21 = require("react/jsx-runtime");
7200
+ var import_jsx_runtime22 = require("react/jsx-runtime");
7057
7201
  var LEVEL = {
7058
7202
  key: { name: "Key", none: "No cap (unlimited)" },
7059
7203
  user: { name: "User", none: "No personal budget" },
@@ -7077,8 +7221,8 @@ function resetLabel(limit) {
7077
7221
  const window2 = fmtBudgetDuration(limit.budgetDuration);
7078
7222
  return window2 ? `resets ${window2}` : "never resets";
7079
7223
  }
7080
- var Tag = ({ children, tone, title }) => /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7081
- import_Typography17.default,
7224
+ var Tag = ({ children, tone, title }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7225
+ import_Typography18.default,
7082
7226
  {
7083
7227
  title,
7084
7228
  sx: (theme) => ({
@@ -7095,10 +7239,10 @@ var Tag = ({ children, tone, title }) => /* @__PURE__ */ (0, import_jsx_runtime2
7095
7239
  children
7096
7240
  }
7097
7241
  );
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,
7242
+ var InlineStat = ({ label, value, hint, tone = "accent", title }) => /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { minWidth: 0, flex: 1 }, children: [
7243
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { display: "flex", alignItems: "center", gap: 0.625, minWidth: 0 }, children: [
7244
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7245
+ import_Box20.default,
7102
7246
  {
7103
7247
  sx: (theme) => ({
7104
7248
  width: 6,
@@ -7109,10 +7253,10 @@ var InlineStat = ({ label, value, hint, tone = "accent", title }) => /* @__PURE_
7109
7253
  })
7110
7254
  }
7111
7255
  ),
7112
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Tag, { children: label })
7256
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Tag, { children: label })
7113
7257
  ] }),
7114
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7115
- import_Typography17.default,
7258
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7259
+ import_Typography18.default,
7116
7260
  {
7117
7261
  title,
7118
7262
  sx: {
@@ -7128,8 +7272,8 @@ var InlineStat = ({ label, value, hint, tone = "accent", title }) => /* @__PURE_
7128
7272
  children: value
7129
7273
  }
7130
7274
  ),
7131
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7132
- import_Typography17.default,
7275
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7276
+ import_Typography18.default,
7133
7277
  {
7134
7278
  variant: "caption",
7135
7279
  color: "text.secondary",
@@ -7159,10 +7303,10 @@ var LevelRow = ({
7159
7303
  const subNote = () => {
7160
7304
  if (overCap) return "Over cap";
7161
7305
  if (extra > 0 && keysHref) {
7162
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7163
- import_Typography17.default,
7306
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
7307
+ import_Typography18.default,
7164
7308
  {
7165
- component: import_core_components5.Link,
7309
+ component: import_core_components6.Link,
7166
7310
  to: keysHref,
7167
7311
  variant: "caption",
7168
7312
  sx: {
@@ -7182,8 +7326,8 @@ var LevelRow = ({
7182
7326
  return limit?.sublabel ?? null;
7183
7327
  };
7184
7328
  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,
7329
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
7330
+ import_Box20.default,
7187
7331
  {
7188
7332
  sx: {
7189
7333
  display: "grid",
@@ -7194,7 +7338,7 @@ var LevelRow = ({
7194
7338
  minWidth: 0
7195
7339
  },
7196
7340
  children: [
7197
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7341
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7198
7342
  Gauge,
7199
7343
  {
7200
7344
  value: limit?.pct ?? 0,
@@ -7204,11 +7348,11 @@ var LevelRow = ({
7204
7348
  ariaLabel: gaugeAriaLabel
7205
7349
  }
7206
7350
  ),
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,
7351
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { minWidth: 0 }, children: [
7352
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Tag, { tone: tone === "warning" || tone === "danger" ? tone : void 0, children: name }),
7353
+ limit ? /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
7354
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7355
+ import_Typography18.default,
7212
7356
  {
7213
7357
  variant: "caption",
7214
7358
  title: limit.sublabel ? `${limit.label} \xB7 ${limit.sublabel}` : limit.label,
@@ -7224,8 +7368,8 @@ var LevelRow = ({
7224
7368
  children: limit.label
7225
7369
  }
7226
7370
  ),
7227
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7228
- import_Typography17.default,
7371
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7372
+ import_Typography18.default,
7229
7373
  {
7230
7374
  variant: "caption",
7231
7375
  color: overCap ? "error" : "text.secondary",
@@ -7241,8 +7385,8 @@ var LevelRow = ({
7241
7385
  children: subNote()
7242
7386
  }
7243
7387
  )
7244
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7245
- import_Typography17.default,
7388
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7389
+ import_Typography18.default,
7246
7390
  {
7247
7391
  variant: "caption",
7248
7392
  color: "text.secondary",
@@ -7258,9 +7402,9 @@ var LevelRow = ({
7258
7402
  }
7259
7403
  )
7260
7404
  ] }),
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,
7405
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { minWidth: 0, textAlign: "right" }, children: [
7406
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7407
+ import_Typography18.default,
7264
7408
  {
7265
7409
  title: limit ? `${fmtUsd(limit.spend)} of ${fmtUsd(limit.budget)}` : void 0,
7266
7410
  sx: {
@@ -7277,8 +7421,8 @@ var LevelRow = ({
7277
7421
  children: amountCaption(limit)
7278
7422
  }
7279
7423
  ),
7280
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7281
- import_Typography17.default,
7424
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7425
+ import_Typography18.default,
7282
7426
  {
7283
7427
  variant: "caption",
7284
7428
  color: "text.secondary",
@@ -7309,11 +7453,11 @@ function amountNote(limit) {
7309
7453
  var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, maxBudget }) => {
7310
7454
  const renderPlot = () => {
7311
7455
  if (loading) {
7312
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Skeleton8.default, { variant: "rectangular", width: "100%", height: "100%" });
7456
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Skeleton8.default, { variant: "rectangular", width: "100%", height: "100%" });
7313
7457
  }
7314
7458
  if (data.length === 0) {
7315
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7316
- import_Box19.default,
7459
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7460
+ import_Box20.default,
7317
7461
  {
7318
7462
  display: "flex",
7319
7463
  justifyContent: "center",
@@ -7324,10 +7468,10 @@ var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, m
7324
7468
  }
7325
7469
  );
7326
7470
  }
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)(
7471
+ 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: [
7472
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_recharts4.XAxis, { dataKey: "date", hide: true }),
7473
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_recharts4.Tooltip, { content: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ChartTooltip, { valueFormatter: fmtUsd }) }),
7474
+ maxBudget !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7331
7475
  import_recharts4.ReferenceLine,
7332
7476
  {
7333
7477
  y: maxBudget,
@@ -7336,7 +7480,7 @@ var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, m
7336
7480
  strokeWidth: 1
7337
7481
  }
7338
7482
  ),
7339
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7483
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7340
7484
  import_recharts4.Area,
7341
7485
  {
7342
7486
  type: "monotone",
@@ -7358,10 +7502,10 @@ var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, m
7358
7502
  if (data.length === 0) return "No spend this month";
7359
7503
  return mtdCaption();
7360
7504
  })();
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,
7505
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { role: "img", "aria-label": sparklineAriaLabel(data), sx: { minWidth: 0 }, children: [
7506
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Box20.default, { sx: { height, width: "100%" }, children: renderPlot() }),
7507
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
7508
+ import_Box20.default,
7365
7509
  {
7366
7510
  sx: {
7367
7511
  display: "flex",
@@ -7372,10 +7516,10 @@ var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, m
7372
7516
  minWidth: 0
7373
7517
  },
7374
7518
  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,
7519
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { display: "flex", alignItems: "baseline", gap: 0.75, minWidth: 0 }, children: [
7520
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(Tag, { children: "Spent (mtd)" }),
7521
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7522
+ import_Typography18.default,
7379
7523
  {
7380
7524
  variant: "caption",
7381
7525
  color: "text.secondary",
@@ -7384,8 +7528,8 @@ var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, m
7384
7528
  }
7385
7529
  )
7386
7530
  ] }),
7387
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7388
- import_Typography17.default,
7531
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7532
+ import_Typography18.default,
7389
7533
  {
7390
7534
  title: loading || usageUnavailable ? void 0 : `${fmtUsd(mtdSpend)} spent month to date`,
7391
7535
  sx: {
@@ -7429,33 +7573,33 @@ var LiteLLMBudgetGauges = ({
7429
7573
  teams: propTeams,
7430
7574
  keys: propKeys
7431
7575
  }) => {
7432
- const api = (0, import_core_plugin_api7.useApi)(liteLlmApiRef);
7576
+ const api = (0, import_core_plugin_api8.useApi)(liteLlmApiRef);
7433
7577
  const theme = (0, import_styles13.useTheme)();
7434
7578
  const isSmallScreen = (0, import_useMediaQuery.default)(theme.breakpoints.down("sm"));
7435
7579
  const gaugeSize = isSmallScreen ? Math.min(48, size) : size;
7436
- const expandedRegionId = (0, import_react15.useId)();
7580
+ const expandedRegionId = (0, import_react16.useId)();
7437
7581
  const moduleRouteRef = (0, import_frontend_plugin_api6.useRouteRef)(rootRouteRef);
7438
7582
  const moduleHref = propModuleHref ?? moduleRouteRef?.();
7439
7583
  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);
7584
+ const [usageLoading, setUsageLoading] = (0, import_react16.useState)(true);
7585
+ const [usageError, setUsageError] = (0, import_react16.useState)(null);
7586
+ const [dailySpend, setDailySpend] = (0, import_react16.useState)([]);
7587
+ const [mtdSpend, setMtdSpend] = (0, import_react16.useState)(0);
7444
7588
  const user = propUserInfo !== void 0 ? propUserInfo : hookUserInfo;
7445
7589
  const teams = propTeams !== void 0 ? propTeams : hookTeams;
7446
7590
  const keys = propKeys !== void 0 ? propKeys : hookKeys;
7447
7591
  const loading = propUserInfo === void 0 ? profileLoading : usageLoading;
7448
7592
  const error = propUserInfo === void 0 ? profileError : usageError;
7449
7593
  const isControlled = expanded !== void 0;
7450
- const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react15.useState)(defaultExpanded);
7594
+ const [uncontrolledExpanded, setUncontrolledExpanded] = (0, import_react16.useState)(defaultExpanded);
7451
7595
  const isExpanded = isControlled ? expanded : uncontrolledExpanded;
7452
- const toggleExpanded = (0, import_react15.useCallback)(() => {
7596
+ const toggleExpanded = (0, import_react16.useCallback)(() => {
7453
7597
  const next = !isExpanded;
7454
7598
  if (!isControlled) setUncontrolledExpanded(next);
7455
7599
  onExpandedChange?.(next);
7456
7600
  }, [isControlled, isExpanded, onExpandedChange]);
7457
7601
  const keysTabHref = keysHref ?? (moduleHref ? `${moduleHref}?tab=keys` : void 0);
7458
- (0, import_react15.useEffect)(() => {
7602
+ (0, import_react16.useEffect)(() => {
7459
7603
  let cancelled = false;
7460
7604
  setUsageLoading(true);
7461
7605
  setUsageError(null);
@@ -7483,21 +7627,21 @@ var LiteLLMBudgetGauges = ({
7483
7627
  cancelled = true;
7484
7628
  };
7485
7629
  }, [api]);
7486
- const summary = (0, import_react15.useMemo)(
7630
+ const summary = (0, import_react16.useMemo)(
7487
7631
  () => buildBudgetSummary(user, teams, keys, keys.length),
7488
7632
  [user, teams, keys]
7489
7633
  );
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)(
7634
+ const gauges = (0, import_react16.useMemo)(() => buildBudgetGauges(summary), [summary]);
7635
+ const headline = (0, import_react16.useMemo)(() => budgetHeadline(summary), [summary]);
7636
+ const expandedSummary = (0, import_react16.useMemo)(
7493
7637
  () => buildBudgetSummary(user, teams, keys, maxExpandedKeys),
7494
7638
  [user, teams, keys, maxExpandedKeys]
7495
7639
  );
7496
- const expandedLimits = (0, import_react15.useMemo)(
7640
+ const expandedLimits = (0, import_react16.useMemo)(
7497
7641
  () => allBudgetLimits(expandedSummary),
7498
7642
  [expandedSummary]
7499
7643
  );
7500
- const viewState = (0, import_react15.useMemo)(
7644
+ const viewState = (0, import_react16.useMemo)(
7501
7645
  () => widgetViewState({
7502
7646
  loading,
7503
7647
  error: profileError,
@@ -7514,7 +7658,7 @@ var LiteLLMBudgetGauges = ({
7514
7658
  const yesterdaySpend = dailySpend.some((d) => d.date === toLocalDay(yesterday)) ? spendOnDay(dailySpend, yesterday) : null;
7515
7659
  const todayHint = yesterdaySpend === null ? void 0 : `vs ${fmtUsd(yesterdaySpend)} yesterday`;
7516
7660
  const summaryText = headline.count === 0 ? "no limits apply" : `${headline.count} limit${headline.count === 1 ? "" : "s"}`;
7517
- const resolvedCtas = (0, import_react15.useMemo)(() => {
7661
+ const resolvedCtas = (0, import_react16.useMemo)(() => {
7518
7662
  return resolveCtas({
7519
7663
  ctas,
7520
7664
  hasKeys: (keys?.length ?? 0) > 0,
@@ -7528,20 +7672,20 @@ var LiteLLMBudgetGauges = ({
7528
7672
  switch (cta.kind) {
7529
7673
  case "new-key":
7530
7674
  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);
7675
+ 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
7676
  case "module":
7533
7677
  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);
7678
+ 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
7679
  case "all-limits":
7536
- return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7537
- import_Button8.default,
7680
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7681
+ import_Button9.default,
7538
7682
  {
7539
7683
  size: "small",
7540
7684
  variant: "text",
7541
7685
  onClick: toggleExpanded,
7542
7686
  "aria-expanded": isExpanded,
7543
7687
  "aria-controls": expandedRegionId,
7544
- endIcon: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7688
+ endIcon: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7545
7689
  import_icons_material11.ExpandMore,
7546
7690
  {
7547
7691
  sx: (muiTheme) => ({
@@ -7560,11 +7704,11 @@ var LiteLLMBudgetGauges = ({
7560
7704
  }
7561
7705
  };
7562
7706
  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)(
7707
+ const Wrapper = bare ? import_Box20.default : import_Paper11.default;
7708
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(Wrapper, { sx: bare ? { height: "100%" } : { p: 2, height: "100%" }, children: [
7709
+ /* @__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: [
7710
+ !bare && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Typography18.default, { variant: "h6", lineHeight: 1.2, sx: { minWidth: 0, flex: 1 }, children: title }),
7711
+ !loading && !error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7568
7712
  StatusPill,
7569
7713
  {
7570
7714
  label: summaryText,
@@ -7573,19 +7717,19 @@ var LiteLLMBudgetGauges = ({
7573
7717
  }
7574
7718
  )
7575
7719
  ] }),
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 })
7720
+ 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: [
7721
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Skeleton8.default, { variant: "circular", width: size, height: size }),
7722
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_Box20.default, { sx: { flex: 1 }, children: [
7723
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Skeleton8.default, { variant: "text", width: "70%", height: 12, sx: { mb: 0.25 } }),
7724
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Skeleton8.default, { variant: "text", width: "45%", height: 11 })
7581
7725
  ] }),
7582
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Skeleton8.default, { variant: "text", width: 64, height: 12 })
7726
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Skeleton8.default, { variant: "text", width: 64, height: 12 })
7583
7727
  ] }, 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,
7728
+ viewState.kind === "error" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Typography18.default, { variant: "body2", color: "text.secondary", sx: { mt: 0.5 }, children: viewState.message }),
7729
+ viewState.kind === "unprovisioned" && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Typography18.default, { variant: "body2", color: "text.secondary", sx: { mt: 0.5 }, children: UNPROVISIONED_MSG }),
7730
+ viewState.kind === "ready" && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(import_jsx_runtime22.Fragment, { children: [
7731
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
7732
+ import_Box20.default,
7589
7733
  {
7590
7734
  sx: {
7591
7735
  display: "flex",
@@ -7595,7 +7739,7 @@ var LiteLLMBudgetGauges = ({
7595
7739
  minWidth: 0
7596
7740
  },
7597
7741
  children: [
7598
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7742
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7599
7743
  InlineStat,
7600
7744
  {
7601
7745
  label: "Today spent",
@@ -7605,8 +7749,8 @@ var LiteLLMBudgetGauges = ({
7605
7749
  title: usageLoading || viewState.usageUnavailable ? void 0 : "Spend since local midnight"
7606
7750
  }
7607
7751
  ),
7608
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Box19.default, { sx: { width: "1px", bgcolor: "divider", flexShrink: 0 } }),
7609
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7752
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Box20.default, { sx: { width: "1px", bgcolor: "divider", flexShrink: 0 } }),
7753
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7610
7754
  InlineStat,
7611
7755
  {
7612
7756
  label: "Month to date",
@@ -7618,15 +7762,15 @@ var LiteLLMBudgetGauges = ({
7618
7762
  ]
7619
7763
  }
7620
7764
  ),
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,
7765
+ /* @__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)(
7766
+ import_Box20.default,
7623
7767
  {
7624
7768
  sx: i === 0 ? void 0 : { borderTop: "1px solid", borderColor: "divider" },
7625
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LevelRow, { gauge, size: gaugeSize, keysHref: keysTabHref })
7769
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LevelRow, { gauge, size: gaugeSize, keysHref: keysTabHref })
7626
7770
  },
7627
7771
  gauge.kind
7628
7772
  )) }),
7629
- /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_Box19.default, { sx: { mt: 1.25 }, children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7773
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Box20.default, { sx: { mt: 1.25 }, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7630
7774
  SpendStrip,
7631
7775
  {
7632
7776
  data: dailySpend,
@@ -7637,8 +7781,8 @@ var LiteLLMBudgetGauges = ({
7637
7781
  maxBudget: user?.max_budget ?? void 0
7638
7782
  }
7639
7783
  ) }),
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,
7784
+ /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_Collapse4.default, { in: isExpanded, unmountOnExit: true, children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7785
+ import_Box20.default,
7642
7786
  {
7643
7787
  id: expandedRegionId,
7644
7788
  sx: {
@@ -7648,7 +7792,7 @@ var LiteLLMBudgetGauges = ({
7648
7792
  maxHeight: 300,
7649
7793
  overflowY: "auto"
7650
7794
  },
7651
- children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(LimitListPanel, { children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
7795
+ children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(LimitListPanel, { children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
7652
7796
  BudgetLimitList,
7653
7797
  {
7654
7798
  limits: expandedLimits,
@@ -7659,8 +7803,8 @@ var LiteLLMBudgetGauges = ({
7659
7803
  }
7660
7804
  ) })
7661
7805
  ] }),
7662
- hasFooter && /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
7663
- import_Box19.default,
7806
+ hasFooter && /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
7807
+ import_Box20.default,
7664
7808
  {
7665
7809
  sx: (muiTheme) => ({
7666
7810
  mt: 2,