From 1011f0e946141225906350ae2143db367180d6f2 Mon Sep 17 00:00:00 2001
From: Tim Steiner <tsteiner2@unl.edu>
Date: Tue, 17 Mar 2009 16:31:17 +0000
Subject: [PATCH] Completed implementation of approval chain manager.

---
 .../ApprovalActionCollegeRouterModel.php      |  72 +++++
 .../ApprovalActionDepartmentRouterModel.php   |  72 +++++
 .../ApprovalActionMakeOfficialModel.php       |  72 +++++
 .../ApprovalActionSubjectRouterModel.php      |  72 +++++
 .../edit-action/collegeRouter.phtml           |   1 +
 .../edit-action/departmentRouter.phtml        |   1 +
 .../edit-action/makeOfficial.phtml            |   1 +
 .../edit-action/subjectRouter.phtml           |   1 +
 application/modules/cron/models/JobsModel.php |  13 +-
 .../ApprovalChainManagerController.php        | 143 ++++++++--
 .../models/ApprovalActionAutoModel.php        | 103 +++++++
 .../models/ApprovalActionDelegateModel.php    |  99 +++++++
 .../requests/models/ApprovalActionModel.php   | 267 +++++++++++++++++-
 .../models/ApprovalActionQueueModel.php       | 203 +++++++++++++
 .../models/ApprovalActionRestartModel.php     |  72 +++++
 .../models/ApprovalActionSendToChainModel.php | 115 +++++++-
 .../ApprovalActionSingleApproverModel.php     |  93 ++++++
 .../ApprovalActionSubmitterApprovalModel.php  |  72 +++++
 .../models/ApprovalActionVoteModel.php        | 127 +++++++++
 .../models/ApprovalActionWatchersModel.php    |  98 +++++++
 .../requests/models/ApprovalRoleModel.php     |   2 +-
 .../edit-action/auto.phtml                    |  12 +
 .../edit-action/delegate.phtml                |  15 +
 .../edit-action/queue.phtml                   |  48 ++++
 .../edit-action/restart.phtml                 |   0
 .../edit-action/sendToChain.phtml             |  12 +
 .../edit-action/singleApprover.phtml          |   0
 .../edit-action/submitterApproval.phtml       |   0
 .../edit-action/vote.phtml                    |  18 ++
 .../edit-action/watchers.phtml                |  12 +
 .../approval-chain-manager/edit-actions.phtml |  63 +++++
 .../approval-chain-manager/edit-links.phtml   |  95 +++++++
 .../approval-chain-manager/index.phtml        | 105 +------
 .../css/requests/approval-chain-manager.css   |   7 +-
 .../requests/approval-chain-manager.js        |  55 +++-
 35 files changed, 2007 insertions(+), 134 deletions(-)
 create mode 100644 application/modules/courses/views/scripts/approval-chain-manager/edit-action/collegeRouter.phtml
 create mode 100644 application/modules/courses/views/scripts/approval-chain-manager/edit-action/departmentRouter.phtml
 create mode 100644 application/modules/courses/views/scripts/approval-chain-manager/edit-action/makeOfficial.phtml
 create mode 100644 application/modules/courses/views/scripts/approval-chain-manager/edit-action/subjectRouter.phtml
 create mode 100644 application/modules/requests/views/scripts/approval-chain-manager/edit-action/auto.phtml
 create mode 100644 application/modules/requests/views/scripts/approval-chain-manager/edit-action/delegate.phtml
 create mode 100644 application/modules/requests/views/scripts/approval-chain-manager/edit-action/queue.phtml
 create mode 100644 application/modules/requests/views/scripts/approval-chain-manager/edit-action/restart.phtml
 create mode 100644 application/modules/requests/views/scripts/approval-chain-manager/edit-action/sendToChain.phtml
 create mode 100644 application/modules/requests/views/scripts/approval-chain-manager/edit-action/singleApprover.phtml
 create mode 100644 application/modules/requests/views/scripts/approval-chain-manager/edit-action/submitterApproval.phtml
 create mode 100644 application/modules/requests/views/scripts/approval-chain-manager/edit-action/vote.phtml
 create mode 100644 application/modules/requests/views/scripts/approval-chain-manager/edit-action/watchers.phtml
 create mode 100644 application/modules/requests/views/scripts/approval-chain-manager/edit-actions.phtml
 create mode 100644 application/modules/requests/views/scripts/approval-chain-manager/edit-links.phtml

diff --git a/application/modules/courses/models/ApprovalActionCollegeRouterModel.php b/application/modules/courses/models/ApprovalActionCollegeRouterModel.php
index 30033e60..5f3647e8 100644
--- a/application/modules/courses/models/ApprovalActionCollegeRouterModel.php
+++ b/application/modules/courses/models/ApprovalActionCollegeRouterModel.php
@@ -32,6 +32,73 @@ class Courses_ApprovalActionCollegeRouterModel extends Requests_ApprovalActionMo
         }
 
     }
+    
+    static public function fetchNew()
+    {
+        $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+            'participatingRoles'  => array(),
+            'editingRoles'        => array()
+        );
+        
+        $new = new self($data);
+        $new->_setClean();
+        
+        $new->_data['className'] = 'ApprovalActionCollegeRouter';
+        
+        return $new;
+    }
+
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        // Nothing to update
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsCollegeRouter (approvalActionId) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?) ', $model->_data['approvalActionId']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
 
     public function consider($requests)
     {
@@ -55,6 +122,11 @@ class Courses_ApprovalActionCollegeRouterModel extends Requests_ApprovalActionMo
         // Don't do anything here, this is an automated action.
     }
 
+    public function setExtendedData($in)
+    {
+        // No extended data
+    }
+
     public function getResultStatusStrings()
     {
     	$colleges = array();
diff --git a/application/modules/courses/models/ApprovalActionDepartmentRouterModel.php b/application/modules/courses/models/ApprovalActionDepartmentRouterModel.php
index 3ce90c47..22e013d0 100644
--- a/application/modules/courses/models/ApprovalActionDepartmentRouterModel.php
+++ b/application/modules/courses/models/ApprovalActionDepartmentRouterModel.php
@@ -32,6 +32,73 @@ class Courses_ApprovalActionDepartmentRouterModel extends Requests_ApprovalActio
         }
 
     }
+    
+    static public function fetchNew()
+    {
+        $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+            'participatingRoles'  => array(),
+            'editingRoles'        => array()
+        );
+        
+        $new = new self($data);
+        $new->_setClean();
+        
+        $new->_data['className'] = 'ApprovalActionDepartmentRouter';
+        
+        return $new;
+    }
+
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        // Nothing to update
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsDepartmentRouter (approvalActionId) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?) ', $model->_data['approvalActionId']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
 
     public function consider($requests)
     {
@@ -55,6 +122,11 @@ class Courses_ApprovalActionDepartmentRouterModel extends Requests_ApprovalActio
         // Don't do anything here, this is an automated action.
     }
 
+    public function setExtendedData($in)
+    {
+        // No extended data
+    }
+
     public function getResultStatusStrings()
     {
         if (count($this->_departments) == 0) {
diff --git a/application/modules/courses/models/ApprovalActionMakeOfficialModel.php b/application/modules/courses/models/ApprovalActionMakeOfficialModel.php
index 0b1f241f..ae54d884 100644
--- a/application/modules/courses/models/ApprovalActionMakeOfficialModel.php
+++ b/application/modules/courses/models/ApprovalActionMakeOfficialModel.php
@@ -29,6 +29,73 @@ class Courses_ApprovalActionMakeOfficialModel extends Requests_ApprovalActionMod
             return array_pop($objects);
         }
 	}
+    
+    static public function fetchNew()
+    {
+        $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+            'participatingRoles'  => array(),
+            'editingRoles'        => array()
+        );
+        
+        $new = new self($data);
+        $new->_setClean();
+        
+        $new->_data['className'] = 'ApprovalActionMakeOfficial';
+        
+        return $new;
+    }
+
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        // Nothing to update
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsMakeOfficial (approvalActionId) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?) ', $model->_data['approvalActionId']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
 
     public function consider($requests)
     {
@@ -42,6 +109,11 @@ class Courses_ApprovalActionMakeOfficialModel extends Requests_ApprovalActionMod
         return $requests;
     }
 
+    public function setExtendedData($in)
+    {
+        // No extended data
+    }
+
     public function userMadeDecisions($requests, $requestDecisions)
     {
         // Don't do anything here, this is an automated action.
diff --git a/application/modules/courses/models/ApprovalActionSubjectRouterModel.php b/application/modules/courses/models/ApprovalActionSubjectRouterModel.php
index ab70ac9c..67cdf9ba 100644
--- a/application/modules/courses/models/ApprovalActionSubjectRouterModel.php
+++ b/application/modules/courses/models/ApprovalActionSubjectRouterModel.php
@@ -32,6 +32,73 @@ class Courses_ApprovalActionSubjectRouterModel extends Requests_ApprovalActionMo
         }
 
     }
+    
+    static public function fetchNew()
+    {
+        $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+            'participatingRoles'  => array(),
+            'editingRoles'        => array()
+        );
+        
+        $new = new self($data);
+        $new->_setClean();
+        
+        $new->_data['className'] = 'ApprovalActionSubjectRouter';
+        
+        return $new;
+    }
+
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        // Nothing to update
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsSubjectRouter (approvalActionId) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?) ', $model->_data['approvalActionId']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
 
     public function consider($requests)
     {
@@ -55,6 +122,11 @@ class Courses_ApprovalActionSubjectRouterModel extends Requests_ApprovalActionMo
         // Don't do anything here, this is an automated action.
     }
 
