Description rows wrap; the fine-tune share is tested
A DescriptionList row drops its value under its label once the value has less than half a label's width beside it, so a 280px model card no longer breaks its facts mid-word. FineTuneJobCard's bar share and its epoch line move into tuning::progress, with a test.
This commit is contained in:
1 parent
ff4e828795
commit
7c6b4c883d
4 files changed
+83
-10
No files matched your search
@@ -299,3 +299,4 @@ Per-component lines live in `tasks/`. Tags there:
|
|||||||
| T25c | 2 | PASS | |
|
| T25c | 2 | PASS | |
|
||||||
| T25d | 1 | FAIL | the timeline's strip never scrolled, its child stretched to the box; a focused shot past the edge stayed hidden; many voice tags ran past a 280px row |
|
| T25d | 1 | FAIL | the timeline's strip never scrolled, its child stretched to the box; a focused shot past the edge stayed hidden; many voice tags ran past a 280px row |
|
||||||
| T25d | 2 | PASS | |
|
| T25d | 2 | PASS | |
|
||||||
|
| T25e | 1 | FAIL | a description row never wrapped, so a 280px model card broke its facts mid-word; the fine-tune bar's share had no test |
|
||||||
@@ -9,7 +9,7 @@ use crate::{
|
|||||||
theme::{ActiveTheme, ControlSize, TextSize},
|
theme::{ActiveTheme, ControlSize, TextSize},
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Labels and their values, one pair a row with the labels in a quiet column, or stacked with each label above its value.
|
/// Labels and their values, one pair a row with the labels in a quiet column, or stacked with each label above its value. A value short of room drops under its label.
|
||||||
#[derive(IntoElement, Default)]
|
#[derive(IntoElement, Default)]
|
||||||
pub struct DescriptionList {
|
pub struct DescriptionList {
|
||||||
items: Vec<(SharedString, AnyElement)>,
|
items: Vec<(SharedString, AnyElement)>,
|
||||||
@@ -59,7 +59,9 @@ impl RenderOnce for DescriptionList {
|
|||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
.when(stacked, |row| row.flex_col().gap_0p5())
|
.when(stacked, |row| row.flex_col().gap_0p5())
|
||||||
.when(!stacked, |row| row.items_baseline().gap_4())
|
.when(!stacked, |row| {
|
||||||
|
row.flex_wrap().items_baseline().gap_x_4().gap_y_0p5()
|
||||||
|
})
|
||||||
.py_2()
|
.py_2()
|
||||||
.when(lined && ix < last, |row| {
|
.when(lined && ix < last, |row| {
|
||||||
row.border_b_1().border_color(colors.border)
|
row.border_b_1().border_color(colors.border)
|
||||||
@@ -73,7 +75,8 @@ impl RenderOnce for DescriptionList {
|
|||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
.flex_1()
|
.flex_1()
|
||||||
.min_w_0()
|
.when(stacked, |value| value.min_w_0())
|
||||||
|
.when(!stacked, |value| value.min_w(theme.label_width() * 0.5))
|
||||||
.text_color(colors.fg)
|
.text_color(colors.fg)
|
||||||
.child(div().min_w_0().child(value)),
|
.child(div().min_w_0().child(value)),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
Context, IntoElement, Modifiers, ParentElement, Pixels, Render, Styled, TestAppContext,
|
Bounds, Context, IntoElement, Modifiers, ParentElement, Pixels, Render, Styled, TestAppContext,
|
||||||
VisualTestContext, Window, div, point, px,
|
VisualTestContext, Window, div, point, px,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{Carousel, PropertyGrid, PropertyGroup};
|
use super::{Carousel, DescriptionList, PropertyGrid, PropertyGroup};
|
||||||
use crate::{primitives::Measure, theme::Theme};
|
use crate::{primitives::Measure, theme::Theme};
|
||||||
|
|
||||||
/// A property grid whose drawn height the test reads.
|
/// A property grid whose drawn height the test reads.
|
||||||
@@ -68,6 +68,54 @@ fn a_property_group_folds_from_its_header_and_stays_folded(cx: &mut TestAppConte
|
|||||||
assert_eq!(height.get(), open, "a second press opens it");
|
assert_eq!(height.get(), open, "a second press opens it");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A one-row description list, this wide, that reports where the list and its value sit.
|
||||||
|
struct Facts(Pixels, Rc<Cell<[Bounds<Pixels>; 2]>>);
|
||||||
|
|
||||||
|
impl Render for Facts {
|
||||||
|
fn render(&mut self, _: &mut Window, _: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
let (list, value) = (self.1.clone(), self.1.clone());
|
||||||
|
let value = Measure::new("value", move |bounds, _, _| {
|
||||||
|
value.set([value.get()[0], bounds])
|
||||||
|
})
|
||||||
|
.child("Apache-2.0");
|
||||||
|
div().w(self.0).child(
|
||||||
|
Measure::new("list", move |bounds, _, _| {
|
||||||
|
list.set([bounds, list.get()[1]])
|
||||||
|
})
|
||||||
|
.child(DescriptionList::new().item("License", value)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
fn a_value_drops_below_its_label_when_the_row_runs_short(cx: &mut TestAppContext) {
|
||||||
|
cx.update(Theme::init);
|
||||||
|
let mut place = |width: f32| {
|
||||||
|
let seen = Rc::new(Cell::new([Bounds::default(); 2]));
|
||||||
|
let shared = seen.clone();
|
||||||
|
let (_, cx) = cx.add_window_view(move |_, _| Facts(px(width), shared));
|
||||||
|
settle(cx);
|
||||||
|
let [list, value] = seen.get();
|
||||||
|
(value.left() - list.left(), value.top() - list.top())
|
||||||
|
};
|
||||||
|
let (wide_left, wide_top) = place(400.0);
|
||||||
|
let (narrow_left, narrow_top) = place(240.0);
|
||||||
|
assert_eq!(
|
||||||
|
wide_left,
|
||||||
|
px(176.0),
|
||||||
|
"wide, the value sits beside its label"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
narrow_left,
|
||||||
|
Pixels::ZERO,
|
||||||
|
"narrow, the value starts under its label"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
narrow_top > wide_top,
|
||||||
|
"and a line lower: {wide_top:?} to {narrow_top:?}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/// A three-slide carousel, 200 wide, that turns every five seconds; each slide reports where it sits.
|
/// A three-slide carousel, 200 wide, that turns every five seconds; each slide reports where it sits.
|
||||||
struct Deck(Rc<RefCell<[Pixels; 3]>>);
|
struct Deck(Rc<RefCell<[Pixels; 3]>>);
|
||||||
|
|
||||||
|
|||||||
@@ -39,6 +39,16 @@ impl TunePhase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A running job's bar, whole epochs and the share of the one under way, and the line under it.
|
||||||
|
pub(crate) fn progress(epoch: usize, epochs: usize, share: f32) -> (f32, String) {
|
||||||
|
let whole = ((epoch - 1) as f32 + share) / epochs as f32;
|
||||||
|
let line = format!(
|
||||||
|
"Epoch {epoch} of {epochs} · {}",
|
||||||
|
percent(f64::from(share), 0, false)
|
||||||
|
);
|
||||||
|
(whole, line)
|
||||||
|
}
|
||||||
|
|
||||||
/// A fine-tuning job: its name, the base model and data it learns from, where it stands, how far it has come by epoch, and its loss on training and held-out data. Cancel while it waits or trains; Open once done.
|
/// A fine-tuning job: its name, the base model and data it learns from, where it stands, how far it has come by epoch, and its loss on training and held-out data. Cancel while it waits or trains; Open once done.
|
||||||
#[derive(IntoElement)]
|
#[derive(IntoElement)]
|
||||||
pub struct FineTuneJobCard {
|
pub struct FineTuneJobCard {
|
||||||
@@ -128,7 +138,7 @@ impl RenderOnce for FineTuneJobCard {
|
|||||||
};
|
};
|
||||||
let progress = match &self.phase {
|
let progress = match &self.phase {
|
||||||
TunePhase::Running(epoch, epochs, share) => {
|
TunePhase::Running(epoch, epochs, share) => {
|
||||||
let whole = ((*epoch - 1) as f32 + share) / *epochs as f32;
|
let (whole, line) = progress(*epoch, *epochs, *share);
|
||||||
Some(
|
Some(
|
||||||
div()
|
div()
|
||||||
.flex()
|
.flex()
|
||||||
@@ -143,10 +153,7 @@ impl RenderOnce for FineTuneJobCard {
|
|||||||
tabular(div())
|
tabular(div())
|
||||||
.text_size(theme.text_size(TextSize::Xs))
|
.text_size(theme.text_size(TextSize::Xs))
|
||||||
.text_color(colors.fg_muted)
|
.text_color(colors.fg_muted)
|
||||||
.child(format!(
|
.child(line),
|
||||||
"Epoch {epoch} of {epochs} · {}",
|
|
||||||
percent(f64::from(*share), 0, false)
|
|
||||||
)),
|
|
||||||
)
|
)
|
||||||
.into_any_element(),
|
.into_any_element(),
|
||||||
)
|
)
|
||||||
@@ -228,3 +235,17 @@ impl RenderOnce for FineTuneJobCard {
|
|||||||
.children(chart)
|
.children(chart)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::progress;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn the_bar_counts_whole_epochs_and_the_share_of_the_one_under_way() {
|
||||||
|
let (whole, line) = progress(2, 3, 0.64);
|
||||||
|
assert!((whole - 0.5467).abs() < 1e-4, "{whole}");
|
||||||
|
assert_eq!(line, "Epoch 2 of 3 · 64%");
|
||||||
|
assert_eq!(progress(1, 1, 0.5), (0.5, "Epoch 1 of 1 · 50%".to_string()));
|
||||||
|
assert_eq!(progress(3, 3, 1.0).0, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user