
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-10-2021 11:46 PM
Hi everyone,
I've recently been requested to change the OOTB Propose Major Incident UI Action to change which fields are mandatory when proposing a major incident. Right now, the only mandatory field in the dialog box is Work Notes, we want to make Business Impact required as well. How can I change this?
How can I achieve the mandatory state Work Notes has and apply it to Business Impact as well?
Kind regards
Solved! Go to Solution.
- Labels:
-
Major Incident Management
- 2,728 Views

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-12-2021 03:18 PM
Hey,
The client script is directly below the HTML of the UI Page. You should end up with something like the below:
HTML:
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<g:evaluate var="jvar_isNextPg" expression="RP.getParameterValue('sysparm_next_pg')"/>
<j:if test="${jvar_isNextPg == 'true'}">
<style>
.no_next {
display: none !important;
}
</style>
</j:if>
<style>
body {
overflow-x: hidden;
}
.form-horizontal {
margin-top: 5px;
margin-bottom: 20px;
}
.propose-modal-textarea {
resize: vertical;
min-height: 120px
}
#dialog_buttons .btn{
margin-left: 10px;
padding-left: 15px;
padding-right: 15px;
}
#work-notes-wrapper .required-marker{
display: inline-block;
}
#business-impact-wrapper .required-marker{
display: inline-block;
}
#page_timing_div {
display:none !important;
}
</style>
<script>
var config = {
workspace: '${JS_STRING:RP.getParameterValue('sysparm_workspace')}' == 'true'
};
var iframeMsgHelper = (function () {
function createPayload(action, modalId, data) {
return {
messageType: 'IFRAME_MODAL_MESSAGE_TYPE',
modalAction: action,
modalId: modalId,
data: (data ? data : {})
};
}
function pm(window, payload) {
if (window.parent === window) {
console.warn('Parent is missing. Is this called inside an iFrame?');
return;
}
window.parent.postMessage(payload, location.origin);
}
function IFrameMessagingHelper(window) {
this.window = window;
this.src = location.href;
this.messageHandler = this.messageHandler.bind(this);
this.window.addEventListener('message', this.messageHandler);
}
IFrameMessagingHelper.prototype.messageHandler = function (e) {
if (e.data.messageType !== 'IFRAME_MODAL_MESSAGE_TYPE' || e.data.modalAction !== 'IFRAME_MODAL_ACTION_INIT') {
return;
}
this.modalId = e.data.modalId;
};
IFrameMessagingHelper.prototype.confirm = function (data) {
var payload = createPayload('IFRAME_MODAL_ACTION_CONFIRMED', this.modalId, data);
pm(this.window, payload);
};
IFrameMessagingHelper.prototype.cancel = function (data) {
var payload = createPayload('IFRAME_MODAL_ACTION_CANCELED', this.modalId, data);
pm(this.window, payload);
};
return new IFrameMessagingHelper(window);
}());
</script>
<div class="form-horizontal no_next">
<div class="form-group" id="work-notes-wrapper">
<label class="col-sm-2 control-label" for="mim-propose-work-notes">
<span mandatory="true" class="required-marker"></span>
${gs.getMessage('Work notes')}
</label>
<div class="col-sm-10">
<textarea required="true" class="form-control propose-modal-textarea" id="mim-propose-work-notes" type="text" oninput="proposeModal.workNotesOnChange()" onchange="proposeModal.workNotesOnChange()"></textarea>
</div>
</div>
<div class="form-group" id="business-impact-wrapper">
<label class="col-sm-2 control-label" for="mim-propose-business-impact">
<span mandatory="true" class="required-marker"></span>
${gs.getMessage('Business Impact')}
</label>
<div class="col-sm-10">
<textarea required="true" class="form-control propose-modal-textarea" name="mim-propose-business-impact" id="mim-propose-business-impact" oninput="proposeModal.businessImpactOnChange()" onchange="proposeModal.businessImpactOnChange()"></textarea>
</div>
</div>
</div>
<div id="dialog_buttons" class="clearfix pull-right no_next">
<button type="button" class="btn btn-default" onclick="proposeModal.close()" title="${gs.getMessage('Close the dialog')}">${gs.getMessage('Cancel')}</button>
<button type="button" class="btn btn-primary disabled" aria-disabled="true" id="mim-propose-button" title="${gs.getMessage('Propose Major Incident')}" onclick="proposeModal.propose()">${gs.getMessage('Propose')}</button>
</div>
</j:jelly>
And in the Client Script:
addLoadEvent(function() {
(function(global) {
var workNotes = $("mim-propose-work-notes");
var businessImpact = $("mim-propose-business-impact");
var workNotesWrapper = $('work-notes-wrapper');
var bussImpWrapper = $("business-impact-wrapper");
var proposeBtn = $('mim-propose-button');
workNotes.focus();
var dialog;
if(!config.workspace) {
dialog = GlideModal.prototype.get("sn_major_inc_mgmt_mim_propose");
var currentWorkNotes = dialog.getPreference('WORK_NOTES');
if(currentWorkNotes) {
workNotes.value = currentWorkNotes;
workNotesOnChange();
}
var currentBusinessImpact = dialog.getPreference('BUSINESS_IMPACT');
if(currentBusinessImpact)
businessImpact.value = currentBusinessImpact;
}
function _debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
function workNotesOnChange() {
if (!workNotes.value.trim()) {
workNotesWrapper.removeClassName('is-filled');
proposeBtn.addClassName('disabled');
proposeBtn.writeAttribute('aria-disabled', true);
} else {
// workNotesWrapper.addClassName('is-filled');
// proposeBtn.removeClassName('disabled');
// proposeBtn.writeAttribute('aria-disabled', false);
checkMandatoryFields();
}
}
function businessImpactOnChange() {
if (!businessImpact.value.trim()) {
bussImpWrapper.removeClassName('is-filled');
proposeBtn.addClassName('disabled');
proposeBtn.writeAttribute('aria-disabled', true);
} else {
// bussImpWrapper.addClassName('is-filled');
// proposeBtn.removeClassName('disabled');
// proposeBtn.writeAttribute('aria-disabled', false);
checkMandatoryFields();
}
}
function checkMandatoryFields(){
if(workNotes.value.trim() && businessImpact.value.trim()){
bussImpWrapper.addClassName('is-filled');
proposeBtn.removeClassName('disabled');
proposeBtn.writeAttribute('aria-disabled', false);
workNotesWrapper.addClassName('is-filled');
proposeBtn.removeClassName('disabled');
proposeBtn.writeAttribute('aria-disabled', false);
}
}
function propose() {
if (!proposeBtn.hasClassName('disabled')) {
var msg = getMessage("Proposed as major incident candidate");
var notes = workNotes.value.trim();
var bi = businessImpact.value.trim();
if(!config.workspace) {
g_form.getControl('work_notes').value = msg + "\n" + notes;
if (businessImpact.value)
g_form.setValue('business_impact', bi);
close();
gsftSubmit(null, g_form.getFormElement(), 'sysverb_mim_propose');
}else {
iframeMsgHelper.confirm({
msg: msg,
workNotes: notes,
businessImpact: bi
});
}
}
}
function close() {
if(!config.workspace)
dialog.destroy();
else
window.location.href = window.location.href + '&sysparm_next_pg=true';
}
global.proposeModal = {
propose: propose,
close: close,
workNotesOnChange: _debounce(workNotesOnChange, 200),
businessImpactOnChange: _debounce(businessImpactOnChange, 200)// Only execute when left idle for 200 ms
};
})(window);
});

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-11-2021 04:16 PM
Hi,
you'll need to modify the mim_propose UI Page to add the following line at line 88 onto line 96
<span mandatory="true" class="required-marker"></span>
You'll also need to duplicate the workNotesOnChange client script to mimic the behaviour for your business impact field.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-11-2021 11:45 PM
Hi Kieran,
I've edited the UI Page by adding your line of code here:
<div class="form-horizontal no_next">
<div class="form-group" id="work-notes-wrapper">
<label class="col-sm-2 control-label" for="mim-propose-work-notes">
<span mandatory="true" class="required-marker"></span>
${gs.getMessage('Work notes')}
</label>
<div class="col-sm-10">
<textarea required="true" class="form-control propose-modal-textarea" id="mim-propose-work-notes" type="text" oninput="proposeModal.workNotesOnChange()" onchange="proposeModal.workNotesOnChange()"></textarea>
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label" for="mim-propose-business-impact"><span mandatory="true" class="required-marker"></span>${gs.getMessage('Business Impact')}</label>
<div class="col-sm-10">
<textarea class="form-control propose-modal-textarea" name="mim-propose-business-impact" id="mim-propose-business-impact"></textarea>
</div>
</div>
</div>
What am I missing? The field is not mandatory as per this change. What do you mean with "You'll also need to duplicate the workNotesOnChange client script to mimic the behaviour for your business impact field."
I can't find a client script with that name.
Kind regards,

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-12-2021 03:18 PM
Hey,
The client script is directly below the HTML of the UI Page. You should end up with something like the below:
HTML:
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
<g:evaluate var="jvar_isNextPg" expression="RP.getParameterValue('sysparm_next_pg')"/>
<j:if test="${jvar_isNextPg == 'true'}">
<style>
.no_next {
display: none !important;
}
</style>
</j:if>
<style>
body {
overflow-x: hidden;
}
.form-horizontal {
margin-top: 5px;
margin-bottom: 20px;
}
.propose-modal-textarea {
resize: vertical;
min-height: 120px
}
#dialog_buttons .btn{
margin-left: 10px;
padding-left: 15px;
padding-right: 15px;
}
#work-notes-wrapper .required-marker{
display: inline-block;
}
#business-impact-wrapper .required-marker{
display: inline-block;
}
#page_timing_div {
display:none !important;
}
</style>
<script>
var config = {
workspace: '${JS_STRING:RP.getParameterValue('sysparm_workspace')}' == 'true'
};
var iframeMsgHelper = (function () {
function createPayload(action, modalId, data) {
return {
messageType: 'IFRAME_MODAL_MESSAGE_TYPE',
modalAction: action,
modalId: modalId,
data: (data ? data : {})
};
}
function pm(window, payload) {
if (window.parent === window) {
console.warn('Parent is missing. Is this called inside an iFrame?');
return;
}
window.parent.postMessage(payload, location.origin);
}
function IFrameMessagingHelper(window) {
this.window = window;
this.src = location.href;
this.messageHandler = this.messageHandler.bind(this);
this.window.addEventListener('message', this.messageHandler);
}
IFrameMessagingHelper.prototype.messageHandler = function (e) {
if (e.data.messageType !== 'IFRAME_MODAL_MESSAGE_TYPE' || e.data.modalAction !== 'IFRAME_MODAL_ACTION_INIT') {
return;
}
this.modalId = e.data.modalId;
};
IFrameMessagingHelper.prototype.confirm = function (data) {
var payload = createPayload('IFRAME_MODAL_ACTION_CONFIRMED', this.modalId, data);
pm(this.window, payload);
};
IFrameMessagingHelper.prototype.cancel = function (data) {
var payload = createPayload('IFRAME_MODAL_ACTION_CANCELED', this.modalId, data);
pm(this.window, payload);
};
return new IFrameMessagingHelper(window);
}());
</script>
<div class="form-horizontal no_next">
<div class="form-group" id="work-notes-wrapper">
<label class="col-sm-2 control-label" for="mim-propose-work-notes">
<span mandatory="true" class="required-marker"></span>
${gs.getMessage('Work notes')}
</label>
<div class="col-sm-10">
<textarea required="true" class="form-control propose-modal-textarea" id="mim-propose-work-notes" type="text" oninput="proposeModal.workNotesOnChange()" onchange="proposeModal.workNotesOnChange()"></textarea>
</div>
</div>
<div class="form-group" id="business-impact-wrapper">
<label class="col-sm-2 control-label" for="mim-propose-business-impact">
<span mandatory="true" class="required-marker"></span>
${gs.getMessage('Business Impact')}
</label>
<div class="col-sm-10">
<textarea required="true" class="form-control propose-modal-textarea" name="mim-propose-business-impact" id="mim-propose-business-impact" oninput="proposeModal.businessImpactOnChange()" onchange="proposeModal.businessImpactOnChange()"></textarea>
</div>
</div>
</div>
<div id="dialog_buttons" class="clearfix pull-right no_next">
<button type="button" class="btn btn-default" onclick="proposeModal.close()" title="${gs.getMessage('Close the dialog')}">${gs.getMessage('Cancel')}</button>
<button type="button" class="btn btn-primary disabled" aria-disabled="true" id="mim-propose-button" title="${gs.getMessage('Propose Major Incident')}" onclick="proposeModal.propose()">${gs.getMessage('Propose')}</button>
</div>
</j:jelly>
And in the Client Script:
addLoadEvent(function() {
(function(global) {
var workNotes = $("mim-propose-work-notes");
var businessImpact = $("mim-propose-business-impact");
var workNotesWrapper = $('work-notes-wrapper');
var bussImpWrapper = $("business-impact-wrapper");
var proposeBtn = $('mim-propose-button');
workNotes.focus();
var dialog;
if(!config.workspace) {
dialog = GlideModal.prototype.get("sn_major_inc_mgmt_mim_propose");
var currentWorkNotes = dialog.getPreference('WORK_NOTES');
if(currentWorkNotes) {
workNotes.value = currentWorkNotes;
workNotesOnChange();
}
var currentBusinessImpact = dialog.getPreference('BUSINESS_IMPACT');
if(currentBusinessImpact)
businessImpact.value = currentBusinessImpact;
}
function _debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this,
args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
}
function workNotesOnChange() {
if (!workNotes.value.trim()) {
workNotesWrapper.removeClassName('is-filled');
proposeBtn.addClassName('disabled');
proposeBtn.writeAttribute('aria-disabled', true);
} else {
// workNotesWrapper.addClassName('is-filled');
// proposeBtn.removeClassName('disabled');
// proposeBtn.writeAttribute('aria-disabled', false);
checkMandatoryFields();
}
}
function businessImpactOnChange() {
if (!businessImpact.value.trim()) {
bussImpWrapper.removeClassName('is-filled');
proposeBtn.addClassName('disabled');
proposeBtn.writeAttribute('aria-disabled', true);
} else {
// bussImpWrapper.addClassName('is-filled');
// proposeBtn.removeClassName('disabled');
// proposeBtn.writeAttribute('aria-disabled', false);
checkMandatoryFields();
}
}
function checkMandatoryFields(){
if(workNotes.value.trim() && businessImpact.value.trim()){
bussImpWrapper.addClassName('is-filled');
proposeBtn.removeClassName('disabled');
proposeBtn.writeAttribute('aria-disabled', false);
workNotesWrapper.addClassName('is-filled');
proposeBtn.removeClassName('disabled');
proposeBtn.writeAttribute('aria-disabled', false);
}
}
function propose() {
if (!proposeBtn.hasClassName('disabled')) {
var msg = getMessage("Proposed as major incident candidate");
var notes = workNotes.value.trim();
var bi = businessImpact.value.trim();
if(!config.workspace) {
g_form.getControl('work_notes').value = msg + "\n" + notes;
if (businessImpact.value)
g_form.setValue('business_impact', bi);
close();
gsftSubmit(null, g_form.getFormElement(), 'sysverb_mim_propose');
}else {
iframeMsgHelper.confirm({
msg: msg,
workNotes: notes,
businessImpact: bi
});
}
}
}
function close() {
if(!config.workspace)
dialog.destroy();
else
window.location.href = window.location.href + '&sysparm_next_pg=true';
}
global.proposeModal = {
propose: propose,
close: close,
workNotesOnChange: _debounce(workNotesOnChange, 200),
businessImpactOnChange: _debounce(businessImpactOnChange, 200)// Only execute when left idle for 200 ms
};
})(window);
});

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎03-31-2021 04:41 AM
Thank you, works flawlessly