+    public function setExtendedData($in)
+    {
+        // No extended data
+    }
+
     public function getResultStatusStrings()
     {
         if (count($this->_subjects) == 0) {
diff --git a/application/modules/courses/views/scripts/approval-chain-manager/edit-action/collegeRouter.phtml b/application/modules/courses/views/scripts/approval-chain-manager/edit-action/collegeRouter.phtml
new file mode 100644
index 00000000..f0bcdf3e
--- /dev/null
+++ b/application/modules/courses/views/scripts/approval-chain-manager/edit-action/collegeRouter.phtml
@@ -0,0 +1 @@
+<!-- No options for this action -->
\ No newline at end of file
diff --git a/application/modules/courses/views/scripts/approval-chain-manager/edit-action/departmentRouter.phtml b/application/modules/courses/views/scripts/approval-chain-manager/edit-action/departmentRouter.phtml
new file mode 100644
index 00000000..0821c914
--- /dev/null
+++ b/application/modules/courses/views/scripts/approval-chain-manager/edit-action/departmentRouter.phtml
@@ -0,0 +1 @@
+<!-- No options for this action -->
diff --git a/application/modules/courses/views/scripts/approval-chain-manager/edit-action/makeOfficial.phtml b/application/modules/courses/views/scripts/approval-chain-manager/edit-action/makeOfficial.phtml
new file mode 100644
index 00000000..0821c914
--- /dev/null
+++ b/application/modules/courses/views/scripts/approval-chain-manager/edit-action/makeOfficial.phtml
@@ -0,0 +1 @@
+<!-- No options for this action -->
diff --git a/application/modules/courses/views/scripts/approval-chain-manager/edit-action/subjectRouter.phtml b/application/modules/courses/views/scripts/approval-chain-manager/edit-action/subjectRouter.phtml
new file mode 100644
index 00000000..0821c914
--- /dev/null
+++ b/application/modules/courses/views/scripts/approval-chain-manager/edit-action/subjectRouter.phtml
@@ -0,0 +1 @@
+<!-- No options for this action -->
diff --git a/application/modules/cron/models/JobsModel.php b/application/modules/cron/models/JobsModel.php
index d9874f6f..8667d7b4 100644
--- a/application/modules/cron/models/JobsModel.php
+++ b/application/modules/cron/models/JobsModel.php
@@ -34,6 +34,11 @@ class Cron_JobsModel extends Unl_Model
         }
     }
     
+    /**
+     * Returns a new Cron_JobsModel
+     *
+     * @return Cron_JobsModel
+     */
     static public function fetchNew()
     {
         $data = array(
@@ -184,7 +189,13 @@ class Cron_JobsModel extends Unl_Model
                         . $db->quoteInto('?)'  , $model->_data['arguments']);
         }
         $sql .= implode(', ', $sqlParts);
-        $db->query($sql);
+        try {
+            $db->query($sql);
+        } catch (Zend_Db_Statement_Exception $e) {
+            if (strpos($e->getMessage(), 'Duplicate entry') === FALSE) {
+                throw $e;
+            }
+        }
 
         $lastId = $db->lastInsertId();
         foreach ($models as $model) {
diff --git a/application/modules/requests/controllers/ApprovalChainManagerController.php b/application/modules/requests/controllers/ApprovalChainManagerController.php
index 7765648f..52ee96a6 100644
--- a/application/modules/requests/controllers/ApprovalChainManagerController.php
+++ b/application/modules/requests/controllers/ApprovalChainManagerController.php
@@ -5,28 +5,7 @@ class Requests_ApprovalChainManagerController extends App_Controller_Action
     public function indexAction()
     {
         $in = $this->getRequest()->getParams();
-        $approvalChains = Requests_ApprovalChainModel::findAll();
-
-        $approvalChain = null;
-        if ($id = $in['id']) {
-            $approvalChain = Requests_ApprovalChainModel::find($id);
-            $user = Auth_UserModel::findCurrentUser();
-            $userGroups = Auth_GroupModel::findByUser($user);
-            $approvalBodies = Requests_ApprovalBodyModel::findWithAdminGroups($userGroups);
-            $bodies = new Unl_Model_Collection('Requests_ApprovalBodyModel');
-            foreach ($approvalBodies as $approvalBody) {
-                $bodies->merge($approvalBody);
-            }
-
-            $approvalLinks = Requests_ApprovalLinkModel::findForApprovalChains($approvalChain);
-            $approvalActions = Requests_ApprovalActionModel::findForApprovalChains($approvalChain);
-        }
-
-        $this->view->approvalChains = $approvalChains;
-        $this->view->approvalChain = $approvalChain;
-        $this->view->approvalBodies = $bodies;
-        $this->view->approvalLinks = $approvalLinks;
-        $this->view->approvalActions = $approvalActions;
+        $this->_loadViewWithChainData($in['id']);
     }
 
     public function getActionDetailXmlAction()
@@ -130,4 +109,122 @@ class Requests_ApprovalChainManagerController extends App_Controller_Action
         $this->_redirect('/requests/approval-chain-manager/index/id/' . $in['approvalChain']);
     }
 
-}
\ No newline at end of file
+    public function addActionPostAction()
+    {
+        $in = $this->_getAllParams();
+        
+        $approvalChain = Requests_ApprovalChainModel::find($in['id']);
+        $actionClass = $in['type'];
+        
+        if (!class_exists($actionClass)) {
+            exit;
+        }
+        
+        if ($actionClass instanceof Requests_ApprovalActionModel) {
+            exit;
+        }
+        
+        $new = call_user_func(array($actionClass, 'fetchNew'));
+        $new->setName($in['name']);
+        $new->setApprovalChain($approvalChain);
+        $new->setParticipatingRoleIds($in['participatingRoles']);
+        $new->setEditingRoleIds($in['editingRoles']);
+        
+        $new->setExtendedData($in);
+        
+        Requests_ApprovalActionModel::save($new);
+        
+        $this->_redirect('/requests/approval-chain-manager/index/id/' . $approvalChain->getId());
+    }
+    
+    public function editActionsPostAction()
+    {
+        $in = $this->_getAllParams();
+        
+        $approvalChain = Requests_ApprovalChainModel::find($in['id']);
+        
+        $actionIds = array_keys($in['edit']);
+        $approvalActions = Requests_ApprovalActionModel::find($actionIds);
+        
+        foreach ($in['edit'] as $actionId => $data) {
+            $approvalAction = $approvalActions[$actionId];
+            $approvalAction->setName($data['name']);
+            $approvalAction->setParticipatingRoleIds($data['participatingRoles']);
+            $approvalAction->setEditingRoleIds($data['editingRoles']);
+            $approvalAction->setExtendedData($data);
+        }
+        
+        Requests_ApprovalActionModel::save($approvalActions);
+        
+        $this->_redirect('/requests/approval-chain-manager/index/id/' . $approvalChain->getId());
+    }
+    
+    public function getActionEditXhtmlAction()
+    {
+        $this->_loadViewWithChainData($this->_getParam('chain-id'));
+        $actionClass = $this->_getParam('action-class');
+        
+        if (!class_exists($actionClass)) {
+            exit;
+        }
+        
+        if ($actionClass instanceof Requests_ApprovalActionModel) {
+            exit;
+        }
+        
+        $action = call_user_func(array($actionClass, 'fetchNew'));
+        $xhtml = $action->getEditXhtml($this->view);
+        
+        header('Content-type: application/xhtml+xml');
+        echo '<?xml version="1.0" standalone="yes"?>' . "\n";
+        echo '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">' . "\n";
+        echo '<html xmlns="http://www.w3.org/1999/xhtml"><body>' . "\n";
+        echo $xhtml;
+        echo '</body></html>' . "\n";
+        
+        exit;
+    }
+    
+    protected function _loadViewWithChainData($chainId)
+    {
+        $approvalChains = Requests_ApprovalChainModel::findAll();
+
+        $approvalChain = null;
+        if ($chainId) {
+            $approvalChain = Requests_ApprovalChainModel::find($chainId);
+            $user = Auth_UserModel::findCurrentUser();
+            $userGroups = Auth_GroupModel::findByUser($user);
+            $approvalBodies = Requests_ApprovalBodyModel::findWithAdminGroups($userGroups);
+            $bodies = new Unl_Model_Collection('Requests_ApprovalBodyModel');
+            foreach ($approvalBodies as $approvalBody) {
+                $bodies->merge($approvalBody);
+            }
+
+            $approvalLinks = Requests_ApprovalLinkModel::findForApprovalChains($approvalChain);
+            $approvalActions = Requests_ApprovalActionModel::findForApprovalChains($approvalChain);
+            
+            $approvalActionClasses = Requests_ApprovalActionModel::getApprovalActionModelClasses();
+            
+            $approvalTypes = array();
+            foreach ($approvalActionClasses as $className => $fullClassName) {
+                $approvalTypes[$fullClassName] = substr($className, 14);
+            }
+            $this->view->approvalTypes = $approvalTypes;
+            
+            $ownerBody = Requests_ApprovalBodyModel::find($approvalChain->getOwnerBody());
+            
+            $approvalRoles = Requests_ApprovalRoleModel::findByParentBody($ownerBody);
+            $approvalRolesArray = array();
+            foreach ($approvalRoles as $approvalRole) {
+                $approvalRolesArray[$approvalRole->getId()] = $approvalRole->getName();
+            }
+            $this->view->approvalRoles = $approvalRolesArray;
+        }
+        
+        $this->view->approvalChains = $approvalChains;
+        $this->view->approvalChain = $approvalChain;
+        $this->view->approvalBodies = $bodies;
+        $this->view->approvalLinks = $approvalLinks;
+        $this->view->approvalActions = $approvalActions;
+    }
+}
diff --git a/application/modules/requests/models/ApprovalActionAutoModel.php b/application/modules/requests/models/ApprovalActionAutoModel.php
index 23a52c54..3fc85eeb 100644
--- a/application/modules/requests/models/ApprovalActionAutoModel.php
+++ b/application/modules/requests/models/ApprovalActionAutoModel.php
@@ -29,7 +29,95 @@ class Requests_ApprovalActionAutoModel extends Requests_ApprovalActionModel
             return array_pop($objects);
         }
 	}
