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
19 changes: 18 additions & 1 deletion web/src/components/drawer/record/record-field.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,25 @@
white-space: nowrap
}

.field-text {
display: flex;
flex: 1;
}

.co-resource-item {
display: flex;
}

/* max content lines to show */
.field-text.s>.record-field-value,
.field-text.m>.record-field-value,
.field-text.l>.record-field-value,
.co-resource-item.s>.co-resource-item__resource-name,
.co-resource-item.m>.co-resource-item__resource-name,
.co-resource-item.l>.co-resource-item__resource-name {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}

Expand All @@ -32,14 +39,17 @@
width: 100%;
}

.field-text.s>.record-field-value,
.co-resource-item.s>.co-resource-item__resource-name {
-webkit-line-clamp: 1;
}

.field-text.m>.record-field-value,
.co-resource-item.m>.co-resource-item__resource-name {
-webkit-line-clamp: 2;
}

.field-text.l>.record-field-value,
.co-resource-item.l>.co-resource-item__resource-name {
-webkit-line-clamp: 3;
}
Expand All @@ -50,6 +60,11 @@
flex-direction: column;
}

.record-field-flex-container.s {
flex-direction: row;
flex-wrap: nowrap;
}

/* table tooltips - check pf-c-tooltip__content for values */
.record-field-tooltip {
display: flex;
Expand All @@ -71,6 +86,8 @@
}

