Panics · P33 Devtools: handlers in new; stale collection moves, environments and diagram tables change nothing
This commit is contained in:
1 parent
ffe4f38103
commit
05e846b62a
13 files changed
+220
-215
No files matched your search
+23
-11
@@ -85,7 +85,8 @@ fn placed(items: &mut Vec<Saved>, item: Saved, target: &str, at: DropAt) -> Resu
|
||||
(DropAt::After, _) => items.insert(ix + 1, item),
|
||||
(DropAt::Inside, Saved::Folder { items, .. }) => items.push(item),
|
||||
(DropAt::Inside, Saved::Request { key, .. }) => {
|
||||
panic!("collection: {key} is a request, and nothing goes inside it")
|
||||
log::error!("collection: {key} is a request, and nothing goes inside it");
|
||||
return Err(item);
|
||||
}
|
||||
}
|
||||
return Ok(());
|
||||
@@ -102,15 +103,19 @@ fn placed(items: &mut Vec<Saved>, item: Saved, target: &str, at: DropAt) -> Resu
|
||||
Err(item)
|
||||
}
|
||||
|
||||
/// `items` with `key` moved to `at` of `target`, as a drop in the tree asks.
|
||||
pub fn moved(items: &[Saved], key: &str, target: &str, at: DropAt) -> Vec<Saved> {
|
||||
/// `items` with `key` moved to `at` of `target`, as a drop in the tree asks; none, logged, when either left the items.
|
||||
pub fn moved(items: &[Saved], key: &str, target: &str, at: DropAt) -> Option<Vec<Saved>> {
|
||||
let mut items = items.to_vec();
|
||||
let item = taken(&mut items, key).unwrap_or_else(|| panic!("collection: no {key} to move"));
|
||||
let Some(item) = taken(&mut items, key) else {
|
||||
log::error!("collection: no {key} to move");
|
||||
return None;
|
||||
};
|
||||
if let Err(item) = placed(&mut items, item, target, at) {
|
||||
panic!("collection: no {target} to move {} beside", item.key());
|
||||
log::error!("collection: no {target} to move {} beside", item.key());
|
||||
return None;
|
||||
}
|
||||
log::info!("collection: moved {key} {at:?} {target}");
|
||||
items
|
||||
Some(items)
|
||||
}
|
||||
|
||||
type OnKey = Rc<dyn Fn(&SharedString, &mut Window, &mut App)>;
|
||||
@@ -236,25 +241,32 @@ mod tests {
|
||||
Saved::request("z", "Z", Method::Post),
|
||||
];
|
||||
assert_eq!(
|
||||
keys(&moved(&items, "x", "b", DropAt::Inside)),
|
||||
keys(&moved(&items, "x", "b", DropAt::Inside).expect("both are in the items")),
|
||||
["a[y]", "b[x]", "z"]
|
||||
);
|
||||
assert_eq!(
|
||||
keys(&moved(&items, "z", "a", DropAt::Inside)),
|
||||
keys(&moved(&items, "z", "a", DropAt::Inside).expect("both are in the items")),
|
||||
["a[x,y,z]", "b[]"],
|
||||
"a drop inside a folder lands last"
|
||||
);
|
||||
assert_eq!(
|
||||
keys(&moved(&items, "z", "x", DropAt::Before)),
|
||||
keys(&moved(&items, "z", "x", DropAt::Before).expect("both are in the items")),
|
||||
["a[z,x,y]", "b[]"]
|
||||
);
|
||||
assert_eq!(
|
||||
keys(&moved(&items, "x", "z", DropAt::After)),
|
||||
keys(&moved(&items, "x", "z", DropAt::After).expect("both are in the items")),
|
||||
["a[y]", "b[]", "z", "x"]
|
||||
);
|
||||
assert_eq!(
|
||||
keys(&moved(&items, "b", "a", DropAt::Before)),
|
||||
keys(&moved(&items, "b", "a", DropAt::Before).expect("both are in the items")),
|
||||
["b[]", "a[x,y]", "z"]
|
||||
);
|
||||
assert_eq!(moved(&items, "gone", "a", DropAt::Before), None);
|
||||
assert_eq!(moved(&items, "x", "gone", DropAt::Before), None);
|
||||
assert_eq!(
|
||||
moved(&items, "x", "z", DropAt::Inside),
|
||||
None,
|
||||
"a request holds nothing"
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ pub struct ColorContrastChecker {
|
||||
id: ElementId,
|
||||
text: Hsla,
|
||||
background: Hsla,
|
||||
on_change: Option<OnColors>,
|
||||
on_change: OnColors,
|
||||
}
|
||||
|
||||
impl ColorContrastChecker {
|
||||
@@ -72,23 +72,15 @@ impl ColorContrastChecker {
|
||||
id: impl Into<ElementId>,
|
||||
text: impl Into<Hsla>,
|
||||
background: impl Into<Hsla>,
|
||||
on_change: impl Fn(Hsla, Hsla, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: id.into(),
|
||||
text: text.into(),
|
||||
background: background.into(),
|
||||
on_change: None,
|
||||
on_change: Rc::new(on_change),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the text's and the background's colors after either changes.
|
||||
pub fn on_change(
|
||||
mut self,
|
||||
handler: impl Fn(Hsla, Hsla, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
self.on_change = Some(Rc::new(handler));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for ColorContrastChecker {
|
||||
@@ -99,9 +91,7 @@ impl RenderOnce for ColorContrastChecker {
|
||||
..background
|
||||
};
|
||||
let ratio = contrast(over(text, solid), solid);
|
||||
let on_change = self
|
||||
.on_change
|
||||
.unwrap_or_else(|| panic!("color contrast checker {:?} has no on_change", self.id));
|
||||
let on_change = self.on_change;
|
||||
let theme = cx.theme();
|
||||
let well = |name: &'static str, color: Hsla, set: OnColor| {
|
||||
div()
|
||||
|
||||
+69
-73
@@ -30,7 +30,7 @@ pub struct EnvironmentSelector {
|
||||
id: ElementId,
|
||||
environments: Vec<Environment>,
|
||||
selected: SharedString,
|
||||
on_change: Option<OnKey>,
|
||||
on_change: OnKey,
|
||||
}
|
||||
|
||||
impl EnvironmentSelector {
|
||||
@@ -38,22 +38,15 @@ impl EnvironmentSelector {
|
||||
id: impl Into<ElementId>,
|
||||
environments: impl IntoIterator<Item = Environment>,
|
||||
selected: impl Into<SharedString>,
|
||||
on_change: impl Fn(&SharedString, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: id.into(),
|
||||
environments: environments.into_iter().collect(),
|
||||
selected: selected.into(),
|
||||
on_change: None,
|
||||
on_change: Rc::new(on_change),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_change(
|
||||
mut self,
|
||||
handler: impl Fn(&SharedString, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
self.on_change = Some(Rc::new(handler));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// What a row shows for a value: dots for a secret until it is opened.
|
||||
@@ -84,71 +77,71 @@ impl RenderOnce for EnvironmentSelector {
|
||||
.environments
|
||||
.iter()
|
||||
.find(|environment| environment.key == self.selected)
|
||||
.unwrap_or_else(|| {
|
||||
panic!(
|
||||
"environment selector {id:?}: no environment {}",
|
||||
self.selected
|
||||
)
|
||||
})
|
||||
.clone();
|
||||
.cloned();
|
||||
if chosen.is_none() {
|
||||
log::error!(
|
||||
"environment selector {id:?}: no environment {}; none chosen",
|
||||
self.selected
|
||||
);
|
||||
}
|
||||
let shown = window.use_keyed_state((id.clone(), "shown"), cx, |_, _| Vec::<Secret>::new());
|
||||
let theme = cx.theme();
|
||||
let on_change = self
|
||||
.on_change
|
||||
.unwrap_or_else(|| panic!("environment selector {id:?} has no on_change"));
|
||||
let rows = chosen.variables.iter().map(|(name, value)| {
|
||||
let secret = chosen.secrets.contains(name);
|
||||
let key: Secret = (chosen.key.clone(), name.clone());
|
||||
let open = shown.read(cx).contains(&key);
|
||||
let flip = shown.clone();
|
||||
let seen = format!(
|
||||
"environment-{}-{name}-{}",
|
||||
chosen.key,
|
||||
if secret && !open { "masked" } else { "shown" }
|
||||
);
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_2()
|
||||
.py_1()
|
||||
.child(
|
||||
div()
|
||||
.flex_none()
|
||||
.w(theme.label_width())
|
||||
.font_family(theme.mono_family.clone())
|
||||
.text_size(theme.text_size(TextSize::Sm))
|
||||
.child(Ellipsis::new(format!("{{{{{name}}}}}"))),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.min_w_0()
|
||||
.text_size(theme.text_size(TextSize::Sm))
|
||||
.text_color(theme.colors.fg_muted)
|
||||
.debug_selector(move || seen)
|
||||
.child(Ellipsis::new(shown_value(value, secret, open))),
|
||||
)
|
||||
.children(secret.then(|| {
|
||||
IconButton::new(
|
||||
(id.clone(), format!("reveal-{name}")),
|
||||
if open {
|
||||
IconName::EyeOff
|
||||
} else {
|
||||
IconName::Eye
|
||||
},
|
||||
let on_change = self.on_change;
|
||||
let rows = chosen.iter().flat_map(|chosen| {
|
||||
chosen.variables.iter().map(|(name, value)| {
|
||||
let secret = chosen.secrets.contains(name);
|
||||
let key: Secret = (chosen.key.clone(), name.clone());
|
||||
let open = shown.read(cx).contains(&key);
|
||||
let flip = shown.clone();
|
||||
let seen = format!(
|
||||
"environment-{}-{name}-{}",
|
||||
chosen.key,
|
||||
if secret && !open { "masked" } else { "shown" }
|
||||
);
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_2()
|
||||
.py_1()
|
||||
.child(
|
||||
div()
|
||||
.flex_none()
|
||||
.w(theme.label_width())
|
||||
.font_family(theme.mono_family.clone())
|
||||
.text_size(theme.text_size(TextSize::Sm))
|
||||
.child(Ellipsis::new(format!("{{{{{name}}}}}"))),
|
||||
)
|
||||
.tooltip(if open {
|
||||
"Hide the value"
|
||||
} else {
|
||||
"Show the value"
|
||||
})
|
||||
.on_click(move |_, _, cx| {
|
||||
flip.update(cx, |shown, cx| {
|
||||
flipped(shown, &key);
|
||||
cx.notify();
|
||||
.child(
|
||||
div()
|
||||
.flex_1()
|
||||
.min_w_0()
|
||||
.text_size(theme.text_size(TextSize::Sm))
|
||||
.text_color(theme.colors.fg_muted)
|
||||
.debug_selector(move || seen)
|
||||
.child(Ellipsis::new(shown_value(value, secret, open))),
|
||||
)
|
||||
.children(secret.then(|| {
|
||||
IconButton::new(
|
||||
(id.clone(), format!("reveal-{name}")),
|
||||
if open {
|
||||
IconName::EyeOff
|
||||
} else {
|
||||
IconName::Eye
|
||||
},
|
||||
)
|
||||
.tooltip(if open {
|
||||
"Hide the value"
|
||||
} else {
|
||||
"Show the value"
|
||||
})
|
||||
})
|
||||
}))
|
||||
.on_click(move |_, _, cx| {
|
||||
flip.update(cx, |shown, cx| {
|
||||
flipped(shown, &key);
|
||||
cx.notify();
|
||||
})
|
||||
})
|
||||
}))
|
||||
})
|
||||
});
|
||||
div()
|
||||
.flex()
|
||||
@@ -161,7 +154,7 @@ impl RenderOnce for EnvironmentSelector {
|
||||
Choice::new(environment.key.clone(), environment.name.clone())
|
||||
}),
|
||||
)
|
||||
.selected(chosen.key.clone())
|
||||
.selected(self.selected.clone())
|
||||
.on_change(move |key, window, cx| {
|
||||
log::info!("environment selector: {key}");
|
||||
on_change(key, window, cx);
|
||||
@@ -172,7 +165,10 @@ impl RenderOnce for EnvironmentSelector {
|
||||
.text_size(theme.text_size(TextSize::Xs))
|
||||
.text_color(theme.colors.fg_subtle)
|
||||
.font_weight(FontWeight::MEDIUM)
|
||||
.child(format!("{} variables", chosen.variables.len())),
|
||||
.child(match &chosen {
|
||||
Some(chosen) => format!("{} variables", chosen.variables.len()),
|
||||
None => "No environment chosen".into(),
|
||||
}),
|
||||
)
|
||||
.child(div().flex().flex_col().children(rows))
|
||||
}
|
||||
|
||||
+4
-13
@@ -57,7 +57,7 @@ pub struct GraphQLExplorer {
|
||||
answer: Option<SharedString>,
|
||||
search: Entity<TextInput>,
|
||||
running: bool,
|
||||
on_run: Option<OnRun>,
|
||||
on_run: OnRun,
|
||||
on_pick: Option<OnKey>,
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ impl GraphQLExplorer {
|
||||
query: &Entity<CodeEditor>,
|
||||
variables: &Entity<CodeEditor>,
|
||||
search: &Entity<TextInput>,
|
||||
on_run: impl Fn(String, String, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: id.into(),
|
||||
@@ -78,7 +79,7 @@ impl GraphQLExplorer {
|
||||
answer: None,
|
||||
search: search.clone(),
|
||||
running: false,
|
||||
on_run: None,
|
||||
on_run: Rc::new(on_run),
|
||||
on_pick: None,
|
||||
}
|
||||
}
|
||||
@@ -94,14 +95,6 @@ impl GraphQLExplorer {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_run(
|
||||
mut self,
|
||||
handler: impl Fn(String, String, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
self.on_run = Some(Rc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_pick(
|
||||
mut self,
|
||||
handler: impl Fn(&SharedString, &mut Window, &mut App) + 'static,
|
||||
@@ -149,9 +142,7 @@ impl RenderOnce for GraphQLExplorer {
|
||||
.child(text)
|
||||
};
|
||||
let tall = theme.list_max_height();
|
||||
let on_run = self
|
||||
.on_run
|
||||
.unwrap_or_else(|| panic!("graphql explorer {id:?} has no on_run"));
|
||||
let on_run = self.on_run;
|
||||
let (query, variables) = (self.query.clone(), self.variables.clone());
|
||||
let typed = variables.read(cx).text().to_string();
|
||||
let unread = (!typed.trim().is_empty())
|
||||
|
||||
+11
-11
@@ -245,19 +245,19 @@ pub(crate) fn diagram(
|
||||
) -> (Vec<Node>, Vec<Edge>) {
|
||||
let nodes = tables
|
||||
.iter()
|
||||
.map(|table| {
|
||||
let at = places
|
||||
.iter()
|
||||
.find(|(name, _)| *name == table.name)
|
||||
.unwrap_or_else(|| panic!("ER diagram: no place for {}", table.name))
|
||||
.1;
|
||||
table.fields.iter().fold(
|
||||
.filter_map(|table| {
|
||||
let Some((_, at)) = places.iter().find(|(name, _)| *name == table.name) else {
|
||||
log::error!("ER diagram: no place for {}; left out", table.name);
|
||||
return None;
|
||||
};
|
||||
let at = *at;
|
||||
Some(table.fields.iter().fold(
|
||||
Node::new(table.name.clone(), table.name.clone(), at),
|
||||
|node, field| {
|
||||
node.input(Port::new(field.name.clone(), field.name.clone(), "field"))
|
||||
.output(Port::new(field.name.clone(), field.typed(), "field"))
|
||||
},
|
||||
)
|
||||
))
|
||||
})
|
||||
.collect();
|
||||
let edges = tables
|
||||
@@ -337,8 +337,8 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "no place for orders")]
|
||||
fn a_table_without_a_place_fails_loud() {
|
||||
diagram(&[DbTable::new("orders", [])], &[]);
|
||||
fn a_table_without_a_place_is_left_out() {
|
||||
let (nodes, edges) = diagram(&[DbTable::new("orders", [])], &[]);
|
||||
assert!(nodes.is_empty() && edges.is_empty());
|
||||
}
|
||||
}
|
||||
+4
-14
@@ -53,7 +53,7 @@ pub struct WebSocketConsole {
|
||||
messages: Vec<SocketMessage>,
|
||||
draft: Entity<TextInput>,
|
||||
now: Timestamp,
|
||||
on_send: Option<OnText>,
|
||||
on_send: OnText,
|
||||
on_toggle: Option<Run>,
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ impl WebSocketConsole {
|
||||
messages: impl IntoIterator<Item = SocketMessage>,
|
||||
draft: &Entity<TextInput>,
|
||||
now: Timestamp,
|
||||
on_send: impl Fn(SharedString, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: id.into(),
|
||||
@@ -74,20 +75,11 @@ impl WebSocketConsole {
|
||||
messages: messages.into_iter().collect(),
|
||||
draft: draft.clone(),
|
||||
now,
|
||||
on_send: None,
|
||||
on_send: Rc::new(on_send),
|
||||
on_toggle: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the text to send; the field empties after.
|
||||
pub fn on_send(
|
||||
mut self,
|
||||
handler: impl Fn(SharedString, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
self.on_send = Some(Rc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
/// Asked to connect while closed, or to disconnect while open.
|
||||
pub fn on_toggle(mut self, handler: impl Fn(&mut Window, &mut App) + 'static) -> Self {
|
||||
self.on_toggle = Some(Rc::new(handler));
|
||||
@@ -159,9 +151,7 @@ impl RenderOnce for WebSocketConsole {
|
||||
};
|
||||
let open = self.state == SocketState::Open;
|
||||
let (messages, now) = (Rc::new(self.messages), self.now);
|
||||
let on_send = self
|
||||
.on_send
|
||||
.unwrap_or_else(|| panic!("websocket console {:?} has no on_send", self.id));
|
||||
let on_send = self.on_send;
|
||||
let draft = self.draft.clone();
|
||||
let ready = open && !draft.read(cx).text().trim().is_empty();
|
||||
let send = Rc::new(move |window: &mut Window, cx: &mut App| {
|
||||
|
||||
+16
-33
@@ -100,32 +100,26 @@ struct Room(f32);
|
||||
pub struct TableStructureEditor {
|
||||
id: ElementId,
|
||||
fields: Vec<Field>,
|
||||
on_change: Option<OnEdit<Vec<Field>>>,
|
||||
on_change: OnEdit<Vec<Field>>,
|
||||
}
|
||||
|
||||
impl TableStructureEditor {
|
||||
pub fn new(id: impl Into<ElementId>, fields: impl IntoIterator<Item = Field>) -> Self {
|
||||
pub fn new(
|
||||
id: impl Into<ElementId>,
|
||||
fields: impl IntoIterator<Item = Field>,
|
||||
on_change: impl Fn(Vec<Field>, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: id.into(),
|
||||
fields: fields.into_iter().collect(),
|
||||
on_change: None,
|
||||
on_change: Rc::new(on_change),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_change(
|
||||
mut self,
|
||||
handler: impl Fn(Vec<Field>, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
self.on_change = Some(Rc::new(handler));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for TableStructureEditor {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let on_change = self
|
||||
.on_change
|
||||
.unwrap_or_else(|| panic!("table structure editor {:?} has no on_change", self.id));
|
||||
let on_change = self.on_change;
|
||||
let (id, fields, on_change) = (self.id, self.fields, &on_change);
|
||||
let room = window.use_keyed_state((id.clone(), "room"), cx, |_, _| Room::default());
|
||||
let rem = window.rem_size();
|
||||
@@ -303,8 +297,8 @@ pub struct IndexManager {
|
||||
id: ElementId,
|
||||
indexes: Vec<Index>,
|
||||
fields: Vec<SharedString>,
|
||||
on_drop: Option<OnName>,
|
||||
on_create: Option<OnIndex>,
|
||||
on_drop: OnName,
|
||||
on_create: OnIndex,
|
||||
}
|
||||
|
||||
impl IndexManager {
|
||||
@@ -313,34 +307,23 @@ impl IndexManager {
|
||||
id: impl Into<ElementId>,
|
||||
indexes: impl IntoIterator<Item = Index>,
|
||||
fields: impl IntoIterator<Item = impl Into<SharedString>>,
|
||||
on_create: impl Fn(Index, &mut Window, &mut App) + 'static,
|
||||
on_drop: impl Fn(&SharedString, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: id.into(),
|
||||
indexes: indexes.into_iter().collect(),
|
||||
fields: fields.into_iter().map(Into::into).collect(),
|
||||
on_drop: None,
|
||||
on_create: None,
|
||||
on_drop: Rc::new(on_drop),
|
||||
on_create: Rc::new(on_create),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_drop(
|
||||
mut self,
|
||||
handler: impl Fn(&SharedString, &mut Window, &mut App) + 'static,
|
||||
) -> Self {
|
||||
self.on_drop = Some(Rc::new(handler));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_create(mut self, handler: impl Fn(Index, &mut Window, &mut App) + 'static) -> Self {
|
||||
self.on_create = Some(Rc::new(handler));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl RenderOnce for IndexManager {
|
||||
fn render(self, window: &mut Window, cx: &mut App) -> impl IntoElement {
|
||||
let on_create = self.on_create.expect("an index manager needs on_create");
|
||||
let on_drop = self.on_drop.expect("an index manager needs on_drop");
|
||||
let on_create = self.on_create;
|
||||
let on_drop = self.on_drop;
|
||||
let id = self.id;
|
||||
let draft = window.use_keyed_state((id.clone(), "draft"), cx, |window, cx| Draft {
|
||||
name: cx.new(|cx| TextInput::new(window, cx).placeholder("Index name")),
|
||||
|
||||
+54
-17
@@ -100,10 +100,17 @@ fn console(bench: &Bench, window: &mut Window, cx: &mut App, owner: Entity<Bench
|
||||
_ => SocketState::Closed,
|
||||
};
|
||||
let toggled = owner.clone();
|
||||
WebSocketConsole::new("socket", "wss://example.com", state, [], &draft, now)
|
||||
.on_send(move |text, _, cx| say(&owner, format!("send {text}"), cx))
|
||||
.on_toggle(move |_, cx| say(&toggled, "toggle".into(), cx))
|
||||
.into_any_element()
|
||||
WebSocketConsole::new(
|
||||
"socket",
|
||||
"wss://example.com",
|
||||
state,
|
||||
[],
|
||||
&draft,
|
||||
now,
|
||||
move |text, _, cx| say(&owner, format!("send {text}"), cx),
|
||||
)
|
||||
.on_toggle(move |_, cx| say(&toggled, "toggle".into(), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: Disconnect, the message field, then Send once it holds words.
|
||||
@@ -179,9 +186,15 @@ fn graph(bench: &Bench, window: &mut Window, cx: &mut App, owner: Entity<Bench>)
|
||||
return div().into_any_element();
|
||||
};
|
||||
let search = window.use_keyed_state("search", cx, TextInput::new);
|
||||
GraphQLExplorer::new("graph", [], &query, &variables, &search)
|
||||
.on_run(move |query, variables, _, cx| say(&owner, format!("{query} {variables}"), cx))
|
||||
.into_any_element()
|
||||
GraphQLExplorer::new(
|
||||
"graph",
|
||||
[],
|
||||
&query,
|
||||
&variables,
|
||||
&search,
|
||||
move |query, variables, _, cx| say(&owner, format!("{query} {variables}"), cx),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: the schema, the query, the variables, then Run while they read.
|
||||
@@ -216,10 +229,10 @@ fn environments(bench: &Bench, _: &mut Window, _: &mut App, _: Entity<Bench>) ->
|
||||
variables: vec![("token".into(), token.to_string().into())],
|
||||
secrets: vec!["token".into()],
|
||||
};
|
||||
let selected = if bench.choice == 0 {
|
||||
"staging"
|
||||
} else {
|
||||
"production"
|
||||
let selected = match bench.choice {
|
||||
0 => "staging",
|
||||
1 => "production",
|
||||
_ => "gone",
|
||||
};
|
||||
EnvironmentSelector::new(
|
||||
"environments",
|
||||
@@ -228,8 +241,8 @@ fn environments(bench: &Bench, _: &mut Window, _: &mut App, _: Entity<Bench>) ->
|
||||
env("production", "sk_live_9999"),
|
||||
],
|
||||
selected,
|
||||
|_, _, _| {},
|
||||
)
|
||||
.on_change(|_, _, _| {})
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
@@ -265,10 +278,16 @@ fn schema(_: &Bench, window: &mut Window, cx: &mut App, owner: Entity<Bench>) ->
|
||||
kind: TypeKind::Object,
|
||||
fields: vec![("id".into(), "ID!".into())],
|
||||
};
|
||||
GraphQLExplorer::new("graph", [order], &query, &variables, &search)
|
||||
.on_run(|_, _, _, _| {})
|
||||
.on_pick(move |path, _, cx| say(&owner, path.to_string(), cx))
|
||||
.into_any_element()
|
||||
GraphQLExplorer::new(
|
||||
"graph",
|
||||
[order],
|
||||
&query,
|
||||
&variables,
|
||||
&search,
|
||||
|_, _, _, _| {},
|
||||
)
|
||||
.on_pick(move |path, _, cx| say(&owner, path.to_string(), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// Stops: the schema first, its cursor on Order.
|
||||
@@ -297,8 +316,8 @@ fn log(_: &Bench, window: &mut Window, cx: &mut App, owner: Entity<Bench>) -> An
|
||||
messages,
|
||||
&draft,
|
||||
now,
|
||||
move |text, _, cx| say(&owner, format!("send {text}"), cx),
|
||||
)
|
||||
.on_send(move |text, _, cx| say(&owner, format!("send {text}"), cx))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
@@ -314,3 +333,21 @@ fn the_log_holds_at_its_newest_message(cx: &mut TestAppContext) {
|
||||
"the newest message lies inside the log: {newest:?} in {log:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn an_environment_that_left_shows_none_chosen(cx: &mut TestAppContext) {
|
||||
let (host, cx) = bench(environments, cx);
|
||||
host.update(cx, |bench, cx| {
|
||||
bench.choice = 2;
|
||||
cx.notify();
|
||||
});
|
||||
settle(cx);
|
||||
assert!(
|
||||
cx.debug_bounds("environment-staging-token-masked")
|
||||
.is_none()
|
||||
);
|
||||
assert!(
|
||||
cx.debug_bounds("environment-production-token-masked")
|
||||
.is_none()
|
||||
);
|
||||
}
|
||||
+15
-14
@@ -107,15 +107,18 @@ fn enter_opens_a_connection_and_a_rows_button_leaves_the_row_alone(cx: &mut Test
|
||||
}
|
||||
|
||||
fn structure(_: &Bench, _: &mut Window, _: &mut App, owner: Entity<Bench>) -> AnyElement {
|
||||
TableStructureEditor::new("structure", [Field::new("id", "int").primary()])
|
||||
.on_change(move |fields, _, cx| {
|
||||
TableStructureEditor::new(
|
||||
"structure",
|
||||
[Field::new("id", "int").primary()],
|
||||
move |fields, _, cx| {
|
||||
let names: Vec<String> = fields
|
||||
.iter()
|
||||
.map(|field| format!("{}:{}", field.name, field.ty))
|
||||
.collect();
|
||||
say(&owner, names.join(" "), cx)
|
||||
})
|
||||
.into_any_element()
|
||||
},
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
/// A row's stops: name, type, empty, key, default and remove; Add field comes after.
|
||||
@@ -204,16 +207,14 @@ fn another_engine_brings_its_port(cx: &mut TestAppContext) {
|
||||
fn narrow(_: &Bench, _: &mut Window, _: &mut App, _: Entity<Bench>) -> AnyElement {
|
||||
div()
|
||||
.w(px(280.0))
|
||||
.child(
|
||||
TableStructureEditor::new(
|
||||
"structure",
|
||||
[
|
||||
Field::new("user_id", "timestamptz"),
|
||||
Field::new("total", "numeric"),
|
||||
],
|
||||
)
|
||||
.on_change(|_, _, _| {}),
|
||||
)
|
||||
.child(TableStructureEditor::new(
|
||||
"structure",
|
||||
[
|
||||
Field::new("user_id", "timestamptz"),
|
||||
Field::new("total", "numeric"),
|
||||
],
|
||||
|_, _, _| {},
|
||||
))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user