+	
+	static public function fetchNew()
+	{
+	    $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+	        'participatingRoles'  => array(),
+	        'editingRoles'        => array(),
+            'result'              => ''
+	    );
+	    
+	    $new = new self($data);
+	    $new->_setClean();
+	    
+	    $new->_data['className'] = 'ApprovalActionAuto';
+	    
+	    return $new;
+	}
+
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'CREATE TEMPORARY TABLE creqApprovalActionsAutoUpdate '
+             . 'SELECT * FROM creqApprovalActionsAuto LIMIT 0';
+        $db->query($sql);
 
+        $sql = 'INSERT INTO creqApprovalActionsAutoUpdate VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?) ',  $model->_data['result']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+
+        $sql = 'UPDATE creqApprovalActionsAuto AS a, '
+             . '       creqApprovalActionsAutoUpdate AS b '
+             . 'SET a.result = b.result '
+             . 'WHERE a.approvalActionId = b.approvalActionId ';
+        $db->query($sql);
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsAuto (approvalActionId, result) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?)'  , $model->_data['result']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
+	
     public function consider($requests)
     {
         foreach ($requests as $request) {
@@ -49,4 +137,19 @@ class Requests_ApprovalActionAutoModel extends Requests_ApprovalActionModel
     {
         return $this->_data['result'];
     }
+
+    public function setExtendedData($in)
+    {
+        $this->setResult($in['result']);
+    }
+    
+    public function getResult()
+    {
+        return $this->_data['result'];
+    }
+    
+    public function setResult($result)
+    {
+        $this->_data['result'] = $result;
+    }
 }
diff --git a/application/modules/requests/models/ApprovalActionDelegateModel.php b/application/modules/requests/models/ApprovalActionDelegateModel.php
index c769e3df..35c0f94e 100644
--- a/application/modules/requests/models/ApprovalActionDelegateModel.php
+++ b/application/modules/requests/models/ApprovalActionDelegateModel.php
@@ -32,6 +32,94 @@ class Requests_ApprovalActionDelegateModel extends Requests_ApprovalActionModel
         }
 
     }
+    
+    static public function fetchNew()
+    {
+        $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+            'participatingRoles'  => array(),
+            'editingRoles'        => array(),
+            'delegateBody'        => ''
+        );
+        
+        $new = new self($data);
+        $new->_setClean();
+        
+        $new->_data['className'] = 'ApprovalActionDelegate';
+        
+        return $new;
+    }
+
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'CREATE TEMPORARY TABLE creqApprovalActionsDelegateUpdate '
+             . 'SELECT * FROM creqApprovalActionsDelegate LIMIT 0';
+        $db->query($sql);
+
+        $sql = 'INSERT INTO creqApprovalActionsDelegateUpdate VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?) ',  $model->_data['delegateBody']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+
+        $sql = 'UPDATE creqApprovalActionsDelegate AS a, '
+             . '       creqApprovalActionsDelegateUpdate AS b '
+             . 'SET a.delegateBody = b.delegateBody '
+             . 'WHERE a.approvalActionId = b.approvalActionId ';
+        $db->query($sql);
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsDelegate (approvalActionId, delegateBody) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?)'  , $model->_data['delegateBody']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
 
     public function consider($requests)
     {
@@ -60,6 +148,12 @@ class Requests_ApprovalActionDelegateModel extends Requests_ApprovalActionModel
     {
         // Don't do anything here, this is an automated action.
     }
+
+    public function setExtendedData($in)
+    {
+        $this->_data['delegateBody'] = ($in['delegateBody']);
+    }
+    
     protected function _getTargetChainForType($type)
     {
         $targetChainMap = $this->_getTargetChainMap();
@@ -89,4 +183,9 @@ class Requests_ApprovalActionDelegateModel extends Requests_ApprovalActionModel
     {
         return $this->_data['approvalActionId'];
     }
+    
+    public function getDelegateBody()
+    {
+        return $this->_data['delegateBody'];
+    }
 }
diff --git a/application/modules/requests/models/ApprovalActionModel.php b/application/modules/requests/models/ApprovalActionModel.php
index a677956c..81bff885 100644
--- a/application/modules/requests/models/ApprovalActionModel.php
+++ b/application/modules/requests/models/ApprovalActionModel.php
@@ -92,7 +92,30 @@ class Requests_ApprovalActionModel extends Unl_Model
         foreach ($records as $record) {
             $objects[$record['approvalActionId']]->_data['options'][$record['approvalActionsOptionId']] = $record['name'];
         }
+        
+        $select = new Zend_Db_Select($db);
+        $select->from(array('p' => 'creqApprovalActionParticipants'));
+	    if (Unl_Util::isArray($id)) {
+            $select->where('p.approvalAction IN (?)', $id);
+        } else {
+            $select->where('p.approvalAction = ?', $id);
+        }
+        $records = $select->query()->fetchAll();
+        foreach ($objects as $object) {
+            $object->_data['participatingRoles'] = array();
+            $object->_data['editingRoles'] = array();
+        }
+        foreach ($records as $record) {
+            $objects[$record['approvalAction']]->_data['participatingRoles'][] = $record['approvalBodyRole'];
+            if ($record['canEdit'] == 'yes') {
+                $objects[$record['approvalAction']]->_data['editingRoles'][] = $record['approvalBodyRole'];
+            }
+        }
 
+        foreach ($objects as $object) {
+            $object->_setClean();
+        }
+        
         if (Unl_Util::isArray($id)) {
             return $objects;
         } else {
@@ -287,6 +310,198 @@ class Requests_ApprovalActionModel extends Unl_Model
         }
     }
 
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+        
+        
+        $participatingRolesToAdd = array();
+        $participatingRolesToDelete = array();
+        $editingRolesToAdd = array();
+        $editingRolesToDelete = array();
+        foreach ($models as $model) {
+            $participatingRolesToAdd[$model->getId()] = array_diff($model->_data['participatingRoles'], $model->_cleanData['participatingRoles']);
+            $participatingRolesToDelete[$model->getId()] = array_diff($model->_cleanData['participatingRoles'], $model->_data['participatingRoles']);
+            $editingRolesToAdd[$model->getId()] = array_diff($model->_data['editingRoles'], $model->_cleanData['editingRoles']);
+            $editingRolesToDelete[$model->getId()] = array_diff($model->_cleanData['editingRoles'], $model->_data['editingRoles']);
+        }
+        self::_addParticipatingRoles($participatingRolesToAdd);
+        self::_deleteParticipatingRoles($participatingRolesToDelete);
+        self::_addEditingRoles($editingRolesToAdd);
+        self::_deleteEditingRoles($editingRolesToDelete);
+
+
+        $modelsByClass = array();
+        foreach ($models as $model) {
+            $modelClass = get_class($model);
+            $modelsByClass[$modelClass][] = $model;
+        }
+        
+        foreach ($modelsByClass as $modelClass => $modelsToSave) {
+            call_user_func(array($modelClass, 'save'), $modelsToSave);
+        }
+        
+        
+        foreach ($models as $model)
+        {
+            $model->_setClean();
+        }
+    }
+    
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'CREATE TEMPORARY TABLE creqApprovalActionsUpdate '
+             . 'SELECT * FROM creqApprovalActions LIMIT 0';
+        $db->query($sql);
+
+        $sql = 'INSERT INTO creqApprovalActionsUpdate VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?, ' , $model->_data['name'])
+                        . $db->quoteInto('?, ' , $model->_data['approvalChain'])
+                        . $db->quoteInto('?)'  , $model->_data['className']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+
+        $sql = 'UPDATE creqApprovalActions AS a, '
+             . '       creqApprovalActionsUpdate AS b '
+             . 'SET a.name          = b.name, '
+             . '    a.approvalChain = b.approvalChain, '
+             . '    a.className     = b.className '
+             . 'WHERE a.approvalActionId = b.approvalActionId ';
+        $db->query($sql);
+        
+        $db->query('DROP TABLE creqApprovalActionsUpdate');
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActions (name, approvalChain, className) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['name'])
+                        . $db->quoteInto('?, ' , $model->_data['approvalChain'])
+                        . $db->quoteInto('?)'  , $model->_data['className']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+        
+        $lastId = $db->lastInsertId();
+        foreach ($models as $model) {
+            $model->_data['approvalActionId'] = $lastId;
+            $lastId++;
+        }
+    }
+    
+    static protected function _addParticipatingRoles($data)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionParticipants (approvalAction, approvalBodyRole, canEdit) VALUES ';
+        $sqlParts = array();
+        foreach ($data as $actionId => $roleIds) {
+            foreach ($roleIds as $roleId) {
+                $sqlParts[] = $db->quoteInto('(?, ', $actionId)
+                            . $db->quoteInto('?, ' , $roleId)
+                            . $db->quoteInto('?)'  , 'no');
+            }
+        }
+        if (count($sqlParts) == 0) {
+            return;
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
+    
+    static protected function _deleteParticipatingRoles($data)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'DELETE FROM creqApprovalActionParticipants '
+             . 'WHERE (approvalAction, approvalBodyRole) IN (';
+        $sqlParts = array('(-1, -1)');
+        foreach ($data as $actionId => $roleIds) {
+            foreach ($roleIds as $roleId) {
+                $sqlParts[] = $db->quoteInto('(?, ', $actionId)
+                            . $db->quoteInto('?)'  , $roleId);
+            }
+        }
+        $sql .= implode(', ', $sqlParts) . ')';
+        $db->query($sql);
+    }
+
+    static protected function _addEditingRoles($data)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'UPDATE creqApprovalActionParticipants '
+             . "SET canEdit = 'yes' "
+             . 'WHERE (approvalAction, approvalBodyRole) IN (';
+        $sqlParts = array('(-1, -1)');
+        foreach ($data as $actionId => $roleIds) {
+            foreach ($roleIds as $roleId) {
+                $sqlParts[] = $db->quoteInto('(?, ', $actionId)
+                            . $db->quoteInto('?)'  , $roleId);
+            }
+        }
+        $sql .= implode(', ', $sqlParts) . ')';
+        $db->query($sql);
+    }
+    
+    static protected function _deleteEditingRoles($data)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'UPDATE creqApprovalActionParticipants '
+             . "SET canEdit = 'no'"
+             . 'WHERE (approvalAction, approvalBodyRole) IN (';
+        $sqlParts = array('(-1, -1)');
+        foreach ($data as $actionId => $roleIds) {
+            foreach ($roleIds as $roleId) {
+                $sqlParts[] = $db->quoteInto('(?, ', $actionId)
+                            . $db->quoteInto('?)'  , $roleId);
+            }
+        }
+        $sql .= implode(', ', $sqlParts) . ')';
+        $db->query($sql);
+    }
+    
+    static public function getDefaultStatusStrings()
+    {
+        return array('Approve' => 'Approve', 'Resubmit' => 'Resubmit');
+    }
+    
     public function getId()
     {
     	return $this->_data['approvalActionId'];
@@ -297,11 +512,11 @@ class Requests_ApprovalActionModel extends Unl_Model
     	return $this->_data['name'];
     }
 
