Skip to content

Commit

Permalink
Merge pull request #5830 from rawagner/bmh_credentials
Browse files Browse the repository at this point in the history
Add no power management status and alert for BMH
  • Loading branch information
openshift-merge-robot committed Jul 10, 2020
2 parents 1924694 + 4fc5993 commit 300e2de
Show file tree
Hide file tree
Showing 18 changed files with 197 additions and 98 deletions.
Expand Up @@ -5,8 +5,8 @@ import StatusIconAndText from './StatusIconAndText';

const GenericStatus: React.FC<GenericStatusProps> = (props) => {
const { Icon, children, ...restProps } = props;
return children ? (
<PopoverStatus {...restProps} icon={<Icon />}>
return React.Children.toArray(children).length ? (
<PopoverStatus {...restProps} statusBody={<StatusIconAndText {...restProps} icon={<Icon />} />}>
{children}
</PopoverStatus>
) : (
Expand Down
@@ -1,22 +1,17 @@
import * as React from 'react';
import { Button, Popover, PopoverPosition } from '@patternfly/react-core';
import { Instance as TippyInstance } from 'tippy.js';
import StatusIconAndText from './StatusIconAndText';

const PopoverStatus: React.FC<PopoverStatusProps> = ({
title,
hideHeader,
icon,
activeIcon,
children,
isVisible = null,
shouldClose = null,
...other
statusBody,
title,
onHide,
onShow,
}) => {
const [isActive, setActive] = React.useState(false);
const onHide = React.useCallback(() => setActive(false), [setActive]);
const onShow = React.useCallback(() => setActive(true), [setActive]);

return (
<Popover
position={PopoverPosition.right}
Expand All @@ -29,18 +24,17 @@ const PopoverStatus: React.FC<PopoverStatusProps> = ({
shouldClose={shouldClose}
>
<Button variant="link" isInline>
<StatusIconAndText
{...other}
title={title}
icon={isActive && activeIcon ? activeIcon : icon}
/>
{statusBody}
</Button>
</Popover>
);
};

type PopoverStatusProps = React.ComponentProps<typeof StatusIconAndText> & {
activeIcon?: React.ReactElement;
type PopoverStatusProps = {
statusBody: React.ReactNode;
onHide?: () => void;
onShow?: () => void;
title?: string;
hideHeader?: boolean;
isVisible?: boolean;
shouldClose?: (tip: TippyInstance) => void;
Expand Down
@@ -1,9 +1,10 @@
import * as React from 'react';
import { InfoCircleIcon, HourglassHalfIcon, InProgressIcon } from '@patternfly/react-icons';
import { HourglassHalfIcon, InProgressIcon } from '@patternfly/react-icons';
import {
RedExclamationCircleIcon,
GreenCheckCircleIcon,
YellowExclamationTriangleIcon,
BlueInfoCircleIcon,
} from './icons';
import GenericStatus from './GenericStatus';
import { StatusComponentProps } from './types';
Expand All @@ -14,7 +15,7 @@ export const ErrorStatus: React.FC<StatusComponentProps> = (props) => (
ErrorStatus.displayName = 'ErrorStatus';

export const InfoStatus: React.FC<StatusComponentProps> = (props) => (
<GenericStatus {...props} Icon={InfoCircleIcon} />
<GenericStatus {...props} Icon={BlueInfoCircleIcon} />
);
InfoStatus.displayName = 'InfoStatus';

Expand Down
22 changes: 18 additions & 4 deletions frontend/packages/kubevirt-plugin/src/components/form/form-row.tsx
@@ -1,8 +1,9 @@
import * as React from 'react';
import { FormGroup } from '@patternfly/react-core';
import { HelpIcon } from '@patternfly/react-icons';
import * as classnames from 'classnames';
import { LoadingInline } from '@console/internal/components/utils';
import { PopoverStatus, ValidationErrorType } from '@console/shared';
import { PopoverStatus, ValidationErrorType, StatusIconAndText } from '@console/shared';
import './form-row.scss';

export const FormRow: React.FC<FormRowProps> = ({
Expand All @@ -18,6 +19,9 @@ export const FormRow: React.FC<FormRowProps> = ({
children,
className,
}) => {
const [isActive, setActive] = React.useState(false);
const onHide = React.useCallback(() => setActive(false), [setActive]);
const onShow = React.useCallback(() => setActive(true), [setActive]);
if (isHidden) {
return null;
}
Expand All @@ -39,11 +43,21 @@ export const FormRow: React.FC<FormRowProps> = ({
{help && (
<span className="kubevirt-form-row__icon-status-container">
<PopoverStatus
icon={<HelpIcon className="kubevirt-form-row__help-icon--hidden" />}
activeIcon={<HelpIcon />}
title={`${fieldId} help`}
iconOnly
hideHeader
onHide={onHide}
onShow={onShow}
statusBody={
<StatusIconAndText
title={`${fieldId} help`}
iconOnly
icon={
<HelpIcon
className={classnames({ 'kubevirt-form-row__help-icon--hidden': !isActive })}
/>
}
/>
}
>
{help}
</PopoverStatus>
Expand Down
Expand Up @@ -23,6 +23,7 @@ import {
StatusIconAndText,
DetailPropertyList,
DetailPropertyListItem,
SecondaryStatus,
} from '@console/shared';
import { getHostStatus } from '../../status/host-status';
import {
Expand All @@ -41,13 +42,14 @@ import {
getHostProvisioningState,
getHostBootMACAddress,
isHostScheduledForRestart,
hasPowerManagement,
} from '../../selectors';
import { BareMetalHostKind } from '../../types';
import { HOST_REGISTERING_STATES } from '../../constants/bare-metal-host';
import MachineLink from './MachineLink';
import BareMetalHostPowerStatusIcon from './BareMetalHostPowerStatusIcon';
import BareMetalHostStatus from './BareMetalHostStatus';
import { HOST_SCHEDULED_FOR_RESTART } from './BareMetalHostSecondaryStatus';
import { HOST_SCHEDULED_FOR_RESTART, HOST_NO_POWER_MGMT } from './BareMetalHostSecondaryStatus';

type BareMetalHostDetailsProps = {
obj: BareMetalHostKind;
Expand Down Expand Up @@ -147,15 +149,21 @@ const BareMetalHostDetails: React.FC<BareMetalHostDetailsProps> = ({
<>
<dt>Power Status</dt>
<dd>
<StatusIconAndText
title={powerStatus}
icon={<BareMetalHostPowerStatusIcon powerStatus={powerStatus} />}
/>
{isHostScheduledForRestart(host) && (
<StatusIconAndText
title={HOST_SCHEDULED_FOR_RESTART}
icon={<RebootingIcon />}
/>
{!hasPowerManagement(host) ? (
<SecondaryStatus status={HOST_NO_POWER_MGMT} />
) : (
<>
<StatusIconAndText
title={powerStatus}
icon={<BareMetalHostPowerStatusIcon powerStatus={powerStatus} />}
/>
{isHostScheduledForRestart(host) && (
<StatusIconAndText
title={HOST_SCHEDULED_FOR_RESTART}
icon={<RebootingIcon />}
/>
)}
</>
)}
</dd>
</>
Expand Down
Expand Up @@ -5,6 +5,7 @@ import {
getHostPowerStatus,
getHostProvisioningState,
isHostScheduledForRestart,
hasPowerManagement,
} from '../../selectors';
import { HOST_POWER_STATUS_POWERED_ON, HOST_REGISTERING_STATES } from '../../constants';

Expand All @@ -13,14 +14,17 @@ type BareMetalHostSecondaryStatusProps = {
};

export const HOST_SCHEDULED_FOR_RESTART = 'Restart pending';
export const HOST_NO_POWER_MGMT = 'No power management';

const BareMetalHostSecondaryStatus: React.FC<BareMetalHostSecondaryStatusProps> = ({ host }) => {
const powerStatus = getHostPowerStatus(host);
const provisioningState = getHostProvisioningState(host);
const status = [];

// don't show power status when host registration/inspection hasn't finished
if (!HOST_REGISTERING_STATES.includes(provisioningState)) {
if (!hasPowerManagement(host)) {
status.push(HOST_NO_POWER_MGMT);
// don't show power status when host registration/inspection hasn't finished
} else if (!HOST_REGISTERING_STATES.includes(provisioningState)) {
if (isHostScheduledForRestart(host)) {
status.push(HOST_SCHEDULED_FOR_RESTART);
}
Expand Down
@@ -1,45 +1,45 @@
import * as React from 'react';
import { Button } from 'patternfly-react';
import { AddCircleOIcon } from '@patternfly/react-icons';
import { Link } from 'react-router-dom';
import { resourcePathFromModel } from '@console/internal/components/utils';
import {
ProgressStatus,
SuccessStatus,
ErrorStatus,
Status,
StatusIconAndText,
getNamespace,
PopoverStatus,
InfoStatus,
} from '@console/shared';
import { RequireCreatePermission } from '@console/internal/components/utils';
import { K8sResourceKind } from '@console/internal/module/k8s';
import {
HOST_STATUS_DISCOVERED,
HOST_PROGRESS_STATES,
HOST_ERROR_STATES,
HOST_SUCCESS_STATES,
NODE_STATUS_UNDER_MAINTENANCE,
NODE_STATUS_STARTING_MAINTENANCE,
NODE_STATUS_STOPPING_MAINTENANCE,
HOST_STATUS_UNMANAGED,
HOST_INFO_STATES,
} from '../../constants';
import { BareMetalHostModel } from '../../models';
import { getHostErrorMessage } from '../../selectors';
import { StatusProps } from '../types';
import MaintenancePopover from '../maintenance/MaintenancePopover';
import { BareMetalHostKind } from '../../types';
import { K8sResourceKind } from '@console/internal/module/k8s';

// TODO(jtomasek): Update this with onClick handler once add discovered host functionality
// is available
export const AddDiscoveredHostButton: React.FC<{ host: BareMetalHostKind }> = (
{ host }, // eslint-disable-line @typescript-eslint/no-unused-vars
) => {
const namespace = getNamespace(host);
import { BareMetalHostModel } from '../../models';

return (
<RequireCreatePermission model={BareMetalHostModel} namespace={namespace}>
<Button bsStyle="link">
<StatusIconAndText icon={<AddCircleOIcon />} title="Add host" />
</Button>
</RequireCreatePermission>
);
export const HOST_STATUS_ACTIONS = {
[HOST_STATUS_UNMANAGED]: (host: BareMetalHostKind) => (
<p>
<Link
to={`${resourcePathFromModel(
BareMetalHostModel,
host.metadata.name,
host.metadata.namespace,
)}/edit`}
>
Add credentials
</Link>
</p>
),
};

const BareMetalHostStatus: React.FC<BareMetalHostStatusProps> = ({
Expand All @@ -50,24 +50,51 @@ const BareMetalHostStatus: React.FC<BareMetalHostStatusProps> = ({
nodeMaintenance,
}) => {
const statusTitle = title || status;
const action = HOST_STATUS_ACTIONS[status]?.(host);
switch (true) {
case status === HOST_STATUS_DISCOVERED:
return <AddDiscoveredHostButton host={host} />;
case [NODE_STATUS_STARTING_MAINTENANCE, NODE_STATUS_UNDER_MAINTENANCE].includes(status):
return <MaintenancePopover title={statusTitle} nodeMaintenance={nodeMaintenance} />;
case [NODE_STATUS_STOPPING_MAINTENANCE, ...HOST_PROGRESS_STATES].includes(status):
return <ProgressStatus title={statusTitle}>{description}</ProgressStatus>;
return (
<ProgressStatus title={statusTitle}>
{description}
{action}
</ProgressStatus>
);
case HOST_ERROR_STATES.includes(status):
return (
<ErrorStatus title={statusTitle}>
<p>{description}</p>
<p>{getHostErrorMessage(host)}</p>
{action}
</ErrorStatus>
);
case HOST_SUCCESS_STATES.includes(status):
return <SuccessStatus title={statusTitle}>{description}</SuccessStatus>;
default:
return <Status status={status} title={statusTitle} />;
return (
<SuccessStatus title={statusTitle}>
{description}
{action}
</SuccessStatus>
);
case HOST_INFO_STATES.includes(status):
return (
<InfoStatus title={statusTitle}>
{description}
{action}
</InfoStatus>
);
default: {
const statusBody = <Status status={status} title={statusTitle} />;

return description || action ? (
<PopoverStatus title={statusTitle} statusBody={statusBody}>
{description}
{action}
</PopoverStatus>
) : (
statusBody
);
}
}
};

Expand Down
Expand Up @@ -6,10 +6,6 @@ import DashboardCardTitle from '@console/shared/src/components/dashboard/dashboa
import DetailsBody from '@console/shared/src/components/dashboard/details-card/DetailsBody';
import DetailItem from '@console/shared/src/components/dashboard/details-card/DetailItem';
import DashboardCardLink from '@console/shared/src/components/dashboard/dashboard-card/DashboardCardLink';
import {
DashboardItemProps,
withDashboardResources,
} from '@console/internal/components/dashboard/with-dashboard-resources';
import { getName, getNamespace } from '@console/shared';
import { MachineKind, NodeKind } from '@console/internal/module/k8s';
import { resourcePathFromModel } from '@console/internal/components/utils';
Expand Down Expand Up @@ -56,9 +52,9 @@ const DetailsCard: React.FC<DetailsCardProps> = () => {
);
};

export default withDashboardResources(DetailsCard);
export default DetailsCard;

type DetailsCardProps = DashboardItemProps & {
type DetailsCardProps = {
obj: BareMetalHostKind;
machines: MachineKind[];
nodes: NodeKind[];
Expand Down

0 comments on commit 300e2de

Please sign in to comment.