@acarmisc/backstage-plugin-litellm 0.30.0 → 0.31.1

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.esm.js CHANGED
@@ -1038,16 +1038,21 @@ var init_Gauge = __esm({
1038
1038
  fontSize: size <= 64 ? 15 : 18,
1039
1039
  fontWeight: 700,
1040
1040
  fontVariantNumeric: "tabular-nums",
1041
- color: "text.primary"
1041
+ color: isOverCap ? "currentColor" : "text.primary"
1042
1042
  },
1043
- children: isOverCap ? "Over cap" : label ?? `${Math.round(value)}%`
1043
+ children: label ?? `${Math.round(value)}%`
1044
1044
  }
1045
1045
  ),
1046
1046
  caption && /* @__PURE__ */ jsx5(
1047
1047
  Typography3,
1048
1048
  {
1049
1049
  variant: "caption",
1050
- sx: { fontSize: 9.5, color: "text.secondary", mt: 0.25 },
1050
+ sx: {
1051
+ fontSize: 9.5,
1052
+ color: "text.secondary",
1053
+ mt: 0.25,
1054
+ whiteSpace: "nowrap"
1055
+ },
1051
1056
  children: caption
1052
1057
  }
1053
1058
  )
@@ -2550,9 +2555,22 @@ var init_KeyFormDialog = __esm({
2550
2555
  setCloseWithoutCopyConfirm(false);
2551
2556
  setTouched({});
2552
2557
  setSubmitAttempted(false);
2553
- onGetConfig().then(setConfig).catch(() => setConfig(null));
2554
2558
  }
2555
- }, [open, isCreate, keyToEdit, username, keyGenerationSettings?.allowUnlimitedBudget, onGetConfig]);
2559
+ }, [open, isCreate, keyToEdit, username, keyGenerationSettings?.allowUnlimitedBudget]);
2560
+ const onGetConfigRef = useRef3(onGetConfig);
2561
+ onGetConfigRef.current = onGetConfig;
2562
+ useEffect3(() => {
2563
+ if (!open) return void 0;
2564
+ let cancelled = false;
2565
+ onGetConfigRef.current().then((c) => {
2566
+ if (!cancelled) setConfig(c);
2567
+ }).catch(() => {
2568
+ if (!cancelled) setConfig(null);
2569
+ });
2570
+ return () => {
2571
+ cancelled = true;
2572
+ };
2573
+ }, [open]);
2556
2574
  const allowUnlimitedBudget = keyGenerationSettings?.allowUnlimitedBudget ?? false;
2557
2575
  const teamRequired = keyGenerationSettings?.teamRequired ?? true;
2558
2576
  const formData = isCreate ? generateForm : editFormState;
@@ -6084,6 +6102,7 @@ var init_LiteLLMPage = __esm({
6084
6102
  ]);
6085
6103
  return allModels.filter((m) => allowed.has(m.model_name));
6086
6104
  }, [allModels, userInfo, teams]);
