Customising the Pentaho User Console – Part 4.

Posted under BI Server, Open Source, Pentaho, Tutorials, User Console

This post is part 4 of the series “Customising the Pentaho User Console (PUC)” Version 3.5.x. Here is a list of what I have covered in other parts:

In this post I will show you how to customise the launch page.

The Launch Page

The launch page is the default page that is displayed when you log into the PUC, below is a screenshot of the launch page:

What Is The Launch Page

launch.jsp

The contents of the launch page are generated by the launch.jsp file which is located under the tomcat/webapps/pentaho/mantle/launch/ directory, the images which are used for the launch page are located under the tomcat/webapps/pentaho/mantle/launch/images directory.

The contents of the launch.jsp are:

<%@ taglib prefix='c' uri='http://java.sun.com/jstl/core'%><%@
    page
  language="java"
  import="java.io.InputStream,
      java.util.Locale,
      java.util.PropertyResourceBundle,
      java.util.ResourceBundle,
      java.util.regex.Pattern,
      java.util.regex.Matcher,
      org.pentaho.platform.util.messages.LocaleHelper,
      org.pentaho.platform.api.engine.IPentahoSession,
      org.pentaho.platform.api.engine.IPluginManager,
      org.pentaho.platform.api.repository.ISolutionRepository,
      org.pentaho.platform.engine.core.system.PentahoSystem,
      org.pentaho.platform.engine.core.system.StandaloneSession,
      org.pentaho.platform.util.logging.Logger,
      org.pentaho.platform.web.jsp.messages.Messages,
      org.pentaho.platform.web.http.PentahoHttpSessionHelper,
      org.apache.commons.lang.StringEscapeUtils"%>
<%
  /*
   * Copyright 2006 Pentaho Corporation.  All rights reserved.
   * This software was developed by Pentaho Corporation and is provided under the terms
   * of the Mozilla Public License, Version 1.1, or any later version. You may not use
   * this file except in compliance with the license. If you need a copy of the license,
   * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
   * BI Platform.  The Initial Developer is Pentaho Corporation.
   *
   * Software distributed under the Mozilla Public License is distributed on an "AS IS"
   * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to
   * the license for the specific language governing your rights and limitations.
   *
   * @created Jul 23, 2005
   * @author James Dixon
   *
   */
%>
 
<%@page import="org.pentaho.ui.xul.XulOverlay"%>
<%@page import="org.pentaho.platform.api.engine.IPluginManager"%><html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
 
 
<title><%=Messages.getString("UI.PUC.LAUNCH.TITLE")%></title>
 
<style type="text/css">
<!--
body {
  color: #000000;
  background-color: #FFFFFF;
  margin: 0px;
}
 
p {
  margin: 0px;
  padding: 0px;
}
 
A:link,A:visited,A:hover {
  color: #7e932f;
  text-decoration: underline;
}
 
A:hover {
  color: #ca6333;
  text-decoration: underline;
}
 
.launchPanel {
  background-color: white;
  background-image: url(images/quicklaunch_bg.png);
  background-repeat: no-repeat;
  background-position: center;
  height: 100%;
}
 
.ql_container {
  width: 620px;
  margin-bottom: 50px;
}
 
.ql_icon_bar_left {
  width: 41px;
  height: 147px;
  vertical-align: top;
  padding-top: 25px;
}
 
.ql_icon_bar_middle {
  background-image:
    url(images/ql_icon_bar_middle.png);
  background-repeat: repeat-x;
  width: 100%;
  height: 199px;
}
 
.ql_icon_bar_right {
  width: 41px;
  height: 147px;
  vertical-align: top;
  padding-top: 25px;
}
 
.ql_spacer {
  width: 20px;
}
 
.ql_btn {
  width: 167px;
}
 
.ql_btn_left {
  width: 41px;
  height: 56px;
}
 
.ql_btn_middle {
  background-image: url(images/ql_btn_middle.png);
  background-repeat: repeat-x;
  width: 100%;
  font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
  font-size: 1.25em;
  line-height: 20px;
  font-weight: 300;
  text-align: center;
  vertical-align: top;
  white-space: nowrap;
  padding-top: 5px;
}
 
