When making Power Apps we are often only as good as the components we have, and although Microsoft is doing a great job at rolling out new ones, we are still limited compared to ProCode.
Fortunately there is Component Framework which allows you to create custom components, but this has a few drawbacks:
- It isn't LowCode (professional developers required)
- Requires enablement in environment (security risks may require turned off)
- Requires premium license for users
Fortunately as with most LowCode, if we think outside of the box we can create a custom component like experience, without any of the above issues.
How exactly? Certain API's (some free) allow you to unload the complexity to outside of the app, in this demo I'm going to create a Flow diagram tool (like Visio) leveraging a great free API called QuickChart. How is this not a premium connector, well the API returns images (png or svg), which means we can pass the get request as an image source url.
The Viso tool is going to be used to create SDD's (Simple Design Diagrams) for Flows, Apps and PVA's. The App will do the following:
- Get list of connectors from Microsoft*
- Populate dropdowns
- Create diagram code url from dropdowns
- Use QuickChart API to populate image
- Send diagram code url to a flow
- Use HTTP request to get image content*
- Save to SharePoint
- Send link so app user can download
* Requires premium license, but this is for the demo, the flow chart diagram would work without these added functionality.
- Custom Connector
- App Setup
- API request
- Flow to create file
1. Connectors
The custom connector is relatively simple, there is a free API provided by Microsoft that returns all connectors.
https://powerautomate.microsoft.com/en-us/api/connectors/all
I wrote a previous blog about how to create a custom connector here if you need some guidance.
In the App I save the response as an object, then convert it to a collection to be used in combo boxes. To make it easier I copy some nested fields to the route and I create a formatted value for the diagram, as unfortunately this API won't work with following in the labels:
- leading numbers
- spaces
- special characters (excluding _ )
so we remove them with a substitute regex function.
Set(colValue,PowerPlatformConenctors.GetConnectors().value);
ClearCollect(colConnectors,
AddColumns(colValue,
"DisplayName",
properties.displayName,
"DesignLabel",
Concat(Split(properties.displayName,""),
If(IsMatch(Value,"[A-Za-z]"),Value,"")
),
"Trigger",
"_"&Concat(Split(properties.displayName,""),
If(IsMatch(Value,"[A-Za-z]"),Value,"")
),
"Output",
Concat(Split(properties.displayName,""),
If(IsMatch(Value,"[A-Za-z]"),Value,"")
)&"_",
"Tier",properties. Tier
)
)
To keep the trigger and output unique I add a leading/trailing '_' to the label. Else the diagram wouldn't know the difference between trigger, connector, output and only render it once.
2. App Setup
For the app I have a few combo boxes for the inputs to the diagram.
- Type - is it a flow, app, pva, or app & flow (if not flow there is no trigger, so we use a 'User' as the trigger)
- Trigger - connector for flows only (connector collection)
- Connectors - any connector used (connector collection)
- Privileges - the permissions each connector uses (Create,Read,Update,Delete)
- Output - the primary end point of the data (connector collection)
I then added an image to the render the diagram. To help with the demo I have also added a label that displays the code created for the API call (also great for debugging during the build).
3. API request
Now this is where it gets a little complex. We have to dynamically create the url and use that as the source of an image component.
The QuickChart API uses DOT (graph description language) so there is plenty of documentation (Mermaid and other libraries all use it). I recommend graphviz as the best documentation site.
The API has the following end point we are using:
https://quickchart.io/graphviz?format=svg&graph=digraph{YOURCODE}
As you can see we have selected svg format instead of png (I always find png quality low) and type digraph (change for different QuickChart chart types).
Next is the code, a simple one would be
start -> middle;
middle -> end;
https://quickchart.io/graphviz?format=svg&graph=digraph{start -> middle; middle -> end;}
We can add formatting to the nodes and the links by using []
start [style=filled,color="grey", shape="square"];
start -> end [penwidth=3,label=" label"]
Finally we can add formatting for the entire diagram and add containers/boxes/clusters:
rankdir=LR;
Node [shape=rectangle];
subgraph cluster_1 {
label="a box";
start;
}
start [style=filled,color="grey",shape="square"];
start -> end [penwidth=3,label=" label"]
There is so much more to graphviz, and better documentation out there so I won't go into it much more. But I recommend this online editor to play with magjac.com/graphviz-visual-editor.
So how did I build it, with lots of variables and concat's is the answer.
Apologise now, I'm old fashioned and don't like $-String syntax, for some reason I find it harder to read so expect lots of &'s
My crazy code is:
"https://quickchart.io/graphviz?format=svg&graph=digraph{
rankdir=LR;
Node [shape=rectangle];
subgraph cluster_0 {
label=%22Microsoft Tenant - All connections HTTPS%22;
"&
"subgraph cluster_1 {
label=%22Power Platform%22;
"&
vsType.label&
";
"&If(vsType.flow,"PowerAutomate -> ")& "Connector"&If(vsType.flow,"[dir=%22both%22]")& ";
}
"&
If(vsType.label<>"PowerAutomate",vsType.code,
coTrigger.Selected.Trigger &" [style=filled,color=%22"&EncodeUrl("grey")&"%22,fontcolor=white, tooltip =%22Read%22];
")&
If(vsType.label<>"PowerAutomate","User",coTrigger.Selected.Trigger)&"->"&vsType.label&" [penwidth=3,label=%22Trigger%22];
"&
If(Not("PowerVirtualAgent" in vsType.label), vsType.label& "-> Connector [dir=%22both%22];
")&
If(vsType.flow,vsType.label&"->"&"PowerAutomate [dir=%22both%22];")&
Concat(coConnections.SelectedItems,DesignLabel&" [style=filled,color=%22"&EncodeUrl("Blue")&"%22,fontcolor=white, tooltip=%22"&Concat(Distinct(Filter(coPrivileges.SelectedItems,DesignLabel=connector),label),Value&" ")&"%22];
")&
Concat(coConnections.SelectedItems,"Connector"&"->"&DesignLabel&" [dir=%22both%22,label=%22/ "&Concat(Filter(coPrivileges.SelectedItems,connector=DesignLabel),label&" / ")&"%22];")&
"Connector ->"&coOutput.Selected.Output &
" [penwidth=3,shape=oval,style=rounded,label=%22Output%22];
"&
coOutput.Selected.Output&
"[style=filled,color=%22"&EncodeUrl("DarkGreen")&"%22,fontcolor=white,tooltip=%22Write / Update%22]
}
}"
As you can see, I add the combo box options in concat's for multi-select and single references for single select. I EncodeUrl for any " or just type %22. It is a lot of trial and error to get right, which is why I added the label. Top tip add new lines inside strings, as then the error returns the line number to find the issue.
If it goes to plan it ends up as this:
https://quickchart.io/graphviz?format=svg&graph=digraph{
rankdir=LR;
Node [shape=rectangle];
subgraph cluster_0 {
label=%22Microsoft Tenant - All connections HTTPS%22;
subgraph cluster_1 {
label=%22Power Platform%22;
PowerAutomate;
Connector;
}
_OfficeOutlook [style=filled, color=%22grey%22,fontcolor=white, tooltip =%22Read%22];
_OfficeOutlook->PowerAutomate [penwidth=3,label=%22Trigger%22];
PowerAutomate-> Connector [dir=%22both%22];
SharePoint [style=filled, color=%22Blue%22,fontcolor=white, tooltip=%22Create Read Update %22];
MicrosoftTeams [style=filled, color=%22Blue%22,fontcolor=white, tooltip=%22Create %22];
MeCorporate [style=filled, color=%22Blue%22,fontcolor=white, tooltip=%22Create %22];
OfficeUsers [style=filled,color=%22Blue%22,fontcolor=white, tooltip=%22Read %22];
Connector->SharePoint [dir=%22both%22,label=%22/ Create / Read / Update / %22];
Connector->MicrosoftTeams [dir=%22both%22,label=%22/ Create / %22];
Connector->OfficeUsers [dir=%22both%22,label=%22/ Read / %22];
Connector->MeCorporate [dir=%22both%22,label=%22/ %22];
Connector->SharePoint_ [penwidth=3,shape=oval, style=rounded, label=%22Output%22];
SharePoint_[style=filled, color=%22DarkGreen%22,fontcolor=white,tooltip=%22Write / Update%22]
}
}
4. Flow to create file
The only thing we can't do in the app is download the diagram, so this is where we need a flow (for a http request). If we didn't want to be premium we could open the url in a Launch function. This would open it in a new browser window where we could save page as svg or save image if png.
We simply pass the diagram code url we created as the input to the http request. To create a file we need to convert it:
base64ToBinary(base64(body('HTTP')))
if we wanted to embed in a html file it would be:
base64ToString(base64(body('HTTP')))
Although I wouldn't say the process is super simple, it is easier then custom components, and other API's are a lot simpler. challenge is the syntax of the API. There are loads of other great free image API's, QuickChart alone has loads and then there is Static Google maps just to name a few.
I've saved a none premium version of the app here (No custom connector or flow) if you want to explore more.
Further Reading
Top comments (2)
thx for the awesome article =)
Are you sure the PCF requires premium license for users?
Good shout out, I didn't realise if it didn't use a premium functionality it didn't need a premium licences. Think I need to avoid talking about Microsoft licensing as it's a nightmare lol.