Bridging the gap to Fusion through our PeopleSoft Solutions Extenders
Grey Sparling PeopleSoft Expert's Corner
Oracle Blogs
 Subscribe Now!

Friday, February 29, 2008

Using Flash for End-User Training

One of our customers is in the process of rolling out our Excel Add-in, and wanted to find the easiest and most effective means for training the end-users on how to use it. For those who are not familiar with our product selling model, we record demos of each of our products and post them on the website, so that prospective customers can get comfortable with how it works prior to making the commitment to contact us for a potential trial of the product.

This customer asked us to remove the product configuration topic from the demo (as end-users don't do configuration), and provide them a version they could use internally to accomplish this. This way, the end-users can quickly navigate between the different topics and see how they would use it (the fact that this demo shows GL and the initial rollout is for GL users was a benefit as well).

I decided to use this opportunity to finally upgrade the version of Camtasia I used, because it has the option of including the table of contents directly in the flash file, instead of generating HTML with it (which makes it much easier for packaging, embedding, and sharing).

Here is what I came up with:

Doing it this way has a lot of benefits

  • You can put the training on your corporate intranet, so that it's easy to get to
  • You can show navigation and what they should expect instead of describing it
  • The file size isn't that much larger than the documentation (with all the screenshots we put in, our doc is around 3-4MB in size, whereas this flash is about 8MB in size which really suprised me)
  • Users are much more likely to watch a 10 minute flash demo than to read through a manual or go to a training class.

Labels: ,

Thursday, October 11, 2007

Re-Posted yesterday's item.

Well, I guess that I should have done a little more testing prior to publishing last night's posting. In order to figure out what pages and components to look at when adding my code, I opened them up and used PSIDE helper to drill into the definitions.

Unfortunately, I didn't realize that there were global variables that drove the logic on the pages that I was working with (and those vairables prevented me from finding a couple of design flaws in my approach).

Well, I discovered the error of my ways and realized that I needed to move one component back in the chain with my entry-point (which meant that I needed to add code to two pages instead of one). Try the code on the posting now.

Labels: , ,

Wednesday, October 10, 2007

Opening up a Performance or Development Document from a URL

I've recently been spending a bit of time working in HR on a Co-Presentation with Business Objects for their upcoming conference this week. One of the things I wanted to show was how to open up a performance review or a development plan from a report. Unfortunately, the pages in HCM don't allow you to pass in an EMPLID or a Review Type to open it up.

The Solution

The solution is similar in nature to what I did for navigating to values in the Journal Entry page. I used the %Request.GetParameter() function to allow the URL to navigate to the page to contain the extra parameters I needed. I then used the parameters to find the document I wanted to open, and opened it. I ended up need needing to add code to two different locations to make it work (mainly because the performance documents were written as several different components that transfer the user around):

  • The first was to add Page.Activate PeopleCode to the EP_LAUNCH page. This code accepts the parameters passed on the URL. Because those parameters will be lost after a transfer event, it puts them into global variables to be used later.
  • The second is to modify the Page.Activate PeopleCode of the EP_APPR_SELECT page to use the parameters passed on the command line to walk through the list of documents and open the appropriate one.

In case you were wondering what the navigation would look like, here are a couple of URLS that would open up the appropriate documents.

The first is a URL to open an annual performance document (for employee KU0065): http://www.gsdemo.com/psp/ps/EMPLOYEE/HRMS/c/ROLE_MANAGER.EP_CURRENT_MY_PRF.GBL?&PAGE=EP_APPR_SELECT&EMPLID=KU0065&EP_REVIEW_TYPE=K0ANNUAL

The second URL opens up a development document (for employee KU0119): http://www.gsdemo.com/psp/ps/EMPLOYEE/HRMS/c/ROLE_MANAGER.EP_CURRENT_MY_DVL.GBL?&PAGE=EP_APPR_SELECT&EMPLID=KU0119

Here's the code needed on the Page.Activate program within the EP_LAUNCH page:

Because this page doesn't already have PeopleCode here, you can simply copy and paste the following code(tested against HCM 8.9).

/* ********************************************************** */
/* Grey Sparling - Add Code to Open up an item passed on URL */
/* ********************************************************** */

rem Grey Sparling - Retrieve Parameters to open up employee;
Global string &gsEmplID;
Global string &gsRevType;

&gsEmplID = RTrim(%Request.GetParameter("EMPLID"));
&gsRevType = RTrim(%Request.GetParameter("EP_REVIEW_TYPE"));

Here's the code needed on the Page.Activate program within the EP_APPR_SELECT page:

The first step is to declare the global variables near the top of the program. It already contains the declaration for &EP_GBLKEYS_WRK. You should put the following lines above it.

/* Grey Sparling - Declare Globals */
Global string &gsEmplID;
Global string &gsRevType;

The rest of the code should be appended to the end of the page activate peoplecode on the EP_APPR_SELECT page.

/* ********************************************************** */
/* Grey Sparling - Add Code to Open up an item passed on URL */
/* ********************************************************** */

If None(&gsEmplID) Then

    &gsEmplID = RTrim(%Request.GetParameter("EMPLID"));

End-If;
If None(&gsRevType) Then
    &gsRevType = RTrim(%Request.GetParameter("EP_REVIEW_TYPE"));
End-If;

rem Grey Sparling - If EMPLID is passed, walk through the rowset to find it;
If All(&gsEmplID) Then
    Local Rowset &rsEPApprSelect = GetLevel0().GetRow(1).GetRowset(Scroll.EP_APPR_SEL_VW);

    Local number &j;
    For &j = 1 To &rsEPApprSelect.ActiveRowCount

      Local Row &rowTest = &rsEPApprSelect.GetRow(&j);

      rem Grey Sparling - Test passed in parameter against current row's emplid;
      If &rowTest.GetRecord(Record.EP_APPR_SEL_VW).GetField(Field.EMPLID).Value = &gsEmplID Then
        Local string &rsRevType = RTrim(&rowTest.GetRecord(Record.EP_APPR_SEL_VW).GetField(Field.EP_REVIEW_TYPE).Value);

        rem Grey Sparling - If there's no reivew type parameter or if there is and parameter matches for current row, open up document;
        If None(&gsRevType) Or
          &rsRevType = &gsRevType Then

          /* Transfer the user to the selected review sub-document */
          &EP_GBLKEYS_WRK.EMPLID.Value = &rowTest.GetRecord(Record.EP_APPR_SEL_VW).GetField(Field.EMPLID).Value;
          &EP_GBLKEYS_WRK.EP_APPRAISAL_ID.Value = &rowTest.GetRecord(Record.EP_APPR_SEL_VW).GetField(Field.EP_APPRAISAL_ID).Value;
          TransferPage(Page.EP_APPR_DETAIL);
          Break;

        End-If;
      End-If;
    End-For;
End-If;

In case you saw this post prior to October 12, 2007, you may have noticed that it's different (and the original posting didn't work). I apologize for that, and now that I understood the way that global variables worked in the design of the application, I was able to figure out that I needed to test by establishing completely new sessions to ensure that prior runs didn't utilize previously set global variables.

