/ Development  

Unlock your knowledge for dominating task workqueues; You'll never work the same way again

Hi there AppWorks fans,

Welcome to a new installment of AppWorks tips.

At this moment of writing this post, I have no idea if the “central queue” mechanism is even possible on our beloved platform. We’ll just figure it out how to make it a proper implementation. If it’s the best solution possible all depends, but we can for sure learn from it. Why a task queueing mechanism? Well, I hear in every project such a requirement passing by. So, we have a team of knowledge workers and want to grab (automatically?) a task from a central task-bin when the previous task is “DONE”.


Let get right into it…

During writing the introduction (and a good night sleep) I get to the conclusion it’s a wise decision to split the post into two sections. One section for “Case related working” and the other based on “Task related working”. What is the difference and who cares? Well, that’s almost a post on itself, but to be in short:

  • “Case related”: The case itself is central; Actions and updates are done on the case itself. Your UI will start with an overview/dashboard of cases (open, closed, assigned, overdue, priority, difficulty level, etc.). The knowledge worker can pick a case to work on related to its skills. Cases follow a lifecycle flow and will be archived/cleaned over time and contain relative information (even subcases) and content related to the case. A case can have a task to be done, but that’s not the main focus; With intermediate tasks a case handler can add additional information based on their knowledge. A real inbox is not needed as “optional” tasks are managed within the case.
  • “Task related”: A task (something to be done) is central; A solution leans heavily on the inbox. Not only the inbox for a specific user, but can also be a central task inbox to pick from; like a work-queue. A task can have a case involved, but is not its main purpose. Updates on an “optional” case are done via the task showing the case information when the task is opened. There is no direct need for task dashboarding to pick tasks from, but separate reporting is asked at management level; Keep this also separate from the solution! For this post we’ll also build dashboarding for tasks, but that’s more to see the difference with case dashboarding.

There is one thing you should avoid at all times; Don’t mix both principles in one solution!! Trust me, it’ll be a mess…I saw it several times! Involve your UI expert here as well as he/she can bring focus on these principles. Treating him/her with positive feedback has direct impact on the User eXperience!

Let’s dive into the implementation phase for both situations…After, starting your VM, getting a ☕, and diving into your workspace.

My project always starts with a basic folderstructure, so dive into the entities folder and create a new one. I name it case with just one case_name property, generate the rest and brush it up naming wise to something like this:

workqueue_001

With cases, you want to do magic things…Like assigning it to a colleague, moving it through phases of a lifecycle, or flag it with a priority stamp. To keep an overview, we need a dashboard (as in a new homepage) as well. Don’t over-rush now, first things first!

Add the ‘Assignee’ BB to the case entity and make sure the case is assigned to a role; In my case the crafted fun_coordinator:

workqueue_002

Do you need to assign it? Well, I was looking to just leave it unassigned, but couldn’t find an option to do so!? #SUPPORT, but it doesn’t matter…A good coordinator has (normally) nothing to do, so be it! 😂…Yes, it’s Friday (and too hot where I currently sit!)

The fun_coordinator is a new document…see screenshot. Assign yourself (or a test-account) to this role in the ‘User Manager’ artifact.

Publish your project and try to create a new case instance now…

workqueue_003

Interesting! My role is published!?…After a “ReThink” the solution for the error is found in this post. After following the steps in that post and making sure my awdev account is member of the fun_coordinator from an OTDS perspective, the creation is working fine.

I do see something interesting, as after creating my case property in runtime it’s not assigned (yet!)? Is this strange? I don’t know…It depends on how you look at it! It might be even better like this; If you have multiple department coordinator roles, you can make this even dynamic and flow your case directly to a group of department members! That’s an “Aha”-moment…Not for now, but you get the point. See the screenshot what I see currently in runtime:

workqueue_004

So, that’s not assigning “assigning”, but more queuing “assigning”…We’re learning things here, Great; Next!

The ‘Lifecycle’ BB, add it to the entity with a basic implementation like this:

workqueue_005

Save it, but before publishing it, I make 2 extra changes:

  1. Add the ‘Lifecycle’ panel to the default layout.
  2. Add some ‘Lifecycle’ properties (and ‘Assignee’ properties) to the ‘Create’ form.