.ql_btn_right {
  width: 41px;
  height: 56px;
}
 
.ql_btn_left_hover {
  width: 41px;
  height: 56px;
}
 
.ql_btn_middle_hover {
  background-image:
    url(images/ql_btn_middle_hover.png);
  background-repeat: repeat-x;
  width: 100%;
  font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
  font-size: 1.25em;
  line-height: 20px;
  font-weight: 300;
  text-align: center;
  vertical-align: top;
  white-space: nowrap;
  padding-top: 5px;
}
 
.ql_btn_right_hover {
  width: 41px;
  height: 56px;
}
 
.ql_new_report {
  width: 120px;
  height: 130px;
  padding-bottom: 13px;
  cursor: pointer;
}
 
.ql_new_analysis {
  width: 120px;
  height: 130px;
  padding-bottom: 13px;
  cursor: pointer;
}
 
.ql_manage {
  width: 120px;
  height: 130px;
  padding-bottom: 13px;
  cursor: pointer;
}
 
.ql_logo {
  width: 290px;
  height: 91px;
  padding-bottom: 30px;
}
 
.button {
  cursor: pointer;
  width: 167px;
  padding: 0px;
  spacing: 0px;
  height: 56px;
}
 
.btn_left {
  background-image: url("images/ql_btn_left.png");
  background-repeat: no-repeat;
  height: 56px;
  width: 22px;
}
 
.btn_right {
  background-image: url("images/ql_btn_right.png");
  background-repeat: no-repeat;
  height: 56px;
  width: 22px;
}
 
.btn_center {
  background-image: url(images/ql_btn_middle.png);
  background-repeat: repeat-x;
  width: 100%;
  font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
  font-size: 1.25em;
  line-height: 20px;
  font-weight: 300;
  text-align: center;
  vertical-align: top;
  white-space: nowrap;
  padding-top: 5px;
}
 
.btn_left_hover {
  background-image:
    url("images/ql_btn_left_hover.png");
  background-repeat: no-repeat;
  height: 56px;
  width: 22px;
}
 
.btn_right_hover {
  background-image:
    url("images/ql_btn_right_hover.png");
  background-repeat: no-repeat;
  height: 56px;
  width: 22px;
}
 
.btn_center_hover {
  background-image:
    url(images/ql_btn_middle_hover.png);
  background-repeat: repeat-x;
  width: 100%;
  font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
  font-size: 1.25em;
  line-height: 20px;
  font-weight: 300;
  text-align: center;
  vertical-align: top;
  white-space: nowrap;
  padding-top: 5px;
}
-->
</style>
 
<script type="text/javascript">
Button = function(label, container){
 
    var btn = document.createElement("input");
    btn.setAttribute("type","button");
 
 
    table = document.createElement("table");
    document.getElementById(container).innerHTML="";
    document.getElementById(container).appendChild(table);
 
    table.setAttribute("cellpadding","0");
    table.setAttribute("cellspacing","0");
    table.setAttribute("border","0");
    table.className="button";
    table.setAttribute("height","56");
    table.setAttribute("width","167");
    table.cellSpacing = "0px";
    table.cellPadding = "0px";
 
    var tbody = document.createElement("tbody");
 
    var tr = document.createElement("tr");
 
    var left_td = document.createElement("td");
    left_td.className="btn_left";
    left_td.innerHTML = "<img src='images/ql_spacer.png'/ width='22' height='1'/><br/>";
    tr.appendChild(left_td);
 
    var center_td = document.createElement("td");
    center_td.setAttribute("width","100%");
    center_td.className="btn_center";
    center_td.onselectstart=function(){return false;}
    center_td.style.MozUserSelect='none';
    center_td.innerHTML = label;
    tr.appendChild(center_td);
 
    var right_td = document.createElement("td");
    right_td.innerHTML = "<img src='images/ql_spacer.png'/ width='22' height='1'/><br/>";
    right_td.className="btn_right";
    tr.appendChild(right_td);
    tbody.appendChild(tr);
 
    table.appendChild(tbody);
 
    table.onmouseover=function(){
      window.selectedButton = this;
      left_td.className="btn_left_hover";
      right_td.className="btn_right_hover";
      center_td.className="btn_center_hover";
    };
    this.reset = function(){
      left_td.className="btn_left";
      right_td.className="btn_right";
      center_td.className="btn_center";
    }
 
    table.onmouseout = this.reset;
 
    this.onClick=function(onClick){
      if(window.parent && window.parent.mantle_initialized){
        table.onclick = function(){eval("window.parent." + onClick)};
      }
    };
}
 
