Index: trunk/grails-app/controllers/TaskDetailedController.groovy
===================================================================
--- trunk/grails-app/controllers/TaskDetailedController.groovy	(revision 808)
+++ trunk/grails-app/controllers/TaskDetailedController.groovy	(revision 809)
@@ -434,15 +434,9 @@
             def assignedPersonList = taskInstance.assignedPersons.sort { p1, p2 -> p1.person.firstName.compareToIgnoreCase(p2.person.firstName) }
 
-            def taskProcedureInstance = TaskProcedure.get(taskInstance.taskProcedure?.id)
+            def taskProcedureRevision = TaskProcedureRevision.get(taskInstance.taskProcedureRevision?.id)
             def taskProcedureExits = new Boolean("true")
-            if(!taskProcedureInstance) {
+            if(!taskProcedureRevision) {
                 taskProcedureExits = false
             }
-
-            def maParams = [:]
-            maParams.max = 100
-            maParams.order = "asc"
-            maParams.sort = "procedureStepNumber"
-            def maintenanceActionList = MaintenanceAction.findAllByTaskProcedure(taskProcedureInstance, maParams)
 
             def taskRecurringScheduleInstance = TaskRecurringSchedule.get(taskInstance.taskRecurringSchedule?.id)
@@ -456,5 +450,5 @@
                             entryCauseList: entryCauseList,
                             entryWorkDoneList: entryWorkDoneList,
-                            taskProcedureInstance: taskProcedureInstance,
+                            taskProcedureRevision: taskProcedureRevision,
                             taskProcedureExits: taskProcedureExits,
                             showTab: showTab,
@@ -462,5 +456,4 @@
                             subTaskInstanceTotal: subTaskInstanceTotal,
                             subTaskInstanceMax: params.max,
-                            maintenanceActionList: maintenanceActionList,
                             taskRecurringScheduleInstance: taskRecurringScheduleInstance,
                             taskRecurringScheduleExits: taskRecurringScheduleExits,
Index: trunk/grails-app/controllers/TaskProcedureDetailedController.groovy
===================================================================
--- trunk/grails-app/controllers/TaskProcedureDetailedController.groovy	(revision 808)
+++ trunk/grails-app/controllers/TaskProcedureDetailedController.groovy	(revision 809)
@@ -43,41 +43,22 @@
         if(!taskProcedureInstance) {
             flash.errorMessage = "TaskProcedure not found with id ${params.id}"
-            redirect(controller:'taskDetailed', action:'search')
+            redirect(action:'list')
             return
         }
 
-        redirect(controller:'taskDetailed',
-                        action:'show',
-                        id:taskProcedureInstance.linkedTask?.id,
-                        params:[showTab:"showProcedureTab"])
-    }
+        def taskProcedureRevision
+        if(params.revision?.toInteger())
+             taskProcedureRevision = taskProcedureInstance.getRevision( params.revision )
+        else
+             taskProcedureRevision = taskProcedureInstance.latestRevision
 
