Home Community Uploads
image

Cireson Partners, Customers and Community members share your customizations and examples here to help benefit the community as a whole to earn Kudos and badges.

DISCLAIMER

All files and projects located here are provided and come "as-is" and without any warranty or support. Use at your own risk. Your use of Community Uploads is subject to our Terms of Use.

Cireson does not and will not support or maintain these enhancements, extensions, and scripts.

For Team Cireson uploads click here.

How-To: Update User Details Input Screen For Analysts

Adrian_PaechAdrian_Paech Customer Advanced IT Monkey ✭✭✭
edited June 2016 in Community Uploads

Heya,

Our company had a requirement for analysts to be able to update user details on the fly when taking calls, or actioning incidents / service requests.
Our analysts don't use the console, so for us, we had to figure out a way of achieving the same thing via the portal.

I have been working on this for a couple of weeks now, and finally have it working.

Essentially you need to add a button somewhere on your incident form (or Service Request form), which will trigger an action and run the code. This will then open up an input form and allow the analyst to update details associated with the currently selected "Affected User".
Note: This solution will only update SCSM (not AD). You will need to setup a separate workflow or runbook to then push these changes back into AD. To do this, we also set a "syncToAD" Boolean value in SCSM. when when triggered, runs a workflow, which pushes all the changes back into AD.

Please note. I have commented out sections of code which are specific to our business unit, but they may still be useful for others.
For example, we have two enum lists, one for "Addresses", and another for "Offices" that we use to force analysts to pick specific entries, rather than use a free text field.

If you look through the code, you will be able to see where I have set this up, and you can uncomment these sections, update the enum GUID and you should be good to go.

Otherwise, you can leave the code as is, and you can just update free text input fields instead.

Also note, I could not get the AJAX Post calls working properly "without" disabling AJAX caching globally. With AJAX caching enabled globally (even with AJAX caching disabled on specific calls), user details were only updating intermittently or not at all, however they would update with the development tools enabled. This is known bug in IE, so to get around this I have added code at the top of Custom.js to disable AJAX caching globally. The Cireson guys may have a different trick to get around this.

Saying all that, I have not noticed any issues (or related slowness) with AJAX caching disabled.

Due to the limitations in characters of the post, I will post the code after this post.

Any questions, just ask, and I will try to help. :)

Adrian


