Skip to content

Commit 0350685

Browse files
authored
improve table display (#700)
1 parent bfb47b3 commit 0350685

File tree

2 files changed

+87
-53
lines changed

2 files changed

+87
-53
lines changed

web/src/components/drawer/record/record-field.css

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,25 @@
44
white-space: nowrap
55
}
66

7+
.field-text {
8+
display: flex;
9+
flex: 1;
10+
}
11+
712
.co-resource-item {
813
display: flex;
914
}
1015

1116
/* max content lines to show */
17+
.field-text.s>.record-field-value,
18+
.field-text.m>.record-field-value,
19+
.field-text.l>.record-field-value,
1220
.co-resource-item.s>.co-resource-item__resource-name,
1321
.co-resource-item.m>.co-resource-item__resource-name,
1422
.co-resource-item.l>.co-resource-item__resource-name {
1523
overflow: hidden;
1624
text-overflow: ellipsis;
1725
display: -webkit-box;
18-
-webkit-line-clamp: 2;
1926
-webkit-box-orient: vertical;
2027
}
2128

@@ -32,14 +39,17 @@
3239
width: 100%;
3340
}
3441

42+
.field-text.s>.record-field-value,
3543
.co-resource-item.s>.co-resource-item__resource-name {
3644
-webkit-line-clamp: 1;
3745
}
3846

47+
.field-text.m>.record-field-value,
3948
.co-resource-item.m>.co-resource-item__resource-name {
4049
-webkit-line-clamp: 2;
4150
}
4251

52+
.field-text.l>.record-field-value,
4353
.co-resource-item.l>.co-resource-item__resource-name {
4454
-webkit-line-clamp: 3;
4555
}
@@ -50,6 +60,11 @@
5060
flex-direction: column;
5161
}
5262

63+
.record-field-flex-container.s {
64+
flex-direction: row;
65+
flex-wrap: nowrap;
66+
}
67+
5368
/* table tooltips - check pf-c-tooltip__content for values */
5469
.record-field-tooltip {
5570
display: flex;
@@ -71,6 +86,8 @@
7186
}
7287

