Step 585: add workflow visualization v2
This commit is contained in:
118
editor/src/WorkflowVisualizationV2.h
Normal file
118
editor/src/WorkflowVisualizationV2.h
Normal file
@@ -0,0 +1,118 @@
|
||||
#pragma once
|
||||
// Step 585: Workflow Visualization 2.0
|
||||
|
||||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
enum class WorkflowNodeKind {
|
||||
Intake,
|
||||
ReviewGate,
|
||||
TaskQueue,
|
||||
Execution,
|
||||
Verification
|
||||
};
|
||||
|
||||
struct WorkflowNodeVisual {
|
||||
std::string nodeId;
|
||||
WorkflowNodeKind kind = WorkflowNodeKind::Intake;
|
||||
std::string label;
|
||||
std::string accentColorHex = "#2F7BFF"; // electric-blue baseline
|
||||
};
|
||||
|
||||
struct WorkflowEdgeVisual {
|
||||
std::string edgeId;
|
||||
std::string fromNodeId;
|
||||
std::string toNodeId;
|
||||
std::string routingReason;
|
||||
};
|
||||
|
||||
struct WorkflowVisualizationGraph {
|
||||
std::vector<WorkflowNodeVisual> nodes;
|
||||
std::vector<WorkflowEdgeVisual> edges;
|
||||
};
|
||||
|
||||
class WorkflowVisualizationV2 {
|
||||
public:
|
||||
static bool addNode(WorkflowVisualizationGraph* graph,
|
||||
const WorkflowNodeVisual& node,
|
||||
std::string* error) {
|
||||
if (!graph || !error) return false;
|
||||
error->clear();
|
||||
if (node.nodeId.empty()) return fail(error, "node_id_missing");
|
||||
if (node.label.empty()) return fail(error, "node_label_missing");
|
||||
if (!isValidColor(node.accentColorHex)) return fail(error, "node_color_invalid");
|
||||
if (findNode(*graph, node.nodeId) != nullptr) return fail(error, "node_duplicate");
|
||||
graph->nodes.push_back(node);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool addEdge(WorkflowVisualizationGraph* graph,
|
||||
const WorkflowEdgeVisual& edge,
|
||||
std::string* error) {
|
||||
if (!graph || !error) return false;
|
||||
error->clear();
|
||||
if (edge.edgeId.empty()) return fail(error, "edge_id_missing");
|
||||
if (edge.fromNodeId.empty() || edge.toNodeId.empty()) return fail(error, "edge_endpoint_missing");
|
||||
if (edge.routingReason.empty()) return fail(error, "edge_reason_missing");
|
||||
if (findEdge(*graph, edge.edgeId) != nullptr) return fail(error, "edge_duplicate");
|
||||
if (!findNode(*graph, edge.fromNodeId) || !findNode(*graph, edge.toNodeId)) {
|
||||
return fail(error, "edge_node_missing");
|
||||
}
|
||||
graph->edges.push_back(edge);
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::vector<WorkflowEdgeVisual> outgoing(const WorkflowVisualizationGraph& graph,
|
||||
const std::string& nodeId) {
|
||||
std::vector<WorkflowEdgeVisual> out;
|
||||
for (const auto& edge : graph.edges) if (edge.fromNodeId == nodeId) out.push_back(edge);
|
||||
return out;
|
||||
}
|
||||
|
||||
static std::vector<std::string> plainLanguageRoutingSummary(
|
||||
const WorkflowVisualizationGraph& graph) {
|
||||
std::vector<std::string> lines;
|
||||
for (const auto& edge : graph.edges) {
|
||||
lines.push_back(edge.fromNodeId + " -> " + edge.toNodeId + ": " + edge.routingReason);
|
||||
}
|
||||
std::stable_sort(lines.begin(), lines.end());
|
||||
return lines;
|
||||
}
|
||||
|
||||
static std::vector<WorkflowNodeVisual> nodesByKind(const WorkflowVisualizationGraph& graph,
|
||||
WorkflowNodeKind kind) {
|
||||
std::vector<WorkflowNodeVisual> out;
|
||||
for (const auto& node : graph.nodes) if (node.kind == kind) out.push_back(node);
|
||||
return out;
|
||||
}
|
||||
|
||||
private:
|
||||
static bool fail(std::string* error, const char* code) {
|
||||
*error = code;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool isValidColor(const std::string& c) {
|
||||
if (c.size() != 7 || c[0] != '#') return false;
|
||||
for (size_t i = 1; i < c.size(); ++i) {
|
||||
const char x = c[i];
|
||||
const bool hex = (x >= '0' && x <= '9') || (x >= 'a' && x <= 'f') || (x >= 'A' && x <= 'F');
|
||||
if (!hex) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static const WorkflowNodeVisual* findNode(const WorkflowVisualizationGraph& graph,
|
||||
const std::string& nodeId) {
|
||||
for (const auto& node : graph.nodes) if (node.nodeId == nodeId) return &node;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static const WorkflowEdgeVisual* findEdge(const WorkflowVisualizationGraph& graph,
|
||||
const std::string& edgeId) {
|
||||
for (const auto& edge : graph.edges) if (edge.edgeId == edgeId) return &edge;
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user