1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 08:21:15 +03:00

Merge pull request #3061 from jakemcdermott/inventory-scm-job-linkage

add linked status indicator for scm inventory project updates

Reviewed-by: https://github.com/softwarefactory-project-zuul[bot]
This commit is contained in:
softwarefactory-project-zuul[bot] 2019-01-25 13:05:36 +00:00 committed by GitHub
commit 2a86c5b944
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 119 additions and 5 deletions

View File

@ -2209,6 +2209,44 @@ class InventoryUpdateSerializer(UnifiedJobSerializer, InventorySourceOptionsSeri
return res
class InventoryUpdateDetailSerializer(InventoryUpdateSerializer):
source_project = serializers.SerializerMethodField(
help_text=_('The project used for this job.'),
method_name='get_source_project_id'
)
class Meta:
model = InventoryUpdate
fields = ('*', 'source_project',)
def get_source_project(self, obj):
return getattrd(obj, 'source_project_update.unified_job_template', None)
def get_source_project_id(self, obj):
return getattrd(obj, 'source_project_update.unified_job_template.id', None)
def get_related(self, obj):
res = super(InventoryUpdateDetailSerializer, self).get_related(obj)
source_project_id = self.get_source_project_id(obj)
if source_project_id:
res['source_project'] = self.reverse('api:project_detail', kwargs={'pk': source_project_id})
return res
def get_summary_fields(self, obj):
summary_fields = super(InventoryUpdateDetailSerializer, self).get_summary_fields(obj)
summary_obj = self.get_source_project(obj)
if summary_obj:
summary_fields['source_project'] = {}
for field in SUMMARIZABLE_FK_FIELDS['project']:
value = getattr(summary_obj, field, None)
if value is not None:
summary_fields['source_project'][field] = value
return summary_fields
class InventoryUpdateListSerializer(InventoryUpdateSerializer, UnifiedJobListSerializer):
class Meta:

View File

@ -1972,7 +1972,7 @@ class InventoryInventorySourcesUpdate(RetrieveAPIView):
details['status'] = None
if inventory_source.can_update:
update = inventory_source.update()
details.update(InventoryUpdateSerializer(update, context=self.get_serializer_context()).to_representation(update))
details.update(InventoryUpdateDetailSerializer(update, context=self.get_serializer_context()).to_representation(update))
details['status'] = 'started'
details['inventory_update'] = update.id
successes += 1
@ -2135,7 +2135,7 @@ class InventorySourceUpdateView(RetrieveAPIView):
headers = {'Location': update.get_absolute_url(request=request)}
data = OrderedDict()
data['inventory_update'] = update.id
data.update(InventoryUpdateSerializer(update, context=self.get_serializer_context()).to_representation(update))
data.update(InventoryUpdateDetailSerializer(update, context=self.get_serializer_context()).to_representation(update))
return Response(data, status=status.HTTP_202_ACCEPTED, headers=headers)
else:
return self.http_method_not_allowed(request, *args, **kwargs)
@ -2150,7 +2150,7 @@ class InventoryUpdateList(ListAPIView):
class InventoryUpdateDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
model = InventoryUpdate
serializer_class = InventoryUpdateSerializer
serializer_class = InventoryUpdateDetailSerializer
class InventoryUpdateCredentialsList(SubListAPIView):

View File

@ -113,7 +113,7 @@ class TestInventoryInventorySourcesUpdate:
with mocker.patch.object(InventoryInventorySourcesUpdate, 'get_object', return_value=obj):
with mocker.patch.object(InventoryInventorySourcesUpdate, 'get_serializer_context', return_value=None):
with mocker.patch('awx.api.views.InventoryUpdateSerializer') as serializer_class:
with mocker.patch('awx.api.views.InventoryUpdateDetailSerializer') as serializer_class:
serializer = serializer_class.return_value
serializer.to_representation.return_value = {}

View File

@ -187,6 +187,12 @@ function getInventorySourceDetails () {
return null;
}
if (resource.model.get('summary_fields.inventory_source.source') === 'scm') {
// we already show a SOURCE PROJECT item for scm inventory updates, so we
// skip the display of the standard source details item.
return null;
}
const { source } = resource.model.get('summary_fields.inventory_source');
const choices = mapChoices(resource.model.options('actions.GET.source.choices'));
@ -324,6 +330,33 @@ function getProjectUpdateDetails (updateId) {
return { link, tooltip };
}
function getInventoryScmDetails (updateId, updateStatus) {
const projectId = resource.model.get('summary_fields.source_project.id');
const projectName = resource.model.get('summary_fields.source_project.name');
const jobId = updateId || resource.model.get('source_project_update');
const status = updateStatus || resource.model.get('summary_fields.inventory_source.status');
if (!projectId || !projectName) {
return null;
}
const label = strings.get('labels.INVENTORY_SCM');
const jobLink = `/#/jobs/project/${jobId}`;
const link = `/#/projects/${projectId}`;
const jobTooltip = strings.get('tooltips.INVENTORY_SCM_JOB');
const tooltip = strings.get('tooltips.INVENTORY_SCM');
let icon;
if (status === 'unknown') {
icon = 'fa icon-job-pending';
} else {
icon = `fa icon-job-${status}`;
}
return { label, link, icon, jobLink, jobTooltip, tooltip, value: projectName };
}
function getSCMRevisionDetails () {
const label = strings.get('labels.SCM_REVISION');
const value = resource.model.get('scm_revision');
@ -718,6 +751,7 @@ function JobDetailsController (
vm.projectUpdate = getProjectUpdateDetails();
vm.projectStatus = getProjectStatusDetails();
vm.scmRevision = getSCMRevisionDetails();
vm.inventoryScm = getInventoryScmDetails();
vm.playbook = getPlaybookDetails();
vm.resultTraceback = getResultTracebackDetails();
vm.launchedBy = getLaunchedByDetails();
@ -748,12 +782,13 @@ function JobDetailsController (
vm.toggleLabels = toggleLabels;
vm.showLabels = showLabels;
unsubscribe = subscribe(({ status, started, finished, scm, environment }) => {
unsubscribe = subscribe(({ status, started, finished, scm, inventoryScm, environment }) => {
vm.started = getStartDetails(started);
vm.finished = getFinishDetails(finished);
vm.projectUpdate = getProjectUpdateDetails(scm.id);
vm.projectStatus = getProjectStatusDetails(scm.status);
vm.environment = getEnvironmentDetails(environment);
vm.inventoryScm = getInventoryScmDetails(inventoryScm.id, inventoryScm.status);
vm.status = getStatusDetails(status);
vm.job.status = status;
});

View File

@ -198,6 +198,27 @@
</div>
</div>
<!-- INVENTORY SCM DETAIL -->
<div class="JobResults-resultRow" ng-if="!vm.project && vm.inventoryScm">
<label class="JobResults-resultRowLabel">{{ vm.inventoryScm.label }}</label>
<div class="JobResults-resultRowText">
<span>
<a href="{{ vm.inventoryScm.jobLink }}"
aw-tool-tip="{{ vm.inventoryScm.jobTooltip }}"
data-placement="top">
<i class="JobResults-statusResultIcon {{ vm.inventoryScm.icon }}"></i>
</a>
</span>
<span>
<a href="{{ vm.inventoryScm.link }}"
aw-tool-tip="{{ vm.inventoryScm.tooltip }}"
data-placement="top">
{{ vm.inventoryScm.value }}
</a>
</span>
</div>
</div>
<!-- REVISION DETAIL -->
<div class="JobResults-resultRow" ng-if="vm.scmRevision">
<label class="JobResults-resultRowLabel">{{ vm.scmRevision.label }}</label>

View File

@ -22,6 +22,8 @@ function OutputStrings (BaseString) {
EXPAND_OUTPUT: t.s('Expand Output'),
EXTRA_VARS: t.s('Read-only view of extra variables added to the job template'),
INVENTORY: t.s('View the Inventory'),
INVENTORY_SCM: t.s('View the Project'),
INVENTORY_SCM_JOB: t.s('View Project checkout results'),
JOB_TEMPLATE: t.s('View the Job Template'),
SLICE_JOB_DETAILS: t.s('Job is one of several from a JT that slices on inventory'),
PROJECT: t.s('View the Project'),
@ -54,6 +56,7 @@ function OutputStrings (BaseString) {
FORKS: t.s('Forks'),
INSTANCE_GROUP: t.s('Instance Group'),
INVENTORY: t.s('Inventory'),
INVENTORY_SCM: t.s('Source Project'),
JOB_EXPLANATION: t.s('Explanation'),
JOB_TAGS: t.s('Job Tags'),
JOB_TEMPLATE: t.s('Job Template'),

View File

@ -44,6 +44,10 @@ function JobStatusService (moment, message) {
id: model.get('summary_fields.project_update.id'),
status: model.get('summary_fields.project_update.status')
},
inventoryScm: {
id: model.get('source_project_update'),
status: model.get('summary_fields.inventory_source.status')
}
};
this.initHostStatusCounts({ model });
@ -86,6 +90,7 @@ function JobStatusService (moment, message) {
this.pushStatusEvent = data => {
const isJobStatusEvent = (this.job === data.unified_job_id);
const isProjectStatusEvent = (this.project && (this.project === data.project_id));
const isInventoryScmStatus = (this.model.get('source_project_update') === data.unified_job_id);
if (isJobStatusEvent) {
this.setJobStatus(data.status);
@ -94,6 +99,10 @@ function JobStatusService (moment, message) {
this.setProjectStatus(data.status);
this.setProjectUpdateId(data.unified_job_id);
this.dispatch();
} else if (isInventoryScmStatus) {
this.setInventoryScmStatus(data.status);
this.setInventoryScmId(data.unified_job_id);
this.dispatch();
}
};
@ -249,6 +258,14 @@ function JobStatusService (moment, message) {
this.state.scm.id = id;
};
this.setInventoryScmStatus = status => {
this.state.inventoryScm.status = status;
};
this.setInventoryScmId = id => {
this.state.inventoryScm.id = id;
};
this.setFinished = time => {
if (!time) return;