6105
+ const getConfig = useCallback4(() => api.getConfig(), [api]);
6087
6106
  const handleGenerateKey = useCallback4(
6088
6107
  async (request) => {
6089
6108
  try {
@@ -6409,7 +6428,7 @@ var init_LiteLLMPage = __esm({
6409
6428
  onCreateKey: handleGenerateKey,
6410
6429
  onUpdateKey: handleUpdateKey,
6411
6430
  onResetKeySpend: handleResetKeySpend,
6412
- onGetConfig: () => api.getConfig()
6431
+ onGetConfig: getConfig
6413
6432
  }
6414
6433
  ),
6415
6434
  /* @__PURE__ */ jsx18(
@@ -6573,6 +6592,7 @@ import { Link as Link3 } from "@backstage/core-components";
6573
6592
  // src/homeWidgetHelpers.ts
6574
6593
  init_format();
6575
6594
  init_tokens();
6595
+ init_dates();
6576
6596
  function rangeCaption(startDay, endDay) {
6577
6597
  return `${fmtDateShort(startDay)} \u2013 ${fmtDateShort(endDay)}`;
6578
6598
  }
@@ -6597,6 +6617,10 @@ function sparklineAriaLabel(points) {
6597
6617
  const peakDate = fmtDateShort(maxPoint.date);
6598
6618
  return `Daily spend over ${dayCount} day${dayCount === 1 ? "" : "s"}, total ${fmtUsd(total)}, peak ${fmtUsd(maxPoint.spend)} on ${peakDate}`;
6599
6619
  }
6620
+ function spendOnDay(points, now = /* @__PURE__ */ new Date()) {
6621
+ const day = toLocalDay(now);
6622
+ return points.find((p) => p.date === day)?.spend ?? 0;
6623
+ }
6600
6624
  function usageSummary(usage) {
6601
6625
  if (!usage) {
6602
6626
  return "$0.00 spent \xB7 0 in \xB7 0 out";
@@ -6825,7 +6849,76 @@ function resetLabel(limit) {
6825
6849
  const window2 = fmtBudgetDuration(limit.budgetDuration);
6826
6850
  return window2 ? `resets ${window2}` : "never resets";
6827
6851
  }
6828
- var LevelGauge = ({
6852
+ var Tag = ({ children, tone, title }) => /* @__PURE__ */ jsx21(
6853
+ Typography17,
6854
+ {
6855
+ title,
6856
+ sx: (theme) => ({
6857
+ fontSize: 10.5,
6858
+ fontWeight: 700,
6859
+ letterSpacing: "0.08em",
6860
+ textTransform: "uppercase",
6861
+ lineHeight: 1.3,
6862
+ color: tone ? toneColor(theme, tone) : theme.palette.text.secondary,
6863
+ whiteSpace: "nowrap",
6864
+ overflow: "hidden",
6865
+ textOverflow: "ellipsis"
6866
+ }),
6867
+ children
6868
+ }
6869
+ );
6870
+ var InlineStat = ({ label, value, hint, tone = "accent", title }) => /* @__PURE__ */ jsxs19(Box19, { sx: { minWidth: 0, flex: 1 }, children: [
6871
+ /* @__PURE__ */ jsxs19(Box19, { sx: { display: "flex", alignItems: "center", gap: 0.625, minWidth: 0 }, children: [
6872
+ /* @__PURE__ */ jsx21(
6873
+ Box19,
6874
+ {
6875
+ sx: (theme) => ({
6876
+ width: 6,
6877
+ height: 6,
6878
+ borderRadius: "50%",
6879
+ bgcolor: toneColor(theme, tone),
6880
+ flexShrink: 0
6881
+ })
6882
+ }
6883
+ ),
6884
+ /* @__PURE__ */ jsx21(Tag, { children: label })
6885
+ ] }),
6886
+ /* @__PURE__ */ jsx21(
6887
+ Typography17,
6888
+ {
6889
+ title,
6890
+ sx: {
6891
+ fontSize: 19,
6892
+ fontWeight: 700,
6893
+ lineHeight: 1.15,
6894
+ mt: 0.25,
6895
+ fontVariantNumeric: "tabular-nums",
6896
+ whiteSpace: "nowrap",
6897
+ overflow: "hidden",
6898
+ textOverflow: "ellipsis"
6899
+ },
6900
+ children: value
6901
+ }
6902
+ ),
6903
+ /* @__PURE__ */ jsx21(
6904
+ Typography17,
6905
+ {
6906
+ variant: "caption",
6907
+ color: "text.secondary",
6908
+ sx: {
6909
+ display: "block",
6910
+ mt: 0.25,
6911
+ fontSize: 10.5,
6912
+ minHeight: 14,
6913
+ whiteSpace: "nowrap",
6914
+ overflow: "hidden",
6915
+ textOverflow: "ellipsis"
6916
+ },
6917
+ children: hint ?? ""
6918
+ }
6919
+ )
6920
+ ] });
6921
+ var LevelRow = ({
6829
6922
  gauge,
6830
6923
  size,
6831
6924
  keysHref
@@ -6834,14 +6927,42 @@ var LevelGauge = ({
6834
6927
  const limit = gauge.limit;
6835
6928
  const tone = limit ? budgetTone2(limit.pct) : "neutral";
6836
6929
  const extra = gauge.kind === "key" ? Math.max(0, gauge.count - 1) : 0;
6930
+ const overCap = Boolean(limit && limit.pct > 100);
6931
+ const subNote = () => {
6932
+ if (overCap) return "Over cap";
6933
+ if (extra > 0 && keysHref) {
6934
+ return /* @__PURE__ */ jsxs19(
6935
+ Typography17,
6936
+ {
6937
+ component: Link4,
6938
+ to: keysHref,
6939
+ variant: "caption",
6940
+ sx: {
6941
+ fontSize: 10.5,
6942
+ color: "primary.main",
6943
+ textDecoration: "none",
6944
+ "&:hover": { textDecoration: "underline" }
6945
+ },
6946
+ children: [
6947
+ "+",
6948
+ extra,
6949
+ " more"
6950
+ ]
6951
+ }
6952
+ );
6953
+ }
6954
+ return limit?.sublabel ?? null;
6955
+ };
6837
6956
  const gaugeAriaLabel = limit ? `${name} budget used: ${Math.round(limit.pct)}%` : `${name} \u2014 no cap`;
6838
6957
  return /* @__PURE__ */ jsxs19(
6839
6958
  Box19,
6840
6959
  {
6841
6960
  sx: {
6842
- display: "flex",
6843
- flexDirection: "column",
6961
+ display: "grid",
6962
+ gridTemplateColumns: "auto minmax(0, 1fr) auto",
6844
6963
  alignItems: "center",
6964
+ gap: 1.25,
6965
+ py: 0.75,
6845
6966
  minWidth: 0
6846
6967
  },
6847
6968
  children: [
@@ -6855,84 +6976,109 @@ var LevelGauge = ({
6855
6976
  ariaLabel: gaugeAriaLabel
6856
6977
  }
6857
6978
  ),
6858
- /* @__PURE__ */ jsx21(
6859
- Typography17,
6860
- {
6861
- sx: (theme) => ({
6862
- mt: 0.75,
6863
- fontSize: 10.5,
6864
- fontWeight: 700,
6865
- letterSpacing: "0.08em",
6866
- textTransform: "uppercase",
6867
- color: tone === "neutral" ? theme.palette.text.secondary : void 0
6868
- }),
6869
- children: name
6870
- }
6871
- ),
6872
- limit ? /* @__PURE__ */ jsxs19(Fragment11, { children: [
6873
- /* @__PURE__ */ jsx21(
6979
+ /* @__PURE__ */ jsxs19(Box19, { sx: { minWidth: 0 }, children: [
6980
+ /* @__PURE__ */ jsx21(Tag, { tone: tone === "warning" || tone === "danger" ? tone : void 0, children: name }),
6981
+ limit ? /* @__PURE__ */ jsxs19(Fragment11, { children: [
6982
+ /* @__PURE__ */ jsx21(
6983
+ Typography17,
6984
+ {
6985
+ variant: "caption",
6986
+ title: limit.sublabel ? `${limit.label} \xB7 ${limit.sublabel}` : limit.label,
6987
+ sx: {
6988
+ display: "block",
6989
+ fontSize: 11.5,
6990
+ fontWeight: 600,
6991
+ lineHeight: 1.35,
6992
+ overflow: "hidden",
6993
+ textOverflow: "ellipsis",
6994
+ whiteSpace: "nowrap"
6995
+ },
6996
+ children: limit.label
6997
+ }
6998
+ ),
6999
+ /* @__PURE__ */ jsx21(
7000
+ Typography17,
7001
+ {
7002
+ variant: "caption",
7003
+ color: overCap ? "error" : "text.secondary",
7004
+ sx: {
7005
+ display: "block",
7006
+ fontSize: 10.5,
7007
+ fontWeight: overCap ? 700 : void 0,
7008
+ lineHeight: 1.35,
7009
+ overflow: "hidden",
7010
+ textOverflow: "ellipsis",
7011
+ whiteSpace: "nowrap"
7012
+ },
7013
+ children: subNote()
7014
+ }
7015
+ )
7016
+ ] }) : /* @__PURE__ */ jsx21(
6874
7017
  Typography17,
6875
7018
  {
6876
7019
  variant: "caption",
6877
- title: limit.sublabel ? `${limit.label} \xB7 ${limit.sublabel}` : limit.label,
7020
+ color: "text.secondary",
6878
7021
  sx: {
6879
- mt: 0.25,
6880
- fontSize: 11,
6881
- fontWeight: 600,
6882
- maxWidth: "100%",
7022
+ display: "block",
7023
+ fontSize: 10.5,
7024
+ lineHeight: 1.35,
6883
7025
  overflow: "hidden",
6884
7026
  textOverflow: "ellipsis",
6885
7027
  whiteSpace: "nowrap"
6886
7028
  },
6887
- children: limit.label
7029
+ children: none
6888
7030
  }
6889
- ),
7031
+ )
7032
+ ] }),
7033
+ /* @__PURE__ */ jsxs19(Box19, { sx: { minWidth: 0, textAlign: "right" }, children: [
6890
7034
  /* @__PURE__ */ jsx21(
6891
7035
  Typography17,
6892
7036
  {
6893
- variant: "caption",
6894
- color: "text.secondary",
7037
+ title: limit ? `${fmtUsd(limit.spend)} of ${fmtUsd(limit.budget)}` : void 0,
6895
7038
  sx: {
6896
- fontSize: 10.5,
7039
+ display: "block",
7040
+ fontSize: 12.5,
7041
+ fontWeight: 600,
7042
+ lineHeight: 1.35,
6897
7043
  fontVariantNumeric: "tabular-nums",
6898
- textAlign: "center"
7044
+ whiteSpace: "nowrap",
7045
+ overflow: "hidden",
7046
+ textOverflow: "ellipsis",
7047
+ color: limit ? void 0 : "text.secondary"
6899
7048
  },
6900
- children: spendCaption(limit)
7049
+ children: amountCaption(limit)
6901
7050
  }
6902
7051
  ),
6903
- extra > 0 && keysHref ? /* @__PURE__ */ jsxs19(
7052
+ /* @__PURE__ */ jsx21(
6904
7053
  Typography17,
6905
7054
  {
6906
- component: Link4,
6907
- to: keysHref,
6908
7055
  variant: "caption",
7056
+ color: "text.secondary",
6909
7057
  sx: {
7058
+ display: "block",
6910
7059
  fontSize: 10.5,
6911
- color: "primary.main",
6912
- textDecoration: "none",
6913
- "&:hover": { textDecoration: "underline" }
7060
+ lineHeight: 1.35,
7061
+ whiteSpace: "nowrap",
7062
+ overflow: "hidden",
7063
+ textOverflow: "ellipsis"
6914
7064
  },
6915
- children: [
6916
- "+",
6917
- extra,
6918
- " more"
6919
- ]
7065
+ children: amountNote(limit)
6920
7066
  }
6921
- ) : /* @__PURE__ */ jsx21(Typography17, { variant: "caption", color: "text.secondary", sx: { fontSize: 10.5 }, children: resetLabel(limit) })
6922
- ] }) : /* @__PURE__ */ jsx21(
6923
- Typography17,
6924
- {
6925
- variant: "caption",
6926
- color: "text.secondary",
6927
- sx: { mt: 0.25, fontSize: 10.5, textAlign: "center" },
6928
- children: none
6929
- }
6930
- )
7067
+ )
7068
+ ] })
6931
7069
  ]
6932
7070
  }
6933
7071
  );
6934
7072
  };
6935
- var UsageMiniChart = ({ data, totalSpend, loading, height, usageUnavailable = false, maxBudget }) => {
7073
+ function amountCaption(limit) {
7074
+ if (!limit) return "";
7075
+ return limit.hidden ? `${Math.round(limit.pct)}%` : spendCaption(limit);
7076
+ }
7077
+ function amountNote(limit) {
7078
+ if (!limit) return "";
7079
+ return limit.hidden ? "hidden by admin" : resetLabel(limit);
7080
+ }
7081
+ var SpendStrip = ({ data, mtdSpend, loading, height, usageUnavailable = false, maxBudget }) => {
6936
7082
  const renderPlot = () => {
6937
7083
  if (loading) {
6938
7084
  return /* @__PURE__ */ jsx21(Skeleton8, { variant: "rectangular", width: "100%", height: "100%" });
@@ -6978,99 +7124,70 @@ var UsageMiniChart = ({ data, totalSpend, loading, height, usageUnavailable = fa
6978
7124
  )
6979
7125
  ] }) });
6980
7126
  };
6981
- const renderCaption = () => {
6982
- if (loading) {
6983
- return /* @__PURE__ */ jsx21(Typography17, { variant: "caption", color: "text.secondary", sx: { mt: 0.25, fontSize: 11 }, children: "\u2026" });
6984
- }
6985
- if (usageUnavailable) {
6986
- return /* @__PURE__ */ jsx21(
6987
- Typography17,
6988
- {
6989
- variant: "caption",
6990
- color: "text.secondary",
6991
- sx: { mt: 0.25, fontSize: 10.5, textAlign: "center" },
6992
- children: USAGE_UNAVAILABLE_MSG
6993
- }
6994
- );
6995
- }
6996
- if (data.length === 0) {
6997
- return /* @__PURE__ */ jsx21(
6998
- Typography17,
6999
- {
7000
- variant: "caption",
7001
- color: "text.secondary",
7002
- sx: { mt: 0.25, fontSize: 10.5, textAlign: "center" },
7003
- children: "No spend this month"
7004
- }
7005
- );
7006
- }
7007
- return /* @__PURE__ */ jsxs19(Fragment11, { children: [
7008
- /* @__PURE__ */ jsx21(
7009
- Typography17,
7010
- {
7011
- variant: "caption",
7012
- title: `${fmtUsd(totalSpend)} spent month to date`,
7013
- sx: {
7014
- mt: 0.25,
7015
- fontSize: 11,
7016
- fontWeight: 600,
7017
- maxWidth: "100%",
7018
- overflow: "hidden",
7019
- textOverflow: "ellipsis",
7020
- whiteSpace: "nowrap",
7021
- fontVariantNumeric: "tabular-nums"
7022
- },
7023
- children: fmtUsd(totalSpend)
7024
- }
7025
- ),
7026
- /* @__PURE__ */ jsx21(Typography17, { variant: "caption", color: "text.secondary", sx: { fontSize: 10.5 }, children: "month to date" })
7027
- ] });
7028
- };
7029
- return /* @__PURE__ */ jsxs19(
7030
- Box19,
7031
- {
7032
- sx: {
7033
- display: "flex",
7034
- flexDirection: "column",
7035
- alignItems: "center",
7036
- minWidth: 0
7037
- },
7038
- role: "img",
7039
- "aria-label": sparklineAriaLabel(data),
7040
- children: [
7041
- /* @__PURE__ */ jsx21(Box19, { sx: { height, width: "100%" }, children: renderPlot() }),
7042
- /* @__PURE__ */ jsx21(
7043
- Typography17,
7044
- {
7045
- sx: (theme) => ({
7046
- mt: 0.75,
7047
- fontSize: 10.5,
7048
- fontWeight: 700,
7049
- letterSpacing: "0.08em",
7050
- textTransform: "uppercase",
7051
- color: theme.palette.text.secondary
7052
- }),
7053
- children: "Spend (MTD)"
7054
- }
7055
- ),
7056
- /* @__PURE__ */ jsx21(
7057
- Typography17,
7058
- {
7059
- variant: "caption",
7060
- color: "text.secondary",
7061
- sx: { mt: 0.25, fontSize: 10.5 },
7062
- children: mtdCaption()
7063
- }
7064
- ),
7065
- renderCaption()
7066
- ]
7067
- }
7068
- );
7127
+ const caption = (() => {
7128
+ if (loading) return "\u2026";
7129
+ if (usageUnavailable) return USAGE_UNAVAILABLE_MSG;
7130
+ if (data.length === 0) return "No spend this month";
7131
+ return mtdCaption();
7132
+ })();
7133
+ return /* @__PURE__ */ jsxs19(Box19, { role: "img", "aria-label": sparklineAriaLabel(data), sx: { minWidth: 0 }, children: [
7134
+ /* @__PURE__ */ jsx21(Box19, { sx: { height, width: "100%" }, children: renderPlot() }),
7135
+ /* @__PURE__ */ jsxs19(
7136
+ Box19,
7137
+ {
7138
+ sx: {
7139
+ display: "flex",
7140
+ alignItems: "baseline",
7141
+ justifyContent: "space-between",
7142
+ gap: 1,
7143
+ mt: 0.5,
7144
+ minWidth: 0
7145
+ },
7146
+ children: [
7147
+ /* @__PURE__ */ jsxs19(Box19, { sx: { display: "flex", alignItems: "baseline", gap: 0.75, minWidth: 0 }, children: [
7148
+ /* @__PURE__ */ jsx21(Tag, { children: "Spent (mtd)" }),
7149
+ /* @__PURE__ */ jsx21(
7150
+ Typography17,
7151
+ {
7152
+ variant: "caption",
7153
+ color: "text.secondary",
7154
+ sx: { fontSize: 10.5, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
7155
+ children: caption
7156
+ }
7157
+ )
7158
+ ] }),
7159
+ /* @__PURE__ */ jsx21(
7160
+ Typography17,
7161
+ {
7162
+ title: loading || usageUnavailable ? void 0 : `${fmtUsd(mtdSpend)} spent month to date`,
7163
+ sx: {
7164
+ fontSize: 12.5,
7165
+ fontWeight: 700,
7166
+ fontVariantNumeric: "tabular-nums",
7167
+ whiteSpace: "nowrap"
7168
+ },
7169
+ children: loading || usageUnavailable ? "\u2014" : fmtUsd(mtdSpend)
7170
+ }
7171
+ )
7172
+ ]
7173
+ }
7174
+ )
7175
+ ] });
7069
7176
  };
7177
+ function statValue(loading, unavailable, value) {
7178
+ if (loading) return "\u2026";
7179
+ if (unavailable) return "\u2014";
7180
+ return value;
7181
+ }
7182
+ function statHint(loading, unavailable, hint) {
7183
+ if (loading) return void 0;
7184
+ if (unavailable) return USAGE_UNAVAILABLE_MSG;
7185
+ return hint;
7186
+ }
7070
7187
  var LiteLLMBudgetGauges = ({
7071
7188
  title = "Budget",
7072
7189
  bare = false,
7073
- size = 72,
7190
+ size = 56,
7074
7191
  keysHref,
7075
7192
  moduleHref: propModuleHref,
7076
7193
  onCreateKey,
@@ -7087,7 +7204,7 @@ var LiteLLMBudgetGauges = ({
7087
7204
  const api = useApi6(liteLlmApiRef);
7088
7205
  const theme = useTheme4();
7089
7206
  const isSmallScreen = useMediaQuery(theme.breakpoints.down("sm"));
7090
- const gaugeSize = isSmallScreen ? 56 : size;
7207
+ const gaugeSize = isSmallScreen ? Math.min(48, size) : size;
7091
7208
  const expandedRegionId = useId2();
7092
7209
  const moduleRouteRef = useRouteRef3(rootRouteRef);
7093
7210
  const moduleHref = propModuleHref ?? moduleRouteRef?.();
@@ -7162,6 +7279,12 @@ var LiteLLMBudgetGauges = ({
7162
7279
  }),
7163
7280
  [loading, profileError, user, usageError, keys]
7164
7281
  );
7282
+ const today = /* @__PURE__ */ new Date();
7283
+ const todaySpend = spendOnDay(dailySpend, today);
7284
+ const yesterday = new Date(today);
7285
+ yesterday.setDate(yesterday.getDate() - 1);
7286
+ const yesterdaySpend = dailySpend.some((d) => d.date === toLocalDay(yesterday)) ? spendOnDay(dailySpend, yesterday) : null;
7287
+ const todayHint = yesterdaySpend === null ? void 0 : `vs ${fmtUsd(yesterdaySpend)} yesterday`;
7165
7288
  const summaryText = headline.count === 0 ? "no limits apply" : `${headline.count} limit${headline.count === 1 ? "" : "s"}`;
7166
7289
  const resolvedCtas = useMemo11(() => {
7167
7290
  return resolveCtas({
@@ -7222,29 +7345,70 @@ var LiteLLMBudgetGauges = ({
7222
7345
  }
7223
7346
  )
7224
7347
  ] }),
7225
- viewState.kind === "loading" && /* @__PURE__ */ jsx21(Box19, { sx: { display: "flex", alignItems: "flex-start", gap: 1, minHeight: size }, children: [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsxs19(Box19, { sx: { display: "flex", flexDirection: "column", alignItems: "center", flex: 1 }, children: [
7226
- /* @__PURE__ */ jsx21(Skeleton8, { variant: "circular", width: size, height: size, sx: { mb: 0.75 } }),
7227
- /* @__PURE__ */ jsx21(Skeleton8, { variant: "text", width: "100%", height: 12, sx: { mb: 0.25 } }),
7228
- /* @__PURE__ */ jsx21(Skeleton8, { variant: "text", width: "80%", height: 11, sx: { mb: 0.25 } }),
7229
- /* @__PURE__ */ jsx21(Skeleton8, { variant: "text", width: "70%", height: 10.5 })
7348
+ viewState.kind === "loading" && /* @__PURE__ */ jsx21(Box19, { sx: { display: "flex", flexDirection: "column", gap: 1.25, minHeight: size }, children: [0, 1, 2].map((i) => /* @__PURE__ */ jsxs19(Box19, { sx: { display: "flex", alignItems: "center", gap: 1.25 }, children: [
7349
+ /* @__PURE__ */ jsx21(Skeleton8, { variant: "circular", width: size, height: size }),
7350
+ /* @__PURE__ */ jsxs19(Box19, { sx: { flex: 1 }, children: [
7351
+ /* @__PURE__ */ jsx21(Skeleton8, { variant: "text", width: "70%", height: 12, sx: { mb: 0.25 } }),
7352
+ /* @__PURE__ */ jsx21(Skeleton8, { variant: "text", width: "45%", height: 11 })
7353
+ ] }),
7354
+ /* @__PURE__ */ jsx21(Skeleton8, { variant: "text", width: 64, height: 12 })
7230
7355
  ] }, i)) }),
7231
7356
  viewState.kind === "error" && /* @__PURE__ */ jsx21(Typography17, { variant: "body2", color: "text.secondary", sx: { mt: 0.5 }, children: viewState.message }),
7232
7357
  viewState.kind === "unprovisioned" && /* @__PURE__ */ jsx21(Typography17, { variant: "body2", color: "text.secondary", sx: { mt: 0.5 }, children: UNPROVISIONED_MSG }),
7233
7358
  viewState.kind === "ready" && /* @__PURE__ */ jsxs19(Fragment11, { children: [
7234
- /* @__PURE__ */ jsxs19(Box19, { sx: { display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(76px, 1fr))", gap: 1 }, children: [
7235
- gauges.map((gauge) => /* @__PURE__ */ jsx21(LevelGauge, { gauge, size: gaugeSize, keysHref: keysTabHref }, gauge.kind)),
7236
- /* @__PURE__ */ jsx21(
7237
- UsageMiniChart,
7238
- {
7239
- data: dailySpend,
7240
- totalSpend: mtdSpend,
7241
- loading: usageLoading,
7242
- height: gaugeSize,
7243
- usageUnavailable: viewState.usageUnavailable,
7244
- maxBudget: user?.max_budget ?? void 0
7245
- }
7246
- )
7247
- ] }),
7359
+ /* @__PURE__ */ jsxs19(
7360
+ Box19,
7361
+ {
7362
+ sx: {
7363
+ display: "flex",
7364
+ alignItems: "stretch",
7365
+ gap: 2,
7366
+ mb: 1.25,
7367
+ minWidth: 0
7368
+ },
7369
+ children: [
7370
+ /* @__PURE__ */ jsx21(
7371
+ InlineStat,
7372
+ {
7373
+ label: "Today spent",
7374
+ tone: "accent",
7375
+ value: statValue(usageLoading, viewState.usageUnavailable, fmtUsd(todaySpend)),
7376
+ hint: statHint(usageLoading, viewState.usageUnavailable, todayHint),
7377
+ title: usageLoading || viewState.usageUnavailable ? void 0 : "Spend since local midnight"
7378
+ }
7379
+ ),
7380
+ /* @__PURE__ */ jsx21(Box19, { sx: { width: "1px", bgcolor: "divider", flexShrink: 0 } }),
7381
+ /* @__PURE__ */ jsx21(
7382
+ InlineStat,
7383
+ {
7384
+ label: "Month to date",
7385
+ value: statValue(usageLoading, viewState.usageUnavailable, fmtUsd(mtdSpend)),
7386
+ hint: statHint(usageLoading, viewState.usageUnavailable, mtdCaption()),
7387
+ title: usageLoading || viewState.usageUnavailable ? void 0 : "Spend from the 1st of this month"
7388
+ }
7389
+ )
7390
+ ]
7391
+ }
7392
+ ),
7393
+ /* @__PURE__ */ jsx21(Box19, { sx: { borderTop: "1px solid", borderColor: "divider" }, children: gauges.map((gauge, i) => /* @__PURE__ */ jsx21(
7394
+ Box19,
7395
+ {
7396
+ sx: i === 0 ? void 0 : { borderTop: "1px solid", borderColor: "divider" },
7397
+ children: /* @__PURE__ */ jsx21(LevelRow, { gauge, size: gaugeSize, keysHref: keysTabHref })
7398
+ },
7399
+ gauge.kind
7400
+ )) }),
7401
+ /* @__PURE__ */ jsx21(Box19, { sx: { mt: 1.25 }, children: /* @__PURE__ */ jsx21(
7402
+ SpendStrip,
7403
+ {
7404
+ data: dailySpend,
7405
+ mtdSpend,
7406
+ loading: usageLoading,
7407
+ height: gaugeSize,
7408
+ usageUnavailable: viewState.usageUnavailable,
7409
+ maxBudget: user?.max_budget ?? void 0
7410
+ }
7411
+ ) }),
7248
7412
  /* @__PURE__ */ jsx21(Collapse4, { in: isExpanded, unmountOnExit: true, children: /* @__PURE__ */ jsx21(
7249
7413
  Box19,
7250
7414
  {