Skip to content

Commit 96f1243

Browse files
authored
truncate chart texts option (#239)
1 parent f00ace5 commit 96f1243

16 files changed

+161
-94
lines changed

web/src/components/dropdowns/__tests__/truncate-dropdown.spec.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import * as React from 'react';
22
import { mount, shallow } from 'enzyme';
33

4-
import TruncateDropdown from '../truncate-dropdown';
5-
import { TopologyTruncateLength } from '../../../model/topology';
4+
import { TruncateDropdown, TruncateLength } from '../truncate-dropdown';
65

76
describe('<TruncateDropdown />', () => {
87
const props = {
9-
selected: TopologyTruncateLength.M,
8+
selected: TruncateLength.M,
109
setTruncateLength: jest.fn(),
1110
id: 'truncate'
1211
};
@@ -37,13 +36,13 @@ describe('<TruncateDropdown />', () => {
3736
//open dropdown and select NONE
3837
dropdown.at(0).simulate('click');
3938
wrapper.find('[id="0"]').at(0).simulate('click');
40-
expect(props.setTruncateLength).toHaveBeenCalledWith(TopologyTruncateLength.OFF);
39+
expect(props.setTruncateLength).toHaveBeenCalledWith(TruncateLength.OFF);
4140
expect(wrapper.find('li').length).toBe(0);
4241

4342
//open dropdown and select OWNERS
4443
dropdown.at(0).simulate('click');
4544
wrapper.find('[id="40"]').at(0).simulate('click');
46-
expect(props.setTruncateLength).toHaveBeenCalledWith(TopologyTruncateLength.XL);
45+
expect(props.setTruncateLength).toHaveBeenCalledWith(TruncateLength.XL);
4746
expect(wrapper.find('li').length).toBe(0);
4847

4948
//setTruncateLength should be called twice

web/src/components/dropdowns/overview-display-dropdown.tsx

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { MetricScope, MetricType } from '../../model/flow-query';
77
import MetricTypeDropdown from './metric-type-dropdown';
88
import './overview-display-dropdown.css';
99
import ScopeDropdown from './scope-dropdown';
10+
import TruncateDropdown, { TruncateLength } from './truncate-dropdown';
1011

1112
export type Size = 's' | 'm' | 'l';
1213

@@ -15,7 +16,9 @@ export const OverviewDisplayOptions: React.FC<{
1516
setMetricType: (t: MetricType) => void;
1617
metricScope: MetricScope;
1718
setMetricScope: (s: MetricScope) => void;
18-
}> = ({ metricType, setMetricType, metricScope, setMetricScope }) => {
19+
truncateLength: TruncateLength;
20+
setTruncateLength: (v: TruncateLength) => void;
21+
}> = ({ metricType, setMetricType, metricScope, setMetricScope, truncateLength, setTruncateLength }) => {
1922
const { t } = useTranslation('plugin__netobserv-plugin');
2023

2124
return (
@@ -46,6 +49,18 @@ export const OverviewDisplayOptions: React.FC<{
4649
<ScopeDropdown data-test="scope" id="scope" selected={metricScope} setScopeType={setMetricScope} />
4750
</div>
4851
</div>
52+
<div className="pf-c-select__menu-group">
53+
<Tooltip content={t('Long labels can reduce visibility.')}>
54+
<div className="pf-c-select__menu-group-title">
55+
<>
56+
{t('Truncate labels')} <InfoAltIcon />
57+
</>
58+
</div>
59+
</Tooltip>
60+
<div className="display-dropdown-padding">
61+
<TruncateDropdown id="truncate" selected={truncateLength} setTruncateLength={setTruncateLength} />
62+
</div>
63+
</div>
4964
</>
5065
);
5166
};
@@ -55,7 +70,9 @@ export const OverviewDisplayDropdown: React.FC<{
5570
setMetricType: (t: MetricType) => void;
5671
metricScope: MetricScope;
5772
setMetricScope: (s: MetricScope) => void;
58-
}> = ({ metricType, setMetricType, metricScope, setMetricScope }) => {
73+
truncateLength: TruncateLength;
74+
setTruncateLength: (v: TruncateLength) => void;
75+
}> = ({ metricType, setMetricType, metricScope, setMetricScope, truncateLength, setTruncateLength }) => {
5976
const { t } = useTranslation('plugin__netobserv-plugin');
6077
const [isOpen, setOpen] = React.useState<boolean>(false);
6178

@@ -72,6 +89,8 @@ export const OverviewDisplayDropdown: React.FC<{
7289
setMetricType={setMetricType}
7390
metricScope={metricScope}
7491
setMetricScope={setMetricScope}
92+
truncateLength={truncateLength}
93+
setTruncateLength={setTruncateLength}
7594
/>
7695
}
7796
/>

web/src/components/dropdowns/topology-display-dropdown.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ import * as React from 'react';
44
import { useTranslation } from 'react-i18next';
55
import { MetricFunction, MetricScope, MetricType } from '../../model/flow-query';
66
import { MetricScopeOptions } from '../../model/metrics';
7-
import { LayoutName, TopologyGroupTypes, TopologyOptions, TopologyTruncateLength } from '../../model/topology';
7+
import { LayoutName, TopologyGroupTypes, TopologyOptions } from '../../model/topology';
88
import GroupDropdown from './group-dropdown';
99
import LayoutDropdown from './layout-dropdown';
10-
import TruncateDropdown from './truncate-dropdown';
10+
import TruncateDropdown, { TruncateLength } from './truncate-dropdown';
1111

1212
import './topology-display-dropdown.css';
1313
import MetricFunctionDropdown from './metric-function-dropdown';
@@ -51,7 +51,7 @@ export const TopologyDisplayOptions: React.FC<{
5151
});
5252
};
5353

54-
const setTruncateLength = (truncateLength: TopologyTruncateLength) => {
54+
const setTruncateLength = (truncateLength: TruncateLength) => {
5555
setTopologyOptions({
5656
...topologyOptions,
5757
truncateLength

web/src/components/dropdowns/truncate-dropdown.tsx

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,35 @@
11
import { Dropdown, DropdownItem, DropdownToggle } from '@patternfly/react-core';
22
import * as React from 'react';
33
import { useTranslation } from 'react-i18next';
4-
import { TopologyTruncateLength } from '../../model/topology';
4+
5+
export enum TruncateLength {
6+
OFF = 0,
7+
XS = 10,
8+
S = 20,
9+
M = 25,
10+
L = 30,
11+
XL = 40
12+
}
513

614
export const TruncateDropdown: React.FC<{
7-
selected: TopologyTruncateLength;
8-
setTruncateLength: (v: TopologyTruncateLength) => void;
15+
selected: TruncateLength;
16+
setTruncateLength: (v: TruncateLength) => void;
917
id?: string;
1018
}> = ({ selected, setTruncateLength, id }) => {
1119
const { t } = useTranslation('plugin__netobserv-plugin');
1220
const [truncateDropdownOpen, setTruncateDropdownOpen] = React.useState(false);
1321

14-
const getTruncateDisplay = (v: TopologyTruncateLength) => {
22+
const getTruncateDisplay = (v: TruncateLength) => {
1523
switch (v) {
16-
case TopologyTruncateLength.XL:
24+
case TruncateLength.XL:
1725
return t('XL');
18-
case TopologyTruncateLength.L:
26+
case TruncateLength.L:
1927
return t('L');
20-
case TopologyTruncateLength.M:
28+
case TruncateLength.M:
2129
return t('M');
22-
case TopologyTruncateLength.S:
30+
case TruncateLength.S:
2331
return t('S');
24-
case TopologyTruncateLength.XS:
32+
case TruncateLength.XS:
2533
return t('XS');
2634
default:
2735
return t('None');
@@ -43,13 +51,13 @@ export const TruncateDropdown: React.FC<{
4351
}
4452
isOpen={truncateDropdownOpen}
4553
dropdownItems={[
46-
TopologyTruncateLength.OFF,
47-
TopologyTruncateLength.XS,
48-
TopologyTruncateLength.S,
49-
TopologyTruncateLength.M,
50-
TopologyTruncateLength.L,
51-
TopologyTruncateLength.XL
52-
].map((v: TopologyTruncateLength) => (
54+
TruncateLength.OFF,
55+
TruncateLength.XS,
56+
TruncateLength.S,
57+
TruncateLength.M,
58+
TruncateLength.L,
59+
TruncateLength.XL
60+
].map((v: TruncateLength) => (
5361
<DropdownItem
5462
data-test={String(v)}
5563
id={String(v)}

web/src/components/metrics/metrics-content.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,5 @@
44
}
55

66
.small-chart-label>tspan {
7-
font-size: 10px !important;
7+
font-size: 11px !important;
88
}

web/src/components/metrics/metrics-content.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ export type MetricsContentProps = {
3030
showArea?: boolean;
3131
showScatter?: boolean;
3232
smallerTexts?: boolean;
33+
itemsPerRow?: number;
3334
};
3435

3536
export const MetricsContent: React.FC<MetricsContentProps> = ({
@@ -43,7 +44,8 @@ export const MetricsContent: React.FC<MetricsContentProps> = ({
4344
showBar,
4445
showArea,
4546
showScatter,
46-
smallerTexts
47+
smallerTexts,
48+
itemsPerRow
4749
}) => {
4850
const filteredMetrics = metrics.slice(0, limit);
4951

@@ -56,6 +58,7 @@ export const MetricsContent: React.FC<MetricsContentProps> = ({
5658

5759
const legentComponent = (
5860
<ChartLegend
61+
itemsPerRow={itemsPerRow ? itemsPerRow : 1}
5962
labelComponent={<ChartLabel className={smallerTexts ? 'small-chart-label' : ''} />}
6063
data={legendData}
6164
/>
@@ -81,7 +84,7 @@ export const MetricsContent: React.FC<MetricsContentProps> = ({
8184
ariaTitle={title}
8285
containerComponent={chartVoronoi(legendData, metricType)}
8386
legendData={legendData}
84-
legendOrientation="vertical"
87+
legendOrientation={'horizontal'}
8588
legendPosition="bottom-left"
8689
legendAllowWrap={true}
8790
legendComponent={legentComponent}
@@ -92,7 +95,7 @@ export const MetricsContent: React.FC<MetricsContentProps> = ({
9295
height={dimensions.height}
9396
domainPadding={{ x: 0, y: 0 }}
9497
padding={{
95-
bottom: legendData.length * 25 + 75,
98+
bottom: (itemsPerRow && itemsPerRow > 1 ? legendData.length / 2 + 1 : legendData.length) * 25 + 75,
9699
left: 90,
97100
right: 50,
98101
top: 50

web/src/components/metrics/metrics-helper.tsx

Lines changed: 39 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
import * as React from 'react';
21
import { ChartLegendTooltip, createContainer, getResizeObserver } from '@patternfly/react-charts';
32
import { TFunction } from 'i18next';
3+
import * as React from 'react';
44
import { NamedMetric, TopologyMetricPeer, TopologyMetrics } from '../../api/loki';
5+
import { MetricScope, MetricType } from '../../model/flow-query';
56
import { NodeData } from '../../model/topology';
67
import { getDateFromUnix, getFormattedDate } from '../../utils/datetime';
78
import { getFormattedRateValue, matchPeer } from '../../utils/metrics';
8-
import { MetricScope, MetricType } from '../../model/flow-query';
9+
import { TruncateLength } from '../dropdowns/truncate-dropdown';
910

1011
export type LegendDataItem = {
1112
childName?: string;
@@ -51,30 +52,37 @@ export const chartVoronoi = (legendData: LegendDataItem[], metricType: MetricTyp
5152
);
5253
};
5354

54-
//TODO: NETOBSERV-688 add this as tab options
55-
// function truncate(input: string) {
56-
// const length = doubleWidth ? 64 : showDonut ? 10 : 18;
57-
// if (input.length > length) {
58-
// return input.substring(0, length / 2) + '…' + input.substring(input.length - length / 2);
59-
// }
60-
// return input;
61-
// }
55+
const truncate = (input: string, length: number) => {
56+
if (input.length > length) {
57+
return input.substring(0, length / 2) + '…' + input.substring(input.length - length / 2);
58+
}
59+
return input;
60+
};
61+
62+
const truncateParts = (input: string, length: number) => {
63+
if (length === 0) {
64+
return input;
65+
}
6266

63-
// function truncateParts(input: string) {
64-
// if (input.includes('.')) {
65-
// const splitted = input.split('.');
66-
// const result: string[] = [];
67-
// splitted.forEach(s => {
68-
// result.push(truncate(s));
69-
// });
70-
// return result.join('.');
71-
// }
72-
// return truncate(input);
73-
// }
67+
if (input.includes('.')) {
68+
const splitted = input.split('.');
69+
const result: string[] = [];
70+
splitted.forEach(s => {
71+
result.push(truncate(s, length / splitted.length));
72+
});
73+
return result.join('.');
74+
}
75+
return truncate(input, length);
76+
};
7477

75-
const getPeerName = (t: TFunction, peer: TopologyMetricPeer, scope: MetricScope): string => {
78+
const getPeerName = (
79+
t: TFunction,
80+
peer: TopologyMetricPeer,
81+
scope: MetricScope,
82+
truncateLength: TruncateLength = TruncateLength.OFF
83+
): string => {
7684
if (peer.displayName) {
77-
return peer.displayName;
85+
return truncateParts(peer.displayName, truncateLength);
7886
}
7987
if (scope === 'app') {
8088
// No peer distinction here
@@ -90,9 +98,14 @@ const getPeerName = (t: TFunction, peer: TopologyMetricPeer, scope: MetricScope)
9098
}
9199
};
92100

93-
export const toNamedMetric = (t: TFunction, m: TopologyMetrics, data?: NodeData): NamedMetric => {
94-
const srcName = getPeerName(t, m.source, m.scope);
95-
const dstName = getPeerName(t, m.destination, m.scope);
101+
export const toNamedMetric = (
102+
t: TFunction,
103+
m: TopologyMetrics,
104+
data?: NodeData,
105+
truncateLength: TruncateLength = TruncateLength.OFF
106+
): NamedMetric => {
107+
const srcName = getPeerName(t, m.source, m.scope, truncateLength);
108+
const dstName = getPeerName(t, m.destination, m.scope, truncateLength);
96109
if (srcName === dstName) {
97110
if (m.source.displayName) {
98111
// E.g: namespace "netobserv" to "netobserv"

web/src/components/metrics/metrics-total-content.tsx

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export type MetricsTotalContentProps = {
3636
showTotal: boolean;
3737
showInternal: boolean;
3838
showOutOfScope: boolean;
39+
smallerTexts?: boolean;
3940
};
4041

4142
export const MetricsTotalContent: React.FC<MetricsTotalContentProps> = ({
@@ -47,7 +48,8 @@ export const MetricsTotalContent: React.FC<MetricsTotalContentProps> = ({
4748
limit,
4849
showTotal,
4950
showInternal,
50-
showOutOfScope
51+
showOutOfScope,
52+
smallerTexts
5153
}) => {
5254
let filtered = topKMetrics;
5355
if (!showInternal) {
@@ -71,7 +73,13 @@ export const MetricsTotalContent: React.FC<MetricsTotalContentProps> = ({
7173
const topKDatapoints: ChartDataPoint[][] = filtered.map(toDatapoints);
7274
const totalDatapoints: ChartDataPoint[] = toDatapoints(totalMetric);
7375

74-
const legentComponent = <ChartLegend labelComponent={<ChartLabel />} data={legendData} />;
76+
const legentComponent = (
77+
<ChartLegend
78+
itemsPerRow={2}
79+
labelComponent={<ChartLabel className={smallerTexts ? 'small-chart-label' : ''} />}
80+
data={legendData}
81+
/>
82+
);
7583

7684
const containerRef = React.createRef<HTMLDivElement>();
7785
const [dimensions, setDimensions] = React.useState<Dimensions>(defaultDimensions);
@@ -88,7 +96,7 @@ export const MetricsTotalContent: React.FC<MetricsTotalContentProps> = ({
8896
ariaTitle={title}
8997
containerComponent={chartVoronoi(legendData, metricType)}
9098
legendData={legendData}
91-
legendOrientation="vertical"
99+
legendOrientation="horizontal"
92100
legendPosition="bottom-left"
93101
legendAllowWrap={true}
94102
legendComponent={legentComponent}
@@ -99,7 +107,7 @@ export const MetricsTotalContent: React.FC<MetricsTotalContentProps> = ({
99107
height={dimensions.height}
100108
domainPadding={{ x: 0, y: 0 }}
101109
padding={{
102-
bottom: legendData.length * 25 + 75,
110+
bottom: (legendData.length / 2) * 25 + 100,
103111
left: 90,
104112
right: 50,
105113
top: 50

web/src/components/metrics/stat-donut.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export const StatDonut: React.FC<StatDonutProps> = ({
113113
padding={{
114114
bottom: 20,
115115
left: 20,
116-
right: 300,
116+
right: 400,
117117
top: 20
118118
}}
119119
title={`${getFormattedRateValue(total, metricType)}`}

web/src/components/netflow-overview/__tests__/netflow-overview.spec.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { MetricType } from '../../../model/flow-query';
88
import { SamplePanel, ShuffledDefaultPanels } from '../../__tests-data__/panels';
99
import { NetflowOverview, NetflowOverviewProps } from '../netflow-overview';
1010
import { NetflowOverviewPanel } from '../netflow-overview-panel';
11+
import { TruncateLength } from '../../../components/dropdowns/truncate-dropdown';
1112

1213
describe('<NetflowOverview />', () => {
1314
const props: NetflowOverviewProps = {
@@ -18,7 +19,8 @@ describe('<NetflowOverview />', () => {
1819
metricType: 'bytes' as MetricType,
1920
metrics: [],
2021
totalMetric: undefined,
21-
filterActionLinks: <></>
22+
filterActionLinks: <></>,
23+
truncateLength: TruncateLength.M
2224
};
2325
it('should render component', async () => {
2426
const wrapper = shallow(<NetflowOverview {...props} />);

0 commit comments

Comments
 (0)