7388
/* show tooltip on content hover */
89+
.field-text:hover .record-field-tooltip,
90+
.force-truncate:hover .record-field-tooltip,
7491
.record-field-content-flex.truncated:hover .record-field-tooltip,
7592
.record-field-content.truncated:hover .record-field-tooltip {
7693
visibility: visible;

web/src/components/drawer/record/record-field.tsx

Lines changed: 69 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ export type RecordFieldFilter = {
2424
isDelete: boolean;
2525
};
2626

27+
export type FlexValue = 'flexDefault' | 'flexNone' | 'flex_1' | 'flex_2' | 'flex_3' | 'flex_4';
28+
export type FlexWrapValue = 'wrap' | 'wrapReverse' | 'nowrap';
29+
2730
export interface RecordFieldProps {
2831
allowPktDrops: boolean;
2932
flow: Record;
@@ -46,16 +49,7 @@ export const RecordField: React.FC<RecordFieldProps> = ({
4649
isDark
4750
}) => {
4851
const { t } = useTranslation('plugin__netobserv-plugin');
49-
50-
const onMouseOver = (event: React.MouseEvent<HTMLDivElement, MouseEvent>, className: string) => {
51-
if (event.currentTarget) {
52-
const isTruncated =
53-
event.currentTarget.offsetHeight < event.currentTarget.scrollHeight ||
54-
event.currentTarget.offsetWidth < event.currentTarget.scrollWidth ||
55-
(event.currentTarget.children.length > 0 && event.currentTarget.children[0].className === 'force-truncate');
56-
event.currentTarget.className = isTruncated ? `${className} truncated ${size}` : `${className} ${size}`;
57-
}
58-
};
52+
const multiLineSize = size === 'l' ? 'm' : 's';
5953

6054
const errorTextValue = (value: string, text: string) => {
6155
return (
@@ -96,10 +90,13 @@ export const RecordField: React.FC<RecordFieldProps> = ({
9690
);
9791
};
9892

99-
const simpleTextWithTooltip = (text?: string, color?: string, child?: JSX.Element) => {
93+
const simpleTextWithTooltip = (text?: string, color?: string, child?: JSX.Element, forcedSize?: Size) => {
10094
if (text) {
10195
return (
102-
<TextContent className="netobserv-no-child-margin" data-test={`field-text-${text}`}>
96+
<TextContent
97+
className={`field-text ${forcedSize || size} netobserv-no-child-margin`}
98+
data-test={`field-text-${text}`}
99+
>
103100
<Text className="record-field-value" component={TextVariants.p} style={{ color }}>
104101
{text}
105102
</Text>
@@ -113,13 +110,13 @@ export const RecordField: React.FC<RecordFieldProps> = ({
113110
return undefined;
114111
};
115112

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

132129
const kubeObjContainer = (k: KubeObj) => {
133-
const main = kubeObjContent(k.name, k.kind, k.namespace);
130+
const main = kubeObjContent(k.name, k.kind, k.namespace, multiLineSize);
134131
if (k.showNamespace && k.namespace) {
135-
return doubleContainer(main, kindContent('Namespace', k.namespace), false);
132+
return doubleContainer(main, kindContent('Namespace', k.namespace, multiLineSize), false, true, 'm');
136133
}
137134
return singleContainer(main);
138135
};
139136

140-
const kubeObjContent = (value: string | undefined, kind: string | undefined, ns: string | undefined) => {
137+
const kubeObjContent = (
138+
value: string | undefined,
139+
kind: string | undefined,
140+
ns: string | undefined,
141+
forcedSize?: Size
142+
) => {
141143
// Note: namespace is not mandatory here (e.g. Node objects)
142144
if (value && kind) {
143145
return (
144146
<div data-test={`field-resource-${kind}.${ns}.${value}`} className="force-truncate">
145-
{resourceIconText(value, kind, ns)}
147+
{resourceIconText(value, kind, ns, forcedSize)}
146148
{kubeTooltip(value, kind, ns)}
147149
</div>
148150
);
@@ -165,11 +167,11 @@ export const RecordField: React.FC<RecordFieldProps> = ({
165167
);
166168
};
167169

168-
const kindContent = (kind: 'Namespace' | 'Node', value?: string) => {
170+
const kindContent = (kind: 'Namespace' | 'Node', value?: string, forcedSize?: Size) => {
169171
if (value) {
170172
return (
171173
<div data-test={`field-kind-${kind}.${value}`} className="force-truncate">
172-
{resourceIconText(value, kind)}
174+
{resourceIconText(value, kind, undefined, forcedSize)}
173175
<TextContent className="record-field-tooltip netobserv-no-child-margin">
174176
<Text component={TextVariants.h4}>{t(kind)}</Text>
175177
<Text component={TextVariants.p}>{value}</Text>
@@ -213,43 +215,48 @@ export const RecordField: React.FC<RecordFieldProps> = ({
213215
);
214216
};
215217

216-
const nthContainer = (children: (JSX.Element | undefined)[], asChild = true, childIcon = true) => {
218+
const nthContainer = (children: (JSX.Element | undefined)[], asChild = true, childIcon = true, forcedSize?: Size) => {
217219
return (
218-
<Flex className={`record-field-flex-container ${asChild ? size : ''}`} flex={{ default: 'flex_1' }}>
219-
{children.map((c, i) => (
220-
<FlexItem
221-
key={i}
222-
className={`record-field-content`}
223-
onMouseOver={e => onMouseOver(e, `record-field-content`)}
224-
flex={{ default: 'flex_1' }}
225-
>
226-
{i > 0 && asChild && childIcon && <span className="child-arrow">{'↪'}</span>}
227-
{c ? c : emptyText()}
228-
</FlexItem>
229-
))}
220+
<Flex className={`record-field-flex-container ${forcedSize || size}`} flex={{ default: 'flex_1' }}>
221+
{children.map((c, i) => {
222+
const child = c ? c : emptyText();
223+
if (i > 0 && asChild && childIcon) {
224+
const arrow = <span className="child-arrow">{'↪'}</span>;
225+
return sideBySideContainer(arrow, child, 'flexNone', 'flex_1', 'nowrap');
226+
}
227+
return child;
228+
})}
230229
</Flex>
231230
);
232231
};
233232

234-
const doubleContainer = (child1?: JSX.Element, child2?: JSX.Element, asChild = true, childIcon = true) => {
235-
return nthContainer([child1, child2], asChild, childIcon);
233+
const doubleContainer = (
234+
child1?: JSX.Element,
235+
child2?: JSX.Element,
236+
asChild = true,
237+
childIcon = true,
238+
forcedSize?: Size
239+
) => {
240+
return nthContainer([child1, child2], asChild, childIcon, forcedSize);
236241
};
237242

238-
const sideBySideContainer = (leftElement?: JSX.Element, rightElement?: JSX.Element) => {
243+
const sideBySideContainer = (
244+
leftElement?: JSX.Element,
245+
rightElement?: JSX.Element,
246+
leftFlex: FlexValue = 'flex_1',
247+
rightFlex: FlexValue = 'flex_1',
248+
wrap: FlexWrapValue = 'wrap'
249+
) => {
239250
return (
240-
<Flex direction={{ default: 'row' }} flex={{ default: 'flex_1' }}>
241-
<FlexItem flex={{ default: 'flex_1' }}>{leftElement || emptyText()}</FlexItem>
242-
<FlexItem flex={{ default: 'flex_1' }}>{rightElement || emptyText()}</FlexItem>
251+
<Flex direction={{ default: 'row' }} flex={{ default: 'flex_1' }} flexWrap={{ default: wrap }}>
252+
<FlexItem flex={{ default: leftFlex }}>{leftElement || emptyText()}</FlexItem>
253+
<FlexItem flex={{ default: rightFlex }}>{rightElement || emptyText()}</FlexItem>
243254
</Flex>
244255
);
245256
};
246257

247258
const singleContainer = (child?: JSX.Element) => {
248-
return (
249-
<div className={`record-field-content ${size}`} onMouseOver={e => onMouseOver(e, 'record-field-content')}>
250-
{child ? child : emptyText()}
251-
</div>
252-
);
259+
return <div className={`record-field-content ${size}`}>{child ? child : emptyText()}</div>;
253260
};
254261

255262
const clickableContent = (text: string, content: string, docUrl?: string) => {
@@ -408,7 +415,8 @@ export const RecordField: React.FC<RecordFieldProps> = ({
408415
return nthContainer(
409416
value.map(dir => simpleTextWithTooltip(getDirectionDisplayString(String(dir) as FlowDirection, t))),
410417
true,
411-
false
418+
false,
419+
multiLineSize
412420
);
413421
}
414422
return singleContainer(simpleTextWithTooltip(getDirectionDisplayString(String(value) as FlowDirection, t)));
@@ -418,7 +426,8 @@ export const RecordField: React.FC<RecordFieldProps> = ({
418426
return nthContainer(
419427
value.map(iName => simpleTextWithTooltip(String(iName))),
420428
true,
421-
false
429+
false,
430+
multiLineSize
422431
);
423432
}
424433
return singleContainer(simpleTextWithTooltip(String(value)));
@@ -444,9 +453,12 @@ export const RecordField: React.FC<RecordFieldProps> = ({
444453
return nthContainer(
445454
flow.fields.Interfaces.map((iName, i) =>
446455
sideBySideContainer(
447-
simpleTextWithTooltip(iName),
456+
simpleTextWithTooltip(iName, undefined, undefined, multiLineSize),
448457
simpleTextWithTooltip(
449-
getDirectionDisplayString(String(flow.fields.IfDirections![i]) as FlowDirection, t)
458+
getDirectionDisplayString(String(flow.fields.IfDirections![i]) as FlowDirection, t),
459+
undefined,
460+
undefined,
461+
multiLineSize
450462
)
451463
)
452464
),
@@ -477,13 +489,16 @@ export const RecordField: React.FC<RecordFieldProps> = ({
477489
return doubleContainer(
478490
simpleTextWithTooltip(
479491
detailed ? `${sentCount} ${c.name.toLowerCase()} ${t('sent')}` : sentCount,
480-
allowPktDrops ? (isDark ? '#3E8635' : '#1E4F18') : undefined
492+
allowPktDrops ? (isDark ? '#3E8635' : '#1E4F18') : undefined,
493+
undefined,
494+
multiLineSize
481495
),
482496
droppedCount ? (
483497
simpleTextWithTooltip(
484498
detailed ? `${droppedCount} ${c.name.toLowerCase()} ${droppedText}` : droppedCount,
485499
isDark ? '#C9190B' : '#A30000',
486-
child
500+
child,
501+
multiLineSize
487502
)
488503
) : (
489504
<></>
@@ -555,8 +570,10 @@ export const RecordField: React.FC<RecordFieldProps> = ({
555570
if (Array.isArray(value) && value.length) {
556571
// we can only show two values properly with containers
557572
if (value.length === 2) {
558-
const contents = value.map(v => (isKubeObj(v) ? kubeObjContainer(v) : simpleTextWithTooltip(String(v))));
559-
return doubleContainer(contents[0], contents[1]);
573+
const contents = value.map(v =>
574+
isKubeObj(v) ? kubeObjContainer(v) : simpleTextWithTooltip(String(v), undefined, undefined, multiLineSize)
575+
);
576+
return doubleContainer(contents[0], contents[1], undefined, undefined, multiLineSize);
560577
}
561578
// else we will show values as single joigned string
562579
return singleContainer(simpleTextWithTooltip(value.map(v => String(v)).join(', ')));

0 commit comments

Comments
 (0)