Revision 71ce89cb
Added by Amir Fefer over 2 years ago
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
Fixes #34142 - make the core cards arrangeable in new host page (#8995)