-    static public function getDefaultStatusStrings()
+    public function setName($name)
     {
-        return array('Approve' => 'Approve', 'Resubmit' => 'Resubmit');
+        $this->_data['name'] = $name;
     }
-
+    
     public function getResultStatusStrings()
     {
         if (Unl_Util::isArray($this->_data['options'])) {
@@ -325,5 +540,51 @@ class Requests_ApprovalActionModel extends Unl_Model
     {
         return $this->_data['approvalChain'];
     }
+    
+    public function setApprovalChain(Requests_ApprovalChainModel $approvalChain)
+    {
+        $this->_data['approvalChain'] = $approvalChain->getId();
+    }
+    
+    public function getParticipatingRoleIds()
+    {
+        return $this->_data['participatingRoles'];
+    }
+    
+    public function setParticipatingRoleIds($roleIds)
+    {
+        if (!$roleIds) {
+            $roleIds = array();
+        }
+        $this->_data['participatingRoles'] = $roleIds;
+    }
+    
+    public function getEditingRoleIds()
+    {
+        return $this->_data['editingRoles'];
+    }
+    
+    public function setEditingRoleIds($roleIds)
+    {
+        if (!$roleIds) {
+            $roleIds = array();
+        }
+        $this->_data['editingRoles'] = $roleIds;
+    }
+    
+    public function getEditXhtml(Zend_View $view)
+    {
+        $className = get_class($this);
+        $className = explode('_', $className);
+        $moduleName = strtolower(array_shift($className));
+        $actionName = substr(implode('_', $className), 14, -5);
+        $actionName[0] = strtolower($actionName[0]);
+        
+        $helpers = $view->getHelpers();
+        $view->setBasePath(APPLICATION_DIR . '/modules/' . $moduleName . '/views');
+        $view->addHelperPath(APPLICATION_DIR . '/../library/Unl/View/Helper', 'Unl_View_Helper');
+        $view->approvalAction = $this;
+        return $view->render('approval-chain-manager/edit-action/' . $actionName . '.phtml');
+    }
 }
 
diff --git a/application/modules/requests/models/ApprovalActionQueueModel.php b/application/modules/requests/models/ApprovalActionQueueModel.php
index 3c2b8557..b0bb67c8 100644
--- a/application/modules/requests/models/ApprovalActionQueueModel.php
+++ b/application/modules/requests/models/ApprovalActionQueueModel.php
@@ -18,10 +18,26 @@ class Requests_ApprovalActionQueueModel extends Requests_ApprovalActionModel
         $records = $db->query($select)->fetchAll();
         $objects = new Unl_Model_Collection(__CLASS__);
         foreach ($records as $record) {
+            $record['dates'] = array();
             $object = Unl_Model_Registry::getInstance()->getOrAdd(new self($record));
             $objectId = $object->getId();
             $objects[$objectId] = $object;
         }
+        
+        $select = new Zend_Db_Select($db);
+        $select->from(array('d' => 'creqApprovalActionsQueueDates'));
+        if (Unl_Util::isArray($id)) {
+            $select->where('d.approvalAction IN(?)', $id);
+        } else {
+            $select->where('d.approvalAction = ?', $id);
+        }
+        $records = $db->query($select)->fetchAll();
+        
+        foreach ($records as $record) {
+            $objectId = $record['approvalAction'];
+            $date = $record['date'];
+            $objects[$objectId]->_data['dates'][] = new Zend_Date($date); 
+        }
 
         if (Unl_Util::isArray($objects)) {
             return $objects;
@@ -29,7 +45,156 @@ class Requests_ApprovalActionQueueModel extends Requests_ApprovalActionModel
             return array_pop($objects);
         }
     }
+    
+    static public function fetchNew()
+    {
+        $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+            'participatingRoles'  => array(),
+            'editingRoles'        => array(),
+            'canChangeVote'       => NULL,
+            'dates'               => array()
+        );
+        
+        $new = new self($data);
+        $new->_setClean();
+        
+        $new->_data['className'] = 'ApprovalActionQueue';
+        
+        return $new;
+    }
+
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+        
+        
+        $datesToInsert = array();
+        $datesToDelete = array();
+        foreach ($models as $model) {
+            $datesToInsert[$model->getId()] = array_diff($model->_data['dates'], $model->_cleanData['dates']);
+            $datesToDelete[$model->getId()] = array_diff($model->_cleanData['dates'], $model->_data['dates']);
+        }
+        
+        self::_insertDates($datesToInsert);
+        self::_deleteDates($datesToDelete);
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'CREATE TEMPORARY TABLE creqApprovalActionsQueueUpdate '
+             . 'SELECT * FROM creqApprovalActionsQueue LIMIT 0';
+        $db->query($sql);
+
+        $sql = 'INSERT INTO creqApprovalActionsQueueUpdate VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?)'  , $model->_data['canChangeVote']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+
+        $sql = 'UPDATE creqApprovalActionsQueue AS a, '
+             . '       creqApprovalActionsQueueUpdate AS b '
+             . 'SET a.canChangeVote = b.canChangeVote '
+             . 'WHERE a.approvalActionId = b.approvalActionId ';
+        $db->query($sql);
+        
+        $db->query('DROP TABLE creqApprovalActionsQueueUpdate');
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsQueue (approvalActionId, canChangeVote) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?)'  , $model->_data['canChangeVote']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
+    
+    static protected function _insertDates(array $models)
+    {
+        $db = Zend_Registry::get('db');
 
+        $sql = 'INSERT INTO creqApprovalActionsQueueDates (approvalAction, date) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $approvalActionId => $dates) {
+            foreach ($dates as $date) {
+                $sqlParts[] = $db->quoteInto('(?, ', $approvalActionId)
+                            . $db->quoteInto('?)'  , $date->getTimestamp());
+            }
+        }
+        if (count($sqlParts) == 0) {
+            return;
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+        
+        $jobs = new Unl_Model_Collection('Cron_JobsModel');
+        foreach ($models as $approvalActionId => $dates) {
+            foreach ($dates as $date) {
+                $job = Cron_JobsModel::fetchNew();
+                $job->setDate($date);
+                $job->setClass(__CLASS__);
+                $job->setMethod('advanceQueues');
+                $jobs[] = $job;
+            }
+        }
+        Cron_JobsModel::save($jobs);
+    }
+     
+    static protected function _deleteDates(array $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'DELETE FROM creqApprovalActionsQueueDates WHERE (approvalAction, date) IN (';
+        $sqlParts = array('(-1, -1)');
+        foreach ($models as $approvalActionId => $dates) {
+            foreach ($dates as $date) {
+                $sqlParts[] = $db->quoteInto('(?, ', $approvalActionId)
+                            . $db->quoteInto('?)'  , $date->getTimestamp());
+            }
+        }
+        $sql .= implode(', ', $sqlParts) . ')';
+        $db->query($sql);
+    }
+    
     static public function advanceQueues()
     {
         $db = Zend_Registry::get('db');
@@ -116,5 +281,43 @@ class Requests_ApprovalActionQueueModel extends Requests_ApprovalActionModel
     {
         return (bool) ($this->_data['canChangeVote'] == 'yes');
     }
+    
+    public function getDates()
+    {
+        return $this->_data['dates'];
+    }
+    
+    public function setDates($dates)
+    {
+        foreach ($dates as $date) {
+            if (!($date instanceof Zend_Date)) {
+                throw new Zend_Exception('Each date must be a Zend_Date object.');
+            }
+        }
+        $this->_data['dates'] = $dates;
+    }
+    
+    public function setExtendedData($data)
+    {
+        $this->_data['canChangeVote'] = $data['canChangeVote'];
+        
+        $dates = array();
+        foreach ($data['schedule'] as $dateParts) {
+            if ($dateParts['delete']) {
+                continue;
+            }
+            $date = new Zend_Date();
+            $date->setYear($dateParts['year']);
+            $date->setMonth($dateParts['month']);
+            $date->setDay($dateParts['day']);
+            $date->setHour($dateParts['hour']);
+            $date->setMinute($dateParts['minute']);
+            $date->setSecond(0);
+            
+            $dates[] = $date;
+        }
+        
+        $this->setDates($dates);
+    }
 }
 
diff --git a/application/modules/requests/models/ApprovalActionRestartModel.php b/application/modules/requests/models/ApprovalActionRestartModel.php
index d8b3182b..4b47a3a5 100644
--- a/application/modules/requests/models/ApprovalActionRestartModel.php
+++ b/application/modules/requests/models/ApprovalActionRestartModel.php
@@ -29,6 +29,73 @@ class Requests_ApprovalActionRestartModel extends Requests_ApprovalActionModel
             return array_pop($objects);
         }
     }