Labels: , ,

Monday, July 09, 2007

Grey Sparling Excel Add-in for PeopleSoft

Well, it's official. We've expanded our add-in to provide lots of cool new features for excel output in PeopleSoft.

It's always interesting to see how one of your products gets used at a customer site and the value of it. When we added query features to the product, we knew they were cool (otherwise, why would you spend the time, right?). What we didn't realize how much it could change the way people use PeopleSoft.

What do you mean?

Well, we recently did some travelling to spend some time looking at how customers were using the new features of the product, and here's what we found.

  • Requests for new Reports went to near zero.
  • End-users were able to cut the time the spent looking for information in half.

Although we realized there would be some impact here, the numbers were surprising. However, this is merely an aspect of scale and is limited to the aspect of reporting. What really surprised us is how the feature of drilling to pages from queries changed the way end-users utilized PeopleSoft.

  • End-users used queries in place of PeopleSoft search pages in the application, because the queries gave them a more efficient list of items to work.
  • End-users also used our Excel drill menu in place of the PeopleSoft menus wherever possible because it allowed them to get to pages more quickly than using the PeopleSoft-delivered navigation (with the added bonus of passing the context from where they were)

And, finally the metrics: Some end-users at one customer were almost 50% more productive with these features because so much of the time spent using PeopleSoft for them was navigating to pages and finding the list of items that they needed to work. Bringing it all together and streamlining the navigation made a dramatic impact for them (and gave them the additional time to tackle other projects that had been languishing).

