Stop the Module Madness

We all love creating module links for our application, mostly because it's so easy. While it does make it easier to find what's important, it can quickly clutter the navigation list. It's common for app creators to add modules to quickly get to related business rules, script includes, and other app files that a customer might need to know about.


I like simple and clean environments (although you wouldn't know by the number of stickies all over my desk and office). In an effort to clean up the cluttered world of ServiceNow modules, I started to use a single module and page to collect all of the application configuration files I want to expose.



UI Page

Create a UI page in your app scope with the following attributes.

Name: app_config_files

HTML: (also available here)

<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:g2="null" xmlns:g="glide" xmlns:j2="null" xmlns:j="jelly:core">

  <!-- get the scope of the current record and list of tables to display-->
  <g:evaluate var="jvar_my_scope">
    var scope = new GlideRecord("sys_scope"); scope.get("scope", gs.getCurrentScopeName()); scope;
  <g:evaluate expression="scope.getDisplayValue()" var="jvar_my_scope_name"/>
  <g:evaluate expression="scope.getUniqueValue()" var="jvar_my_scope_id"/>
  <g:evaluate expression="gs.getProperty(scope.scope + '.config_file_tables','')" var="jvar_config_tables"/>

  <!-- notify user if we don't have tables property -->
  <j:if test="${jvar_config_tables == ''}">
    The required property 'config_file_tables' in scope ''${scope.scope}'' is missing
  <j:if test="${jvar_config_tables != ''}">
    <nav class="navbar navbar-default" role="navigation" style="min-width:935px;">
      <div class="container-fluid">
        <div class="navbar-header">
          <h1 class="navbar-title" style="display:inline-block;">Configuration files for ${jvar_my_scope_name}</h1>
        <div class="nav navbar-right"></div>
    <g:inline template="tabs2.xml"/>

    <TABLE border="0" cellPadding="0" cellSpacing="0" id="testtable" width="100%">
        <TD valign="top">
          <j:set value="cardboard" var="jvar_list_type"/>
          <!-- tabstrip for related lists -->
          <div class="tabs2_strip" id="tabs2_list">
            <!-- hack for IE bug when tab strip causes a horizontal scroll bar to appear -->
            <img alt="" height="1px" src="images/s.gifx" style="margin-right: 0px;" width="1px"/>
                  Start with the lists not displayed so that we do not impact the page scroll position - gets shown in
                  the onLoad event below
          <span id="list_span" style="display:none;border-top: 1px solid black; padding-top: 5px; margin-top: -7px;">
            <j:set value="true" var="jvar_use_name_for_list_id"/>

            <j:forEach items="${jvar_config_tables.split(',')}" var="jvar_config_table">
              <!-- make sure we have a valid table -->
              <g:evaluate jelly="true" var="jvar_valid_table">
                var isValid = false; var tableName = jelly.jvar_config_table.trim(); var configTable = new GlideRecord(tableName); if (configTable.isValid()) isValid = true; isValid;
              <j:if test="${jvar_valid_table == true}">
                <!-- display the table list of filtered records -->
                <g:inline source="${jvar_my_scope_id}" table="${jvar_config_table.trim()}" table_field="sys_scope" template="personalize_all_list.xml"/>

      addLoadEvent(function () {
        var tabs = new GlideTabs2("tabs2_list", gel("list_span"), 0, '');



Create a property that will control the application file tables displayed (because who really wants to change jelly scripts). 

Name: config_file_tables (this will create the required property in the form of x_vendorkey_app.config_file_tables) 

Value: comma-delimited list of tables (must be app file extensions) to display on the page. You can add 'sys_metadata' if you want to display a tab with all app files. Example (sys_script,sysevent_script,sys_script_include,sys_ui_action,sys_processor,sys_ui_page,sys_ui_macro,sys_metadata)


Create a new model to call the UI page.

Name: Configuration files (or whatever you want to call it)

Link Type: URL from arguments

Arguments: [your_app_scope] (actual name can be viewed from the UI page form)


Even though you'd still have to create a new UI page for each app, I didn't want to hard code scope info in the script. It's designed for easy copy/paste and will pull the scope info from the scope that the UI page lives in.

I know the need for this may be eliminated in Geneva when the Dev Studio interface hits the streets, but this should help clean things up before then.