window.onresize = function(){
  if(window.selectedButton){
     window.selectedButton.onmouseout();
  }
 
 
  // IE_6_FIX: When resized by PUC, IE will display rendering issues. This is accounted for by the code below. 
  if(window.isIE6){
 
    // IE6 has a rate limit on the number of resize events that it will fire. This means we cannot rely on the
    // resize event alone to determine when the reisize is complete. The timer ensures that the layout is
    // recomputed after PUC is done resizing the iframe.
    setTimeout(function(){
      window.tableWrapperDiv.style.top = "1px";
      window.tableWrapperDiv.style.top = "0px";
    }, 350);
 
  }
 
}
 
function loader(){
 
  // IE_6_FIX: We're using a CSS filter to enable transparany in IE 6. This has the side-effect of trapping mouse events in the
  // filtered area. The standard workaround is to wrap that area in two divs, one absolutely positioned inside a relative one.
 
  var navAgent = window.navigator.userAgent;
  window.isIE6 = false;
  var reg = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})").exec(navAgent)
  if (reg != null) {
    var version = parseFloat( RegExp.$1 );
    window.isIE6 = version >= 6.0 && version < 7.0;
  }
 
  // The following wrapps the button table with two DIVs, one positioned relative and the other absolute.
  if(window.isIE6){
    var buttonTable = document.getElementById("buttonTable");
    var parent = buttonTable.parentNode;
    window.tableWrapperDiv = document.createElement("div");
    var absDiv = document.createElement("div");
 
    with(tableWrapperDiv.style){
      position = "relative";
      width = "100%";
      height = "100%";
    }
    with(absDiv.style){
      position = "absolute";
      top = "0px";
      left = "0px";
    }
 
    parent.removeChild(buttonTable);
    parent.appendChild(tableWrapperDiv);
    tableWrapperDiv.appendChild(absDiv);
    absDiv.appendChild(buttonTable);
    tableWrapperDiv.id = "buttonWrapperDiv";
  }
  // End IE_6_FIX
 
    new Button("<%=Messages.getString( "UI.PUC.LAUNCH.NEW_REPORT" )%>", "launch_new_report").onClick("openWAQR()");
    new Button("<%=Messages.getString( "UI.PUC.LAUNCH.NEW_ANALYSIS" )%>", "launch_new_analysis").onClick("openAnalysis()");
<%!
  private static ResourceBundle getBundle(String messageUri) {
    Locale locale = LocaleHelper.getLocale();
    IPentahoSession session = new StandaloneSession( "dashboards messages" ); //$NON-NLS-1$
    try {
        if (messageUri.startsWith("content/")) {
          messageUri = "system/" + messageUri.substring(8); //$NON-NLS-1$
        }
      InputStream in = PentahoSystem.get(ISolutionRepository.class, session).getResourceInputStream(messageUri, true, ISolutionRepository.ACTION_EXECUTE);
      return new PropertyResourceBundle( in );
    } catch (Exception e) {
      Logger.error( Messages.class.getName(), "Could not get localization bundle", e ); //$NON-NLS-1$
    }
    return null;
  }
