public inbox for yew-devel@lists.proxmox.com
 help / color / mirror / Atom feed
From: Shannon Sterz <s.sterz@proxmox.com>
To: yew-devel@lists.proxmox.com
Subject: [PATCH yew-mobile-gui 18/20] node: add a rudimentary firewall tab for cluster nodes
Date: Fri,  8 May 2026 17:05:33 +0200	[thread overview]
Message-ID: <20260508150535.420205-19-s.sterz@proxmox.com> (raw)
In-Reply-To: <20260508150535.420205-1-s.sterz@proxmox.com>

Signed-off-by: Shannon Sterz <s.sterz@proxmox.com>
---
 src/pages/page_node_status/firewall_panel.rs | 163 +++++++++++++++++++
 src/pages/page_node_status/mod.rs            |  18 ++
 2 files changed, 181 insertions(+)
 create mode 100644 src/pages/page_node_status/firewall_panel.rs

diff --git a/src/pages/page_node_status/firewall_panel.rs b/src/pages/page_node_status/firewall_panel.rs
new file mode 100644
index 0000000..c64c05e
--- /dev/null
+++ b/src/pages/page_node_status/firewall_panel.rs
@@ -0,0 +1,163 @@
+use std::rc::Rc;
+
+use serde::{Deserialize, Serialize};
+use yew::virtual_dom::{VComp, VNode};
+
+use pwt::prelude::*;
+use pwt::props::StorageLocation;
+use pwt::state::PersistentState;
+use pwt::widget::{Column, MiniScroll, TabBar, TabBarItem};
+
+use proxmox_yew_comp::configuration::pve::{FirewallOptionsNodePanel, FirewallRulesPanel};
+
+#[derive(Clone, PartialEq, Properties)]
+pub struct NodeFirewallPanel {
+    node: AttrValue,
+}
+
+impl NodeFirewallPanel {
+    pub fn new(node: impl Into<AttrValue>) -> Self {
+        Self { node: node.into() }
+    }
+}
+
+#[derive(Copy, Clone, Default, PartialEq, Serialize, Deserialize)]
+pub enum ViewState {
+    #[default]
+    Rules,
+    Options,
+    //Alias,
+    //IPSet,
+    //Log,
+}
+pub struct PveNodeFirewallPanel {
+    view_state: PersistentState<ViewState>,
+}
+
+pub enum Msg {
+    SetViewState(ViewState),
+}
+
+impl Component for PveNodeFirewallPanel {
+    type Message = Msg;
+    type Properties = NodeFirewallPanel;
+
+    fn create(ctx: &Context<Self>) -> Self {
+        let props = ctx.props();
+
+        let view_state = PersistentState::new(StorageLocation::session(format!(
+            "node-{}-firewall-tab-bar-state",
+            props.node
+        )));
+
+        Self { view_state }
+    }
+
+    fn update(&mut self, _ctx: &Context<Self>, msg: Self::Message) -> bool {
+        match msg {
+            Msg::SetViewState(view_state) => {
+                self.view_state.update(view_state);
+            }
+        }
+        true
+    }
+    fn view(&self, ctx: &Context<Self>) -> Html {
+        let props = ctx.props();
+
+        let (active_tab, content): (_, Html) = match *self.view_state {
+            ViewState::Rules => (
+                "rules",
+                FirewallRulesPanel::node_firewall(props.node.clone())
+                    .mobile(true)
+                    .readonly(true)
+                    .into(),
+            ),
+            ViewState::Options => (
+                "options",
+                FirewallOptionsNodePanel::new(props.node.clone())
+                    .mobile(true)
+                    .readonly(true)
+                    .into(),
+            ),
+            /*ViewState::Alias => (
+                "alias",
+                html! {
+                    <div>{ format!("Firewall alias for VM {}", props.vmid) }</div>
+                },
+            ),
+            ViewState::IPSet => (
+                "ipset",
+                html! {
+                    <div>{ format!("Firewall ipset for VM {}", props.vmid) }</div>
+                },
+            ),
+            ViewState::Log => (
+                "log",
+                html! {
+                    <div>{ format!("Firewall log for VM {}", props.vmid) }</div>
+                },
+            ),*/
+        };
+
+        let tab_bar = TabBar::new()
+            .style(pwt::widget::TabBarStyle::MaterialSecondary)
+            .class(pwt::css::JustifyContent::Center)
+            .class("pwt-flex-fill")
+            .active(active_tab)
+            .with_item(
+                TabBarItem::new()
+                    .key("rules")
+                    .label(tr!("Rules"))
+                    .icon_class("fa fa-shield")
+                    .on_activate(ctx.link().callback(|_| Msg::SetViewState(ViewState::Rules))),
+            )
+            .with_item(
+                TabBarItem::new()
+                    .key("options")
+                    .label(tr!("Options"))
+                    .icon_class("fa fa-gear")
+                    .on_activate(
+                        ctx.link()
+                            .callback(|_| Msg::SetViewState(ViewState::Options)),
+                    ),
+            )
+            /*.with_item(
+                TabBarItem::new()
+                    .key("alias")
+                    .label(tr!("Alias"))
+                    .icon_class("fa fa-external-link")
+                    .on_activate(ctx.link().callback(|_| Msg::SetViewState(ViewState::Alias))),
+            )
+            .with_item(
+                TabBarItem::new()
+                    .key("ipset")
+                    .label(tr!("IPSet"))
+                    .icon_class("fa fa-list-ol")
+                    .on_activate(ctx.link().callback(|_| Msg::SetViewState(ViewState::IPSet))),
+            )
+            .with_item(
+                TabBarItem::new()
+                    .key("log")
+                    .label(tr!("Log"))
+                    .icon_class("fa fa-list")
+                    .on_activate(ctx.link().callback(|_| Msg::SetViewState(ViewState::Log))),
+            )*/;
+
+        Column::new()
+            .class(pwt::css::FlexFit)
+            .with_child(
+                MiniScroll::new(tab_bar)
+                    .class("pwt-flex-none")
+                    .scroll_mode(pwt::widget::MiniScrollMode::Native),
+            )
+            .with_child(content)
+            .into()
+    }
+}
+
+impl From<NodeFirewallPanel> for VNode {
+    fn from(val: NodeFirewallPanel) -> Self {
+        let comp = VComp::new::<PveNodeFirewallPanel>(Rc::new(val), None);
+        VNode::from(comp)
+    }
+}
diff --git a/src/pages/page_node_status/mod.rs b/src/pages/page_node_status/mod.rs
index a566179..efb3d92 100644
--- a/src/pages/page_node_status/mod.rs
+++ b/src/pages/page_node_status/mod.rs
@@ -28,6 +28,9 @@ pub use services_panel::NodeServicesPanel;
 mod updates_panel;
 pub use updates_panel::NodeUpdatesPanel;
 
