@acarmisc/backstage-plugin-litellm 0.21.1 → 0.21.2

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
@@ -2855,7 +2855,7 @@ function levelToneColor(tone, theme) {
2855
2855
  return theme.palette.primary.main;
2856
2856
  }
2857
2857
  }
2858
- var import_react7, import_Paper5, import_Box7, import_Typography7, import_CircularProgress4, import_Alert3, import_Collapse, import_IconButton4, import_icons_material5, import_styles4, import_core_plugin_api3, LevelFrame, EmptyLimitCard, LimitCard, CLOSEST_LEVEL_LABEL, TaggedLimit, FullBody, CompactBody, LiteLLMBudgetWidget;
2858
+ var import_react7, import_Paper5, import_Box7, import_Typography7, import_CircularProgress4, import_Alert3, import_Collapse, import_IconButton4, import_icons_material5, import_styles4, import_core_plugin_api3, import_core_components, LevelFrame, EmptyLimitCard, LimitCard, CLOSEST_LEVEL_LABEL, KEYS_PATH, MoreKeysNote, HierarchyNote, TaggedLimit, FullBody, CompactBody, LiteLLMBudgetWidget;
2859
2859
  var init_LiteLLMBudgetWidget = __esm({
2860
2860
  "src/components/LiteLLMBudgetWidget.tsx"() {
2861
2861
  "use strict";
@@ -2870,6 +2870,7 @@ var init_LiteLLMBudgetWidget = __esm({
2870
2870
  import_icons_material5 = require("@mui/icons-material");
2871
2871
  import_styles4 = require("@mui/material/styles");
2872
2872
  import_core_plugin_api3 = require("@backstage/core-plugin-api");
2873
+ import_core_components = require("@backstage/core-components");
2873
2874
  init_api();
2874
2875
  init_format();
2875
2876
  init_ui();
@@ -2983,6 +2984,21 @@ var init_LiteLLMBudgetWidget = __esm({
2983
2984
  user: "personal",
2984
2985
  team: "team"
2985
2986
  };
2987
+ KEYS_PATH = "/litellm?tab=keys";
2988
+ MoreKeysNote = ({ count }) => /* @__PURE__ */ import_react7.default.createElement(import_core_components.Link, { to: KEYS_PATH, variant: "caption" }, "+", count, " more budgeted key", count > 1 ? "s" : "", " further from the cap \u2192");
2989
+ HierarchyNote = ({ withReset }) => /* @__PURE__ */ import_react7.default.createElement(
2990
+ import_Box7.default,
2991
+ {
2992
+ sx: (theme) => ({
2993
+ px: 1.5,
2994
+ py: 1.25,
2995
+ borderRadius: 1.5,
2996
+ border: "1px dashed",
2997
+ borderColor: (0, import_styles4.alpha)(theme.palette.text.primary, 0.18)
2998
+ })
2999
+ },
3000
+ /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary", display: "block" }, /* @__PURE__ */ import_react7.default.createElement("b", null, "Order:"), " key \u2192 personal \u2192 team \u2192 global. The first cap you reach blocks the request; a key that belongs to a team uses the team's cap, not your personal one.", withReset && " A cap with a reset window drops to $0 when the window closes; without one it never resets.")
3001
+ );
2986
3002
  TaggedLimit = ({ limit }) => {
2987
3003
  const tone = budgetTone2(limit.pct);
2988
3004
  return /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, null, /* @__PURE__ */ import_react7.default.createElement(
@@ -3012,7 +3028,7 @@ var init_LiteLLMBudgetWidget = __esm({
3012
3028
  },
3013
3029
  !hasBudgetedKeys && /* @__PURE__ */ import_react7.default.createElement(EmptyLimitCard, null, "No key has a budget, so no key-level cap applies."),
3014
3030
  summary.keys.map((k) => /* @__PURE__ */ import_react7.default.createElement(LimitCard, { key: k.sublabel ?? k.label, limit: k })),
3015
- summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary" }, "+", summary.hiddenBudgetedKeys, " more budgeted key", summary.hiddenBudgetedKeys > 1 ? "s" : "", " further from the cap")
3031
+ summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ import_react7.default.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys })
3016
3032
  ), /* @__PURE__ */ import_react7.default.createElement(
3017
3033
  LevelFrame,
3018
3034
  {
@@ -3022,27 +3038,14 @@ var init_LiteLLMBudgetWidget = __esm({
3022
3038
  note: "skipped for team-bound keys"
3023
3039
  },
3024
3040
  summary.user ? /* @__PURE__ */ import_react7.default.createElement(LimitCard, { limit: summary.user }) : /* @__PURE__ */ import_react7.default.createElement(EmptyLimitCard, null, "No personal budget is set on your account.")
3025
- ), /* @__PURE__ */ import_react7.default.createElement(LevelFrame, { rank: 3, name: "Team", tagline: "shared cap for all keys in a team (if any)" }, summary.teams.length > 0 ? summary.teams.map((t) => /* @__PURE__ */ import_react7.default.createElement(LimitCard, { key: t.sublabel ?? t.label, limit: t })) : /* @__PURE__ */ import_react7.default.createElement(EmptyLimitCard, null, "No team you belong to has a budget.")), /* @__PURE__ */ import_react7.default.createElement(LevelFrame, { rank: 4, name: "Global", tagline: "proxy-wide cap set by your admin", isLast: true }, /* @__PURE__ */ import_react7.default.createElement(EmptyLimitCard, null, "Configured by your admin in the proxy config \u2014 it isn't visible from this page. When set, it limits spend across every request on the proxy.")), /* @__PURE__ */ import_react7.default.createElement(
3026
- import_Box7.default,
3027
- {
3028
- sx: (theme) => ({
3029
- mt: 2,
3030
- px: 1.5,
3031
- py: 1.25,
3032
- borderRadius: 1.5,
3033
- border: "1px dashed",
3034
- borderColor: (0, import_styles4.alpha)(theme.palette.text.primary, 0.18)
3035
- })
3036
- },
3037
- /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary", display: "block" }, "The first cap a request runs into is the one that stops it. A limit with a reset window (e.g. daily or every 30 days) clears its spend to $0 when the window closes; without a window it never resets.")
3038
- ));
3041
+ ), /* @__PURE__ */ import_react7.default.createElement(LevelFrame, { rank: 3, name: "Team", tagline: "shared cap for all keys in a team (if any)" }, summary.teams.length > 0 ? summary.teams.map((t) => /* @__PURE__ */ import_react7.default.createElement(LimitCard, { key: t.sublabel ?? t.label, limit: t })) : /* @__PURE__ */ import_react7.default.createElement(EmptyLimitCard, null, "No team you belong to has a budget.")), /* @__PURE__ */ import_react7.default.createElement(LevelFrame, { rank: 4, name: "Global", tagline: "proxy-wide cap set by your admin", isLast: true }, /* @__PURE__ */ import_react7.default.createElement(EmptyLimitCard, null, "Configured by your admin in the proxy config \u2014 it isn't visible from this page. When set, it limits spend across every request on the proxy.")), /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { sx: { mt: 2 } }, /* @__PURE__ */ import_react7.default.createElement(HierarchyNote, { withReset: true })));
3039
3042
  };
3040
3043
  CompactBody = ({ summary }) => {
3041
3044
  const { count } = budgetHeadline(summary);
3042
3045
  if (count === 0) {
3043
3046
  return /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "body2", color: "text.secondary", sx: { fontSize: 13 } }, "No budget limits apply to you right now.");
3044
3047
  }
3045
- return /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { sx: { display: "flex", flexDirection: "column", gap: 1.25 } }, summary.keys.map((k) => /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { key: k.sublabel ?? k.label, limit: k })), summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ import_react7.default.createElement(import_Typography7.default, { variant: "caption", color: "text.secondary" }, "+", summary.hiddenBudgetedKeys, " more budgeted key", summary.hiddenBudgetedKeys > 1 ? "s" : "", " further from the cap"), summary.user && /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { limit: summary.user }), summary.teams.map((t) => /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { key: t.sublabel ?? t.label, limit: t })));
3048
+ return /* @__PURE__ */ import_react7.default.createElement(import_Box7.default, { sx: { display: "flex", flexDirection: "column", gap: 1.25 } }, /* @__PURE__ */ import_react7.default.createElement(HierarchyNote, null), summary.keys.map((k) => /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { key: k.sublabel ?? k.label, limit: k })), summary.hiddenBudgetedKeys > 0 && /* @__PURE__ */ import_react7.default.createElement(MoreKeysNote, { count: summary.hiddenBudgetedKeys }), summary.user && /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { limit: summary.user }), summary.teams.map((t) => /* @__PURE__ */ import_react7.default.createElement(TaggedLimit, { key: t.sublabel ?? t.label, limit: t })));
3046
3049
  };
