package action import ( "context" "encoding/json" "fmt" "github.com/rockliang/poimen/workflows/pkg/db" ) // CanvasWithRelationsData combines canvas nodes/edges with relation wording type CanvasWithRelationsData struct { WorkflowID string `json:"workflow_id"` Version int `json:"version"` Nodes []db.WorkflowNode `json:"nodes"` Edges []db.WorkflowEdge `json:"edges"` Relations []EdgeWithWording `json:"relations"` UpdatedAt string `json:"updated_at"` } // FetchCanvasRelationsInput parameters type FetchCanvasRelationsInput struct { WorkflowID string `json:"workflow_id"` Version int `json:"version"` } // FetchCanvasRelationsActivity fetches canvas + relations from DB func FetchCanvasRelationsActivity(ctx context.Context, input FetchCanvasRelationsInput) (CanvasWithRelationsData, error) { logger := newActivityLogger(ctx) output := CanvasWithRelationsData{ WorkflowID: input.WorkflowID, Version: input.Version, Nodes: []db.WorkflowNode{}, Edges: []db.WorkflowEdge{}, Relations: []EdgeWithWording{}, } logger.logf("info", "Fetching canvas relations: %s v%d", input.WorkflowID, input.Version) // Get database client from context or activity manager dbClient, ok := ctx.Value("db_client").(*db.Client) if !ok { return output, fmt.Errorf("database client not in context") } // Fetch workflow workflow, err := dbClient.GetWorkflow(ctx, input.WorkflowID) if err != nil { return output, fmt.Errorf("failed to get workflow: %w", err) } // Parse canvas nodes and edges var nodes []db.WorkflowNode if err := json.Unmarshal([]byte(workflow.Nodes), &nodes); err != nil { return output, fmt.Errorf("failed to parse nodes: %w", err) } var edges []db.WorkflowEdge if err := json.Unmarshal([]byte(workflow.Edges), &edges); err != nil { return output, fmt.Errorf("failed to parse edges: %w", err) } output.Nodes = nodes output.Edges = edges output.UpdatedAt = workflow.UpdatedAt.String() // Fetch workflow relations relations, err := dbClient.GetWorkflowRelations(ctx, input.WorkflowID, input.Version) if err != nil { // Relations may not exist for old canvases - this is OK logger.logf("warn", "Failed to fetch relations: %v", err) return output, nil } // Map to EdgeWithWording for _, rel := range relations { edge := EdgeWithWording{ ID: rel.ID, Source: rel.SourceNodeID, Target: rel.TargetNodeID, RelationType: rel.RelationType, RelationLabel: rel.Label, CreatedAt: rel.CreatedAt.String(), } // Parse relation wording JSON if err := json.Unmarshal(rel.RelationWording, &edge.RelationWording); err != nil { logger.logf("warn", "Failed to parse relation wording: %v", err) } output.Relations = append(output.Relations, edge) } logger.logf("info", "Fetched %d nodes, %d edges, %d relations", len(output.Nodes), len(output.Edges), len(output.Relations)) return output, nil }