From 8c2276de7994b44ee4fc6d0584c358edddee87bf Mon Sep 17 00:00:00 2001 From: timurgordon Date: Tue, 27 May 2025 11:42:52 +0300 Subject: [PATCH] flowbroker wip --- actix_mvc_app/src/views/auth/register.html | 1003 +++++++++++++++-- actix_mvc_app/src/views/flows/index copy.html | 411 +++++++ actix_mvc_app/src/views/flows/index.html | 282 +++-- flowbroker/Cargo.lock | 29 +- flowbroker/src/main.rs | 142 +-- flowbroker/templates/index.html | 321 +++++- 6 files changed, 1883 insertions(+), 305 deletions(-) create mode 100644 actix_mvc_app/src/views/flows/index copy.html diff --git a/actix_mvc_app/src/views/auth/register.html b/actix_mvc_app/src/views/auth/register.html index a2f030f..94f45df 100644 --- a/actix_mvc_app/src/views/auth/register.html +++ b/actix_mvc_app/src/views/auth/register.html @@ -3,11 +3,14 @@ {% block title %}Register for Digital Freezone Residence{% endblock %} {% block content %} -
-
-

Register for Digital Freezone Residence

-
-
+
+ +
+

Digital Freezone Registration

+

Complete the steps below to register for your Digital Freezone Residence

+
+
+ {% if errors %} {% endif %} -
- -
-
Step 1 of 2
-
- - -
-
- 1 Personal Info -
-
- 2 Contracts & KYC -
-
- - -
-

Personal Information

-
-
- - + +
+ +
+ + +
+

Connect Your Digital ID

+
+ + First step: Connect or create your Digital ID to start the registration process. This allows us to verify your identity and check for any existing registrations.
-
- - + +
+
+ +
+ + +
+
Your digital identity for secure signing and blockchain transactions.
+
+ +
+
+
+
+
Why Connect Your Digital ID First?
+
    +
  • Verify your unique identity in the digital freezone
  • +
  • Check for any existing registrations or applications
  • +
  • Prepare for secure contract signing in later steps
  • +
  • Enable blockchain-based identity verification
  • +
+
+
+
+
-
-
- - -
Your digital identity for secure signing and blockchain transactions.
+ + - -
diff --git a/actix_mvc_app/src/views/flows/index copy.html b/actix_mvc_app/src/views/flows/index copy.html new file mode 100644 index 0000000..2464034 --- /dev/null +++ b/actix_mvc_app/src/views/flows/index copy.html @@ -0,0 +1,411 @@ +{% extends "base.html" %} + +{% block title %}Flows Dashboard{% endblock %} + +{% block content %} + +
+
+ +
+
+ + +
+
+
+ +
About Workflows
+

The workflow system helps you track and manage business processes across your organization. Create new workflows, monitor progress, and collaborate with team members to ensure smooth operations.

+ +
+
+
+ + +
+ +
+
+
+
Workflows with Pending Actions
+ +
+
+ {% if flows and flows|length > 0 %} +
+ + + + + + + + + + + + + {% for flow in flows %} + + + + + + + + + {% endfor %} + +
WorkflowTypeCurrent StepLast UpdatedOwnerActions
+
+
+
+ +
+
+
+ {{ flow.name }} +
ID: {{ flow.id }}
+
+
+
{{ flow.flow_type }} + {% if flow.current_step %} + {{ flow.current_step.name }} +
{{ flow.current_step.description }}
+ {% else %} + No pending step + {% endif %} +
+ {{ flow.updated_at | date(format="%Y-%m-%d") }} + {% if flow.status == 'Stuck' %} +
May need attention
+ {% else %} +
Last updated
+ {% endif %} +
+
+
+
+ {{ flow.owner_name }} +
+
+
{{ flow.owner_name }}
+
+
+ +
+
+ {% else %} +
+ +
No Pending Actions
+

There are no workflows that require your immediate attention.

+
+ {% endif %} +
+
+
+ + +
+
+
+
Recent Activity
+ View All +
+
+ {% if flows and flows|length > 0 %} +
+ {% set count = 0 %} + {% for flow in flows %} + {% if count < 8 %} + {% set count = count + 1 %} +
+
+
+
+ +
+
+
+
+
+ {% if flow.status == 'In Progress' %}Working on{% elif flow.status == 'Completed' %}Completed{% elif flow.status == 'Stuck' %}Stuck at{% else %}Updated{% endif %} + {% if flow.current_step %} {{ flow.current_step.name }}{% endif %} +
+
{{ flow.updated_at | date(format="%H:%M") }}
+
+ +
by {{ flow.owner_name }}
+
+
+
+ {% endif %} + {% endfor %} +
+ + {% else %} +
+
+ +
No Recent Activity
+

