From 4659697ae22729ede255f4a05a495812bb6f8d56 Mon Sep 17 00:00:00 2001 From: Mahmoud-Emad Date: Thu, 22 May 2025 15:47:11 +0300 Subject: [PATCH] feat: Add filtering and searching to governance proposals page - Added filtering of proposals by status (Draft, Active, Approved, Rejected, Cancelled). - Added searching of proposals by title and description. - Improved UI to persist filter and search values. - Added a "No proposals found" message for better UX. --- actix_mvc_app/src/controllers/governance.rs | 48 ++++++++++++++++++- .../src/views/governance/proposals.html | 27 ++++++++--- 2 files changed, 66 insertions(+), 9 deletions(-) diff --git a/actix_mvc_app/src/controllers/governance.rs b/actix_mvc_app/src/controllers/governance.rs index 04d4b89..71e90df 100644 --- a/actix_mvc_app/src/controllers/governance.rs +++ b/actix_mvc_app/src/controllers/governance.rs @@ -133,7 +133,11 @@ impl GovernanceController { } /// Handles the proposal list page route - pub async fn proposals(tmpl: web::Data, session: Session) -> Result { + pub async fn proposals( + query: web::Query, + tmpl: web::Data, + session: Session + ) -> Result { let mut ctx = tera::Context::new(); ctx.insert("active_page", "governance"); ctx.insert("active_tab", "proposals"); @@ -144,14 +148,47 @@ impl GovernanceController { } // Get proposals from the database - let proposals = match crate::db::proposals::get_proposals() { + let mut proposals = match crate::db::proposals::get_proposals() { Ok(props) => props, Err(e) => { ctx.insert("error", &format!("Failed to load proposals: {}", e)); vec![] } }; + + // Filter proposals by status if provided + if let Some(status_filter) = &query.status { + if !status_filter.is_empty() { + proposals = proposals + .into_iter() + .filter(|p| { + let proposal_status = format!("{:?}", p.status); + proposal_status == *status_filter + }) + .collect(); + } + } + + // Filter by search term if provided (title or description) + if let Some(search_term) = &query.search { + if !search_term.is_empty() { + let search_term = search_term.to_lowercase(); + proposals = proposals + .into_iter() + .filter(|p| { + p.title.to_lowercase().contains(&search_term) || + p.description.to_lowercase().contains(&search_term) + }) + .collect(); + } + } + + // Add the filtered proposals to the context ctx.insert("proposals", &proposals); + + // Add the filter values back to the context for form persistence + ctx.insert("status_filter", &query.status); + ctx.insert("search_filter", &query.search); render_template(&tmpl, "governance/proposals.html", &ctx) } @@ -597,6 +634,13 @@ pub struct VoteForm { pub comment: Option, } +/// Query parameters for filtering proposals +#[derive(Debug, Deserialize)] +pub struct ProposalQuery { + pub status: Option, + pub search: Option, +} + /// Represents statistics for the governance dashboard #[derive(Debug, Serialize)] pub struct GovernanceStats { diff --git a/actix_mvc_app/src/views/governance/proposals.html b/actix_mvc_app/src/views/governance/proposals.html index dba23f2..e0c565e 100644 --- a/actix_mvc_app/src/views/governance/proposals.html +++ b/actix_mvc_app/src/views/governance/proposals.html @@ -58,18 +58,18 @@
+ placeholder="Search by title or description" value="{% if search_filter %}{{ search_filter }}{% endif %}">
@@ -89,6 +89,7 @@ Create New Proposal
+ {% if proposals and proposals|length > 0 %}
@@ -129,9 +130,21 @@ {% endfor %}
+ {% else %} +
+ +
No proposals found
+ {% if status_filter or search_filter %} +

No proposals match your current filter criteria. Try adjusting your filters or view all proposals.

+ {% else %} +

There are no proposals in the system yet.

+ {% endif %} + Create New Proposal
+ {% endif %}
+ {% endblock %} \ No newline at end of file