Comments

  • Adrian_PaechAdrian_Paech Customer Advanced IT Monkey ✭✭✭
    edited June 2016

    To get this working, first you will need to add a button somewhere on the Incident.js or ServiceRequest.js forms:

    { DataType: "Button", PropertyDisplayName: "Update User Details", ButtonType: "Default", Action: "AffectedUser_UpdateDetails" }



    Then you will need to disable AJAX caching globally in the custom.js:

    //Disable AJAX Caching.
    // If caching is not disabled globally, there are problems saving user property back to SCSM via AJAX
    // (Potentially just related to IE11)
    $.ajaxSetup({ cache: false });



    Now you will need to add the calling "button" functions in your custom.js

    //Update User Details Button (on Incident Form)
    //Button Must Be Configured to Trigger Action: "AffectedUser_UpdateDetails"
    app.custom.formTasks.add('Incident', null, function(formObj, viewModel) {  
     viewModel.set("AffectedUser_UpdateDetails", function() {
      var userGUID = pageForm.viewModel.RequestedWorkItem.BaseId;
      UpdateUserDetails(userGUID);
     });
    });

    //Update User Details Button. (on Service Request Form)
    //Button Must Be Configured to Trigger Action: "AffectedUser_UpdateDetails"
    app.custom.formTasks.add('ServiceRequest', null, function(formObj, viewModel) {  
     viewModel.set("AffectedUser_UpdateDetails", function() {
      var userGUID = pageForm.viewModel.RequestedWorkItem.BaseId;
      UpdateUserDetails(userGUID);
     });
    });


    Now the "UpdateUserDetails" function that do the grunt work:

    /* Update User Details Function
    Input Parameter: "userGUID" = SCSM GUID of User to update.
    */
    function UpdateUserDetails(userGUID) {    
     //Store All Template Selection Data in HashTable
     var htTemplateDropDownData = new Object();
     
     /*
     //Get 'Business Unit' Drop Down Selection Box data from 'Customers' Enum
     //Append it to "htTemplateSelectionData" hash table
     var enumCustomers_ID = "46c85264-c896-bc2e-d131-255b4b5d32bd";
     $.ajax({
      url: "/api/V3/Enum/GetFlatList",
      data: {Id: enumCustomers_ID, itemFilter: ""},
      type: "GET",
      success: function (data) {
       //Adds all of the Enum elements to the dropdown (as text fields)
       appendTemplateDropDownData ("dropDownData_OFFICE", data);
      }
     });
     
     //Get 'Address Selection' Drop Down Selection Box data from 'Locations' Enum
     //Append it to "htTemplateSelectionData" hash table
     var enumCustomers_ID = "c6c024c7-9b5e-6705-394b-c6dbf69c8051";
     $.ajax({
      url: "/api/V3/Enum/GetFlatList",
      data: {Id: enumCustomers_ID, itemFilter: ""},
      type: "GET",
      success: function (data) {  
       //Adds all of the Enum elements to the dropdown (as text fields)
       appendTemplateDropDownData ("dropDownData_ADDRESS", data);
      }
     });
     */
     
     //Get Current User Properties
     //Then Load Template with UserProps and DropDown Data.
     var userProps;
     var url_getUserProps = "/Search/GetObjectPropertiesByProjection?projectionId=490ab845-b14c-1d91-c39f-bb9e8a350933&id="
     setTimeout(function (){
      $.get(url_getUserProps + userGUID, function (data) {
       objUser = data[0]; 
       loadTemplate(objUser, htTemplateDropDownData);
      });
     }, 1200);
     
     //Append to DropDownData
     function appendTemplateDropDownData (field, data) {
      htTemplateDropDownData[field] = data;
     }
     
     //Load Form to Update User Properties
     function loadTemplate (objUser, htDropDownData) {
            //use requires to load the HTML template first       
      require(["text!/CustomSpace/ext_UpdateUserDetails_template.html"],
                function (htmlTemplate) {
                    //make a jQuery obj
                    templateObj = $(htmlTemplate);
       
        //Create User Object for Updating.
        var strUser = JSON.stringify(objUser);
        var objUserUpdated = JSON.parse(strUser);   
       
                    //create a view model to handle the UX
                    var _vmWindow = new kendo.observable({
                        editFirstName: objUser.FirstName,
         editLastName: objUser.LastName,
         editTitle: objUser.Title,
         editMobile: objUser.Mobile,
         editBusinessPhone: objUser.BusinessPhone,
         //populate Drop Down options lists from pre-populated hash table.
         //dropDownData_OFFICE: htDropDownData["dropDownData_OFFICE"],
         //dropDownData_ADDRESS: htDropDownData["dropDownData_ADDRESS"],

                        valueChanged_ADDRESS : function(e) {
                            var dataItem = e.sender.dataItem();     
                            //console.log ("Selected Address: " + dataItem.Name);
                        },
         valueChanged_OFFICE : function(e) {
                            var dataItem = e.sender.dataItem(); 
                            //console.log ("Selected Location: " + dataItem.Name);
                        },
                        saveClick: function () {
          //Retrieve Updated Text Fields
          objUserUpdated.FirstName = this.editFirstName;
          objUserUpdated.LastName = this.editLastName;
          objUserUpdated.Title = this.editTitle;
          objUserUpdated.Mobile = this.editMobile;
          objUserUpdated.BusinessPhone = this.editBusinessPhone;
         
          //Retrieve Updated Drop Down Fields
          //objUserUpdated.StreetAddress = $("#editAddress option:selected").text();
          //objUserUpdated.Office = $("#editOffice option:selected").text();
         
          //Sets extended class property "Sync Changes To AD" to "true"
          //This kicks of a Powershell workflow in SCSM, which syncs all changes back into AD.
          //objUserUpdated.SyncChangesToAD = true;
         
          //Call AJAX Function to update User Details.
          UpdateUserProperties(objUser, objUserUpdated); 
         
                            customWindow.close();
                        },
                        cancelClick: function () {
                            customWindow.close();

                        }
                    });
                
                    //create the kendo window
                    customWindow = templateObj.kendoWindow({
                        title: "Update User Details",
                        resizable: false,
                        modal: true,
                        viewable: false,
                        width: 400,
                        height: 500,
                        close: function () {
          kendo.unbind(templateObj);
                        },
                        activate: function () {
                            //on window activate bind the view model to the loaded template content
                            kendo.bind(templateObj, _vmWindow);
               
          //Update "Office" DropDown to be set to currently selected Business Unit.                 
          //$("#editOffice").data("kendoDropDownList").search(objUser.Office);
              
          //Update "Address" DropDown to be set to currently selected Street Address.     
          //$("#editAddress").data("kendoDropDownList").search(objUser.StreetAddress);     
                        },
         deactivate: function() {
                            //Required, otherwise there will be problems when re-opening the window again.
          this.destroy();
         }    
                    }).data("kendoWindow");
                
                    //now open the window
                    customWindow.open().center();
                }
            );
        }
     
     //Update User Details
     function UpdateUserProperties (objUser, objUserUpdated) {
      var strData = { "formJson":{"original": objUser, "current": objUserUpdated}}
            //console.log (strData); 
      $.ajax({
       url: "/api/V3/Projection/Commit",
       type: "POST",
       contentType: "application/json; charset=utf-8",
       dataType: "json",
       data: JSON.stringify(strData) ,
       success: function (d) {
        //console.log(d);
        kendo.ui.ExtAlertDialog.show({
                        title: "Update User Details",
                        message: (objUserUpdated.DisplayName + " (" + objUserUpdated.UserName + ") updated successfully!")
                    });
       },
       error: function (d) {
        kendo.ui.ExtAlertDialog.show({
                        title: "Update User Details",
                        message: (objUserUpdated.DisplayName + " (" + objUserUpdated.UserName + ") update failed! Please reload the page and try again.")
                    });
       }
      });
     } 
    }

  • Adrian_PaechAdrian_Paech Customer Advanced IT Monkey ✭✭✭

    Just a quick thought. You could alternatively trigger the "Update User Details" function from a task instead of a button, which might be a bit cleaner. Its really up to you. :)

    Cheers,

    Adrian

  • David_MeldrumDavid_Meldrum Member IT Monkey ✭
    Hi Adrian,

    Sounds like a great solution to implement. I've tried your code however I've found that when the incident form is opened, the browser (element inspector) complains about a .html template file not being found (404). When I add a blank .html file, clicking on the action button does nothing. Any idea? Is it looking for some particular content in the html template?

    Cheers,
    David
  • Adrian_PaechAdrian_Paech Customer Advanced IT Monkey ✭✭✭
    edited August 2016

    Hi David,

    I forgot to upload the form template for updating the user details, my apologies.

    To make things easier, I have uploaded two separate versions of the extension:

    • UpdateUserDetails (text).zip = Text Only Fields (Custom.js + Form)
    • UpdateUserDetails (text).zip = Drop Down List Fields (Custom.js + Form)

    The "Drop Down List" version requires you to have specific enums that you link to to pull values that you want the analyst to select from. The "Text Only" only uses free text fields.

    Both files will need to be placed in CustomSpace.

    You will also need to add the button in the "Incident.js" or "ServiceRequest.js" form e.g.:

    { DataType: "Button", PropertyDisplayName: "Update User Details", ButtonType: "Default", Action: "AffectedUser_UpdateDetails" },

    Hope this helps :)

    Keep in mind this only updates changes to SCSM, not back into AD. you will need to trigger the change to push into AD separately via a workflow or runbook.

    Let me know if you still have issues, and I will try to assist.

    Regards,

    Adrian

  • David_MeldrumDavid_Meldrum Member IT Monkey ✭
    Perfect! Thanks for updating this so promptly. It works perfectly now!

    Have you experimented with creating any Runbooks to push changes back in to AD?

    Thanks again!

    David

  • Adrian_PaechAdrian_Paech Customer Advanced IT Monkey ✭✭✭

    Glad its working.

    I didn't bother using a runbook in this scenario, I used a workflow instead, which is much quicker. (takes 1 minute max to push changes back into AD).

    In the "ddList" version, you will notice line 121 which sets a variable on the user object called "SyncChangesToAD".

    I extended the "Active Directory User" class, and added the "SyncChangesToAD" field as a "Boolean" value, ensuring the default value is always set to "False".

    When the value gets changed from "false" to "true" (applied as part of the "Update User Details" function in the portal), it triggers a workflow to automatically run in the back-end, which than runs a powershell script to push the changes into AD. Once completed it changes the user's "SyncChangesToAD" back to false.

    If your willing to give it a go, this is a much cleaner / slicker way to do sync changes back into AD, rather than using a runbook..

    Hope this helps.

    Regards,

    Adrian

  • Thanks for Sharing this! Moving to the new "Community Uploads" Category for better viability and to help anyone else wanting to implement \ learn 
Sign In or Register to comment.