Topic
6 replies Latest Post - ‏2013-03-01T09:56:16Z by Dave_Ward
SystemAdmin
SystemAdmin
35 Posts
ACCEPTED ANSWER

Pinned topic Complex Workbasket filtering

‏2012-08-29T09:48:36Z |
We have been thrown a bit of a curveball by one of our customers, and I would like some advice please!

When we first started developing the solution here, we had a requirement that workitems would only be shown in a queue if two properties (Business Unit and Department) that are resident in case (and thus workitem) data match similar properties for the logged in user which we were set as user attributes in the LDAP server, and which we were retrieving using a custom widget. This means that we could reduce the 740 queues in the existing (non-FileNet) application (one for each BU/Dept combination) to just one workbasket in the new solution, but with some clever filtering applied.

So, to clarify, we effectively have a matrix something like this:

User attributes BU1 / Dept 1
Case Attributes BU1 / Dept 1 user can see workitem in workbasket

User attributes BU1 / Dept 1
Case Attributes BU2 / Dept 2 user cannot see workitem in workbasket

To make this work, we currently have a custom widget that applies two filter objects to the workbasket in the background:

Case BU = User BU
Case Dept = User Dept

The filter objects are implicitly ANDed together (as this is the only option available in CM), and we hidden the filter options so the user cannot change them.

The problem now arises that the customer has come back and told us that users may be members of several BUs and Departments, and that they should be able to see all the workitems relevant in the workbasket. In other words, we would need to be able to either apply a filter like:

{user attribute list} CONTAINS {case property}

or possibly

{case property} IS A SUBSTRING OF {user attribute list}

As a second best,we would need to be able to apply multiple filters in an OR configuration. Neither of these approaches seems to be possible using the native functionality.

Can anyone suggest an approach that we could take using what is available (either OOTB or as an asset)? We are desperately trying to avoid writing yet another custom workbasket...
Cheers,

