Collaboration Store, Part LII

“Long is the road from conception to completion.”
Molière

Last time, we finished up the Update Set Preview process and it looked like all that was left was to code out the Commit process and we would be done with the last major component of this long drawn-out project. Unfortunately, that’s not entirely true. Before we can move on to the Commit process, we have to deal with the fact that the Preview process may have uncovered some issues with the Update Set. In the manual process, these issues are reported to the operator, and the operator is required to deal them all before the Commit option is available. Not only do we need to address that possibility, we also have to add code to update the application and version records to reflect the version that was just installed and to link the newly installed application with the application record. So we have a little more work to do beyond just launching the Commit process before we can declare project completion.

First of all, we need to decide what to do with any Preview issues that may have been detected. Ideally, you would want to give the operator the opportunity to review these issues and make the appropriate decisions based on their knowledge of their instance and the application. However, since we are trying to make this first version as automated as possible, I have decided to have the software make arbitrary decisions about each reported problem, at least for now. In some future version, I may want to pop up a dialog and ask the operator whether they want to do their own review or trust the system to do it for them, but for now, that’s a little more sophisticated than I am ready to tackle. This may not be the best approach, but it is the simplest, and I am trying wrap up the work on this initial version.

My plan is to add yet another client-callable function to our existing ApplicationInstaller Script Include that will hunt down all of the problems and resolve them. The problem records have a field called available_actions that contains a list of all of the actions available for the problem, so I am going to use that as a guide to Accept Remote Update if I can, or Skip Remote Update if I cannot. I also want to keep track of the number of problems found, the number of updates accepted, and the number of updates skipped so that I can report that information back to the caller. In reviewing the code behind the UI Actions that accept and skip updates, I found a call to a global component called GlidePreviewProblemAction, but when I tried to access that component in my scoped Script Include, I got a security violation error. To work around that, I had to add the following new function to our global utilities, where I could make the call without error.

fixRemoteUpdateIssue: function(remUpdGR) {
	var resolution = 'accepted';
	var ppa = new GlidePreviewProblemAction(gs.action, remUpdGR);
	if (remUpdGR.available_actions.contains('43d7d01a97b00100f309124eda2975e4')) {
		ppa.ignoreProblem();
	} else {
		ppa.skipUpdate();
		resolution = 'skipped';
	}
	return resolution;
}

With that out of the way, I was able to put the rest of the code where it belonged, and just called out to the global component for the part that I was unable to do in the scoped component.

evaluatePreview: function() {
	var answer = {problems: 0, accepted: 0, skipped: 0};
	var sysId = this.getParameter('remote_update_set_id');
	if (sysId) {
		problemId = [];
		var remUpdGR = new GlideRecord('sys_update_preview_problem');
		remUpdGR.addQuery('remote_update_set', sysId);
		remUpdGR.query();
		while (remUpdGR.next()) {
			problemId.push(remUpdGR.getUniqueValue());
			answer.problems++;
		}
		var csgu = new global.CollaborationStoreGlobalUtils();
		for (var i=0; i<problemId.length; i++) {
			remUpdGR.get(problemId[i]);
			var resolution = csgu.fixRemoteUpdateIssue(remUpdGR);
			if (resolution == 'accepted') {
				answer.accepted++;
			} else {
				answer.skipped++;
			}
		}
	}
	return JSON.stringify(answer);
}

Now we just need make the GlideAjax call to that function from the client side before we attempt to launch the Commit process. Right now, when the Preview process is complete, a Close button appears on the progress dialog, and when you click on the Close button, our new UI Page reloads and starts all over again because the script that we lifted from the UI Action on the Update Set form was set up to reload that form. For our purposes, we do not want our own page reloaded, and in fact, we don’t even want a Close button; we just want to move on to the process of reviewing the results of the Preview. The relevant portion of the script that we stole looks like this:

dd.on("executionComplete", function(trackerObj) {
	var cancelBtn = $("sysparm_button_cancel");
	if (cancelBtn)
		cancelBtn.remove();
         
	var closeBtn = $("sysparm_button_close");
	if (closeBtn) {
		closeBtn.onclick = function() {
			dd.destroy();
		};
	}
});
     
dd.on("beforeclose", function() {
	reloadWindow(window);
});

Since we do not want to wait for operator action, we can short-cut this entire operation and just move on as soon as execution has been completed. I replaced all of the above with the following:

dd.on("executionComplete", function(trackerObj) {
	dd.destroy();
	checkPreviewResults();
});

Since the Preview process is now complete at this point, and we are now looking at the results, I decided to wrap the original message on the page with a span that had an id attribute so that I could change the message as things moved along. That line of HTML now looks like this:

<span id="status_text">Previewing Uploaded Update Set ...</span>

With that in place, I was able to update the message with the new status before I made the Ajax call to our new Script Include function.

function checkPreviewResults() {
	document.getElementById('status_text').innerHTML = 'Evaluating Preview Results ...';
	var ga = new GlideAjax('ApplicationInstaller');
	ga.addParam('sysparm_name', 'evaluatePreview');
	ga.addParam('remote_update_set_id', updateSetId);
	ga.getXMLAnswer(commitUpdateSet);
}

function commitUpdateSet(answer) {
	alert(answer);
}

I’m not ready to take on the Commit process just yet, so I stubbed out the commitUpdateSet function with a simple alert of the response from our Ajax call. That was enough to let me know that everything was working up to this point, which is what I needed to know before I attempted to move on.

Now that we have dealt with the possibility of Preview problems, we can finally take a look at what it will take to Commit the Update Set. That’s obviously a bit of work, so we’ll leave all of that for our next episode.