+    
+    static public function fetchNew()
+    {
+        $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+            'participatingRoles'  => array(),
+            'editingRoles'        => array()
+        );
+        
+        $new = new self($data);
+        $new->_setClean();
+        
+        $new->_data['className'] = 'ApprovalActionRestart';
+        
+        return $new;
+    }
+
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        // nothing to update
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsRestart (approvalActionId) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?) ', $model->_data['approvalActionId']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
 
     public function consider($requests)
     {
@@ -39,5 +106,10 @@ class Requests_ApprovalActionRestartModel extends Requests_ApprovalActionModel
 
         return $requests;
     }
+
+    public function setExtendedData($in)
+    {
+        // No extended Data
+    }
 }
 
diff --git a/application/modules/requests/models/ApprovalActionSendToChainModel.php b/application/modules/requests/models/ApprovalActionSendToChainModel.php
index f1ed72f4..88788f5f 100644
--- a/application/modules/requests/models/ApprovalActionSendToChainModel.php
+++ b/application/modules/requests/models/ApprovalActionSendToChainModel.php
@@ -22,7 +22,8 @@ class Requests_ApprovalActionSendToChainModel extends Requests_ApprovalActionMod
             $objectId = $object->getId();
             $objects[$objectId] = $object;
         }
-
+        
+        
         if (Unl_Util::isArray($objects)) {
             return $objects;
         } else {
@@ -30,6 +31,94 @@ class Requests_ApprovalActionSendToChainModel extends Requests_ApprovalActionMod
         }
 
     }
+    
+    static public function fetchNew()
+    {
+        $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+            'participatingRoles'  => array(),
+            'editingRoles'        => array(),
+            'targetChain'         => NULL
+        );
+        
+        $new = new self($data);
+        $new->_setClean();
+        
+        $new->_data['className'] = 'ApprovalActionSendToChain';
+        
+        return $new;
+    }
+
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'CREATE TEMPORARY TABLE creqApprovalActionsSendToChainUpdate '
+             . 'SELECT * FROM creqApprovalActionsSendToChain LIMIT 0';
+        $db->query($sql);
+
+        $sql = 'INSERT INTO creqApprovalActionsSendToChainUpdate VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?) ',  $model->_data['targetChain']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+
+        $sql = 'UPDATE creqApprovalActionsSendToChain AS a, '
+             . '       creqApprovalActionsSendToChainUpdate AS b '
+             . 'SET a.targetChain = b.targetChain '
+             . 'WHERE a.approvalActionId = b.approvalActionId ';
+        $db->query($sql);
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsSendToChain (approvalActionId, targetChain) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?)'  , $model->_data['targetChain']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
 
     public function consider($requests)
     {
@@ -58,8 +147,32 @@ class Requests_ApprovalActionSendToChainModel extends Requests_ApprovalActionMod
         // Don't do anything here, this is an automated action.
     }
 
+    public function setExtendedData($in)
+    {
+        $this->_data['targetChain'] = $in['targetChain'];
+    }
+
     public function getTargetChain()
     {
         return $this->_data['targetChain'];
     }
+    
+    static public function getPossibleChains(Requests_ApprovalChainModel $chain)
+    {
+        $db = Zend_Registry::get('db');
+        
+        $select = new Zend_Db_Select($db);
+        $select->from(array('c1' => 'creqApprovalChains'), array());
+        $select->join(array('c2' => 'creqApprovalChains'), 'c1.ownerBody = c2.ownerBody', array('approvalChainId', 'name'));
+        $select->where('c1.approvalChainId != c2.approvalChainId');
+        $select->where('c1.approvalChainId = ?', $chain->getId());
+        
+        $records = $db->query($select)->fetchAll();
+        $possibleChains = array();
+        foreach ($records as $record) {
+            $possibleChains[$record['approvalChainId']] = $record['name']; 
+        }
+        
+        return $possibleChains;
+    }
 }
diff --git a/application/modules/requests/models/ApprovalActionSingleApproverModel.php b/application/modules/requests/models/ApprovalActionSingleApproverModel.php
index 750693c4..c2e0b2fe 100644
--- a/application/modules/requests/models/ApprovalActionSingleApproverModel.php
+++ b/application/modules/requests/models/ApprovalActionSingleApproverModel.php
@@ -29,7 +29,95 @@ class Requests_ApprovalActionSingleApproverModel extends Requests_ApprovalAction
             return array_pop($objects);
         }
     }
+    
+    static public function fetchNew()
+    {
+        $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+            'participatingRoles'  => array(),
+            'editingRoles'        => array()
+        );
+        
+        $new = new self($data);
+        $new->_setClean();
+        
+        $new->_data['className'] = 'ApprovalActionSingleApprover';
+        
+        return $new;
+    }
+    
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
 
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        /* Nothing to update... alter if this ever changes
+        $db = Zend_Registry::get('db');
+
+        $sql = 'CREATE TEMPORARY TABLE creqApprovalActionsSingleApproverUpdate '
+             . 'SELECT * FROM creqApprovalActionsSingleApprover LIMIT 0';
+        $db->query($sql);
+
+        $sql = 'INSERT INTO creqApprovalActionsSingleApproverUpdate VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?) ',  $model->_data['result']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+
+        $sql = 'UPDATE creqApprovalActionsSingleApprover AS a, '
+             . '       creqApprovalActionsSingleApproverUpdate AS b '
+             . 'SET a.result = b.result '
+             . 'WHERE a.approvalActionId = b.approvalActionId ';
+        $db->query($sql);
+        */
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsSingleApprover (approvalActionId) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?) ', $model->_data['approvalActionId']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
+    
     public function consider($requests)
     {
         return new Unl_Model_Collection('Requests_RequestModel');
@@ -44,5 +132,10 @@ class Requests_ApprovalActionSingleApproverModel extends Requests_ApprovalAction
         Requests_ApprovalChainModel::advance($requests);
         return $requests;
     }
+    
+    public function setExtendedData($data)
+    {
+        //Nothing to set yet
+    }
 }
 
diff --git a/application/modules/requests/models/ApprovalActionSubmitterApprovalModel.php b/application/modules/requests/models/ApprovalActionSubmitterApprovalModel.php
index 8a22d37e..4934bb19 100644
--- a/application/modules/requests/models/ApprovalActionSubmitterApprovalModel.php
+++ b/application/modules/requests/models/ApprovalActionSubmitterApprovalModel.php
@@ -29,6 +29,73 @@ class Requests_ApprovalActionSubmitterApprovalModel extends Requests_ApprovalAct
             return array_pop($objects);
         }
     }
+    
+    static public function fetchNew()
+    {
+        $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+            'participatingRoles'  => array(),
+            'editingRoles'        => array()
+        );
+        
+        $new = new self($data);
+        $new->_setClean();
+        
+        $new->_data['className'] = 'ApprovalActionSubmitterApproval';
+        
+        return $new;
+    }
+
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        // Nothing to update
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsSubmitterApproval (approvalActionId) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?) ', $model->_data['approvalActionId']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
 
     public function consider($requests)
     {
@@ -49,6 +116,11 @@ class Requests_ApprovalActionSubmitterApprovalModel extends Requests_ApprovalAct
         Requests_RequestModel::save($requests);
         Requests_ApprovalChainModel::advance($requests);
     }
+
+    public function setExtendedData($in)
+    {
+        // No extended data
+    }
     
     public function getResultStatusStrings()
     {
diff --git a/application/modules/requests/models/ApprovalActionVoteModel.php b/application/modules/requests/models/ApprovalActionVoteModel.php
index b80afb70..637c20a0 100644
--- a/application/modules/requests/models/ApprovalActionVoteModel.php
+++ b/application/modules/requests/models/ApprovalActionVoteModel.php
@@ -19,6 +19,7 @@ class Requests_ApprovalActionVoteModel extends Requests_ApprovalActionQueueModel
         $records = $db->query($select)->fetchAll();
         $objects = new Unl_Model_Collection(__CLASS__);
         foreach ($records as $record) {
+            $record['dates'] = array();
             $object = Unl_Model_Registry::getInstance()->getOrAdd(new self($record));
             $objectId = $object->getId();
             $objects[$objectId] = $object;
@@ -36,6 +37,21 @@ class Requests_ApprovalActionVoteModel extends Requests_ApprovalActionQueueModel
             $objects[$record['approvalAction']]->_data['votes'][$record['request']][$record['approverVoteId']] = $record;
         }
 
+        $select = new Zend_Db_Select($db);
+        $select->from(array('d' => 'creqApprovalActionsQueueDates'));
+        if (Unl_Util::isArray($id)) {
+            $select->where('d.approvalAction IN(?)', $id);
+        } else {
+            $select->where('d.approvalAction = ?', $id);
+        }
+        $records = $db->query($select)->fetchAll();
+        
+        foreach ($records as $record) {
+            $objectId = $record['approvalAction'];
+            $date = $record['date'];
+            $objects[$objectId]->_data['dates'][] = new Zend_Date($date); 
+        }
+        
         if (Unl_Util::isArray($objects)) {
             return $objects;
         } else {
@@ -43,11 +59,117 @@ class Requests_ApprovalActionVoteModel extends Requests_ApprovalActionQueueModel
         }
 
     }
