From 025ddcbfdea41cf7bca7ee1777395f58713d3530 Mon Sep 17 00:00:00 2001
From: RCD <90105158+Finesssee@users.noreply.github.com>
Date: Fri, 2 Oct 2026 21:04:06 +0700
Subject: [PATCH] Port upstream 0.62.0: detail-section visibility via
detailSection IDs
---
.../src-tauri/src/commands/tests.rs | 54 +++++++++++++++++++
.../src-tauri/src/commands/usage_items.rs | 50 +++++++++++++++++
.../src/components/MenuCardDetails.tsx | 19 +++----
.../src/lib/usageItemVisibility.ts | 14 +++++
rust/src/settings.rs | 5 +-
5 files changed, 130 insertions(+), 12 deletions(-)
diff --git a/apps/desktop-tauri/src-tauri/src/commands/tests.rs b/apps/desktop-tauri/src-tauri/src/commands/tests.rs
index 444e93da0ab..a778318982f 100644
--- a/apps/desktop-tauri/src-tauri/src/commands/tests.rs
+++ b/apps/desktop-tauri/src-tauri/src/commands/tests.rs
@@ -988,6 +988,60 @@ fn usage_item_descriptors_keep_raw_ids_and_redact_titles() {
assert!(!items[2].available);
}
+#[test]
+fn usage_item_descriptors_include_detail_sections() {
+ let metadata = instantiate_provider(ProviderId::Codex).metadata().clone();
+ let result = ProviderFetchResult {
+ usage: codexbar::core::UsageSnapshot::new(codexbar::core::RateWindow::new(10.0)),
+ cost: None,
+ wayfinder_usage: None,
+ inventory: Vec::new(),
+ display_details: vec![
+ codexbar::core::ProviderDisplayDetail::new("d1", "Rate limits", "5")
+ .expect("valid detail"),
+ codexbar::core::ProviderDisplayDetail::new("d2", "Rate limits", "6")
+ .expect("valid detail"),
+ codexbar::core::ProviderDisplayDetail::new("d3", "owner@example.com quota", "1")
+ .expect("valid detail"),
+ ],
+ source_label: "OAuth".to_string(),
+ has_successful_claude_cli_quota: false,
+ pace_authoritative: true,
+ account_identity: None,
+ };
+ let snapshot =
+ ProviderUsageSnapshot::from_fetch_result(ProviderId::Codex, &metadata, &result, None);
+
+ let mut settings = Settings {
+ hide_personal_info: true,
+ ..Settings::default()
+ };
+ settings.set_hidden_usage_item_ids(
+ ProviderId::Codex,
+ vec!["detailSection:owner@example.com quota".to_string()],
+ );
+
+ let items = super::usage_item_descriptors(Some(&snapshot), &settings, ProviderId::Codex);
+
+ // First three items are the distinct detail sections, redacted titles.
+ assert_eq!(items[0].id, "detailSection:Rate limits");
+ assert_eq!(items[0].title, "Rate limits");
+ assert!(items[0].available);
+ // Duplicate title is deduped to one descriptor; the email title is redacted.
+ assert!(
+ !items[1..]
+ .iter()
+ .any(|item| item.title.contains("owner@example.com"))
+ );
+ // The hidden detail section is a placeholder, redacted in the stored ID.
+ let hidden = items
+ .iter()
+ .find(|item| item.id.starts_with("detailSection:") && !item.available)
+ .expect("hidden detail placeholder");
+ assert!(hidden.id.contains("owner@example.com quota"));
+ assert_eq!(hidden.title, "Hidden quota");
+}
+
#[test]
fn pace_stage_serializes_to_snake_case_string() {
use codexbar::core::PaceStage;
diff --git a/apps/desktop-tauri/src-tauri/src/commands/usage_items.rs b/apps/desktop-tauri/src-tauri/src/commands/usage_items.rs
index fd34eba4921..17bf96a776a 100644
--- a/apps/desktop-tauri/src-tauri/src/commands/usage_items.rs
+++ b/apps/desktop-tauri/src-tauri/src/commands/usage_items.rs
@@ -81,6 +81,53 @@ pub(crate) fn usage_item_descriptors(
let mut seen = std::collections::HashSet::new();
let mut items = Vec::new();
+ // Detail sections (upstream 0.62.0 #3638): one descriptor per distinct
+ // display-detail title, hidden independently of the metric rows. Detail
+ // IDs round-trip as-is (no metric prefix), so they bypass the `push`
+ // helper below.
+ if let Some(snapshot) = snapshot {
+ let mut detail_titles = std::collections::HashSet::new();
+ for detail in &snapshot.display_details {
+ if detail_titles.insert(detail.title.clone()) {
+ let redacted = PersonalInfoRedactor::redact_emails_in_text(
+ Some(&detail.title),
+ settings.hide_personal_info,
+ )
+ .unwrap_or_default();
+ let id = format!(
+ "{}{}",
+ codexbar::settings::USAGE_ITEM_DETAIL_SECTION_PREFIX,
+ redacted
+ );
+ if seen.insert(id.clone()) {
+ items.push(ProviderUsageItemSnapshot {
+ id,
+ title: redacted,
+ available: true,
+ });
+ }
+ }
+ }
+ }
+ for id in &hidden {
+ if !id.starts_with(codexbar::settings::USAGE_ITEM_DETAIL_SECTION_PREFIX) {
+ continue;
+ }
+ // Placeholder for a hidden detail section the provider no longer
+ // reports: the title is recovered from the stored ID.
+ if seen.insert(id.clone()) {
+ items.push(ProviderUsageItemSnapshot {
+ id: id.clone(),
+ title: redacted_usage_item_title(
+ id.strip_prefix(codexbar::settings::USAGE_ITEM_DETAIL_SECTION_PREFIX)
+ .unwrap_or(id.as_str()),
+ settings,
+ ),
+ available: false,
+ });
+ }
+ }
+
let mut push = |raw_id: &str, title: &str, available: bool| {
let id = usage_item_id(raw_id);
if seen.insert(id.clone()) {
@@ -126,6 +173,9 @@ pub(crate) fn usage_item_descriptors(
}
for id in hidden {
+ if id.starts_with(codexbar::settings::USAGE_ITEM_DETAIL_SECTION_PREFIX) {
+ continue;
+ }
let raw_id = id
.strip_prefix(codexbar::settings::USAGE_ITEM_METRIC_PREFIX)
.unwrap_or(id.as_str());
diff --git a/apps/desktop-tauri/src/components/MenuCardDetails.tsx b/apps/desktop-tauri/src/components/MenuCardDetails.tsx
index 31634bd910e..ce5ec3f93d1 100644
--- a/apps/desktop-tauri/src/components/MenuCardDetails.tsx
+++ b/apps/desktop-tauri/src/components/MenuCardDetails.tsx
@@ -24,6 +24,7 @@ import { SimpleBarChart, StackedBarChart } from "./MiniBarChart";
import { InventoryItemRow } from "./InventoryRows";
import { QuotaWindowHistory } from "./QuotaWindowHistory";
import { getPaceBudget, type PaceBudget } from "../lib/paceBudget";
+import { isDetailSectionVisible } from "../lib/usageItemVisibility";
import PaceDetailsChart from "./PaceDetailsChart";
/** Format a reserve description from raw pace data at render time. */
@@ -597,17 +598,13 @@ export default function MenuCardDetails({
)}
{!provider.error && hasDisplayDetails && !compactOverview && (
- {provider.displayDetails?.map((detail, index) => (
-
- ))}
-
- )}
-
- {!provider.error && hasDisplayDetails && (
-
- {provider.displayDetails?.map((detail, index) => (
-
- ))}
+ {provider.displayDetails
+ ?.filter((detail) =>
+ isDetailSectionVisible(provider.hiddenUsageItemIds, detail.title),
+ )
+ .map((detail, index) => (
+
+ ))}
)}
diff --git a/apps/desktop-tauri/src/lib/usageItemVisibility.ts b/apps/desktop-tauri/src/lib/usageItemVisibility.ts
index 21e86589dd4..b4d9c9344f6 100644
--- a/apps/desktop-tauri/src/lib/usageItemVisibility.ts
+++ b/apps/desktop-tauri/src/lib/usageItemVisibility.ts
@@ -1,13 +1,27 @@
export const USAGE_ITEM_METRIC_PREFIX = "metric:";
+export const USAGE_ITEM_DETAIL_SECTION_PREFIX = "detailSection:";
/** Stable bridge ID for a metric or extra usage row. */
export function usageItemId(rawMetricId: string): string {
return `${USAGE_ITEM_METRIC_PREFIX}${rawMetricId}`;
}
+/** Stable bridge ID for a provider detail section (upstream 0.62.0 #3638). */
+export function detailSectionItemId(rawSectionTitle: string): string {
+ return `${USAGE_ITEM_DETAIL_SECTION_PREFIX}${rawSectionTitle}`;
+}
+
export function isUsageItemVisible(
hiddenUsageItemIds: readonly string[] | undefined,
rawMetricId: string,
): boolean {
return !hiddenUsageItemIds?.includes(usageItemId(rawMetricId));
}
+
+/** A detail section is visible unless its title-based ID is hidden. */
+export function isDetailSectionVisible(
+ hiddenUsageItemIds: readonly string[] | undefined,
+ rawSectionTitle: string,
+): boolean {
+ return !hiddenUsageItemIds?.includes(detailSectionItemId(rawSectionTitle));
+}
diff --git a/rust/src/settings.rs b/rust/src/settings.rs
index 9863f194ceb..f35f6d06835 100755
--- a/rust/src/settings.rs
+++ b/rust/src/settings.rs
@@ -19,6 +19,8 @@ use crate::core::ProviderId;
/// Stable namespace used by the desktop bridge for quota metric rows.
pub const USAGE_ITEM_METRIC_PREFIX: &str = "metric:";
+/// Stable namespace for provider detail sections (upstream 0.62.0 #3638).
+pub const USAGE_ITEM_DETAIL_SECTION_PREFIX: &str = "detailSection:";
pub const CODEX_SPARK_USAGE_ITEM_IDS: [&str; 2] = [
"metric:extra-codex-spark",
"metric:extra-codex-spark-weekly",
@@ -509,7 +511,8 @@ fn normalize_hidden_usage_item_ids(ids: Vec) -> Vec {
!id.is_empty()
&& id.len() <= 128
&& !id.chars().any(char::is_control)
- && id.starts_with(USAGE_ITEM_METRIC_PREFIX)
+ && (id.starts_with(USAGE_ITEM_METRIC_PREFIX)
+ || id.starts_with(USAGE_ITEM_DETAIL_SECTION_PREFIX))
})
.filter(|id| seen.insert(id.clone()))
.collect::>();