“Beginning in itself has no value; it is an end which makes beginning meaningful; we must end what we begun.”
— Amit Kalantri
Last time, we added the Requested Item table to our Service Account dashboard so that we could see the pending requests, but we left off with a field name error and the desire to add a few item variables to the table using some Scripted Value Columns. Today, we will fix up that little error, and add some columns to both tables, hopefully wrapping things up, at least for this version of the dashboard.
In our field list for the new table, we had included the field name opened, when in actuality, the correct field name for the opened date/time is opened_at. That’s an easy fix, and now our field list looks like this:
number,opened_at,request.requested_for,stage
While we are in the configuration updating field lists, let’s also add the new link to the original request to the field list for the Service Account table, which will now look like this:
number,type,user_id,owner,owning_group,original_request
Also, since that new column will be a link to the sc_req_item table, let’s map that table to the ticket page by adding a new entry to the reference map.
That should take care of the errors and oversights. Now let’s take a look at adding some item variables to the pending request view. We put some catalog item variables on an example table not too long ago, so let’s just follow that same approach and maybe steal a little code from that guy so that we don’t end up reinventing an existing wheel. Here is the script that we built for that exercise.
var ScriptedCatalogValueProvider = Class.create();
ScriptedCatalogValueProvider.prototype = {
initialize: function() {
},
questionMap: {
cpu: 'e46305fbc0a8010a01f7d51642fd6737',
memory: 'e463064ac0a8010a01f7d516207cd5ab',
drive: 'e4630669c0a8010a01f7d51690673603',
os: 'e4630688c0a8010a01f7d516f68c1504'
},
getScriptedValue: function(item, config) {
var response = '';
var column = config.name;
if (this.questionMap[column]) {
response = this.getVariableValue(this.questionMap[column], item.sys_id);
}
return response;
},
getVariableValue: function(questionId, itemId) {
var response = '';
var mtomGR = new GlideRecord('sc_item_option_mtom');
mtomGR.addQuery('request_item', itemId);
mtomGR.addQuery('sc_item_option.item_option_new', questionId);
mtomGR.query();
if (mtomGR.next()) {
var value = mtomGR.getDisplayValue('sc_item_option.value');
if (value) {
response = this.getDisplayValue(questionId, value);
}
}
return response;
},
getDisplayValue: function(questionId, value) {
var response = '';
var choiceGR = new GlideRecord('question_choice');
choiceGR.addQuery('question', questionId);
choiceGR.addQuery('value', value);
choiceGR.query();
if (choiceGR.next()) {
response = choiceGR.getDisplayValue('text');
}
return response;
},
type: 'ScriptedCatalogValueProvider'
};
We can make a copy of this script and call ours ServiceAccountDashboardValueProvider. Most of this appears to be salvageable, but we will want to build our own questionMap using the columns that we will want to use for our use case. To find the sys_ids for the variables that we will want to use, we can pull up the Catalog Item to get to the list of variables, and then pull up each variable and use the context menu to snag the sys_id for each one.
Once we gather up all of the sys_ids, we will have a new map that looks like this:
questionMap: {
account_id: '59fe77a4971311100362bfb6f053afcc',
type: 'f98b24a4971711100362bfb6f053afa0',
group: '3d4fbba4971311100362bfb6f053afe3'
},
That should be enough to make things work; however, in our case the types of variables involved will return the display value directly, so we do not need to go through that secondary process to look up the display value from the value. We can simply delete that unneeded function and return the value directly in this instance. That will make our new script look like this:
var ServiceAccountDashboardValueProvider = Class.create();
ServiceAccountDashboardValueProvider.prototype = {
initialize: function() {
},
questionMap: {
account_id: '59fe77a4971311100362bfb6f053afcc',
type: 'f98b24a4971711100362bfb6f053afa0',
group: '3d4fbba4971311100362bfb6f053afe3'
},
getScriptedValue: function(item, config) {
var response = '';
var column = config.name;
if (this.questionMap[column]) {
response = this.getVariableValue(this.questionMap[column], item.sys_id);
}
return response;
},
getVariableValue: function(questionId, itemId) {
var response = '';
var mtomGR = new GlideRecord('sc_item_option_mtom');
mtomGR.addQuery('request_item', itemId);
mtomGR.addQuery('sc_item_option.item_option_new', questionId);
mtomGR.query();
if (mtomGR.next()) {
response = mtomGR.getDisplayValue('sc_item_option.value');
}
return response;
},
type: 'ServiceAccountDashboardValueProvider'
};
Now that we have a script to reference, we can go back into the Content Selector Configuration Editor and add our new columns.
Once we have added our three new columns to the configuration, we can save the configuration script, which now looks like this:
var ServiceAccountDashboardConfig = Class.create();
ServiceAccountDashboardConfig.prototype = Object.extendsObject(global.ContentSelectorConfig, {
initialize: function() {
},
perspective: [{
name: 'requester',
label: 'Requester',
roles: ''
},{
name: 'fulfiller',
label: 'Fulfiller',
roles: 'itil'
}],
state: [{
name: 'active',
label: 'Active'
},{
name: 'retired',
label: 'Retired'
},{
name: 'pending',
label: 'Pending'
}],
table: {
requester: [{
name: 'x_660634_service_0_service_account',
displayName: 'Service Account',
active: {
filter: 'active=true^ownerDYNAMIC90d1921e5f510100a9ad2572f2b477fe^ORowning_groupDYNAMICd6435e965f510100a9ad2572f2b47744',
fields: 'number,type,user_id,owner,owning_group,original_request',
svcarray: [],
aggarray: [],
btnarray: [],
refmap: {
sc_req_item: 'ticket',
sys_user: 'user_profile'
},
actarray: []
},
retired: {
filter: 'active=false^ownerDYNAMIC90d1921e5f510100a9ad2572f2b477fe^ORowning_groupDYNAMICd6435e965f510100a9ad2572f2b47744',
fields: 'number,type,user_id,owner,owning_group,original_request',
svcarray: [],
aggarray: [],
btnarray: [],
refmap: {
sc_req_item: 'ticket',
sys_user: 'user_profile'
},
actarray: []
},
pending: {
filter: 'number=0',
fields: 'number',
svcarray: [],
aggarray: [],
btnarray: [],
refmap: {},
actarray: []
}
},{
name: 'sc_req_item',
displayName: 'Requested Item',
active: {
filter: 'number=0',
fields: 'number',
svcarray: [],
aggarray: [],
btnarray: [],
refmap: {},
actarray: []
},
retired: {
filter: 'number=0',
fields: 'number',
svcarray: [],
aggarray: [],
btnarray: [],
refmap: {},
actarray: []
},
pending: {
filter: 'active=true^request.requested_forDYNAMIC90d1921e5f510100a9ad2572f2b477fe^cat_item=55cc38eb970711100362bfb6f053afa8',
fields: 'number,opened_at,request.requested_for,stage',
svcarray: [{
name: 'account_id',
label: 'ID',
heading: '',
script: 'x_660634_service_0.ServiceAccountDashboardValueProvider'
},{
name: 'type',
label: 'Type',
heading: '',
script: 'x_660634_service_0.ServiceAccountDashboardValueProvider'
},{
name: 'group',
label: 'Responsible Group',
heading: '',
script: 'x_660634_service_0.ServiceAccountDashboardValueProvider'
}],
aggarray: [],
btnarray: [],
refmap: {
sys_user: 'user_profile'
},
actarray: []
}
}],
fulfiller: [{
name: 'x_660634_service_0_service_account',
displayName: 'Service Account',
active: {
filter: 'active=true^type.fulfillment_groupDYNAMICd6435e965f510100a9ad2572f2b47744',
fields: 'number,type,user_id,owner,owning_group',
svcarray: [],
aggarray: [],
btnarray: [],
refmap: {
sys_user: 'user_profile'
},
actarray: []
},
retired: {
filter: 'active=false^type.fulfillment_groupDYNAMICd6435e965f510100a9ad2572f2b47744',
fields: 'number,type,user_id,owner,owning_group',
svcarray: [],
aggarray: [],
btnarray: [],
refmap: {
sys_user: 'user_profile'
},
actarray: []
},
pending: {
filter: 'number=0',
fields: 'number',
svcarray: [],
aggarray: [],
btnarray: [],
refmap: {},
actarray: []
}
},{
name: 'sc_req_item',
displayName: 'Requested Item',
active: {
filter: 'number=0',
fields: 'number',
svcarray: [],
aggarray: [],
btnarray: [],
refmap: {},
actarray: []
},
retired: {
filter: 'number=0',
fields: 'number',
svcarray: [],
aggarray: [],
btnarray: [],
refmap: {},
actarray: []
},
pending: {
filter: 'active=true^cat_item=55cc38eb970711100362bfb6f053afa8^assignment_groupDYNAMICd6435e965f510100a9ad2572f2b47744',
fields: 'number',
svcarray: [],
aggarray: [],
btnarray: [],
refmap: {
sys_user: 'user_profile'
},
actarray: []
}
}]
},
type: 'ServiceAccountDashboardConfig'
});
Now all we need to do is to pull up the dashboard under the new configuration and see how it all looks. First, let’s take a look at the new column that we added for the original request.
There is only data there for the most recent test, but that’s just because that field did not exist on the table until recently. Now let’s click on the Pending state and see how our item variables came out.
Very nice! OK, I think that about does it for this version of the sample dashboard. There is still some work that we could do on the Fulfiller perspective, and it might be nice to add an Admin perspective that showed everything, but since this is just an example of what might be done, I will leave that as an exercise for those who might want to play around with things a bit. Next time, let’s take a look at what now have up to this point, and at what there might be left to do before we can wrap this one up and call it done.