+    
+    static public function fetchNew()
+    {
+        $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+            'participatingRoles'  => array(),
+            'editingRoles'        => array(),
+            'canChangeVote'       => NULL,
+            'quorum'              => NULL,
+            'requiredVotes'       => NULL,
+            'dates'               => array()
+        );
+        
+        $new = new self($data);
+        $new->_setClean();
+        
+        $new->_data['className'] = 'ApprovalActionVote';
+        
+        return $new;
+    }
+
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+        
+        parent::save($models);
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'CREATE TEMPORARY TABLE creqApprovalActionsVoteUpdate '
+             . 'SELECT * FROM creqApprovalActionsVote LIMIT 0';
+        $db->query($sql);
+
+        $sql = 'INSERT INTO creqApprovalActionsVoteUpdate VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?,'  , $model->_data['quorum'])
+                        . $db->quoteInto('?)'  , $model->_data['requiredVotes']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+
+        $sql = 'UPDATE creqApprovalActionsVote AS a, '
+             . '       creqApprovalActionsVoteUpdate AS b '
+             . 'SET a.quorum        = b.quorum, '
+             . '    a.requiredVotes = b.requiredVotes '
+             . 'WHERE a.approvalActionId = b.approvalActionId ';
+        $db->query($sql);
+        
+        $db->query('DROP TABLE creqApprovalActionsVoteUpdate');
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsVote (approvalActionId, quorum, requiredVotes) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?,'  , $model->_data['quorum'])
+                        . $db->quoteInto('?)'  , $model->_data['requiredVotes']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
 
     public function consider($requests)
     {
         return new Unl_Model_Collection('Requests_RequestModel');
     }
+    
+    public function setExtendedData($data)
+    {
+        $this->_data['quorum'] = $data['quorum'];
+        $this->_data['requiredVotes'] = $data['requiredVotes'];
+        
+        parent::setExtendedData($data);
+    }
 
     public function finalize($requests)
     {
@@ -126,4 +248,9 @@ class Requests_ApprovalActionVoteModel extends Requests_ApprovalActionQueueModel
     {
         return $this->_data['quorum'];
     }
+    
+    public function getRequiredVotes()
+    {
+        return $this->_data['requiredVotes'];
+    }
 }
diff --git a/application/modules/requests/models/ApprovalActionWatchersModel.php b/application/modules/requests/models/ApprovalActionWatchersModel.php
index b4845616..a26304cb 100644
--- a/application/modules/requests/models/ApprovalActionWatchersModel.php
+++ b/application/modules/requests/models/ApprovalActionWatchersModel.php
@@ -29,6 +29,94 @@ class Requests_ApprovalActionWatchersModel extends Requests_ApprovalActionModel
             return array_pop($objects);
         }
     }
+    
+    static public function fetchNew()
+    {
+        $data = array(
+            'approvalActionId'    => NULL,
+            'name'                => '',
+            'approvalChain'       => NULL,
+            'className'           => '',
+            'participatingRoles'  => array(),
+            'editingRoles'        => array(),
+            'watchingRole'        => NULL
+        );
+        
+        $new = new self($data);
+        $new->_setClean();
+        
+        $new->_data['className'] = 'ApprovalActionWatchers';
+        
+        return $new;
+    }
+
+    static public function save($models)
+    {
+        $modelsToInsert = new Unl_Model_Collection(__CLASS__);
+        $modelsToUpdate = new Unl_Model_Collection(__CLASS__);
+
+        if (!Unl_Util::isArray($models)) {
+            $model = $models;
+            $models = new Unl_Model_Collection(__CLASS__);
+            $models[$model->getId()] = $model;
+        }
+
+        foreach ($models as $model) {
+            if ($model->_cleanData['approvalActionId'] && $model->getId()) {
+                if ($model->_cleanData != $model->_data) {
+                    $modelsToUpdate[] = $model;
+                }
+            } else {
+                $modelsToInsert[] = $model;
+            }
+        }
+
+        if (count($modelsToInsert) > 0) {
+            self::_insert($modelsToInsert);
+        }
+
+        if (count($modelsToUpdate) > 0) {
+            self::_update($modelsToUpdate);
+        }
+    }
+
+    static protected function _update(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'CREATE TEMPORARY TABLE creqApprovalActionsWatchersUpdate '
+             . 'SELECT * FROM creqApprovalActionsWatchers LIMIT 0';
+        $db->query($sql);
+
+        $sql = 'INSERT INTO creqApprovalActionsWatchersUpdate VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?) ',  $model->_data['watchingRole']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+
+        $sql = 'UPDATE creqApprovalActionsWatchers AS a, '
+             . '       creqApprovalActionsWatchersUpdate AS b '
+             . 'SET a.watchingRole = b.watchingRole '
+             . 'WHERE a.approvalActionId = b.approvalActionId ';
+        $db->query($sql);
+    }
+
+    static protected function _insert(Unl_Model_Collection $models)
+    {
+        $db = Zend_Registry::get('db');
+
+        $sql = 'INSERT INTO creqApprovalActionsWatchers (approvalActionId, watchingRole) VALUES ';
+        $sqlParts = array();
+        foreach ($models as $model) {
+            $sqlParts[] = $db->quoteInto('(?, ', $model->_data['approvalActionId'])
+                        . $db->quoteInto('?)'  , $model->_data['watchingRole']);
+        }
+        $sql .= implode(', ', $sqlParts);
+        $db->query($sql);
+    }
 
     public function consider($requests)
     {
@@ -59,4 +147,14 @@ class Requests_ApprovalActionWatchersModel extends Requests_ApprovalActionModel
     {
         //
     }
+
+    public function setExtendedData($in)
+    {
+        $this->_data['watchingRole'] = $in['watchingRole'];
+    }
+    
+    public function getWatchingRole()
+    {
+        return $this->_data['watchingRole'];
+    }
 }
\ No newline at end of file
diff --git a/application/modules/requests/models/ApprovalRoleModel.php b/application/modules/requests/models/ApprovalRoleModel.php
index ba879f80..4275bc84 100644
--- a/application/modules/requests/models/ApprovalRoleModel.php
+++ b/application/modules/requests/models/ApprovalRoleModel.php
@@ -129,7 +129,7 @@ class Requests_ApprovalRoleModel extends Unl_Model
         }
     }
     