Activity will appear here as workflows progress.

+
+
+ {% endif %} +
+
+
+
+ + +
+
+
+
+
Workflow Filters
+ +
+
+
+
+
+ + +
+ +
+ + +
Coming soon
+
+
+ + +
+
+ + +
+
+ + + Clear Filters + +
+
+
+
+
+
+
+ + +
+
+
+
+
Active Workflows (Recent Updates)
+ View All +
+
+
+ {% set count = 0 %} + {% for flow in flows %} + {% if count < 3 and flow.status == 'In Progress' %} +
+
+
+
{{ flow.name }}
+
Owner: {{ flow.owner_name }}
+
+ {{ flow.flow_type }} +
+

Current stage: + {% set current = flow.current_step %} + {% if current %} + {{ current.name }} + {% else %} + No active stage + {% endif %} +

+
+
{{ flow.progress_percentage }}%
+
+
+ Updated: {{ flow.updated_at | date(format="%Y-%m-%d") }} + View Details +
+
+
+
+ {% set count = count + 1 %} + {% endif %} + {% endfor %} + {% if count == 0 %} +
+ +
No active workflows
+

All workflows are either completed or not yet started.

+ Create New Workflow +
+ {% endif %} +
+
+
+
+
+ + +
+
+
+
+
Recent Workflows
+ View All Workflows +
+
+ {% if flows|length > 0 %} +
+ + + + + + + + + + + + + + + + {% for flow in flows %} + + + + + + + + + + + + {% endfor %} + +
Workflow NameTypeStatusAssigneeProgressInitiatedLast UpdatedCurrent StageActions
+ {{ flow.name }} + {{ flow.flow_type }} + + {{ flow.status }} + + {{ flow.owner_name }} +
+
{{ flow.progress_percentage }}%
+
+
{{ flow.created_at | date(format="%Y-%m-%d") }}{{ flow.updated_at | date(format="%Y-%m-%d") }} + {% set current = flow.current_step %} + {% if current %} + {{ current.name }} + {% else %} + {% if flow.status == 'Completed' %} + All stages completed + {% elif flow.status == 'Cancelled' %} + Workflow cancelled + {% else %} + No active stage + {% endif %} + {% endif %} + +
+ + + + {% if flow.status == 'In Progress' %} + + + + {% endif %} +
+
+
+ {% else %} +
+ +

No workflows found matching your criteria.

+

Try adjusting your filters or create a new workflow.

+
+ {% endif %} +
+
+
+
+ +{% endblock %} diff --git a/actix_mvc_app/src/views/flows/index.html b/actix_mvc_app/src/views/flows/index.html index 33ff456..f25932d 100644 --- a/actix_mvc_app/src/views/flows/index.html +++ b/actix_mvc_app/src/views/flows/index.html @@ -3,122 +3,188 @@ {% block title %}Flows Dashboard{% endblock %} {% block content %} -
-
-

Flows Dashboard

-

Track and manage workflow processes across the organization.

-
- -
- - -
-
-
-
-
Total Flows
-

{{ stats.total_flows }}

-
-
-
-
-
-
-
In Progress
-

{{ stats.in_progress_flows }}

-
-
-
-
-
-
-
Stuck
-

{{ stats.stuck_flows }}

-
-
-
-
-
-
-
Completed
-

{{ stats.completed_flows }}

-
-
-
-
- - -
+ +
-
-
-
Filter Workflows
-
-
-
-
- - -
- -
- - -
Coming soon
-
-
- - -
-
- - -
-
- - - Clear Filters - -
-
+ +
+
+ + +
+
+
+ +
About Workflows
+

The workflow system helps you track and manage business processes across your organization. Create new workflows, monitor progress, and collaborate with team members to ensure smooth operations.

+
- + +
+ +
+
+
+
Workflows with Pending Actions
+ +
+
+ {% if flows and flows|length > 0 %} +
+ + + + + + + + + + + + {% for flow in flows %} + + + + + + + + {% endfor %} + +
WorkflowTypeCurrent StepLast UpdatedActions
+
+
+
+ +
+
+
+ {{ flow.name }} +
ID: {{ flow.id }}
+
+
+
{{ flow.flow_type }} + {% if flow.current_step %} + {{ flow.current_step.name }} +
{{ flow.current_step.description }}
+ {% else %} + No pending step + {% endif %} +
+ {{ flow.updated_at | date(format="%Y-%m-%d") }} + {% if flow.status == 'Stuck' %} +
May need attention
+ {% else %} +
Last updated
+ {% endif %} +
+ +
+
+ {% else %} +
+ +
No Pending Actions
+

There are no workflows that require your immediate attention.

