Configurable Workspace is a really great ServiceNow product. Even the legacy one, the original Agent Workspace was a big step forward. I remember first seeing this, it was so impressive! I had big hopes which grew bigger when they announced the possibility to built custom components. I tried, built something, it worked, I was happy. Recently I’ve came back to this topic, hoping to see improvements… But I saw the same old stuff. It will be improved, I know. Custom components will use supported version of node.js
to develop. We just have to wait.
But this post is about something else. A friend of mine recently asked me how to open a custom page designed for service portal in Service Operations Workspace. He wanted to open it in a tab, next to active record form, from a UI Action. Sounds simple? Should be, shouldn’t it? There must be an API for this, it seems like a valid use case, easy to implement, right?
Teaser – final result
Spoiler alert! 😉
Research
Well, no. Whether you do your research on big Internet search engines or on ServiceNow documentation page, you will find no direct solution. Just some hints. Some sources suggest g_navigate
(which doesn’t work in configurable workspace), other suggest using a modal instead of opening a new tab (which actually works and can also be considered, depending on your requirements) with g_modal.show_frame({})
(undocumented, but you can find examples on OOB instance).
There is also an API called g_aw
. I had high hopes for it, but:
- it only contains
openRecord()
andcloseRecord()
methods - when you try to be smart and open
sp_page
record, you get exaclty what you ask for – a form, backend view of the page
This wasn’t the best approach. So I had to take a step back and analyze how the other pages are displayed in tabes. Records, sometimes catalog item page (so it is possible to show page from service portal!). I was actually lucky that my friend’s use case was around interactions. On OOB instance, there is a Create Request UI Action, which opens a catalog item page with the portal look & feel.
Analysis
So how does it work? Let’s dive deeper. The UI Action has a pretty simple script with the most interesting part here:
var params ={};
params.sysparm_parent_table = "interaction";
params.sysparm_parent_sys_id = g_form.getUniqueValue();
g_service_catalog.openCatalogItem('sc_cat_item', '-1', params);
Ah, so there is g_service_catalog
API! Unfortunatelly, it has offically only one method, not the one used. When you use it, you will be redirected to the following URL:
https://instance.service-now.com/
now/sow/
record/interaction/[sys_id]/
sub/
record/sc_cat_item/-1_uid_1/
params/extra-params/parent_table%2Finteraction%2Fparent_sys_id%2F[sys_id]%2Fsysparm_parent_table%2Finteraction%2Fsysparm_parent_sys_id%2F[sys_id]
I split it on purpose to facilitate analysis. Now, what you see here is:
- Line 1 is the instance URL
- Line 2 is the SOW path
- Line 3 is the page with required parameters
- Line 4 is interesting. I can’t explain it yet, but it seems to be a divider to allow another tab to be opened
- Line 5 is same as 3. Notice the
sc_cat_item
passed as atable
required parameter - Line 6 provides optional params to the page call from previous line
Next step? Let’s check the record
page in UI Builder. OOB it may look like that:
So the sc_cat_item
case, used by Create Request UI Action is a page variant with a table=sc_cat_item
condition!
We are getting closer and closer – let’s see what they use to display sc_cat_item
page:
It’s a custom component. Which gives us more hints:
- It is not yet possible OOB to open portal pages in workspace environment
- SN used custom component to achieve that – this means that regular
iFrame
will cause problems
Implementation
OK, that was a good brain experience. Now what you need to implement it?
- A new
record
page variant in your workspace. This means, you will have to add it for every workspace where you want to use it. No surprise here. - A UI Action to open the custom page.
How you implement it is up to you. However, remember about couple of things
- Since this is a variant, you gave to utilise mandatory parameters
table
andsysId
. I usedtable
for the condition andsysId
for the page to be displayed along with any parameters - In the
iFrame
component, make sure to check Disable sandbox. Otherwise you will get tons of errors and nothing else - Provide the source of your
iFrame
component as a script result and utilise theapi.context.props.sysId
parameter - Now you can write just one line in your client UI Action (yes, it has to be marked as Client) –
g_service_catalog.openCatalogItem('page', 'the page you want to see with parameters');
Final touches
There are two more things worth noting down. First of all, consider displaying the page on a portal without unnecesary branding. You may even create a new one, with minimal theme and no header/footer, just to display pages from service portal in the workspace.
And secondly, you may have noticed that the new tab displaying the portal page has an ugly title: Loading… And it doesn’t change. Why? Since it’s a UI Builder page, the answer is simple – because you didn’t write any instructions on the page when and how to do that. You may take a look at the OOB Catalog Item Page SNC variant. Check client scripts there and examine this one:
/**
* @param {params} params
* @param {api} params.api
* @param {any} params.event
* @param {any} params.imports
* @param {ApiHelpers} params.helpers
*/
function handler({api, event, helpers, imports}) {
if (event.payload && event.payload.title)
api.emit('SCREEN_STATUS_CHANGED', {
title: event.payload.title
});
else if (event.payload)
helpers.translate("Custom tab title").then(
(value) => {
api.emit('SCREEN_STATUS_CHANGED', {
"title" : value
});
}
);
}
You set the tab title on line 14. Now all you have to do is to run this script. How? Via events – iFrame
components has one event, iFrame Loaded
. Add a script execution there and there you go!
Conclusion
With the UI Builder getting more and more updates a lot is possible. Learn about it, build something on it and understand it. This is the only way to be able to create custom solutions to problems which shouldn’t exist 🙂