Showing posts with label Actions. Show all posts
Showing posts with label Actions. Show all posts

Monday, 2 August 2010

The New Action Mechanism

With the release of xProcess v3.5 we have implemented a new way of collecting data through Actions:
http://sourceforge.net/apps/mediawiki/xprocess/index.php?title=Reporting (the Recursive Solution). Existing actions can still be used but those that have a tendency to generate large amounts of data may need to be rewritten in order to get the benefit of the new mechanism.

The following example reworks the Work Log for Person action.
In which ever Process you want to, create a new Action called 'Get DailyRecords for Person'. This will return a set of daily records in a date range and is the FetchSet Action.
The first difference we see in v3.5 is that there is a new Editor for Actions. The Editor is split into three tabs:
  • Editor tab – a text area for the OGNL Expression


  • Details Tab:


  • Action Name - the name of the action
  • Applicable to - What it is applicable to (any element is the default)
  • UI Action - should it appear on context menu for element its applicable to?
  • On this tab are a further two tabs; Parameters: add the Parameters that will be presented to the user when the Action is run. These parameter values are sent into the OGNL expression when run. We will come onto the Export tab later.
  • Test Action Tab:


  • On the Test Action Tab you can choose an Element to run the Action on to test it and enter the parameters for that action. It is recommended that you create test Elements for this, as the Action may change that Elements data.
  • The lower part of this tab shows the output when the test it run