+
+ {% endif %} +
+
+
+ + +
+
+
+
Recent Activity
+ View All +
+
+ {% if flows and flows|length > 0 %} +
+ {% set count = 0 %} + {% for flow in flows %} + {% if count < 8 %} + {% set count = count + 1 %} +
+
+
+
+ +
+
+
+
+
+ {% if flow.status == 'In Progress' %}Working on{% elif flow.status == 'Completed' %}Completed{% elif flow.status == 'Stuck' %}Stuck at{% else %}Updated{% endif %} + {% if flow.current_step %} {{ flow.current_step.name }}{% endif %} +
+
{{ flow.updated_at | date(format="%H:%M") }}
+
+ +
+
+
+ {% endif %} + {% endfor %} +
+ + {% else %} +
+
+ +
No Recent Activity
+

Activity will appear here as workflows progress.

+
+
+ {% endif %} +
+
+
+
+ +
-
-
All Workflows
+
+
Recent Workflows
+ View All Workflows
{% if flows|length > 0 %} @@ -129,7 +195,6 @@ Workflow Name Type Status - Assignee Progress Initiated Last Updated @@ -150,7 +215,6 @@ {{ flow.status }} - {{ flow.owner_name }}
) -> ActixResult { - let mut context = Context::new(); - - match data.db.collection::() { - Ok(flow_collection) => { - match flow_collection.get_all() { - Ok(mut flows_vec) => { - // Sort by creation date, newest first - flows_vec.sort_by(|a, b| b.base_data.created_at.cmp(&a.base_data.created_at)); - context.insert("flows", &flows_vec); - }, - Err(e) => { - error!("Failed to retrieve flows from database: {:?}", e); - // Optionally, insert an empty vec or an error message for the template - context.insert("flows", &Vec::::new()); - context.insert("db_error", "Failed to load flows."); - } - } - }, - Err(e) => { - error!("Failed to get flow collection from database: {}", e); - context.insert("flows", &Vec::::new()); - context.insert("db_error", "Database collection error."); - } - } - - let rendered = data.templates.render("index.html", &context) - .map_err(|e| { - error!("Template error (index.html): {}", e); - actix_web::error::ErrorInternalServerError("Template error rendering index.html") - })?; - Ok(HttpResponse::Ok().content_type("text/html").body(rendered)) -} - -// Show form to create a new flow -#[derive(Serialize, Clone)] // Clone is for the context, Serialize for Tera -struct RhaiExampleScript { +// --- Context Structs for Templates --- +#[derive(Serialize, Clone)] +struct RhaiExampleDisplay { name: String, content: String, } -async fn new_flow_form(data: web::Data) -> impl Responder { - let mut context = Context::new(); - let mut example_scripts = Vec::new(); - let examples_path = PathBuf::from("templates/rhai_examples"); +#[derive(Serialize)] +struct ListFlowsContext { + flows: Vec, // Using heromodels::models::flowbroker_models::Flow + example_scripts: Vec, + error_message: Option, + success_message: Option, +} +// --- Handlers --- + +// Display list of flows +async fn list_flows(data: web::Data) -> ActixResult { + let tera = &data.templates; + + // Fetch actual flows from the database + let flows_collection = data.db.collection::() + .map_err(|e| actix_web::error::ErrorInternalServerError(format!("DB Error: Failed to get flows collection: {}", e)))?; + let (mut flows, flow_error_message) = match flows_collection.get_all() { + Ok(mut flows_vec) => { + flows_vec.sort_by(|a, b| b.base_data.created_at.cmp(&a.base_data.created_at)); // Sort by newest + (flows_vec, None) + }, + Err(e) => { + error!("Failed to fetch flows: {:?}", e); + (Vec::new(), Some(format!("Error fetching flows: {:?}", e))) + } + }; + + // Load Rhai example scripts + let examples_path = PathBuf::from("templates/rhai_examples"); + let mut example_scripts_display = Vec::new(); if examples_path.is_dir() { match std_fs::read_dir(examples_path) { Ok(entries) => { for entry in entries { if let Ok(entry) = entry { let path = entry.path(); - if path.is_file() && path.extension().and_then(|s| s.to_str()) == Some("rhai") { + if path.is_file() && path.extension().and_then(std::ffi::OsStr::to_str) == Some("rhai") { + let file_stem = path.file_stem().and_then(std::ffi::OsStr::to_str).unwrap_or("Unknown Script"); + // Convert filename (e.g., simple_two_step) to a nicer name (e.g., Simple Two Step) + let script_name = file_stem.replace("_", " ") + .split_whitespace() + .map(|word| { + let mut c = word.chars(); + match c.next() { + None => String::new(), + Some(f) => f.to_uppercase().collect::() + c.as_str(), + } + }) + .collect::>().join(" "); + match std_fs::read_to_string(&path) { Ok(content) => { - let file_stem = path.file_stem().and_then(|s| s.to_str()).unwrap_or("Unknown Script"); - // Convert filename (e.g., simple_two_step) to a nicer name (e.g., Simple Two Step) - let name = file_stem.replace("_", " ") - .split_whitespace() - .map(|word| { - let mut c = word.chars(); - match c.next() { - None => String::new(), - Some(f) => f.to_uppercase().collect::() + c.as_str(), - } - }) - .collect::>().join(" "); - example_scripts.push(RhaiExampleScript { name, content }); + example_scripts_display.push(RhaiExampleDisplay { name: script_name, content }); } Err(e) => { - error!("Failed to read Rhai example script {}: {}", path.display(), e); + error!("Failed to read Rhai example script {:?}: {}", path, e); } } } @@ -219,20 +208,31 @@ async fn new_flow_form(data: web::Data) -> impl Responder { } } Err(e) => { - error!("Failed to read rhai_examples directory: {}", e); + error!("Failed to read Rhai examples directory: {}", e); } } } + example_scripts_display.sort_by(|a, b| a.name.cmp(&b.name)); - context.insert("example_scripts", &example_scripts); - info!("Rendering new flow form with {} examples from files.", example_scripts.len()); - match data.templates.render("new_flow_form.html", &context) { - Ok(rendered) => HttpResponse::Ok().body(rendered), - Err(e) => { - error!("Template error in new_flow_form: {}", e); - HttpResponse::InternalServerError().body(format!("Template error: {}", e)) - } - } + let list_context = ListFlowsContext { + flows, + example_scripts: example_scripts_display, + error_message: flow_error_message, + success_message: None, // TODO: Populate from query params or session later if needed + }; + + let tera_ctx = Context::from_serialize(&list_context).unwrap_or_else(|e| { + error!("Failed to serialize ListFlowsContext: {}", e); + // Fallback to a minimal context or an error state if serialization fails + let mut err_ctx = Context::new(); + err_ctx.insert("error_message", &"Critical error preparing page data.".to_string()); + err_ctx + }); + + // Still rendering to index.html, which will be the revamped list_flows.html + let rendered = tera.render("index.html", &tera_ctx) + .map_err(|e| actix_web::error::ErrorInternalServerError(format!("Template error (index.html): {}", e)))?; + Ok(HttpResponse::Ok().content_type("text/html").body(rendered)) } // Handle creation of a new flow @@ -646,7 +646,7 @@ pub fn configure_app_routes(cfg: &mut web::ServiceConfig) { .service( web::scope("/flows") // Group flow-related routes under /flows // .route("", web::get().to(list_flows)) // If you want /flows to also list flows - .route("/new", web::get().to(new_flow_form)) + // .route("/new", web::get().to(new_flow_form)) // Deprecated, functionality merged into root list_flows .route("/create", web::post().to(create_flow)) .route("/create_script", web::post().to(create_flow_from_script)) // Moved inside /flows scope ) diff --git a/flowbroker/templates/index.html b/flowbroker/templates/index.html index 0848a55..44bcc01 100644 --- a/flowbroker/templates/index.html +++ b/flowbroker/templates/index.html @@ -2,27 +2,316 @@ - Flowbroker - Flows + + FlowBroker Dashboard + + -

Active Flows

- Create New Flow -
- {% if flows %} -
    - {% for flow in flows %} -
  • - {{ flow.name }} (UUID: {{ flow.flow_uuid }}) - Status: {{ flow.status }} -
    - Created: {{ flow.base_data.created_at | date(format="%Y-%m-%d %H:%M:%S") }} -

    View Details

    +
+
+
+ + +
+ {% if error_message %} + {% endif %} + {% if success_message %} + + {% endif %} + +

Active Flows

+
+ {% if flows %} + + + + + + + + + + + + {% for flow in flows %} + + + + + + + + {% endfor %} + +
NameUUIDStatusCreated AtActions
{{ flow.name }}{{ flow.flow_uuid }}{{ flow.status | default(value="Unknown") }}{{ flow.base_data.created_at | date(format="%Y-%m-%d %H:%M:%S") }} + View + +
+ {% else %} +

No active flows found. You can create one below.

+ {% endif %} +
+ +
+ +

Runnable Example Scripts

+
+ {% if example_scripts %} +
    + {% for example in example_scripts %} +
  • + {{ example.name }} + +
  • + {% endfor %} +
+ {% else %} +

No example scripts found.

+ {% endif %} +
+ +
+ +
+
+

Create New Flow from Rhai Script

+
+
+
+ + +
+ +
+
+
+
+

Create New Flow (Step-by-Step UI)

+
+
+
+ + +
+
+ +
+ +

Steps will appear here as you add them.

+
+ + +
+ +
+
+
+
+
+ + + + + + + + +