How to get a watch list in widget in Service Portal ?

Nithin12
Tera Expert

Hi Team,

How to get watch list for a particular ticket opened in service portal.

How to create a widget for this?

Any suggestions or ideas will help me a lot.

Thanks.

PlatformDeveloper Community

1 ACCEPTED SOLUTION

Hi Nithin,



Here is a quick widget I made, however it does not have any save functionality so you would have to add that. Also the sn-record-picker does not allow to add an email address as the usual watch list field does. If your goal is only to display a read of what was set on creation than this would do the job by simply setting sn-disabled="true".



HTML:


<div ng-if="data.canRead" class="panel panel-primary b">


  <div class="panel-heading">


      <h4 class="panel-title pull-left">


          ${Watch list}


      </h4>


      <div class="clearfix"></div>


  </div>


  <div class="panel-body">


          <div class="text-center text-italic text-muted">


              <sn-record-picker field="watch_list" sn-disabled="!data.canWrite" table="'sys_user'" display-field="'name'" search-fields="'name'" value-field="'sys_id'" default-query="'active=true'" multiple="true"></sn-record-picker>


          </div>


  </div>


</div>



Client script:


function($scope, spUtil) {


      var c = this;


     


      $scope.watch_list = {  


              displayValue: c.data.displayValue,  


              value: c.data.value,


              name: 'watch_list'  


  };


}



Server script:


(function() {


     


      var table = $sp.getParameter('table')


      var sys_id = $sp.getParameter('sys_id')


      var gr = new GlideRecord(table);


      if(gr.get(sys_id)){


              data.canRead = gr.watch_list.canRead();


              data.canWrite = gr.watch_list.canWrite();


              if(data.canRead){


                      data.displayValue = gr.getDisplayValue('watch_list');


                      data.value = gr.getValue('watch_list');


              }


      }


})();



I know this is incomplete but I hope it helps.


View solution in original post

65 REPLIES 65

Ok so first I update the HTML so it checks for the canWrite for the Update button:



<div class="panel panel-default" ng-if="data.canRead">          


  <div class="panel-heading">          


      <h4 class="panel-title pull-left">          


          ${Watch list}          


      </h4>          


      <div class="clearfix"></div>          


  </div>                      


  <div class="panel-body">  


      <form ng-submit="save()">  


          <div class="text-center text-italic text-muted">  


              <div>  


                  <sn-record-picker field="watch_list" sn-disabled="!data.canWrite" table="'sys_user'" display-field="'email'" display-fields="'name'" search-fields="'email'" value-field="'sys_id'" default-query="'active=true^web_service_access_only=false^user_nameISNOTEMPTY^emailISNOTEMPTY'" page-size="10" multiple="true"></sn-record-picker>  


              </div>  


              <div style="margin-top:15px; float: right;">  


                  <button ng-disabled="!data.canWrite" type="submit" class="btn btn-default btn-sm">${Update}</button>  


              </div>  


          </div>  


      </form>  


  </div>  


</div>  



Then for the recordWatch I was able to use it however the way I use it does not match the documentaiton, the function callback of the recordWatch was returning me a single parameter which was the data object, I was not receiving any name... So if it does not work this way, you can try to change the callback function to function(name, data)



function($scope, spUtil, $http) {      


      var c = this;      


             


      $scope.watch_list = {      


              displayValue: c.data.displayValue,      


              value: c.data.value,      


              name: 'watch_list'  


      };      


      $scope.save = function(){      


              c.data.watchList = $scope.watch_list.value;      


              c.server.update().then(function(){      


              });      


      };      


      spUtil.recordWatch($scope, c.data.table, "sys_id=" + c.data.sys_id, function(data) {


if(data.data.operation == 'update'){


var activeUpdate = data.data.changes.indexOf('active') > -1;


var watchListUpdate = data.data.changes.indexOf('watch_list') > -1;


if(activeUpdate || watchListUpdate){


c.data.recordRefresh = true;


c.data.watchList = false; //Do not pass the watch list in the update


c.server.update().then(function(){


$scope.watch_list.displayValue = c.data.displayValue;


$scope.watch_list.value = c.data.value;


});


}


}    


      });      


}



We need to go back to server script because we cannot simply use the display value provided as we need to get the email addresses. So we simply server update and run the initialization script again, it is a light script so I'm not really worried about it's performance. I changed the condition for if(input.watchList) so that the other script is runned for other outputs.



(function() {      


      var gr;      


      if(input.watchList){  


gr = new GlideRecordSecure(input.table);      


if(gr.get(input.sys_id)){      


if(gr.watch_list.canWrite()){      


gr.watch_list = input.watchList;      


gr.update();      


gs.addInfoMessage('Updated');      


}      


else{      


gs.addErrorMessage("Update failed, you don't have the required access");      


}      


}


      }      


      else{      


              var table = $sp.getParameter('table');      


              var sys_id = $sp.getParameter('sys_id');      


              gr = new GlideRecord(table);      


              if(gr.get(sys_id)){      


                      data.table = table;      


                      data.sys_id = sys_id;      


                      data.canRead = gr.watch_list.canRead();      


                      data.canWrite = gr.watch_list.canWrite();      


                      if(data.canRead){


var emails = [];


if(!gr.watch_list.nil()){


var usersId = gr.getValue('watch_list').split(',');


var userDisplay = gr.watch_list.getDisplayValue().split(',');


usersId.forEach(function(userId, index){


var userGr = new GlideRecord('sys_user');


if(userGr.get(userId) && !userGr.email.nil()){


emails.push(userGr.getValue('email'));


}


else{


//Keep display value


emails.push(userDisplay[index]);


}


});


}


var dV = emails.join(',');


var sV = gr.getValue('watch_list');      


data.displayValue = dV;      


data.value = sV == null ? "" : sV;      


                      }      


              }      


      }      


})();  



