use crate::AppModel;
use crate::cli_outbound::Cli;
use crate::delete::Confirmation;
use crate::theme;
use std::path::{Path, PathBuf};
use super::ShellState;
#[derive(Default)]
pub struct DeleteState {
pub target: Option<PathBuf>,
pub typed: String,
pub error: String,
}
pub(super) fn open(state: &mut ShellState, ws: &Path) {
state.delete = DeleteState {
target: Some(ws.to_path_buf()),
..DeleteState::default()
};
}
pub(super) fn danger_row(ui: &mut egui::Ui, model: &AppModel, state: &mut ShellState) {
let Some(ws) = model.focused_workspace().map(Path::to_path_buf) else {
return;
};
if model.delete_confirmation(&ws).is_none() {
return;
}
if ui
.button(egui::RichText::new("delete this workspace…").color(theme::ICHOR))
.on_hover_text(
"takes the sphere wall down — irrecoverable. Typed, it is \
`/delete-workspace <typed name>`.",
)
.clicked()
{
open(state, &ws);
}
}
pub(super) fn dialog(
ctx: &egui::Context,
model: &mut AppModel,
state: &mut ShellState,
lernie: &Cli,
bl: &Cli,
) {
if state.delete.target.is_none() {
return;
}
window(ctx, model, state, lernie, bl);
if state.delete.target.is_none() {
super::focus::request(state);
}
}
fn window(
ctx: &egui::Context,
model: &mut AppModel,
state: &mut ShellState,
lernie: &Cli,
bl: &Cli,
) {
let Some(ws) = state.delete.target.clone() else {
return;
};
let Some(confirm) = model.delete_confirmation(&ws) else {
state.delete = DeleteState::default();
return;
};
let mut shown = true;
egui::Window::new(format!("delete workspace {}", confirm.name))
.collapsible(false)
.resizable(false)
.open(&mut shown)
.show(ctx, |ui| body(ui, model, state, lernie, bl, &confirm));
if !shown {
state.delete = DeleteState::default();
}
}
fn body(
ui: &mut egui::Ui,
model: &mut AppModel,
state: &mut ShellState,
lernie: &Cli,
bl: &Cli,
confirm: &Confirmation,
) {
ui.colored_label(
theme::ICHOR,
"this destroys the workspace and everything inside it — irrecoverably",
);
ui.label("conversations that die:");
enumerate(ui, &confirm.conversations, "(none)");
ui.label("balls released:");
enumerate(ui, &confirm.ball_ids(), "(none)");
ui.separator();
if confirm.refused() {
ui.colored_label(
theme::ICHOR,
format!("live: {} — stop them first", confirm.live.join(", ")),
);
return;
}
ui.horizontal(|ui| {
ui.label(format!("type “{}” to confirm:", confirm.name));
ui.text_edit_singleline(&mut state.delete.typed)
.on_hover_text(
"Type the workspace's name exactly as shown to arm the delete — the \
same name `/delete-workspace <typed name>` carries.",
);
});
let armed = confirm.armed(&state.delete.typed);
if ui
.add_enabled(armed, egui::Button::new("Delete workspace"))
.on_hover_text(
"Destroy this workspace and every conversation listed above, and release \
the balls it holds. There is no undo and no archive. Typed, it is \
`/delete-workspace <typed name>`.",
)
.on_disabled_hover_text("type the workspace's name above to arm this")
.clicked()
{
fire(model, state, lernie, bl, &confirm.workspace);
}
if !state.delete.error.is_empty() {
ui.colored_label(theme::ICHOR, &state.delete.error);
}
}
fn enumerate(ui: &mut egui::Ui, items: &[String], empty: &str) {
if items.is_empty() {
ui.weak(empty);
}
for item in items {
ui.weak(item);
}
}
fn fire(model: &mut AppModel, state: &mut ShellState, lernie: &Cli, bl: &Cli, ws: &Path) {
match model.delete_workspace(lernie, bl, ws, &state.delete.typed, &super::now_ts()) {
Ok(()) => {
state.forget_wall(ws);
state.delete = DeleteState::default();
}
Err(e) => state.delete.error = e,
}
}