-    public function findByParentBody($parentBody)
+    static public function findByParentBody($parentBody)
     {
         $db = Zend_Registry::get('db');
 
diff --git a/application/modules/requests/views/scripts/approval-chain-manager/edit-action/auto.phtml b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/auto.phtml
new file mode 100644
index 00000000..830be18f
--- /dev/null
+++ b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/auto.phtml
@@ -0,0 +1,12 @@
+<?php 
+if ($this->approvalAction->getId()) {
+    $prefix = 'edit[' . $this->approvalAction->getId() . '][';
+    $postifx = ']';
+}
+?>
+
+Automatically Select:<br />
+<?php echo $this->formSelect($prefix . 'result' . $postifx,
+                             $this->approvalAction->getResult(),
+                             null,
+                             array('' => '--Select--', 'Approve' => 'Approve', 'Resubmit' => 'Resubmit')); ?>
diff --git a/application/modules/requests/views/scripts/approval-chain-manager/edit-action/delegate.phtml b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/delegate.phtml
new file mode 100644
index 00000000..7e43fc6d
--- /dev/null
+++ b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/delegate.phtml
@@ -0,0 +1,15 @@
+<?php 
+if ($this->approvalAction->getId()) {
+    $prefix = 'edit[' . $this->approvalAction->getId() . '][';
+    $postifx = ']';
+}
+?>
+
+Approval Body to Delegate To:<br />
+<?php
+
+$this->approvalBodies->orderBy('getName');
+echo $this->formSelect($prefix . 'delegateBody' . $postifx,
+                       $this->approvalAction->getDelegateBody(),
+                       null,
+                       array('' => '--Select--') + $this->approvalBodies->arrayFromMethod('getName')); ?>
diff --git a/application/modules/requests/views/scripts/approval-chain-manager/edit-action/queue.phtml b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/queue.phtml
new file mode 100644
index 00000000..2332800e
--- /dev/null
+++ b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/queue.phtml
@@ -0,0 +1,48 @@
+<?php 
+if ($this->approvalAction->getId()) {
+    $prefix = 'edit[' . $this->approvalAction->getId() . '][';
+    $postfix = ']';
+}
+?>
+
+<div>
+Can Change Vote:
+<?php echo $this->formCheckbox($prefix . 'canChangeVote'. $postfix, ($this->approvalAction->getCanChangeVote() ? 'yes' : 'no'), null, array('yes', 'no')); ?>
+</div>
+
+<table>
+    <tr>
+        <th>Year</th>
+        <th>Month</th>
+        <th>Day</th>
+        <th colspan="2">Time</th>
+    </tr>
+    <?php foreach ($this->approvalAction->getDates() as $date) { $i++; ?>
+    <tr>
+        <td><?php echo $this->formSelectYear($prefix . 'schedule' . $postfix . '[' . $i . '][year]',
+                                             $date->get(Zend_Date::YEAR)); ?></td>
+        <td><?php echo $this->formSelectMonth($prefix . 'schedule' . $postfix . '[' . $i . '][month]',
+                                              $date->get(Zend_Date::MONTH)); ?></td>
+        <td><?php echo $this->formSelectDay($prefix . 'schedule' . $postfix . '[' . $i . '][day]',
+                                            $date->get(Zend_Date::DAY)); ?></td>
+        <td><?php echo $this->formSelectHour($prefix . 'schedule' . $postfix . '[' . $i . '][hour]',
+                                             $date->get(Zend_Date::HOUR)); ?></td>
+        <td><?php echo $this->formSelectMinute($prefix . 'schedule' . $postfix . '[' . $i . '][minute]',
+                                               $date->get(Zend_Date::MINUTE)); ?></td>
+        <td><?php echo $this->formCheckbox($prefix . 'schedule' . $postfix . '[' . $i . '][delete]'); ?></td>
+    </tr>
+    <?php } ?>
+    <tr class="hidden_new_record">
+        <td> <?php echo $this->formSelectYear($prefix . 'schedule' . $postfix . '[__key__][year]', null, array('disabled' => 'disabled')); ?> </td>
+        <td> <?php echo $this->formSelectMonth($prefix . 'schedule' . $postfix . '[__key__][month]', null, array('disabled' => 'disabled')); ?> </td>
+        <td> <?php echo $this->formSelectDay($prefix . 'schedule' . $postfix . '[__key__][day]', null, array('disabled' => 'disabled')); ?> </td>
+        <td> <?php echo $this->formSelectHour($prefix . 'schedule' . $postfix . '[__key__][hour]', null, array('disabled' => 'disabled')); ?> </td>
+        <td> <?php echo $this->formSelectMinute($prefix . 'schedule' . $postfix . '[__key__][minute]', null, array('disabled' => 'disabled')); ?> </td>
+        <td> <a href="#" class="remove_record_button">-</a> </td>
+    </tr>
+    <tr>
+        <td colspan="4">
+            <a href="#" class="add_record_button">Add Scheduled Advance</a>
+        </td>
+    </tr>
+</table>
diff --git a/application/modules/requests/views/scripts/approval-chain-manager/edit-action/restart.phtml b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/restart.phtml
new file mode 100644
index 00000000..e69de29b
diff --git a/application/modules/requests/views/scripts/approval-chain-manager/edit-action/sendToChain.phtml b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/sendToChain.phtml
new file mode 100644
index 00000000..909c1bed
--- /dev/null
+++ b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/sendToChain.phtml
@@ -0,0 +1,12 @@
+<?php 
+if ($this->approvalAction->getId()) {
+    $prefix = 'edit[' . $this->approvalAction->getId() . '][';
+    $postifx = ']';
+}
+?>
+
+Target Chain:<br />
+<?php echo $this->formSelect($prefix . 'targetChain' . $postifx,
+                             $this->approvalAction->getTargetChain(),
+                             null,
+                             array('' => '--Select--') + Requests_ApprovalActionSendToChainModel::getPossibleChains($this->approvalChain)); ?>
diff --git a/application/modules/requests/views/scripts/approval-chain-manager/edit-action/singleApprover.phtml b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/singleApprover.phtml
new file mode 100644
index 00000000..e69de29b
diff --git a/application/modules/requests/views/scripts/approval-chain-manager/edit-action/submitterApproval.phtml b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/submitterApproval.phtml
new file mode 100644
index 00000000..e69de29b
diff --git a/application/modules/requests/views/scripts/approval-chain-manager/edit-action/vote.phtml b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/vote.phtml
new file mode 100644
index 00000000..2c0ab03b
--- /dev/null
+++ b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/vote.phtml
@@ -0,0 +1,18 @@
+<?php 
+if ($this->approvalAction->getId()) {
+    $prefix = 'edit[' . $this->approvalAction->getId() . '][';
+    $postfix = ']';
+}
+?>
+
+Quorum:<br />
+<?php echo $this->formText($prefix . 'quorum' . $postfix, $this->approvalAction->getQuorum()); ?><br />
+
+Required Vote Margin:
+<?php echo $this->formSelect($prefix . 'requiredVotes' . $postfix,
+                             $this->approvalAction->getRequiredVotes(),
+                             null,
+                             array('' => '--Select--', 'plurality' => 'Plurality', 'majority' => 'Majority', 'unanimity' => 'Unanimity')); ?>
+
+
+<?php echo $this->partial('approval-chain-manager/edit-action/queue.phtml', $this); ?>
\ No newline at end of file
diff --git a/application/modules/requests/views/scripts/approval-chain-manager/edit-action/watchers.phtml b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/watchers.phtml
new file mode 100644
index 00000000..d11133f3
--- /dev/null
+++ b/application/modules/requests/views/scripts/approval-chain-manager/edit-action/watchers.phtml
@@ -0,0 +1,12 @@
+<?php 
+if ($this->approvalAction->getId()) {
+    $prefix = 'edit[' . $this->approvalAction->getId() . '][';
+    $postifx = ']';
+}
+?>
+
+Role to set as watchers:<br />
+<?php echo $this->formSelect($prefix . 'watchingRole' . $postifx,
+                             $this->approvalAction->getWatchingRole(),
+                             null,
+                             array('' => '--Select--') + $this->approvalRoles); ?>
diff --git a/application/modules/requests/views/scripts/approval-chain-manager/edit-actions.phtml b/application/modules/requests/views/scripts/approval-chain-manager/edit-actions.phtml
new file mode 100644
index 00000000..be1407d2
--- /dev/null
+++ b/application/modules/requests/views/scripts/approval-chain-manager/edit-actions.phtml
@@ -0,0 +1,63 @@
+<?php echo $this->formHidden('chainId', $this->approvalChain->getId()); ?>
+<h2>Add New Action</h2>
+<div class="editChain">
+    <form method="post" action="<?php echo $this->baseUrl(); ?>/requests/approval-chain-manager/add-action.post/id/<?php echo $this->approvalChain->getId(); ?>">
+        <label>
+            Name <br />
+            <?php echo $this->formText('name'); ?>
+        </label><br />
+        
+        <label>
+            Type <br />
+            <?php echo $this->formSelect('type', null, array('class' => 'actionTypeSelect'), array('_null' => '--Select--') + $this->approvalTypes); ?>
+        </label><br />
+        
+        <label>
+            Participating Roles<br />
+            <?php echo $this->formSelect('participatingRoles', null, array('multiple' => 'multiple'), $this->approvalRoles); ?>
+        </label><br />
+        
+        <label>
+            Editing Roles<br />
+            <?php echo $this->formSelect('editingRoles', null, array('multiple' => 'multiple'), $this->approvalRoles); ?>
+        </label><br />
+        
+        <div class="editApprovalChainSpecifics"></div>
+        
+        <?php echo $this->formSubmit('submit', 'Create Action'); ?>
+    </form>
+</div>
+
+<h2>Edit Current Actions</h2>
+<form method="post" action="<?php echo $this->baseUrl(); ?>/requests/approval-chain-manager/edit-actions.post/id/<?php echo $this->approvalChain->getId(); ?>">
+    <?php
+    foreach ($this->approvalActions as $approvalAction) {
+        $prefix = 'edit[' . $approvalAction->getId() . ']';
+    ?>
+    <div class="editChain">
+        <label>
+            Name <br />
+            <?php echo $this->formText($prefix . '[name]', $approvalAction->getName()); ?>
+        </label><br />
+        
+        Type <br />
+        <?php echo get_class($approvalAction); ?><br />
+        
+        <label>
+            Participating Roles<br />
+            <?php echo $this->formSelect($prefix . '[participatingRoles]', $approvalAction->getParticipatingRoleIds(), array('multiple' => 'multiple'), $this->approvalRoles); ?>
+        </label><br />
+        
+        <label>
+            Editing Roles<br />
+            <?php echo $this->formSelect($prefix . '[editingRoles]', $approvalAction->getEditingRoleIds(), array('multiple' => 'multiple'), $this->approvalRoles); ?>
+        </label><br />
+        
+        <div class="editApprovalChainSpecifics">
+            <?php echo $approvalAction->getEditXhtml($this); ?>
+        </div>
+    </div>
+    <?php } ?>
+    
+    <?php echo $this->formSubmit('submit', 'Update Actions'); ?>
+</form>
diff --git a/application/modules/requests/views/scripts/approval-chain-manager/edit-links.phtml b/application/modules/requests/views/scripts/approval-chain-manager/edit-links.phtml
new file mode 100644
index 00000000..46b3b22c
--- /dev/null
+++ b/application/modules/requests/views/scripts/approval-chain-manager/edit-links.phtml
@@ -0,0 +1,95 @@
+<div>
+    <h3>Add Link to Chain</h3>
+    <form method="post" action="<?php echo $this->baseUrl(); ?>/requests/approval-chain-manager/add-link.post">
+        <?php echo $this->formHidden('approvalChain', $this->approvalChain->getId()); ?>
+        <table>
+            <tr>
+                <th>Previous Action</th>
+                <th>Resulted In</th>
+                <th>Next Action</th>
+            </tr>
+            <tr>
+                <td>
+                    <?php echo $this->formSelect(
+                        'currentAction',
+                        null,
+                        array('class' => 'actionSelectElement'),
+                        array('_null' => '--Just Entered Chain--')
+                        + $this->approvalActions->arrayFromMethod('getName')
+                    ); ?>
+                </td>
+                <td>
+                    <?php echo $this->formSelect(
+                        'currentState',
+                        null,
+                        null,
+                        array('_null' => '--N/A--')
+                    ); ?>
+                </td>
+                <td>
+                    <?php echo $this->formSelect(
+                        'nextAction',
+                        null,
+                        null,
+                        array('_null' => '--Exit Chain--')
+                        + $this->approvalActions->arrayFromMethod('getName')
+                    ); ?>
+                </td>
+            </tr>
+        </table>
+        <?php echo $this->formSubmit('submitAddLink', 'Add Link'); ?>
+    </form>
+</div>
+
+
+<div>
+    <h3>Edit/Remove Links in Chain</h3>
+    <form method="post" action="<?php echo $this->baseUrl(); ?>/requests/approval-chain-manager/edit-links.post">
+        <?php echo $this->formHidden('approvalChain', $this->approvalChain->getId()); ?>
+        <table>
+            <tr>
+                <th>Previous Action</th>
+                <th>Resulted In</th>
+                <th>Next Action</th>
+                <th>Delete</th>
+            </tr>
+            <?php foreach ($this->approvalLinks as $approvalLink) { ?>
+            <tr>
+                <td>
+                    <?php echo $this->formSelect(
+                        'currentAction[' . $approvalLink->getId() . ']',
+                        $approvalLink->getCurrentAction(),
+                        array('class' => 'actionSelectElement'),
+                        array('_null' => '--Just Entered Chain--')
+                        + $this->approvalActions->arrayFromMethod('getName')
+                    ); ?>
+                </td>
+                <td>
+                    <?php echo $this->formSelect(
+                        'currentState[' . $approvalLink->getId() . ']',
+                        $approvalLink->getCurrentState(),
+                        null,
+                        array('_null' => '--N/A--')
+                        + ($approvalLink->getCurrentAction()
+                            ? $this->approvalActions[$approvalLink->getCurrentAction()]->getResultStatusStrings()
+                            : array())
+                    ); ?>
+                </td>
+                <td>
+                    <?php echo $this->formSelect(
+                        'nextAction[' . $approvalLink->getId() . ']',
+                        $approvalLink->getNextAction(),
+                        null,
+                        array('_null' => '--Exit Chain--')
+                        + $this->approvalActions->arrayFromMethod('getName')
+                    ); ?>
+                </td>
+                <td>
+                    <?php echo $this->formCheckbox('delete[' . $approvalLink->getId() . ']'); ?>
+                </td>
+            </tr>
+            <?php } ?>
+        </table>
+        <?php echo $this->formSubmit('submitEditLinks', 'Update Links'); ?>
+    </form>
+</div>
diff --git a/application/modules/requests/views/scripts/approval-chain-manager/index.phtml b/application/modules/requests/views/scripts/approval-chain-manager/index.phtml
index b5eeb2bb..5edcbd46 100644
--- a/application/modules/requests/views/scripts/approval-chain-manager/index.phtml
+++ b/application/modules/requests/views/scripts/approval-chain-manager/index.phtml
@@ -1,5 +1,6 @@
 <?php $this->headLink()->appendStylesheet($this->baseUrl() . '/css/requests/approval-chain-manager.css', 'all'); ?>
 <?php $this->headScript()->appendFile($this->baseUrl() . '/javascript/requests/approval-chain-manager.js'); ?>
+<?php $this->headScript()->appendFile($this->baseUrl() . '/javascript/courses/edit.js'); ?>
 <?php $this->layout()->tagline = 'Approval Chain Manager'; ?>
 <?php $this->layout()->hideMenu = true; ?>
 
@@ -24,106 +25,16 @@
         Owner: <?php echo $this->formSelect('owner', $this->approvalChain->getOwnerBody(), null, $this->approvalBodies->arrayFromMethod('getName')); ?> <br />
         <?php echo $this->formSubmit('submit', 'Update'); ?>
     </form>
-
+    
     <div>
-        <a href="#">Links</a> |
-        <a href="#">Actions</a>
+        <a id="selectLinksTabLink" href="#">Links</a> |
+        <a id="selectActionsTabLink" href="#">Actions</a>
     </div>
 
-    <div>
-        <h3>Add Link to Chain</h3>
-        <form method="post" action="<?php echo $this->baseUrl(); ?>/requests/approval-chain-manager/add-link.post">
-            <?php echo $this->formHidden('approvalChain', $this->approvalChain->getId()); ?>
-            <table>
-                <tr>
-                    <th>Previous Action</th>
-                    <th>Resulted In</th>
-                    <th>Next Action</th>
-                </tr>
-                <tr>
-                    <td>
-                        <?php echo $this->formSelect(
-                            'currentAction',
-                            null,
-                            array('class' => 'actionSelectElement'),
-                            array('_null' => '--Just Entered Chain--')
-                            + $this->approvalActions->arrayFromMethod('getName')
-                        ); ?>
-                    </td>
-                    <td>
-                        <?php echo $this->formSelect(
-                            'currentState',
-                            null,
-                            null,
-                            array('_null' => '--N/A--')
-                        ); ?>
-                    </td>
-                    <td>
-                        <?php echo $this->formSelect(
-                            'nextAction',
-                            null,
-                            null,
-                            array('_null' => '--Exit Chain--')
-                            + $this->approvalActions->arrayFromMethod('getName')
-                        ); ?>
-                    </td>
-                </tr>
-            </table>
-            <?php echo $this->formSubmit('submitAddLink', 'Add Link'); ?>
-        </form>
+    <div id="editLinksTab">
+        <?php echo $this->partial('approval-chain-manager/edit-links.phtml', $this); ?>
     </div>
-
-
-    <div>
-        <h3>Edit/Remove Links in Chain</h3>
-        <form method="post" action="<?php echo $this->baseUrl(); ?>/requests/approval-chain-manager/edit-links.post">
-            <?php echo $this->formHidden('approvalChain', $this->approvalChain->getId()); ?>
-            <table>
-                <tr>
-                    <th>Previous Action</th>
-                    <th>Resulted In</th>
-                    <th>Next Action</th>
-                    <th>Delete</th>
-                </tr>
-                <?php foreach ($this->approvalLinks as $approvalLink) { ?>
-                <tr>
-                    <td>
-                        <?php echo $this->formSelect(
-                            'currentAction[' . $approvalLink->getId() . ']',
-                            $approvalLink->getCurrentAction(),
-                            array('class' => 'actionSelectElement'),
-                            array('_null' => '--Just Entered Chain--')
-                            + $this->approvalActions->arrayFromMethod('getName')
-                        ); ?>
-                    </td>
-                    <td>
-                        <?php echo $this->formSelect(
-                            'currentState[' . $approvalLink->getId() . ']',
-                            $approvalLink->getCurrentState(),
-                            null,
-                            array('_null' => '--N/A--')
-                            + ($approvalLink->getCurrentAction()
-                                ? $this->approvalActions[$approvalLink->getCurrentAction()]->getResultStatusStrings()
-                                : array())
-                        ); ?>
-                    </td>
-                    <td>
-                        <?php echo $this->formSelect(
-                            'nextAction[' . $approvalLink->getId() . ']',
-                            $approvalLink->getNextAction(),
-                            null,
-                            array('_null' => '--Exit Chain--')
-                            + $this->approvalActions->arrayFromMethod('getName')
-                        ); ?>
-                    </td>
-                    <td>
-                        <?php echo $this->formCheckbox('delete[' . $approvalLink->getId() . ']'); ?>
-                    </td>
-                </tr>
-                <?php } ?>
-            </table>
-            <?php echo $this->formSubmit('submitEditLinks', 'Update Links'); ?>
-        </form>
+    <div id="editActionsTab">
+        <?php echo $this->partial('approval-chain-manager/edit-actions.phtml', $this); ?>
     </div>
-
 </div>
diff --git a/document_root/css/requests/approval-chain-manager.css b/document_root/css/requests/approval-chain-manager.css
index e7cc3fde..0722723f 100644
--- a/document_root/css/requests/approval-chain-manager.css
+++ b/document_root/css/requests/approval-chain-manager.css
@@ -1,4 +1,9 @@
 ul.editMenu {float: left;}
 li.selected {font-weight: bold; font-size: 110%;}
 
-div.editMain {float: left; overflow: hidden; padding: 0px 1em;}
\ No newline at end of file
+div.editMain {float: left; overflow: hidden; padding: 0px 1em;}
+div.editChain {border: 1px solid #444; padding: 0.2em;}
+
+#editActionsTab {display: none;}
+
+.hidden_new_record {display: none;}
diff --git a/document_root/javascript/requests/approval-chain-manager.js b/document_root/javascript/requests/approval-chain-manager.js
index e4cec201..68b9ec8b 100644
--- a/document_root/javascript/requests/approval-chain-manager.js
+++ b/document_root/javascript/requests/approval-chain-manager.js
@@ -19,6 +19,37 @@ var actionTypeSelectAjaxResponder = AjaxClient.extend(
     }
 });
 