%><% 
  boolean pluginButton = false;
  String buttonLabel = "";
  String buttonCommand = "";
  String buttonImage = "";
  IPluginManager pluginManager = PentahoSystem.get(IPluginManager.class, PentahoHttpSessionHelper.getPentahoSession(request)); //$NON-NLS-1$
    if (pluginManager != null) {
        for(XulOverlay overlayObj : pluginManager.getOverlays()) {
          if (overlayObj.getId() != null && overlayObj.getId().equals("launch")) {
      ResourceBundle bundle = getBundle(overlayObj.getResourceBundleUri());
        // replace I18N parameters
        Pattern p = Pattern.compile("\\$\\{([^\\}]*)\\}");
        Matcher m = p.matcher(overlayObj.getOverlayXml());
        StringBuffer sb = new StringBuffer();
        while (m.find()) {
          String param = m.group(1);
          m.appendReplacement(sb, bundle.getString(param));
        }
        m.appendTail(sb);
        String overlay = sb.toString();
 
      if (overlay.indexOf("id=\"manage_content\"") >= 0) {
        int startButtonLabel = overlay.indexOf("label=\"");
        int endButtonLabel = overlay.indexOf("\"", startButtonLabel + 7);
        buttonLabel = overlay.substring(startButtonLabel + 7, endButtonLabel);
 
        int startButtonImage = overlay.indexOf("image=\"");
        int endButtonImage = overlay.indexOf("\"", startButtonImage + 7);
        buttonImage = overlay.substring(startButtonImage + 7, endButtonImage);
 
        int startButtonCommand = overlay.indexOf("command=\"");
        int endButtonCommand = overlay.indexOf("\"", startButtonCommand + 9);
        buttonCommand = overlay.substring(startButtonCommand + 9, endButtonCommand);
        pluginButton = true;
        break;
      }
          }
      }
    }
  if (pluginButton) {
%>    new Button("<%=buttonLabel%>", "manage_content").onClick("<%= buttonCommand%>");
<%
  } else {
%>    new Button("<%=Messages.getString( "UI.PUC.LAUNCH.MANAGE_CONTENT" )%>", "manage_content").onClick("openManage()");
<%  }  %>
    fixPNGs();
}
 
</script>
  <script type="text/javascript" src="../pngfix.js"></script>
  <script type="text/javascript">
      PngFix.spacerURL = "images/ql_spacer.png";
  </script>
</head>
 
<body onLoad="loader()">
 
<div style="margin: 0px; padding: 0px; width: 100%; height: 100%;">
<table style="width: 100%; height: 100%;" class="launchPanel" id="launchPanel"
  cellpadding="0" cellspacing="0">
  <tr>
    <td style="vertical-align: middle;" align="center">
 
    <table width="564" border="0" align="center" cellpadding="0"
      cellspacing="0" class="ql_container">
      <tr>
        <td colspan="3" align="center"><img
          src="images/ql_logo.png" alt="Pentaho.com"
          class="ql_logo" /></td>
      </tr>
      <tr>
        <td class="ql_icon_bar_left"><img
          src="images/ql_icon_bar_left.png" width="41"
          height="147" /></td>
        <td class="ql_icon_bar_middle" >
 
            <table id="buttonTable" width="100%" border="0" cellspacing="0" cellpadding="0"
              height="100%">
              <tr>
                <td align="center" valign="top" onClick="window.parent.openWAQR()"><img
                  src="images/btn_ql_newreport.png"
                  class="ql_new_report" /></td>
                <td align="center" valign="top">&nbsp;</td>
                <td align="center" valign="top"
                  onClick="window.parent.openAnalysis()"><img
                  src="images/btn_ql_newanalysis.png"
                  class="ql_new_analysis" /></td>
                <td align="center" valign="top">&nbsp;</td>
