diff --git a/awx/api/serializers.py b/awx/api/serializers.py index 082e12bd73..3dd5d017c8 100644 --- a/awx/api/serializers.py +++ b/awx/api/serializers.py @@ -3441,6 +3441,17 @@ class WorkflowApprovalSerializer(UnifiedJobSerializer): return res +class WorkflowApprovalActivityStreamSerializer(WorkflowApprovalSerializer): + """ + timed_out and status are usually read-only fields + However, when we generate an activity stream record, we *want* to record + these types of changes. This serializer allows us to do so. + """ + status = serializers.ChoiceField(choices=JobTemplate.JOB_TEMPLATE_STATUS_CHOICES) + timed_out = serializers.BooleanField() + + + class WorkflowApprovalListSerializer(WorkflowApprovalSerializer, UnifiedJobListSerializer): class Meta: diff --git a/awx/main/models/workflow.py b/awx/main/models/workflow.py index c2b9427df9..840a556262 100644 --- a/awx/main/models/workflow.py +++ b/awx/main/models/workflow.py @@ -681,38 +681,16 @@ class WorkflowApproval(UnifiedJob): return 'workflow_approval_template' def approve(self, request=None): - from awx.main.signals import model_serializer_mapping # circular import self.status = 'successful' self.save() self.websocket_emit_status(self.status) - changes = model_to_dict(self, model_serializer_mapping()) - changes['status'] = ['pending', 'successful'] - activity_entry = ActivityStream( - operation='update', - object1='workflow_approval', - actor=request.user, - changes=json.dumps(changes), - ) - activity_entry.save() - getattr(activity_entry, 'workflow_approval').add(self.pk) schedule_task_manager() return reverse('api:workflow_approval_approve', kwargs={'pk': self.pk}, request=request) def deny(self, request=None): - from awx.main.signals import model_serializer_mapping # circular import self.status = 'failed' self.save() self.websocket_emit_status(self.status) - changes = model_to_dict(self, model_serializer_mapping()) - changes['status'] = ['pending', 'failed'] - activity_entry = ActivityStream( - operation='update', - object1='workflow_approval', - actor=request.user, - changes=json.dumps(changes), - ) - activity_entry.save() - getattr(activity_entry, 'workflow_approval').add(self.pk) schedule_task_manager() return reverse('api:workflow_approval_deny', kwargs={'pk': self.pk}, request=request) diff --git a/awx/main/signals.py b/awx/main/signals.py index 627711f530..a655c19b3b 100644 --- a/awx/main/signals.py +++ b/awx/main/signals.py @@ -430,7 +430,7 @@ def model_serializer_mapping(): models.Label: serializers.LabelSerializer, models.WorkflowJobTemplate: serializers.WorkflowJobTemplateWithSpecSerializer, models.WorkflowJobTemplateNode: serializers.WorkflowJobTemplateNodeSerializer, - models.WorkflowApproval: serializers.WorkflowApprovalSerializer, + models.WorkflowApproval: serializers.WorkflowApprovalActivityStreamSerializer, models.WorkflowApprovalTemplate: serializers.WorkflowApprovalTemplateSerializer, models.WorkflowJob: serializers.WorkflowJobSerializer, models.OAuth2AccessToken: serializers.OAuth2TokenSerializer, diff --git a/awx/ui/client/lib/components/approvalsDrawer/approvalsDrawer.partial.html b/awx/ui/client/lib/components/approvalsDrawer/approvalsDrawer.partial.html index 01ff402042..7ef3b29443 100644 --- a/awx/ui/client/lib/components/approvalsDrawer/approvalsDrawer.partial.html +++ b/awx/ui/client/lib/components/approvalsDrawer/approvalsDrawer.partial.html @@ -30,11 +30,19 @@
+
+ + + + +
@@ -78,4 +86,4 @@ hide-view-per-page="true">
- \ No newline at end of file + diff --git a/awx/ui/client/src/activity-stream/factories/build-anchor.factory.js b/awx/ui/client/src/activity-stream/factories/build-anchor.factory.js index 09992c6029..7063f0110a 100644 --- a/awx/ui/client/src/activity-stream/factories/build-anchor.factory.js +++ b/awx/ui/client/src/activity-stream/factories/build-anchor.factory.js @@ -95,7 +95,7 @@ export default function BuildAnchor($log, $filter) { break; case 'workflow_approval': url += `workflows/${activity.summary_fields.workflow_job[0].id}`; - name = activity.summary_fields.workflow_job[0].name; + name = activity.summary_fields.workflow_job[0].name + ' | ' + activity.summary_fields.workflow_approval[0].name; break; default: url += resource + 's/' + obj.id + '/'; diff --git a/awx/ui/client/src/activity-stream/factories/build-description.factory.js b/awx/ui/client/src/activity-stream/factories/build-description.factory.js index ba82d5250f..4e25e21b48 100644 --- a/awx/ui/client/src/activity-stream/factories/build-description.factory.js +++ b/awx/ui/client/src/activity-stream/factories/build-description.factory.js @@ -132,7 +132,13 @@ export default function BuildDescription(BuildAnchor, $log, i18n) { if (activity.changes.status[1] === 'successful') { operationText = i18n._('approved'); } else if (activity.changes.status[1] === 'failed') { - operationText = i18n._('denied'); + if (activity.changes.timed_out && activity.changes.timed_out[1] === true) { + operationText = i18n._('timed out'); + } else { + operationText = i18n._('denied'); + } + } else { + operationText = i18n._('updated'); } activity.description = `${operationText} ${activity.object1} ${BuildAnchor(activity.summary_fields[activity.object1][0], activity.object1, activity)}`; } else {