use ratatui::Terminal;
use ratatui::backend::TestBackend;
use ratatui::layout::Rect;
use ratatui::text::Line;
use super::super::super::app::App;
use super::super::super::pane::{ConfigPane, PaneRow};
use super::super::fixtures;
use super::draw::pane_lines;
use crate::lookout::frames::render_text;
pub(super) fn web_pane() -> ConfigPane {
ConfigPane::sheep(fixtures::sheep_config_view())
}
pub(super) fn text_of(lines: &[Line<'static>]) -> Vec<String> {
lines
.iter()
.map(|line| {
line.spans
.iter()
.map(|span| span.content.as_ref())
.collect()
})
.collect()
}
pub(super) fn secret_array_dog_pane() -> ConfigPane {
let schema = serde_json::json!({
"properties": {
"tokens": {
"type": "array",
"items": { "type": "string" },
"x-shep-secret": true,
}
}
});
let mut pane = ConfigPane::dog(
"watch".into(),
None,
schema,
"tokens = [\"ab12cd34\", \"ef56gh78\"]\n".into(),
);
pane.move_to_key("tokens");
pane
}
pub(super) fn nested_secret_dog_pane() -> ConfigPane {
let schema = serde_json::json!({
"properties": { "db": { "$ref": "#/$defs/Db" } },
"$defs": {
"Db": {
"type": "object",
"properties": {
"host": { "type": "string" },
"password": { "type": "string", "x-shep-secret": true },
},
},
},
});
let mut pane = ConfigPane::dog(
"watch".into(),
None,
schema,
"[db]\nhost = \"pg.internal\"\npassword = \"ab12cd34\"\n".into(),
);
pane.move_to_key("db.password");
pane
}
pub(super) fn opaque_secret_dog_pane() -> ConfigPane {
let schema = serde_json::json!({
"properties": { "hosts": { "type": "array", "items": { "$ref": "#/$defs/Host" } } },
"$defs": {
"Host": {
"type": "object",
"properties": {
"name": { "type": "string" },
"key": { "type": "string", "x-shep-secret": true },
},
},
},
});
let mut pane = ConfigPane::dog(
"watch".into(),
None,
schema,
"[[hosts]]\nname = \"a\"\nkey = \"ab12cd34\"\n".into(),
);
pane.move_to_key("hosts");
pane
}
pub(super) fn secret_dog_pane_with_an_edit() -> ConfigPane {
let schema = serde_json::json!({
"properties": {
"token": {
"type": "string",
"x-shep-secret": true,
}
}
});
let mut pane = ConfigPane::dog(
"watch".into(),
None,
schema,
"token = \"ab12cd34\"\n".into(),
);
pane.move_to_key("token");
pane.begin_typing();
for c in "ef56gh78".chars() {
pane.type_char(c);
}
assert!(
pane.apply_typing().is_none(),
"the fixture must type a value the field takes"
);
pane
}
pub(super) fn web_with_args(args: &[&str]) -> shep_core::protocol::SheepConfigView {
let config = shep_core::config::AppConfig {
name: "web".to_string(),
args: args.iter().map(|arg| (*arg).to_string()).collect(),
..Default::default()
};
shep_core::protocol::SheepConfigView::new(config, Vec::new(), Vec::new())
}
pub(super) fn pane_to(app: &mut App, key: &str) {
fixtures::select_field(app, key);
}
pub(super) fn screen_at(app: &mut App, height: u16) -> String {
screen_of(app, 120, height)
}
pub(super) fn screen_of(app: &mut App, width: u16, height: u16) -> String {
let area = Rect::new(0, 0, width, height);
app.note_body_rows(super::super::body_rows(area));
app.note_body_width(width);
let mut terminal = Terminal::new(TestBackend::new(width, height)).unwrap();
terminal
.draw(|frame| super::super::draw(app, frame))
.unwrap();
render_text(terminal.backend().buffer())
}
pub(super) fn marked(text: &str) -> usize {
text.lines().filter(|line| line.starts_with('>')).count()
}
pub(super) fn blurb_anchor(pane: &ConfigPane) -> String {
let help = field_help_under_cursor(pane);
help.split_whitespace()
.max_by_key(|word| word.len())
.expect("the field help is empty")
.to_owned()
}
pub(super) fn field_help_under_cursor(pane: &ConfigPane) -> String {
let Some(PaneRow::Field(index)) = pane.cursor() else {
panic!("the cursor is not on a field");
};
pane.fields().fields()[index].help.clone()
}
pub(super) fn bark_pane() -> ConfigPane {
let schema = crate::dog::builtin_schema("bark").expect("bark is a built-in");
ConfigPane::dog(
"bark".into(),
None,
schema,
"poll = \"60s\"\nhistory_bytes = 4096\n\n[sinks.ops]\nkind = \"slack\"\nurl = \"https://hooks.example/x\"\n"
.into(),
)
}
pub(super) fn nested_table_dog_pane() -> ConfigPane {
ConfigPane::dog(
"jobs".into(),
None,
fixtures::nested_dog_schema(),
fixtures::nested_dog_section(),
)
}
pub(super) fn nested_sheep_dog_pane() -> ConfigPane {
let table = serde_json::json!({
"name": "small",
"models": { "worker": { "model": "gpt", "token": "sk-live-51Hx9Qa" } },
});
ConfigPane::sheep_dog(
"web".into(),
"jobs".into(),
&fixtures::nested_dog_schema(),
table.as_object().cloned().expect("a table"),
)
}
pub(super) fn config_pane_lines_for_tests(
app: &App,
width: u16,
height: u16,
) -> Vec<Line<'static>> {
let pane = app.config_pane().expect("the pane is open");
pane_lines(pane, fixtures::plain(), width, height)
}