<% if (pluginButton) { %>
                <td align="center" valign="top"
                  onClick="window.parent.<%=buttonCommand %>"><img
                  src="../../<%=buttonImage %>"
                  class="ql_manage" /></td>
<% } else { %>
                <td align="center" valign="top"
                  onClick="window.parent.openManage()"><img
                  src="images/btn_ql_manage.png"
                  class="ql_manage" /></td>
<% } %>
              </tr>
              <tr>
                <td id="launch_new_report" height="100%"><!--  container for New Report Button -->
                </td>
                <td><img src="images/ql_spacer.png"
                  class="ql_spacer" /></td>
                <td id="launch_new_analysis"><!--  container for New Analysis Button -->
                </td>
                <td><img src="images/ql_spacer.png"
                  class="ql_spacer" /></td>
                <td id="manage_content"><!--  container for manage content Button -->
                </td>
              </tr>
          </table>
 
        </td>
        <td class="ql_icon_bar_right"><img
          src="images/ql_icon_bar_right.png"
          width="41" height="147" /></td>
      </tr>
    </table>
    </td>
  </tr>
</table>
</div>
 
</body>
</html>

Before you make any changes to launch.jsp make sure you keep a backup copy.

Example 1

The launch.jsp page is like any other JSP (or HTML) page. For example, if I wanted to make the launch.jsp page display my blog’s logo all I need to do is change the contents of the launch.jsp file so that they now look like this:

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>Launch</title>
</head>
<body>
<div style="margin: 0px; padding: 0px; width: 100%; height: 100%;">
<table style="width: 100%; height: 100%;" class="launchPanel" id="launchPanel" cellpadding="0" cellspacing="0">
  <tr>
    <td style="vertical-align: middle;" align="center">
      <img src="images/logo.jpg" alt="Logo"/>
    </td>
    </table>
  </tr>
</table>
</div>
</body>
</html>

I have placed the logo.jpg image under the tomcat/webapps/pentaho/mantle/launch/images/ directory.

After refreshing the browser the new launch.jsp now looks like this:

Adding a Logo to the Launch Page

Example 2

You could also embed information from other sites i.e. intranet home page etc. by using an iframe. For example, to include Google News instead of the default launch page I will need to make changes to the launch.jsp page so that it now looks like this:

<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>Launch</title>
</head>
<body>
<iframe src="http://www.google.com/news" width="100%" height="100%" frameborder="0">
  <p>Your browser does not support iframes.</p>
</iframe>
</body>
</html>

After refreshing the browser the new launch.jsp now looks like this:

External Content with Launch Page

Example 3

Another example would be to add a list of links to key reports, analysis views and/or dashboards using xactions. Just say I would like to create a list which are links for the following:

  • Area Chart Example (Steel Wheels > Charts)
  • Marketing Analysis by Year (Steel Wheels > Analysis)

After making changes the launch.jsp file now looks like this:

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
<title>Launch</title>
</head>
<body>
<h1>Steel Wheels Launch pad</h1>
<p>Maybe one of these reports/analysis/dashboards can help you:</p>
<ul>
  <li><a href="http://localhost:8080/pentaho/ViewAction?&solution=steel-wheels&path=charts&action=areachart_data.xaction">Area Chart Example</a></li>
  <li><a href="http://localhost:8080/pentaho/ViewAction?&solution=steel-wheels&path=analysis&action=analysis_customers.analysisview.xaction">Marketing Analysis by Year</a></li>
</ul>
</body>
</html>

After refreshing the browser the new launch.jsp now looks like this:

Links to Report Launch Page

Example 4

You can also redirect the launch.jsp page to a xaction, to do this change the contents of the launch.jsp file so that they now look like this:

<%
    // xactionPath is the xaction path
    String xactionPath = "http://localhost:8080/pentaho/ViewAction?&solution=steel-wheels&path=analysis&action=analysis_customers.analysisview.xaction";
    response.sendRedirect(xactionPath);
%>

After refreshing the browser the new launch.jsp will automatically redirect to the xaction specified.

Final Notes

If you want to embed or replace the launch.jsp with xactions, dashboards, reports etc. I believe that you should use the startup-urls option instead, this option is covered in my previous post Customising the Pentaho User Console – Part 3.

Do you have any other examples? Post a comment or drop me an email and I’ll add it to this post.

Enjoy.

Posted by Prashant Raju on Mar 10, 2010 — 14 CommentsShare

