Skip to content

Commit 6c18c98

Browse files
committed
fix(log): handle errors better
1 parent 86165a0 commit 6c18c98

File tree

2 files changed

+51
-37
lines changed

2 files changed

+51
-37
lines changed

src/widget/log.rs

+22-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ use kube::{api::LogParams, Api, ResourceExt};
1212
use ratatui::{
1313
buffer::Buffer,
1414
layout::{Position, Rect},
15+
style::{palette::tailwind, Style},
16+
widgets::Paragraph,
1517
Frame,
1618
};
1719
use tokio::{
@@ -34,7 +36,7 @@ use crate::{
3436
};
3537

3638
pub struct Log {
37-
task: JoinHandle<Result<()>>,
39+
task: Option<JoinHandle<Result<()>>>,
3840

3941
rx: mpsc::UnboundedReceiver<String>,
4042
buffer: Vec<String>,
@@ -74,7 +76,7 @@ impl Log {
7476
));
7577

7678
Self {
77-
task,
79+
task: Some(task),
7880
rx,
7981
buffer: Vec::new(),
8082

@@ -134,8 +136,8 @@ impl Widget for Log {
134136
self.position.y = u16::MAX;
135137
}
136138

137-
if self.task.is_finished() {
138-
let task = &mut self.task;
139+
if self.task.as_ref().map_or(false, JoinHandle::is_finished) {
140+
let task = self.task.take().expect("task is finished");
139141

140142
match futures::executor::block_on(async move { task.await? }) {
141143
Ok(()) => return Err(eyre!("Log task finished unexpectedly")),
@@ -151,17 +153,30 @@ impl Widget for Log {
151153
}
152154
}
153155

154-
Viewport::builder()
156+
let result = Viewport::builder()
155157
.buffer(&self.buffer)
156158
.view(self.position)
157159
.build()
158-
.draw(frame, area)
160+
.draw(frame, area);
161+
162+
if self.task.is_none() {
163+
frame.render_widget(
164+
Paragraph::new("Log stream ended, come back to restart")
165+
.style(Style::default().fg(tailwind::RED.c300))
166+
.centered(),
167+
area,
168+
);
169+
}
170+
171+
result
159172
}
160173
}
161174

162175
impl Drop for Log {
163176
fn drop(&mut self) {
164-
self.task.abort();
177+
if let Some(task) = self.task.as_ref() {
178+
task.abort();
179+
}
165180
}
166181
}
167182

src/widget/tabs.rs

+29-30
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,6 @@ impl Widget for Bar {
5656
if let Some(Movement::X(x)) = move_cursor(key, area) {
5757
self.idx = self
5858
.idx
59-
// TODO: this isn't a great solution, it effectively means that if the middle tab
60-
// has an error, you can never get to the last tab. It should be
61-
// possible to navigate between things when an error is displayed.
62-
// This gets weird though when you think about scrolling the error
63-
// dialog.
6459
.wrapping_add_signed(x.into())
6560
.clamp(0, self.items.len().saturating_sub(1));
6661

@@ -131,37 +126,41 @@ impl TabbedView {
131126
items: tabs,
132127
}
133128
}
129+
130+
fn select(&mut self, idx: usize, buffer: &Buffer) {
131+
let start = if self.current < idx {
132+
Start::Left
133+
} else {
134+
Start::Right
135+
};
136+
137+
self.current = idx;
138+
139+
// TODO: this is *probably* a valid assumption, but it might need to be actually
140+
// checked.
141+
self.view.pop();
142+
self.view.push(
143+
Animated::builder()
144+
.widget(self.items[idx].widget())
145+
.effect(fx::parallel(&[
146+
fx::coalesce(EffectTimer::from_ms(500, Interpolation::SineInOut)),
147+
horizontal_wipe()
148+
.buffer(buffer.clone())
149+
.timer(EffectTimer::from_ms(500, Interpolation::SineInOut))
150+
.start(start)
151+
.call(),
152+
]))
153+
.build()
154+
.boxed(),
155+
);
156+
}
134157
}
135158

136159
impl Widget for TabbedView {
137160
fn dispatch(&mut self, event: &Event, buffer: &Buffer, area: Rect) -> Result<Broadcast> {
138161
match self.view.dispatch(event, buffer, area)? {
139162
Broadcast::Selected(idx) => {
140-
let start = if self.current < idx {
141-
Start::Left
142-
} else {
143-
Start::Right
144-
};
145-
146-
self.current = idx;
147-
148-
// TODO: this is *probably* a valid assumption, but it might need to be actually
149-
// checked.
150-
self.view.pop();
151-
self.view.push(
152-
Animated::builder()
153-
.widget(self.items[idx].widget())
154-
.effect(fx::parallel(&[
155-
fx::coalesce(EffectTimer::from_ms(500, Interpolation::SineInOut)),
156-
horizontal_wipe()
157-
.buffer(buffer.clone())
158-
.timer(EffectTimer::from_ms(500, Interpolation::SineInOut))
159-
.start(start)
160-
.call(),
161-
]))
162-
.build()
163-
.boxed(),
164-
);
163+
self.select(idx, buffer);
165164

166165
Ok(Broadcast::Consumed)
167166
}

0 commit comments

Comments
 (0)