Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ deno run \
--allow-read \
--allow-write \
jsr:@goog/flow-lens \
--diagramTool="graphviz" \
--diagramTool="mermaid" \
--gitRepo="/path/to/salesforce_project/" \
--gitDiffFromHash="HEAD~1" \
--gitDiffToHash="HEAD" \
Expand All @@ -336,8 +336,8 @@ deno run \
{
"path": "force-app/main/default/flows/Demo.flow-meta.xml",
"difference": {
"old": "digraph {\nlabel=<<B>Demo</B>>\ntitle = \"Demo\";\nlabelloc = \"t\";\nnode [shape=box, style=filled]\nSet_the_Description [\n label=<\n<TABLE CELLSPACING=\"0\" CELLPADDING=\"0\">\n <TR><TD BGCOLOR=\"WHITE\" WIDTH=\"20\"><FONT COLOR=\"red\"><B>-</B></FONT></TD>\n <TD>\n <B>Assignment ⬅️</B>\n </TD>\n </TR>\n <TR>\n <TD COLSPAN=\"2\"><U>Set the Description</U></TD>\n </TR>\n</TABLE>\n>\n color=\"#DD7A00\"\n fontcolor=\"white\"\n];\nGet_the_Acme_Account [\n label=<\n<TABLE CELLSPACING=\"0\" CELLPADDING=\"0\">\n <TR><TD BGCOLOR=\"WHITE\" WIDTH=\"20\"><FONT COLOR=\"#DD7A00\"><B>Δ</B></FONT></TD>\n <TD>\n <B>Record Lookup 🔍</B>\n </TD>\n </TR>\n <TR>\n <TD COLSPAN=\"2\"><U>Get the 'Acme' Account</U></TD>\n </TR>\n</TABLE>\n>\n color=\"#F9548A\"\n fontcolor=\"white\"\n];\nUpdate_the_Acme_Account [\n label=<\n<TABLE CELLSPACING=\"0\" CELLPADDING=\"0\">\n <TR><TD BGCOLOR=\"WHITE\" WIDTH=\"20\"><FONT COLOR=\"#DD7A00\"><B>Δ</B></FONT></TD>\n <TD>\n <B>Record Update ✏️</B>\n </TD>\n </TR>\n <TR>\n <TD COLSPAN=\"2\"><U>Update the 'Acme' Account</U></TD>\n </TR>\n</TABLE>\n>\n color=\"#F9548A\"\n fontcolor=\"white\"\n];\nFLOW_START -> Get_the_Acme_Account [label=\"\" color=\"black\" style=\"\"]\nGet_the_Acme_Account -> Set_the_Description [label=\"\" color=\"black\" style=\"\"]\nSet_the_Description -> Update_the_Acme_Account [label=\"\" color=\"black\" style=\"\"]\n}",
"new": "digraph {\nlabel=<<B>Demo</B>>\ntitle = \"Demo\";\nlabelloc = \"t\";\nnode [shape=box, style=filled]\nSet_the_Type [\n label=<\n<TABLE CELLSPACING=\"0\" CELLPADDING=\"0\">\n <TR><TD BGCOLOR=\"WHITE\" WIDTH=\"20\"><FONT COLOR=\"green\"><B>+</B></FONT></TD>\n <TD>\n <B>Assignment ⬅️</B>\n </TD>\n </TR>\n <TR>\n <TD COLSPAN=\"2\"><U>Set the Type</U></TD>\n </TR>\n</TABLE>\n>\n color=\"#DD7A00\"\n fontcolor=\"white\"\n];\nGet_the_Acme_Account [\n label=<\n<TABLE CELLSPACING=\"0\" CELLPADDING=\"0\">\n <TR><TD BGCOLOR=\"WHITE\" WIDTH=\"20\"><FONT COLOR=\"#DD7A00\"><B>Δ</B></FONT></TD>\n <TD>\n <B>Record Lookup 🔍</B>\n </TD>\n </TR>\n <TR>\n <TD COLSPAN=\"2\"><U>Get the 'Acme' Account</U></TD>\n </TR>\n</TABLE>\n>\n color=\"#F9548A\"\n fontcolor=\"white\"\n];\nUpdate_the_Acme_Account [\n label=<\n<TABLE CELLSPACING=\"0\" CELLPADDING=\"0\">\n <TR><TD BGCOLOR=\"WHITE\" WIDTH=\"20\"><FONT COLOR=\"#DD7A00\"><B>Δ</B></FONT></TD>\n <TD>\n <B>Record Update ✏️</B>\n </TD>\n </TR>\n <TR>\n <TD COLSPAN=\"2\"><U>Update the 'Acme' Account</U></TD>\n </TR>\n</TABLE>\n>\n color=\"#F9548A\"\n fontcolor=\"white\"\n];\nLog_Error [\n label=<\n<TABLE CELLSPACING=\"0\" CELLPADDING=\"0\">\n <TR><TD BGCOLOR=\"WHITE\" WIDTH=\"20\"><FONT COLOR=\"green\"><B>+</B></FONT></TD>\n <TD>\n <B>Action Call ⚡</B>\n </TD>\n </TR>\n <TR>\n <TD COLSPAN=\"2\"><U>Log Error</U></TD>\n </TR>\n</TABLE>\n>\n color=\"#344568\"\n fontcolor=\"white\"\n];\nLog_Error2 [\n label=<\n<TABLE CELLSPACING=\"0\" CELLPADDING=\"0\">\n <TR><TD BGCOLOR=\"WHITE\" WIDTH=\"20\"><FONT COLOR=\"green\"><B>+</B></FONT></TD>\n <TD>\n <B>Action Call ⚡</B>\n </TD>\n </TR>\n <TR>\n <TD COLSPAN=\"2\"><U>Log Error</U></TD>\n </TR>\n</TABLE>\n>\n color=\"#344568\"\n fontcolor=\"white\"\n];\nFLOW_START -> Get_the_Acme_Account [label=\"\" color=\"black\" style=\"\"]\nGet_the_Acme_Account -> Set_the_Type [label=\"\" color=\"black\" style=\"\"]\nGet_the_Acme_Account -> Log_Error [label=\"Fault\" color=\"red\" style=\"dashed\"]\nSet_the_Type -> Update_the_Acme_Account [label=\"\" color=\"black\" style=\"\"]\nUpdate_the_Acme_Account -> Log_Error2 [label=\"Fault\" color=\"red\" style=\"dashed\"]\n}"
"old": "---\ntitle: \"Demo\"\n---\nstateDiagram-v2\n\n classDef pink fill:#F9548A, color:white\n classDef orange fill:#DD7A00, color:white\n classDef navy fill:#344568, color:white\n classDef blue fill:#1B96FF, color:white\n classDef modified stroke-width: 5px, stroke: orange\n classDef added stroke-width: 5px, stroke: green\n classDef deleted stroke-width: 5px, stroke: red\n\n state \"<span style='padding:6px;margin:6px;background-color:#FFFFFF;'><font color=\"red\"><b>-</b></font></span><b>Assignment</b> 📝<br> <u>Set the Description</u><hr>Get_the_Acme_Account.Description = This is a Demonstration!\" as Set_the_Description\n class Set_the_Description orange deleted\n state \"<span style='padding:6px;margin:6px;background-color:#FFFFFF;'><font color=\"#DD7A00\"><b>Δ</b></font></span><b>Record Lookup</b> 🔍<br> <u>Get the 'Acme' Account</u><hr><b>sObject: Account</b><br>Fields Queried: all<br>Filter Logic: and<br>1. Name EqualTo Acme<br>Limit: First Record Only\" as Get_the_Acme_Account\n class Get_the_Acme_Account pink modified\n state \"<span style='padding:6px;margin:6px;background-color:#FFFFFF;'><font color=\"#DD7A00\"><b>Δ</b></font></span><b>Record Update</b> ✏️<br> <u>Update the 'Acme' Account</u><hr><b>Reference Update</b><br><u>Get_the_Acme_Account</u><br>\" as Update_the_Acme_Account\n class Update_the_Acme_Account pink modified\n FLOW_START --> Get_the_Acme_Account\n Get_the_Acme_Account --> Set_the_Description\n Set_the_Description --> Update_the_Acme_Account",
"new": "---\ntitle: \"Demo\"\n---\nstateDiagram-v2\n\n classDef pink fill:#F9548A, color:white\n classDef orange fill:#DD7A00, color:white\n classDef navy fill:#344568, color:white\n classDef blue fill:#1B96FF, color:white\n classDef modified stroke-width: 5px, stroke: orange\n classDef added stroke-width: 5px, stroke: green\n classDef deleted stroke-width: 5px, stroke: red\n\n state \"<span style='padding:6px;margin:6px;background-color:#FFFFFF;'><font color=\"green\"><b>+</b></font></span><b>Assignment</b> 📝<br> <u>Set the Type</u><hr>Get_the_Acme_Account.Type = Other\" as Set_the_Type\n class Set_the_Type orange added\n state \"<span style='padding:6px;margin:6px;background-color:#FFFFFF;'><font color=\"#DD7A00\"><b>Δ</b></font></span><b>Record Lookup</b> 🔍<br> <u>Get the 'Acme' Account</u><hr><b>sObject: Account</b><br>Fields Queried: all<br>Filter Logic: and<br>1. Name EqualTo Acme<br>Limit: First Record Only\" as Get_the_Acme_Account\n class Get_the_Acme_Account pink modified\n state \"<span style='padding:6px;margin:6px;background-color:#FFFFFF;'><font color=\"#DD7A00\"><b>Δ</b></font></span><b>Record Update</b> ✏️<br> <u>Update the 'Acme' Account</u><hr><b>Reference Update</b><br><u>Get_the_Acme_Account</u><br>\" as Update_the_Acme_Account\n class Update_the_Acme_Account pink modified\n state \"<span style='padding:6px;margin:6px;background-color:#FFFFFF;'><font color=\"green\"><b>+</b></font></span><b>Action Call</b> ⚡<br> <u>Log Error</u>\" as Log_Error\n class Log_Error navy added\n state \"<span style='padding:6px;margin:6px;background-color:#FFFFFF;'><font color=\"green\"><b>+</b></font></span><b>Action Call</b> ⚡<br> <u>Log Error</u>\" as Log_Error2\n class Log_Error2 navy added\n FLOW_START --> Get_the_Acme_Account\n Get_the_Acme_Account --> Set_the_Type\n Get_the_Acme_Account --> Log_Error : ❌ Fault ❌\n Set_the_Type --> Update_the_Acme_Account\n Update_the_Acme_Account --> Log_Error2 : ❌ Fault ❌"
}
}
]
Expand Down
2 changes: 1 addition & 1 deletion deno.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@goog/flow-lens",
"version": "0.1.11",
"version": "0.1.12",
"license": "Apache",
"exports": "./src/main/main.ts",
"imports": {
Expand Down
Binary file modified docs/img/Diff_New.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/img/Diff_Old.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions src/main/flow_parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export class FlowParser {

this.beingParsed.apexPluginCalls = ensureArray(flow.apexPluginCalls);
this.beingParsed.assignments = ensureArray(flow.assignments);
setAssignments(this.beingParsed.assignments);
this.beingParsed.collectionProcessors = ensureArray(
flow.collectionProcessors,
);
Expand Down Expand Up @@ -443,6 +444,20 @@ function ensureArray<T>(input: T[] | undefined): T[] | undefined {
return input ? (Array.isArray(input) ? input : [input]) : input;
}

/**
* Set Assignments
*
* Assignment items are nested properties which also need to be converted to an
* array.
*/
function setAssignments(assignments: flowTypes.FlowAssignment[] | undefined) {
assignments?.forEach((assignment) => {
assignment.assignmentItems = ensureArray(
assignment.assignmentItems,
) as flowTypes.FlowAssignmentItem[];
});
}

/**
* Set Orchestrated Stage Steps
*
Expand Down
29 changes: 29 additions & 0 deletions src/main/uml_generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,9 +194,38 @@ export abstract class UmlGenerator {
type: "Assignment",
color: SkinColor.ORANGE,
icon: Icon.ASSIGNMENT,
innerNodes: this.getFlowAssignmentInnerNodes(node),
});
}

private getFlowAssignmentInnerNodes(
node: flowTypes.FlowAssignment,
): InnerNode[] {
const result: InnerNode[] = [];
if (!node.assignmentItems) {
return result;
}

const assignments: string[] = [];
for (const item of node.assignmentItems) {
const operator = item.operator === flowTypes.FlowAssignmentOperator.ASSIGN
? "="
: item.operator;
assignments.push(
`${item.assignToReference} ${operator} ${toString(item.value)}`,
);
}

result.push({
id: `${node.name}__Assignments`,
type: "",
label: "",
content: assignments,
});

return result;
}

private getFlowCollectionProcessor(
node: flowTypes.FlowCollectionProcessor,
): string {
Expand Down
92 changes: 91 additions & 1 deletion src/test/uml_generator_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ const NODE_NAMES = {

const UML_REPRESENTATIONS = {
apexPluginCall: (name: string) => `state Apex Plugin Call ${name}`,
assignment: (name: string) => `state Assignment ${name}`,
assignment: (name: string) =>
`state Assignment ${name}
var1 = Hello World
var2 AddItem Test Value`,
collectionProcessor: (name: string) => `state Collection Processor ${name}`,
decision: (name: string) => `state Decision ${name}${EOL}`,
loop: (name: string) => `state Loop ${name}`,
Expand Down Expand Up @@ -189,6 +192,33 @@ function getFlowNodes(name: string): flowTypes.FlowNode[] {
] as flowTypes.FlowRecordDelete[];
}

if (name === NODE_NAMES.assignment) {
return [
{
...baseNode,
elementSubtype: "Assignment",
assignmentItems: [
{
assignToReference: "var1",
operator: flowTypes.FlowAssignmentOperator.ASSIGN,
value: {
stringValue: "Hello World",
},
processMetadataValues: [],
},
{
assignToReference: "var2",
operator: flowTypes.FlowAssignmentOperator.ADD_ITEM,
value: {
stringValue: "Test Value",
},
processMetadataValues: [],
},
],
},
] as flowTypes.FlowAssignment[];
}

// Return basic node for other types
return [baseNode] as flowTypes.FlowNode[];
}
Expand Down Expand Up @@ -541,4 +571,64 @@ Deno.test("UmlGenerator", async (t) => {
});
},
);

await t.step(
"should generate proper inner node content for FlowAssignment",
() => {
// Setup test data
const assignmentNode: flowTypes.FlowAssignment = {
name: "testAssignment",
label: "Test Assignment",
description: "Test assignment description",
elementSubtype: "Assignment",
locationX: 0,
locationY: 0,
assignmentItems: [
{
assignToReference: "var1",
operator: flowTypes.FlowAssignmentOperator.ASSIGN,
value: { stringValue: "Hello World" },
processMetadataValues: [],
},
{
assignToReference: "var2",
operator: flowTypes.FlowAssignmentOperator.ADD,
value: { numberValue: 42 },
processMetadataValues: [],
},
{
assignToReference: "var3",
operator: flowTypes.FlowAssignmentOperator.SUBTRACT,
value: { elementReference: "someVariable" },
processMetadataValues: [],
},
{
assignToReference: "var4",
operator: flowTypes.FlowAssignmentOperator.ADD_ITEM,
value: { formulaExpression: "1 + 1" },
processMetadataValues: [],
},
],
};

mockParsedFlow.assignments = [assignmentNode];
const uml = systemUnderTest.generateUml();

const expectedContent = [
"Assignment testAssignment",
"var1 = Hello World",
"var2 Add 42",
"var3 Subtract someVariable",
"var4 AddItem 1 + 1",
];

expectedContent.forEach((content) => {
assertEquals(
uml.includes(content),
true,
`Expected UML: ${uml} to contain: ${content}`,
);
});
},
);
});