Index: openacs-4/packages/workflow/www/doc/developer-guide.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/workflow/www/doc/developer-guide.html,v diff -u -r1.1.2.2 -r1.1.2.3 --- openacs-4/packages/workflow/www/doc/developer-guide.html 15 Apr 2003 16:55:54 -0000 1.1.2.2 +++ openacs-4/packages/workflow/www/doc/developer-guide.html 22 Apr 2003 17:15:03 -0000 1.1.2.3 @@ -18,10 +18,17 @@ th { background-color: #ffcccc; } + th.header { + background-color: #eeeeee; + color: black; + font-size: 125%; + padding: 8px; + } tr { background-color: white; } table { + font-size: 85%; margin-left: 24px; background-color: #999999; } @@ -134,6 +141,28 @@ +
+ As mentioned, workflow is designed to support workflows based on any + model, however the only model currently implemented is the finite + state machine. +
+ +
+ The workflow API is designed so that whenver you're using features
+ that are specific to finite state machines, the procedure name will
+ include the letters "fsm" in the name, as in
+ workflow::case::fsm::get
. That way you'll know when
+ you're hard-wiring a dependency on the particular workflow model.
+
+ It's considered good practice to only use non-fsm API calls, but in + practice, it can be hard to create good user experiences without. So + feel free. +
+Notation:@@ -331,6 +360,9 @@
+ +Workflow Attributes +@@ -402,6 +434,9 @@ Attribute Description
+ +Role Attributes +@@ -428,6 +463,9 @@ Attribute Description
+ +Examples of States +@@ -463,6 +501,9 @@ Application States
+ +State Attributes +@@ -547,6 +588,9 @@ Attribute Description
+ +Action Attributes +@@ -781,6 +825,9 @@ Attribute Description
+ +Service contracts +Service Contract Applies To Description @@ -793,7 +840,8 @@Used to get the default assignees for a role. Called for all roles when a case is started. Also called for roles with no - assignees, when that role is assigned to an action. + assignees, when that role is assigned to an action. Should return a + list of party_id's. @@ -804,7 +852,8 @@ Used when the users wants to reassign a role to populate a drop-down list of the most likely users/groups to assign this role - to. Should return less than 25 users/groups. + to. Should return less than 25 users/groups. Should return a + list of party_id's. @@ -817,6 +866,12 @@ new assignee for a role. Could typically be used to limit the search to members of a particular group, organizers of a particular event, etc. + + Should return a subquery ready to be + included in the from-clause of a query, which will be used when + querying for users, for example '(select * from parties where + ...)', (sub-selects must be in parenthesis), or simply + 'cc_users' or 'parties'. Defaults to 'cc_users'.
@@ -827,7 +882,14 @@ This is executed whenever the given action is executed. If specified for the workflow, it will be executed whenever any - action is executed on the workflow. + action is executed on the workflow. For details about how to use + this in conjunction with log entry data and format log title, + see below. + + Side-effects are executed after the application object has been + updated, after the workflow state has been changed, after the + log entry has been crated, and roles assigned, but before + notifications have been sent out.
@@ -839,6 +901,10 @@ Used to format the title of the case log. In bug-tracker, this is used to get the resolution code displayed in the case log as "Resolved (Fixed)" or "Resolved (Not Reproducable)". + + The implementation should return the text string that should go + into the parenthesis. The parenthesis are automatically added + if the returned string is non-empty.
@@ -849,29 +915,412 @@ Allows the application to supply information about the case object for the notification. + + + Should return the notification information as a 4-element list + containing: +
+
- url +
- one-line summary +
- details about the object in + the form of an array-list with label/value +
- tag for the notification subject (optional). If present, + it will be put inside brackets []. +
- $$$ service contract operations, input, output + All the service contracts have 3 operations each. The first two are + the same for all service contracts, and they really just act like + static variables:
++
++ +Common service contract operations ++ +Operation +Input +Output +Description ++ +GetObjectType ++ None + ++ object_type:string + ++ Get the object type for which this implementation is valid. If + your implementation is valid for any object, return + 'acs_object', otherwise return the object type. + ++ +GetPrettyName ++ None + ++ pretty_name:string + ++ Get the pretty name of this implementation. This will be used in + the user interface to let the workflow designer pick which + implementation to use. + +- $$$ linking implementations to object types. + The third operation is the one that does the real work. Here are the + inputs and outputs:
++
-+ +Specific service contract operations ++ +Contract +Operation +Input +Output ++ ++ Workflow.Role_DefaultAssignees + ++ GetAssignees + ++ case_id:integer +
+ object_id:integer
+ role_id:integer ++ party_ids:integer,multiple + ++ +Workflow.Role_AssigneePickList ++ GetPickList + ++ case_id:integer +
+ object_id:integer
+ role_id:integer ++ party_ids:integer,multiple + ++ +Workflow.Role_AssigneeSubQuery ++ GetSubquery + ++ case_id:integer +
+ object_id:integer
+ role_id:integer ++ subquery:string + ++ +Workflow.Action_SideEffect ++ DoSideEffect + ++ case_id:integer + object_id:integer + action_id:integer + entry_id:integer + ++ None + ++ +Workflow.ActivityLog_FormatTitle ++ GetTitle + ++ case_id:integer + object_id:integer + action_id:integer + entry_id:integer + data_arraylist:string,multiple + ++ title:string + ++ +Workflow.NotificationInfo ++ GetNotificationInfo + ++ case_id:integer + object_id:integer + ++ info:string,multiple + +Installing and Instantiating
++ For the most up-to-date information about the service contracts, + your safest bet is to refer to the user-visible pages of the + acs-service-contract package itself, which will let you view your + currently installed contracts and implementations. +
+Log Entry Data and Log Entry Titles
+ ++ One noteworthy thing that side-effects can be used for, is to + record information about a log entry for use later in displaying a + more detailed log entry title, or can be used to e.g. tie a workflow + log entry to a particular content repository revision, etc. +
+ ++ Using workflow::case::add_log_data, you can add arbitrary key/value + pairs to a log entry. These can the be retrieved later using + workflow::case::get_log_data_by_key, and workflow::case::get_log_data. +
+ + +Installing and Instantiating (APM Tcl Callbacks)
+ ++ Here are the workflow-related operations that you'll typically want + your application to do from the APM Tcl Callbacks: +
+ ++
+ +- after-install
+- +
+ ++
+- Register service contract implementations +
- Create default workflow (
workflow::fsm::new_from_spec
) +- before-uninstall
+- +
+ ++
+- Delete default workflow (
workflow::delete
) +- Unregister service contract implementations +
- before-upgrade
+- +
+ ++
+- Add new service contract implementations +
- Add new workflows +
- Make changes to existing default workflows (if the installed + verison is not modified) (this isn't yet supported on the workflow API) +
- after-instantiate
+- +
+ ++
+- + Clone default workflow to create a new workflow attached to + the instance (
+workflow::fsm::clone
) +- before-uninstantiate
+- +
++
+- + Delete the workflow attached to the instance (
+workflow::delete
) ++ To see what this could look like in practice, check out +
+ +packages/bug-tracker/tcl/install-procs.tcl
. +Integrating With Your Application's API
-Integrating With Your Application's User Interface
++ Newer applications will define a namespace for each of the objects + it defines, which will contain procs like "get", "new", "delete", + etc., to manipulate these objects. +
++ Given such a setup, here are the procs that you want to integrate + workflow into for your workflow-integrated objects. For a real-life + example, see
+ +packages/bug-tracker/tcl/bug-procs.tcl
and + search for "workflow::". ++
+ +- get
+- + In addition to your application's object data, you'll want to call +
+ +workflow::case::get_id
to get the case_id for your + object, and then eitherworkflow::case::get
or +workflow::case::fsm::get
in order to get state + information from workflow to include in the data set returned by + your API proc. +- new
+- + When creating a new object, you should also start a new workflow + case for that object using
+ +workflow::case::new
. +- edit
+- + Editing an object should only happen through a workflow action, if + you want to have a complete audit log (workflow case log). Thus, + your edit proc should take the following arguments, in addition to + the object_id and the array containing the object data: +
++ -action_id:required + -comment:required + -comment_format:required + {-entry_id {}} ++ (entry_id is for double-click protection). ++ First, you should update your application object data as normal. + Then you'll probably want to use +
workflow::case::get_id
to find the case_id. If you + have assignment integrated in your form, you'll want to call +workflow::case::role::assign
to pass these on to + workflow, and finally you'll say +workflow::case::action::execute
to execute the + action, including state changes, side-effects, and notifications. +Integrating With Your Application's User Interface
+ ++ Usually, you'll want one page that lists all the objects in your + package instance, and another that lets the user view/edit one + object, called the object form page. This section is about the + object form page, the next section is about the object listing page. +
+ ++ For a real-life example, look at +
+ +packages/bug-tracker/www/bug.tcl
. You may want to have + that handy while reading through this. ++ We're hoping to make some streamlining of both ad_form and workflow + to make this form page integration even easier at some point. But no promises. +
+ ++ Use
+ +workflow::case::get_id
to get the case_id. ++ If you want buttons along the bottom of the form like bug-tracker, + use the new 'action' feature of the form builder. What you do is + pass a list of possible actions to the form builder as a + list-of-lists with { label value }. These will be + displayed as buttons at the bottom of the form. +
+ ++ When one of these buttons are clicked, the form will be in + edit-mode, and you can use
+ +form get_action
to get the + value of the action chosen. ++ So up top, you'll want to ask the form if an action is in progress, + and which one it is, by saying
+ +set action_id [form get_action + form-id]
. If no action is in progress this will return + the empty string. ++ Then you should check that this action is currently available to + this user by saying +
+ +workflow::case::action::available_p
. ++ To get the currently available actions so you can offer them to the + user, use
+ +workflow::case::get_available_actions
which + will return the action_id's, thenworkflow::action::get
+ to get the details about each of the actions. ++ If you're using
+ +ad_form
, and you want only one assignee + per role, and you want assignment integrated with your form, use +workflow::case::role::add_assignee_widgets
to add the + widgets. It'll do anad_form -extend
, so they'll appear + at the point at which you call this proc. ++ To set the editable fields as defined for the action, do this: +
+ ++if { ![empty_string_p $action_id] } { + foreach field [workflow::action::get_element -action_id $action_id -element edit_fields] { + element set_properties bug $field -mode edit + } +} ++ ++ Similarly, on submit, you'll want to set the value of the editable fields. +
+ ++ To populate values of the assignee widgets, use +
+ +workflow::case::role::set_assignee_values
in your +on_request
block. ++ To add the case log to the comment field, use
+ + +workflow::case::get_activity_html
. +Integrating With Your Application's Queries
+
lars@pinds.com