mirror of
https://github.com/openai/codex.git
synced 2026-11-02 19:43:24 +00:00
## Why Wrapping navigation and contextual hints can shift report content as the displayed state changes, especially on narrow terminals. ## What changed - Use compact report tabs, fixed control rows, and two footer hint rows to keep report geometry stable. - Show the account plan in the `Usage` heading and move date ranges, grouping, model filters, sort controls, and update timestamps above reports. - Add scrollable `?` help with an independent scroll position, preserving report selection, expanded details, and reading position when dismissed. - Share control availability between keyboard actions and help, and preserve configured keybindings when they conflict with the help shortcut. ## Testing Add regression coverage for stable tabs after request failures, help state preservation, dashboard selection scrolling, date and update-time controls, and custom keybinding precedence. Update layout snapshots for the revised navigation and narrow help view. GitOrigin-RevId: ab89ed2fd346171362f487c64af7206d9123859a
77 lines
2.7 KiB
Rust
77 lines
2.7 KiB
Rust
//! Account profile loading and the Summary's year-view interaction.
|
|
//! Aggregation changes reuse the loaded profile; account refresh replaces all profile data.
|
|
|
|
use super::AnalyticsView;
|
|
use super::activity_chart::TokenActivityView;
|
|
use super::client::Live;
|
|
use super::data::Load;
|
|
use super::sections::Section;
|
|
use crate::keymap::ListAction;
|
|
use codex_backend_client::AccountProfile;
|
|
|
|
pub(super) const VIEWS: [TokenActivityView; 3] = [
|
|
TokenActivityView::Daily,
|
|
TokenActivityView::Weekly,
|
|
TokenActivityView::Cumulative,
|
|
];
|
|
|
|
impl Live {
|
|
pub(super) async fn profile(&self) -> Result<Option<AccountProfile>, String> {
|
|
let session = self.session().await?;
|
|
let profile = session
|
|
.backend
|
|
.request(|client| async move { client.get_account_profile().await })
|
|
.await;
|
|
self.ensure_identity().await?;
|
|
profile.map(Some).map_err(super::client::request_error)
|
|
}
|
|
}
|
|
|
|
impl AnalyticsView {
|
|
pub(crate) fn select_summary(&mut self, view: Option<TokenActivityView>) {
|
|
self.section = Section::Summary;
|
|
self.zoomed = true;
|
|
self.show_help = false;
|
|
*self.scroll_offset_mut() = 0;
|
|
if let Some(view) = view {
|
|
self.sections[Section::Summary].group = VIEWS
|
|
.iter()
|
|
.position(|item| *item == view)
|
|
.unwrap_or_default();
|
|
}
|
|
}
|
|
|
|
pub(super) fn load_summary(&mut self) {
|
|
if let (Some((_, _, frame)), Some(live)) = (&self.connection, &self.live) {
|
|
let live = std::sync::Arc::clone(live);
|
|
self.profile = Load::start(async move { live.profile().await }, frame.clone());
|
|
}
|
|
}
|
|
|
|
pub(super) fn summary_action(&mut self, action: Option<ListAction>) {
|
|
let step = match action {
|
|
Some(ListAction::MoveUp) => Some(-1),
|
|
Some(ListAction::MoveDown) => Some(1),
|
|
Some(ListAction::PageUp) => Some(-(self.viewport_height as isize)),
|
|
Some(ListAction::PageDown) => Some(self.viewport_height as isize),
|
|
Some(ListAction::JumpTop) => {
|
|
*self.scroll_offset_mut() = 0;
|
|
Some(0)
|
|
}
|
|
Some(ListAction::JumpBottom) => {
|
|
*self.scroll_offset_mut() = usize::MAX;
|
|
Some(0)
|
|
}
|
|
Some(ListAction::Cancel) => {
|
|
self.is_done = true;
|
|
None
|
|
}
|
|
Some(ListAction::MoveLeft | ListAction::MoveRight | ListAction::Accept) | None => None,
|
|
};
|
|
if let Some(step) = step {
|
|
*self.scroll_offset_mut() = self.scroll_offset().saturating_add_signed(step);
|
|
self.follow_selection = false;
|
|
}
|
|
}
|
|
}
|