Hope it works without bugs for you this time .


I think hiding the "Update" button is not enough for the behavior we want to achieve.



So here's what's my working code's behavior right now - when the incident's state is changed to Resolved or Closed, the snRecordPicker is disabled.This behavior is much better since users will only see a read-only view of the watch list. The problem with my current code is that it only works when you reload the page (whatever the state is during that reload), if ever the state changes to Resolved/Closed while use is viewing the page, the snRecordPicker does not update - that is where we need help, to make it update in real-time as state changes.



And by the way, on your server script, it will not allow a blank value (if user removes everything on watch list) to save since you used if(input.watchList){, we used if(input){ instead so it will accept blank value.



HTML


<div class="panel panel-default" ng-if="data.canRead">    


  <div class="panel-heading">    


      <h4 class="panel-title pull-left">    


          ${Watch list}    


      </h4>    


      <div class="clearfix"></div>    


  </div>                


  <div class="panel-body">


      <form ng-submit="save()">


          <div class="text-center text-italic text-muted">


              <div>


                  <sn-record-picker field="watch_list" sn-disabled="!data.canWrite||!data.editWatchlist" table="'sys_user'" display-field="'email'" display-fields="'name'" search-fields="'email'" value-field="'sys_id'" default-query="'active=true^web_service_access_only=false^user_nameISNOTEMPTY^emailISNOTEMPTY^emailNOT LIKEcorp.jgsummit^emailNOT LIKEonmicrosoft.com^emailNOT LIKElocal.com^emailNOT LIKE.local'" page-size="10" multiple="true"></sn-record-picker>


              </div>


              <div style="margin-top:15px; float: right;">


                  <button type="submit" class="btn btn-default btn-sm" ng-disabled="!data.canWrite">${Update}</button>


              </div>


          </div>


      </form>


  </div>


</div>



Client Script


function($scope, spUtil, $http) {


var c = this;




$scope.watch_list = {


displayValue: c.data.displayValue,


value: c.data.value,


name: 'watch_list'


};


$scope.save = function(){


c.data.watchList = $scope.watch_list.value;


c.server.update().then(function(){


});


};


spUtil.recordWatch($scope, c.data.table, "sys_id=" + c.data.sys_id, function(name, data) {


if(name.name == 'record.updated' && data.operation == 'update'){


$scope.watch_list.value = data.record.watch_list.value;


$scope.watch_list.displayValue = data.record.watch_list.display_value;


$scope.$apply();


}


});


$scope.$on("field.change", function(evt, parms) {


if (parms.field.name == 'watch_list'){


}


});


}



Server Script


(function() {


var gr;


if(input){


gr = new GlideRecord(input.table);


if(gr.get(input.sys_id)){


if(gr.watch_list.canWrite()){


gr.watch_list = input.watchList;


gr.update();


gs.addInfoMessage('Updated');


}


else{


gs.addErrorMessage("Update failed, you don't have the required access");


}


}


}


else{


var table = $sp.getParameter('table');


var sys_id = $sp.getParameter('sys_id');


gr = new GlideRecord(table);


if(gr.get(sys_id)){


data.table = table;


data.sys_id = sys_id;


data.canRead = gr.watch_list.canRead();


data.canWrite = gr.watch_list.canWrite();


if(data.canRead){


var emails = [];


if(!gr.watch_list.nil()){


var usersId = gr.getValue('watch_list').split(',');


var userDisplay = gr.watch_list.getDisplayValue().split(',');


usersId.forEach(function(userId, index){


var userGr = new GlideRecord('sys_user');


if(userGr.get(userId) && !userGr.email.nil()){


emails.push(userGr.getValue('email'));


}


else{


//Keep display value


emails.push(userDisplay[index]);


}


});


}


var dV = emails.join(',');


var sV = gr.getValue('watch_list');


data.displayValue = dV;


data.value = sV == null ? "" : sV;


}


}


}



// Check if current ticket is in Closed/Resolved State (make watch list read only)


if(data.table == 'incident' && gr.caller_id == gs.getUserID() && gr.state == 6||gr.state == 7){


data.editWatchlist = false;


} else {


data.editWatchlist = true;


}


// End



})();


You are right about the blank value.



However, maybe I was not explicit enough but the code I proposed does not simply grey out the update button, it updates the data.canWrite and data.canRead when the active field is updated. Also I changed the script so it uses the GlideRecordSecure API so that ACL are checked when the user update the watch list. For the part about the data.canRead and data.canWrite being evaluated on change of the active field, you could change that to the state field, you could also completely remove this condition to refresh the widget on each update if you want to make sure the ACL take into account any dynamic security rule you have:



var stateUpdate = data.data.changes.indexOf('state') > -1;


instead of


var activeUpdate = data.data.changes.indexOf('active') > -1;



and the condition would become if(stateUpdate || watchListUpdate)



As for the input being potentially blank, you can change condition to check for an explicit false boolean as we are passing false when simply refreshing the widget: if(input && input.watchList !== false)


Hi Laurent,



I have a requirement to add Watch list on create incident screen portal view.


i have created a widget and added to the variable (As per your above response). I could see watch-list field and update button, when I type in not getting any suggestion, i even entered complete emailId and clicked on Update button it's not capturing.



please respond. Thanks.


got this working in Kingston with some tweaking - but can't seem to allow ability to add email addresses. i added a separate textbox for the user to enter an email address into ...but can't get it to write to the watchlist on save. Any ideas?