Giles.
Updated on 2013-03-01T09:56:16Z at 2013-03-01T09:56:16Z by Dave_Ward
  • drdamour
    drdamour
    25 Posts
    ACCEPTED ANSWER

    Re: Complex Workbasket filtering

    ‏2012-09-05T19:24:47Z  in response to SystemAdmin
    man, are we on the same project? i did the same thing just a few months back with hidden filters. I did it by changing the inbasket script function at runtime to always add values for the filters right before the REST URL is constructed, this hid the filtered value from the UI but made it still apply. i was (pleasantly) surprised to find that the filters applied from the UI still functioned as an additive AND to the filters i was applying in secret.

    as to your question, this is exactly where i am now as well. I need to OR multiple filters instead of ANDing them and cannot find a way to do this OOTB. My previous solutions to this problem have always involved querying the PE QUEUE VIEWS directly and i was thinking this was my only choice once again, expose a JAX-RS service that has identical semantics of the exisiting PE REST API and create my own Inbaskets that allow OR'ing. Then point PE to my new custom API...very ugly w/ a lot of effort required.

    would love to hear how you applied your filters in secret and what you're thinking to enable "and's over or's" functionality in an inbasket.


    I am Just a new Boy,
    A Stranger in this Town,
    Where are All the Good Times,
    Who's Gonna Show this Stranger Around?
    Check out our Agile ACM Catalogue: Widgets, APIs, & Components for Building Solutions
    • SystemAdmin
      SystemAdmin
      35 Posts
      ACCEPTED ANSWER

      Re: Complex Workbasket filtering

      ‏2012-10-19T07:32:26Z  in response to drdamour
      A few years on and we find ourselves in exactly the same boat that we want to have an OR value applied for a single filter (eg. Pet = 'Cat' OR Pet = 'DOG).

      Anyone found any clever ways of doing this without have to build a new inbasket and corresponding service to feed it?
    • Dave_Ward
      Dave_Ward
      38 Posts
      ACCEPTED ANSWER

      Re: Complex Workbasket filtering

      ‏2012-12-10T13:33:28Z  in response to drdamour
      Hi there,

      Really interested in how you managed to add filters but make them hidden. Don't suppose you could share a bit of the technical detail on how you did it?
      Do the hidden filters stay applied all the time (even if the user adds / changes some visible filters or hits the "clear filter" button?

      Thanks
      • SystemAdmin
        SystemAdmin
        35 Posts
        ACCEPTED ANSWER

        Re: Complex Workbasket filtering

        ‏2012-12-21T05:50:18Z  in response to Dave_Ward
        i used the prototype overloading magic that makes ECMAScript more LISP than Javascript. this has an unfortunate side effect of only working as long as the existing widgets are coded the same..but they don't often change and you can always reflect on he existing code and make decisions in your custom widget. anyways...here's the info:

        It took a while to dig around in the code but eventually I found the com.ibm.im.ecmwidgets.common.domain.QueueElementsQuery class that seemed to be in charge of getting the queue elements and counts for the various inbaskets. It uses it’s member variables (properties on it’s this pointer) url & queryArgs to in calls to the bpmService class’s getQueueElementsCount & getQueueElements. The queryArgs member is the more important one, it has it’s own members one of which is filters that is a string that looks something like this:

        Filter1Name=Filter1OperatorValue,Filter2Name=Filter2OperatorValue

        Which is generated by enumerating the current filters applied on the inbasket. Interestingly, the programmers made an assumption that there will not be any filters applied on the first query, thus the execution paths for retrieving the elements for the current page and the counts that first run have checks like this:

        getCount:function(_466)
        {

        if(_466)
        {
        this.createFiltersQueryArgs(_466);
        }

        Interesting to note is that the filter arguments aren’t managed/owned by the QueueElementsQuery class, they are passed into the method as a parameter. This kind of makes sense as it means the inbasket is in charge of managing the filters, not the query. It is actually the inbasket widget that makes the assumptions that there are no filters present for the initial query making calls like getCount() instead of getCount(filters) where filters is some default value. The fact that the filter model is owned by the inbasket widget and not this query class poses some unique problems as it will be difficult to keep the UI classes and data access classes in sync. I ran this by the person requesting the functionality and they said it was ok at this time to not worry about that little gotcha (you’ll see how this presents itself in the ui later in this post).
        My strategy was pretty simple, no matter what filters were sent to the QueueElementsQuery (even none) I needed to add an additional filter. This rule needed to apply to the first query that occurs on initial widget load (when the inbasket doesn’t pass in a parameter specifying filters to the getCount method) for both the count and queue element queries as well as all subsequent queries. I created a new widget that overrode three methods on the QueueElementsQuery class. I will go over each of them now.

        Code Snippet
        com.ibm.im.ecmwidgets.common.domain.QueueElementsQuery.prototype.createFiltersQueryArgs = function (Filters) {
        var temp = [];
        temp.unshift("[");

        //Begin Adding Secret Overridden filters
        temp.push("Filter1"); //The name of the filter per PCC config
        temp.push("="); //always =
        temp.push("%administrator%"); //The value to pass into the filter, IE %string% for like operators, -1 for < operators
        //End adding secret overriden filters

        dojo.forEach(Filters, function (Filter) {
        if (Filter.operatorValue !== null && Filter.operatorValue !== "") {
        temp.push(",");
        temp.push(Filter.name);
        temp.push("=");
        temp.push(Filter.operatorValue);
        }
        }, this);

        temp.push("]");
        this.queryArgs.filters = temp.join("");

        };
        This is the key new behaviour. On top of any filters that are passed in, we also add as many secret filters as we need. You could determine what filters to add at runtime using if statements against the current environment.
        Code Snippet
        var OverriddenGetCountMethod = com.ibm.im.ecmwidgets.common.domain.QueueElementsQuery.prototype.getCount;
        com.ibm.im.ecmwidgets.common.domain.QueueElementsQuery.prototype.getCount = function (CurrentFilters) {

        //If there are no filters calculated, let's calculate at least the minimum ones
        if (this.queryArgs.filters == null) this.createFiltersQueryArgs();

        return OverriddenGetCountMethod.call(this, CurrentFilters);

        };
        This just makes sure our secret filters are applied no matter what. If queryArgs.filters is null that means the user has defined no filters because they don’t have values. This happens the very first time the widget loads as well, so we’re covering that special case.

        Code Snippet
        var Overridden_retrieveMethod = com.ibm.im.ecmwidgets.common.domain.QueueElementsQuery.prototype._retrieve;
        com.ibm.im.ecmwidgets.common.domain.QueueElementsQuery.prototype._retrieve = function () {

        //If there are no filters calculated, let's calculate at least the minimum ones
        if (this.queryArgs.filters == null) this.createFiltersQueryArgs();
        return Overridden_retrieveMethod.call(this);
        };
        This is the analogous code for retrieving the queue elements to the previous snippet that gets the count. Same logic applies to cover the same scenarios (when the filter dialog is empty and the first time the inbasket widget loads). Notice for both that I am actually returning the result overridden base class method, some serious OO going on here.

        Note: You might be worried that setting a filter in the UI will override our secret filter but they seem to be additive! I can only imagine this works because the PE REST API is looping through every item in the filters query string parameter then resolving that to a filter calculating a SQL where clause fragment and appending that to the overall sql clause to be executed against the PE database. I’m not certain this behaviour is by design, but it’s certainly working to our advantage here.

        the last trick is cause widgets are loaded randomly (kind of, in BSpace they are left right ot top to bottom..but you can't rely on that). so you have to query the active code base for the method to override. So in the custom widget's load use a setTimeout loop to wait for the code to override to be there. something like this:

        Code Snippet
        //IBM iwidget event. Occurs when widget is loaded on the page.
        onLoad: function () {
        var i = 0;

        function OverridewidgetsMethods() {
        try {
        if (!dojo._hasResource) {

        i++
        //let's only check 100 times, then give up
        if (i > 100) {
        alert("Couldn't find the QueueElementsQueryafter 100 attempts, it's probably not on the page, you should remove the widgetname from the page since there's no inbasket");
        return;
        }

        setTimeout(OverrideCalculateColumns, 100);
        }
        else {
        //do the overloading (the snippets from above)
        }
        some tricky but effective stuff here. gotta love functional programming!
      • SystemAdmin
        SystemAdmin
        35 Posts
        ACCEPTED ANSWER

        Re: Complex Workbasket filtering

        ‏2012-12-21T05:56:32Z  in response to Dave_Ward
        Do the hidden filters stay applied all the time (even if the user adds / changes some visible filters or hits the "clear filter" button?

        oh yeah, mos definitely they do, that's why they're hidden! much better than that technique of the incoming events for filters.
        • Dave_Ward
          Dave_Ward
          38 Posts
          ACCEPTED ANSWER

          Re: Complex Workbasket filtering

          ‏2013-03-01T09:56:16Z  in response to SystemAdmin
          Thanks for the very comprehensive answers. Appreciate it.