...
This commit is contained in:
parent
15b05cb599
commit
34594b95fa
@ -2,6 +2,7 @@ use actix_web::{web, HttpResponse, Responder, Result, http::header, cookie::Cook
|
|||||||
use actix_session::Session;
|
use actix_session::Session;
|
||||||
use tera::Tera;
|
use tera::Tera;
|
||||||
use crate::models::user::{User, LoginCredentials, RegistrationData, UserRole};
|
use crate::models::user::{User, LoginCredentials, RegistrationData, UserRole};
|
||||||
|
use crate::utils::render_template;
|
||||||
use jsonwebtoken::{encode, decode, Header, Algorithm, Validation, EncodingKey, DecodingKey};
|
use jsonwebtoken::{encode, decode, Header, Algorithm, Validation, EncodingKey, DecodingKey};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use chrono::{Utc, Duration};
|
use chrono::{Utc, Duration};
|
||||||
@ -91,13 +92,7 @@ impl AuthController {
|
|||||||
let mut ctx = tera::Context::new();
|
let mut ctx = tera::Context::new();
|
||||||
ctx.insert("active_page", "login");
|
ctx.insert("active_page", "login");
|
||||||
|
|
||||||
let rendered = tmpl.render("auth/login.html", &ctx)
|
render_template(&tmpl, "auth/login.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles user login
|
/// Handles user login
|
||||||
@ -146,13 +141,7 @@ impl AuthController {
|
|||||||
let mut ctx = tera::Context::new();
|
let mut ctx = tera::Context::new();
|
||||||
ctx.insert("active_page", "register");
|
ctx.insert("active_page", "register");
|
||||||
|
|
||||||
let rendered = tmpl.render("auth/register.html", &ctx)
|
render_template(&tmpl, "auth/register.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles user registration
|
/// Handles user registration
|
||||||
|
@ -6,7 +6,7 @@ use tera::Tera;
|
|||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
use crate::models::{CalendarEvent, CalendarViewMode};
|
use crate::models::{CalendarEvent, CalendarViewMode};
|
||||||
use crate::utils::RedisCalendarService;
|
use crate::utils::{RedisCalendarService, render_template};
|
||||||
|
|
||||||
/// Controller for handling calendar-related routes
|
/// Controller for handling calendar-related routes
|
||||||
pub struct CalendarController;
|
pub struct CalendarController;
|
||||||
@ -215,13 +215,7 @@ impl CalendarController {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let rendered = tmpl.render("calendar/index.html", &ctx)
|
render_template(&tmpl, "calendar/index.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the new event page route
|
/// Handles the new event page route
|
||||||
@ -234,13 +228,7 @@ impl CalendarController {
|
|||||||
ctx.insert("user", &user);
|
ctx.insert("user", &user);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rendered = tmpl.render("calendar/new_event.html", &ctx)
|
render_template(&tmpl, "calendar/new_event.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the create event route
|
/// Handles the create event route
|
||||||
@ -298,13 +286,9 @@ impl CalendarController {
|
|||||||
ctx.insert("user", &user);
|
ctx.insert("user", &user);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rendered = tmpl.render("calendar/new_event.html", &ctx)
|
let result = render_template(&tmpl, "calendar/new_event.html", &ctx)?;
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::InternalServerError().content_type("text/html").body(rendered))
|
Ok(HttpResponse::InternalServerError().content_type("text/html").body(result.into_body()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use chrono::{Utc, Duration};
|
|||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::models::contract::{Contract, ContractStatus, ContractType, ContractStatistics, SignerStatus};
|
use crate::models::contract::{Contract, ContractStatus, ContractType, ContractStatistics, SignerStatus};
|
||||||
|
use crate::utils::render_template;
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
pub struct ContractForm {
|
pub struct ContractForm {
|
||||||
@ -62,15 +63,7 @@ impl ContractController {
|
|||||||
|
|
||||||
context.insert("draft_contracts", &draft_contracts);
|
context.insert("draft_contracts", &draft_contracts);
|
||||||
|
|
||||||
let rendered = tmpl.render("contracts/index.html", &context)
|
render_template(&tmpl, "contracts/index.html", &context)
|
||||||
.map_err(|e| {
|
|
||||||
log::error!("Template rendering error: {}", e);
|
|
||||||
log::error!("Error details: {:?}", e);
|
|
||||||
log::error!("Context: {:?}", context);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display the list of all contracts
|
// Display the list of all contracts
|
||||||
@ -89,15 +82,7 @@ impl ContractController {
|
|||||||
context.insert("contracts", &contracts_data);
|
context.insert("contracts", &contracts_data);
|
||||||
context.insert("filter", &"all");
|
context.insert("filter", &"all");
|
||||||
|
|
||||||
let rendered = tmpl.render("contracts/contracts.html", &context)
|
render_template(&tmpl, "contracts/contracts.html", &context)
|
||||||
.map_err(|e| {
|
|
||||||
log::error!("Template rendering error: {}", e);
|
|
||||||
log::error!("Error details: {:?}", e);
|
|
||||||
log::error!("Context: {:?}", context);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display the list of user's contracts
|
// Display the list of user's contracts
|
||||||
@ -115,15 +100,7 @@ impl ContractController {
|
|||||||
|
|
||||||
context.insert("contracts", &contracts_data);
|
context.insert("contracts", &contracts_data);
|
||||||
|
|
||||||
let rendered = tmpl.render("contracts/my_contracts.html", &context)
|
render_template(&tmpl, "contracts/my_contracts.html", &context)
|
||||||
.map_err(|e| {
|
|
||||||
log::error!("Template rendering error: {}", e);
|
|
||||||
log::error!("Error details: {:?}", e);
|
|
||||||
log::error!("Context: {:?}", context);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display a specific contract
|
// Display a specific contract
|
||||||
@ -146,15 +123,7 @@ impl ContractController {
|
|||||||
context.insert("contract", &contract_json);
|
context.insert("contract", &contract_json);
|
||||||
context.insert("user_has_signed", &false); // Mock data
|
context.insert("user_has_signed", &false); // Mock data
|
||||||
|
|
||||||
let rendered = tmpl.render("contracts/contract_detail.html", &context)
|
render_template(&tmpl, "contracts/contract_detail.html", &context)
|
||||||
.map_err(|e| {
|
|
||||||
log::error!("Template rendering error: {}", e);
|
|
||||||
log::error!("Error details: {:?}", e);
|
|
||||||
log::error!("Context: {:?}", context);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
},
|
},
|
||||||
None => {
|
None => {
|
||||||
Ok(HttpResponse::NotFound().finish())
|
Ok(HttpResponse::NotFound().finish())
|
||||||
@ -180,26 +149,18 @@ impl ContractController {
|
|||||||
|
|
||||||
context.insert("contract_types", &contract_types);
|
context.insert("contract_types", &contract_types);
|
||||||
|
|
||||||
let rendered = tmpl.render("contracts/create_contract.html", &context)
|
render_template(&tmpl, "contracts/create_contract.html", &context)
|
||||||
.map_err(|e| {
|
|
||||||
log::error!("Template rendering error: {}", e);
|
|
||||||
log::error!("Error details: {:?}", e);
|
|
||||||
log::error!("Context: {:?}", context);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process the create contract form
|
// Process the create contract form
|
||||||
pub async fn create(
|
pub async fn create(
|
||||||
tmpl: web::Data<Tera>,
|
_tmpl: web::Data<Tera>,
|
||||||
form: web::Form<ContractForm>,
|
_form: web::Form<ContractForm>,
|
||||||
) -> Result<HttpResponse> {
|
) -> Result<HttpResponse> {
|
||||||
// In a real application, we would save the contract to the database
|
// In a real application, we would save the contract to the database
|
||||||
// For now, we'll just redirect to the contracts list
|
// For now, we'll just redirect to the contracts list
|
||||||
|
|
||||||
Ok(HttpResponse::Found().header("Location", "/contracts").finish())
|
Ok(HttpResponse::Found().append_header(("Location", "/contracts")).finish())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to convert Contract to a JSON object for templates
|
// Helper method to convert Contract to a JSON object for templates
|
||||||
|
@ -3,10 +3,10 @@ use actix_session::Session;
|
|||||||
use chrono::{Utc, Duration};
|
use chrono::{Utc, Duration};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use tera::Tera;
|
use tera::Tera;
|
||||||
use std::error::Error; // Add this line
|
|
||||||
|
|
||||||
use crate::models::flow::{Flow, FlowStatus, FlowType, FlowStatistics, FlowStep, StepStatus, FlowLog};
|
use crate::models::flow::{Flow, FlowStatus, FlowType, FlowStatistics, FlowStep, StepStatus, FlowLog};
|
||||||
use crate::controllers::auth::Claims;
|
use crate::controllers::auth::Claims;
|
||||||
|
use crate::utils::render_template;
|
||||||
|
|
||||||
pub struct FlowController;
|
pub struct FlowController;
|
||||||
|
|
||||||
@ -25,15 +25,7 @@ impl FlowController {
|
|||||||
ctx.insert("active_flows", &flows.iter().filter(|f| f.status == FlowStatus::InProgress).collect::<Vec<_>>());
|
ctx.insert("active_flows", &flows.iter().filter(|f| f.status == FlowStatus::InProgress).collect::<Vec<_>>());
|
||||||
ctx.insert("stuck_flows", &flows.iter().filter(|f| f.status == FlowStatus::Stuck).collect::<Vec<_>>());
|
ctx.insert("stuck_flows", &flows.iter().filter(|f| f.status == FlowStatus::Stuck).collect::<Vec<_>>());
|
||||||
|
|
||||||
let rendered = tmpl.render("flows/index.html", &ctx)
|
render_template(&tmpl, "flows/index.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
log::error!("Template rendering error: {}", e);
|
|
||||||
log::error!("Error details: {:?}", e);
|
|
||||||
log::error!("Context: {:?}", ctx);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders the flows list page
|
/// Renders the flows list page
|
||||||
@ -46,15 +38,7 @@ impl FlowController {
|
|||||||
ctx.insert("user", &user);
|
ctx.insert("user", &user);
|
||||||
ctx.insert("flows", &flows);
|
ctx.insert("flows", &flows);
|
||||||
|
|
||||||
let rendered = tmpl.render("flows/flows.html", &ctx)
|
render_template(&tmpl, "flows/flows.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
log::error!("Template rendering error: {}", e);
|
|
||||||
log::error!("Error details: {:?}", e);
|
|
||||||
log::error!("Context: {:?}", ctx);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders the flow detail page
|
/// Renders the flow detail page
|
||||||
@ -76,29 +60,20 @@ impl FlowController {
|
|||||||
ctx.insert("user", &user);
|
ctx.insert("user", &user);
|
||||||
ctx.insert("flow", flow);
|
ctx.insert("flow", flow);
|
||||||
|
|
||||||
let rendered = tmpl.render("flows/flow_detail.html", &ctx)
|
render_template(&tmpl, "flows/flow_detail.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
log::error!("Template rendering error: {}", e);
|
|
||||||
log::error!("Error details: {:?}", e);
|
|
||||||
log::error!("Context: {:?}", ctx);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
} else {
|
} else {
|
||||||
let mut ctx = tera::Context::new();
|
let mut ctx = tera::Context::new();
|
||||||
ctx.insert("active_page", "flows");
|
ctx.insert("active_page", "flows");
|
||||||
ctx.insert("error", "Flow not found");
|
ctx.insert("error", "Flow not found");
|
||||||
|
|
||||||
let rendered = tmpl.render("error.html", &ctx)
|
// For the error page, we'll use a special case to set the status code to 404
|
||||||
.map_err(|e| {
|
match tmpl.render("error.html", &ctx) {
|
||||||
log::error!("Template rendering error: {}", e);
|
Ok(content) => Ok(HttpResponse::NotFound().content_type("text/html").body(content)),
|
||||||
log::error!("Error details: {:?}", e);
|
Err(e) => {
|
||||||
log::error!("Context: {:?}", ctx);
|
log::error!("Error rendering error template: {}", e);
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
Err(actix_web::error::ErrorInternalServerError(format!("Error: {}", e)))
|
||||||
})?;
|
}
|
||||||
|
}
|
||||||
Ok(HttpResponse::NotFound().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,21 +85,13 @@ impl FlowController {
|
|||||||
ctx.insert("active_page", "flows");
|
ctx.insert("active_page", "flows");
|
||||||
ctx.insert("user", &user);
|
ctx.insert("user", &user);
|
||||||
|
|
||||||
let rendered = tmpl.render("flows/create_flow.html", &ctx)
|
render_template(&tmpl, "flows/create_flow.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
log::error!("Template rendering error: {}", e);
|
|
||||||
log::error!("Error details: {:?}", e);
|
|
||||||
log::error!("Context: {:?}", ctx);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the create flow form submission
|
/// Handles the create flow form submission
|
||||||
pub async fn create_flow(
|
pub async fn create_flow(
|
||||||
_form: web::Form<FlowForm>,
|
_form: web::Form<FlowForm>,
|
||||||
session: Session
|
_session: Session
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
// In a real application, we would create a new flow here
|
// In a real application, we would create a new flow here
|
||||||
// For now, just redirect to the flows list
|
// For now, just redirect to the flows list
|
||||||
@ -149,15 +116,7 @@ impl FlowController {
|
|||||||
ctx.insert("user", &user);
|
ctx.insert("user", &user);
|
||||||
ctx.insert("flows", &my_flows);
|
ctx.insert("flows", &my_flows);
|
||||||
|
|
||||||
let rendered = tmpl.render("flows/my_flows.html", &ctx)
|
render_template(&tmpl, "flows/my_flows.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
log::error!("Template rendering error: {}", e);
|
|
||||||
log::error!("Error details: {:?}", e);
|
|
||||||
log::error!("Context: {:?}", ctx);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
} else {
|
} else {
|
||||||
Ok(HttpResponse::Found()
|
Ok(HttpResponse::Found()
|
||||||
.append_header(("Location", "/login"))
|
.append_header(("Location", "/login"))
|
||||||
|
@ -5,6 +5,7 @@ use serde_json::Value;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use chrono::{Utc, Duration};
|
use chrono::{Utc, Duration};
|
||||||
use crate::models::governance::{Proposal, Vote, ProposalStatus, VoteType, VotingResults};
|
use crate::models::governance::{Proposal, Vote, ProposalStatus, VoteType, VotingResults};
|
||||||
|
use crate::utils::render_template;
|
||||||
|
|
||||||
/// Controller for handling governance-related routes
|
/// Controller for handling governance-related routes
|
||||||
pub struct GovernanceController;
|
pub struct GovernanceController;
|
||||||
@ -35,13 +36,7 @@ impl GovernanceController {
|
|||||||
let stats = Self::get_mock_statistics();
|
let stats = Self::get_mock_statistics();
|
||||||
ctx.insert("stats", &stats);
|
ctx.insert("stats", &stats);
|
||||||
|
|
||||||
let rendered = tmpl.render("governance/index.html", &ctx)
|
render_template(&tmpl, "governance/index.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the proposal list page route
|
/// Handles the proposal list page route
|
||||||
@ -59,13 +54,7 @@ impl GovernanceController {
|
|||||||
let proposals = Self::get_mock_proposals();
|
let proposals = Self::get_mock_proposals();
|
||||||
ctx.insert("proposals", &proposals);
|
ctx.insert("proposals", &proposals);
|
||||||
|
|
||||||
let rendered = tmpl.render("governance/proposals.html", &ctx)
|
render_template(&tmpl, "governance/proposals.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the proposal detail page route
|
/// Handles the proposal detail page route
|
||||||
@ -96,23 +85,18 @@ impl GovernanceController {
|
|||||||
let results = Self::get_mock_voting_results(&proposal_id);
|
let results = Self::get_mock_voting_results(&proposal_id);
|
||||||
ctx.insert("results", &results);
|
ctx.insert("results", &results);
|
||||||
|
|
||||||
let rendered = tmpl.render("governance/proposal_detail.html", &ctx)
|
render_template(&tmpl, "governance/proposal_detail.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
} else {
|
} else {
|
||||||
// Proposal not found
|
// Proposal not found
|
||||||
ctx.insert("error", "Proposal not found");
|
ctx.insert("error", "Proposal not found");
|
||||||
let rendered = tmpl.render("error.html", &ctx)
|
// For the error page, we'll use a special case to set the status code to 404
|
||||||
.map_err(|e| {
|
match tmpl.render("error.html", &ctx) {
|
||||||
eprintln!("Template rendering error: {}", e);
|
Ok(content) => Ok(HttpResponse::NotFound().content_type("text/html").body(content)),
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
Err(e) => {
|
||||||
})?;
|
eprintln!("Error rendering error template: {}", e);
|
||||||
|
Err(actix_web::error::ErrorInternalServerError(format!("Error: {}", e)))
|
||||||
Ok(HttpResponse::NotFound().content_type("text/html").body(rendered))
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,18 +114,12 @@ impl GovernanceController {
|
|||||||
return Ok(HttpResponse::Found().append_header(("Location", "/login")).finish());
|
return Ok(HttpResponse::Found().append_header(("Location", "/login")).finish());
|
||||||
}
|
}
|
||||||
|
|
||||||
let rendered = tmpl.render("governance/create_proposal.html", &ctx)
|
render_template(&tmpl, "governance/create_proposal.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the submission of a new proposal
|
/// Handles the submission of a new proposal
|
||||||
pub async fn submit_proposal(
|
pub async fn submit_proposal(
|
||||||
form: web::Form<ProposalForm>,
|
_form: web::Form<ProposalForm>,
|
||||||
tmpl: web::Data<Tera>,
|
tmpl: web::Data<Tera>,
|
||||||
session: Session
|
session: Session
|
||||||
) -> Result<impl Responder> {
|
) -> Result<impl Responder> {
|
||||||
@ -166,19 +144,13 @@ impl GovernanceController {
|
|||||||
let proposals = Self::get_mock_proposals();
|
let proposals = Self::get_mock_proposals();
|
||||||
ctx.insert("proposals", &proposals);
|
ctx.insert("proposals", &proposals);
|
||||||
|
|
||||||
let rendered = tmpl.render("governance/proposals.html", &ctx)
|
render_template(&tmpl, "governance/proposals.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the submission of a vote on a proposal
|
/// Handles the submission of a vote on a proposal
|
||||||
pub async fn submit_vote(
|
pub async fn submit_vote(
|
||||||
path: web::Path<String>,
|
path: web::Path<String>,
|
||||||
form: web::Form<VoteForm>,
|
_form: web::Form<VoteForm>,
|
||||||
tmpl: web::Data<Tera>,
|
tmpl: web::Data<Tera>,
|
||||||
session: Session
|
session: Session
|
||||||
) -> Result<impl Responder> {
|
) -> Result<impl Responder> {
|
||||||
@ -211,23 +183,18 @@ impl GovernanceController {
|
|||||||
let results = Self::get_mock_voting_results(&proposal_id);
|
let results = Self::get_mock_voting_results(&proposal_id);
|
||||||
ctx.insert("results", &results);
|
ctx.insert("results", &results);
|
||||||
|
|
||||||
let rendered = tmpl.render("governance/proposal_detail.html", &ctx)
|
render_template(&tmpl, "governance/proposal_detail.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
} else {
|
} else {
|
||||||
// Proposal not found
|
// Proposal not found
|
||||||
ctx.insert("error", "Proposal not found");
|
ctx.insert("error", "Proposal not found");
|
||||||
let rendered = tmpl.render("error.html", &ctx)
|
// For the error page, we'll use a special case to set the status code to 404
|
||||||
.map_err(|e| {
|
match tmpl.render("error.html", &ctx) {
|
||||||
eprintln!("Template rendering error: {}", e);
|
Ok(content) => Ok(HttpResponse::NotFound().content_type("text/html").body(content)),
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
Err(e) => {
|
||||||
})?;
|
eprintln!("Error rendering error template: {}", e);
|
||||||
|
Err(actix_web::error::ErrorInternalServerError(format!("Error: {}", e)))
|
||||||
Ok(HttpResponse::NotFound().content_type("text/html").body(rendered))
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -245,13 +212,7 @@ impl GovernanceController {
|
|||||||
let votes = Self::get_mock_votes_for_user(1); // Assuming user ID 1 for mock data
|
let votes = Self::get_mock_votes_for_user(1); // Assuming user ID 1 for mock data
|
||||||
ctx.insert("votes", &votes);
|
ctx.insert("votes", &votes);
|
||||||
|
|
||||||
let rendered = tmpl.render("governance/my_votes.html", &ctx)
|
render_template(&tmpl, "governance/my_votes.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
} else {
|
} else {
|
||||||
// Redirect to login if not logged in
|
// Redirect to login if not logged in
|
||||||
Ok(HttpResponse::Found().append_header(("Location", "/login")).finish())
|
Ok(HttpResponse::Found().append_header(("Location", "/login")).finish())
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
use actix_web::{web, HttpResponse, Responder, Result};
|
use actix_web::{web, Responder, Result};
|
||||||
use actix_session::Session;
|
use actix_session::Session;
|
||||||
use tera::Tera;
|
use tera::Tera;
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
|
|
||||||
|
use crate::utils::render_template;
|
||||||
|
|
||||||
/// Controller for handling home-related routes
|
/// Controller for handling home-related routes
|
||||||
pub struct HomeController;
|
pub struct HomeController;
|
||||||
|
|
||||||
@ -24,13 +26,7 @@ impl HomeController {
|
|||||||
ctx.insert("user", &user);
|
ctx.insert("user", &user);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rendered = tmpl.render("editor.html", &ctx)
|
render_template(&tmpl, "editor.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the home page route
|
/// Handles the home page route
|
||||||
@ -43,13 +39,7 @@ impl HomeController {
|
|||||||
ctx.insert("user", &user);
|
ctx.insert("user", &user);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rendered = tmpl.render("index.html", &ctx)
|
render_template(&tmpl, "index.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the about page route
|
/// Handles the about page route
|
||||||
@ -62,13 +52,7 @@ impl HomeController {
|
|||||||
ctx.insert("user", &user);
|
ctx.insert("user", &user);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rendered = tmpl.render("about.html", &ctx)
|
render_template(&tmpl, "about.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles the contact page route
|
/// Handles the contact page route
|
||||||
@ -81,13 +65,7 @@ impl HomeController {
|
|||||||
ctx.insert("user", &user);
|
ctx.insert("user", &user);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rendered = tmpl.render("contact.html", &ctx)
|
render_template(&tmpl, "contact.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles form submissions from the contact page
|
/// Handles form submissions from the contact page
|
||||||
@ -112,13 +90,7 @@ impl HomeController {
|
|||||||
ctx.insert("user", &user);
|
ctx.insert("user", &user);
|
||||||
}
|
}
|
||||||
|
|
||||||
let rendered = tmpl.render("contact.html", &ctx)
|
render_template(&tmpl, "contact.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ use tera::Tera;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
use crate::models::{User, Ticket, TicketComment, TicketStatus, TicketPriority};
|
use crate::models::{User, Ticket, TicketComment, TicketStatus, TicketPriority};
|
||||||
|
use crate::utils::render_template;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
@ -131,13 +132,7 @@ impl TicketController {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// Render the template
|
// Render the template
|
||||||
let rendered = tmpl.render("tickets/list.html", &ctx)
|
render_template(&tmpl, "tickets/list.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shows the form for creating a new ticket
|
/// Shows the form for creating a new ticket
|
||||||
@ -172,13 +167,7 @@ impl TicketController {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// Render the template
|
// Render the template
|
||||||
let rendered = tmpl.render("tickets/new.html", &ctx)
|
render_template(&tmpl, "tickets/new.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new ticket
|
/// Creates a new ticket
|
||||||
@ -285,13 +274,7 @@ impl TicketController {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// Render the template
|
// Render the template
|
||||||
let rendered = tmpl.render("tickets/show.html", &ctx)
|
render_template(&tmpl, "tickets/show.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a comment to a ticket
|
/// Adds a comment to a ticket
|
||||||
@ -443,12 +426,6 @@ impl TicketController {
|
|||||||
ctx.insert("my_tickets", &true);
|
ctx.insert("my_tickets", &true);
|
||||||
|
|
||||||
// Render the template
|
// Render the template
|
||||||
let rendered = tmpl.render("tickets/list.html", &ctx)
|
render_template(&tmpl, "tickets/list.html", &ctx)
|
||||||
.map_err(|e| {
|
|
||||||
eprintln!("Template rendering error: {}", e);
|
|
||||||
actix_web::error::ErrorInternalServerError("Template rendering error")
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(HttpResponse::Ok().content_type("text/html").body(rendered))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
|
use actix_web::{error, Error, HttpResponse};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use tera::{self, Function, Result, Value};
|
use tera::{self, Context, Function, Tera, Value};
|
||||||
|
|
||||||
// Export modules
|
// Export modules
|
||||||
pub mod redis_service;
|
pub mod redis_service;
|
||||||
@ -7,6 +8,22 @@ pub mod redis_service;
|
|||||||
// Re-export for easier imports
|
// Re-export for easier imports
|
||||||
pub use redis_service::RedisCalendarService;
|
pub use redis_service::RedisCalendarService;
|
||||||
|
|
||||||
|
/// Error type for template rendering
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TemplateError {
|
||||||
|
pub message: String,
|
||||||
|
pub details: String,
|
||||||
|
pub location: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::fmt::Display for TemplateError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Template error in {}: {}", self.location, self.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for TemplateError {}
|
||||||
|
|
||||||
/// Registers custom Tera functions
|
/// Registers custom Tera functions
|
||||||
pub fn register_tera_functions(tera: &mut tera::Tera) {
|
pub fn register_tera_functions(tera: &mut tera::Tera) {
|
||||||
tera.register_function("now", NowFunction);
|
tera.register_function("now", NowFunction);
|
||||||
@ -18,7 +35,7 @@ pub fn register_tera_functions(tera: &mut tera::Tera) {
|
|||||||
pub struct NowFunction;
|
pub struct NowFunction;
|
||||||
|
|
||||||
impl Function for NowFunction {
|
impl Function for NowFunction {
|
||||||
fn call(&self, args: &std::collections::HashMap<String, Value>) -> Result<Value> {
|
fn call(&self, args: &std::collections::HashMap<String, Value>) -> tera::Result<Value> {
|
||||||
let format = match args.get("format") {
|
let format = match args.get("format") {
|
||||||
Some(val) => match val.as_str() {
|
Some(val) => match val.as_str() {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
@ -43,7 +60,7 @@ impl Function for NowFunction {
|
|||||||
pub struct FormatDateFunction;
|
pub struct FormatDateFunction;
|
||||||
|
|
||||||
impl Function for FormatDateFunction {
|
impl Function for FormatDateFunction {
|
||||||
fn call(&self, args: &std::collections::HashMap<String, Value>) -> Result<Value> {
|
fn call(&self, args: &std::collections::HashMap<String, Value>) -> tera::Result<Value> {
|
||||||
let timestamp = match args.get("timestamp") {
|
let timestamp = match args.get("timestamp") {
|
||||||
Some(val) => match val.as_i64() {
|
Some(val) => match val.as_i64() {
|
||||||
Some(ts) => ts,
|
Some(ts) => ts,
|
||||||
@ -96,6 +113,50 @@ pub fn truncate_string(s: &str, max_length: usize) -> String {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Renders a template with error handling
|
||||||
|
///
|
||||||
|
/// This function attempts to render a template and handles any errors by rendering
|
||||||
|
/// the error template with detailed error information.
|
||||||
|
pub fn render_template(
|
||||||
|
tmpl: &Tera,
|
||||||
|
template_name: &str,
|
||||||
|
ctx: &Context,
|
||||||
|
) -> Result<HttpResponse, Error> {
|
||||||
|
match tmpl.render(template_name, ctx) {
|
||||||
|
Ok(content) => Ok(HttpResponse::Ok().content_type("text/html").body(content)),
|
||||||
|
Err(e) => {
|
||||||
|
// Log the error
|
||||||
|
log::error!("Template rendering error: {}", e);
|
||||||
|
log::error!("Error details: {:?}", e);
|
||||||
|
log::error!("Context: {:?}", ctx);
|
||||||
|
|
||||||
|
// Create a context for the error template
|
||||||
|
let mut error_ctx = Context::new();
|
||||||
|
error_ctx.insert("error", &format!("Template rendering error: {}", e));
|
||||||
|
error_ctx.insert("error_details", &format!("{:?}", e));
|
||||||
|
error_ctx.insert("error_location", &template_name);
|
||||||
|
|
||||||
|
// Try to render the error template
|
||||||
|
match tmpl.render("error.html", &error_ctx) {
|
||||||
|
Ok(error_page) => {
|
||||||
|
// Return the error page with a 500 status code
|
||||||
|
Ok(HttpResponse::InternalServerError()
|
||||||
|
.content_type("text/html")
|
||||||
|
.body(error_page))
|
||||||
|
}
|
||||||
|
Err(render_err) => {
|
||||||
|
// If we can't render the error template, log it and return a basic error
|
||||||
|
log::error!("Error rendering error template: {}", render_err);
|
||||||
|
Err(error::ErrorInternalServerError(format!(
|
||||||
|
"Template rendering error: {}. Failed to render error page: {}",
|
||||||
|
e, render_err
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -7,18 +7,44 @@
|
|||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<div class="card border-danger">
|
<div class="card border-danger">
|
||||||
<div class="card-header bg-danger text-white">
|
<div class="card-header bg-danger text-white">
|
||||||
<h4 class="mb-0"><i class="bi bi-exclamation-triangle-fill me-2"></i>Error</h4>
|
<h4 class="mb-0"><i class="bi bi-exclamation-triangle-fill me-2"></i>Template Rendering Error</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">Something went wrong</h5>
|
<h5 class="card-title">Something went wrong while rendering the template</h5>
|
||||||
<p class="card-text">{{ error }}</p>
|
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
<p class="mb-2"><strong>Error Message:</strong></p>
|
||||||
|
<pre class="p-3 bg-light border rounded"><code>{{ error | default(value="Unknown error") }}</code></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{% if error_details is defined and error_details %}
|
||||||
|
<div class="mt-3">
|
||||||
|
<p class="mb-2"><strong>Error Details:</strong></p>
|
||||||
|
<pre class="p-3 bg-light border rounded"><code>{{ error_details }}</code></pre>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if error_location is defined and error_location %}
|
||||||
|
<div class="mt-3">
|
||||||
|
<p class="mb-2"><strong>Error Location:</strong></p>
|
||||||
|
<p>{{ error_location }}</p>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<div class="alert alert-info mt-3">
|
||||||
|
<p class="mb-0"><i class="bi bi-info-circle me-2"></i>This error is visible only in development mode. In production, a generic error page will be shown.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mt-4">
|
<div class="mt-4">
|
||||||
<a href="/" class="btn btn-primary me-2">
|
<a href="/" class="btn btn-primary me-2">
|
||||||
<i class="bi bi-house-door me-1"></i>Go to Home
|
<i class="bi bi-house-door me-1"></i>Go to Home
|
||||||
</a>
|
</a>
|
||||||
<a href="javascript:history.back()" class="btn btn-outline-secondary">
|
<a href="javascript:history.back()" class="btn btn-outline-secondary me-2">
|
||||||
<i class="bi bi-arrow-left me-1"></i>Go Back
|
<i class="bi bi-arrow-left me-1"></i>Go Back
|
||||||
</a>
|
</a>
|
||||||
|
<button onclick="window.location.reload()" class="btn btn-outline-primary">
|
||||||
|
<i class="bi bi-arrow-clockwise me-1"></i>Reload Page
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
{% extends "base.html" %}
|
{% extends "base.html" %}
|
||||||
|
|
||||||
{% block title %}All Flows{% endblock %}
|
{% block title %}Freezone Workflows{% endblock %}
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<nav aria-label="breadcrumb">
|
<nav aria-label="breadcrumb">
|
||||||
<ol class="breadcrumb">
|
<ol class="breadcrumb">
|
||||||
<li class="breadcrumb-item"><a href="/flows">Flows</a></li>
|
<li class="breadcrumb-item"><a href="/flows">Workflows</a></li>
|
||||||
<li class="breadcrumb-item active" aria-current="page">All Flows</li>
|
<li class="breadcrumb-item active" aria-current="page">Freezone Workflows</li>
|
||||||
</ol>
|
</ol>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
@ -16,11 +16,11 @@
|
|||||||
|
|
||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
<h1 class="display-5 mb-0">All Flows</h1>
|
<h1 class="display-5 mb-0">Freezone Workflow Management</h1>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4 text-md-end">
|
<div class="col-md-4 text-md-end">
|
||||||
<a href="/flows/create" class="btn btn-primary">
|
<a href="/flows/create" class="btn btn-primary">
|
||||||
<i class="bi bi-plus-circle me-1"></i> Create New Flow
|
<i class="bi bi-plus-circle me-1"></i> Create New Workflow
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -31,7 +31,7 @@
|
|||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<form class="row g-3" action="/flows/list" method="get">
|
<form class="row g-3" action="/flows/list" method="get">
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="status" class="form-label">Status</label>
|
<label for="status" class="form-label">Status</label>
|
||||||
<select class="form-select" id="status" name="status">
|
<select class="form-select" id="status" name="status">
|
||||||
<option value="all" selected>All</option>
|
<option value="all" selected>All</option>
|
||||||
@ -41,19 +41,34 @@
|
|||||||
<option value="cancelled">Cancelled</option>
|
<option value="cancelled">Cancelled</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<!-- Freezone filter - for UI demonstration only -->
|
||||||
<label for="type" class="form-label">Type</label>
|
<div class="col-md-3">
|
||||||
|
<label for="freezone" class="form-label">Freezone</label>
|
||||||
|
<select class="form-select" id="freezone" name="freezone" disabled>
|
||||||
|
<option value="all" selected>All Freezones</option>
|
||||||
|
<option value="dubai_multi_commodities_centre">DMCC</option>
|
||||||
|
<option value="dubai_international_financial_centre">DIFC</option>
|
||||||
|
<option value="jebel_ali_free_zone">JAFZA</option>
|
||||||
|
<option value="dubai_silicon_oasis">DSO</option>
|
||||||
|
<option value="dubai_internet_city">DIC</option>
|
||||||
|
<option value="dubai_media_city">DMC</option>
|
||||||
|
<option value="abu_dhabi_global_market">ADGM</option>
|
||||||
|
</select>
|
||||||
|
<div class="form-text">Coming soon</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-3">
|
||||||
|
<label for="type" class="form-label">Workflow Type</label>
|
||||||
<select class="form-select" id="type" name="type">
|
<select class="form-select" id="type" name="type">
|
||||||
<option value="all" selected>All</option>
|
<option value="all" selected>All</option>
|
||||||
<option value="company_registration">Company Registration</option>
|
<option value="company_registration">Company Incorporation</option>
|
||||||
<option value="user_onboarding">User Onboarding</option>
|
<option value="user_onboarding">KYC Verification</option>
|
||||||
<option value="service_activation">Service Activation</option>
|
<option value="service_activation">License Activation</option>
|
||||||
<option value="payment_processing">Payment Processing</option>
|
<option value="payment_processing">Payment Processing</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-4">
|
<div class="col-md-3">
|
||||||
<label for="search" class="form-label">Search</label>
|
<label for="search" class="form-label">Search</label>
|
||||||
<input type="text" class="form-control" id="search" name="search" placeholder="Search flows...">
|
<input type="text" class="form-control" id="search" name="search" placeholder="Search workflows...">
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 text-end">
|
<div class="col-12 text-end">
|
||||||
<button type="submit" class="btn btn-primary">
|
<button type="submit" class="btn btn-primary">
|
||||||
@ -79,14 +94,14 @@
|
|||||||
<table class="table table-hover">
|
<table class="table table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Flow Name</th>
|
<th>Workflow Name</th>
|
||||||
<th>Type</th>
|
<th>Type</th>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<th>Owner</th>
|
<th>Assignee</th>
|
||||||
<th>Progress</th>
|
<th>Progress</th>
|
||||||
<th>Created</th>
|
<th>Initiated</th>
|
||||||
<th>Updated</th>
|
<th>Last Updated</th>
|
||||||
<th>Current Step</th>
|
<th>Current Stage</th>
|
||||||
<th>Actions</th>
|
<th>Actions</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -120,21 +135,21 @@
|
|||||||
{{ current.name }}
|
{{ current.name }}
|
||||||
{% else %}
|
{% else %}
|
||||||
{% if flow.status == 'Completed' %}
|
{% if flow.status == 'Completed' %}
|
||||||
All steps completed
|
<span class="text-success">All stages completed</span>
|
||||||
{% elif flow.status == 'Cancelled' %}
|
{% elif flow.status == 'Cancelled' %}
|
||||||
Flow cancelled
|
<span class="text-secondary">Workflow cancelled</span>
|
||||||
{% else %}
|
{% else %}
|
||||||
No active step
|
<span class="text-muted">No active stage</span>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
<a href="/flows/{{ flow.id }}" class="btn btn-sm btn-primary">
|
<a href="/flows/{{ flow.id }}" class="btn btn-sm btn-primary" title="View Details">
|
||||||
<i class="bi bi-eye"></i>
|
<i class="bi bi-eye"></i>
|
||||||
</a>
|
</a>
|
||||||
{% if flow.status == 'In Progress' %}
|
{% if flow.status == 'In Progress' %}
|
||||||
<a href="/flows/{{ flow.id }}#advance" class="btn btn-sm btn-success">
|
<a href="/flows/{{ flow.id }}#advance" class="btn btn-sm btn-success" title="Advance to Next Stage">
|
||||||
<i class="bi bi-arrow-right"></i>
|
<i class="bi bi-arrow-right"></i>
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@ -146,7 +161,11 @@
|
|||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="text-center">No flows found matching your criteria.</p>
|
<div class="text-center py-4">
|
||||||
|
<i class="bi bi-search display-1 text-muted"></i>
|
||||||
|
<p class="lead mt-3">No workflows found matching your criteria.</p>
|
||||||
|
<p class="text-muted">Try adjusting your filters or create a new workflow.</p>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user