mirror of
https://github.com/ansible/awx.git
synced 2026-03-27 22:05:07 -02:30
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:
@@ -2209,6 +2209,44 @@ class InventoryUpdateSerializer(UnifiedJobSerializer, InventorySourceOptionsSeri
|
|||||||
return res
|
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 InventoryUpdateListSerializer(InventoryUpdateSerializer, UnifiedJobListSerializer):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|||||||
@@ -1972,7 +1972,7 @@ class InventoryInventorySourcesUpdate(RetrieveAPIView):
|
|||||||
details['status'] = None
|
details['status'] = None
|
||||||
if inventory_source.can_update:
|
if inventory_source.can_update:
|
||||||
update = inventory_source.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['status'] = 'started'
|
||||||
details['inventory_update'] = update.id
|
details['inventory_update'] = update.id
|
||||||
successes += 1
|
successes += 1
|
||||||
@@ -2135,7 +2135,7 @@ class InventorySourceUpdateView(RetrieveAPIView):
|
|||||||
headers = {'Location': update.get_absolute_url(request=request)}
|
headers = {'Location': update.get_absolute_url(request=request)}
|
||||||
data = OrderedDict()
|
data = OrderedDict()
|
||||||
data['inventory_update'] = update.id
|
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)
|
return Response(data, status=status.HTTP_202_ACCEPTED, headers=headers)
|
||||||
else:
|
else:
|
||||||
return self.http_method_not_allowed(request, *args, **kwargs)
|
return self.http_method_not_allowed(request, *args, **kwargs)
|
||||||
@@ -2150,7 +2150,7 @@ class InventoryUpdateList(ListAPIView):
|
|||||||
class InventoryUpdateDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
|
class InventoryUpdateDetail(UnifiedJobDeletionMixin, RetrieveDestroyAPIView):
|
||||||
|
|
||||||
model = InventoryUpdate
|
model = InventoryUpdate
|
||||||
serializer_class = InventoryUpdateSerializer
|
serializer_class = InventoryUpdateDetailSerializer
|
||||||
|
|
||||||
|
|
||||||
class InventoryUpdateCredentialsList(SubListAPIView):
|
class InventoryUpdateCredentialsList(SubListAPIView):
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ class TestInventoryInventorySourcesUpdate:
|
|||||||
|
|
||||||
with mocker.patch.object(InventoryInventorySourcesUpdate, 'get_object', return_value=obj):
|
with mocker.patch.object(InventoryInventorySourcesUpdate, 'get_object', return_value=obj):
|
||||||
with mocker.patch.object(InventoryInventorySourcesUpdate, 'get_serializer_context', return_value=None):
|
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 = serializer_class.return_value
|
||||||
serializer.to_representation.return_value = {}
|
serializer.to_representation.return_value = {}
|
||||||
|
|
||||||
|
|||||||
@@ -187,6 +187,12 @@ function getInventorySourceDetails () {
|
|||||||
return null;
|
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 { source } = resource.model.get('summary_fields.inventory_source');
|
||||||
const choices = mapChoices(resource.model.options('actions.GET.source.choices'));
|
const choices = mapChoices(resource.model.options('actions.GET.source.choices'));
|
||||||
|
|
||||||
@@ -324,6 +330,33 @@ function getProjectUpdateDetails (updateId) {
|
|||||||
return { link, tooltip };
|
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 () {
|
function getSCMRevisionDetails () {
|
||||||
const label = strings.get('labels.SCM_REVISION');
|
const label = strings.get('labels.SCM_REVISION');
|
||||||
const value = resource.model.get('scm_revision');
|
const value = resource.model.get('scm_revision');
|
||||||
@@ -718,6 +751,7 @@ function JobDetailsController (
|
|||||||
vm.projectUpdate = getProjectUpdateDetails();
|
vm.projectUpdate = getProjectUpdateDetails();
|
||||||
vm.projectStatus = getProjectStatusDetails();
|
vm.projectStatus = getProjectStatusDetails();
|
||||||
vm.scmRevision = getSCMRevisionDetails();
|
vm.scmRevision = getSCMRevisionDetails();
|
||||||
|
vm.inventoryScm = getInventoryScmDetails();
|
||||||
vm.playbook = getPlaybookDetails();
|
vm.playbook = getPlaybookDetails();
|
||||||
vm.resultTraceback = getResultTracebackDetails();
|
vm.resultTraceback = getResultTracebackDetails();
|
||||||
vm.launchedBy = getLaunchedByDetails();
|
vm.launchedBy = getLaunchedByDetails();
|
||||||
@@ -748,12 +782,13 @@ function JobDetailsController (
|
|||||||
vm.toggleLabels = toggleLabels;
|
vm.toggleLabels = toggleLabels;
|
||||||
vm.showLabels = showLabels;
|
vm.showLabels = showLabels;
|
||||||
|
|
||||||
unsubscribe = subscribe(({ status, started, finished, scm, environment }) => {
|
unsubscribe = subscribe(({ status, started, finished, scm, inventoryScm, environment }) => {
|
||||||
vm.started = getStartDetails(started);
|
vm.started = getStartDetails(started);
|
||||||
vm.finished = getFinishDetails(finished);
|
vm.finished = getFinishDetails(finished);
|
||||||
vm.projectUpdate = getProjectUpdateDetails(scm.id);
|
vm.projectUpdate = getProjectUpdateDetails(scm.id);
|
||||||
vm.projectStatus = getProjectStatusDetails(scm.status);
|
vm.projectStatus = getProjectStatusDetails(scm.status);
|
||||||
vm.environment = getEnvironmentDetails(environment);
|
vm.environment = getEnvironmentDetails(environment);
|
||||||
|
vm.inventoryScm = getInventoryScmDetails(inventoryScm.id, inventoryScm.status);
|
||||||
vm.status = getStatusDetails(status);
|
vm.status = getStatusDetails(status);
|
||||||
vm.job.status = status;
|
vm.job.status = status;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -198,6 +198,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</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 -->
|
<!-- REVISION DETAIL -->
|
||||||
<div class="JobResults-resultRow" ng-if="vm.scmRevision">
|
<div class="JobResults-resultRow" ng-if="vm.scmRevision">
|
||||||
<label class="JobResults-resultRowLabel">{{ vm.scmRevision.label }}</label>
|
<label class="JobResults-resultRowLabel">{{ vm.scmRevision.label }}</label>
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ function OutputStrings (BaseString) {
|
|||||||
EXPAND_OUTPUT: t.s('Expand Output'),
|
EXPAND_OUTPUT: t.s('Expand Output'),
|
||||||
EXTRA_VARS: t.s('Read-only view of extra variables added to the job template'),
|
EXTRA_VARS: t.s('Read-only view of extra variables added to the job template'),
|
||||||
INVENTORY: t.s('View the Inventory'),
|
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'),
|
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'),
|
SLICE_JOB_DETAILS: t.s('Job is one of several from a JT that slices on inventory'),
|
||||||
PROJECT: t.s('View the Project'),
|
PROJECT: t.s('View the Project'),
|
||||||
@@ -54,6 +56,7 @@ function OutputStrings (BaseString) {
|
|||||||
FORKS: t.s('Forks'),
|
FORKS: t.s('Forks'),
|
||||||
INSTANCE_GROUP: t.s('Instance Group'),
|
INSTANCE_GROUP: t.s('Instance Group'),
|
||||||
INVENTORY: t.s('Inventory'),
|
INVENTORY: t.s('Inventory'),
|
||||||
|
INVENTORY_SCM: t.s('Source Project'),
|
||||||
JOB_EXPLANATION: t.s('Explanation'),
|
JOB_EXPLANATION: t.s('Explanation'),
|
||||||
JOB_TAGS: t.s('Job Tags'),
|
JOB_TAGS: t.s('Job Tags'),
|
||||||
JOB_TEMPLATE: t.s('Job Template'),
|
JOB_TEMPLATE: t.s('Job Template'),
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ function JobStatusService (moment, message) {
|
|||||||
id: model.get('summary_fields.project_update.id'),
|
id: model.get('summary_fields.project_update.id'),
|
||||||
status: model.get('summary_fields.project_update.status')
|
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 });
|
this.initHostStatusCounts({ model });
|
||||||
@@ -86,6 +90,7 @@ function JobStatusService (moment, message) {
|
|||||||
this.pushStatusEvent = data => {
|
this.pushStatusEvent = data => {
|
||||||
const isJobStatusEvent = (this.job === data.unified_job_id);
|
const isJobStatusEvent = (this.job === data.unified_job_id);
|
||||||
const isProjectStatusEvent = (this.project && (this.project === data.project_id));
|
const isProjectStatusEvent = (this.project && (this.project === data.project_id));
|
||||||
|
const isInventoryScmStatus = (this.model.get('source_project_update') === data.unified_job_id);
|
||||||
|
|
||||||
if (isJobStatusEvent) {
|
if (isJobStatusEvent) {
|
||||||
this.setJobStatus(data.status);
|
this.setJobStatus(data.status);
|
||||||
@@ -94,6 +99,10 @@ function JobStatusService (moment, message) {
|
|||||||
this.setProjectStatus(data.status);
|
this.setProjectStatus(data.status);
|
||||||
this.setProjectUpdateId(data.unified_job_id);
|
this.setProjectUpdateId(data.unified_job_id);
|
||||||
this.dispatch();
|
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.state.scm.id = id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.setInventoryScmStatus = status => {
|
||||||
|
this.state.inventoryScm.status = status;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setInventoryScmId = id => {
|
||||||
|
this.state.inventoryScm.id = id;
|
||||||
|
};
|
||||||
|
|
||||||
this.setFinished = time => {
|
this.setFinished = time => {
|
||||||
if (!time) return;
|
if (!time) return;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user