+var updateEditActionDetailsAjaxResponder = AjaxClient.extend(
+{
+    actionElement: null,
+
+    processResponse: function() {
+        var detailsDiv = this.actionElement.parentNode;
+        while (detailsDiv.nextSibling) {
+            detailsDiv = detailsDiv.nextSibling;
+            if (detailsDiv.className == 'editApprovalChainSpecifics') {
+                break;
+            }
+        }
+        while (detailsDiv.childNodes.length > 0) {
+            detailsDiv.removeChild(detailsDiv.childNodes[0]);
+        }
+
+        if(!this.requestObject.responseXML) {
+            return;
+        }
+
+        var editXHTML = this.requestObject.responseXML.childNodes[1].childNodes[0];
+        while (editXHTML.childNodes.length > 0) {
+            detailsDiv.appendChild(editXHTML.childNodes[0]);
+        }
+        var clearDiv = document.createElement('div');
+        clearDiv.className = 'clear';
+        detailsDiv.appendChild(clearDiv);
+    }
+});
+
+
 function loadApprovalChainManager()
 {
     var actionSelectElements = getElementsByClass('actionSelectElement');
@@ -26,16 +57,16 @@ function loadApprovalChainManager()
         var actionSelectElement = actionSelectElements[i];
         actionSelectElement.onchange = updateActionResults;
     }
-/*
-    document.getElementById('select_manage_links').onclick = selectLinksOrActions;
-    document.getElementById('select_manage_actions').onclick = selectLinksOrActions;
+    
+    document.getElementById('selectLinksTabLink').onclick = handleSelectLinksOrActions;
+    document.getElementById('selectActionsTabLink').onclick = handleSelectLinksOrActions;
 
-    var actionTypeSelects = getElementsByClass('action_type_select');
+    var actionTypeSelects = getElementsByClass('actionTypeSelect');
     for (var i = 0; i < actionTypeSelects.length; i++) {
         actionTypeSelects[i].onchange = updateEditActionDetails;
     }
 
-
+/*
     var addButtons = getElementsByClass('add_record_button');
     for(var i = 0; i < addButtons.length; i++) {
         addButtons[i].onclick = handleAddRecord;
@@ -45,7 +76,7 @@ function loadApprovalChainManager()
     for(var i = 0; i < removeButtons.length; i++) {
         removeButtons[i].onclick = handleRemoveRecord;
     }
-    */
+*/
 }
 
 addLoadEvent(loadApprovalChainManager);
@@ -116,7 +147,7 @@ function updateActionResults()
 function updateEditActionDetails()
 {
     var chainId = document.getElementById('chainId').value;
-    var url = '/ApprovalChainManager/GetActionEditXhtml/' + this.value + '/' + chainId;
+    var url = baseUrl + '/requests/approval-chain-manager/get-action-edit-xhtml/action-class/' + this.value + '/chain-id/' + chainId;
     var responder = new updateEditActionDetailsAjaxResponder();
     responder.actionElement = this;
     responder.sendRequest(url);
@@ -161,3 +192,13 @@ function handleRemoveRecord()
     return false;
 }
 
+function handleSelectLinksOrActions()
+{
+    document.getElementById('editLinksTab').style.display = 'none';
+    document.getElementById('editActionsTab').style.display = 'none';
+    if (this.id == 'selectLinksTabLink') {
+        document.getElementById('editLinksTab').style.display = 'block';
+    } else {
+        document.getElementById('editActionsTab').style.display = 'block';
+    }
+}
-- 
GitLab