Skip to content

Commit

Permalink
Showing side panel with full message contents when message ID in tabl…
Browse files Browse the repository at this point in the history
…e is clicked.
  • Loading branch information
dmackdev committed Oct 14, 2023
1 parent ed14c9b commit efab04c
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 54 deletions.
104 changes: 104 additions & 0 deletions pubsubman/src/app.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
use std::collections::{HashMap, HashSet};

use chrono::{DateTime, Local};
use egui_json_tree::{DefaultExpand, JsonTree};
use pubsubman_backend::{
message::{BackendMessage, FrontendMessage},
model::{PubsubMessage, SubscriptionName, TopicName},
Backend,
};
use serde_json::{Map, Value};
use tokio::sync::mpsc::{Receiver, Sender};

use crate::{
Expand Down Expand Up @@ -35,6 +38,7 @@ pub struct App {
front_tx: Sender<FrontendMessage>,
back_rx: Receiver<BackendMessage>,
notifications: Notifications,
selected_message: Option<(TopicName, usize)>,
}

impl App {
Expand Down Expand Up @@ -66,6 +70,7 @@ impl App {
front_tx,
back_rx,
notifications: Notifications::default(),
selected_message: None,
}
}

Expand Down Expand Up @@ -165,6 +170,8 @@ impl App {
cancel_token.cancel();
}

self.selected_message.take();

self.selected_topic = Some(topic_name.clone());

if !self.memory.subscriptions.contains_key(topic_name) {
Expand All @@ -181,6 +188,100 @@ impl App {
fn render_central_panel(&mut self, ctx: &egui::Context) {
match &self.selected_topic {
Some(selected_topic) => {
let selected_message =
&self
.selected_message
.as_ref()
.and_then(|(topic_name, idx)| {
self.memory
.messages
.get(topic_name)
.and_then(|messages| messages.get(*idx))
});

egui::SidePanel::right("selected_message")
.frame(egui::Frame::none())
.resizable(true)
.show_animated(ctx, selected_message.is_some(), |ui| {
if let Some(message) = selected_message {
egui::TopBottomPanel::top("selected_message_top_panel")
.frame(egui::Frame::side_top_panel(&ctx.style()).inner_margin(8.0))
.show_inside(ui, |ui| {
ui.with_layout(
egui::Layout::left_to_right(egui::Align::Center),
|ui| {
ui.heading(format!("Message {}", &message.id));
ui.with_layout(
egui::Layout::right_to_left(egui::Align::Center),
|ui| {
if ui.button("✖").clicked() {
self.selected_message.take();
}
},
);
},
);
});

egui::CentralPanel::default().show_inside(ui, |ui| {
egui::ScrollArea::vertical().show(ui, |ui| {
let publish_time =
if let Some(publish_time) = message.publish_time {
let local_publish_time: DateTime<Local> =
publish_time.into();
local_publish_time.format("%d/%m/%Y %H:%M").to_string()
} else {
"<Empty>".to_string()
};

ui.horizontal(|ui| {
ui.label("Publish Time: ");
ui.monospace(publish_time);
});

egui::CollapsingHeader::new("Data")
.id_source("selected_message_data_collapsing_header")
.default_open(false)
.show(ui, |ui| {
JsonTree::new(
format!(
"selected_message_data_json_{}",
&message.id
),
&message.data_json,
)
.default_expand(DefaultExpand::All)
.show(ui);
});

egui::CollapsingHeader::new("Attributes")
.id_source("selected_message_attributes_collapsing_header")
.default_open(false)
.show(ui, |ui| {
if message.attributes.is_empty() {
ui.monospace("<Empty>");
} else {
JsonTree::new(
format!(
"selected_message_attributes_json_{}",
&message.id
),
&Value::Object(Map::from_iter(
message.attributes.iter().map(|(k, v)| {
(k.to_owned(), Value::String(v.clone()))
}),
)),
)
.default_expand(egui_json_tree::DefaultExpand::All)
.show(ui);
}
});
ui.allocate_space(ui.available_size());
});
});
}
});

egui::TopBottomPanel::top("topic_view_top_panel")
.frame(egui::Frame::side_top_panel(&ctx.style()).inner_margin(8.0))
.show(ctx, |ui| {
Expand Down Expand Up @@ -229,6 +330,9 @@ impl App {
.entry(selected_topic.clone())
.or_default(),
self.memory.messages.get(selected_topic).unwrap_or(&vec![]),
|idx| {
self.selected_message = Some((selected_topic.clone(), idx))
},
);
}
None => {
Expand Down
12 changes: 0 additions & 12 deletions pubsubman/src/column_settings.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
#[derive(Clone, serde::Deserialize, serde::Serialize)]
pub struct ColumnSettings {
pub show_id: bool,
pub show_published_at: bool,
pub show_attributes: bool,
}

impl Default for ColumnSettings {
fn default() -> Self {
Self {
show_id: true,
show_published_at: true,
show_attributes: true,
}
}
}
Expand All @@ -19,17 +15,9 @@ impl ColumnSettings {
pub fn show(&mut self, ui: &mut egui::Ui) {
ui.visuals_mut().widgets.inactive.weak_bg_fill = egui::Color32::from_gray(32);
ui.menu_button("Columns ⏷", |ui| {
ui.horizontal(|ui| {
ui.checkbox(&mut self.show_id, " ID");
});

ui.horizontal(|ui| {
ui.checkbox(&mut self.show_published_at, " Published at");
});

ui.horizontal(|ui| {
ui.checkbox(&mut self.show_attributes, " Attributes");
});
});
}
}
56 changes: 14 additions & 42 deletions pubsubman/src/ui/messages_view.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
use std::collections::HashMap;
use std::fmt::Write;

use chrono::{DateTime, Local};
use egui_json_tree::{DefaultExpand, JsonTree};
use pubsubman_backend::{
Expand All @@ -24,6 +21,7 @@ pub struct MessagesView {
}

impl MessagesView {
#[allow(clippy::too_many_arguments)]
pub fn show(
&mut self,
ui: &mut egui::Ui,
Expand All @@ -32,6 +30,7 @@ impl MessagesView {
sub_name: &SubscriptionName,
column_settings: &mut ColumnSettings,
messages: &[PubsubMessage],
on_message_id_click: impl FnMut(usize),
) {
let search_query = self.search_query.to_ascii_lowercase();
let filtered_messages = messages
Expand Down Expand Up @@ -155,6 +154,7 @@ impl MessagesView {
filtered_messages,
&search_query,
search_query_changed,
on_message_id_click,
);
});
});
Expand All @@ -170,37 +170,29 @@ fn render_messages_table<'a, I>(
messages: I,
search_term: &str,
search_query_changed: bool,
mut on_message_id_click: impl FnMut(usize),
) where
I: Iterator<Item = &'a PubsubMessage>,
{
let ColumnSettings {
show_id,
show_published_at,
show_attributes,
} = *column_settings;
let ColumnSettings { show_published_at } = *column_settings;

let mut num_columns = 2; // ID and Data columns will always be shown.

let num_columns = [show_id, show_published_at, show_attributes].iter().fold(
1, // Data column will always be present
|acc, col_enabled| if *col_enabled { acc + 1 } else { acc },
);
if show_published_at {
num_columns += 1;
}

egui::Grid::new(&selected_topic.0)
.striped(true)
.num_columns(num_columns)
.spacing((25.0, 8.0))
.show(ui, |ui| {
if show_id {
ui.label("ID");
}
ui.label("ID");

if show_published_at {
ui.label("Published at");
}

if show_attributes {
ui.label("Attributes");
}

// Let Data column take up all remaining space.
ui.with_layout(
egui::Layout::left_to_right(egui::Align::Center)
Expand All @@ -213,9 +205,9 @@ fn render_messages_table<'a, I>(

ui.end_row();

for message in messages {
if show_id {
ui.label(&message.id);
for (idx, message) in messages.enumerate() {
if ui.link(&message.id).clicked() {
on_message_id_click(idx);
}

if show_published_at {
Expand All @@ -226,10 +218,6 @@ fn render_messages_table<'a, I>(
}
}

if show_attributes {
ui.label(format_attributes(&message.attributes));
}

let response = JsonTree::new(&message.id, &message.data_json)
.default_expand(DefaultExpand::SearchResults(search_term))
.response_callback(|response, pointer| {
Expand Down Expand Up @@ -276,19 +264,3 @@ fn show_context_menu(ui: &mut egui::Ui, pointer: &String, value: &Value) {
}
});
}

fn format_attributes(attributes: &HashMap<String, String>) -> String {
attributes
.iter()
.enumerate()
.fold(String::new(), |mut acc, (i, (k, v))| {
let _ = write!(
acc,
"{}:{}{}",
k,
v,
(if i == attributes.len() - 1 { "" } else { ", " })
);
acc
})
}

0 comments on commit efab04c

Please sign in to comment.