Login flow polish (#3632)
# Description - Update sign in flow # Tests - Passes CI --------- Co-authored-by: Michael Bolin <mbolin@openai.com>
This commit is contained in:
@@ -137,12 +137,12 @@ impl AuthModeWidget {
|
||||
fn render_pick_mode(&self, area: Rect, buf: &mut Buffer) {
|
||||
let mut lines: Vec<Line> = vec![
|
||||
Line::from(vec![
|
||||
"> ".into(),
|
||||
"Sign in with ChatGPT to use Codex as part of your paid plan".bold(),
|
||||
" ".into(),
|
||||
"Sign in with ChatGPT to use Codex as part of your paid plan".into(),
|
||||
]),
|
||||
Line::from(vec![
|
||||
" ".into(),
|
||||
"or connect an API key for usage-based billing".bold(),
|
||||
"or connect an API key for usage-based billing".into(),
|
||||
]),
|
||||
"".into(),
|
||||
];
|
||||
@@ -182,6 +182,7 @@ impl AuthModeWidget {
|
||||
"Sign in with ChatGPT",
|
||||
"Usage included with Plus, Pro, and Team plans",
|
||||
));
|
||||
lines.push("".into());
|
||||
lines.extend(create_mode_item(
|
||||
1,
|
||||
AuthMode::ApiKey,
|
||||
@@ -205,7 +206,7 @@ impl AuthModeWidget {
|
||||
}
|
||||
|
||||
fn render_continue_in_browser(&self, area: Rect, buf: &mut Buffer) {
|
||||
let mut spans = vec!["> ".into()];
|
||||
let mut spans = vec![" ".into()];
|
||||
// Schedule a follow-up frame to keep the shimmer animation going.
|
||||
self.request_frame
|
||||
.schedule_frame_in(std::time::Duration::from_millis(100));
|
||||
@@ -217,7 +218,8 @@ impl AuthModeWidget {
|
||||
&& !state.auth_url.is_empty()
|
||||
{
|
||||
lines.push(" If the link doesn't open automatically, open the following link to authenticate:".into());
|
||||
lines.push(vec![" ".into(), state.auth_url.as_str().cyan().underlined()].into());
|
||||
lines.push("".into());
|
||||
lines.push(Line::from(state.auth_url.as_str().cyan().underlined()));
|
||||
lines.push("".into());
|
||||
}
|
||||
|
||||
@@ -231,7 +233,7 @@ impl AuthModeWidget {
|
||||
let lines = vec![
|
||||
"✓ Signed in with your ChatGPT account".fg(Color::Green).into(),
|
||||
"".into(),
|
||||
"> Before you start:".into(),
|
||||
" Before you start:".into(),
|
||||
"".into(),
|
||||
" Decide how much autonomy you want to grant Codex".into(),
|
||||
Line::from(vec![
|
||||
|
||||
@@ -24,6 +24,7 @@ use crate::tui::TuiEvent;
|
||||
use color_eyre::eyre::Result;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
use std::time::Instant;
|
||||
|
||||
#[allow(clippy::large_enum_variant)]
|
||||
enum Step {
|
||||
@@ -74,6 +75,8 @@ impl OnboardingScreen {
|
||||
let codex_home = config.codex_home;
|
||||
let mut steps: Vec<Step> = vec![Step::Welcome(WelcomeWidget {
|
||||
is_logged_in: !matches!(login_status, LoginStatus::NotAuthenticated),
|
||||
request_frame: tui.frame_requester(),
|
||||
start: Instant::now(),
|
||||
})];
|
||||
if show_login_screen {
|
||||
steps.push(Step::Auth(AuthModeWidget {
|
||||
|
||||
@@ -3,23 +3,62 @@ use ratatui::layout::Rect;
|
||||
use ratatui::prelude::Widget;
|
||||
use ratatui::style::Stylize;
|
||||
use ratatui::text::Line;
|
||||
use ratatui::widgets::Paragraph;
|
||||
use ratatui::widgets::WidgetRef;
|
||||
use ratatui::widgets::Wrap;
|
||||
|
||||
use crate::frames::FRAME_TICK_DEFAULT;
|
||||
use crate::frames::FRAMES_DEFAULT;
|
||||
use crate::onboarding::onboarding_screen::StepStateProvider;
|
||||
use crate::tui::FrameRequester;
|
||||
|
||||
use super::onboarding_screen::StepState;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
|
||||
const FRAME_TICK: Duration = FRAME_TICK_DEFAULT;
|
||||
|
||||
pub(crate) struct WelcomeWidget {
|
||||
pub is_logged_in: bool,
|
||||
pub request_frame: FrameRequester,
|
||||
pub start: Instant,
|
||||
}
|
||||
|
||||
impl WidgetRef for &WelcomeWidget {
|
||||
fn render_ref(&self, area: Rect, buf: &mut Buffer) {
|
||||
let line = Line::from(vec![
|
||||
">_ ".into(),
|
||||
"Welcome to Codex, OpenAI's command-line coding agent".bold(),
|
||||
]);
|
||||
line.render(area, buf);
|
||||
let elapsed_ms = self.start.elapsed().as_millis();
|
||||
|
||||
// Align next draw to the next FRAME_TICK boundary to reduce jitter.
|
||||
{
|
||||
let tick_ms = FRAME_TICK.as_millis();
|
||||
let rem_ms = elapsed_ms % tick_ms;
|
||||
let delay_ms = if rem_ms == 0 {
|
||||
tick_ms
|
||||
} else {
|
||||
tick_ms - rem_ms
|
||||
};
|
||||
// Safe cast: delay_ms < tick_ms and FRAME_TICK is small.
|
||||
self.request_frame
|
||||
.schedule_frame_in(Duration::from_millis(delay_ms as u64));
|
||||
}
|
||||
|
||||
let frames = &FRAMES_DEFAULT;
|
||||
let idx = ((elapsed_ms / FRAME_TICK.as_millis()) % frames.len() as u128) as usize;
|
||||
|
||||
let mut lines: Vec<Line> = Vec::with_capacity(frames.len() + 2);
|
||||
lines.extend(frames[idx].lines().map(|l| l.into()));
|
||||
|
||||
lines.push("".into());
|
||||
lines.push(Line::from(vec![
|
||||
" ".into(),
|
||||
"Welcome to ".into(),
|
||||
"Codex".bold(),
|
||||
", OpenAI's command-line coding agent".into(),
|
||||
]));
|
||||
|
||||
Paragraph::new(lines)
|
||||
.wrap(Wrap { trim: false })
|
||||
.render(area, buf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,3 +70,14 @@ impl StepStateProvider for WelcomeWidget {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
/// A number of things break down if FRAME_TICK is zero.
|
||||
#[test]
|
||||
fn frame_tick_must_be_nonzero() {
|
||||
assert!(FRAME_TICK.as_millis() > 0);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user