Want to learn more?

You can learn more about the product here. In addition, we've put together a flash demo that shows it in action.

Labels: , , , ,

Tuesday, January 02, 2007

Grey Sparling 2006 In Review

Out with the Old
We watched Dick Clark, drank Champagne, and sang Auld Lang Syne. We also began work on our year-end close, just like so many of the PeopleSoft customers who read our blog. This must mean that 2006 is over and 2007 is beginning. It was such a great year for us that we felt we would be remiss not to blog the year.

In with the New
2006 marked the first full year of operations for Grey Sparling Solutions. It was a great year to be part of the Oracle/PeopleSoft world. 2005 was a year of uncertainty for PeopleSoft customers (what is Oracle going to do? what is Fusion all about? who planned the PeopleSoft content at the 2005 OpenWorld?), but 2006 was a huge improvement.

Oracle announced Applications Unlimited at the Collaborate 2006 conference, and that has been hugely popular. Oracle also announced that the PeopleSoft products would have their own General Manager structure, with longtime PeopleSofter Doris Wong heading things up. Another interesting metric is that all of the system integrator companies that we work with seem to have more business with PeopleSoft projects than ever before

The Grey Sparling Effect
We saw a significant increase in the number of customers using Grey Sparling products. That wasn't too hard since we shipped our first product in November 2005, but we have more customers than employees now, which I always remember as being a key statistic for enterprise software.

It also helped that we have several new products that we shipped this year:

All of that helped us turn a profit for 2006. Woo hoo! Well, it wasn't a very large profit, but it still feels pretty good to hit profitability in our first 18 months of operation. We also became an official Oracle partner this year.

PeopleSoft Experts on the Road
Aside from folks that became Grey Sparling customers this year, we talked with a large number of people at various conferences. We were extremely flattered to be asked as subject matter experts by conference organizers to give Oracle (versus vendor) presentations. This allowed us to connect with over 2,000 PeopleSoft customers in person in 2006.

PeopleSoft Experts Online
In addition to physical meetings with folks, we also met lots of people via our weblog. I'm always surprised that there aren't more PeopleSoft bloggers out there - we certainly know plenty of people with lots to say about PeopleSoft!

We were also proud to be credited with inspiring some new bloggers out there.

2006 Blog Entry awards.
We figured that if Time Magazine can have its set of top 10's, we should too.:

Top Grey Sparling Conference Stories of 2006
While we're putting together our top blog entries, we might as well list out our top conference stories of the year.

  • Best Sales story. At Oracle Open World, we literally had a PeopleSoft customer come up to our booth on the first day and ask us how quickly we could generate an invoice for our Desktop Single Signon product. We did a remote install using the Open World wireless, and they were using the product live within 2 weeks for their 2007 Open Enrollment. Initial contact to Production in less than 2 weeks!
  • Runner-Up Sales story. At the FSIUG in New York after demonstrating the nVision Drilling Snap-on, we did a remote installation of a trial version at a customer. This customer was able to use WebEx to show it to end-users who were not at the conference, and decide to purchase it right then and there.
  • Best Cheapskate story. This had to be at the Alliance Conference, where we discovered how expensive it would be to rent an additional table for our booth for the 3 days the exhibition hall was open. Bert Laws of BearingPoint (a local of Nashville) was kind enough to make a run to Costco and buy a table for us (yes, it was significantly less expensive to buy a table than to rent it). We ended up giving the table to the folks at the Dell booth next to ours at the end of the conference (it would have been too difficult to check with our baggage).
  • Best Clueless travel story. As good interenet users, we used Google Maps to print driving directions for all the places we were going in the UK while we were there for the UKOUG (knowing that Chris's mobile account for his Blackberry wouldn't work there). I don't remember the last time I had to look at a map to get where I needed to go in the states. This didn't work too well in the UK, and we ended up getting hopelessly lost many times on the trip. We ended up buying a map to help us make it through the trip.
2007 - The Year Ahead
The coming year looks to be an exciting one as well. With the success of the conferences we attended last year, we're signed up for lots of conferences this year as well. Although the sessions haven't been formally approved for these conference, expect to see us at:
  • 2007 Northern California Training Day
  • 2007 Alliance Conference
  • 2007 EMEA Conference
  • 2007 Collaborate
  • 2007 Open World

From an engineering perspective, we've got two new products that we're partnering with customers to build in the first half of the year:

  • nVision Bolt-on. This will address most of the outstanding nVision issues that we had hoped to address while we were still at PeopleSoft.
  • Workflow Notifications. This is a product requested by a long-time Higher Education customer who saw our email notification functionality in our report distribution product, and are currently grappling with the best way to deploy workflow with eProcurement and HCM applications.

We also have plans to add some new features to our existing products, so if you've already licensed something from us, you'll probably hear from us soon.

Labels: , , , , , , ,

Thursday, August 31, 2006

Java and PeopleCode Tips and Tricks - Part 3

I haven't written anything on the Java and PeopleCode series (part 1, part 2) recently, so I thought I'd whip something together this evening.

As previously discussed in the series, there are a few, um, quirks in the bindings between Java and PeopleCode. One typical workaround when you can't cross between Java and PeopleCode successfully is to write some additional glue code on the Java side to provide an easier "target" to work with. This post will discuss a few tips and techniques for doing it all from the PeopleCode side.

Why would you want to avoid writing the Java glue code to simplify things? Well, it's certainly not to avoid the complexity of Java (as the rest of this post will show). A more common reason is to avoid needing to distribute the compiled Java code out to each application server (which can be the source of various logistical difficulties).

On with the code. The use case here is to take an image and modify it so that we can stamp some text on it. The example comes from an article that shows how to use the Java Advanced Imaging libraries that are part of the standard Java environment as of Java 1.4.

The actual working code is below. Let's start by looking at the first line of code that causes problems.

&jBufImage = &jImageIO.read(CreateJavaObject("java.io.File", &sSourceFileName));

This line of code will trigger the infamous "more than 1 overload matches" PeopleCode error. If you look at the relevant Javadoc, you'll see that there are indeed multiple versions of the read method. Java can tell these apart by the type of the parameters being sent in, but PeopleCode only uses the number of parameters to differentiate among methods in a Java class with the same name.

In order to call this method from PeopleCode, we'll need to use reflection. Reflection is how Java lets you determine class metadata (such as what methods it has and what parameters they take) at runtime.

Here's what it looks like in action. This is broken into separate lines for clarity, but as you'll see in the code, you can combine these where it makes sense.

&jReadArgTypes = CreateJavaObject("java.lang.Class[]", &jIOFileClass);
&jReadMethod = &jImageIOClass.getDeclaredMethod("read", &jReadArgTypes);
&jReadArgs = CreateJavaObject("java.lang.Object[]", CreateJavaObject("java.io.File", &sSourceFileName));
&jBufImage = &jReadMethod.invoke(&jImageIO, &jReadArgs);