/* show tooltip on content hover */
.field-text:hover .record-field-tooltip,
.force-truncate:hover .record-field-tooltip,
.record-field-content-flex.truncated:hover .record-field-tooltip,
.record-field-content.truncated:hover .record-field-tooltip {
visibility: visible;
Expand Down
121 changes: 69 additions & 52 deletions web/src/components/drawer/record/record-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export type RecordFieldFilter = {
isDelete: boolean;
};

export type FlexValue = 'flexDefault' | 'flexNone' | 'flex_1' | 'flex_2' | 'flex_3' | 'flex_4';
export type FlexWrapValue = 'wrap' | 'wrapReverse' | 'nowrap';

export interface RecordFieldProps {
allowPktDrops: boolean;
flow: Record;
Expand All @@ -46,16 +49,7 @@ export const RecordField: React.FC<RecordFieldProps> = ({
isDark
}) => {
const { t } = useTranslation('plugin__netobserv-plugin');

const onMouseOver = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, className: string) => {
if (event.currentTarget) {
const isTruncated =
event.currentTarget.offsetHeight < event.currentTarget.scrollHeight ||
event.currentTarget.offsetWidth < event.currentTarget.scrollWidth ||
(event.currentTarget.children.length > 0 && event.currentTarget.children[0].className === 'force-truncate');
event.currentTarget.className = isTruncated ? `${className} truncated ${size}` : `${className} ${size}`;
}
};
const multiLineSize = size === 'l' ? 'm' : 's';

const errorTextValue = (value: string, text: string) => {
return (
Expand Down Expand Up @@ -96,10 +90,13 @@ export const RecordField: React.FC<RecordFieldProps> = ({
);
};

const simpleTextWithTooltip = (text?: string, color?: string, child?: JSX.Element) => {
const simpleTextWithTooltip = (text?: string, color?: string, child?: JSX.Element, forcedSize?: Size) => {
if (text) {
return (
<TextContent className="netobserv-no-child-margin" data-test={`field-text-${text}`}>
<TextContent
className={`field-text ${forcedSize || size} netobserv-no-child-margin`}
data-test={`field-text-${text}`}
>
<Text className="record-field-value" component={TextVariants.p} style={{ color }}>
{text}
</Text>
Expand All @@ -113,13 +110,13 @@ export const RecordField: React.FC<RecordFieldProps> = ({
return undefined;
};

const resourceIconText = (value: string, kind: string, ns?: string) => {
const resourceIconText = (value: string, kind: string, ns?: string, forcedSize?: Size) => {
return (
//force ResourceLink when ResourceIcon is not defined (ie OCP < 4.12)
!ResourceIcon || useLinks ? (
<ResourceLink className={size} inline={true} kind={kind} name={value} namespace={ns} />
) : (
<TextContent className={`co-resource-item ${size} netobserv-no-child-margin`}>
<TextContent className={`co-resource-item ${forcedSize || size} netobserv-no-child-margin`}>
<ResourceIcon kind={kind} />
<Text component={TextVariants.p} className="co-resource-item__resource-name" data-test-id={value}>
{value}
Expand All @@ -130,19 +127,24 @@ export const RecordField: React.FC<RecordFieldProps> = ({
};

const kubeObjContainer = (k: KubeObj) => {
const main = kubeObjContent(k.name, k.kind, k.namespace);
const main = kubeObjContent(k.name, k.kind, k.namespace, multiLineSize);
if (k.showNamespace && k.namespace) {
return doubleContainer(main, kindContent('Namespace', k.namespace), false);
return doubleContainer(main, kindContent('Namespace', k.namespace, multiLineSize), false, true, 'm');
}
return singleContainer(main);
};

const kubeObjContent = (value: string | undefined, kind: string | undefined, ns: string | undefined) => {
const kubeObjContent = (
value: string | undefined,
kind: string | undefined,
ns: string | undefined,
forcedSize?: Size
) => {
// Note: namespace is not mandatory here (e.g. Node objects)
if (value && kind) {
return (
<div data-test={`field-resource-${kind}.${ns}.${value}`} className="force-truncate">
{resourceIconText(value, kind, ns)}
{resourceIconText(value, kind, ns, forcedSize)}
{kubeTooltip(value, kind, ns)}
</div>
);
Expand All @@ -165,11 +167,11 @@ export const RecordField: React.FC<RecordFieldProps> = ({
);
};

const kindContent = (kind: 'Namespace' | 'Node', value?: string) => {
const kindContent = (kind: 'Namespace' | 'Node', value?: string, forcedSize?: Size) => {
if (value) {
return (
<div data-test={`field-kind-${kind}.${value}`} className="force-truncate">
{resourceIconText(value, kind)}
{resourceIconText(value, kind, undefined, forcedSize)}
<TextContent className="record-field-tooltip netobserv-no-child-margin">
<Text component={TextVariants.h4}>{t(kind)}</Text>
<Text component={TextVariants.p}>{value}</Text>
Expand Down Expand Up @@ -213,43 +215,48 @@ export const RecordField: React.FC<RecordFieldProps> = ({
);
};

const nthContainer = (children: (JSX.Element | undefined)[], asChild = true, childIcon = true) => {
const nthContainer = (children: (JSX.Element | undefined)[], asChild = true, childIcon = true, forcedSize?: Size) => {
return (
<Flex className={`record-field-flex-container ${asChild ? size : ''}`} flex={{ default: 'flex_1' }}>
{children.map((c, i) => (
<FlexItem
key={i}
className={`record-field-content`}
onMouseOver={e => onMouseOver(e, `record-field-content`)}
flex={{ default: 'flex_1' }}
>
{i > 0 && asChild && childIcon && <span className="child-arrow">{'↪'}</span>}
{c ? c : emptyText()}
</FlexItem>
))}
<Flex className={`record-field-flex-container ${forcedSize || size}`} flex={{ default: 'flex_1' }}>
{children.map((c, i) => {
const child = c ? c : emptyText();
if (i > 0 && asChild && childIcon) {
const arrow = <span className="child-arrow">{'↪'}</span>;
return sideBySideContainer(arrow, child, 'flexNone', 'flex_1', 'nowrap');
}
return child;
})}
</Flex>
);
};

const doubleContainer = (child1?: JSX.Element, child2?: JSX.Element, asChild = true, childIcon = true) => {
return nthContainer([child1, child2], asChild, childIcon);
const doubleContainer = (
child1?: JSX.Element,
child2?: JSX.Element,
asChild = true,
childIcon = true,
forcedSize?: Size
) => {
return nthContainer([child1, child2], asChild, childIcon, forcedSize);
};

const sideBySideContainer = (leftElement?: JSX.Element, rightElement?: JSX.Element) => {
const sideBySideContainer = (
leftElement?: JSX.Element,
rightElement?: JSX.Element,
leftFlex: FlexValue = 'flex_1',
rightFlex: FlexValue = 'flex_1',
wrap: FlexWrapValue = 'wrap'
) => {
return (
<Flex direction={{ default: 'row' }} flex={{ default: 'flex_1' }}>
<FlexItem flex={{ default: 'flex_1' }}>{leftElement || emptyText()}</FlexItem>
<FlexItem flex={{ default: 'flex_1' }}>{rightElement || emptyText()}</FlexItem>
<Flex direction={{ default: 'row' }} flex={{ default: 'flex_1' }} flexWrap={{ default: wrap }}>
<FlexItem flex={{ default: leftFlex }}>{leftElement || emptyText()}</FlexItem>
<FlexItem flex={{ default: rightFlex }}>{rightElement || emptyText()}</FlexItem>
</Flex>
);
};

const singleContainer = (child?: JSX.Element) => {
return (
<div className={`record-field-content ${size}`} onMouseOver={e => onMouseOver(e, 'record-field-content')}>
{child ? child : emptyText()}
</div>
);
return <div className={`record-field-content ${size}`}>{child ? child : emptyText()}</div>;
};

const clickableContent = (text: string, content: string, docUrl?: string) => {
Expand Down Expand Up @@ -408,7 +415,8 @@ export const RecordField: React.FC<RecordFieldProps> = ({
return nthContainer(
value.map(dir => simpleTextWithTooltip(getDirectionDisplayString(String(dir) as FlowDirection, t))),
true,
false
false,
multiLineSize
);
}
return singleContainer(simpleTextWithTooltip(getDirectionDisplayString(String(value) as FlowDirection, t)));
Expand All @@ -418,7 +426,8 @@ export const RecordField: React.FC<RecordFieldProps> = ({
return nthContainer(
value.map(iName => simpleTextWithTooltip(String(iName))),
true,
false
false,
multiLineSize
);
}
return singleContainer(simpleTextWithTooltip(String(value)));
Expand All @@ -434,9 +443,12 @@ export const RecordField: React.FC<RecordFieldProps> = ({
return nthContainer(
flow.fields.Interfaces.map((iName, i) =>
sideBySideContainer(
simpleTextWithTooltip(iName),
simpleTextWithTooltip(iName, undefined, undefined, multiLineSize),
simpleTextWithTooltip(
getDirectionDisplayString(String(flow.fields.IfDirections![i]) as FlowDirection, t)
getDirectionDisplayString(String(flow.fields.IfDirections![i]) as FlowDirection, t),
undefined,
undefined,
multiLineSize
)
)
),
Expand Down Expand Up @@ -467,13 +479,16 @@ export const RecordField: React.FC<RecordFieldProps> = ({
return doubleContainer(
simpleTextWithTooltip(
detailed ? `${sentCount} ${c.name.toLowerCase()} ${t('sent')}` : sentCount,
allowPktDrops ? (isDark ? '#3E8635' : '#1E4F18') : undefined
allowPktDrops ? (isDark ? '#3E8635' : '#1E4F18') : undefined,
undefined,
multiLineSize
),
droppedCount ? (
simpleTextWithTooltip(
detailed ? `${droppedCount} ${c.name.toLowerCase()} ${droppedText}` : droppedCount,
isDark ? '#C9190B' : '#A30000',
child
child,
multiLineSize
)
) : (
<></>
Expand Down Expand Up @@ -545,8 +560,10 @@ export const RecordField: React.FC<RecordFieldProps> = ({
if (Array.isArray(value) && value.length) {
// we can only show two values properly with containers
if (value.length === 2) {
const contents = value.map(v => (isKubeObj(v) ? kubeObjContainer(v) : simpleTextWithTooltip(String(v))));
return doubleContainer(contents[0], contents[1]);
const contents = value.map(v =>
isKubeObj(v) ? kubeObjContainer(v) : simpleTextWithTooltip(String(v), undefined, undefined, multiLineSize)
);
return doubleContainer(contents[0], contents[1], undefined, undefined, multiLineSize);
}
// else we will show values as single joigned string
return singleContainer(simpleTextWithTooltip(value.map(v => String(v)).join(', ')));
Expand Down
Loading