You can do both tasks for yourself…Comment me otherwise.

To keep in mind:

  • A lifecycle always starts on creation of an entity.
  • Old entities don’t get this lifecycle magically (that’s another post…For the future; if requested!)

Now, do your publication and have a view on the new option in the action bar on a new entity instance in runtime:

workqueue_006

How nice…But now the case is almost a task on its own? EXACTLY!! Who raised that question!? You can join my parade of knowledge…Have a call and I put you personally on a project! 🤗

Let’s continue…I will leave the priority flagging (case_has_priority) on a case with you. It’s just a ‘Boolean’ type of property to scope further down in our lists. That’s the same for the case_level to differentiate between LOW, MEDIUM, and HARD cases. It’s just an Enum property with fixed values. Finally, I put a case_duration property in place to calculate cases out of due; It’s a property of type ‘Duration’ which we can use for interesting business rules later on…Managers like colors and see when cases are out of date!

This is how it looks like in runtime for now:

workqueue_007

Ohw…Before I forget, I also add the ‘Tracking’ BB to have a creation date available…Could be handy for the overdue calculation (I’m not sure)! We might use a different route, but I just leave it for those interesting “data”-managers. 😏

Next is to add some fancy ‘List’ BBs to scope further down in specific cases. A dashboard can show different lists; We already have the ‘All cases’ list in place:

workqueue_008

First the cases with lifecycle state “Finalize”; I create a copy of the available list and add an extra filter in the lifecycle state:

workqueue_009

I guess you can figure out the lst_high_cases, the lst_priority_cases, and lst_unassigned_cases (where the AssigneeIdentity.Identity.Id equals “empty”)…right?

The tricky lists are the lst_my_cases and the list lst_overdue_cases!?!? Only, not when you follow this blogpost! 😁

lst_my_cases

workqueue_010

For you to copy: $(User.Properties.Name)

lst_overdue_cases

Well, this one is tricky as we can’t select any ‘Duration’ type of properties as a filter condition for the list!…Don’t shoot the messenger. To make the filter work, we introduce a new Boolean property case_is_overdue which we can check (like the other lists); The only thing we need to do, is setting it to TRUE once the date is out of due. When will this be? Yes, my friend…That’s business logic; Not in a ‘Rule’ BB, but in a ‘Deadline’ BB (again…Don’t shoot the messenger!):

workqueue_011

What should happen when reached? Well, we can’t set any properties, but we can start a BPM bpm_flag_as_overdue! I won’t do the implementation in this post (as it requires webservices, message mappings, and an ‘Application Server Connector’ service container), but have a look yourself in the download link of my project at the end of this post.

workqueue_012

If you’re curious what happens in the back-end…Watch the PIM as this ‘Deadline’ BB will instantiate a process with name ‘Entity Deadline Monitoring Process’ in “waiting” mode; When I create a new case instance in runtime, wait for one minute (which is my dynamic duration setting during creation), this will be the outcome:

workqueue_013

Fascinating…!! We’re learning here! 😉

Did you know (I also write this down for myself) that when you fill in $() as equal condition on a text property (like case_name), you get the advanced expression editor exposed after closing and opening the list again:

workqueue_014

This is what a tried: now - item.Tracking.CreatedDate > item.Properties.case_duration; It’s validated correct and also publishable, but it eventually failed in runtime…

With all this “basic” functionality in place, I would now like to focus on the dashboarding part from here.

For this we right-click on the ‘homepages’ folder and create a new ‘Home Page Layout’ type of document. I give it the name hp_cases_dashboard; Leave it as ‘Regular’ layout type fitting the display screen (all by default). Once done, we can configure it with a set of ‘Results’ panels that will show the lists of our ‘Case’ entity for a regular knowledge worker.

workqueue_015

In runtime (after publication), you can now move to this UI:

workqueue_016

I do this all with a ‘Developer’ account currently as I want to leave any security out of scope; Normally, I would set the correct runtime security for the homepage documents to a specific solution role and show only the correct homepage to the correct role!