This is easier to explain working from the bottom up. In order to call a method via reflection, we need to have the correct Method class instance and use it's invoke method. That's what the 4th line is doing. The first parameter, &jImageIO, is the same object that we were trying to use before, and the second parameter is an array of parameters that invoke() will pass along to the "real" method.

Getting that parameter array is what line 3 does. When we have all of the values that are ever going to be in the array, then using CreateJavaObject with the braces, [], at the end of the class name is nicer than using the CreateJavaArray PeopleCode function. Mainly because we can pass all of the values in at once instead of setting them one by one as CreateJavaArray forces you to do.

We also needed to have the actual Method object. That's what line 2 is doing. We call the getDeclaredMethod() method of the underlying Class object (this is the actual Java class that defines what a Java class is; chicken, meet egg) and pass it the name of the method that we want, along with array of the parameter types (not the parameter values!) that the method expects.

You can get the underlying Class object for any Java object by calling the getClass() method (there are examples in the code below). But when you have a JavaObject in PeopleCode that you obtained via GetJavaClass (instead of CreateJavaObject), then you actually have a PeopleCode reference to the class and not an instance of java.lang.Class. The PeopleCode reference allows you to call static methods on the class, but if you call getClass() on it, you'll get an error. The secret to getting to a java.lang.Class instance for a particular class when you don't have any instances of that class is to do something like this.

&jImageIOClass = GetJavaClass("java.lang.Class").forName("javax.imageio.ImageIO");

Now &jImageIOClass is an actual java.lang.Class instance, suitable for the reflection work that we're doing.

Finishing things off, in line 1, we created the array of parameter types that we needed for the call to getDeclaredMethod(). The parameter types are specified by using their underlying java class, so you definitely want to be sure that you understand the difference between a java class and the java.lang.Class object which describes that java class.

Whew! That's a lot of explaining to do just because PeopleCode doesn't resolve all Java methods properly. What's worse is that we're not done yet. We now have another problem.

In the original line of PeopleCode, we called a method ("read") that returns a Java object. Specifically an object of type java.awt.image.Bufferedimage. But we can't use it as a BufferedImage object, because PeopleTools looks at the return type for invoke() and sees that it returns java.lang.Object, which is the base class for everything in Java. If you try to do something useful with &jBufImage (like get the dimensions of the image), PeopleTools will give you a "method not found" error.

Thankfully the underlying JVM still understands that this is a BufferedImage object and not just a java.lang.Object. So we can (read "have to") use reflection again in order to use our BufferedImage. Of course, since we're using reflection with BufferedImage, that means that any Java objects that we get back from reflected method calls are also misunderstood by PeopleTools (it will think that they are instances of java.lang.Object rather than whatever they really are).

So, once you fall into needing to use reflection within PeopleCode, you end up using a lot of it. Believe it or not, it's not so bad once you wrap your head around it. It took me longer to write this post than it took to write the code below since the extra work is essentially just some extra typing.

Obviously if you are doing a lot of Java/PeopleCode integration, then you'd be better off just writing a little bit of glue code on the Java side to avoid all of this, but when you're just doing something quick (like using Java hashmaps instead of faking it with 2 dimensional arrays in PeopleCode), then this technique works well.

Finally, here is the actual code, along with the starting image (found in your PeopleTools directory) and the altered image.





Labels: ,

Wednesday, August 30, 2006

Passing additional parameters to PeopleSoft pages

PeopleSoft applications support passing parameters in the URL for a given component so that you can pop someone directly into a purchase order, employee record, etc. This is tied directly into how row level security works in PeopleSoft, except that row level security is tied to the fields in a record that are flagged as unique keys, while search processing is tied to the fields that are flagged as search fields in the record definition in Application Designer.

However there are times when you want to pass in additional parameters. This could be either from some particular business use case (e.g. delivered page shows all detail, but sometimes you want to limit that) or even the case where the delivered page does not use regular row level security, but instead rolls it's own, along with a bunch of search fields at level 0. The PeopleTools Process Monitor page is a good example of this, along with a good chunk of Financials.

