Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ impl MessageView {
.and_then(|view| view.read(cx).row.clone())
.filter(|row| row.id == id)
}),
copy_thread: None,
thread: None,
composer: WeakEntity::new_invalid(),
};
Expand Down
20 changes: 20 additions & 0 deletions apps/buzz-gpui/crates/app/src/ui/agent_activity/bubble.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,26 @@ fn label(work: &RequestWork) -> String {
local_work_label(state, work.reason.as_deref(), work.step.as_ref())
}

/// One agent's status as text, for "Copy thread": what its bubble and
/// popover show, "Could not finish" with the reason when one is known.
pub fn status(work: &RequestWork) -> String {
if !work.lifecycle {
return if work.working {
"Working"
} else {
"Status unknown"
}
.into();
}
if work.state == WorkState::Error {
return match work.reason.as_deref().filter(|r| !r.is_empty()) {
Some(reason) => format!("Could not finish: {reason}"),
None => "Could not finish".into(),
};
}
label(work)
}

/// Names for the bubble's agents: the directory's, with the key's suffix
/// when two read alike.
fn names(works: &[RequestWork], names: &Names) -> Vec<SharedString> {
Expand Down
1 change: 1 addition & 0 deletions apps/buzz-gpui/crates/app/src/ui/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,7 @@ impl ChannelPage {
.map(|item| item.row.clone())
})
}),
copy_thread: None,
thread: None,
composer: composer.downgrade(),
};
Expand Down
2 changes: 1 addition & 1 deletion apps/buzz-gpui/crates/app/src/ui/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2546,7 +2546,7 @@ pub(super) mod tests {
)
}

fn directory() -> Directory {
pub(in crate::ui) fn directory() -> Directory {
Directory::new(Profiles::default(), Arc::from([]), media())
}

Expand Down
1 change: 1 addition & 0 deletions apps/buzz-gpui/crates/app/src/ui/media/comments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ impl Comments {
find.upgrade()
.and_then(|comments| comments.read(cx).row(id))
}),
copy_thread: None,
thread: Some(root),
composer: composer.downgrade(),
};
Expand Down
38 changes: 36 additions & 2 deletions apps/buzz-gpui/crates/app/src/ui/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,8 @@ pub enum Command {
ReviewReport,
CopyLink,
CopyMessage,
/// The whole loaded thread as Markdown, from its root.
CopyThread,
MarkRead,
MarkUnread,
SendToChannel,
Expand Down Expand Up @@ -276,6 +278,8 @@ pub struct Actions {
/// A reader's conversation offers no Reply (`ChannelPreview` has no
/// `onReply`).
pub no_reply: bool,
/// The page can copy its whole thread: the root offers "Copy thread".
pub copy_thread: bool,
}

/// A page's loaded row by id.
Expand Down Expand Up @@ -1627,8 +1631,9 @@ struct Entry {
}

/// `MessageActionBar`'s menu, in its order: read state, Copy message,
/// Send to channel, Edit, Delete, Follow, registered actions, View
/// activity, then Report under a separator.
/// Copy thread (a thread panel's root), Send to channel, Edit, Delete,
/// Follow, registered actions, View activity, then Report under a
/// separator.
fn menu_entries(row: &MessageRow, rows: &Rows) -> Vec<Entry> {
let mut entries = Vec::new();
let managed = rows.managed(row) && rows.actions.on_command.is_some();
Expand Down Expand Up @@ -1662,6 +1667,17 @@ fn menu_entries(row: &MessageRow, rows: &Rows) -> Vec<Entry> {
disabled: false,
separated: false,
});
if rows.actions.copy_thread && row.thread_root_id.is_none() {
entries.push(Entry {
name: "copy-thread".into(),
label: "Copy thread".into(),
icon: IconName::Copy,
icon_size: 16.,
command: Command::CopyThread,
disabled: false,
separated: false,
});
}
let writable = rows.listed() && !rows.archived() && !rows.read_only();
if writable
&& row.thread_root_id.is_some()
Expand Down Expand Up @@ -2626,6 +2642,24 @@ mod tests {
use buzz_relay_client::fold::{LocalDelivery, Reaction};
use core::prelude::v1::test;

#[test]
fn only_a_copyable_threads_root_offers_copy_thread() {
let offers = |copy_thread: bool, reply: bool| {
let mut rows = Rows::new("", super::super::markdown::tests::directory());
rows.actions.copy_thread = copy_thread;
let mut row = super::super::markdown::tests::row("x");
if reply {
row.thread_root_id = Some(EventId::from_byte_array([7; 32]));
}
menu_entries(&row, &rows)
.iter()
.any(|entry| entry.command == Command::CopyThread)
};
assert!(offers(true, false));
assert!(!offers(true, true));
assert!(!offers(false, false));
}

/// The quiet line's label for `content` from Morgarita, which names
/// Rivet in a `p` tag.
fn quiet_line(content: &str) -> String {
Expand Down
11 changes: 11 additions & 0 deletions apps/buzz-gpui/crates/app/src/ui/message_actions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ pub type RowHook = Rc<dyn Fn(Arc<MessageRow>, &mut Window, &mut App)>;
pub type FocusHook = Rc<dyn Fn(&mut Window, &mut App)>;
pub type RootHook = Rc<dyn Fn(&App) -> Option<Arc<MessageRow>>>;
pub type FindHook = Rc<dyn Fn(EventId, &App) -> Option<Arc<MessageRow>>>;
/// The page's whole thread as Markdown, `None` before it has loaded.
pub type CopyThreadHook = Rc<dyn Fn(&App) -> Option<String>>;

/// What only the page knows how to do.
pub struct Hooks {
Expand All @@ -41,6 +43,8 @@ pub struct Hooks {
pub thread_root: Option<RootHook>,
/// A loaded row by id, for the picker's target.
pub find: FindHook,
/// "Copy thread" on a thread panel's root.
pub copy_thread: Option<CopyThreadHook>,
/// Typing in this view: the channel, or a thread root.
pub thread: Option<EventId>,
/// The page's composer, where edits happen.
Expand Down Expand Up @@ -563,6 +567,7 @@ impl MessageActions {
on_open_thread: self.open_thread.clone(),
find_row: Some(self.hooks.find.clone()),
no_reply: self.no_reply,
copy_thread: self.hooks.copy_thread.is_some(),
on_retry: Some(Rc::new(move |row, _, cx| {
let _ = retry.update(cx, |this, cx| {
let (session, id) = (this.session(cx), row.id);
Expand Down Expand Up @@ -710,6 +715,12 @@ impl MessageActions {
cx.write_to_clipboard(ClipboardItem::new_string(text));
notice::success("Message copied", cx);
}
Command::CopyThread => {
if let Some(text) = self.hooks.copy_thread.as_ref().and_then(|copy| copy(cx)) {
cx.write_to_clipboard(ClipboardItem::new_string(text));
notice::success("Thread copied", cx);
}
}
Command::MarkRead | Command::MarkUnread => {
self.error = None;
let read = command == Command::MarkRead;
Expand Down
Loading
Loading