14 Comments for “Customising the Pentaho User Console – Part 4.”

  1. Posted by Diddy on Mar 10, 2010

    Hi Prashant!
    Very interesting series. Do you have all the articles in PDF format as well?
    Thanks,
    Diddy

  2. Posted by Prashant Raju on Mar 11, 2010

    @Diddy

    I will be transferring these to my guide as a new chapter … when I get the time :)

    In the mean time let me know if you would like me to convert these to PDF.

    Prashant.

  3. Posted by Diddy on Mar 11, 2010

    Hi Prashant,
    Yes, please, can you send me your posts as pdf (the whole guide if possible)?
    Thanks,
    Diddy

  4. Posted by Brandon Jackson on Mar 31, 2010

    Hi Prashant,

    Would you please email me a PDF of whatever tutorials you have available as PDF. We would like to print them and keep them in a binder. Very high quality stuff. Thanks for taking the time and effort to produce it so carefully.

    Thanks,

    Brandon

  5. Posted by Prashant Raju on Apr 6, 2010

    Brandon

    Sorry WYSIWYG :) Why not install PrimoPDF and just print the page as a PDF?

    Prashant

  6. Posted by amer on Apr 14, 2010

    Prashant,

    Great blog series. I had to make some modifications to login and launch page myself, ended up going through code to figure out what was going on. I wish I had found this post earlier & saved whole bunch of time.

    I created blog post too but it was nowhere as complete & elegant as yours.

    Thank you for your effort.

    Amer

  7. Posted by Nambi B on May 12, 2010

    Hello Prashant,

    You have being doing an amazing job.

    Just using your guides, I was able to configure and run Pentaho in my Mac.

    keep the good work.

    Thanks.
    Nambi

  8. Posted by Prashant Raju on May 12, 2010

    @Nambi B

    Thanks! It’s always good to hear that I’m helping out someone!

    Prashant.

  9. Posted by mike d on May 29, 2010

    Hey Prashant,
    Thank you very much for these guides. As a new Pentaho user I found these to be very helpful.

    I was wondering if you could help me change the title on the launch page. I tried changing it in both the launch.jsp and mantle.jsp, but the title still loads as “Pentaho User Console.” Do you have any suggestions?

    Thank you very much,
    Mike

  10. Posted by Prashant Raju on May 29, 2010

    Mike

    You might want to have a look at this post. There is a productName property which is by default “Pentaho User Console” – might be worth a shot!

    Prashant

  11. Posted by Bill on Jun 30, 2010

    DO you know how to change the web page address that is linked to the large rectangular button in the upper right hand corner of the User console, says “@pentaho”.

    I changed the graphic image but the web link underneath seems to be embedded as http://www.pentaho.com.

    I tried resetting the pentahoHomePageName=
    propertly in /biserver-ce/tomcat/webapps/pentaho/mantle/messages/messeges_en.PROPERTIES but that didn’t work.

  12. Posted by Prashant Raju on Jun 30, 2010

    Bill,

    Have you tried checking out the source code and (I’m not a Java programmer by the way) and doing a find for the logo file name or even the surrounding elements (you can find these out using Firebug) then you should be able to make a hard coded modification or reference a new/old properties entry in the messages_en.PROPERTIES file?

    Prashant

  13. Posted by Bill on Jul 2, 2010

    Thanks Prashant. I am not a Java programmer and I assume doing as you suggest (modifying the source code) would then require me to recompile the Pentaho application. I am not comfortable doing that at this point as I think I would break things, maybe it’s not a big deal.

    But I wasn’t exactly sure what you meant by potentially referencing a new/old properties entry? That sounds more like the sort of change I would desire.

    I’ll check out looking for the logo file via firebug.

    Thanks again for this most informative blog.

  14. Posted by Prashant Raju on Jul 2, 2010

    @Bill

    When I refer to the .properties file it involves adding a reference to that properties entry in the source code which makes up the UI (Mantle).

    The only way to change that link is to make changes in the source (which I have already outlined in this post).

    Prashant.


Post a Comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">