chrome_menu help

Eric54
Tera Expert

I have portal app shell experience that I’m working on and I need to configure the chrome_menu to add a link to a standard service portal page.  This portal page named Daily Activity Bulletin is not part of my experience.  I have two possible approaches I can take implement this.

 

The first way, and what I think should be easiest to implement, is to add the link on the menu bar which would open the DAB in a new browser tab.  The part that I can’t seem to figure out here is targeting the new tab.  Is it possible to target a new tab? Here is what I have so far for my chrome_menu property.

 

Eric54_1-1727108410417.png

 

[
  {
    "value": {
      "label": {
        "translatable": true,
        "message": "Daily Activities Bulletin"
      },
      "type": "navigation",
      "value": {
        "href": "/services?id=daily_activities_bulletin"
      }
    }
  }
]

The second way would be for me to view the DAB inside a viewport on a new experience page.   This way the user could click the DAB menu item to view it and then click on another menu item to return to the previous page.  The problem with this approach is that the initial page (Search) has a page property that I need to preserve.  I need to know if data binding is possible within the menu fields or any part of the menu for that matter?  This way I can add the same property on the new DAB page which I could use pass the value back when returning to the previous page. 

 

Eric54_2-1727108410422.png

 

[
  {
    "value": {
      "label": {
        "translatable": true,
        "message": "Search"
      },
      "type": "route",
      "value": {
        "route": "home",
        "fields": {
          "sys_id": "<the sys_id i need to preserve>"
        }
      }
    }
  },
  {
    "value": {
      "label": {
        "translatable": true,
        "message": "Daily Activities Bulletin"
      },
      "type": "route",
      "value": {
        "route": "dab",
        "fields": {
          "sys_id": "<the sys_id i need to preserve>"
        }
      }
    }
  }
]

 

The documentation for the chrome properties is weak, any help is appreciated!

 

Thanks,

Eric.

1 ACCEPTED SOLUTION

Eric54
Tera Expert

 

Nearly two years later, after diving deep into the ServiceNow code, I finally figured it out. All it took was for me to look at the definition of the Portal App Shell component to find that it is driven by the Composite Data Resource named "Portal AppShell Menu Provider." Digging a little deeper still led me to the Script Include app_shell_portal.PortalAppShellProvider (/now/nav/ui/classic/params/target/sys_script_include.do%3Fsys_id=285e55d1532511101c7eddeeff7b1279), which checks if there is an implementation of the Extension Point defined here: (/now/nav/ui/classic/params/target/sys_extension_point.do?sys_id=15253919536511101c7eddeeff7b12aa).

Now that I have everything I need, all I had to do was define a Script Include that implements the Extension Point in my application scope.

var MyPortalAppShellMenuProvider = Class.create();

MyPortalAppShellMenuProvider.prototype = {
    initialize: function() {},

    getAppId: function() {
        /** fill this value with your sys_ux_page_registry */
        return "your sys_ux_page_registry guid goes here";
    },

    /**
     * @returns {[{
     * 			value: {
     * 				label: string,
     * 				target: string,
     * 				type: string,
     * 				value: {
     * 					route: string,
     *					field: Record<string, any>
     *              }
     * 	        }
     * }]}
     */
    provideMenuItems: function() {
        var lang = gs.getSession().getLanguage();
        var items = [{
            "value": {
                "label": gs.getMessage("Home"),
                "type": "route",
                "value": {
                    "route": "home",
                    "fields": {
                        "lang": lang
                    }
                }
            }
        },
        {
            "value": {
                "label": gs.getMessage("Other Page"),
                "type": "route",
                "value": {
                    "route": "other",
                    "fields": {
                        "lang": lang
                    }
                }
            }
        }];

        return items;
    },


    /**
     * Label: action button label
     * Size: sm | md | lg
     * variant: now-button variants.
     *
     * @returns  {[{
     * 		label: string,
     * 		value: string,
     * 		size: string,
     * 		variant: string
     * }]}
     */
    provideActionButtons: function() {
        return [];
    },

    type: 'MyPortalAppShellMenuProvider'
}

 

Then register the implementation of my extension in the Extension Instance table (sys_extension_instance).

 

And BAM!!! I now have dynamic menus in my portal experience.

 

Hopefully, this helps people avoid the pain that I experienced.

 

View solution in original post

1 REPLY 1

Eric54
Tera Expert

 

Nearly two years later, after diving deep into the ServiceNow code, I finally figured it out. All it took was for me to look at the definition of the Portal App Shell component to find that it is driven by the Composite Data Resource named "Portal AppShell Menu Provider." Digging a little deeper still led me to the Script Include app_shell_portal.PortalAppShellProvider (/now/nav/ui/classic/params/target/sys_script_include.do%3Fsys_id=285e55d1532511101c7eddeeff7b1279), which checks if there is an implementation of the Extension Point defined here: (/now/nav/ui/classic/params/target/sys_extension_point.do?sys_id=15253919536511101c7eddeeff7b12aa).

Now that I have everything I need, all I had to do was define a Script Include that implements the Extension Point in my application scope.

var MyPortalAppShellMenuProvider = Class.create();

MyPortalAppShellMenuProvider.prototype = {
    initialize: function() {},

    getAppId: function() {
        /** fill this value with your sys_ux_page_registry */
        return "your sys_ux_page_registry guid goes here";
    },

    /**
     * @returns {[{
     * 			value: {
     * 				label: string,
     * 				target: string,
     * 				type: string,
     * 				value: {
     * 					route: string,
     *					field: Record<string, any>
     *              }
     * 	        }
     * }]}
     */
    provideMenuItems: function() {
        var lang = gs.getSession().getLanguage();
        var items = [{
            "value": {
                "label": gs.getMessage("Home"),
                "type": "route",
                "value": {
                    "route": "home",
                    "fields": {
                        "lang": lang
                    }
                }
            }
        },
        {
            "value": {
                "label": gs.getMessage("Other Page"),
                "type": "route",
                "value": {
                    "route": "other",
                    "fields": {
                        "lang": lang
                    }
                }
            }
        }];

        return items;
    },


    /**
     * Label: action button label
     * Size: sm | md | lg
     * variant: now-button variants.
     *
     * @returns  {[{
     * 		label: string,
     * 		value: string,
     * 		size: string,
     * 		variant: string
     * }]}
     */
    provideActionButtons: function() {
        return [];
    },

    type: 'MyPortalAppShellMenuProvider'
}

 

Then register the implementation of my extension in the Extension Instance table (sys_extension_instance).

 

And BAM!!! I now have dynamic menus in my portal experience.

 

Hopefully, this helps people avoid the pain that I experienced.