3047
3050
  LiteLLMBudgetWidget = ({
3048
3051
  title = "Budget Policy",
@@ -3847,7 +3850,7 @@ function initDateRange() {
3847
3850
  else start.setDate(start.getDate() - 7);
3848
3851
  return { start, end };
3849
3852
  }
3850
- var import_react11, import_Box11, import_Snackbar2, import_Alert6, import_CircularProgress6, import_Typography11, import_Paper7, import_Tabs2, import_Tab2, import_Grid2, import_react_use3, import_core_plugin_api4, import_plugin_permission_react, PERIOD_LS_KEY2, LiteLLMPage;
3853
+ var import_react11, import_Box11, import_Snackbar2, import_Alert6, import_CircularProgress6, import_Typography11, import_Paper7, import_Tabs2, import_Tab2, import_Grid2, import_react_router_dom, import_react_use3, import_core_plugin_api4, import_plugin_permission_react, PERIOD_LS_KEY2, PAGE_TABS, isPageTab, LiteLLMPage;
3851
3854
  var init_LiteLLMPage = __esm({
3852
3855
  "src/components/LiteLLMPage.tsx"() {
3853
3856
  "use strict";
@@ -3861,6 +3864,7 @@ var init_LiteLLMPage = __esm({
3861
3864
  import_Tabs2 = __toESM(require("@mui/material/Tabs"));
3862
3865
  import_Tab2 = __toESM(require("@mui/material/Tab"));
3863
3866
  import_Grid2 = __toESM(require("@mui/material/Grid"));
3867
+ import_react_router_dom = require("react-router-dom");
3864
3868
  import_react_use3 = require("react-use");
3865
3869
  import_core_plugin_api4 = require("@backstage/core-plugin-api");
3866
3870
  import_plugin_permission_react = require("@backstage/plugin-permission-react");
@@ -3876,6 +3880,8 @@ var init_LiteLLMPage = __esm({
3876
3880
  init_api();
3877
3881
  init_permissions();
3878
3882
  PERIOD_LS_KEY2 = "litellm_usage_period";
3883
+ PAGE_TABS = ["overview", "keys", "teams", "models", "audit"];
3884
+ isPageTab = (v) => !!v && PAGE_TABS.includes(v);
3879
3885
  LiteLLMPage = () => {
3880
3886
  const api = (0, import_core_plugin_api4.useApi)(liteLlmApiRef);
3881
3887
  const [dateRange, setDateRange] = (0, import_react11.useState)(initDateRange);
@@ -3886,7 +3892,25 @@ var init_LiteLLMPage = __esm({
3886
3892
  return "7d";
3887
3893
  }
3888
3894
  });
3889
- const [activeTab, setActiveTab] = (0, import_react11.useState)("overview");
3895
+ const [searchParams, setSearchParams] = (0, import_react_router_dom.useSearchParams)();
3896
+ const [activeTab, setActiveTab] = (0, import_react11.useState)(() => {
3897
+ const t = searchParams.get("tab");
3898
+ return isPageTab(t) ? t : "overview";
3899
+ });
3900
+ const selectTab = (0, import_react11.useCallback)(
3901
+ (tab) => {
3902
+ setActiveTab(tab);
3903
+ setSearchParams(
3904
+ (prev) => {
3905
+ const next = new URLSearchParams(prev);
3906
+ next.set("tab", tab);
3907
+ return next;
3908
+ },
3909
+ { replace: true }
3910
+ );
3911
+ },
3912
+ [setSearchParams]
3913
+ );
3890
3914
  const [snackbar, setSnackbar] = (0, import_react11.useState)(null);
3891
3915
  const [generateDialogOpen, setGenerateDialogOpen] = (0, import_react11.useState)(false);
3892
3916
  const [manageTeam, setManageTeam] = (0, import_react11.useState)(null);
@@ -4093,7 +4117,7 @@ var init_LiteLLMPage = __esm({
4093
4117
  import_Tabs2.default,
4094
4118
  {
4095
4119
  value: activeTab,
4096
- onChange: (_, v) => setActiveTab(v),
4120
+ onChange: (_, v) => selectTab(v),
4097
4121
  variant: "scrollable",
4098
4122
  scrollButtons: "auto",
4099
4123
  sx: {