The trick is to use the %Request object in PeopleCode to check if there are additional parameters that have been sent on the URL. If so, then take action appropriately.

Put something like this in your component's Prebuild event or even on the page Activate event for the page that you're working with.

Local String &sMyValue = %Request.GetParameter("myvalue");
If All(&sMyValue) Then
rem Do something with &sMyValue - like filtering the data on the page;
End-if;


Keep in mind that, depending on where you place this logic, the default component processor logic may have already run.

Also, keep in mind that the %Request object is only valid during processing of online pages. It does not work when you call a component from a component interface.

Labels: ,

Determing the PeopleSoft Portlet URL

If you've ever wondered how to get direct access to the content with each portlet on a PeopleSoft portal page, the answer is to use the source, Luke! (That's why they don't let me do much marketing around here :-)

If you view the source of the portal page in your browser, you can search for "Begin Pagelet" and you'll see the direct URL for each portlet. You may need to do repeated searches to find the portlet that you're particularly interested in.

If you load that portlet URL directly into the browser's location bar, then you'll see nothing but that portlet. Of course, nothing also means no CSS. The CSS that gives the portlet some semblance of looking nice (beauty being in the eye of the beholder and all that) is loaded by the overall portal page, so when you go after just the portlet, you get the raw HTML without CSS. Which is likely what you want - if you're pulling one portlet into a separate portal, then you want that portal to be able to apply it's own look and feel to the PeopleSoft content.

One thing to keep in mind before using those URLs. If you need to login to see the portlet in the PeopleSoft portal, then you also need to login to see just the portlet. So if there's some other portal (or RSS reader or whatever) that is accessing the portlet on your behalf, then it needs to somehow get a working PeopleSoft session cookie on your behalf before accessing the portlet.

Historical question for you all; why are portlets called "pagelets" within PeopleSoft? Rich Manalang, you are not allowed to answer this :-)

Labels: ,

Friday, August 25, 2006

Hiding the PeopleSoft Pagebar in all component

We had an interesting "Ask the Experts" question yesterday about how to disable the PeopleSoft page bar across the entire system. The page bar is what has the "New Window", "Customize Page", and "Copy URL to clipboard" links in it.



There is a personalization setting for the "Customize Page" link that can be defaulted completely off at the system level, but the other options can only be turned off by going into each component and changing these properties. Financials 8.9 has 6723 components in it. Not something that you want to do one at time, especially since changing these settings is technically a customization.

One potential workaround to this is to just use SQL and update the component properties manually, but you generally don't want to muck around with making direct updates to the PeopleTools tables (and you're still customizing a ton of objects - you're just doing it faster).

The other potential workaround that can be used still involves a customization, but a less invasive one. It involves using a little CSS to hide the page bar. This one line of JavaScript will do the trick.

document.write("<style>#PAGEBAR { display: none; }</style>");

If you put this into one of the delivered JavaScript programs that is added to every page (which is a customization), then you'll be set.

Note that you haven't actually disabled this functionality, just hidden it. So if you're really desperate to keep people from using the pagebar, then you will have to disable it on each component so that the backend knows that it's disabled as well.

Labels: , ,

Monday, August 14, 2006

IE August Update Crashes PeopleSoft

The IE security updates that just rolled out last week are having a bad effect on numerous websites, including PeopleSoft applications. By bad effect, I mean completely crashing Internet Explorer (IE 6 SP1 specifically).

The crash comes fairly quickly when using websites that are served with HTTP 1.1 and using compression. These have been the default settings for PeopleSoft applications for quite awhile now, so

Microsoft has a page up that details this and provides both a workaround and a hotfix. You'll need to contact Microsoft directly for the hotfix - there isn't a direct link to download it.

The workaround, turning off HTTP 1.1, actually causes problems because IE then gets confused by the compressed data coming out of PeopleSoft. This shows up when you start navigating through the PeopleSoft portal and instead of seeing pages, you are asked to save a file. If you look inside the file, you'll see the compressed data that PeopleSoft was sending out.

