Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

Service Portal Menu Widget using 'spDropdownTreeTemplate' is not populating the redirect URL correct

Liam Rhodes
Kilo Guru

Hi all,

I very recently updated one of our Service Portal's menu items called "My Tickets" to include Incidents as well as Requests. Below is the updated script.

 

// maximum number of entries in this Menu
var max = 40;

var t = data;  // shortcut
t.items = [];

var u = gs.getUser().getID();

// use record watchers to tell header when to update dropdown counts
// updated by Francis C SJP to include 60 days of historic records
//updated by MH to show sc_req_item instead of sc_request
t.record_watchers = [];
t.record_watchers.push({'table':'service_task','filter':'opened_by=' + u + '^active=true^ORclosed_atRELATIVEGE@dayofweek@ago@60'});
t.record_watchers.push({'table':'incident','filter':'caller_id=' + u + '^active=true^ORresolved_atRELATIVEGE@dayofweek@ago@60'});
t.record_watchers.push({'table':'sc_req_item','filter':'request.requested_for=' + u + '^ORopened_by=' + u + '^active=true^ORclosed_atRELATIVEGE@dayofweek@ago@60'});

//queries back service task records where user is opened by and record is active - ammended to st1 instead of st by Francis C SJP
var st1 = new GlideRecord('service_task');
if (st1.isValid()) {
  //st1.addActiveQuery(); //commented out to introduce OR query by Francis C SJP to
  st1.addQuery('active',true).addOrCondition('closed_at','>=','javascript:gs.daysAgoStart(60)');  // added to introduce a grouped OR and a relative query
  st1.addQuery('opened_by', gs.getUserID());
  st1.orderByDesc('sys_updated_on');
  st1.setLimit(max);
  st1.query();
  while (st1.next()) {
    var a = {};
    $sp.getRecordValues(a, st1, 'short_description,sys_id,number,sys_updated_on,state'); // added state Francis C SJP
    if (st1.short_description.nil())
      a.short_description = "(No description)";
    a.__table = st1.getTableName();
    a.type = 'record';
    a.sortOrder = st1.sys_updated_on.getGlideObject().getNumericValue();
    t.items.push(a);
  }
}


//queries back service request records where user is requested for and record is active - ammended to z1 instead of z by Francis C SJP
var z1 = new GlideRecord('sc_req_item');
// z1.addActiveQuery(); //commented out to introduce OR query by Francis C SJP to
z1.addQuery('active',true).addOrCondition('closed_at','>=','javascript:gs.daysAgoStart(60)');  // added to introduce a grouped OR and a relative query
z1.addQuery('request.requested_for', gs.getUserID());
z1.orderByDesc('sys_updated_on');
z1.setLimit(max);
z1.query();
while (z1.next()) {
  var ritm = new GlideRecord('sc_req_item');
  ritm.addQuery('sys_id', z1.getUniqueValue());
  ritm.query();
  if (!ritm.next())
    continue;

  var a = {};
  $sp.getRecordValues(a, z1, 'sys_id,number,sys_updated_on,state'); // added state Francis C SJP
  if (ritm.hasNext())
    a.short_description = ritm.getRowCount() + ' requested items';
  else
    a.short_description = ritm.cat_item.getDisplayValue() || ritm.getDisplayValue("short_description");
  a.__table = z1.getTableName();
  a.type = 'request';
  a.sortOrder = z1.sys_updated_on.getGlideObject().getNumericValue();
  t.items.push(a);
}

var inc1 = new GlideRecord('incident');
//inc1.addActiveQuery();
inc1.addQuery('active',true)
inc1.addQuery('caller_id', gs.getUserID());
inc1.orderByDesc('sys_updated_on');
inc1.setLimit(max);
inc1.query();
while (inc1.next()){
  if (!inc1.canRead())
    continue;
  
  var a = {};
  $sp.getRecordValues(a, inc1, 'short_description,sys_id,number,sys_updated_on');
  if (inc1.short_description.nil())
    a.short_description = "(No description)";
  a._table = inc1.getTableName();
  a.type = 'record';
  a.sortOrder = inc1.sys_updated_on.getGlideObject().getNumbericValue();
  t.items.push(a);
}


t.items.sort(function(a, b) {
  return b.sortOrder - a.sortOrder;
});
t.items = t.items.slice(0, max); // only want first 20
t.count = t.items.length;

var link = {title: gs.getMessage('View all tickets'), type: 'link', href: '?id=sjp_my_tickets', items: []};
t.items.unshift(link); // put 'View all requests' first	

 

And this of course displays perfect fine on the Service Portal showing both Incidents and Requests - no problem there.

LiamRhodes_0-1668594881175.png

My problem is that although the redirect links for the RITM records work fine, those for Incidents do not. When clicking on them I instead get a "Record not found" error, and the URL is not what I want.

 

LiamRhodes_1-1668594952636.png

/sp?id=ticket&table=&sys_id=23a441611b035d1403890ed0f54bcb20

As you can see, the ticket&table part of the URL is not populating correctly.

I have narrowed it down that the issue is in the spDropdownTreeTemplate angular template and can see that when I click on the Incident's link it is triggering the below part of the template so mi.type must == 'record'. From what I can see my problem is that {{::mi.__table}} is not populating with "Incident".

<a ng-if="mi.type == 'record' && !mi.__page" aria-label="${Open} {{::mi.number}} : {{::mi.short_description}}" aria-describedby="id_{{::mi.unique_number}}" ng-href="?id=ticket&table={{::mi.__table}}&sys_id={{::mi.sys_id}}" ng-click="collapse()" role="menuitem">
  <span>{{::mi.short_description | characters:60}}</span>
  <span class="block color-primary text-muted">
    <span class="block" style="float: right" id="id_{{::mi.unique_number}}">
      <sn-time-ago timestamp="::mi.sys_updated_on" />
    </span>
    {{mi.number}}
  </span>
</a>

My question is - anyone know where the "Incident" data gets passed through for {{::mi__table}}? I could just hardcode it in as Incident but don't want it to impact other features in the future. Perhaps I could create a new mi.type for Incidents.. if so what would be the correct way to do this? Thank you in advance!

0 REPLIES 0