For the 'Get DailyRecords for Person' we just need the OGNL for retrieving the daily records, so in the Actions Editor we enter in:
#project = projects.isEmpty() ? null : projects.iterator().next(),#from
= (#project != null) ? #project.getDayProperty("fromDateForReport") :
null,#to = (#project != null) ?
#project.getDayProperty("toDateForReport") : null,
#dailyrecords = getWorkLog(#from,#to,null)
Hit Ctrl+S to save the Action.
The next Action to create is the 'Generate Work Log Details'. This Action is the Subordinate Action. You can have one or more Subordinate Actions, and these Actions are run against the data set that the FetchSet Action returns. The OGNL to enter in this Actions Editor is:
#output = '"' +
day + '","' +
assignment.task.project.label + '","' +
assignment.task.label + '","' +
assignment.requiredResource.roleType.label + '","' +
time/60.0 + '","' +
logEntry + '","' +
confirmed + '"',
#output = #output + '\n',
#output
Hit Ctrl+S to save the Action.
The final Action is the 'New Work Log for Person'. It's OGNL gets called before the FetchSet and Subordinate Actions, so we use that to provide the column header that will be written to file:
#project = projects.isEmpty() ? null : projects.iterator().next(),#from
= (#project != null) ? #project.getDayProperty("fromDateForReport") :
null,#to = (#project != null) ?
#project.getDayProperty("toDateForReport") : null,
#output = 'Work Log for: ' + label + '\n'
+ 'From: ' + ((#from==null) ? 'earliest booked time in data source'
: #andfrom) + ' To: ' + ((#to==null) ? #$today : #to) +'\n'
+ 'Date,Project,Task,Role,Hours,Log Entry,Confirmed\n',
#output
Then go to the Details tab and:
  • Make the Action applicable to Person
  • Click on the Export tab and tick the Export Action checkbox. Give it a .csv extension
  • On the FetchSet Field click on the '…' and select the ' Get DailyRecords for Person' Action
  • Now click on the Add button in the Subordinate section, and select the ' Generate Work Log Details' Action
  • Hit Ctrl+S to save the Action
We can now test the Action via File | Export | xProcess Export | Custom Reports. When the Action runs it uses the FetchSet Action to retrieve a set of Daily Records on Projects for the selected Person. This Daily Record set is then iterated over passing in the Daily Records to the Subordinate Action.
Since each time a Daily Record is iterated over a line is written out to file, it prevents the building up of large data to be written out to file, and possible memory issues.

Tuesday, 17 March 2009

How to define a custom report in v3

There are 2 ways to generate a report on a project. One is to right-click on a project and select "Reports", and the other is to select from the File menu: File -> Menu -> Custom Reports and then select the type of report you want and its subject. For example using File->Export we can select a "Work Log" report for a person or a task.

What if the report we want isn't in the list? Can you write your own report template? Yes you can - that's what this article is about.

Let's say I want a report on a task in the project. I need to define an "Action" in the process I'm using, identify that action as an "Export Action" (checkbox in the Action dialog) and define the file extension for the report. Let's say in this case we want an html file. You can see in the screenshot this action being defined. Note that the "Applicable to:" field has been filled in as "Task" and also the "Expression:" field has been given the value "name". This won't be a terribly fascinating report but even so let's run it!

Use the File-> Export-> Custom Reports menu and select one of the tasks in your project as the subject of the report. Once you've supplied a filename and pressed "Finish" you should find that a browser is launched and a page generated containing the name of your task. Congratulations you've generated your first xProcess custom report!

So what about doing someting a bit more interesting. As you've probably guessed by now that will mean looking in a bit more detail at the "Expression" field. The script that goes in this field must be written in OGNL so you need to know a bit about that language - if you'd like to read the (quite small) reference manual click here - and a little bit about the xProcess Java API. (You'll also find the OGNL reference manual in the xProcess Help documentation.)

So let's try a slightly larger bit of OGNL to generate our task report. How about this:
'<h1>' + name + '</h1>' + '<br>' +
description + '<br>' +
'Start: ' + start + '<br>' +
'End: ' + end50 + '<br>' +
'Closed?: ' + closed

You could even turn this into a report on all tasks in your project. First change the "Applicable to:" field to "Project" (this will also mean you can invoke it by right-clicking on your project) and turn the above code into a subroutine that can be called for every task. Like this...

#taskReport = :[
#output = #output +
'<h1>' + name + '</h1>' + '<br>' +
description + '<br>' +
'Start: ' + start + '<br>' +
'End: ' + end50 + '<br>' +
'Closed?: ' + closed
],
#output = '',
allTasks.{#taskReport(#this)},
#output

Browse other Actions in the predefined processes to see other examples of using OGNL. Then if you make a report you think others will find useful - or if you need help with syntax or the API - post it to one of the xProcess Forums on SourceForge. See xProcessForums.

Monday, 15 September 2008

Running xProcess with a console

It seems I missed out a vital piece of information in the previous blog - how do you create a shortcut that runs xProcess with a console. Actually it's pretty simple: add "- console" to the target command. So on a Windows machine the Target field of the shortcut should look something like this...
"C:\Program Files\Ivis\xProcess 2\xProcess\xprocess.exe" -console

Friday, 12 September 2008

Reporting and exporting from xProcess 2.9

A project I've been working with recently has been needing to get reports and data out of xProcess to integrate with other management reports. This hasn't proved as easy as I would have hoped with the product's standard reports, custom reports through BIRT, exporting and other options failing to give us what we needed. I decided to do some more experimenting with "UI Actions", which use OGNL to navigate over the data. Turns out this is a pretty good option with writing the required scripts being quite straightforward. The hardest thing turned out to be actually getting the export file which was a bit more of a hassle. I'm told all this will be great in v3 but for now here's my solution.

First you need to create a new Action in your process, and set it applicable to "Task" (or whatever type of object you want to report on) and "UI Action to "true". The only other crucial bit in this stage is writing the OGNL Expression. My script is below so you can always paste that in, see what it does and then change it!

We wanted to extract a set of key attributes of tasks (like dates and size) and display them in a spreadsheet.The script produces a set of comma-separated values (csv format). Unfortunately v2.9 doesn't give you an easy way to save this in a file. Instead the script outputs the values to the console (so you have to start xProcess with a console window). Once the output has been produced you then have to cut and paste the data into a csv file -- yes that's the "clonky" bit. Still it doesn't take a moment and you then have the data in a spreadsheet where you can mess with it to your heart's content. Brill!

All I want now is v3 so I can get this sort of report through a nice clean user interface. Here's the script...
"-- Output to console action - summarises task information --",

#categoryName ='Importance',
#category = #this.getProcess().getCategoryTypeByName(#categoryName),

#output='\n\nTabular output for: ' + getName() +'\n'+
'Name,'+
'Parent Task,'+
'Start,'+
'End,'+
'Target End,'+
#categoryName + (#category==null ? ' (WARNING - no such category)' : '') +','+
'Size (points),'+
'Estimate (person-hours),'+
'Actual/Planned (person-hours),'+
'Actual to date (person-hours),'+
'Closed?,'+
'Assigned to' +
'\n',

"-- First define the different functions for Leaf and Parent tasks --",

#leafOutput = :[
#output = #output +
name +','+
parent.name +','+
start +','+
end50 +','+
(targetEnd==null ? '' : targetEnd) +','+
(#cat=getCategoryInType(#category), #cat ==null ? '' : #cat.label) +','+
size + ','+
estimateOfEffort/60.0 +','+
bookedTime/60.0 +','+
bookedTimeToDateIncludingConfirmedTimeToday/60.0 +','+
closed,
getCurrentManualAssignments().{#output = #output + ',' + person.label},
#output = #output + '\n'
],

#parentOutput = :[
#output = #output +
'REST OF ' + name +','+
(parent==null ? '' : parent.name) +','+
start +','+
end50 +','+
(targetEnd==null ? '' : targetEnd) +','+
(#cat=getCategoryInType(#deliveryCategory), #cat ==null ? '' : #cat.label) +','+
(topDown ? (#result = size - sizeRolledUpFromChildren, #result>0 ? #result : 0) : '') + ','+
(topDown ? (#effort = estimateOfEffort - estimateOfEffortRolledUpFromChildren, #effort>0 ? #effort/60.0 : 0) : '') + ','+
bookedTime/60.0 +','+
bookedTimeToDateIncludingConfirmedTimeToday/60.0 +','+
closed,
getCurrentManualAssignments().{#output = #output + ',' + person.label},
#output = #output + '\n'
],

"-- Then process all the tasks, including the one selected --",

#tasks = getAllTasks(),
#tasks.add(#this),
#tasks.{
#this.isDesignatedAsParent() ? #parentOutput(#this): #leafOutput(#this)
},
#$sysout.println(#output),

"-- Inform the user where the output is",

#$dialog.informUser('Output to console: ' + getName(), 'The result of this action has been sent to the console.\nCut and paste the output into a Spreadsheet and use Data->Text to Columns... to create the table.\n\n'+
'Note: If you do not have a visible console, close xProcess and restart it from a command line window, or run xProcess with a console by adding "- console" to the target command. (E.g. on a Windows machine the Target field of the shortcut should look something like:\n\n"C:\\Program Files\\Ivis\\xProcess 2\\xProcess\\xprocess.exe" -console')
Note: one of the columns this scripts outputs is a category value ("Importance"). You could use the same pattern to display other relevant categories - "Target Delivery" for example if this was a category defined in your data.

Wednesday, 6 February 2008

Set effort to match size

A previous entry provided the script required to define an action shortcut for setting the Size of tasks based on existing estimates for the effort required (see Set size to match effort). In some cases the inverse of this operation - Set effort to match size - is the useful operation. Here's the code you need for that one. Once again you should make it a "UI Action" by setting this field to True so that it appears on the right-click menu when you select a task or set of tasks.

Action Name: Set effort to match size
Expression:
#factor = getProject().getFloatProperty( "CurrentProductivity_pointsPerIdealPersonDay"),
#factor = (#factor < 0.01) ? 1.0 : #factor,
#size = getSize(),
setBest(#size/#factor*240.0),
setMostLikely(#size/#factor*480.0),
setWorst(#size/#factor*720.0)
Applicable to:
Task
UI Action:
True

Parameters: (none)

Note that the operation uses a factor to scale the mapping between size points and effort. If this factor is 1.0 the mapping is 8 hours effort (480 minutes) per size point.

Perhaps - like it's inverse operation, this will one day appear in the preconfigured operations of the Simple Process. Note that is very similar to the Set estimates action which is delivered in this process. However that operation is designed to take Size as a parameter (usually during the instantiation of a pattern) and so it is not suitable to make that one into a UI Action for operating directly on existing tasks.

Tuesday, 22 January 2008

Using parameters in task patterns

Processes are defined in xProcess through Patterns - patterns for sets of tasks, for projects, for priority groupings (e.g. Folders) and patterns for artifacts. By constructing sets of patterns, including patterns within patterns (Composite Tasks), a complete definition of the process behind a family of projects can be built up. A key part of pattern definition is the specification the pattern's parameters. This is what this article looks at.
The diagram above shows the editor for a typical pattern from the Simple Process, showing the 4 parameters that this pattern has: Name, Project Home Page, Start Date, Duration. These are the values that the user can supply when creating an instance of the pattern. Parameters always have default values which are used if the user does not change them, but you can add an action to a parameter - a DefaultValueGetter - which will set the default value at run time based on teh context or time at which the pattern is being instantiated. You can see in this case that Start Date has such an action attached which sets the start date to the current date. Parameters also have a type which can be one of: Integer, Floating Point, Boolean, String or Rich Text.

Having set up the parameters of your pattern you can then use these values to set values within the elements that are created by your pattern. Typically these will be projects, tasks and artifacts any or all which can be modified from the state of the prototype elements in the pattern to the real elements made when a user uses the pattern.

Th first way to use a parameter is by string substitution. Any text field in your prototypes, for example the prototype project's name, can include a parameter substitution. Simply enclose the parameter name with 'Simple Project pattern, the name of the prototype project is $Name$, showing that when the pattern is used the name of the project comes from this parameter. It's also used in the case of the Project Home Page parameter, which sets the description field to point to this url.

You can even use string substitution with artifacts, provided that the artifact uses a text-based, rather than binary format (e.g. rtf, xml, csv formats). In this case just put the substitution string, say $Name$ inside the file attached to your pattern. You'll find when you use the pattern that the corresponding artifact has this string substitution applied. Several patterns in the Basic FDD signs in the field, and when the pattern is instantiated the parameter value will appear at this point instead. You can see an example of this type of parameter use in nearly all the pre-defined patterns delivered with xProcess. In our example here, the Simple Project pattern, the name of the prototype project is $Name$, showing that when the pattern is used the name of the project comes from this parameter. It's also used in the case of the Project Home Page parameter, which sets the description field to point to this url.

You can even use string substitution with artifacts, provided that the artifact uses a text-based, rather than binary format (e.g. rtf, xml, csv formats). In this case just put the substitution string, say $Name$, inside the file attached to your pattern. You'll find when you use the pattern that the corresponding artifact has this string substitution applied. Several patterns in the Basic FDD process have artifacts that use this feature.

The second important way that parameters are used is in actions. As well as DefaultValueGetters, patterns have another very useful type of action - InstantiationActions. These actions are called when a pattern is used. When you define InstantiationActions you specify which of the prototype tasks you want to be transformed by the the action, and which particular action you wish to be called.
Here's the InstantiationAction used in the Simple Project pattern.It uses the Set project dates action which sets a number of dates (targets and scheduler dates) associated with the project. It is this code which ensures projects you create start on the date provided by the Start Date parameter. One thing to note about parameters appearing in OGNL code is that spaces in parameter names are replaced by underscores and non-alphanumeric codes are ignored. Also following OGNL conventions the parameter is preceded by a hash (#). Note that the Set project dates action uses both the Start Date and Duration parameters.

When you're starting to use parameters in your patterns the best approach is to look at patterns delivered with the pre-configured processes in xProcess and to re-use actions that these patterns use. The Simple Process for example provides the following actions that you can re-use in your own patterns:
  • Next timebox date (Project): finds the latest finishing folder/timebox and adds a day to its end date
  • Set required role type (Task): finds a RoleType matching the supplied string and sets this as the required role type for the task
  • Set target dates (Task): sets targets
  • Get today with offset: returns a date relative to the current date
  • Set max participants (Task): sets the number of people for a task
  • Set project dates (Project): sets target and schedule dates
  • Assign to account name (Task): searches for a matching user and assigns to the task
  • Get earliest start or end date (Task): returns either today or the task's project's scheduleStart if this is later
  • Set target dates and weight (Folder): sets the folder's targets and priority weighting based on that of preceding folders/timeboxes
  • Next timebox name (Project): finds the name of the latest finishing folder/timebox with the appropriate name and returns a name with its number incremented
  • Set estimates (Task): sets three-point estimates based on Size
  • Set importance (Task): categorizes task into High, Medium or Low categories.
Note: there are also some UI Actions in the set of actions supplied by the Simple Process. See for example this article: Set size to match effort.

Thursday, 15 November 2007

Searching the blog by topic

Blogspot offers some useful facilities for finding blog entries by topic. Below most entries there are a series of labels. Clicking on any of these will bring up other related articles on the same topic. Try it our with the labels below this post.

Wednesday, 5 September 2007

The Simple Process... or is it?

The Simple Process in xProcess is the first one you are likely to use. It contains basic patterns for a project, a task a timebox and so on, and it also has some useful actions in there that can be used in your own patterns or even exposed as "User Actions" so they can be called on your projects.

The Simple Process has several elements that you cannot delete as for example xProcess assumes that even if no other Role Types exist (such as Project Manager, Developer, Tester and so on) at the very least the Participant role type will exist. When you define your own process it's likely that you will inherit Simple Process patterns (though you can hide them by defining your own hidden patterns with the same name. So it's definitely worth taking a snoop at all the elements in there. You might even want to cut and paste some bits into your own processes and modify their behaviour.

Wednesday, 20 June 2007

Set size to match effort

I explained in another entry that size and effort are distinct metrics for tasks. However it's useful to keep the overhead of estimating two closely related items to an absolute minimum. This is why the patterns in the "Simple Process" uses the user's input of a size metric (in "ideal days") to automatically complete the effort estimates (usually displayed in person-hours or person-days). They can be changed subsequently though and if you want to re-synchronize them at some point - say when you a re baselining a plan - a utility for doing so is useful.

Here's a simple Action that you can define in your process (make it a "UI Action" by setting this field to True).

Action Name: Set size to match effort
Expression: setSize(getEffortIncludingChildren()/480.0)
Applicable to: Task
UI Action: True
Parameters: (none)

Having done this you can expand your task hierarchy in the explorer, select the tasks you wish to set size on, and then right-click and select UI Action -> Set size to match effort .

Note: From version 2.9 of xProcess this action is included in the Simple Process.