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
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { mount, shallow } from 'enzyme';
import * as React from 'react';

import { MetricType } from '../../../model/flow-query';
import { MetricTypeDropdown } from '../metric-type-dropdown';

describe('<MetricDropdown />', () => {
const props = {
allowedTypes: ['Bytes', 'Packets'] as MetricType[],
selected: 'Bytes',
setMetricType: jest.fn(),
id: 'metric'
Expand Down
28 changes: 3 additions & 25 deletions web/src/components/dropdowns/metric-type-dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,41 +6,19 @@ import { MetricType } from '../../model/flow-query';
export interface MetricTypeDropdownProps {
selected?: string;
setMetricType: (v: MetricType) => void;
isTopology?: boolean;
allowPktDrop?: boolean;
allowDNSMetric?: boolean;
allowRTTMetric?: boolean;
allowedTypes: MetricType[];
id?: string;
}

export const MetricTypeDropdown: React.FC<MetricTypeDropdownProps> = ({
selected,
setMetricType,
id,
isTopology,
allowPktDrop,
allowDNSMetric,
allowRTTMetric
allowedTypes
}) => {
const { t } = useTranslation('plugin__netobserv-plugin');
const [metricDropdownOpen, setMetricDropdownOpen] = React.useState(false);

const getMetricTypeOptions = React.useCallback(() => {
let options: MetricType[] = ['Bytes', 'Packets'];
if (isTopology) {
if (allowPktDrop) {
options = options.concat('PktDropBytes', 'PktDropPackets');
}
if (allowDNSMetric) {
options.push('DnsLatencyMs');
}
if (allowRTTMetric) {
options.push('TimeFlowRttNs');
}
}
return options;
}, [allowDNSMetric, allowPktDrop, allowRTTMetric, isTopology]);

const getMetricDisplay = React.useCallback(
(metricType: MetricType): string => {
switch (metricType) {
Expand Down Expand Up @@ -78,7 +56,7 @@ export const MetricTypeDropdown: React.FC<MetricTypeDropdownProps> = ({
</DropdownToggle>
}
isOpen={metricDropdownOpen}
dropdownItems={getMetricTypeOptions().map(v => (
dropdownItems={allowedTypes.map(v => (
<DropdownItem
data-test={v}
id={v}
Expand Down
12 changes: 3 additions & 9 deletions web/src/components/dropdowns/topology-display-dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ export const TopologyDisplayDropdown: React.FC<{
setMetricScope: (s: FlowScope) => void;
topologyOptions: TopologyOptions;
setTopologyOptions: (o: TopologyOptions) => void;
allowPktDrop: boolean;
allowDNSMetric: boolean;
allowRTTMetric: boolean;
allowedTypes: MetricType[];
allowedScopes: FlowScope[];
}> = ({
metricFunction,
Expand All @@ -28,9 +26,7 @@ export const TopologyDisplayDropdown: React.FC<{
setMetricScope,
topologyOptions,
setTopologyOptions,
allowPktDrop,
allowDNSMetric,
allowRTTMetric,
allowedTypes,
allowedScopes
}) => {
const { t } = useTranslation('plugin__netobserv-plugin');
Expand All @@ -53,9 +49,7 @@ export const TopologyDisplayDropdown: React.FC<{
setMetricScope={setMetricScope}
topologyOptions={topologyOptions}
setTopologyOptions={setTopologyOptions}
allowPktDrop={allowPktDrop}
allowDNSMetric={allowDNSMetric}
allowRTTMetric={allowRTTMetric}
allowedTypes={allowedTypes}
allowedScopes={allowedScopes}
/>
}
Expand Down
13 changes: 3 additions & 10 deletions web/src/components/dropdowns/topology-display-options.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,7 @@ export interface TopologyDisplayOptionsProps {
setMetricScope: (s: FlowScope) => void;
topologyOptions: TopologyOptions;
setTopologyOptions: (o: TopologyOptions) => void;
allowPktDrop: boolean;
allowDNSMetric: boolean;
allowRTTMetric: boolean;
allowedTypes: MetricType[];
allowedScopes: FlowScope[];
}

Expand All @@ -39,9 +37,7 @@ export const TopologyDisplayOptions: React.FC<TopologyDisplayOptionsProps> = ({
setMetricScope,
topologyOptions,
setTopologyOptions,
allowPktDrop,
allowDNSMetric,
allowRTTMetric,
allowedTypes,
allowedScopes
}) => {
const { t } = useTranslation('plugin__netobserv-plugin');
Expand Down Expand Up @@ -92,12 +88,9 @@ export const TopologyDisplayOptions: React.FC<TopologyDisplayOptionsProps> = ({
<MetricTypeDropdown
data-test="metricType"
id="metricType"
isTopology
selected={metricType}
setMetricType={setMetricType}
allowPktDrop={allowPktDrop}
allowDNSMetric={allowDNSMetric}
allowRTTMetric={allowRTTMetric}
allowedTypes={allowedTypes}
/>
</FlexItem>
</Flex>
Expand Down
96 changes: 54 additions & 42 deletions web/src/components/netflow-traffic.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import { useTranslation } from 'react-i18next';
import { defaultNetflowMetrics, Stats } from '../api/loki';
import { Config } from '../model/config';
import { Filters, getDisabledFiltersRecord, getEnabledFilters } from '../model/filters';
import { filtersToString, FlowQuery, FlowScope, isTimeMetric, MetricType } from '../model/flow-query';
import { MetricScopeOptions } from '../model/metrics';
import { filtersToString, FlowQuery, FlowScope, MetricType } from '../model/flow-query';
import { netflowTrafficModel } from '../model/netflow-traffic';
import { parseQuickFilters } from '../model/quick-filters';
import { getGroupsForScope, TopologyGroupTypes } from '../model/topology';
import { TopologyGroupTypes } from '../model/topology';
import { getFetchFunctions as getBackAndForthFetch } from '../utils/back-and-forth';
import { ColumnsId, getDefaultColumns } from '../utils/columns';
import { loadConfig } from '../utils/config';
Expand All @@ -29,8 +28,11 @@ import { mergeStats } from '../utils/metrics';
import { dnsIdMatcher, droppedIdMatcher, getDefaultOverviewPanels, rttIdMatcher } from '../utils/overview-panels';
import { usePoll } from '../utils/poll-hook';
import {
defaultMetricScope,
defaultMetricType,
defaultTimeRange,
getFiltersFromURL,
setURLDatasource,
setURLFilters,
setURLLimit,
setURLMatch,
Expand All @@ -44,7 +46,6 @@ import {
import { useTheme } from '../utils/theme-hook';
import { getURLParams, hasEmptyParams, netflowTrafficPath, removeURLParam, setURLParams, URLParam } from '../utils/url';
import NetflowTrafficDrawer, { NetflowTrafficDrawerHandle } from './drawer/netflow-traffic-drawer';
import { rateMetricFunctions, timeMetricFunctions } from './dropdowns/metric-function-dropdown';
import { limitValues, topValues } from './dropdowns/query-options-panel';
import { RefreshDropdown } from './dropdowns/refresh-dropdown';
import TimeRangeDropdown from './dropdowns/time-range-dropdown';
Expand Down Expand Up @@ -171,6 +172,22 @@ export const NetflowTraffic: React.FC<NetflowTrafficProps> = ({
return scopes;
}, [isMultiCluster, isZones, dataSourceHasLabels]);

const getAllowedMetricTypes = React.useCallback(() => {
let options: MetricType[] = ['Bytes', 'Packets'];
if (model.selectedViewId === 'topology') {
if (isPktDrop()) {
options = options.concat('PktDropBytes', 'PktDropPackets');
}
if (isDNSTracking()) {
options.push('DnsLatencyMs');
}
if (isFlowRTT()) {
options.push('TimeFlowRttNs');
}
}
return options;
}, [isDNSTracking, isFlowRTT, isPktDrop, model.selectedViewId]);

const getAvailablePanels = React.useCallback(() => {
return model.panels.filter(
panel =>
Expand Down Expand Up @@ -200,25 +217,6 @@ export const NetflowTraffic: React.FC<NetflowTrafficProps> = ({
return getAvailableColumns().filter(column => column.isSelected);
}, [getAvailableColumns]);

const updateTopologyMetricType = React.useCallback(
(metricType: MetricType) => {
if (isTimeMetric(metricType)) {
// fallback on average if current function not available for time queries
if (!timeMetricFunctions.includes(model.topologyMetricFunction)) {
model.setTopologyMetricFunction('avg');
}
} else {
// fallback on average if current function not available for rate queries
if (!rateMetricFunctions.includes(model.topologyMetricFunction)) {
model.setTopologyMetricFunction('avg');
}
}
model.setTopologyMetricType(metricType);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[model.topologyMetricFunction, model.setTopologyMetricFunction, model.setTopologyMetricType]
);

const getFilterDefs = React.useCallback(() => {
return getFilterDefinitions(model.config.filters, model.config.columns, t).filter(
fd =>
Expand Down Expand Up @@ -504,19 +502,6 @@ export const NetflowTraffic: React.FC<NetflowTrafficProps> = ({
]);
usePoll(tick, model.interval);

const setMetricScope = React.useCallback(
(scope: FlowScope) => {
model.setMetricScope(scope);
// Invalidate groups if necessary, when metrics scope changed
const groups = getGroupsForScope(scope as MetricScopeOptions);
if (!groups.includes(model.topologyOptions.groupTypes)) {
model.setTopologyOptions({ ...model.topologyOptions, groupTypes: TopologyGroupTypes.none });
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[model.setMetricScope, model.topologyOptions, model.setTopologyOptions]
);

const clearFilters = React.useCallback(() => {
if (forcedFilters) {
navigate(netflowTrafficPath);
Expand All @@ -529,6 +514,8 @@ export const NetflowTraffic: React.FC<NetflowTrafficProps> = ({
}, [forcedFilters, model.filters, updateTableFilters]);

// Effects

// invalidate record type if not available
React.useEffect(() => {
if (initState.current.includes('configLoaded')) {
if (model.recordType === 'flowLog' && !isFlow() && isConnectionTracking()) {
Expand All @@ -540,6 +527,7 @@ export const NetflowTraffic: React.FC<NetflowTrafficProps> = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [model.config.recordTypes, isConnectionTracking, isFlow, model.recordType]);

// invalidate datasource if not available
React.useEffect(() => {
if (
initState.current.includes('configLoaded') &&
Expand All @@ -551,6 +539,31 @@ export const NetflowTraffic: React.FC<NetflowTrafficProps> = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [allowLoki, allowProm, model.dataSource]);

// invalidate packet loss if not available
React.useEffect(() => {
if (initState.current.includes('configLoaded') && !isPktDrop() && model.packetLoss !== 'all') {
model.setPacketLoss('all');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isPktDrop, model.packetLoss, model.setPacketLoss]);

// invalidate metric scope / group if not available
React.useEffect(() => {
if (initState.current.includes('configLoaded') && !getAllowedScopes().includes(model.metricScope)) {
model.setMetricScope(defaultMetricScope);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [getAllowedScopes, model.metricScope, model.setMetricScope]);

// invalidate metric type / function if not available
React.useEffect(() => {
if (initState.current.includes('configLoaded') && !getAllowedMetricTypes().includes(model.topologyMetricType)) {
model.setTopologyMetricType(defaultMetricType);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [getAllowedMetricTypes, model.topologyMetricType, model.setTopologyMetricType]);

// select columns / panels from local storage
React.useEffect(() => {
if (initState.current.includes('configLoaded')) {
model.setColumns(
Expand Down Expand Up @@ -671,6 +684,10 @@ export const NetflowTraffic: React.FC<NetflowTrafficProps> = ({
setURLRecortType(model.recordType, !initState.current.includes('configLoaded'));
}, [model.recordType]);

React.useEffect(() => {
setURLDatasource(model.dataSource, !initState.current.includes('configLoaded'));
}, [model.dataSource]);

// update local storage saved query params
React.useEffect(() => {
if (!forcedFilters) {
Expand Down Expand Up @@ -865,12 +882,8 @@ export const NetflowTraffic: React.FC<NetflowTrafficProps> = ({
<ViewOptionsToolbar
{...model}
isDarkTheme={isDarkTheme}
setMetricType={updateTopologyMetricType}
allowPktDrop={isPktDrop()}
allowDNSMetric={isDNSTracking()}
allowRTTMetric={isFlowRTT()}
allowedTypes={getAllowedMetricTypes()}
allowedScopes={getAllowedScopes()}
setMetricScope={setMetricScope}
ref={searchRef}
/>
)}
Expand All @@ -885,7 +898,6 @@ export const NetflowTraffic: React.FC<NetflowTrafficProps> = ({
allowPktDrop={isPktDrop()}
allowDNSMetric={isDNSTracking()}
allowRTTMetric={isFlowRTT()}
setMetricScope={setMetricScope}
resetDefaultFilters={resetDefaultFilters}
clearFilters={clearFilters}
filterDefinitions={getFilterDefs()}
Expand Down
3 changes: 2 additions & 1 deletion web/src/components/tabs/netflow-overview/panel-kebab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,8 @@ export const PanelKebab: React.FC<PanelKebabProps> = ({ id, options, setOptions,
<Divider key="first-divider" component="li" />
</div>
);
}, [id, options, setGraph, t]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [id, options, setGraph]);

const items = [];
if (options?.graph?.options?.length) {
Expand Down
12 changes: 4 additions & 8 deletions web/src/components/toolbar/view-options-toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,10 @@ export interface ViewOptionsToolbarProps {
topologyMetricFunction: StatFunction;
setTopologyMetricFunction: (f: StatFunction) => void;
topologyMetricType: MetricType;
setMetricType: (t: MetricType) => void;
setTopologyMetricType: (t: MetricType) => void;
topologyOptions: TopologyOptions;
setTopologyOptions: (o: TopologyOptions) => void;
allowPktDrop: boolean;
allowDNSMetric: boolean;
allowRTTMetric: boolean;
allowedTypes: MetricType[];
allowedScopes: FlowScope[];
size: Size;
setSize: (v: Size) => void;
Expand Down Expand Up @@ -247,14 +245,12 @@ export const ViewOptionsToolbar: React.FC<ViewOptionsToolbarProps> = React.forwa
metricFunction={props.topologyMetricFunction}
setMetricFunction={props.setTopologyMetricFunction}
metricType={props.topologyMetricType}
setMetricType={props.setMetricType}
setMetricType={props.setTopologyMetricType}
metricScope={props.metricScope}
setMetricScope={props.setMetricScope}
topologyOptions={props.topologyOptions}
setTopologyOptions={props.setTopologyOptions}
allowPktDrop={props.allowPktDrop}
allowDNSMetric={props.allowDNSMetric}
allowRTTMetric={props.allowRTTMetric}
allowedTypes={props.allowedTypes}
allowedScopes={props.allowedScopes}
/>
)}
Expand Down
Loading
Loading