Skip to content

Commit

Permalink
Fixes theforeman#264 - Add last configuration status card
Browse files Browse the repository at this point in the history
  • Loading branch information
nadjaheitmann authored and stejskalleos committed Jan 18, 2024
1 parent c2d55a7 commit 3649503
Show file tree
Hide file tree
Showing 6 changed files with 205 additions and 1 deletion.
2 changes: 1 addition & 1 deletion webpack/src/Extends/Host/PuppetTab/Routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Reports from './SubTabs/Reports';
import ENCPreview from './SubTabs/ENCPreview';

const SecondaryTabRoutes = ({ hostName, hostInfo, status }) => (
<Switch>
<Switch ouiaId="foreman-puppet-switch">
<Route path={route('reports')}>
<Reports hostName={hostName} hostInfo={hostInfo} status={status} />
</Route>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { API_OPERATIONS, get } from 'foremanReact/redux/API';
import { FOREMAN_PUPPET_LAST_REPORT_KEY } from './ConfigStatusCardConstants';

export const getReportByIdAction = reportId =>
get({
type: API_OPERATIONS.GET,
key: FOREMAN_PUPPET_LAST_REPORT_KEY,
url: `/api/config_reports/${reportId}`,
});
export default getReportByIdAction;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const FOREMAN_PUPPET_LAST_REPORT_KEY = 'FOREMAN_PUPPET_LAST_REPORT';
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import PropTypes from 'prop-types';
import React, { useCallback, useEffect } from 'react';
import {
Divider,
Flex,
FlexItem,
Button,
DescriptionList,
DescriptionListTerm,
DescriptionListGroup,
DescriptionListDescription,
} from '@patternfly/react-core';
import {
TableComposable,
TableText,
Tr,
Tbody,
Td,
} from '@patternfly/react-table';
import { useSelector, useDispatch } from 'react-redux';
import { selectAPIResponse } from 'foremanReact/redux/API/APISelectors';
import CardTemplate from 'foremanReact/components/HostDetails/Templates/CardItem/CardTemplate';
import RelativeDateTime from 'foremanReact/components/common/dates/RelativeDateTime';
import SkeletonLoader from 'foremanReact/components/common/SkeletonLoader';
import DefaultLoaderEmptyState from 'foremanReact/components/HostDetails/DetailsCard/DefaultLoaderEmptyState';
import { statusFormatter } from 'foremanReact/components/HostDetails/Tabs/ReportsTab/helpers';
import { translate as __ } from 'foremanReact/common/I18n';

import { getReportByIdAction } from './ConfigStatusCardActions';
import { FOREMAN_PUPPET_LAST_REPORT_KEY } from './ConfigStatusCardConstants';
import './styles.scss';

const cardHeaderDivider = () => (
<Divider
orientation={{
default: 'vertical',
}}
inset={{ default: 'insetMd' }}
/>
);

const generateCardHeader = (allReports = [], reportsCount) =>
reportsCount > 0 ? (
<>
{__('Last configuration status')}
<Flex>
<FlexItem>
<Button
ouiaId="foreman-puppet-last-report-button"
variant="link"
component="a"
isInline
isDisabled={!allReports.length}
href={`/config_reports/${allReports[0].id}`}
>
<RelativeDateTime
date={allReports[0].reported_at}
defaultValue={__('Never')}
/>
</Button>
</FlexItem>
<FlexItem>{statusFormatter('failed', allReports[0])}</FlexItem>
{cardHeaderDivider()}
<FlexItem>{statusFormatter('failed_restarts', allReports[0])}</FlexItem>
{cardHeaderDivider()}
<FlexItem>{statusFormatter('restarted', allReports[0])}</FlexItem>
{cardHeaderDivider()}
<FlexItem>{statusFormatter('applied', allReports[0])}</FlexItem>
{cardHeaderDivider()}
<FlexItem>{statusFormatter('skipped', allReports[0])}</FlexItem>
{cardHeaderDivider()}
<FlexItem>{statusFormatter('pending', allReports[0])}</FlexItem>
</Flex>
</>
) : (
<> {__('No configuration status available')} </>
);

const createPuppetMetricsTableElement = (name, value = '--') => (
<>
<Td modifier="truncate" key={`metrics-name-${name}`}>
<TableText
className={name === 'Total' ? 'last-config-puppet-metrics-total' : ''}
>
{name}
</TableText>
</Td>
<Td modifier="truncate" key={`metrics-name-${value}`}>
<TableText
className={name === 'Total' ? 'last-config-puppet-metrics-total' : ''}
>
{value}
</TableText>
</Td>
</>
);

const createPuppetMetricsTable = (metrics = undefined) => (
<TableComposable
aria-label="foreman puppet metrics table"
variant="compact"
borders="compactBorderless"
ouiaId="foreman-puppet-metrics-table"
key="foreman-puppet-metrics-table"
>
<Tbody>
<Tr>
{createPuppetMetricsTableElement(__('Failed'), metrics.failed)}
{createPuppetMetricsTableElement(__('Changed'), metrics.changed)}
{createPuppetMetricsTableElement(__('Scheduled'), metrics.scheduled)}
</Tr>
<Tr>
{createPuppetMetricsTableElement(
__('Failed to start'),
metrics.failed_to_start
)}
{createPuppetMetricsTableElement(__('Restarted'), metrics.restarted)}
{createPuppetMetricsTableElement(
__('Corrective Change'),
metrics.corrective_change
)}
</Tr>
<Tr>
{createPuppetMetricsTableElement(__('Skipped'), metrics.skipped)}
{createPuppetMetricsTableElement(
__('Out of sync'),
metrics.out_of_sync
)}
{createPuppetMetricsTableElement(__('Total'), metrics.total)}
</Tr>
</Tbody>
</TableComposable>
);

const ConfigStatusCard = ({ hostName, parentStatus }) => {
const dispatch = useDispatch();
// get already fetched results from reports tab
const API_KEY = `get-reports-${hostName}`;
const { reports, itemCount } = useSelector(state =>
selectAPIResponse(state, API_KEY)
);

// we need to fetch the last Puppet report to get all Puppet metrics
const getLastReport = useCallback(() => {
if (hostName && reports?.length)
dispatch(getReportByIdAction(reports[0].id));
}, [hostName, reports, dispatch]);

useEffect(() => {
getLastReport();
}, [hostName, reports]);

const { metrics } = useSelector(state =>
selectAPIResponse(state, FOREMAN_PUPPET_LAST_REPORT_KEY)
);

return (
<CardTemplate header={generateCardHeader(reports, itemCount)} expandable>
<DescriptionList isCompact>
<DescriptionListGroup>
<DescriptionListTerm>{__('Puppet metrics')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
status={parentStatus}
emptyState={<DefaultLoaderEmptyState />}
>
{metrics && createPuppetMetricsTable(metrics.resources)}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
</CardTemplate>
);
};

ConfigStatusCard.propTypes = {
hostName: PropTypes.string,
parentStatus: PropTypes.string,
};

ConfigStatusCard.defaultProps = {
hostName: undefined,
parentStatus: undefined,
};

export default ConfigStatusCard;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.last-config-puppet-metrics-total {
font-weight: bold;
}
4 changes: 4 additions & 0 deletions webpack/src/Extends/Host/PuppetTab/SubTabs/Reports/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React from 'react';
import { Grid, GridItem } from '@patternfly/react-core';
import ReportsTab from 'foremanReact/components/HostDetails/Tabs/ReportsTab';
import DescriptionCard from './components/DescriptionCard';
import ConfigStatusCard from './components/ConfigStatusCard';
import './styles.scss';

const Reports = ({
Expand All @@ -18,6 +19,9 @@ const Reports = ({
}) => (
<div className="report-tab">
<Grid hasGutter>
<GridItem span={8}>
<ConfigStatusCard hostName={hostName} parentStatus={status} />
</GridItem>
<GridItem span={4}>
<DescriptionCard
proxyName={proxyName}
Expand Down

0 comments on commit 3649503

Please sign in to comment.