What you'll need to do instead is to turn off compression temporarily for your PeopleSoft applications. You can do this by going to PeopleTools -> Web Profile -> General and turning off the checkboxes for Compress Response, Compress Response References, and Compress Query. This will require restarting the web server though.

This will definitely hurt network performance for your remote users though, so if you have only internal users with known browser configurations and have not rolled out these IE patches, then you'll have to weigh the pros and cons of waiting on the patches versus the network performance.

Labels: ,

Tuesday, August 08, 2006

Drag and Drop stopped working in Tree Manager?!?!

One of the cool features added in PeopleTools 8.4 was drag and drop in tree manager. Yesterday, as we were installing Report Explorer at another customer, they mentioned that recently drag and drop stopped working in their environment. Interestingly, they had been dealing with that issue for quite some time although the solution was relatively simple.

Drag and Drop in Tree Manager... What's that?
Drag and drop allows you to move tree nodes around within a tree without requiring you to cut and paste them. This makes the product much more usable, when you are resequencing nodes or moving subtrees from one location to another. For companies that perform reorganizations on a regular basis, this feature is a life saver.



Okay, so why did it break all of a sudden?
Good question. The drag and drop features in Tree Manager are enabled through some javascript embedded in the Tree Manager page. In almost all the circumstances where drag and drop stops working, it has to do with the security settings in Internet Explorer.

Mike Friedman put together a very good posting on the IEBlog that explains how Internet Explorer applies and manages security related to JavaScript and other embedded objects that could be used to perform malicious activities on a machine.

Great... How do I fix it?
Fortunately, the fix is relatively simple. You merely need to make your PeopleSoft URI a trusted site in Internet explorer. In the default IE configuration, JavaScript will execute on a trusted site.

Here's how you do it. First, you go into Internet Explorer and use the Tools menu and select Internet Options.



You will then be displayed the Internet Options dialog. Click on the Security tab to modify the security settings.



Finally, click on the Trusted Sites button and enter your PeopleSoft site into it. You can use wildcards in the URL, if you like.



Drag and Drop should start working if you put in a valid address.

Labels: , ,

Monday, February 13, 2006

Enhancing the Usability of PeopleSoft Applications

This entry is about how to enhance the usability of your PeopleSoft applications.

PeopleSoft always did well against competitors when comparing user interfaces, but there is still plenty of room for improvement. I don't know of any PeopleSoft users that would disagree with that. Let's take a look at one example of how we can improve the user interface in existing PeopleSoft applications.

It's common in PeopleSoft applications to see lots of grid controls on the pages. One issue that grid controls have is that they don't provide great keyboard navigation for power users. There are hotkeys that you can use to insert and delete rows from a grid (alt-7 and alt-8) as well as more advanced things like searching the grid, toggling between showing all rows of data or just a subset. You can see a list of the system hotkeys by pressing Control-K on any page in PeopleTools 8.4x applications.

If you'd like to do something like move through a grid like you do in a spreadsheet (up key moves up a row, down key moves down a row), then you have to do some work. So, that's what we're going to do. Along the way we'll also show how to highlight the field with the cursor in it. I did that to help make the demo video (see below) a little more obvious, but it's a useful tip in and of itself.

Step one is to capture the up and down keystrokes in the grid. PeopleTools has a delivered keystroke handler that gets inserted each page at runtime. Unfortunately there's no support for you changing how that works. You do have access to the code for the generic keyhandler, but I'd recommend against changing it. It's a little bit complicated to understand, and there's an easier way to insert our logic.

For the purposes of keeping the demo fairly simple, we'll insert our logic into to the page by placing an HTML area on the page definition. There are better ways of getting your logic into PeopleSoft pages without touching the delivered PeopleSoft definitions (which is the only way that we at Grey Sparling build our products), but those are beyond our scope today.

