Home
Github
Wiki
Videos
Contact
Sponsor
Setting up custom workflows
custom workflows are scripted using javascript. as with all [backoffice extensions](/wiki/extending-the-backoffice), you start off in the `puckweb/Areas/puck/Views/Shared/includes.cshtml` file. here's the skeleton of a workflow: ```js ``` so as you can see, you specify a `workflows` array which you then add entries to, for each `Type` of ViewModel you want workflows for. in the example above, we've added an entry for the `Homepage` ViewModel and you can see that the workflow object contains two functions, `comment` and `handler`. `comment` decides whether or not a user needs to add a comment on saving/publishing a ViewModel. this comment is then passed onto the second function, the `handler`. to decide whether or not a comment is needed, you are passed in the following parameters: ```js workflowItem:{ Id:int, Status:string, Message:string, Group:string, Complete:bool, CompleteDate:datetime Timestamp:datetime(created), ContentId:string(guid), Variant:string, LockedBy:string(username), LockedUntil:datetime } userObject:{ userName:string, userRoles:array
, userGroups:array
} ``` as well as the above parameters `workflowItem` and `userObject`, the `comment` function is also passed in the beginning state of the content being edited and the state at the point of saving in the form of `FormData` objects. you can use the `formdata.Get("NodeName")` method to get specific values from the content being edited. all of these parameters are passed in to the `comment` function to help you decide whether or not you want to show a comment entry box after the user hits the save/publish buttons. if you don't want the user to enter a comment, return undefined from the `comment` function, otherwise, return the string that will be used on the comment entry modal as the title. the second function, `handler`, is where you can add workflow entries. starting with the parameters - you have the current `workflowItem` object, which has been detailed already and the `userObject`, also detailed above. you also have `isPublished` to let you know if a user is saving or publishing, `startingState` which is a `FormData` object with the state of the content being edited when first loaded and `currentState` which is another `FormData` object with the state of the content being edited at the point of saving. you also get passed in a user entered `comment` if available (in a `commentObject` that includes the comment string and any user `mentions`) and a services object which will be detailed below: ```js services:{ add:function(status:string,message:string,userGroup:string,assignees:string(csv of usernames), complete:function(), msg:function(state:true(for positive messages - will display green)/false(for errors - will display red)/undefined(for neutral messages - will display grey),message:string) } ``` as you can see above, the `services` object has an `add` function which allows you to add new workflow items, all arguments are required apart from `assignees`, which is optional. you only need to use the `complete` function (which has no arguments) on the last step of your workflow once everything is complete. moving from one step of your workflow to another you only need to use `add` as this will automatically complete any previous step. returning `true` from this function will cancel saving so in that event you may want to display a message and that is what the `msg` function is for. users will be notified in the backoffice when you add a workflow item belonging to a `User Group` that they are in or assigned specifically to them using the `assignees` argument. ## examples how i see this being used is that you use all the information passed into the `handler` to decide what step of the workflow you're moving to next. for example, with the information passed in, i can know that the current workflow step status is `needs-approval` and that the current user editing the content is in the `Approver` group and i can then `complete` the workflow. or i can tell that the current step status is `needs-approval` and the person currently trying to edit the content is not in the `Approver` group and i can cancel the save event and show a user friendly message. here's an example workflow: ```js ``` as you can see above, the `comment` handler returns `undefined` since we don't want any comments being entered. then, there's the first step where we check that the current `workflowItem` is `undefined`, meaning that this is likely newly created content and we create our first workflow item with a status of `needs-approval`. we then move onto the approved state with a status of `approved-for-publishing` and finally we `complete` the workflow. if a particular user is not allowed to modify the content in the current step of the workflow, perhaps because they are not in the correct `User Group`, you can cancel the save event by returning `true` and show a message: ```js ``` in the example above, if the current workflow step/status is `needs-approval` but the user currently editing the content is not in the `Approver` `User Group`, you display an error using `services.msg` and return `true` to cancel the save event. ## more advanced use cases what if a user requires more than one save to complete a workflow? an example would be a copy editor who wants to see how the copy/text fits on a given page - they may edit a rich text editor field and save to do a preview multiple times. in this instance, you may want to add a `property` to your `ViewModel`, a `boolean` flag which indicates that they are finished editing, you can add the `Property` to a specific tab on the edit screen by using the standard MVC `Display` attribute and specifying the `GroupName` option: ```cs public class Homepage:BaseModel { [Display(GroupName = "Workflow")] public bool ChecksComplete { get; set; } } ``` you can then check the value of this field in the `handler` function using the `currentState` property and decide whether or not to move to the next step in your workflow.