powhttp_sdk/
context_menu.rs1use std::sync::Arc;
2use serde::Serialize;
3
4use crate::runtime::handlers::{MultiEntryContext, SingleEntryContext};
5use crate::runtime::state::ContextMenuHandler;
6use crate::runtime::handle::ExtensionHandle;
7use crate::error::Error;
8
9#[derive(Serialize)]
27#[serde(bound(serialize = ""))]
28#[serde(rename_all = "camelCase")]
29pub struct ContextMenuItem<C> {
30 id: String,
31 label: String,
32 #[serde(skip)]
33 handler: ContextMenuHandler<C>,
34}
35
36impl<C> ContextMenuItem<C> {
37 pub fn new<F, Fut>(id: impl Into<String>, label: impl Into<String>, handler: F) -> Self
39 where
40 F: Fn(C, ExtensionHandle) -> Fut + Send + Sync + 'static,
41 Fut: Future<Output = Result<(), Error>> + Send + 'static,
42 {
43 Self {
44 id: id.into(),
45 label: label.into(),
46 handler: Arc::new(move |ctx, handle| {
47 let fut = handler(ctx, handle);
48 Box::pin(async move { fut.await.map_err(Error::into_jrpc) })
49 }),
50 }
51 }
52}
53
54#[derive(Serialize)]
56#[serde(bound(serialize = ""))]
57#[serde(rename_all = "camelCase")]
58pub struct ContextMenuSubmenu<C> {
59 label: String,
60 children: Vec<ContextMenuNode<C>>,
61}
62
63impl<C> ContextMenuSubmenu<C> {
64 pub fn new(label: impl Into<String>) -> Self {
66 Self {
67 label: label.into(),
68 children: Vec::new()
69 }
70 }
71
72 pub fn with_children(mut self, children: &mut Vec<ContextMenuNode<C>>) -> Self {
74 self.children.append(children);
75 self
76 }
77
78 pub fn with_child(mut self, child: ContextMenuNode<C>) -> Self {
80 self.children.push(child);
81 self
82 }
83}
84
85#[derive(Serialize)]
88#[serde(bound(serialize = ""))]
89#[serde(tag = "type", rename_all = "snake_case")]
90pub enum ContextMenuNode<C> {
91 Submenu(ContextMenuSubmenu<C>),
92 Item(ContextMenuItem<C>),
93}
94
95impl<C> ContextMenuNode<C> {
96 pub(crate) fn extract_handlers(&self) -> Vec<(String, ContextMenuHandler<C>)> {
97 match self {
98 Self::Item(item) => vec![(item.id.clone(), Arc::clone(&item.handler))],
99 Self::Submenu(sub) => sub
100 .children
101 .iter()
102 .flat_map(|child| child.extract_handlers())
103 .collect(),
104 }
105 }
106}
107
108impl<C> From<ContextMenuItem<C>> for ContextMenuNode<C> {
109 fn from(item: ContextMenuItem<C>) -> Self {
110 ContextMenuNode::Item(item)
111 }
112}
113
114impl<C> From<ContextMenuSubmenu<C>> for ContextMenuNode<C> {
115 fn from(submenu: ContextMenuSubmenu<C>) -> Self {
116 ContextMenuNode::Submenu(submenu)
117 }
118}
119
120pub type ContextMenuItemSingle = ContextMenuItem<SingleEntryContext>;
122pub type ContextMenuSubmenuSingle = ContextMenuSubmenu<SingleEntryContext>;
124pub type ContextMenuNodeSingle = ContextMenuNode<SingleEntryContext>;
126
127pub type ContextMenuItemMulti = ContextMenuItem<MultiEntryContext>;
129pub type ContextMenuSubmenuMulti = ContextMenuSubmenu<MultiEntryContext>;
131pub type ContextMenuNodeMulti = ContextMenuNode<MultiEntryContext>;