+mod firewall_panel;
+use firewall_panel::NodeFirewallPanel;
+
 #[derive(Clone, PartialEq, Properties)]
 pub struct PageNodeStatus {
     node: AttrValue,
@@ -47,6 +50,7 @@ pub enum ViewState {
     Dashboard,
     Services,
     Updates,
+    Firewall,
 }
 
 pub enum Msg {
@@ -119,6 +123,10 @@ impl Component for PvePageNodeStatus {
                 NodeServicesPanel::new(props.node.clone(), standalone).into(),
             ),
             ViewState::Updates => ("updates", NodeUpdatesPanel::new(props.node.clone()).into()),
+            ViewState::Firewall => (
+                "firewall",
+                NodeFirewallPanel::new(props.node.clone()).into(),
+            ),
         };
 
         let tab_bar = TabBar::new()
@@ -154,6 +162,16 @@ impl Component for PvePageNodeStatus {
                         ctx.link()
                             .callback(|_| Msg::SetViewState(ViewState::Updates)),
                     ),
+            )
+            .with_item(
+                TabBarItem::new()
+                    .label(tr!("Firewall"))
+                    .icon_class("fa fa-shield")
+                    .key("firewall")
+                    .on_activate(
+                        ctx.link()
+                            .callback(|_| Msg::SetViewState(ViewState::Firewall)),
+                    ),
             );
 
         Column::new()
-- 
2.47.3





  parent reply	other threads:[~2026-05-08 15:16 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-08 15:05 [PATCH yew-comp/yew-mobile-gui 00/20] firewall tabs and clean up for pve-yew-mobile-gui Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-comp 01/20] firewall rules panel: correct the url for the pve cluster firewall rules Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 02/20] cargo.toml: globally ignore certain clippy lints Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 03/20] main: avoid unnecessary clones Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 04/20] tree-wide: collapse if statements Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 05/20] tree-wide: implement the `From` trait instead of the `Into` trait Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 06/20] tree-wide: implement `Default` for types with an `new()` constructor Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 07/20] tree-wide: remove unnecessary lazy evaluations Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 08/20] tree-wide: remove needless borrows Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 09/20] configuration page: remove redundant static lifetimes Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 10/20] resources/configuration page: remove useless `.into()` calls Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 11/20] tree-wide: fix several clippy lints Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 12/20] dashboard: use proper plural translation string instead of "CPU(s)" Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 13/20] configuration: clarify that "Firewall" shows the cluster's firewall Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 14/20] cluster/qemu firewall: use rules panel and comment out unused tabs Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 15/20] lxc page: align layout for lxc guest with qemu guests Shannon Sterz
2026-05-08 15:43   ` Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 16/20] lxc: add support for a rudimentary firewall tab for lxc guests Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 17/20] node status: align layout for node status with guest pages Shannon Sterz
2026-05-08 15:05 ` Shannon Sterz [this message]
2026-05-08 15:05 ` [PATCH yew-mobile-gui 19/20] api types: remove unused file Shannon Sterz
2026-05-08 15:05 ` [PATCH yew-mobile-gui 20/20] resources page: map subscription level analogous to dashboard Shannon Sterz
2026-05-08 15:22   ` Shan Shaji
2026-05-08 15:59 ` Superseded: Re: [PATCH yew-comp/yew-mobile-gui 00/20] firewall tabs and clean up for pve-yew-mobile-gui Shannon Sterz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260508150535.420205-19-s.sterz@proxmox.com \
    --to=s.sterz@proxmox.com \
    --cc=yew-devel@lists.proxmox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal