Name
global.WorkflowTimeline
Description
Schedule page script include for the generating a view that shows a workflow context on the Timeline. See the AbstractTimelineSchedulePage script include description for correct implementation and API usage.
Script
var TimelineItem = GlideTimelineItem;
var WorkflowTimeline = Class.create();
WorkflowTimeline.prototype = Object.extendsObject(AbstractTimelineSchedulePage, {
getItems: function() {
var history = this.getParameter('sysparm_timeline_history');
var au = new ArrayUtil();
if (JSUtil.notNil(history)) {
var contexts = this._getContexts(history);
this._constructPageTitle(contexts);
for (var context in contexts) {
var contextItem = new TimelineItem(new Date().getTime());
contextItem.setLeftLabelText(this._getLabelForRecord(context));
contextItem.setImage('images/workflow/wkfl_all.gif');
contextItem.setTextBold(true);
var contextId = contextItem.getSysId();
this.add(contextItem);
var model = new WorkflowModelManager(context);
var activities = model.getExecutedHistory();
var list = contexts[context];
var activity = model.begin;
while (activity != null) {
// This basically says if we don't have a list of activities, it means we got a workflow
// context, not a list of history items, so just include all items, otherwise go and see
// if the history item was a selected history item before displaying it
if (gs.nil(list) || au.contains(list, activity.sys_id)) {
var item = this._getItem(activity);
item.contextItem = contextId;
var previous = model.getPreviousByTransition(activity);
if (!gs.nil(previous)) {
var parents = item.parents;
for (var p = 0; p < previous.length; p++)
if (gs.nil(list) || au.contains(list, previous[p].sys_id))
parents.push(previous[p].sys_id);
}
this._item_map[item.sysId] = item;
}
activity = model.getNextByExecutedOrder(activity);
}
}
// Now render the list of items
this._treeify();
for (var item in this._item_map)
this._renderItem(this._item_map[item]);
}
},
_getContexts: function(history) {
var contexts = {};
// If the history variable is for wf_history and has a comma in it, we're getting the sys ids for multiple
// individual history records, so fetch those records, otherwise get all of them for the given workflow context
if (history.indexOf('wf_history') > -1) {
var gr = new GlideRecord('wf_history');
history = history.substring(10);
var list = new Packages.java.util.ArrayList();
var histids = [];
if (history.indexOf(',') > -1) {
var ids = history.split(',');
for (var i = 0; i < ids.length; i++) {
list.add('' + ids[i]);
histids.push('' + ids[i]);
}
} else {
list.add(history);
histids.push(history);
}
gr.addQuery('sys_id', list);
gr.query();
while (gr.next()) {
var id = '' + gr.context.sys_id;
if (gs.nil(contexts[id]))
contexts[id] = histids;
}
} else
contexts[history] = null;
return contexts;
},
_constructPageTitle: function(contexts) {
var pageTitle = 'Workflow context';
var contextCount = 0;
for (var c in contexts)
contextCount++;
if (contextCount == 1) {
var gr = new GlideRecord('wf_context');
for (var c in contexts) {
if (gr.get(c)) {
pageTitle += ': ' + gr.workflow_version.name;
if (JSUtil.notNil(gr.table)) {
pageTitle += ', ' + GlideTableDescriptor.get(gr.table).getLabel();
var displayValue = JSUtil.notNil(gr.id.getDisplayValue()) ? gr.id.getDisplayValue() : gr.id;
pageTitle += ': ' + displayValue;
}
}
else
pageTitle += ': UNKNOWN';
}
} else
pageTitle += ': Multiple contexts';
this.setPageTitle(pageTitle);
},
_getLabelForRecord: function(recordId) {
var label = '';
if (!gs.nil(recordId)) {
var gr = new GlideRecord('wf_context');
if (gr.get(recordId))
label = gr.workflow_version.name;
if (JSUtil.notNil(gr.table)) {
label += ', ' + GlideTableDescriptor.get(gr.table).getLabel();
var displayValue = JSUtil.notNil(gr.id.getDisplayValue()) ? gr.id.getDisplayValue() : gr.id;
label += ': ' + displayValue;
}
}
return label;
},
_renderItem: function(queueItem) {
var item = new TimelineItem('wf_history', queueItem.sysId);
item.setParent(queueItem.contextItem);
var span = item.createTimelineSpan('wf_history', queueItem.sysId);
span.setTimeSpan(queueItem.startTime, queueItem.endTime);
span.setSpanText(queueItem.text);
span.setSpanColor(queueItem.spanColor);
span.setInnerSegmentTimeSpan(queueItem.innerSegStartTime, queueItem.innerSegEndTime);
span.setInnerSegmentClass(queueItem.innerClass);
item.setLeftLabelText(queueItem.text);
var image = this._getActivityImage(queueItem.activityId);
if (image)
item.setImage(image);
for (var i = 0; i < queueItem.parents.length; i++) {
span.addPredecessor(queueItem.parents[i]);
item.setParent(queueItem.parents[i]);
}
var tooltip = '';
for (var i = 0; i < queueItem.tips.length; i++) {
var tip = queueItem.tips[i];
tooltip += '<strong>' + tip.title + ': </strong>' + tip.value + '<br/>';
}
if (tooltip)
span.setTooltip(tooltip);
// Finally, add the item (which contains the span).
this.add(item);
},
//////////////////////////////////////////////////////////////////////////////////////////////////
// CORE OBJECT
//////////////////////////////////////////////////////////////////////////////////////////////////
// map of items by sys_id
_item_map: {},
_addTooltips: function(item, activity) {
this._addTooltip(item, "Name", activity.wfaName);
this._addTooltip(item, "Activity definition name", activity.adName);
var processedTime = this._getProcessedTime(item, activity);
this._addTooltip(item, "Activity processing time", processedTime);
this._addTooltip(item, "Start time", this._getTimeDisplay(activity.startTime));
this._addTooltip(item, "End time", this._getTimeDisplay(activity.endTime));
},
_getItem: function(activity) {
var item = {};
item.sysId = activity.sys_id;
item.startTime = activity.startTime;
item.endTime = activity.endTime;
item.innerSegStartTime = activity.startTime;
item.innerSegEndTime = activity.endTime;
item.text = activity.wfaName;
item.innerClass = activity.adName == 'Workflow' ? 'blue' : 'green';
item.spanColor = 'tomato';
item.activityId = activity.adId;
item.tips = [];
item.kids = [];
item.parents = [];
this._addTooltips(item, activity);
return item;
},
_treeify: function() {
for (var sys_id in this._item_map) {
var item = this._item_map[sys_id];
for (var i = 0; i < item.parents.length; i++) {
var parent = this._item_map[item.parents[i]];
if (parent)
parent.kids.push(item);
}
}
},
_getActivityImage: function(activityId) {
if (gs.nil(activityId))
return null;
var gr = new GlideRecord('wf_activity_definition');
if (gr.get(activityId))
return gr.image;
return null;
},
_getTimeDisplay: function(time) {
var gdt = new GlideDateTime();
gdt.setNumericValue(time);
return gdt.getDisplayValue();
},
_getProcessedTime: function(activity) {
var timeStart = parseInt(activity.startTime, 10);
var timeEnd = parseInt(activity.endTime, 10);
return this._getTimeDurationDisplay(timeEnd - timeStart);
},
_getTimeDurationDisplay: function(timeDuration) {
var d = new GlideDuration();
d.setNumericValue(timeDuration);
return d.getDisplayValue();
},
_addTooltip: function(item, title, value) {
var tip = {};
tip.title = title;
tip.value = value;
item.tips.push(tip);
},
type: 'WorkflowTimeline'
});
Sys ID
313d4ff207130000dada43c0d1021e90