-    def delete = {
-        def taskProcedureInstance = TaskProcedure.get( params.id )
-        if(taskProcedureInstance) {
-            def taskInstance = taskProcedureInstance.linkedTask
-            try {
-                taskProcedureInstance.tasks.each {
-                    it.taskProcedure = null
-                }
-                taskProcedureInstance.delete(flush:true)
-                flash.message = "TaskProcedure ${params.id} deleted"
-                redirect(controller:'taskDetailed',
-                                action:'show',
-                                id:taskInstance.id,
-                                params:[showTab:"showProcedureTab"])
-            }
-            catch(org.springframework.dao.DataIntegrityViolationException e) {
-                flash.errorMessage = "TaskProcedure ${params.id} could not be deleted"
-                redirect(controller:'taskDetailed',
-                                action:'show',
-                                id:taskInstance.id,
-                                params:[showTab:"showProcedureTab"])
-            }
+        if(!taskProcedureRevision) {
+            flash.errorMessage = "TaskProcedure ${params.id} revision ${params.revision} not found"
+            redirect(action:'list')
+            return
         }
-        else {
-            flash.errorMessage = "TaskProcedure not found with id ${params.id}"
-            redirect(action:list)
-        }
+
+        return [taskProcedureRevision: taskProcedureRevision]
+
     }
 
@@ -85,5 +66,5 @@
 
         // In the case of an actionSubmit button, rewrite action name from 'index'.
-        if(params._action_Edit)
+        //if(params._action_Edit)
             params.action='edit'
 
@@ -106,8 +87,5 @@
         if(!result.error) {
             flash.message = g.message(code: "default.update.success", args: ["TaskProcedure", params.id])
-            redirect(controller:'taskDetailed',
-                            action:'show',
-                            id:result.taskProcedureInstance.linkedTask.id,
-                            params:[showTab:"showProcedureTab"])
+            redirect(action:'show', id:result.taskProcedureInstance.id)
             return
         }
@@ -121,8 +99,5 @@
         if(result.error.code == "default.optimistic.locking.failure") {
             flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
-            redirect(controller:'taskDetailed',
-                            action:'show',
-                            id:result.taskProcedureInstance.linkedTask.id,
-                            params:[showTab:"showProcedureTab"])
+            redirect(action:'show', id:result.taskProcedureInstance.id)
             return
         }
@@ -144,5 +119,5 @@
 
         // Task already has a taskProcedure.
-        if(params.linkedTask.taskProcedure) {
+        if(params.linkedTask.taskProcedureRevision) {
             flash.errorMessage = g.message(code: 'default.optimistic.locking.failure')
             redirect(controller:'taskDetailed',
@@ -183,16 +158,14 @@
         if(!result.error) {
             flash.message = g.message(code: "default.create.success", args: ["TaskProcedure", result.taskProcedureInstance.id])
-            redirect(controller:'taskDetailed',
-                            action:'show',
-                            id:result.taskProcedureInstance.linkedTask.id,
-                            params:[showTab:"showProcedureTab"])
+            redirect(action:'show', id:result.taskProcedureInstance.id)
             return
         }
 
+        // Task already has a taskProcedure.
         if(result.error.code == "default.optimistic.locking.failure") {
             flash.errorMessage = g.message(code: result.error.code, args: result.error.args)
             redirect(controller:'taskDetailed',
                             action:'show',
-                            id:result.taskProcedureInstance.linkedTask.id,
+                            id:params.linkedTask.id,
                             params:[showTab:"showProcedureTab"])
             return
Index: trunk/grails-app/domain/DocumentReference.groovy
===================================================================
--- trunk/grails-app/domain/DocumentReference.groovy	(revision 808)
+++ trunk/grails-app/domain/DocumentReference.groovy	(revision 809)
@@ -10,5 +10,9 @@
 //     static hasMany = []
 
-    static belongsTo = [TaskProcedure]
+    static belongsTo = [TaskProcedure, TaskProcedureRevision]
+
+    static mapping = {
+        batchSize 10
+    }
 
     static constraints = {
Index: trunk/grails-app/domain/MaintenanceAction.groovy
===================================================================
--- trunk/grails-app/domain/MaintenanceAction.groovy	(revision 808)
+++ trunk/grails-app/domain/MaintenanceAction.groovy	(revision 809)
@@ -1,5 +1,4 @@
 class MaintenanceAction {
 
-    TaskProcedure taskProcedure
     MaintenancePolicy maintenancePolicy
     Section section
@@ -17,5 +16,9 @@
 //     static hasMany = []
 
-    static belongsTo = [TaskProcedure]
+    static mapping = {
+        batchSize 10
+    }
+
+    static belongsTo = [TaskProcedure, TaskProcedureRevision]
 
     static constraints = {
@@ -26,5 +29,5 @@
         procedureStepNumber(nullable:true)
         description(blank:false,maxSize:100)
-        pageRef(maxSize:100)
+        pageRef(maxSize:25)
     }
 
Index: trunk/grails-app/domain/Task.groovy
===================================================================
--- trunk/grails-app/domain/Task.groovy	(revision 808)
+++ trunk/grails-app/domain/Task.groovy	(revision 809)
@@ -13,5 +13,5 @@
     AssetSubItem assetSubItem
     TaskRecurringSchedule taskRecurringSchedule
-    TaskProcedure taskProcedure
+    TaskProcedureRevision taskProcedureRevision
 
     String description
@@ -61,5 +61,5 @@
         assetSubItem(nullable:true)
         taskRecurringSchedule(nullable:true)
-        taskProcedure(nullable:true)
+        taskProcedureRevision(nullable:true)
 
     }
Index: trunk/grails-app/domain/TaskProcedure.groovy
===================================================================
--- trunk/grails-app/domain/TaskProcedure.groovy	(revision 808)
+++ trunk/grails-app/domain/TaskProcedure.groovy	(revision 809)
@@ -5,8 +5,4 @@
 
     Task linkedTask
-    Person createdBy
-    Person lastUpdatedBy
-    Date dateCreated = new Date() // autoTimestamp
-    Date lastUpdated = new Date() // autoTimestamp
 
     def getDescription() { linkedTask.description }
@@ -15,8 +11,9 @@
     List maintenanceActions = new ArrayList()
     List documentReferences = new ArrayList()
+    List revisions = new ArrayList()
 
-    static hasMany = [tasks: Task,
-                                    maintenanceActions: MaintenanceAction,
-                                    documentReferences: DocumentReference]
+    static hasMany = [maintenanceActions: MaintenanceAction,
+                                    documentReferences: DocumentReference,
+                                    revisions: TaskProcedureRevision]
 
     def getMaintenanceActionLazyList() {
@@ -28,9 +25,40 @@
     }
 
-    static mappedBy = [tasks:"taskProcedure"]
+    // The current revision number is equal to the count of the revisions created.
+    // More efficient than loading the entire revisions list and using size().
+    // WithTransaction is used to allow calling in a transaction however objects
+    // in the current transaction must not trigger DataIntegrityViolationException.
+    def getRevision() {
+        def revision
+        TaskProcedure.withTransaction {
+            revision = TaskProcedureRevision.countByTaskProcedure(this)
+        }
+        return revision
+    }
+
+    // Get a specific revision.
+    def getRevision(revision) {
+        def taskProcedureRevision
+        TaskProcedure.withTransaction {
+            taskProcedureRevision = TaskProcedureRevision.findByTaskProcedureAndRevision(this, revision)
+        }
+        return taskProcedureRevision
+    }
+
+    // Get the latest revision of this procedure.
+    def getLatestRevision() {
+        def taskProcedureRevision
+        TaskProcedure.withTransaction {
+            taskProcedureRevision = TaskProcedureRevision.findByTaskProcedureAndRevision(this, this.revision)
+        }
+        return taskProcedureRevision
+    }
 
     static mapping = {
+        linkedTask lazy:false
+        revisions batchSize: 10
         maintenanceActions cascade:"all-delete-orphan"
         documentReferences cascade:"all-delete-orphan"
+        revisions cascade:"all-delete-orphan"
     }
 
Index: trunk/grails-app/domain/TaskProcedureRevision.groovy
===================================================================
--- trunk/grails-app/domain/TaskProcedureRevision.groovy	(revision 809)
+++ trunk/grails-app/domain/TaskProcedureRevision.groovy	(revision 809)
@@ -0,0 +1,62 @@
+import org.apache.commons.collections.list.LazyList
+import org.apache.commons.collections.FactoryUtils
+
+class TaskProcedureRevision {
+
+    Task linkedTask
+
+    TaskProcedure taskProcedure
+    Integer revision
+    Person createdBy
+    Date dateCreated = new Date() // autoTimestamp
+
+    def getDescription() { linkedTask.description }
+    def getAsset() { linkedTask.primaryAsset }
+
+    List maintenanceActions = new ArrayList()
+    List documentReferences = new ArrayList()
+
+    static hasMany = [tasks: Task,
+                                    maintenanceActions: MaintenanceAction,
+                                    documentReferences: DocumentReference]
+
+    def getMaintenanceActionLazyList() {
+        return LazyList.decorate(maintenanceActions, FactoryUtils.instantiateFactory(MaintenanceAction.class))
+    }
+
+    def getDocumentReferenceLazyList() {
+        return LazyList.decorate(documentReferences, FactoryUtils.instantiateFactory(DocumentReference.class))
+    }
+
+    // The taskProcedure holds the procedure id number.
+    def getTaskProcedureId() {
+        taskProcedure.id
+    }
+
+    static mappedBy = [tasks:"taskProcedureRevision"]
+
+    static mapping = {
+        taskProcedure lazy:false
+        linkedTask lazy:false
+        tasks batchSize: 10
+        maintenanceActions cascade:"all-delete-orphan"
+        documentReferences cascade:"all-delete-orphan"
+    }
+
+    static belongsTo = [TaskProcedure]
+
+    static constraints = {
+    }
+
+    String toString() {
+        "${this.id}"
+    }
+
+    def getRevisionDateString() {
+        "${this.revision} -- ${dateCreated.format('EEE, dd-MMM-yyyy')}"
+    }
+
+    def getFullRevisionString() {
+        "${this.revision} -- ${createdBy} on ${dateCreated.format('EEE, dd-MMM-yyyy @ HH:mm')}"
+    }
+}
Index: trunk/grails-app/i18n/messages.properties
===================================================================
--- trunk/grails-app/i18n/messages.properties	(revision 808)
+++ trunk/grails-app/i18n/messages.properties	(revision 809)
@@ -154,6 +154,6 @@
 task.operationNotPermittedOnTaskHavingSubTasksWithoutAuth=This operation is not permitted \
     on a task that has sub tasks without authorisation.
-task.operationNotPermittedOnTaskLinkedToProcedure=This operation is not permitted \
-    on a task that is linked to a procedure.
+task.operationNotPermittedOnTaskLinkedToProcedureWithoutAuth=This operation is not permitted \
+    on a task that is linked to a procedure without authorisation.
 task.operationNotPermittedOnParentPmTask=This operation is not permitted \
     on a Parent PM task.
@@ -317,4 +317,5 @@
 default.create.success={0} {1} created.
 default.create.failure={0} could not be created.
+default.create.revision.failure=Could not create revision.
 default.optimistic.locking.failure=Another user has updated this item while you were editing, please check the updated values.
 default.file.over.max.size=Supplied file is greater than max size of {0} {1}.
Index: trunk/grails-app/services/CreateDataService.groovy
===================================================================
--- trunk/grails-app/services/CreateDataService.groovy	(revision 808)
+++ trunk/grails-app/services/CreateDataService.groovy	(revision 809)
@@ -140,6 +140,6 @@
         createDemoAssignedGroups()
         createDemoAssignedPersons()
-        createDemoTaskProcedure()
-        createDemoMaintenanceActions()
+//         createDemoTaskProcedure()
+//         createDemoMaintenanceActions()
         createDemoTaskRecurringSchedules()
 
Index: trunk/grails-app/services/TaskProcedureService.groovy
===================================================================
--- trunk/grails-app/services/TaskProcedureService.groovy	(revision 808)
+++ trunk/grails-app/services/TaskProcedureService.groovy	(revision 809)
@@ -7,4 +7,5 @@
 
     def authService
+    def dateUtilService
 
     /**
@@ -23,6 +24,5 @@
                 result.error = [ code: m.code, args: ["TaskProcedure", params.id] ]
                 // Fetch to prevent lazy initialization error.
-                result.taskProcedureInstance?.linkedTask.primaryAsset
-                result.taskProcedureInstance?.createdBy
+                result.taskProcedureInstance.revisions.each {it.createdBy.toString()}
                 return result
             }
@@ -40,6 +40,4 @@
 
             result.taskProcedureInstance.properties = params
-            result.taskProcedureInstance.lastUpdatedBy = authService.currentUser
-            result.taskProcedureInstance.lastUpdated = new Date() // Required to trigger version increment.
 
             // Gaps in the html index's can be created by adding 2 items and removing the first one.
@@ -80,8 +78,31 @@
             }
 
+            def r = createRevision(result.taskProcedureInstance)
+            if(r.error)
+                return fail(field:'id', code:"default.create.revision.failure")
+
+            // Also sets: taskInstance.taskProcedureRevision = taskProcedureRevision
+            r.taskProcedureRevision.addToTasks(result.taskProcedureInstance.linkedTask)
+
+            // Update tasks that are using previousRevision.
+            // Only those that are not started and due to be started today or in the future.
+            def previousRevision = result.taskProcedureInstance.getRevision(r.taskProcedureRevision.revision - 1)
+            if(previousRevision) {
+                Task.withCriteria {
+                    eq("taskProcedureRevision", previousRevision)
+                    ge("targetStartDate", dateUtilService.today)
+                    taskStatus {
+                        idEq(1L) // Not Started.
+                    }
+                    maxResults(10000)
+                }.each {
+                    it.taskProcedureRevision = r.taskProcedureRevision
+                }
+            }
+
             // Success.
             return result
 
-        } //end withTransaction
+        } // end withTransaction
     }  // end update()
 
@@ -96,5 +117,5 @@
             def fail = { Map m ->
                 status.setRollbackOnly()
-                if(result.taskProcedureInstance && m.field) 
+                if(result.taskProcedureInstance && m.field)
                     result.taskProcedureInstance.errors.rejectValue(m.field, m.code)
                 result.error = [ code: m.code, args: ["TaskProcedure", params.id] ]
@@ -107,9 +128,6 @@
 
             // Optimistic locking check on linkedTask.
-            if(result.taskProcedureInstance.linkedTask.taskProcedure)
+            if(result.taskProcedureInstance.linkedTask.taskProcedureRevision)
                     return fail(field:"version", code:"default.optimistic.locking.failure")
-
-            result.taskProcedureInstance.createdBy = authService.currentUser
-            result.taskProcedureInstance.lastUpdatedBy = authService.currentUser
 
             // Gaps in the html index's can be created by adding 2 items and removing the first one.
@@ -124,7 +142,4 @@
             }
 
-            // Also sets: taskInstance.taskProcedure = taskProcedureInstance
-            result.taskProcedureInstance.addToTasks(result.taskProcedureInstance.linkedTask)
-
             if(result.taskProcedureInstance.hasErrors() || !result.taskProcedureInstance.save()) {
                 // Populate collection errors for display.
@@ -134,11 +149,58 @@
             }
 
-        } //end withTransaction
-
-        result.taskProcedureInstance.lastUpdated = new Date() // Required to trigger version increment to 1.
-
-        // success
+            def r = createRevision(result.taskProcedureInstance)
+            if(r.error)
+                return fail(field:'id', code:"default.create.revision.failure")
+
+            // Also sets: taskInstance.taskProcedureRevision = taskProcedureRevision
+            r.taskProcedureRevision.addToTasks(result.taskProcedureInstance.linkedTask)
+
+        } // end withTransaction
+
+        // Success.
         return result
     }  // end save()
 
+    /**
+    * Creates a new taskProcedureRevision.
+    * @param taskProcedureInstance The taskProcedure to create the revision for.
+    * @returns A map containing result.error (if any error) and result.taskProcedureRevision.
+    */
+    def createRevision(taskProcedureInstance) {
+        def result = [:]
+        TaskProcedureRevision.withTransaction { status ->
+            def fail = { Map m ->
+                status.setRollbackOnly()
+                if(result.taskProcedureRevision && m.field)
+                    result.taskProcedureRevision.errors.rejectValue(m.field, m.code)
+                result.error = [ code: m.code, args: ["TaskProcedureRevision"] ]
+                return result
+            }
+
+            result.taskProcedureRevision = new TaskProcedureRevision()
+            taskProcedureInstance.addToRevisions(result.taskProcedureRevision)
+
+            result.taskProcedureRevision.taskProcedure = taskProcedureInstance
+            result.taskProcedureRevision.linkedTask = taskProcedureInstance.linkedTask
+            result.taskProcedureRevision.createdBy =  authService.currentUser
+            result.taskProcedureRevision.revision = 0 // init to prevent DataIntegrityViolationException
+            result.taskProcedureRevision.revision = taskProcedureInstance.revision
+            taskProcedureInstance.maintenanceActions.each {
+                result.taskProcedureRevision.addToMaintenanceActions(new MaintenanceAction(it.properties))
+            }
+            taskProcedureInstance.documentReferences.each {
+                result.taskProcedureRevision.addToDocumentReferences(new DocumentReference(it.properties))
+            }
+
+            if(result.taskProcedureRevision.hasErrors() || !result.taskProcedureRevision.save()) {
+                log.error result.taskProcedureRevision.errors
+                return fail(code:"default.create.failure")
+            }
+
+        } // end withTransaction
+
+        // Success.
+        return result
+    } // end createRevision()
+
 } // end class
Index: trunk/grails-app/services/TaskRecurringScheduleService.groovy
===================================================================
--- trunk/grails-app/services/TaskRecurringScheduleService.groovy	(revision 808)
+++ trunk/grails-app/services/TaskRecurringScheduleService.groovy	(revision 809)
@@ -68,5 +68,5 @@
                 p.targetStartDate = it.nextTargetStartDate
                 p.targetCompletionDate = it.nextTargetCompletionDate
-                if(it.task.taskProcedure) p.taskProcedure = it.task.taskProcedure
+                if(it.task.taskProcedureRevision) p.taskProcedureRevision = it.task.taskProcedureRevision
                 if(it.task.assignedGroups) p.assignedGroups = new ArrayList(it.task.assignedGroups)
                 if(it.task.assignedPersons) p.assignedPersons = new ArrayList(it.task.assignedPersons)
Index: trunk/grails-app/services/TaskService.groovy
===================================================================
--- trunk/grails-app/services/TaskService.groovy	(revision 808)
+++ trunk/grails-app/services/TaskService.groovy	(revision 809)
@@ -188,5 +188,5 @@
     * Creates a subTask copying sane attributes from the parentTask unless otherwise specified in params.
     * The targetStartDate and targetCompletionDate default to today since that is the sane thing to do.
-    * The taskProcedure is only assigned to the sub task if supplied in params.
+    * The taskProcedureRevision is only assigned to the sub task if supplied in params.
     * The assignedPersons and assignedGroups are only added to the sub task if supplied in params.
     * The positiveFault property is never set on the subTask.
@@ -228,5 +228,5 @@
 
         // Supplied by recurring tasks.
-        if(params.taskProcedure) p.taskProcedure = params.taskProcedure
+        if(params.taskProcedureRevision) p.taskProcedureRevision = params.taskProcedureRevision
         if(params.assignedGroups) p.assignedGroups = params.assignedGroups // Collection.
         if(params.assignedPersons) p.assignedPersons = params.assignedPersons // Collection.
@@ -691,11 +691,13 @@
             }
 
-            // Check for taskProcedure using this task as linkedTask.
-            if(result.taskInstance.taskProcedure?.linkedTask?.id == result.taskInstance.id)
-                return fail(field:"taskProcedure", code:"task.operationNotPermittedOnTaskLinkedToProcedure")
+            // Check for taskProcedureRevision using this task as linkedTask.
+            if(result.taskInstance.taskProcedureRevision?.linkedTask?.id == result.taskInstance.id) {
+                if(!authenticateService.ifAnyGranted('ROLE_AppAdmin,ROLE_Manager,ROLE_TaskManager'))
+                    return fail(field:"taskProcedureRevision", code:"task.operationNotPermittedOnTaskLinkedToProcedureWithoutAuth")
+            }
 
             // Check for Parent PM task type.
             if(result.taskInstance.taskType.id == 6)
-                return fail(field:"taskProcedure", code:"task.operationNotPermittedOnParentPmTask")
+                return fail(field:"taskType", code:"task.operationNotPermittedOnParentPmTask")
 
             result.taskInstance.trash = true
Index: trunk/grails-app/views/taskDetailed/show.gsp
===================================================================
--- trunk/grails-app/views/taskDetailed/show.gsp	(revision 808)
+++ trunk/grails-app/views/taskDetailed/show.gsp	(revision 809)
@@ -524,136 +524,6 @@
                         </g:if>
                         <g:else>
-                            <div class="dialog">
-                                <table>
-                                    <tbody>
-
-                                        <tr class="prop">
-                                            <td valign="top" class="name">Procedure Id:</td>
-                                            <td valign="top" class="value">
-                                                ${fieldValue(bean:taskProcedureInstance, field:'id')}
-                                            </td>
-                                        </tr>
-
-                                        <tr class="prop">
-                                            <td valign="top" class="name">Linked Task:</td>
-                                            <td valign="top" class="value">
-                                                <g:link controller="taskDetailed"
-                                                                action="show"
-                                                                id="${taskProcedureInstance.linkedTask.id}">
-                                                    ${taskProcedureInstance.linkedTask.encodeAsHTML()}
-                                                </g:link>
-                                            </td>
-                                        </tr>
-
-                                        <tr class="prop">
-                                            <td valign="top" class="name">Linked Asset:</td>
-                                            <td valign="top" class="value">
-                                                <g:render template="/shared/assetTreeCompact" model="['assetInstance': taskProcedureInstance.linkedTask.primaryAsset]" />
-                                            </td>
-                                        </tr>
-
-                                        <tr class="prop">
-                                            <td valign="top" class="name">Version:</td>
-                                            <td valign="top" class="value">
-                                                    ${fieldValue(bean:taskProcedureInstance, field:'version')}
-                                            </td>
-                                        </tr>
-
-                                        <tr class="prop">
-                                            <td valign="top" class="name">Last Updated:</td>
-                                            <td valign="top" class="value">
-                                                <g:formatDate date="${taskProcedureInstance.lastUpdated}"
-                                                                            format="EEE, dd-MMM-yyyy"/>
-                                            </td>
-                                        </tr>
-
-                                    </tbody>
-                                </table>
-                            </div>
-                            <div class="buttons">
-                                <g:form controller="taskProcedureDetailed">
-                                    <input type="hidden" name="id" value="${taskProcedureInstance?.id}" />
-                                    <span class="button"><g:actionSubmit class="edit" value="Edit" /></span>
-                                </g:form>
-                            </div>
-
-                            <br />
-
-                            <g:if test="${taskProcedureInstance.documentReferences}">
-                                <div class="list">
-                                    <table>
-                                        <thead>
-                                            <tr>
-                                                <th>Document Reference</th>
-                                                <th>Location</th>
-                                            </tr>
-                                        </thead>
-                                        <tbody>
-                                            <g:each in="${taskProcedureInstance.documentReferences}" status="i" var="docRef">
-                                                <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
-
-                                                    <td valign="top" class="name">
-                                                        ${fieldValue(bean:docRef, field:'name')}
-                                                    </td>
-
-                                                    <td  valign="top" style="text-align:left;" class="value">
-                                                        <custom:easyUrl url="${docRef.location}" />
-                                                    </td>
-
-                                                </tr>
-                                            </g:each>
-
-                                        </tbody>
-                                    </table>
-                                </div>
-                            </g:if>
-
-                            <br />
-
-                            <div class="list">
-                                <table>
-                                    <thead>
-                                        <tr>
-                                            <th>Step</th>
-                                            <th>Assembly</th>
-                                            <th>Description</th>
-                                            <th>Page Ref</th>
-                                            <th>Condition</th>
-                                        </tr>
-                                    </thead>
-                                    <tbody>
-                                        <g:each in="${maintenanceActionList}" status="i" var="maintenanceAction">
-                                            <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
-
-                                                <td valign="top" class="name">
-                                                    ${fieldValue(bean:maintenanceAction, field:'procedureStepNumber')}
-                                                </td>
-
-                                                <td  valign="top" style="text-align:left;" class="value">
-                                                    <g:if test="${maintenanceAction.assetSubItem}">
-                                                        ${maintenanceAction.assetSubItem.parentItem?.encodeAsHTML()}
-                                                        --
-                                                        ${maintenanceAction.assetSubItem.encodeAsHTML()}
-                                                    </g:if>
-                                                </td>
-
-                                                <td  valign="top" style="text-align:left;" class="value">
-                                                    ${fieldValue(bean:maintenanceAction, field:'description')}
-                                                </td>
-
-                                                <td  valign="top" style="text-align:left;" class="value">
-                                                    ${fieldValue(bean:maintenanceAction, field:'pageRef')}
-                                                </td>
-
-                                                <td  valign="top" style="text-align:left;" class="value">
-                                                </td>
-
-                                            </tr>
-                                        </g:each>
-
-                                    </tbody>
-                                </table>
-                            </div>
-
+                            <g:render template="/taskProcedureDetailed/taskProcedureRevision"
+                                                model="['taskProcedureRevision':taskProcedureRevision]" />
                         </g:else>
 
Index: trunk/grails-app/views/taskProcedureDetailed/_taskProcedure.gsp
===================================================================
--- trunk/grails-app/views/taskProcedureDetailed/_taskProcedure.gsp	(revision 808)
+++ trunk/grails-app/views/taskProcedureDetailed/_taskProcedure.gsp	(revision 809)
@@ -31,27 +31,17 @@
             </tr>
 
-            <g:if test="${taskProcedureInstance.version}">
+            <g:if test="${taskProcedureInstance.id}">
                 <tr class="prop">
-                    <td valign="top" class="name">Version:</td>
+                    <td valign="top" class="name">Revisions:</td>
                     <td valign="top" class="value">
-                            ${fieldValue(bean:taskProcedureInstance, field:'version')}
-                    </td>
-                </tr>
-
-                <tr class="prop">
-                    <td valign="top" class="name">Created By:</td>
-                    <td valign="top" class="value">
-                            ${fieldValue(bean:taskProcedureInstance, field:'createdBy')}
-                            on
-                            <g:formatDate date="${taskProcedureInstance.dateCreated}" format="EEE, dd-MMM-yyyy @ HH:mm"/>
-                    </td>
-                </tr>
-
-                <tr class="prop">
-                    <td valign="top" class="name">Last Updated By:</td>
-                    <td valign="top" class="value">
-                            ${fieldValue(bean:taskProcedureInstance, field:'lastUpdatedBy')}
-                            on
-                            <g:formatDate date="${taskProcedureInstance.lastUpdated}" format="EEE, dd-MMM-yyyy @ HH:mm"/>
+                        <ul>
+                        <g:each var="r" in="${taskProcedureInstance.revisions}">
+                            <li>
+                                <g:link action="show" id="${taskProcedureInstance.id}" params="['revision':r.revision]">
+                                    ${r.fullRevisionString.encodeAsHTML()}
+                                </g:link>
+                            </li>
+                        </g:each>
+                        </ul>
                     </td>
                 </tr>
Index: trunk/grails-app/views/taskProcedureDetailed/_taskProcedureRevision.gsp
===================================================================
--- trunk/grails-app/views/taskProcedureDetailed/_taskProcedureRevision.gsp	(revision 809)
+++ trunk/grails-app/views/taskProcedureDetailed/_taskProcedureRevision.gsp	(revision 809)
@@ -0,0 +1,133 @@
+
+        <div class="dialog">
+            <table>
+                <tbody>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Procedure Id:</td>
+                        <td valign="top" class="value">
+                            ${fieldValue(bean:taskProcedureRevision, field:'taskProcedureId')}
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Linked Task:</td>
+                        <td valign="top" class="value">
+                            <g:link controller="taskDetailed"
+                                            action="show"
+                                            id="${taskProcedureRevision.linkedTask.id}">
+                                ${taskProcedureRevision.linkedTask.encodeAsHTML()}
+                            </g:link>
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Linked Asset:</td>
+                        <td valign="top" class="value">
+                            <g:render template="/shared/assetTreeCompact" model="['assetInstance': taskProcedureRevision.linkedTask.primaryAsset]" />
+                        </td>
+                    </tr>
+
+                    <tr class="prop">
+                        <td valign="top" class="name">Revision:</td>
+                        <td valign="top" class="value">
+                            ${fieldValue(bean:taskProcedureRevision, field:'revisionDateString')}
+                        </td>
+                    </tr>
+
+                </tbody>
+            </table>
+        </div>
+        <div class="buttons">
+            <g:form controller="taskProcedureDetailed">
+                <input type="hidden" name="id" value="${taskProcedureRevision.taskProcedureId}" />
+                Latest Revision: ${taskProcedureRevision?.taskProcedure.revision}
+                <span class="button">
+                    <g:actionSubmit class="edit" value="Edit" />
+                </span>
+                <span class="button">
+                    <g:actionSubmit class="go" value="Show" />
+                </span>
+            </g:form>
+        </div>
+
+        <br />
+
+        <g:if test="${taskProcedureRevision.documentReferences}">
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                            <th>Document Reference</th>
+                            <th>Location</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                        <g:each in="${taskProcedureRevision.documentReferences}" status="i" var="docRef">
+                            <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+
+                                <td valign="top" class="name">
+                                    ${fieldValue(bean:docRef, field:'name')}
+                                </td>
+
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    <custom:easyUrl url="${docRef.location}" />
+                                </td>
+
+                            </tr>
+                        </g:each>
+
+                    </tbody>
+                </table>
+            </div>
+        </g:if>
+
+        <br />
+
+        <g:if test="${taskProcedureRevision.maintenanceActions}">
+            <div class="list">
+                <table>
+                    <thead>
+                        <tr>
+                            <th>Step</th>
+                            <th>Assembly</th>
+                            <th>Description</th>
+                            <th>Page Ref</th>
+                            <th>Condition</th>
+                        </tr>
+                    </thead>
+                    <tbody>
+                        <g:each in="${taskProcedureRevision.maintenanceActions}" status="i" var="maintenanceAction">
+                            <tr class="${(i % 2) == 0 ? 'odd' : 'even'}">
+
+                                <td valign="top" class="name">
+                                    ${fieldValue(bean:maintenanceAction, field:'procedureStepNumber')}
+                                </td>
+
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    <g:if test="${maintenanceAction.assetSubItem}">
+                                        ${maintenanceAction.assetSubItem.parentItem?.encodeAsHTML()}
+                                        --
+                                        ${maintenanceAction.assetSubItem.encodeAsHTML()}
+                                    </g:if>
+                                </td>
+
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    ${fieldValue(bean:maintenanceAction, field:'description')}
+                                </td>
+
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    ${maintenanceAction.pageRef.encodeAsHTML() ?: '-'}
+                                </td>
+
+                                <td  valign="top" style="text-align:left;" class="value">
+                                    ${'A | B | C | D'}
+                                </td>
+
+                            </tr>
+                        </g:each>
+
+                    </tbody>
+                </table>
+            </div>
+        </g:if>
Index: trunk/grails-app/views/taskProcedureDetailed/edit.gsp
===================================================================
--- trunk/grails-app/views/taskProcedureDetailed/edit.gsp	(revision 808)
+++ trunk/grails-app/views/taskProcedureDetailed/edit.gsp	(revision 809)
@@ -31,5 +31,4 @@
                     <span class="button"><g:actionSubmit class="save" value="Update" /></span>
                     <span class="button"><g:actionSubmit class="cancel" value="Cancel" action="Show"/></span>
-                    <span class="button"><g:actionSubmit class="delete" onclick="return confirm('Are you sure?');" value="Delete" /></span>
                 </div>
             </g:form>
Index: trunk/grails-app/views/taskProcedureDetailed/list.gsp
===================================================================
--- trunk/grails-app/views/taskProcedureDetailed/list.gsp	(revision 808)
+++ trunk/grails-app/views/taskProcedureDetailed/list.gsp	(revision 809)
@@ -14,7 +14,5 @@
         </div>
         <div class="body">
-            <g:if test="${flash.message}">
-            <div class="message">${flash.message}</div>
-            </g:if>
+            <g:render template="/shared/messages" />
             <filterpane:currentCriteria domainBean="TaskProcedure"
                                     action="list"
Index: trunk/grails-app/views/taskProcedureDetailed/show.gsp
===================================================================
--- trunk/grails-app/views/taskProcedureDetailed/show.gsp	(revision 809)
+++ trunk/grails-app/views/taskProcedureDetailed/show.gsp	(revision 809)
@@ -0,0 +1,23 @@
+
+
+<html>
+    <head>
+        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+        <meta name="layout" content="main" />
+        <title>Show TaskProcedure</title>
+        <nav:resources override="true"/>
+    </head>
+    <body>
+        <div class="nav">
+            <nav:renderSubItems group="navAlt"/>
+        </div>
+        <div class="body">
+            <g:if test="${flash.message}">
+            <div class="message">${flash.message}</div>
+            </g:if>
+
+
+            <g:render template="/taskProcedureDetailed/taskProcedureRevision" />
+        </div>
+    </body>
+</html>
