mirror of
https://github.com/ansible/awx.git
synced 2026-01-15 03:40:42 -03:30
project: Add last job status as for feedback feature.
This commit is contained in:
parent
f5c176701b
commit
03d8987d93
@ -24,6 +24,7 @@ import ProjectDetail from './ProjectDetail';
|
||||
import ProjectEdit from './ProjectEdit';
|
||||
import ProjectJobTemplatesList from './ProjectJobTemplatesList';
|
||||
import { OrganizationsAPI, ProjectsAPI } from '../../api';
|
||||
import useWsProject from './useWsProject';
|
||||
|
||||
function Project({ i18n, setBreadcrumb }) {
|
||||
const { me = {} } = useConfig();
|
||||
@ -32,7 +33,7 @@ function Project({ i18n, setBreadcrumb }) {
|
||||
|
||||
const {
|
||||
request: fetchProjectAndRoles,
|
||||
result: { project, isNotifAdmin },
|
||||
result: { projectDetail, isNotifAdmin },
|
||||
isLoading: hasContentLoading,
|
||||
error: contentError,
|
||||
} = useRequest(
|
||||
@ -58,12 +59,12 @@ function Project({ i18n, setBreadcrumb }) {
|
||||
data.summary_fields.credentials = results;
|
||||
}
|
||||
return {
|
||||
project: data,
|
||||
projectDetail: data,
|
||||
isNotifAdmin: notifAdminRes.data.results.length > 0,
|
||||
};
|
||||
}, [id]),
|
||||
{
|
||||
project: null,
|
||||
projectDetail: null,
|
||||
notifAdminRes: null,
|
||||
}
|
||||
);
|
||||
@ -73,10 +74,12 @@ function Project({ i18n, setBreadcrumb }) {
|
||||
}, [fetchProjectAndRoles, location.pathname]);
|
||||
|
||||
useEffect(() => {
|
||||
if (project) {
|
||||
setBreadcrumb(project);
|
||||
if (projectDetail) {
|
||||
setBreadcrumb(projectDetail);
|
||||
}
|
||||
}, [project, setBreadcrumb]);
|
||||
}, [projectDetail, setBreadcrumb]);
|
||||
|
||||
const project = useWsProject(projectDetail);
|
||||
|
||||
const loadScheduleOptions = useCallback(() => {
|
||||
return ProjectsAPI.readScheduleOptions(project.id);
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import React, { Fragment, useCallback } from 'react';
|
||||
import { Link, useHistory } from 'react-router-dom';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { Button, List, ListItem } from '@patternfly/react-core';
|
||||
import { Button, List, ListItem, Tooltip } from '@patternfly/react-core';
|
||||
import { Project } from '../../../types';
|
||||
import { Config } from '../../../contexts/Config';
|
||||
|
||||
@ -22,6 +22,8 @@ import { toTitleCase } from '../../../util/strings';
|
||||
import useRequest, { useDismissableError } from '../../../util/useRequest';
|
||||
import { relatedResourceDeleteRequests } from '../../../util/getRelatedResourceDeleteDetails';
|
||||
import ProjectSyncButton from '../shared/ProjectSyncButton';
|
||||
import StatusLabel from '../../../components/StatusLabel';
|
||||
import { formatDateString } from '../../../util/dates';
|
||||
|
||||
function ProjectDetail({ project, i18n }) {
|
||||
const {
|
||||
@ -84,9 +86,44 @@ function ProjectDetail({ project, i18n }) {
|
||||
);
|
||||
}
|
||||
|
||||
const generateLastJobTooltip = job => {
|
||||
return (
|
||||
<Fragment>
|
||||
<div>{i18n._(t`MOST RECENT SYNC`)}</div>
|
||||
<div>
|
||||
{i18n._(t`JOB ID:`)} {job.id}
|
||||
</div>
|
||||
<div>
|
||||
{i18n._(t`STATUS:`)} {job.status.toUpperCase()}
|
||||
</div>
|
||||
{job.finished && (
|
||||
<div>
|
||||
{i18n._(t`FINISHED:`)} {formatDateString(job.finished)}
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<CardBody>
|
||||
<DetailList gutter="sm">
|
||||
<Detail
|
||||
label={i18n._(t`Last Job Status`)}
|
||||
value={
|
||||
summary_fields.last_job && (
|
||||
<Tooltip
|
||||
position="top"
|
||||
content={generateLastJobTooltip(summary_fields.last_job)}
|
||||
key={summary_fields.last_job.id}
|
||||
>
|
||||
<Link to={`/jobs/project/${summary_fields.last_job.id}`}>
|
||||
<StatusLabel status={summary_fields.last_job.status} />
|
||||
</Link>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Detail
|
||||
label={i18n._(t`Name`)}
|
||||
value={name}
|
||||
|
||||
68
awx/ui_next/src/screens/Project/useWsProject.js
Normal file
68
awx/ui_next/src/screens/Project/useWsProject.js
Normal file
@ -0,0 +1,68 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import useWebsocket from '../../util/useWebsocket';
|
||||
|
||||
export default function useWsProjects(initialProject) {
|
||||
const [project, setProject] = useState(initialProject);
|
||||
const lastMessage = useWebsocket({
|
||||
jobs: ['status_changed'],
|
||||
control: ['limit_reached_1'],
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setProject(initialProject);
|
||||
}, [initialProject]);
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
if (
|
||||
!project ||
|
||||
!lastMessage?.unified_job_id ||
|
||||
lastMessage.type !== 'project_update'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const last_status = project.summary_fields.last_job.status;
|
||||
|
||||
// In case if users spam the sync button, we will need to ensure
|
||||
// the fluent UI on most recent sync tooltip and last job status.
|
||||
// Thus, we will not update our last job status to `Pending` if
|
||||
// there is current running job.
|
||||
//
|
||||
// For instance, we clicked sync for particular project for twice.
|
||||
// For first sync, our last job status should immediately change
|
||||
// to `Pending`, then `Waiting`, then `Running`, then result
|
||||
// (which are `successful`, `failed`, `error`, `cancelled`.
|
||||
// For second sync, if the status response is `pending` and we have
|
||||
// running and waiting jobs, we should not update our UI to `Pending`,
|
||||
// otherwise our most recent sync tooltip UI will lose our current running
|
||||
// job and we cannot navigate to the job link through the link provided
|
||||
// by most recent sync tooltip.
|
||||
//
|
||||
// More ideally, we should prevent any spamming on sync button using
|
||||
// backend logic to reduce overload on server and we can have a
|
||||
// less complex frontend implementation for fluent UI
|
||||
if (
|
||||
lastMessage.status === 'pending' &&
|
||||
!['successful', 'failed', 'error', 'cancelled'].includes(last_status)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const updatedProject = {
|
||||
...project,
|
||||
summary_fields: {
|
||||
...project.summary_fields,
|
||||
last_job: {
|
||||
id: lastMessage.unified_job_id,
|
||||
status: lastMessage.status,
|
||||
finished: lastMessage.finished,
|
||||
},
|
||||
},
|
||||
};
|
||||
setProject(updatedProject);
|
||||
},
|
||||
[lastMessage] // eslint-disable-line react-hooks/exhaustive-deps
|
||||
);
|
||||
|
||||
return project;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user