Why not all lists? Great question…

  1. Not all the lists are interesting for a regular user; Only for a manager type of user
  2. You don’t want to spoil your end-users with lists all over the place…Show what is needed and put the rest behind a security wall (based on roles)

So, next is a manager type of dashboard (Cases reporting) with all the left-over lists; This is my second dashboard in runtime where I introduce tabs by dropping panels on each other during design-time, and you see the enablement of the “Card view” functionality on a list as well (an extra task for you to implement):

workqueue_017

I don’t know if you already saw it on the ‘List’ BB, but in later versions of the platform you can even create a ‘Report View’!

Now what? Well, isn’t this already a simple case management solution? You see, not one task is fired; We can still flow through the lifecycle (with action buttons), we can update our case information, pick it up, and get an overview…What else does a knowledge worker and manager need (next to some security and managing related content)!? What I say…Don’t make the simple, complex! 😎


Now for the other side of the medal where we start with a task handling mindset! This puts the scope directly on the inbox of the user (from the default ‘Home Page’ in runtime)…Or better, the “Worklists tasks” category within it:

workqueue_018

The great question here is: How on earth do I drop on item into this node?

For this we first dive into the ‘Identity’ node on that same view. If you don’t see this node, contact your administrator! In here you can create a new ‘Worklist’ type of entity instance with the fancy name New cases. Just create it and go back to the overview. A worklist requires an ‘Organizational Unit’; You can create one in that same ‘Identity’ node with the name My organization. Open the OU, and add 3 new positions (incl. a lead position!):

workqueue_019

Next step is to add a ‘Member’ to each position…I just assign my awdev account to each position; like this:

workqueue_020

With this circus in place, get back to the worklist New cases, and attach the just created unit as well as a ‘Lead position’ in the tab after:

workqueue_021

By the way, when you search for the ‘Lead position’ it shows all positions!?…Not only the ones flagged with “Lead”! #SUPPORT

Right…Now what? Well, it’s time to drop a task into our worklist! For this we move into our ‘Case’ entity and open the ‘Lifecycle’ BB which is already in place. Here we make a small adjustment for only the first ‘Draft phase…(In the end of this post I’ll demo you a simple dispatch functionality!):

workqueue_022

So, that’s changing the transition type from ‘User event’ to ‘Activity Completion Event’. And we add a new activity which we assign to our work-queue name. Let’s do a publication on this change and create a new ‘Case’ in runtime…What can we expect? How about a task in our work-queue? Yes, please…

workqueue_023

You see it has the same kind of action buttons to claim, or assign it to someone. Just like we saw with the ‘Assignee’ BB on the case itself…Interesting!! 🤔

The only thing we miss is related case information when we open the task itself…Try it yourself; It will show an empty form! For the implementation on this task UI, we go back into design-time and into our ‘Case’ entity. All the task related details are found in the ‘Task list’ BB which was there all the time after the ‘Lifecycle’ BB was applied (could be you missed it!). Now, open this related ‘LifecycleTask’ entity overflow yourself with a new set of building blocks!

Let’s first create a new ‘Default’ form (of type ‘Autosave’). In this view you can make it as nice as you want, but as we are only interested in the ‘Case’ details, we simple miss-use the ‘Create’ form of our parent ‘Case’ entity!

workqueue_024

After a publication, you will see the task form is populated with case details. But how on earth? Well, the ‘Default’ form name is wisely chosen and will be used to view details when nothing is found. Normally I would do it slightly different as with a layout you are more flexible showing other panels as well, but that’s not for now. Have a look in the lifecycle as well where you can even select specific task-layouts in the properties of your activity (a task left over for you!):

workqueue_025

Reusing forms is a hard thing to remember! Trust me on this; When properly implemented, it will benefit for future stability.

The final question is about dashboarding? Well, let me show you a screenshot on my (below downloadable) implementation in runtime which includes eventually a task layout and a preview (just for a simple example):

workqueue_026

