Skip to content

Commit

Permalink
improve table display
Browse files Browse the repository at this point in the history
  • Loading branch information
jpinsonneau committed Jan 28, 2025
1 parent 39d2fb0 commit 958ee46
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 53 deletions.
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

0 comments on commit 958ee46

Please sign in to comment.