Panics · P37 Onboarding: handlers in new; gone articles, steps and topics hold

This commit is contained in:
ZacharyZhang-NY committed 2026-10-07 06:18:15 -04:00
1 parent e7aec1651e
commit 8db6cecd5a
12 files changed
+253 -229

No files matched your search

+46 -22
View File
@@ -1,6 +1,6 @@
use gpui::{AnyElement, Entity, IntoElement, ParentElement, TestAppContext, div, px};
use super::{Bench, bench, edit, said, say, tab, tap};
use super::{Bench, bench, edit, said, say, settle, tab, tap};
use crate::{
buttons::Button,
onboarding::{
@@ -16,19 +16,34 @@ fn wizard(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
body: "A line on it".into(),
});
let [stepper, finisher, skipper] = [(); 3].map(|_| owner.clone());
OnboardingWizard::new("welcome", steps, bench.step)
.ready(bench.ready)
.content(div().child("Fields"))
.on_step(move |to, _, cx| {
OnboardingWizard::new(
"welcome",
steps,
bench.step,
move |to, _, cx| {
stepper.update(cx, |bench, cx| {
bench.step = to;
bench.said.push(format!("step {to}"));
cx.notify();
})
})
.on_finish(move |_, cx| say(&finisher, "finish".into(), cx))
.on_skip(move |_, cx| say(&skipper, "skip".into(), cx))
.into_any_element()
},
move |_, cx| say(&finisher, "finish".into(), cx),
)
.ready(bench.ready)
.content(div().child("Fields"))
.on_skip(move |_, cx| say(&skipper, "skip".into(), cx))
.into_any_element()
}
#[gpui::test]
fn a_step_past_the_last_shows_none(cx: &mut TestAppContext) {
let (host, cx) = bench(wizard, cx);
host.update(cx, |bench, cx| {
bench.step = 9;
cx.notify();
});
settle(cx);
assert!(cx.debug_bounds("onboarding-No step of 3").is_some());
}
/// Stops: Skip, then Next on the first step; Skip, Back, then Next or Finish after it.
@@ -92,9 +107,13 @@ fn back_to_the_first_step_hands_focus_to_next(cx: &mut TestAppContext) {
}
fn hotspot(_: &Bench, owner: Entity<Bench>) -> AnyElement {
Hotspot::new("pins", "Pin a view", "Keep it one press away.")
.on_dismiss(move |_, cx| say(&owner, "seen".into(), cx))
.into_any_element()
Hotspot::new(
"pins",
"Pin a view",
"Keep it one press away.",
move |_, cx| say(&owner, "seen".into(), cx),
)
.into_any_element()
}
/// Stops: the dot; Enter opens the tip, where Got it is the one stop.
@@ -122,13 +141,18 @@ fn a_hotspot_opens_its_tip_from_the_keyboard_and_is_dismissed(cx: &mut TestAppCo
fn hidden_hotspot(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
let after = owner.clone();
let spot = (!bench.hidden).then(|| {
Hotspot::new("pins", "Pin a view", "Keep it one press away.").on_dismiss(move |_, cx| {
owner.update(cx, |bench, cx| {
bench.said.push("seen".into());
bench.hidden = true;
cx.notify();
})
})
Hotspot::new(
"pins",
"Pin a view",
"Keep it one press away.",
move |_, cx| {
owner.update(cx, |bench, cx| {
bench.said.push("seen".into());
bench.hidden = true;
cx.notify();
})
},
)
});
FocusScope::new(&bench.root)
.root()
@@ -160,9 +184,9 @@ fn highlight(_: &Bench, owner: Entity<Bench>) -> AnyElement {
IconName::Columns2,
"Split view",
"Work on two files side by side.",
move |_, cx| say(&owner, "try".into(), cx),
move |_, cx| say(&later, "later".into(), cx),
)
.on_try(move |_, cx| say(&owner, "try".into(), cx))
.on_dismiss(move |_, cx| say(&later, "later".into(), cx))
.into_any_element()
}
@@ -193,8 +217,8 @@ fn checklist(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
task("invite", false),
task("connect", false),
],
move |key, _, cx| say(&owner, format!("start {key}"), cx),
)
.on_start(move |key, _, cx| say(&owner, format!("start {key}"), cx))
.on_dismiss(move |_, cx| say(&hidden, "hide".into(), cx))
.into_any_element()
}
+73 -25
View File
@@ -29,8 +29,12 @@ fn panel(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
div()
.h(px(420.0))
.child(
HelpPanel::new("help", articles, &bench.search, bench.open.clone())
.on_open(move |key, _, cx| {
HelpPanel::new(
"help",
articles,
&bench.search,
bench.open.clone(),
move |key, _, cx| {
let key = key.cloned();
opener.update(cx, |bench, cx| {
bench.said.push(format!(
@@ -40,10 +44,11 @@ fn panel(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
bench.open = key;
cx.notify();
})
})
.on_contact(move |_, cx| say(&contact, "contact".into(), cx))
.on_shortcuts(move |_, cx| say(&keys, "shortcuts".into(), cx))
.on_close(move |_, cx| say(&close, "close".into(), cx)),
},
)
.on_contact(move |_, cx| say(&contact, "contact".into(), cx))
.on_shortcuts(move |_, cx| say(&keys, "shortcuts".into(), cx))
.on_close(move |_, cx| say(&close, "close".into(), cx)),
)
.into_any_element()
}
@@ -84,8 +89,12 @@ fn many(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
.w(px(280.0))
.h(px(300.0))
.child(
HelpPanel::new("help", articles, &bench.search, bench.open.clone())
.on_open(move |key, _, cx| {
HelpPanel::new(
"help",
articles,
&bench.search,
bench.open.clone(),
move |key, _, cx| {
let key = key.cloned();
opener.update(cx, |bench, cx| {
bench.said.push(format!(
@@ -95,8 +104,9 @@ fn many(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
bench.open = key;
cx.notify();
})
})
.on_contact(move |_, cx| say(&contact, "contact".into(), cx)),
},
)
.on_contact(move |_, cx| say(&contact, "contact".into(), cx)),
)
.into_any_element()
}
@@ -169,11 +179,10 @@ fn whats_new_lists_the_releases_and_got_it_closes(cx: &mut TestAppContext) {
}
fn feedback(_: &Bench, owner: Entity<Bench>) -> AnyElement {
FeedbackWidget::new("feedback")
.on_send(move |sentiment, note, _, cx| {
say(&owner, format!("{} {note}", sentiment.key()), cx)
})
.into_any_element()
FeedbackWidget::new("feedback", move |sentiment, note, _, cx| {
say(&owner, format!("{} {note}", sentiment.key()), cx)
})
.into_any_element()
}
/// Stops in the form: the four faces, the note, then Send once a face is picked.
@@ -207,11 +216,12 @@ fn support(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
Choice::new("billing", "Billing"),
Choice::new("bug", "Something broke"),
];
ContactSupport::new("support", topics)
.busy(bench.busy)
.address("help@example.com")
.on_send(move |topic, message, _, cx| say(&owner, format!("{topic}: {message}"), cx))
.into_any_element()
ContactSupport::new("support", topics, move |topic, message, _, cx| {
say(&owner, format!("{topic}: {message}"), cx)
})
.busy(bench.busy)
.address("help@example.com")
.into_any_element()
}
/// Stops: the topic, the message, then Send once both are given; the message empties once sent, with focus back in it.
@@ -261,11 +271,12 @@ fn long_address(_: &Bench, owner: Entity<Bench>) -> AnyElement {
div()
.w(px(280.0))
.child(
ContactSupport::new("support", [Choice::new("bug", "Something broke")])
.address("support-and-billing-questions@example-company.com")
.on_send(move |topic, message, _, cx| {
say(&owner, format!("{topic}: {message}"), cx)
}),
ContactSupport::new(
"support",
[Choice::new("bug", "Something broke")],
move |topic, message, _, cx| say(&owner, format!("{topic}: {message}"), cx),
)
.address("support-and-billing-questions@example-company.com"),
)
.into_any_element()
}
@@ -295,3 +306,40 @@ fn inline_help_offers_more(cx: &mut TestAppContext) {
tap("space", cx);
assert_eq!(said(&host, cx), ["more"]);
}
#[gpui::test]
fn an_article_that_left_draws(cx: &mut TestAppContext) {
let (host, cx) = bench(panel, cx);
host.update(cx, |bench, cx| {
bench.open = Some("gone".into());
cx.notify();
});
cx.run_until_parked();
}
/// Support topics, the second leaving once the bench hides it.
fn dynamic_topics(bench: &Bench, owner: Entity<Bench>) -> AnyElement {
let mut topics = vec![Choice::new("billing", "Billing")];
if !bench.hidden {
topics.push(Choice::new("bug", "Something broke"));
}
ContactSupport::new("support", topics, move |topic, message, _, cx| {
say(&owner, format!("{topic}: {message}"), cx)
})
.into_any_element()
}
#[gpui::test]
fn a_topic_that_left_sends_nothing(cx: &mut TestAppContext) {
let (host, cx) = bench(dynamic_topics, cx);
tab(1, cx);
for key in ["enter", "down", "enter"] {
tap(key, cx);
}
tab(2, cx);
write("It froze", cx);
edit(&host, cx, |bench| bench.hidden = true);
tab(3, cx);
tap("space", cx);
assert_eq!(said(&host, cx), Vec::<String>::new());
}