Skip to content

Commit

Permalink
Markdown generation for Flows
Browse files Browse the repository at this point in the history
First version of Markdown documentation generation for Flows
  • Loading branch information
modery committed Nov 8, 2022
1 parent b7ec236 commit 4275c7b
Show file tree
Hide file tree
Showing 7 changed files with 768 additions and 184 deletions.
282 changes: 282 additions & 0 deletions PowerDocu.FlowDocumenter/FlowDocumentationContent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,282 @@
using System;
using System.Collections.Generic;
using System.Linq;
using PowerDocu.Common;

namespace PowerDocu.FlowDocumenter
{
class FlowDocumentationContent
{
public string folderPath, filename;
public FlowMetadata metadata;
public FlowOverview overview;
public FlowConnectionReferences connectionReferences;
public FlowTrigger trigger;
public FlowVariables variables;
public FlowDetails details;
public FlowActions actions;

public FlowDocumentationContent(FlowEntity flow, string path)
{
folderPath = path + CharsetHelper.GetSafeName(@"\FlowDoc - " + flow.Name + @"\");
filename = CharsetHelper.GetSafeName(flow.Name) + ((flow.ID != null) ? ("(" + flow.ID + ")") : "");
metadata = new FlowMetadata(flow);
overview = new FlowOverview();
connectionReferences = new FlowConnectionReferences(flow);
trigger = new FlowTrigger(flow);
variables = new FlowVariables(flow);
details = new FlowDetails();
actions = new FlowActions(flow);
NotificationHelper.SendNotification("Preparing documentation content for " + flow.Name);
}
}

public class FlowMetadata
{
public string Name;
public string ID;
public string header;
public Dictionary<string, string> metadataTable;

public FlowMetadata(FlowEntity flow)
{
ID = flow.ID;
Name = flow.Name;
header = "Flow Documentation - " + Name;
metadataTable = new Dictionary<string, string>
{
{ "Flow Name", flow.Name }
};
if (!String.IsNullOrEmpty(flow.ID))
{
metadataTable.Add("Flow ID", flow.ID);
}
metadataTable.Add("Documentation generated at", DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString());
metadataTable.Add("Number of Variables", "" + flow.actions.ActionNodes.Count(o => o.Type == "InitializeVariable"));
metadataTable.Add("Number of Actions", "" + flow.actions.ActionNodes.Count);
}
}

public class FlowOverview
{
public string header;
public string infoText;
public string pngFile = "flow.png";
public string svgFile = "flow.svg";

public FlowOverview()
{
header = "Flow Overview";
infoText = "The following chart shows the top level layout of the Flow. For a detailed view, please visit the section called Detailed Flow Diagram";
}
}

public class FlowConnectionReferences
{
public string header;
public string infoText;
public Dictionary<string, Dictionary<string, string>> connectionTable;
public FlowConnectionReferences(FlowEntity flow)
{
header = "Connections";
infoText = $"There are a total of {flow.connectionReferences.Count} connections used in this Flow:";
connectionTable = new Dictionary<string, Dictionary<string, string>>();
foreach (ConnectionReference cRef in flow.connectionReferences)
{
string connectorUniqueName = cRef.Name;
Dictionary<string, string> connectionDetailsTable = new Dictionary<string, string>
{
{ "Connection Type", cRef.Type.ToString() }
};
if (cRef.Type == ConnectionType.ConnectorReference)
{
if (!String.IsNullOrEmpty(cRef.ConnectionReferenceLogicalName))
connectionDetailsTable.Add("Connection Reference Name", cRef.ConnectionReferenceLogicalName);
}
if (!String.IsNullOrEmpty(cRef.ID))
{
connectionDetailsTable.Add("ID", cRef.ID);
}
if (!String.IsNullOrEmpty(cRef.Source))
{
connectionDetailsTable.Add("Source", cRef.Source);
}
connectionTable.TryAdd(connectorUniqueName, connectionDetailsTable);
}
}
}

public class FlowTrigger
{
public string header;
public string infoText;
public Dictionary<string, string> triggerTable;
public List<Expression> inputs;
public string inputsHeader = "Inputs Details";
public List<Expression> triggerProperties;
public string triggerPropertiesHeader = "Other Trigger Properties";
public FlowTrigger(FlowEntity flow)
{
header = "Trigger";

triggerTable = new Dictionary<string, string>
{
{ "Name", flow.trigger.Name },
{ "Type", flow.trigger.Type }
};
if (!String.IsNullOrEmpty(flow.trigger.Connector))
{
triggerTable.Add("Connector", flow.trigger.Connector);
}
//Description = a Note added
if (!String.IsNullOrEmpty(flow.trigger.Description))
{
triggerTable.Add("Description / Note", flow.trigger.Description);
}
if (flow.trigger.Recurrence.Count > 0)
{
triggerTable.Add("Recurrence Details", "mergedrow");
foreach (KeyValuePair<string, string> properties in flow.trigger.Recurrence)
{
triggerTable.Add(properties.Key, properties.Value);
}
}
if (flow.trigger.Inputs.Count > 0)
{
inputs = flow.trigger.Inputs;
}
if (flow.trigger.TriggerProperties.Count > 0)
{
triggerProperties = flow.trigger.TriggerProperties;
}
}
}

public class FlowVariables
{
public string header = "Variables";
public Dictionary<string, Dictionary<string, string>> variablesTable;
public Dictionary<string, List<ActionNode>> referencesTable;
public Dictionary<string, Dictionary<string, string>> initialValTable;
public FlowVariables(FlowEntity flow)
{
variablesTable = new Dictionary<string, Dictionary<string, string>>();
referencesTable = new Dictionary<string, List<ActionNode>>();
initialValTable = new Dictionary<string, Dictionary<string, string>>();
List<ActionNode> variablesNodes = flow.actions.ActionNodes.Where(o => o.Type == "InitializeVariable").OrderBy(o => o.Name).ToList();
List<ActionNode> modifyVariablesNodes = flow.actions.ActionNodes.Where(o => o.Type == "SetVariable" || o.Type == "IncrementVariable").ToList();
foreach (ActionNode node in variablesNodes)
{
foreach (Expression exp in node.actionInputs)
{
if (exp.expressionOperator == "variables")
{
Dictionary<string, string> variableValueTable = new Dictionary<string, string>();
string vname = "";
string vtype = "";
foreach (Expression expO in exp.expressionOperands)
{
if (expO.expressionOperator == "name")
{
vname = expO.expressionOperands[0].ToString();
}
if (expO.expressionOperator == "type")
{
vtype = expO.expressionOperands[0].ToString();
}
if (expO.expressionOperator == "value")
{
if (expO.expressionOperands.Count == 1)
{
variableValueTable.Add(expO.expressionOperands[0].ToString(), "");
}
else
{
foreach (var eop in expO.expressionOperands)
{
if (eop.GetType() == typeof(string))
{
variableValueTable.Add(eop.ToString(), "");
}
else
{
variableValueTable.Add(((Expression)eop).expressionOperator,
(((Expression)eop).expressionOperands.Count > 0) ? ((Expression)eop).expressionOperands[0].ToString() : "");
}
}
}
}
}
List<ActionNode> referencedInNodes = new List<ActionNode>
{
node
};
foreach (ActionNode actionNode in modifyVariablesNodes)
{
foreach (Expression expO in actionNode.actionInputs)
{
if (expO.expressionOperator == "name")
{
if (expO.expressionOperands[0].ToString().Equals(vname))
{
referencedInNodes.Add(actionNode);
}
}
}
}
foreach (ActionNode actionNode in flow.actions.ActionNodes)
{
if (actionNode.actionExpression?.ToString().Contains($"@variables('{vname}')") == true
|| actionNode.Expression?.Contains($"@variables('{vname}')") == true
|| actionNode.actionInput?.ToString().Contains($"@variables('{vname}')") == true)
{
referencedInNodes.Add(actionNode);
}
else
{
foreach (Expression actionInput in actionNode.actionInputs)
{
if (actionInput.ToString().Contains($"@variables('{vname}')"))
{
referencedInNodes.Add(actionNode);
}
}
}
}

Dictionary<string, string> variableDetailsTable = new Dictionary<string, string>
{
{ "Name", vname },
{"Type",vtype},
{"Initial Value", ""}
};
variablesTable.Add(vname, variableDetailsTable);
referencesTable.Add(vname, referencedInNodes);
initialValTable.Add(vname, variableValueTable);
}
}
}
}
}

public class FlowDetails
{
public string header = "Detailed Flow Diagram";
public string infoText = "The following chart shows the detailed layout of the Flow";
public string imageFileName = "flow-detailed";
}

public class FlowActions
{
public string header = "Actions";
public string infoText = "";
public Dictionary<string, Dictionary<string, string>> actionsTable;
public List<ActionNode> actionNodesList;
public FlowActions(FlowEntity flow)
{
actionsTable = new Dictionary<string, Dictionary<string, string>>();
actionNodesList = flow.actions.ActionNodes.OrderBy(o => o.Name).ToList();
infoText = $"There are a total of {actionNodesList.Count} actions used in this Flow:";
}
}
}
22 changes: 16 additions & 6 deletions PowerDocu.FlowDocumenter/FlowDocumentationGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace PowerDocu.FlowDocumenter
{
public static class FlowDocumentationGenerator
{
public static void GenerateWordDocumentation(string filePath, string wordTemplate = null)
public static void GenerateDocumentation(string filePath, string fileFormat, string wordTemplate = null)
{
if (File.Exists(filePath))
{
Expand All @@ -22,17 +22,27 @@ public static void GenerateWordDocumentation(string filePath, string wordTemplat
GraphBuilder gbzip = new GraphBuilder(flow, path);
gbzip.buildTopLevelGraph();
gbzip.buildDetailedGraph();
if (String.IsNullOrEmpty(wordTemplate) || !File.Exists(wordTemplate))
FlowDocumentationContent content = new FlowDocumentationContent(flow, path);
if (fileFormat.Equals(OutputFormatHelper.Word) || fileFormat.Equals(OutputFormatHelper.All))
{
FlowWordDocBuilder wordzip = new FlowWordDocBuilder(flow, path, null);
NotificationHelper.SendNotification("Creating Word documentation");
if (String.IsNullOrEmpty(wordTemplate) || !File.Exists(wordTemplate))
{
FlowWordDocBuilder wordzip = new FlowWordDocBuilder(content, null);
}
else
{
FlowWordDocBuilder wordzip = new FlowWordDocBuilder(content, wordTemplate);
}
}
else
if (fileFormat.Equals(OutputFormatHelper.Markdown) || fileFormat.Equals(OutputFormatHelper.All))
{
FlowWordDocBuilder wordzip = new FlowWordDocBuilder(flow, path, wordTemplate);
NotificationHelper.SendNotification("Creating Markdown documentation");
FlowMarkdownBuilder markdownFile = new FlowMarkdownBuilder(content);
}
}
DateTime endDocGeneration = DateTime.Now;
NotificationHelper.SendNotification("FlowDocumenter: Created Word documentation for " + filePath + ". A total of " + flowParserFromZip.getFlows().Count + " files were processed in " + (endDocGeneration - startDocGeneration).TotalSeconds + " seconds.");
NotificationHelper.SendNotification("FlowDocumenter: Created documentation for " + filePath + ". A total of " + flowParserFromZip.getFlows().Count + " files were processed in " + (endDocGeneration - startDocGeneration).TotalSeconds + " seconds.");
}
else
{
Expand Down
4 changes: 2 additions & 2 deletions PowerDocu.FlowDocumenter/FlowDocumenter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ static void Main(string[] args)
else
{
if (args.Length == 1)
FlowDocumentationGenerator.GenerateWordDocumentation(args[0]);
FlowDocumentationGenerator.GenerateDocumentation(args[0], "All");
if (args.Length == 2)
FlowDocumentationGenerator.GenerateWordDocumentation(args[0], args[1]);
FlowDocumentationGenerator.GenerateDocumentation(args[0], "All", args[1]);
}
}
}
Expand Down
Loading

0 comments on commit 4275c7b

Please sign in to comment.