Note that in this demonstration I attached this to the USER_ROLES page, but it will work on any page with a grid control in PeopleSoft 8.4 and above. I've attached the code that goes in the HTML area as a separate file. Here's what the code inside the HTML area looks like:



We start off with a little CSS that defines how the field with the current focus looks. Here we're just setting the background to yellow, but you can do anything that you want. This gets turned on and off in the onfocus and onblur events for the fields.

Next we define a couple of helper functions (getEvent and getEventSource) to smooth over some browser differences.

Then comes our main function for handling the up and down keys, gridKeyHandler. We want this to get called everytime a key is pressed. The code looks at which key got pressed (38 is the keycode for up and 40 is the keycode for down). If it's not something we're interested in, then we don't do anything.

If it was an up or down key, then we use a regular expression to see if we're in a grid field. Grid fields have IDs of the form RECORD_FIELD$row_number. On the user roles page, the grid control is for the record PSROLEUSER_VW, so we see fields like PSROLEUSER_VW_ROLENAME$1, PSROLEUSER_VW_ROLENAME$2, etc. in the generated HTML. Our regular expression looks for some text followed by a dollar sign, followed by some digits. If we find that, then we add or subtract one from the row number (depending on whether up or down was pressed), and then try to move to the appropriate field.

The next two functions (oninputfocus and oninputblur) exist as event listeners for when focus moves between the fields. This technique comes directly from the HTMLDog folks Suckerfish series. Go check out some of their demo pages. Great stuff!

So how do we get these functions to execute at the proper times? The addEvent function from Scott Andrew LePera. PeopleTools attaches it's key event handler by directly assigning the PeopleTools JavaScript key handler function to the onkeydown and onkeyup properties of the document object. That works, but only for mapping one function to the event. addEvent allows us to "attach" additional functions to these browser DOM events independent of the PeopleTools function. For those are interested in using this technique more extensively, be sure to read these follow up articles that explain why this technique isn't the end-all, be-all method for doing this. It suits our purposes well enough though, so we'll use it here.

The last little bits make use of the addEvent function to wire things up. We can hook up our grid key handler right away, but we need to delay the attaching of our field level handlers until the page finishes loading (otherwise we might not have all of the fields even defined in the DOM yet) so we put that logic in a separate function and use addEvent to call that at page load. Alternatively, you could just make sure that this extra logic that we're adding always gets put into the HTML page after all of the fields that are having handlers attached to them.

I put together a short Flash demo of this code in action. This was my first time using the Wink tutorial/presentation software. It lets you record what you're doing and then lets you go back and do things like add text boxes, etc. highlighting what is happening in the demo. The lack of artistic ability in the demo is definitely due to me and not Wink!

There's lots of things that I would do to beef this up to make it production ready.
  • Don't use an HTML area to get this code into the page.
  • Move the CSS for the current field focus out of this code and use a regular PeopleTools style sheet definition.
  • Add some unit tests for it with Selenium or JSUnit.
  • Add some code to handle "wrapping around". If someone is on row 1 and presses the up arrow, then this should wrap around to the last row in the grid. If they are on the last row in the grid and they press down, then they should move to row 1.
  • Beef up the regular expression test to handle the add row/delete row buttons. If you do a view source on a PeopleSoft page, you'll see that these buttons don't follow the same naming standard as the rest of the fields in a grid.
  • Do some more testing on pages with grids at level 2 and 3.
As you can see, there are ways of enhancing the usability of existing PeopleSoft applications without too much effort. The grid navigation enhancement is just an example of what is possible.

Let me know if you end up implementing this in your PeopleSoft apps and how your users like it.

P.S. That picture of me on our company "About" page? That was Larry's way of letting me know that I should have been in attendance when we were getting pictures taken :-) I'm tempted to leave that picture up though.

P.P.S. I still haven't put up a new picture, but I delete the reference at the top to some conferences that have come and gone.

Labels: ,