634 lines
28 KiB
Rust
634 lines
28 KiB
Rust
use actix_web::{web, HttpResponse, Responder, Result};
|
|
use actix_session::Session;
|
|
use chrono::{Utc, Duration};
|
|
use serde::Deserialize;
|
|
use tera::Tera;
|
|
|
|
use crate::models::flow::{Flow, FlowStatus, FlowType, FlowStatistics, FlowStep, StepStatus, FlowLog};
|
|
use crate::controllers::auth::Claims;
|
|
use crate::utils::render_template;
|
|
|
|
pub struct FlowController;
|
|
|
|
impl FlowController {
|
|
/// Renders the flows dashboard
|
|
pub async fn index(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
|
let user = Self::get_user_from_session(&session);
|
|
let flows = Self::get_mock_flows();
|
|
let stats = FlowStatistics::new(&flows);
|
|
|
|
let mut ctx = tera::Context::new();
|
|
ctx.insert("active_page", "flows");
|
|
ctx.insert("user", &user);
|
|
ctx.insert("flows", &flows);
|
|
ctx.insert("stats", &stats);
|
|
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<_>>());
|
|
|
|
render_template(&tmpl, "flows/index.html", &ctx)
|
|
}
|
|
|
|
/// Renders the flows list page
|
|
pub async fn list_flows(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
|
let user = Self::get_user_from_session(&session);
|
|
let flows = Self::get_mock_flows();
|
|
|
|
let mut ctx = tera::Context::new();
|
|
ctx.insert("active_page", "flows");
|
|
ctx.insert("user", &user);
|
|
ctx.insert("flows", &flows);
|
|
|
|
render_template(&tmpl, "flows/flows.html", &ctx)
|
|
}
|
|
|
|
/// Renders the flow detail page
|
|
pub async fn flow_detail(
|
|
path: web::Path<String>,
|
|
tmpl: web::Data<Tera>,
|
|
session: Session
|
|
) -> Result<impl Responder> {
|
|
let flow_id = path.into_inner();
|
|
let user = Self::get_user_from_session(&session);
|
|
|
|
// Find the flow with the given ID
|
|
let flows = Self::get_mock_flows();
|
|
let flow = flows.iter().find(|f| f.id == flow_id);
|
|
|
|
if let Some(flow) = flow {
|
|
let mut ctx = tera::Context::new();
|
|
ctx.insert("active_page", "flows");
|
|
ctx.insert("user", &user);
|
|
ctx.insert("flow", flow);
|
|
|
|
render_template(&tmpl, "flows/flow_detail.html", &ctx)
|
|
} else {
|
|
let mut ctx = tera::Context::new();
|
|
ctx.insert("active_page", "flows");
|
|
ctx.insert("error", "Flow not found");
|
|
|
|
// For the error page, we'll use a special case to set the status code to 404
|
|
match tmpl.render("error.html", &ctx) {
|
|
Ok(content) => Ok(HttpResponse::NotFound().content_type("text/html").body(content)),
|
|
Err(e) => {
|
|
log::error!("Error rendering error template: {}", e);
|
|
Err(actix_web::error::ErrorInternalServerError(format!("Error: {}", e)))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Renders the create flow page
|
|
pub async fn create_flow_form(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
|
let user = Self::get_user_from_session(&session);
|
|
|
|
let mut ctx = tera::Context::new();
|
|
ctx.insert("active_page", "flows");
|
|
ctx.insert("user", &user);
|
|
|
|
render_template(&tmpl, "flows/create_flow.html", &ctx)
|
|
}
|
|
|
|
/// Handles the create flow form submission
|
|
pub async fn create_flow(
|
|
_form: web::Form<FlowForm>,
|
|
_session: Session
|
|
) -> impl Responder {
|
|
// In a real application, we would create a new flow here
|
|
// For now, just redirect to the flows list
|
|
|
|
HttpResponse::Found()
|
|
.append_header(("Location", "/flows"))
|
|
.finish()
|
|
}
|
|
|
|
/// Renders the my flows page
|
|
pub async fn my_flows(tmpl: web::Data<Tera>, session: Session) -> Result<impl Responder> {
|
|
let user = Self::get_user_from_session(&session);
|
|
|
|
if let Some(user) = &user {
|
|
let flows = Self::get_mock_flows();
|
|
let my_flows = flows.iter()
|
|
.filter(|f| f.owner_name == user.sub)
|
|
.collect::<Vec<_>>();
|
|
|
|
let mut ctx = tera::Context::new();
|
|
ctx.insert("active_page", "flows");
|
|
ctx.insert("user", &user);
|
|
ctx.insert("flows", &my_flows);
|
|
|
|
render_template(&tmpl, "flows/my_flows.html", &ctx)
|
|
} else {
|
|
Ok(HttpResponse::Found()
|
|
.append_header(("Location", "/login"))
|
|
.finish())
|
|
}
|
|
}
|
|
|
|
/// Handles the advance flow step action
|
|
pub async fn advance_flow_step(
|
|
path: web::Path<String>,
|
|
_session: Session
|
|
) -> impl Responder {
|
|
let flow_id = path.into_inner();
|
|
|
|
// In a real application, we would advance the flow step here
|
|
// For now, just redirect to the flow detail page
|
|
|
|
HttpResponse::Found()
|
|
.append_header(("Location", format!("/flows/{}", flow_id)))
|
|
.finish()
|
|
}
|
|
|
|
/// Handles the mark flow step as stuck action
|
|
pub async fn mark_flow_step_stuck(
|
|
path: web::Path<String>,
|
|
_form: web::Form<StuckForm>,
|
|
_session: Session
|
|
) -> impl Responder {
|
|
let flow_id = path.into_inner();
|
|
|
|
// In a real application, we would mark the flow step as stuck here
|
|
// For now, just redirect to the flow detail page
|
|
|
|
HttpResponse::Found()
|
|
.append_header(("Location", format!("/flows/{}", flow_id)))
|
|
.finish()
|
|
}
|
|
|
|
/// Handles the add log to flow step action
|
|
pub async fn add_log_to_flow_step(
|
|
path: web::Path<(String, String)>,
|
|
_form: web::Form<LogForm>,
|
|
_session: Session
|
|
) -> impl Responder {
|
|
let (flow_id, _step_id) = path.into_inner();
|
|
|
|
// In a real application, we would add a log to the flow step here
|
|
// For now, just redirect to the flow detail page
|
|
|
|
HttpResponse::Found()
|
|
.append_header(("Location", format!("/flows/{}", flow_id)))
|
|
.finish()
|
|
}
|
|
|
|
/// Gets the user from the session
|
|
fn get_user_from_session(session: &Session) -> Option<Claims> {
|
|
if let Ok(Some(user)) = session.get::<Claims>("user") {
|
|
Some(user)
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
/// Creates mock flow data for testing
|
|
fn get_mock_flows() -> Vec<Flow> {
|
|
let mut flows = Vec::new();
|
|
|
|
// Create a few mock flows
|
|
let mut flow1 = Flow {
|
|
id: "flow-1".to_string(),
|
|
name: "ZAZ Business Entity Registration".to_string(),
|
|
description: "Register a new business entity within the Zanzibar Autonomous Zone legal framework".to_string(),
|
|
flow_type: FlowType::CompanyRegistration,
|
|
status: FlowStatus::InProgress,
|
|
owner_id: "user-1".to_string(),
|
|
owner_name: "Ibrahim Faraji".to_string(),
|
|
steps: vec![
|
|
FlowStep {
|
|
id: "step-1-1".to_string(),
|
|
name: "Document Submission".to_string(),
|
|
description: "Submit required business registration documents including business plan, ownership structure, and KYC information".to_string(),
|
|
order: 1,
|
|
status: StepStatus::Completed,
|
|
started_at: Some(Utc::now() - Duration::days(5)),
|
|
completed_at: Some(Utc::now() - Duration::days(4)),
|
|
logs: vec![
|
|
FlowLog {
|
|
id: "log-1-1-1".to_string(),
|
|
message: "Initial document package submitted".to_string(),
|
|
timestamp: Utc::now() - Duration::days(5),
|
|
},
|
|
FlowLog {
|
|
id: "log-1-1-2".to_string(),
|
|
message: "Additional ownership verification documents requested".to_string(),
|
|
timestamp: Utc::now() - Duration::days(4) - Duration::hours(12),
|
|
},
|
|
FlowLog {
|
|
id: "log-1-1-3".to_string(),
|
|
message: "Additional documents submitted and verified".to_string(),
|
|
timestamp: Utc::now() - Duration::days(4),
|
|
},
|
|
],
|
|
},
|
|
FlowStep {
|
|
id: "step-1-2".to_string(),
|
|
name: "Regulatory Review".to_string(),
|
|
description: "ZAZ Business Registry review of submitted documents and compliance with regulatory requirements".to_string(),
|
|
order: 2,
|
|
status: StepStatus::InProgress,
|
|
started_at: Some(Utc::now() - Duration::days(3)),
|
|
completed_at: None,
|
|
logs: vec![
|
|
FlowLog {
|
|
id: "log-1-2-1".to_string(),
|
|
message: "Regulatory review initiated by ZAZ Business Registry".to_string(),
|
|
timestamp: Utc::now() - Duration::days(3),
|
|
},
|
|
FlowLog {
|
|
id: "log-1-2-2".to_string(),
|
|
message: "Preliminary compliance assessment completed".to_string(),
|
|
timestamp: Utc::now() - Duration::days(2),
|
|
},
|
|
FlowLog {
|
|
id: "log-1-2-3".to_string(),
|
|
message: "Awaiting final approval from regulatory committee".to_string(),
|
|
timestamp: Utc::now() - Duration::days(1),
|
|
},
|
|
],
|
|
},
|
|
FlowStep {
|
|
id: "step-1-3".to_string(),
|
|
name: "Digital Identity Creation".to_string(),
|
|
description: "Creation of the entity's digital identity and blockchain credentials within the ZAZ ecosystem".to_string(),
|
|
order: 3,
|
|
status: StepStatus::Pending,
|
|
started_at: None,
|
|
completed_at: None,
|
|
logs: vec![],
|
|
},
|
|
FlowStep {
|
|
id: "step-1-4".to_string(),
|
|
name: "License and Certificate Issuance".to_string(),
|
|
description: "Issuance of business licenses, certificates, and digital credentials".to_string(),
|
|
order: 4,
|
|
status: StepStatus::Pending,
|
|
started_at: None,
|
|
completed_at: None,
|
|
logs: vec![],
|
|
},
|
|
],
|
|
created_at: Utc::now() - Duration::days(5),
|
|
updated_at: Utc::now() - Duration::days(1),
|
|
completed_at: None,
|
|
progress_percentage: 40,
|
|
current_step: None,
|
|
};
|
|
|
|
// Update the current step
|
|
flow1.current_step = flow1.steps.iter().find(|s| s.status == StepStatus::InProgress).cloned();
|
|
|
|
let mut flow2 = Flow {
|
|
id: "flow-2".to_string(),
|
|
name: "Digital Asset Tokenization Approval".to_string(),
|
|
description: "Process for approving the tokenization of a real estate asset within the ZAZ regulatory framework".to_string(),
|
|
flow_type: FlowType::AssetTokenization,
|
|
status: FlowStatus::Completed,
|
|
owner_id: "user-2".to_string(),
|
|
owner_name: "Amina Salim".to_string(),
|
|
steps: vec![
|
|
FlowStep {
|
|
id: "step-2-1".to_string(),
|
|
name: "Asset Verification".to_string(),
|
|
description: "Verification of the underlying asset ownership and valuation".to_string(),
|
|
order: 1,
|
|
status: StepStatus::Completed,
|
|
started_at: Some(Utc::now() - Duration::days(30)),
|
|
completed_at: Some(Utc::now() - Duration::days(25)),
|
|
logs: vec![
|
|
FlowLog {
|
|
id: "log-2-1-1".to_string(),
|
|
message: "Asset documentation submitted for verification".to_string(),
|
|
timestamp: Utc::now() - Duration::days(30),
|
|
},
|
|
FlowLog {
|
|
id: "log-2-1-2".to_string(),
|
|
message: "Independent valuation completed by ZAZ Property Registry".to_string(),
|
|
timestamp: Utc::now() - Duration::days(27),
|
|
},
|
|
FlowLog {
|
|
id: "log-2-1-3".to_string(),
|
|
message: "Asset ownership and valuation verified".to_string(),
|
|
timestamp: Utc::now() - Duration::days(25),
|
|
},
|
|
],
|
|
},
|
|
FlowStep {
|
|
id: "step-2-2".to_string(),
|
|
name: "Tokenization Structure Review".to_string(),
|
|
description: "Review of the proposed token structure, distribution model, and compliance with ZAZ tokenization standards".to_string(),
|
|
order: 2,
|
|
status: StepStatus::Completed,
|
|
started_at: Some(Utc::now() - Duration::days(24)),
|
|
completed_at: Some(Utc::now() - Duration::days(20)),
|
|
logs: vec![
|
|
FlowLog {
|
|
id: "log-2-2-1".to_string(),
|
|
message: "Tokenization proposal submitted for review".to_string(),
|
|
timestamp: Utc::now() - Duration::days(24),
|
|
},
|
|
FlowLog {
|
|
id: "log-2-2-2".to_string(),
|
|
message: "Technical review completed by ZAZ Digital Assets Committee".to_string(),
|
|
timestamp: Utc::now() - Duration::days(22),
|
|
},
|
|
FlowLog {
|
|
id: "log-2-2-3".to_string(),
|
|
message: "Tokenization structure approved with minor modifications".to_string(),
|
|
timestamp: Utc::now() - Duration::days(20),
|
|
},
|
|
],
|
|
},
|
|
FlowStep {
|
|
id: "step-2-3".to_string(),
|
|
name: "Smart Contract Deployment".to_string(),
|
|
description: "Deployment and verification of the asset tokenization smart contracts".to_string(),
|
|
order: 3,
|
|
status: StepStatus::Completed,
|
|
started_at: Some(Utc::now() - Duration::days(19)),
|
|
completed_at: Some(Utc::now() - Duration::days(15)),
|
|
logs: vec![
|
|
FlowLog {
|
|
id: "log-2-3-1".to_string(),
|
|
message: "Smart contract code submitted for audit".to_string(),
|
|
timestamp: Utc::now() - Duration::days(19),
|
|
},
|
|
FlowLog {
|
|
id: "log-2-3-2".to_string(),
|
|
message: "Security audit completed with no critical issues".to_string(),
|
|
timestamp: Utc::now() - Duration::days(17),
|
|
},
|
|
FlowLog {
|
|
id: "log-2-3-3".to_string(),
|
|
message: "Smart contracts deployed to ZAZ-approved blockchain".to_string(),
|
|
timestamp: Utc::now() - Duration::days(15),
|
|
},
|
|
],
|
|
},
|
|
FlowStep {
|
|
id: "step-2-4".to_string(),
|
|
name: "Final Approval and Listing".to_string(),
|
|
description: "Final regulatory approval and listing on the ZAZ Digital Asset Exchange".to_string(),
|
|
order: 4,
|
|
status: StepStatus::Completed,
|
|
started_at: Some(Utc::now() - Duration::days(14)),
|
|
completed_at: Some(Utc::now() - Duration::days(10)),
|
|
logs: vec![
|
|
FlowLog {
|
|
id: "log-2-4-1".to_string(),
|
|
message: "Final documentation package submitted for approval".to_string(),
|
|
timestamp: Utc::now() - Duration::days(14),
|
|
},
|
|
FlowLog {
|
|
id: "log-2-4-2".to_string(),
|
|
message: "Regulatory approval granted by ZAZ Financial Authority".to_string(),
|
|
timestamp: Utc::now() - Duration::days(12),
|
|
},
|
|
FlowLog {
|
|
id: "log-2-4-3".to_string(),
|
|
message: "Asset tokens listed on ZAZ Digital Asset Exchange".to_string(),
|
|
timestamp: Utc::now() - Duration::days(10),
|
|
},
|
|
],
|
|
},
|
|
],
|
|
created_at: Utc::now() - Duration::days(30),
|
|
updated_at: Utc::now() - Duration::days(10),
|
|
completed_at: Some(Utc::now() - Duration::days(10)),
|
|
progress_percentage: 100,
|
|
current_step: None,
|
|
};
|
|
|
|
flow2.current_step = flow2.steps.last().cloned();
|
|
|
|
let mut flow3 = Flow {
|
|
id: "flow-3".to_string(),
|
|
name: "Sustainable Tourism Certification".to_string(),
|
|
description: "Application process for ZAZ Sustainable Tourism Certification for eco-tourism businesses".to_string(),
|
|
flow_type: FlowType::Certification,
|
|
status: FlowStatus::Stuck,
|
|
owner_id: "user-3".to_string(),
|
|
owner_name: "Hassan Mwinyi".to_string(),
|
|
steps: vec![
|
|
FlowStep {
|
|
id: "step-3-1".to_string(),
|
|
name: "Initial Application".to_string(),
|
|
description: "Submission of initial application and supporting documentation".to_string(),
|
|
order: 1,
|
|
status: StepStatus::Completed,
|
|
started_at: Some(Utc::now() - Duration::days(15)),
|
|
completed_at: Some(Utc::now() - Duration::days(12)),
|
|
logs: vec![
|
|
FlowLog {
|
|
id: "log-3-1-1".to_string(),
|
|
message: "Application submitted for Coral Reef Eco Tours".to_string(),
|
|
timestamp: Utc::now() - Duration::days(15),
|
|
},
|
|
FlowLog {
|
|
id: "log-3-1-2".to_string(),
|
|
message: "Application fee payment confirmed".to_string(),
|
|
timestamp: Utc::now() - Duration::days(14),
|
|
},
|
|
FlowLog {
|
|
id: "log-3-1-3".to_string(),
|
|
message: "Initial documentation review completed".to_string(),
|
|
timestamp: Utc::now() - Duration::days(12),
|
|
},
|
|
],
|
|
},
|
|
FlowStep {
|
|
id: "step-3-2".to_string(),
|
|
name: "Environmental Impact Assessment".to_string(),
|
|
description: "Assessment of the business's environmental impact and sustainability practices".to_string(),
|
|
order: 2,
|
|
status: StepStatus::Stuck,
|
|
started_at: Some(Utc::now() - Duration::days(11)),
|
|
completed_at: None,
|
|
logs: vec![
|
|
FlowLog {
|
|
id: "log-3-2-1".to_string(),
|
|
message: "Environmental assessment initiated".to_string(),
|
|
timestamp: Utc::now() - Duration::days(11),
|
|
},
|
|
FlowLog {
|
|
id: "log-3-2-2".to_string(),
|
|
message: "Site visit scheduled with environmental officer".to_string(),
|
|
timestamp: Utc::now() - Duration::days(9),
|
|
},
|
|
FlowLog {
|
|
id: "log-3-2-3".to_string(),
|
|
message: "STUCK: Missing required marine conservation plan documentation".to_string(),
|
|
timestamp: Utc::now() - Duration::days(7),
|
|
},
|
|
],
|
|
},
|
|
FlowStep {
|
|
id: "step-3-3".to_string(),
|
|
name: "Community Engagement Verification".to_string(),
|
|
description: "Verification of community engagement and benefit-sharing mechanisms".to_string(),
|
|
order: 3,
|
|
status: StepStatus::Pending,
|
|
started_at: None,
|
|
completed_at: None,
|
|
logs: vec![],
|
|
},
|
|
FlowStep {
|
|
id: "step-3-4".to_string(),
|
|
name: "Certification Issuance".to_string(),
|
|
description: "Final review and issuance of ZAZ Sustainable Tourism Certification".to_string(),
|
|
order: 4,
|
|
status: StepStatus::Pending,
|
|
started_at: None,
|
|
completed_at: None,
|
|
logs: vec![],
|
|
},
|
|
],
|
|
created_at: Utc::now() - Duration::days(15),
|
|
updated_at: Utc::now() - Duration::days(7),
|
|
completed_at: None,
|
|
progress_percentage: 35,
|
|
current_step: None,
|
|
};
|
|
|
|
flow3.current_step = flow3.steps.iter().find(|s| s.status == StepStatus::Stuck).cloned();
|
|
|
|
let mut flow4 = Flow {
|
|
id: "flow-4".to_string(),
|
|
name: "Digital Payment Provider License".to_string(),
|
|
description: "Application for a license to operate as a digital payment provider within the ZAZ financial system".to_string(),
|
|
flow_type: FlowType::LicenseApplication,
|
|
status: FlowStatus::InProgress,
|
|
owner_id: "user-4".to_string(),
|
|
owner_name: "Fatma Busaidy".to_string(),
|
|
steps: vec![
|
|
FlowStep {
|
|
id: "step-4-1".to_string(),
|
|
name: "Initial Application".to_string(),
|
|
description: "Submission of license application and company information".to_string(),
|
|
order: 1,
|
|
status: StepStatus::Completed,
|
|
started_at: Some(Utc::now() - Duration::days(20)),
|
|
completed_at: Some(Utc::now() - Duration::days(18)),
|
|
logs: vec![
|
|
FlowLog {
|
|
id: "log-4-1-1".to_string(),
|
|
message: "Application submitted for ZanziPay digital payment services".to_string(),
|
|
timestamp: Utc::now() - Duration::days(20),
|
|
},
|
|
FlowLog {
|
|
id: "log-4-1-2".to_string(),
|
|
message: "Application fee payment confirmed".to_string(),
|
|
timestamp: Utc::now() - Duration::days(19),
|
|
},
|
|
FlowLog {
|
|
id: "log-4-1-3".to_string(),
|
|
message: "Initial documentation review completed".to_string(),
|
|
timestamp: Utc::now() - Duration::days(18),
|
|
},
|
|
],
|
|
},
|
|
FlowStep {
|
|
id: "step-4-2".to_string(),
|
|
name: "Technical Infrastructure Review".to_string(),
|
|
description: "Review of the technical infrastructure, security measures, and compliance with ZAZ financial standards".to_string(),
|
|
order: 2,
|
|
status: StepStatus::Completed,
|
|
started_at: Some(Utc::now() - Duration::days(17)),
|
|
completed_at: Some(Utc::now() - Duration::days(10)),
|
|
logs: vec![
|
|
FlowLog {
|
|
id: "log-4-2-1".to_string(),
|
|
message: "Technical documentation submitted for review".to_string(),
|
|
timestamp: Utc::now() - Duration::days(17),
|
|
},
|
|
FlowLog {
|
|
id: "log-4-2-2".to_string(),
|
|
message: "Security audit initiated by ZAZ Financial Technology Office".to_string(),
|
|
timestamp: Utc::now() - Duration::days(15),
|
|
},
|
|
FlowLog {
|
|
id: "log-4-2-3".to_string(),
|
|
message: "Technical infrastructure approved with recommendations".to_string(),
|
|
timestamp: Utc::now() - Duration::days(10),
|
|
},
|
|
],
|
|
},
|
|
FlowStep {
|
|
id: "step-4-3".to_string(),
|
|
name: "AML/KYC Compliance Review".to_string(),
|
|
description: "Review of anti-money laundering and know-your-customer procedures".to_string(),
|
|
order: 3,
|
|
status: StepStatus::InProgress,
|
|
started_at: Some(Utc::now() - Duration::days(9)),
|
|
completed_at: None,
|
|
logs: vec![
|
|
FlowLog {
|
|
id: "log-4-3-1".to_string(),
|
|
message: "AML/KYC documentation submitted for review".to_string(),
|
|
timestamp: Utc::now() - Duration::days(9),
|
|
},
|
|
FlowLog {
|
|
id: "log-4-3-2".to_string(),
|
|
message: "Initial compliance assessment completed".to_string(),
|
|
timestamp: Utc::now() - Duration::days(5),
|
|
},
|
|
FlowLog {
|
|
id: "log-4-3-3".to_string(),
|
|
message: "Additional KYC procedure documentation requested".to_string(),
|
|
timestamp: Utc::now() - Duration::days(3),
|
|
},
|
|
],
|
|
},
|
|
FlowStep {
|
|
id: "step-4-4".to_string(),
|
|
name: "License Issuance".to_string(),
|
|
description: "Final review and issuance of Digital Payment Provider License".to_string(),
|
|
order: 4,
|
|
status: StepStatus::Pending,
|
|
started_at: None,
|
|
completed_at: None,
|
|
logs: vec![],
|
|
},
|
|
],
|
|
created_at: Utc::now() - Duration::days(20),
|
|
updated_at: Utc::now() - Duration::days(3),
|
|
completed_at: None,
|
|
progress_percentage: 65,
|
|
current_step: None,
|
|
};
|
|
|
|
flow4.current_step = flow4.steps.iter().find(|s| s.status == StepStatus::InProgress).cloned();
|
|
|
|
flows.push(flow1);
|
|
flows.push(flow2);
|
|
flows.push(flow3);
|
|
flows.push(flow4);
|
|
|
|
flows
|
|
}
|
|
}
|
|
|
|
/// Form for creating a new flow
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct FlowForm {
|
|
/// Flow name
|
|
pub name: String,
|
|
/// Flow description
|
|
pub description: String,
|
|
/// Flow type
|
|
pub flow_type: String,
|
|
}
|
|
|
|
/// Form for marking a step as stuck
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct StuckForm {
|
|
/// Reason for being stuck
|
|
pub reason: String,
|
|
}
|
|
|
|
/// Form for adding a log to a step
|
|
#[derive(Debug, Deserialize)]
|
|
pub struct LogForm {
|
|
/// Log message
|
|
pub message: String,
|
|
}
|