How to access Scroll Version workflow using Velocity script
Asked by Kin Chan:

Hi there,

We are using Scroll Version on a Confluence space to do space version control. We have activated workflow provided by Scroll Version. We would like to access the workflow, namely the page status (draft, review etc) using a Confluence User Macro (written in Velocity code) to show the revision statuses of all the pages in a table. Can someone suggest a way to do that (i.e. to detect the revision status from workflow) please?

Thanks in advance for your help.

Kin


Answers:
author: David _K15t_
body: Hi Kin,

I have a user macro here which could be useful. It must be used together with the Scroll Page Tree macro and adds workflow states to that page tree using some simple Javascript REST calls:

```
## @noparams
<script>
let scrollPages;
let baseURL;
function buildLozenge(state){
if (state == "Complete") {
return "<span style='margin-left: 4px; opacity: 0.8;' class='aui-lozenge aui-lozenge-success'>Complete</span>"
} else if (state == "Review") {
return "<span style='margin-left: 4px; opacity: 0.8;' class='aui-lozenge aui-lozenge-moved'>Review</span>"
} else if (state == "Draft") {
return "<span style='margin-left: 4px; opacity: 0.8;' class='aui-lozenge'>Draft</span>"
}
}

let addWorklowStates = function(scrollPages){
scrollPages.each(function(){
let confPageId = $(this).attr("data-page-id");
let requestUrl = baseUrl+"/rest/scroll-versions/1.0/workflow/"+confPageId;

let wfRequest = new XMLHttpRequest();
let wfState;
wfRequest.open("GET", requestUrl);
wfRequest.setRequestHeader("Content-Type", "application/json");
wfRequest.send();
wfRequest.onload = () => {
if(wfRequest.status === 200) {
let response = JSON.parse(wfRequest.response);
wfState = response.i18nName;
$(this).children("a").append(buildLozenge(wfState));
}
}
$(this).addClass("workflow-stated")
});
}

let addMissingWorkflowStates = function(){
let i = 0;
let waitForPagesToExpand = setInterval(function(){
if ($("div[data-macro-name='sv-pagetree'] li.node.type_change").not(".workflow-stated, .deleted").length > 0){
let expandedPages = $("div[data-macro-name='sv-pagetree'] li.node.type_change").not(".workflow-stated, .deleted");
addWorklowStates(expandedPages);
$("div.openclose").click(addMissingWorkflowStates);
clearInterval(waitForPagesToExpand);
} else{
i++;
if (i >= 50){
clearInterval(waitForPagesToExpand);
}
}
}, 250);
}

AJS.toInit( function(){
let waitForScrollTree = setInterval(function(){
if ($("div[data-macro-name='sv-pagetree'] li.node.type_change").not(".deleted").length > 0){
scrollPages = $("div[data-macro-name='sv-pagetree'] li.node.type_change").not(".deleted");
baseUrl = Confluence.getBaseUrl();
addWorklowStates(scrollPages);
$("div.openclose").click(addMissingWorkflowStates);
clearInterval(waitForScrollTree);
} else {
console.log("no scroll tree pages found, retrying...")
}
},250);

});
</script>
```

Just place this macro and a Scroll Page Tree on the same page and the output will look something like this:

![Screen Shot 2020-10-15 at 08.37.15.png](https://community.atlassian.com/t5/image/serverpage/image-id/114389i582499E3C7977F02/image-dimensions/290x312?v=v2 "Screen Shot 2020-10-15 at 08.37.15.png")

Let me know if this works for you. If it doesn't the first thing I recommend to troubleshoot is the Confluence base url, depending on your settings the context path can be part of that or not.

Cheers,

David

comments: author: Kin Chan
body: Hi David,

Thanks for the code. I have not learnt javascript yet and would like to know more about your code. Would your code work if the pages I am interested to know the revision status of are not subpages of the one with the macro?

Regards,

Kin


author: David _K15t_
body: Hi Kin,

the code I shared always adds the workflow status for all the pages that are displayed in the Scroll Page Tree macro. In the Scroll Page Tree macro settings, you can configure the root page for example, which can be any page in a space, regardless of what page you include the Scroll Page Tree macro on.

So in short, any pages that can be displayed by the macro will have their workflow state added.

Cheers,

David


author: Kin Chan
body: Hi Dave,

I have tested your script on a small space and it works. I just need to test it on a big space to see if it still works. As I am using Velocity script (stated in my original request) and have not learnt javascript, I now need to see how to do the rest of my task with javascript. I need to create a table with the revision status and add more info such as date of change and button for reviewer to click (to record the number and names of reviewers). Do you have any idea how to do that?

Thanks for your help so far.

Regards,

Kin


author: Dominic Lagger
body: Hi [@Kin Chan](/t5/user/viewprofilepage/user-id/4125892)

I once wrote an user macro for getting the page keys.

I get the API requests from the documentation page:

* [Manage workflow states](https://help.k15t.com/scroll-versions/latest/api-resources-164037049.html#id-.APIresourcesv3.13-Manageworkflowsstates)

The code of my macro is here, feel free to adjust the way you need:

```
## Macro title: My Macro

## @noparams

#set( $pageId=$content.getContentId().asLong() )
#set( $listOfDescendants = $content.getDescendants() )

#set($listOfDecendantsPageIds = [])
#foreach ($page in $listOfDescendants)
#set($foo = $listOfDecendantsPageIds.add($page.getContentId().asLong()) )
#end

<table class="confluenceTable tablesorter tablesorter-default" >
<thead class="tableFloatingHeaderOriginal">
<tr role="row">
<th class="confluenceTh">Page name</th>
<th class="confluenceTh">Page key</th>
<th class="confluenceTh">Version</th>
</tr>
</thead>
<tbody id="pk-table-output"></tbody>
</table>


<script>
let baseUrl = Confluence.getBaseUrl().concat(Confluence.getContextPath());
let spaceKey = AJS.Meta.get("space-key");
console.log(baseUrl);
function pkArray(pkPages) {
var pkTable = "";
var i=0;
var list = $listOfDecendantsPageIds;
while (i < pkPages.length) {
var page = pkPages[i];
if( list.includes(page.confluencePageId)) {
if (page.scrollPageKey != undefined) {
pkTable = pkTable.concat("<tr role='row' ><td class='confluenceTd'><a href='"+baseUrl+"/pages/viewpage.action?pageId="+page.confluencePageId+"'>"+page.scrollPageTitle+"</a></td><td class='confluenceTd'><a href='"+baseUrl+"/display/_PK/"+spaceKey+"/"+page.scrollPageKey+"'>"+page.scrollPageKey+"</a></td><td class='confluenceTd'>"+page.targetVersion.name+"</td></tr>");
}else{
pkTable = pkTable.concat("<tr role='row' ><td class='confluenceTd'><a href='"+baseUrl+"/pages/viewpage.action?pageId="+page.confluencePageId+"'>"+page.scrollPageTitle+"</a></td><td class='confluenceTd'>---</td><td class='confluenceTd'>---</td></tr>");
}
}
i++; 
}
return pkTable;
}

let pkRequest = new XMLHttpRequest();
pkRequest.open("POST", ""+baseUrl+"/rest/scroll-versions/1.0/page/"+spaceKey);
pkRequest.setRequestHeader("Content-Type", "application/json");
pkRequest.send(JSON.stringify([{"queryArg": "scrollPageTitle", "value": "*"}]));
pkRequest.onload = () => {
if(pkRequest.status === 200) {
document.getElementById("pk-table-output").innerHTML = pkArray(JSON.parse(pkRequest.response));
}
else {
console.log("whoopsie")
}
}
</script>
```

Regards, Dominic

comments: author: Kin Chan
body: Hi Dominic,

Thanks very much for the code. I am new to Velocity scripting and am trying to understand your code. Would you please point out which statement in your code get the revision status (i.e. draft, review or complete) of the page?

Regards,

Kin


Tags: confluence-server

server