Skip to content
This repository has been archived by the owner on Nov 28, 2024. It is now read-only.

Commit

Permalink
[WIP] NNS topology
Browse files Browse the repository at this point in the history
Signed-off-by: Aviv Turgeman <[email protected]>
  • Loading branch information
avivtur committed Aug 14, 2024
1 parent 84abc5b commit 0964cfc
Show file tree
Hide file tree
Showing 23 changed files with 1,549 additions and 45 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
"@openshift/dynamic-plugin-sdk-webpack": "~1.0.0",
"@patternfly/react-core": "5.1.1",
"@patternfly/react-table": "^5.1.1",
"@patternfly/react-icons": "5.2.1",
"@patternfly/react-topology": "5.2.0",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^12.0.0",
"@testing-library/react-hooks": "^8.0.1",
Expand Down
4 changes: 1 addition & 3 deletions src/console-models/NodeNetworkStateModel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { K8sModel } from '@openshift-console/dynamic-plugin-sdk/lib/api/common-t

import { modelToGroupVersionKind, modelToRef } from './modelUtils';

const NodeNetworkStateModel: K8sModel = {
export const NodeNetworkStateModel: K8sModel = {
label: 'NodeNetworkState',
labelPlural: 'NodeNetworkStates',
apiVersion: 'v1beta1',
Expand All @@ -17,5 +17,3 @@ const NodeNetworkStateModel: K8sModel = {

export const NodeNetworkStateModelGroupVersionKind = modelToGroupVersionKind(NodeNetworkStateModel);
export const NodeNetworkStateModelRef = modelToRef(NodeNetworkStateModel);

export default NodeNetworkStateModel;
17 changes: 17 additions & 0 deletions src/utils/components/DetailItem/DetailItem.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
.description-item__title {
justify-content: space-between;
flex: 1;
}

.margin-top {
margin-top: var(--pf-v5-global--spacer--md);
}

.DescriptionItemHeader {
&--list-term {
.pf-c-description-list__text {
align-items: center;
display: inline-flex;
}
}
}
116 changes: 116 additions & 0 deletions src/utils/components/DetailItem/DetailItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import React, { FC, ReactNode } from 'react';

import {
Button,
DescriptionListDescription,
DescriptionListGroup,
DescriptionListTermHelpText,
Flex,
FlexItem,
} from '@patternfly/react-core';
import { PencilAltIcon } from '@patternfly/react-icons';
import { useNMStateTranslation } from '@utils/hooks/useNMStateTranslation';

import { DetailItemHeader } from './DetailItemHeader';
import EditButtonWithTooltip from './EditButtonWithTooltip';

import './DetailItem.scss';

type DetailItemProps = {
bodyContent?: ReactNode;
breadcrumb?: string;
className?: string;
'data-test-id'?: string;
descriptionData: any;

Check warning on line 24 in src/utils/components/DetailItem/DetailItem.tsx

View workflow job for this annotation

GitHub Actions / Run linter and tests

Unexpected any. Specify a different type
descriptionHeader?: ReactNode;
editOnTitleJustify?: boolean;
isDisabled?: boolean;
isEdit?: boolean;
isPopover?: boolean;
label?: ReactNode;
messageOnDisabled?: string;
moreInfoURL?: string;
onEditClick?: () => void;
showEditOnTitle?: boolean;
};

const DetailItem: FC<DetailItemProps> = ({
bodyContent,
breadcrumb,
className,
'data-test-id': testId,
descriptionData,
descriptionHeader,
editOnTitleJustify = false,
isDisabled,
isEdit,
isPopover,
label,
messageOnDisabled,
moreInfoURL,
onEditClick,
showEditOnTitle,
}) => {
const { t } = useNMStateTranslation();
const NotAvailable = <span className="text-muted">{t('Not available')}</span>;

const description = (
<EditButtonWithTooltip
isEditable={!isDisabled}
onEditClick={onEditClick}
testId={testId}
tooltipContent={messageOnDisabled}
>
{descriptionData ?? NotAvailable}
</EditButtonWithTooltip>
);

return (
<DescriptionListGroup className={`pf-c-description-list__group ${className && className}`}>
<DescriptionListTermHelpText className="pf-c-description-list__term">
<Flex
justifyContent={{
default: editOnTitleJustify ? 'justifyContentSpaceBetween' : 'justifyContentFlexStart',
}}
>
{(bodyContent || breadcrumb || descriptionHeader || label || moreInfoURL) && (
<FlexItem>
<DetailItemHeader
bodyContent={bodyContent}
breadcrumb={breadcrumb}
descriptionHeader={descriptionHeader}
isPopover={isPopover}
label={label}
moreInfoURL={moreInfoURL}
/>
</FlexItem>
)}
{isEdit && showEditOnTitle && (
<FlexItem>
<Button
data-test-id={`${testId}-edit`}
isDisabled={isDisabled}
isInline
onClick={onEditClick}
type="button"
variant="link"
>
{t('Edit')}
<PencilAltIcon className="co-icon-space-l pf-v5-c-button-icon--plain" />
</Button>
</FlexItem>
)}
</Flex>
</DescriptionListTermHelpText>

<DescriptionListDescription
className="pf-c-description-list__description"
data-test-id={testId}
>
{isEdit && !showEditOnTitle ? description : descriptionData}
</DescriptionListDescription>
</DescriptionListGroup>
);
};

export default DetailItem;
74 changes: 74 additions & 0 deletions src/utils/components/DetailItem/DetailItemHeader.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React, { FC, ReactNode } from 'react';

import {
Breadcrumb,
BreadcrumbItem,
DescriptionListTerm,
DescriptionListTermHelpTextButton,
Popover,
} from '@patternfly/react-core';
import { useNMStateTranslation } from '@utils/hooks/useNMStateTranslation';

import './DetailItem.scss';

type DetailItemHeaderProps = {
bodyContent: ReactNode;
breadcrumb?: string;
descriptionHeader: ReactNode;
isPopover: boolean;
label?: ReactNode;
maxWidth?: string;
moreInfoURL?: string;
};

export const DetailItemHeader: FC<DetailItemHeaderProps> = ({
bodyContent,
breadcrumb,
descriptionHeader,
isPopover,
label,
maxWidth,
moreInfoURL,
}) => {
const { t } = useNMStateTranslation();

if (isPopover && bodyContent) {
return (
<Popover
bodyContent={
<>
{bodyContent}
{moreInfoURL && (
<>
{t('More info: ')}
<a href={moreInfoURL}>{moreInfoURL}</a>
</>
)}
{breadcrumb && (
<div className="margin-top">
<Breadcrumb>
{breadcrumb.split('.').map((item) => (
<BreadcrumbItem key={item}>{item}</BreadcrumbItem>
))}
</Breadcrumb>
</div>
)}
</>
}
hasAutoWidth
headerContent={descriptionHeader}
maxWidth={maxWidth || '30rem'}
>
<DescriptionListTermHelpTextButton className="pf-c-description-list__text">
{descriptionHeader}
</DescriptionListTermHelpTextButton>
</Popover>
);
}

return (
<DescriptionListTerm className="DescriptionItemHeader--list-term">
{descriptionHeader} {label}
</DescriptionListTerm>
);
};
51 changes: 51 additions & 0 deletions src/utils/components/DetailItem/EditButtonWithTooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React, { FC, PropsWithChildren, ReactNode, SyntheticEvent } from 'react';

import { Button, Flex, Tooltip } from '@patternfly/react-core';
import { PencilAltIcon } from '@patternfly/react-icons';

type EditButtonWithTooltipProps = PropsWithChildren<{
isEditable: boolean;
onEditClick: () => void;
testId: string;
tooltipContent?: ReactNode;
}>;

const EditButtonWithTooltip: FC<EditButtonWithTooltipProps> = ({
children,
isEditable,
onEditClick,
testId,
tooltipContent,
}) => {
const EditButton = () => (
<Button
onClick={(e: SyntheticEvent<HTMLButtonElement>) => {
e.stopPropagation();
onEditClick?.();
}}
data-test-id={testId}
isDisabled={!isEditable}
isInline
variant="link"
>
<Flex>
{children}
<PencilAltIcon className="co-icon-space-l" />
</Flex>
</Button>
);

if (!isEditable && tooltipContent) {
return (
<Tooltip content={tooltipContent}>
<span>
<EditButton />
</span>
</Tooltip>
);
}

return <EditButton />;
};

export default EditButtonWithTooltip;
60 changes: 60 additions & 0 deletions src/utils/components/DetailItem/OwnerDetailItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React, { FC } from 'react';
import { Trans } from 'react-i18next';

import { K8sResourceCommon } from '@openshift-console/dynamic-plugin-sdk';
import {
Breadcrumb,
BreadcrumbItem,
DescriptionListDescription,
DescriptionListGroup,
DescriptionListTermHelpText,
DescriptionListTermHelpTextButton,
Popover,
} from '@patternfly/react-core';
import { useNMStateTranslation } from '@utils/hooks/useNMStateTranslation';

import OwnerReferences from '../OwnerReferences/OwnerReferences';

type OwnerDetailsItemProps = {
obj: K8sResourceCommon;
};

const OwnerDetailsItem: FC<OwnerDetailsItemProps> = ({ obj }) => {
const { t } = useNMStateTranslation();

return (
<DescriptionListGroup className="pf-c-description-list__group">
<DescriptionListTermHelpText className="pf-c-description-list__term">
<Popover
bodyContent={
<Trans ns="plugin__kubevirt-plugin">
<div>
List of objects depended by this object. If ALL objects in the list have been
deleted, this object will be garbage collected. If this object is managed by a
controller, then an entry in this list will point to this controller, with the
controller field set to true. There cannot be more than one managing controller.
</div>
<Breadcrumb className="margin-top">
<BreadcrumbItem>{{ kind: obj?.kind }}</BreadcrumbItem>
<BreadcrumbItem>metadata</BreadcrumbItem>
<BreadcrumbItem>ownerReferences</BreadcrumbItem>
</Breadcrumb>
</Trans>
}
hasAutoWidth
headerContent={t('Owner')}
maxWidth="30rem"
>
<DescriptionListTermHelpTextButton className="pf-c-description-list__text">
{t('Owner')}
</DescriptionListTermHelpTextButton>
</Popover>
</DescriptionListTermHelpText>
<DescriptionListDescription className="pf-c-description-list__description">
<OwnerReferences obj={obj} />
</DescriptionListDescription>
</DescriptionListGroup>
);
};

export default OwnerDetailsItem;
8 changes: 8 additions & 0 deletions src/utils/components/MetadataLabels/MetadataLabels.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
.metadata-labels-group {
padding-top: var(--pf-c-label-group--m-category--PaddingTop);
padding-right: var(--pf-c-label-group--m-category--PaddingRight);
padding-bottom: var(--pf-c-label-group--m-category--PaddingBottom);
padding-left: var(--pf-c-label-group--m-category--PaddingLeft);
border: var(--pf-c-label-group--m-category--BorderWidth) solid
var(--pf-c-label-group--m-category--BorderColor);
}
38 changes: 38 additions & 0 deletions src/utils/components/MetadataLabels/MetadataLabels.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { FC } from 'react';
import { Link } from 'react-router-dom-v5-compat';
import { modelToRef } from 'src/console-models/modelUtils';

import { K8sModel } from '@openshift-console/dynamic-plugin-sdk';
import { Label, LabelGroup } from '@patternfly/react-core';

import './MetadataLabels.scss';

type MetadataLabelsProps = {
labels?: { [key: string]: string };
model: K8sModel;
};

const MetadataLabels: FC<MetadataLabelsProps> = ({ labels, model }) => {
const modelRef = modelToRef(model);

return (
<LabelGroup className="metadata-labels-group" numLabels={10}>
{Object.keys(labels || {})?.map((key) => {
const labelText = labels?.[key] ? `${key}=${labels?.[key]}` : key;

return (
<Label className="co-label" key={key}>
<Link
className="pf-v5-c-label__content"
to={`/search?kind=${modelRef}&q=${encodeURIComponent(labelText)}`}
>
{labelText}
</Link>
</Label>
);
})}
</LabelGroup>
);
};

export default MetadataLabels;
Loading

0 comments on commit 0964cfc

Please sign in to comment.