If you want to play hard ball you add new ‘Lists’ BBs on your LifecycleTask entity that provide the same type of information as we did on case level:

  • lst_all_tasks (all items; without filter)
  • lst_completed_tasks (items with filter Task.State == 'Completed')
  • lst_my_tasks (items with filter Task.TaskOwnerName == $(User.Properties.IdentityDisplayName)); At least, this is what I thought…It eventually became tsk_owner == $(User.Properties.IdentityDisplayName) which uses a “helper” property with a ‘Rule’ BB e_onchange_set_tsk_owner as a workaround! #SUPPORT as the Task.TaskOwnerName filter is not working as expected for some strange reason (do your investigation in the download at the end of this post)!
  • lst_overdue_tasks (items with filter Task.DueDate < $(now)); Keep in mind here to set the due-date on the activity in the lifecycle! For this I misuse the case_duration property; that’s fine for now, but this is for each single task! This one is also much easier than I thought…Now that I’m rethinking the case duration implementation (in the previous section), it could have been done easier with a simple due-date property!? Have a rethink yourself as well…I leave my solution is described in the post as there are always multiple paths to the city of Rome.
  • lst_priority_tasks (items with filter Task.Priority == '1')
  • lst_unassigned_tasks (items with filter tsk_owner == $('')); The same trick as lst_my_tasks, but with a little “smell” as “empty” is clearly something else (= NULL) then “no characters”!? Well, there is always a workaround to be found with a ‘Rule’ BB e_onchange_clear_tsk_owner
  • lst_private_tasks (items with filter Task.IsPrivateTask == '1')

Make sure that during the implementation of these lists you focus on task-related things! It’s really easy to show parent case details in these lists, but that’s exactly what we want to separate! This is also the reason you miss the list lst_high_tasks which define the “Hard” cases to work on, but remember…We don’t work on the case, but on the task (that’s the introduction of the lst_private_tasks)!! The only thing I struggled with is the creation of a task; We create a case first and get a task afterward…Well, we need to start somewhere! If anybody has an interesting though; Let me know in the comments!

With all these lists in place, we can also create a “Task reporting” homepage like this:

workqueue_027

I leave it with this post as a working solution so far. There is only one last question that followed me during writing this post…Can we automate the manual assigning of cases and tasks? Not only on creation (as that would be too easy), but when the current task is done; Can we than pick up the next one automagically! Well, that’s great input for next week…😁


Finalizing and new input

Download the zipped project here which already includes the optional auto assignment for cases/tasks (for next week) and some nice improvements to make it more interesting…Specially for you!

While clicking (and testing) my own craftsmanship, I did improvements on these features as well and doing further fine-tuning on business logic in the ‘Rule’ BBs:

Create cases with the “Create” menu on the homepage; Instead of creating them in the different lists (like in the screenshots in this post). Don’t jump in all direction, create instances at one location!

workqueue_028

A dispatch switch on the case to tell if the case should be managed task-related or case-related; Just to follow a full lifecycle flow for it. This switch also filters on the lists (for now), and we needed to make a nasty workaround on the ‘Lifecycle’ BB for valid primary transitions between the states. You can only have one, I do a parallel mode here, but you can have only one primary transition! Over time, it was a better decision to subtype the ‘Case’ to a ‘Task case’ managing the flag as an inherited lifecycle, but we’re already on the building path for this post. See it positive for a learning path on different transition types!

workqueue_029

To be clear; I would not recommend to do it like this (as it mixes case-related with task-related)…It’s just for the post to show the possibilities!

Adding an application configuration entity for global settings in ‘/app/admin’…For the auto assignment flag which we read via webservices (via the ‘Application Server Connector’ service container!)

workqueue_030

An assignment for you (during the weekend!); My tasks are all sent into the same queue currently!…Can you guess the assignment? Well, drop the correct task into the correct queue! So, not only New cases, but also Review cases, Final cases. AND…improve on the naming as New tasks might be better!? I leave the decision to you…Choices, choices! 😉


That’s a “DONE” for this post where we learned a lot about two different types of implementations for a solution. Now you also see the importance of making the decision to work case- or task-related upfront of your implementation; It has a big impact on the way a solution is implemented, and you directly see the difference in projects where this choice is never made. Keep a steady focus, don’t mix things…I see you next week when we continue the journey; Have a great weekend.

Don’t forget to subscribe to get updates on the activities happening on this site. Have you noticed the quiz where you find out if you are also “The AppWorks guy”?