Project

General

Profile

« Previous | Next » 

Revision 71ce89cb

Added by Amir Fefer over 2 years ago

Fixes #34142 - make the core cards arrangeable in new host page (#8995)

View differences:

webpack/assets/javascripts/react_app/components/HostDetails/Audits/index.js
DataListItemCells,
DataListText,
DataListCell,
GridItem,
Title,
} from '@patternfly/react-core';
import URI from 'urijs';
......
status = STATUS.PENDING,
} = useAPI('get', apiUrl);
return (
<Card isHoverable>
<CardHeader>
<CardTitle>{__('Recent Audits')}</CardTitle>
<CardActions>
<a onClick={() => dispatch(push(uiUrl))}> {__('All audits')}</a>
</CardActions>
</CardHeader>
<CardBody>
<SkeletonLoader
skeletonProps={{ count: NUMBER_OF_RECORDS }}
status={status}
emptyState={
<Bullseye>
<Title headingLevel="h4"> {__('No Results found')} </Title>
</Bullseye>
}
>
{audits && (
<DataList isCompact>
{audits.map(
({ user_name: user, created_at: timestamp, action, id }) => (
<DataListItem key={id}>
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell
wrapModifier="truncate"
key={`action-${id}`}
>
<DataListText tooltip={action}>
{action}
</DataListText>
</DataListCell>,
<DataListCell
wrapModifier="truncate"
key={`date-${id}`}
>
<RelativeDateTime date={timestamp} />
</DataListCell>,
<DataListCell
wrapModifier="truncate"
key={`user-${id}`}
>
<DataListText tooltip={user}>{user}</DataListText>
</DataListCell>,
]}
/>
</DataListItemRow>
</DataListItem>
)
)}
</DataList>
)}
</SkeletonLoader>
</CardBody>
</Card>
<GridItem xl2={3} xl={4} md={6} lg={4}>
<Card isHoverable>
<CardHeader>
<CardTitle>{__('Recent Audits')}</CardTitle>
<CardActions>
<a onClick={() => dispatch(push(uiUrl))}> {__('All audits')}</a>
</CardActions>
</CardHeader>
<CardBody>
<SkeletonLoader
skeletonProps={{ count: NUMBER_OF_RECORDS }}
status={status}
emptyState={
<Bullseye>
<Title headingLevel="h4"> {__('No Results found')} </Title>
</Bullseye>
}
>
{audits && (
<DataList isCompact>
{audits.map(
({ user_name: user, created_at: timestamp, action, id }) => (
<DataListItem key={id}>
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell
wrapModifier="truncate"
key={`action-${id}`}
>
<DataListText tooltip={action}>
{action}
</DataListText>
</DataListCell>,
<DataListCell
wrapModifier="truncate"
key={`date-${id}`}
>
<RelativeDateTime date={timestamp} />
</DataListCell>,
<DataListCell
wrapModifier="truncate"
key={`user-${id}`}
>
<DataListText tooltip={user}>{user}</DataListText>
</DataListCell>,
]}
/>
</DataListItemRow>
</DataListItem>
)
)}
</DataList>
)}
</SkeletonLoader>
</CardBody>
</Card>
</GridItem>
);
};
AuditCard.propTypes = {
hostName: PropTypes.string.isRequired,
hostName: PropTypes.string,
};
AuditCard.defaultProps = {
hostName: undefined,
};
export default AuditCard;
webpack/assets/javascripts/react_app/components/HostDetails/DetailsCard/index.js
CardBody,
ClipboardCopy,
Divider,
GridItem,
} from '@patternfly/react-core';
import { UserIcon } from '@patternfly/react-icons';
import { translate as __ } from '../../../common/I18n';
......
import './styles.scss';
const DetailsCard = ({
hostName,
ip,
ip6,
mac,
comment,
owner_id: ownerID,
owner_name: ownerName,
hostgroup_name: hostgroupName,
status,
permissions: { power_hosts: hasPowerPermission },
hostName,
hostDetails: {
ip,
ip6,
mac,
comment,
owner_id: ownerID,
owner_name: ownerName,
hostgroup_name: hostgroupName,
permissions: { power_hosts: hasPowerPermission } = {},
},
}) => (
<Card isHoverable>
<CardHeader>
<CardTitle>{__('Details')}</CardTitle>
<CardActions>
<PowerStatusDropDown
hostID={hostName}
hasPowerPermission={hasPowerPermission}
/>
</CardActions>
</CardHeader>
<CardBody>
<DescriptionList
isAutoColumnWidths
columnModifier={{
default: '2Col',
}}
>
<DescriptionListGroup>
<DescriptionListTerm>{__('IPv6 address')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
emptyState={<DefaultLoaderEmptyState />}
status={status}
>
{ip6 && (
<ClipboardCopy isBlock variant="inline-compact">
{ip6}
</ClipboardCopy>
)}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{__('IPv4 address')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
emptyState={<DefaultLoaderEmptyState />}
status={status}
>
{ip && (
<ClipboardCopy isBlock variant="inline-compact">
{ip}
</ClipboardCopy>
)}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{__('MAC address')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
emptyState={<DefaultLoaderEmptyState />}
status={status}
>
{mac && (
<ClipboardCopy isBlock variant="inline-compact">
{mac}
</ClipboardCopy>
)}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
<GridItem xl2={3} xl={4} md={6} lg={4} rowSpan={2}>
<Card isHoverable>
<CardHeader>
<CardTitle>{__('Details')}</CardTitle>
<CardActions>
<PowerStatusDropDown
hostID={hostName}
hasPowerPermission={hasPowerPermission}
/>
</CardActions>
</CardHeader>
<CardBody>
<DescriptionList
isAutoColumnWidths
columnModifier={{
default: '2Col',
}}
>
<DescriptionListGroup>
<DescriptionListTerm>{__('IPv6 address')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
emptyState={<DefaultLoaderEmptyState />}
status={status}
>
{ip6 && (
<ClipboardCopy isBlock variant="inline-compact">
{ip6}
</ClipboardCopy>
)}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{__('IPv4 address')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
emptyState={<DefaultLoaderEmptyState />}
status={status}
>
{ip && (
<ClipboardCopy isBlock variant="inline-compact">
{ip}
</ClipboardCopy>
)}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{__('MAC address')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
emptyState={<DefaultLoaderEmptyState />}
status={status}
>
{mac && (
<ClipboardCopy isBlock variant="inline-compact">
{mac}
</ClipboardCopy>
)}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
<Divider className="padded-divider" />
<DescriptionList>
<DescriptionListGroup>
<DescriptionListTerm>{__('Host group')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
emptyState={<DefaultLoaderEmptyState />}
status={status}
>
{hostgroupName}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{__('Host owner')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
emptyState={<DefaultLoaderEmptyState />}
status={status}
>
{ownerID && (
<span>
<UserIcon /> {ownerName}
</span>
)}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{__('Comment')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
emptyState={<DefaultLoaderEmptyState />}
status={status}
>
{comment}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
</CardBody>
</Card>
<Divider className="padded-divider" />
<DescriptionList>
<DescriptionListGroup>
<DescriptionListTerm>{__('Host group')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
emptyState={<DefaultLoaderEmptyState />}
status={status}
>
{hostgroupName}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{__('Host owner')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
emptyState={<DefaultLoaderEmptyState />}
status={status}
>
{ownerID && (
<span>
<UserIcon /> {ownerName}
</span>
)}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>{__('Comment')}</DescriptionListTerm>
<DescriptionListDescription>
<SkeletonLoader
emptyState={<DefaultLoaderEmptyState />}
status={status}
>
{comment}
</SkeletonLoader>
</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
</CardBody>
</Card>
</GridItem>
);
DetailsCard.propTypes = {
hostName: PropTypes.string.isRequired,
comment: PropTypes.string,
hostgroup_name: PropTypes.string,
ip: PropTypes.string,
ip6: PropTypes.string,
mac: PropTypes.string,
owner_id: PropTypes.number,
owner_name: PropTypes.string,
hostName: PropTypes.string,
status: PropTypes.string,
permissions: PropTypes.object,
hostDetails: PropTypes.shape({
comment: PropTypes.string,
hostgroup_name: PropTypes.string,
ip: PropTypes.string,
ip6: PropTypes.string,
mac: PropTypes.string,
owner_id: PropTypes.number,
owner_name: PropTypes.string,
permissions: PropTypes.object,
}),
};
DetailsCard.defaultProps = {
hostName: undefined,
status: STATUS.PENDING,
comment: undefined,
hostgroup_name: undefined,
ip: undefined,
ip6: undefined,
mac: undefined,
owner_id: undefined,
owner_name: undefined,
permissions: { power_hosts: false },
hostDetails: {
comment: undefined,
hostgroup_name: undefined,
ip: undefined,
ip6: undefined,
mac: undefined,
owner_id: undefined,
owner_name: undefined,
permissions: { power_hosts: false },
},
};
export default DetailsCard;
webpack/assets/javascripts/react_app/components/HostDetails/Status/AggregateStatusCard.js
CardBody,
CardFooter,
Bullseye,
GridItem,
} from '@patternfly/react-core';
import StatusesModal from './StatusesModal';
......
const AggregateStatusCard = ({
hostName,
permissions: {
view_hosts: canViewStatuses,
forget_status_hosts: canForgetStatuses,
hostDetails: {
permissions: {
view_hosts: canViewStatuses,
forget_status_hosts: canForgetStatuses,
} = {},
},
}) => {
const [openModal, setOpenModal] = useState(false);
......
};
return (
<>
<GridItem xl2={3} xl={4} md={6} lg={4}>
<Card className="card-pf-aggregate-status" isHoverable>
<CardTitle>
<span>
......
setOpenModal(false);
}}
/>
</>
</GridItem>
);
};
AggregateStatusCard.propTypes = {
hostName: PropTypes.string.isRequired,
permissions: PropTypes.shape({
view_hosts: PropTypes.bool,
forget_status_hosts: PropTypes.bool,
hostName: PropTypes.string,
hostDetails: PropTypes.shape({
permissions: PropTypes.shape({
view_hosts: PropTypes.bool,
forget_status_hosts: PropTypes.bool,
}),
}),
};
AggregateStatusCard.defaultProps = {
permissions: { statuses_hosts: false, forget_status_hosts: false },
hostName: undefined,
hostDetails: {
permissions: { statuses_hosts: false, forget_status_hosts: false },
},
};
export default AggregateStatusCard;
webpack/assets/javascripts/react_app/components/HostDetails/Tabs/Overview/CardsRegistry.js
import React from 'react';
import { addGlobalFill } from '../../../common/Fill/GlobalFill';
import AuditCard from '../../Audits';
import DetailsCard from '../../DetailsCard';
import AggregateStatus from '../../Status/AggregateStatusCard';
const cards = [
{ key: '[core]-detail-card', Component: DetailsCard, weight: 4000 },
{ key: '[core]-status-card', Component: AggregateStatus, weight: 3500 },
{ key: '[core]-audit-card', Component: AuditCard, weight: 3000 },
];
export const registerCoreCards = () => {
cards.forEach(({ key, Component, weight }) => {
addGlobalFill('details-cards', key, <Component key={key} />, weight);
});
};
webpack/assets/javascripts/react_app/components/HostDetails/Tabs/Overview/index.js
import PropTypes from 'prop-types';
import React, { useEffect } from 'react';
import { Grid, GridItem } from '@patternfly/react-core';
import AuditCard from '../../Audits';
import { Grid } from '@patternfly/react-core';
import { registerCoreCards } from './CardsRegistry';
import Slot from '../../../common/Slot';
import DetailsCard from '../../DetailsCard';
import { STATUS } from '../../../../constants';
import AggregateStatus from '../../Status/AggregateStatusCard';
import './Details.css';
const DetailsTab = ({ response, status, hostName }) => {
......
// This is a workaround for adding gray background inspiring pf4 desgin
// TODO: delete it when pf4 layout (Page copmponent) is implemented in foreman
document.body.classList.add('pf-gray-background');
registerCoreCards();
return () => document.body.classList.remove('pf-gray-background');
}, []);
return (
<div className="host-details-tab-item details-tab">
<Grid hasGutter>
<GridItem xl2={3} xl={4} md={6} lg={4} rowSpan={2}>
<DetailsCard {...response} status={status} hostName={hostName} />
</GridItem>
<GridItem xl2={3} xl={4} md={6} lg={4}>
<AggregateStatus
hostName={hostName}
permissions={response.permissions}
/>
</GridItem>
<GridItem xl2={3} xl={4} md={6} lg={4}>
<AuditCard hostName={hostName} />
</GridItem>
<Slot hostDetails={response} id="details-cards" multi />
<Slot
hostDetails={response}
status={status}
hostName={hostName}
id="details-cards"
multi
/>
</Grid>
</div>
);

Also available in: Unified diff