Skip to content

Instantly share code, notes, and snippets.

@eduglez
Created May 30, 2019 13:34
Show Gist options
  • Save eduglez/8ee6086ca7761ddb0f954d6db5553b63 to your computer and use it in GitHub Desktop.
Save eduglez/8ee6086ca7761ddb0f954d6db5553b63 to your computer and use it in GitHub Desktop.
ServiceNow - Generate documentation in Markdown directly from the browser console
(function(){
var text = "";
var printl = function(str){
text = text + str + '\n';
};
var println = function(str) {
if(str){
text = text + str + '\n\n';
}else{
text = text + '\n';
}
};
var parseUrl = function(url) {
var currentUrl = '';
if(url.indexOf('/') < 1){
currentUrl = url;
}else{
currentUrl = (new URL(url)).searchParams.get('uri') || url.substring(url.lastIndexOf('/'));
currentUrl = decodeURI(currentUrl);
}
currentUrl = currentUrl.substring(currentUrl.indexOf('/')+1);
var tableName = currentUrl.substring(0, currentUrl.indexOf(".do"));
var query;
if(tableName.endsWith('_list')){
tableName = tableName.substring(0, tableName.lastIndexOf('_list'));
query = (new URL('http://fakeorigin/'+currentUrl)).searchParams.get('sysparm_query');
}else{
query = 'sys_id='+(new URL('http://fakeorigin/'+currentUrl)).searchParams.get('sys_id');
}
return {table: tableName, query: query};
};
var docu = {};
var UI_TYPE = {
'0': 'Desktop',
'1': 'Mobile / Service Portal',
'10': 'All'
};
var TEMPLATE = {
'sys_ui_policy': {
'header': function(element) {
println('# UI Policies');
println('<https://docs.servicenow.com/bundle/madrid-platform-administration/page/administer/form-administration/task/t_CreateAUIPolicy.html>');
println('UI policies dynamically change the behavior of information on a form and control custom process flows for tasks.');
println('For example, you can use UI policies to make the number field on a form read-only, make the short description field mandatory, and hide other fields. Basic UI policies do not require any scripting, however for more advanced actions, use the Run scripts option.');
println('You can also use client scripts to perform all of these actions, but for faster load times use UI policies when possible.');
},
'content': function(element) {
println('## ' + element.short_description);
println(element.description);
println('### UI Policy main fields');
println('**<span title="The active status of the UI policy. Only active UI policies are applied.">Active</span>:** ' + element.active);
println('**Table:** ' + element.table);
println('**Order:** ' + element.order);
println('### When to Apply');
println('**Conditions:** ``' + element.conditions + '``');
println('**Global:** ' + element.global);
println('**View:** ' + element.view);
println('**Reverse if false:** ' + element.reverse_if_false);
println('**On load:** ' + element.on_load);
println('**Inherit:** ' + element.inherit);
println('### Script');
println('**Run Scripts:** ' + element.run_scripts);
if(element.run_scripts == 'true'){
println('**Execute if true:**' + "\n" + "```javascript\n" + element.script_true + "\n```");
println('**Execute if false:**' + "\n" + "```javascript\n" + element.script_false + "\n```");
}
println('### Other fields');
println('**Run scripts in UI type:** ' + UI_TYPE[element.ui_type]);
println('### UI Policy Actions');
printl('Table|Field name|Mandatory|Visible|Read Only|Clear the field value');
printl('---|---|---|---|---')
docu['sys_ui_policy_action']
.filter(
function(el){
return el.ui_policy == element.sys_id;
}
)
.forEach(
function(el){
printl(el.table + "|" + el.field + "|" + el.mandatory + "|" + el.visible + "|" + el.disabled + "|" + el.cleared);
}
);
println();
println('### JSON UI Policy Raw definition');
println("```javascript\n" + JSON.stringify(element, null, 2) + "\n```");
docu['sys_ui_policy_action']
.filter(
function(el){
return el.ui_policy == element.sys_id;
}
)
.forEach(
function(el){
println("#### UI Policy Action: **" + el.table + "." + el.field + "**");
println("```javascript\n" + JSON.stringify(el, null, 2) + "\n```");
}
);
},
'footer': function(element) {
},
},
'sys_script_client': {
'header': function(element) {
println('# Client Scripts');
println('<https://docs.servicenow.com/bundle/madrid-application-development/page/script/client-scripts/concept/client-scripts.html>');
println('Client scripts allow the system to run JavaScript on the client (web browser) when client-based events occur, such as when a form loads, after form submission, or when a field changes value.');
},
'content': function(element) {
println('## ' + element.name);
println(element.description);
println('**Type:** ' + element.type);
println('**Table:** ' + element.table);
println("**Script:**" + "\n" + "```javascript\n" + element.script + "\n```");
},
'footer': function(element) {
}
},
'sys_security_acl': {
'header': function(element) {
println('# Access control list rules (ACL)');
println('<https://docs.servicenow.com/bundle/london-platform-administration/page/administer/contextual-security/concept/access-control-rules.html>');
println('Rules for access control lists (ACLs) restrict access to data by requiring users to pass a set of requirements before they can interact with it.');
},
'content': function(element) {
println('## ' + element.name);
println(element.description);
var roles = docu['sys_security_acl_role']
.filter(function(el){
return el.sys_security_acl == element.sys_id;
})
.reduce(function(allRoles, role){
if(allRoles == "")
return role.dv_sys_user_role;
else
return allRoles + ", " + role.dv_sys_user_role;
}, "");
println("**Roles:** " + roles);
println("**Operation:** " + element.operation);
println("**Condition:** " + element.condition);
println("**Script:**" + "\n" + "```javascript\n" + element.script + "\n```");
},
'footer': function(element) {
}
},
'sys_ui_action': {
'header': function(element) {
println('# UI Actions');
println('<https://docs.servicenow.com/bundle/madrid-platform-administration/page/administer/list-administration/concept/c_UIActions.html>');
println('UI actions include the buttons, links, and context menu items on forms and lists. Configure UI actions to make the UI more interactive, customized, and specific to user activities.');
},
'content': function(element) {
println('## '+ element.name);
println(element.comments);
println("**Tabla:** " + element.table);
println("**Condición:** " + element.condition);
println("**Script:**" + "\n" + "```javascript\n" + element.script + "\n```");
},
'footer': function(element) {
}
},
'sys_ui_page': {
'header': function(element) {
println('# UI Pages');
println('<https://docs.servicenow.com/bundle/madrid-application-development/page/script/server-scripting/reference/r_UIPages.html>');
println('UI pages can be used to create and display forms, dialogs, lists and other UI components.');
},
'content': function(element) {
println('## ' + element.name);
println(element.description);
println("**HTML:**" + "\n" + "```xml\n" + element.html + "\n```");
println("**Client script:**" + "\n" + "```javascript\n" + element.client_script + "\n```");
println("**Processing script:**" + "\n" + "```javascript\n" + element.processing_script + "\n```");
},
'footer': function(element) {
}
},
'sys_script_include': {
'header': function(element) {
println('# Script Includes');
println('<https://docs.servicenow.com/bundle/madrid-application-development/page/script/server-scripting/concept/c_ScriptIncludes.html>');
println('Script includes are used to store JavaScript that runs on the server.');
println('Create script includes to store JavaScript functions and classes for use by server scripts. Each script include defines either an object class or a function.');
println('Consider using script includes instead of global business rules because script includes are only loaded on request.');
},
'content': function(element) {
println('## ' + element.name);
println(element.description);
println("**Script:**" + "\n" + "```javascript\n" + element.client_script + "\n```");
},
'footer': function(element) {
}
},
'sys_data_source': {
'header': function(element) {
println('# Data Sources');
println('<https://docs.servicenow.com/bundle/madrid-platform-administration/page/administer/import-sets/concept/c_DataSources.html>');
println('Data sources are used to create an import set so that data can be processed, if necessary, prior to being mapped onto a production table.');
},
'content': function(element) {
println('## ' + element.name);
println("**Import set table:** " + element.import_set_table_name);
println("**Type:** " + element.type);
println("**Format:** " + element.format);
println("**File retrievel method:** " + element.file_retrieval_method);
},
'footer': function(element) {
}
},
'sys_transform_map': {
'header': function(element) {
println('# Transform Maps');
println('<https://docs.servicenow.com/bundle/madrid-platform-administration/page/script/server-scripting/concept/c_CreatingNewTransformMaps.html>');
println('A transform map is a set of field maps that determine the relationships between fields in an import set and fields in an existing ServiceNow table, such as Incident [incident] or User [sys_user].');
},
'content': function(element) {
println('## ' + element.name);
println("**Source table:** " + element.source_table);
println("**Tabla destino:** " + element.target_table);
},
'footer': function(element) {
}
},
'sys_script': {
0: function(element) {
println('## Business Rule: ' + element.name);
println("**Description:** " + element.description);
println("**Table:** " + element.collection);
println("**When:** " + element.when);
println("**Filter condition:** " + element.filter_condition);
println("**Condition:** " + element.condition);
println("**Script:**" + "\n" + "```javascript\n" + element.script + "\n```");
}
},
'sys_db_object': {
0: function(element) {
println('## Tabla: ' + element.label);
println("**Name:** " + element.name);
println("**Extends:** " + element.super_class);
}
},
'sys_properties': {
0: function(element) {
println('## System property: ' + element.name);
println(element.description);
println("**Value:** " + element.value);
}
},
'sysevent_script_action': {
0: function(element) {
println('## Script Action: ' + element.name);
println("**Event name:**" + element.event_name);
println("**Condition Script:** " + element.condition_script);
println("**Script:**" + "\n" + "```javascript\n" + element.script + "\n```");
}
},
}; // var printers
var currentUrl = (new URL(window.location.href)).searchParams.get('uri') || window.location.href.substring(window.location.href.lastIndexOf('/'));
// What I need is a bunch of relative links
var bookmarks = jQuery
.ajax({type: "GET", url: "sys_ui_bookmark_list.do?sysparm_query=titleSTARTSWITHMicro%20-&JSONv2&sysparm_action=getRecords", async: false})
.responseJSON
.records
.map(function(el){
return el.url;
});
bookmarks
.forEach(function(bookmark){
var tableName = bookmark.substring(0, bookmark.indexOf(".do")-5);
docu[tableName] = jQuery.ajax({type: "GET", url: bookmark+"&JSONv2&sysparm_action=getRecords&displayvalue=all", async: false}).responseJSON.records;
});
['sys_ui_policy', 'sys_security_acl', 'sys_script_client', 'sys_ui_action', 'sys_ui_page', 'sys_script_include','sys_data_source', 'sys_transform_map']
.forEach(function(table_name){
TEMPLATE[table_name]['header']();
docu[table_name]
.forEach(function(el){
TEMPLATE[table_name]['content'](el);
});
TEMPLATE[table_name]['footer']();
});
jQuery('body').append('\
<div class="modal fade" id="docModal" tabindex="-1" role="dialog" aria-labelledby="docModalLabel">\
<div class="modal-dialog" role="document">\
<div class="modal-content">\
<div class="modal-header">\
<button type="button" class="close" data-dismiss="modal" aria-label="Close">\
<span aria-hidden="true">&times;</span>\
</button>\
<h4 class="modal-title" id="docModalLabel">Copy documentation</h4>\
</div>\
<div class="modal-body">\
<textarea id="docModalTextArea" rows="20" class="form-control"></textarea>\
</div>\
<div class="modal-footer">\
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>\
<button type="button" class="btn btn-primary" onclick="document.getElementById(\'docModalTextArea\').select();document.execCommand(\'copy\');">Copy content</button>\
</div>\
</div>\
</div>\
</div>\
');
jQuery('#docModalTextArea').text(text);
jQuery('#docModal').modal('show');
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment