Skip to content

Commit

Permalink
Fixes #37122 - Update system status chart in job invocations detail page
Browse files Browse the repository at this point in the history
  • Loading branch information
kmalyjur committed Jan 30, 2024
1 parent 9c0e2e4 commit 1a314dc
Show file tree
Hide file tree
Showing 7 changed files with 225 additions and 32 deletions.
2 changes: 2 additions & 0 deletions app/views/api/v2/job_invocations/base.json.rabl
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ node do |invocation|
:succeeded => invocation_count(invocation, :output_key => :success_count),
:failed => invocation_count(invocation, :output_key => :failed_count),
:pending => invocation_count(invocation, :output_key => :pending_count),
:cancelled => invocation_count(invocation, :output_key => :cancelled_count),
:total => invocation_count(invocation, :output_key => :total_count),
:missing => invocation.missing_hosts_count,
:total_hosts => invocation.total_hosts_count,
}
end

Expand Down
10 changes: 10 additions & 0 deletions webpack/JobInvocationDetail/JobInvocationConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,13 @@ export const STATUS = {
SUCCEEDED: 'succeeded',
FAILED: 'failed',
};

export const DATE_OPTIONS = {
day: 'numeric',
month: 'short',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
hour12: false,
timeZoneName: 'short',
};
42 changes: 42 additions & 0 deletions webpack/JobInvocationDetail/JobInvocationDetail.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.chart-donut {
height: 105px;
width: 105px;

.pf-c-chart {
.pf-c-chart-donut__label__title {
font-size: 50px; // 20 // does not work
background-color: blue;
}
}

.pf-c-chart-donut__label__subtitle {
font-size: 50px; // 12 // does not work
fill: #6A6E73;
background-color: green;
}
}

.chart-legend {
height: 105px;
width: 270px;

.legend-title {
font-weight: bold;
font-size: 14px;
margin-left: 8px;
margin-bottom: 0;
}

.pf-c-description-list {
margin-left: 8px;
margin-top: 8px;

.pf-c-description-list__term .pf-c-description-list__text {
font-weight: normal;
}
}
}

// přidat mezeru pod chart když je menší obrazovka
// ještě style z index.js
// barva prázdného chart je nějaká čudná
34 changes: 9 additions & 25 deletions webpack/JobInvocationDetail/JobInvocationOverview.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@ import {
DescriptionListGroup,
DescriptionListDescription,
} from '@patternfly/react-core';
import { translate as __ } from 'foremanReact/common/I18n';
import DefaultLoaderEmptyState from 'foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState';
import { translate as __, documentLocale } from 'foremanReact/common/I18n';

const JobInvocationOverview = ({ data }) => {
const JobInvocationOverview = ({
data,
isAlreadyStarted,
formattedStartDate,
}) => {
const {
start_at: startAt,
ssh_user: sshUser,
template_id: templateId,
template_name: templateName,
Expand All @@ -22,27 +25,6 @@ const JobInvocationOverview = ({ data }) => {
const canEditJobTemplates = permissions
? permissions.edit_job_templates
: false;
const dateOptions = {
day: 'numeric',
month: 'short',
year: 'numeric',
hour: '2-digit',
minute: '2-digit',
hour12: false,
timeZoneName: 'short',
};
let formattedStartDate = __('Not yet');

if (startAt) {
// Ensures date string compatibility across browsers
const convertedDate = new Date(startAt.replace(/[-.]/g, '/'));
if (convertedDate.getTime() <= new Date().getTime()) {
formattedStartDate = convertedDate.toLocaleString(
documentLocale(),
dateOptions
);
}
}

return (
<DescriptionList
Expand All @@ -63,7 +45,7 @@ const JobInvocationOverview = ({ data }) => {
<DescriptionListGroup>
<DescriptionListTerm>{__('Started at:')}</DescriptionListTerm>
<DescriptionListDescription>
{formattedStartDate}
{isAlreadyStarted ? formattedStartDate : __('Not yet')}
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
Expand Down Expand Up @@ -99,6 +81,8 @@ const JobInvocationOverview = ({ data }) => {

JobInvocationOverview.propTypes = {
data: PropTypes.object.isRequired,
isAlreadyStarted: PropTypes.bool.isRequired,
formattedStartDate: PropTypes.string.isRequired,
};

export default JobInvocationOverview;
119 changes: 119 additions & 0 deletions webpack/JobInvocationDetail/JobInvocationSystemStatusChart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import React from 'react';
import PropTypes from 'prop-types';
import { ChartDonut, ChartLabel, ChartLegend } from '@patternfly/react-charts';
import {
DescriptionList,
DescriptionListTerm,
DescriptionListGroup,
DescriptionListDescription,
FlexItem,
Text,
} from '@patternfly/react-core';
import { translate as __ } from 'foremanReact/common/I18n';
import './JobInvocationDetail.scss';

const JobInvocationSystemStatusChart = ({
data,
isAlreadyStarted,
formattedStartDate,
}) => {
const {
succeeded,
failed,
pending,
cancelled,
total,
total_hosts: totalHosts,
} = data;
const chartData = [
{ title: __('Succeeded:'), count: succeeded, color: '#3E8635' },
{ title: __('Failed:'), count: failed, color: '#C9190B' },
{ title: __('In Progress:'), count: pending, color: '#2B9AF3' },
{ title: __('Canceled:'), count: cancelled, color: '#6A6E73' },
];
const chartDonutTitle = () => {
if (total > 0) return `${succeeded.toString()}/${total}`;
if (totalHosts > 0) return `0/${totalHosts}`;
return '0';
};

return (
<>
<FlexItem className="chart-donut">
<ChartDonut
constrainToVisibleArea
data={chartData.map(d => ({
label: `${d.title} ${d.count} hosts`,
y: d.count,
}))}
colorScale={total > 0 ? chartData.map(d => d.color) : ['#8A8D90']}
subTitle={__('Systems')}
title={chartDonutTitle}
titleComponent={<ChartLabel />}
subTitleComponent={<ChartLabel />}
padding={{
bottom: 0,
left: 0,
right: 0,
top: 0,
}}
width={105}
height={105}
/>
</FlexItem>
<FlexItem className="chart-legend">
<Text className="legend-title">{__('System status')}</Text>
{isAlreadyStarted ? (
<ChartLegend
orientation="vertical"
itemsPerRow={2}
gutter={25}
rowGutter={7}
rowGu
padding={{
bottom: 0,
left: 15,
right: 0,
top: 0,
}}
data={chartData.map(d => ({
name: `${d.title} ${d.count}`,
symbol: { type: 'circle' },
}))}
colorScale={chartData.map(d => d.color)}
width={270}
height={105}
/>
) : (
<DescriptionList
// style={{
// marginLeft: 8,
// marginTop: 8,
// }}
>
<DescriptionListGroup>
<DescriptionListTerm
// style={{
// fontWeight: 'normal',
// }}
>
{__('Scheduled at:')}
</DescriptionListTerm>
<DescriptionListDescription>
{formattedStartDate}
</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
)}
</FlexItem>
</>
);
};

JobInvocationSystemStatusChart.propTypes = {
data: PropTypes.object.isRequired,
isAlreadyStarted: PropTypes.bool.isRequired,
formattedStartDate: PropTypes.string.isRequired,
};

export default JobInvocationSystemStatusChart;
48 changes: 42 additions & 6 deletions webpack/JobInvocationDetail/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import React, { useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import PropTypes from 'prop-types';
import { Divider, PageSection, Flex, FlexItem } from '@patternfly/react-core';
import { translate as __ } from 'foremanReact/common/I18n';
import { translate as __, documentLocale } from 'foremanReact/common/I18n'; // documentlocale
import PageLayout from 'foremanReact/routes/common/PageLayout/PageLayout';
import { stopInterval } from 'foremanReact/redux/middlewares/IntervalMiddleware';
import { getData } from './JobInvocationActions';
import { selectItems } from './JobInvocationSelectors';
import JobInvocationOverview from './JobInvocationOverview';
import { JOB_INVOCATION_KEY, STATUS } from './JobInvocationConstants';
import JobInvocationSystemStatusChart from './JobInvocationSystemStatusChart';
import {
JOB_INVOCATION_KEY,
STATUS,
DATE_OPTIONS,
} from './JobInvocationConstants';

const JobInvocationDetailPage = ({
match: {
Expand All @@ -17,11 +22,28 @@ const JobInvocationDetailPage = ({
}) => {
const dispatch = useDispatch();
const items = useSelector(selectItems);
const { description, status_label: statusLabel, task } = items;
const {
description,
status_label: statusLabel,
task,
start_at: startAt,
} = items;
const finished =
statusLabel === STATUS.FAILED || statusLabel === STATUS.SUCCEEDED;
const autoRefresh = task?.state === STATUS.PENDING || false;

let isAlreadyStarted = false;
let formattedStartDate;
if (startAt) {
// Ensures date string compatibility across browsers
const convertedDate = new Date(startAt.replace(/[-.]/g, '/'));
isAlreadyStarted = convertedDate.getTime() <= new Date().getTime();
formattedStartDate = convertedDate.toLocaleString(
documentLocale(),
DATE_OPTIONS
);
}

useEffect(() => {
dispatch(getData(`/api/job_invocations/${id}`));
if (finished && !autoRefresh) {
Expand Down Expand Up @@ -49,15 +71,29 @@ const JobInvocationDetailPage = ({
>
<React.Fragment>
<PageSection isFilled variant="light">
<Flex>
<FlexItem> </FlexItem>
<Flex
// justifyContent="justifyContentSpaceAround"
style={{ marginBottom: '16px' }} // does not work
alignItems={{ default: 'alignItemsCenter' }}
>
<JobInvocationSystemStatusChart
data={items}
isAlreadyStarted={isAlreadyStarted}
formattedStartDate={formattedStartDate}
/>

<Divider
orientation={{
default: 'vertical',
}}
/>

<FlexItem>
<JobInvocationOverview data={items} />
<JobInvocationOverview
data={items}
isAlreadyStarted={isAlreadyStarted}
formattedStartDate={formattedStartDate}
/>
</FlexItem>
</Flex>
</PageSection>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const AggregateStatus = ({ statuses, chartFilter }) => (
>
<span id="success_count">
<span className="pficon pficon-ok" />
{statuses.success}
{5}
</span>
</a>

Expand Down

0 comments on commit 1a314dc

Please sign in to comment.