Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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} />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this be StatusIconAndText? SecondaryStatus is used as an additional info for Status

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wanted to show No power management as grayed out text which SecondaryStatus provides. I could change that to StatusIconAndText and add className. But I dont really see that as better solution.

) : (
<>
<StatusIconAndText
title={powerStatus}
icon={<BareMetalHostPowerStatusIcon powerStatus={powerStatus} />}
/>
{isHostScheduledForRestart(host) && (
<StatusIconAndText
title={HOST_SCHEDULED_FOR_RESTART}
icon={<RebootingIcon />}
/>
)}
</>
)}
</dd>
</>
Expand Down
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Loading