Full guide on custom actions

28min
you’re a developer and you can’t find everything you need to design your process? you can create your own custom action that you can reuse in any process prerequirements github account visual studio 2019 (or above) step 1 connect to your github account and generate a github access token, by selecting from your personal account "settings" > "developer settings" > "personal access tokens" > "generate new token" make sure that read\ packages option is selected step 2 make sure you have nuget exe ( nuget command line interface (cli) reference ) installed on your computer and that it is added to the path environment variable add procesio nuget source from the command line by running the following the command from command line (in admin mode to be sure it will be processed) nuget sources add name procesio development source https //nuget pkg github com/procesio/index json username \[your git hub user name] password \[your api key] to check the outcome, go in a visual studio 2019, select from the menu tools/options/nuget package manager/package sources and check that the following source under whatever name you’ve used https //nuget pkg github com/procesio/index json alternatively, you can go in any visual studio 2019 menu to tools/options/nuget package manager/package sources and add the following source under whatever name you’d like https //nuget pkg github com/procesio/index json you will be asked to provide your credentials (username \[your git hub user name] and password \[your api key]) the first time you try to use a package from this source step 3 create a new net project of type class library ( net core 3 1) and manage its nuget packages to manage the nuget packages, go to "tools" → "nuget package manager" → "manage nuget packages for solution" select your newly configured package source from the upper right corner dropdown and browse for the latest ringhel procesio action core package step 4 edit the csproj file with the following lines \<project sdk="microsoft net sdk"> \<propertygroup> \<targetframework>net6 0\</targetframework> \<copylocallockfileassemblies>true\</copylocallockfileassemblies> \<generatepackageonbuild>true\</generatepackageonbuild> \<targetsfortfmspecificbuildoutput> $(targetsfortfmspecificbuildoutput);includedepsinpackage \</targetsfortfmspecificbuildoutput> \<allowedoutputextensionsinpackagebuildoutputfolder> $(allowedoutputextensionsinpackagebuildoutputfolder); pdb; json \</allowedoutputextensionsinpackagebuildoutputfolder> \<version>1 0 0 1\</version> \</propertygroup> \<itemgroup> \<packagereference include="ringhel procesio action core" version="1 19 2" /> \</itemgroup> \<target name="includedepsinpackage"> \<itemgroup> \<buildoutputinpackage include="$(outdir) " /> \</itemgroup> \</target> \</project> if you choose to use the following optional tags, you will need to update them manually when you create a new build in the same way as you update the version tag or the changes will not appear in the new build \<assemblyversion>1 0 0 1\</assemblyversion> \<fileversion>1 0 0 1\</fileversion> at the moment of writing this guide the latest ringhel procesio action core package is 1 14 1 3, you need to check the current version when adding the package and use it your csproj file the tag \<version>1 0 0 1\</version> shows the current version of the package and it changes dynamically if you wish to create another custom action using the same project after updating the code you will need to change the package version by select project from the visual studio menu and click projectname projectname properties in the package section you will see the package version, it needs to be changed each time you build a new custom action by default it starts at 1 0 0 0 step 5 create your custom action in a new class to do this there are only two requirements to implement for your classes to become proper custom actions include the following namespaces in your custom action class definition (you can find more details here procesio/action core ) ringhel procesio action core to implement iaction interface ringhel procesio action core actiondecorators to use action decorators ringhel procesio action core utils to use enums that are available for the different enumerators ringhel procesio action core models to use optionmodel class for defining multi values inputs make sure you inherit the iaction interface this is mandatory because procesio needs the execute method in order to run your action within a flow this is where you will add the logic of whatever behavior you need the action to have use proper attributes for your properties to define what type and use they have within your new action these attributes are necessary for procesio to create the action template, which is like a contract used for the ui to dynamically interpret and display any type of provided action correctly within the platform for more details about how to develop your custom action, check the sections below step 6 build the nuget package step 7 connect to procesio and open any process on the left toolbar, select the “custom actions” tab and click on “create custom action” give a name to the action and select an icon (optional), then upload your nuget file click save if all validations pass, your custom action will be displayed in the toolbar, under the “custom actions” tab note that a custom action can be used for any process if you want to update a custom action, you need to rebuild the nuget package with a different version number, then create it again in the process designer example of class implementation \[classdecorator(name = "custom template action", shape = actionshape circle, description = "custom template action description", classification = classification cat1)] \[fedecorator(label = "configuration modal", type = fecomponenttype modal, parent = "config modal", tab = "input tab")] public class mycustomaction iaction { public async task execute() { //add your desired behavior he output = "expected outcome"; } //add properties and helper methods and whatever else is needed for your logic; } required class attributes overview required property attributes overview example of full properties implementation \[fedecorator(label = "fe input property", type = fecomponenttype select, tab = "input tab", options = "myoptionslist")] \[bedecorator(ioproperty = direction input)] \[validator(isrequired = false)] public int myinput { get; set; } \[fedecorator(label = "fe output property", type = fecomponenttype number, tab = "output tab", defaultvalue = "2")] \[bedecorator(ioproperty = direction output)] \[validator(isrequired = true, expects = expectedtype number)] public int myoutput { get; set; } the accepted types for a property are int string boolean double datetime we do not accept at this point user defined types or nullable types the value of a property in the designer will be the defaultvalue from the fedecorator if that property is not required via the validator decorator and defaultvalue is not defined either, then we will use the default value of the corresponding data type from c# (0 for int and double, false for boolean, etc ) the same applies if the default value is deleted by the user and no other value is specified description of the different property attributes usag 1\ back end property attribute used to define whether a property is of input or output type \[bedecorator(ioproperty = direction input)] or \[bedecorator(ioproperty = direction output)] 2\ front end property attributes are used to set the type of component, a default value or a list of options for the values, its parent component or the tab it belongs to the way the fecomponenttype attribute is set will influence the display control used in the platform for control type number 2\ for control type text 3\ for control type checkbox 4\ for control type radio 5\ for control type select 6\ for control type modal besides the control type, you will need a control label using the label attribute you can also set a default value to your control using the defaultvalue attribute example of an input control of number type with default value 0 when not set \[fedecorator(label = "fe input property", type = fecomponenttype number, tab = "input tab", defaultvalue ="0")] the tab attribute, from the above example, is an attribute used in the ui to group all variables associated with it when you have complex types like select, buttons or modals that will open a new window/popup, you can use the parent attribute to group all properties under it the parent attribute and the parent name will be automatically associated also, a property can belong to either a tab or a parent using fecompomponenttype select requires the option attribute so that the ui populates the select control correctly options attribute will contain the name of the list of elements you are permitting example of a select control to give the users the choice of selecting a value from the defined list configoptions (of name & value pairs) \[fedecorator(label = "fe input property", type = fecomponenttype select, tab = "input tab", options = "configoptions")] in your code, you should create a matching named (case sensitive) list with these desired elements these elements must respect the case sensitive “name” & “value” pair format due to the fact that in the ui the select control will list the name, but the value will be the one sent for execution please note that currently procesio supports only primitive values for these elements the way you implement the list content is up to you, but here are two ways in which the options become available in the designer for \[ fedecorator (options = "mylistofoptions" , )] we can either use a string constant private const string mylistofoptions= "\[{\\"name\\" \\"select option name 1\\",\\"value\\" \\"1\\"},{\\"name\\" \\"select option name 2\\",\\"value\\" \\"2\\"},{\\"name\\" \\"select option name 3\\",\\"value\\" \\"3\\"}]"; or an optionmodel list private ienumerable\<optionmodel> mylistofoptions { get; } = new list\<optionmodel>() { new optionmodel(){ name = "select option name 1", value = 1 }, new optionmodel(){ name = "select option name 2", value = 2 } }; the way they get displayed in the platform you can add constraints to your controls by using validator attributes to set which properties are required and their expected type \[validator(isrequired = true, expects = expectedtypeemail)] to control the order in which the frontend components will be displayed, we use the orderid and rowid properties the orderid applies to tab components and it controls the order in which tabs are displayed the rowid controls the order of the components inside a parent (a tab, modal, or side panel) all components inside a parent component should have a unique rowid, otherwise, the display order will be inconsistent multiple components can have the same rowid as long as they belong to different parent components an example of usage is //use orderid to specify the order in which tabs should be displayed \[fetabdecorator(tabname = "details", orderid = 1)] //use rowid to specify the order in which components inside a parent //should be displayed \[fedecorator(label = "value to increment", type = fecomponenttype number, tab = "details", rowid = 1)] using lists to use a list inside a custom action, one would have to define an ienumerable property of the required type to this end, there are several cases where this applies 1\ list of primitive data type ienumerable\<int> numericlist {get; set;} the list usage is quite straightforward in this case 2\ list of custom data type ienumerable\<jobject> mycustomlist {get;set;} this list is a classic ienumerable of objects, but their content is dynamic, receiving a json value as input the action developer must know the json structure to work with 3\ list of files ienumerable\<filemodel> filelist {get; set;} this is a list of files, where each file is sent as a data stream, accessible through the action core filemodel type the filemodel type has only two properties name and file the name property holds the file name, and the file property holds the file stream which can be used to retrieve the file content example in using the file stream when iterating through the file list foreach(var file in filelist) { = file name; // this is the file name if required = file file; // this is the file stream which can be used to retrieve file content // example of file stream use using system io stream filestream = file file; console writeline($"file stream has length of {filestream length}"); } working with credentials inside a custom action apart from the obvious advantages of adding functionality to your processes using custom actions you also have the ability to use smtp servers and rest apis inside your newly create custom action to add this functionality to your process you will only need to include the appropriate namespaces and use the following methods namespaces for the rest api using ringhel procesio action core models credentials api; for the smtp connection using ringhel procesio action core models credentials smtp; smtp example \[fedecorator(label = "smtp credential", type = fecomponenttype credentials smtp, a dropdown will appear inside your process that will allow to pick an existing connection rest api example \[fedecorator(label = "rest api credential", type = fecomponenttype credentials rest, parent = "side panel parent", rowid = 5)] \[bedecorator(ioproperty = direction input)] \[validator(isrequired = true)] public apicredentialsmanager apicredential { get; set; } a dropdown will appear inside your process that will allow to pick an existing connection final observations now all you need to do is to create the nuget package for your code and upload it in procesio as a rule a nuget package must contain only 1 action when uploading it in the platform as of now, uploading batch actions is not supported (more actions in 1 package) also, in order to update your custom actions, users must first delete the initial action (if it is not used in any process yet) and re initiate the upload process with the new updated code if the custom action is already in use in at least a workflow it cannot be deleted, but the users can create a new action with the updated code (e g custom action v2 0) example of a fully written class that is a simple custom action that computes the sum of 2 numbers and saves it on the output \[classdecorator(name = "custom template action", shape = actionshape circle, description = "custom template action description", classification = classification cat1)] \[fedecorator(label = "configuration modal", type = fecomponenttype modal, parent = "config modal", tab = "input tab")] public class mycustonaction iaction { \#region options private const string configp1options = "\[{\\"name\\" \\"my name1\\",\\"value\\" \\"1\\"},{\\"name\\" \\"my name2\\",\\"value\\" \\"2\\"},{\\"name\\" \\"my name3\\",\\"value\\" \\"3\\"}]"; private const string configp2options = "\[{\\"name\\" \\"my name3\\",\\"value\\" \\"my name value 3\\"},{\\"name\\" \\"my name4\\",\\"value\\" \\"my name value 4\\"}]"; \#endregion \#region properties \[fedecorator(label = "fe input property", type = fecomponenttype select, tab = "input tab", options = "configp1options")] \[bedecorator(ioproperty = direction input)] \[validator(isrequired = false)] public int input1 { get; set; } \[fedecorator(label = "fe input property", type = fecomponenttype number, tab = "input tab", defaultvalue ="0")] \[bedecorator(ioproperty = direction input)] \[validator(isrequired = false)] public int input2 { get; set; } \[fedecorator(label = "fe output property", type = fecomponenttype number, tab = "output tab", defaultvalue = "2")] \[bedecorator(ioproperty = direction output)] \[validator(isrequired = true, expects = expectedtype number)] public int output1 { get; set; } \[fedecorator(label = "fe config property 2", type = fecomponenttype select, parent = "config modal", options = "configp2options")] \[bedecorator(ioproperty = direction output)] public string outconfig2 { get; set; } \#endregion \#region execute public async task execute() { output1 = input1 + input2; } \#endregion } besides the examples provided in this document, you can also follow the given example of custom actions provided by the procesio core project custom template action