Skip to content

Commit

Permalink
Merge pull request #93 from jpinsonneau/topology_view
Browse files Browse the repository at this point in the history
NETOBSERV-179 Topology: create page layout & toolbar
  • Loading branch information
jpinsonneau authored Mar 17, 2022
2 parents dffba1f + 61cba18 commit 07c5945
Show file tree
Hide file tree
Showing 24 changed files with 303 additions and 143 deletions.
46 changes: 25 additions & 21 deletions web/locales/en/plugin__network-observability-plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,26 @@
"Compact": "Compact",
"Normal": "Normal",
"Large": "Large",
"Source": "Source",
"Destination": "Destination",
"Both": "Both",
"Match all": "Match all",
"Match any": "Match any",
"Every flow can be reported from the source node and/or the destination node. For in-cluster traffic, usually both source and destination nodes report flows, resulting in duplicated data. Cluster ingress traffic is only reported by destination nodes, and cluster egress by source nodes.": "Every flow can be reported from the source node and/or the destination node. For in-cluster traffic, usually both source and destination nodes report flows, resulting in duplicated data. Cluster ingress traffic is only reported by destination nodes, and cluster egress by source nodes.",
"Reporter node": "Reporter node",
"Whether each query result has to match all the filters or just any of them": "Whether each query result has to match all the filters or just any of them",
"Match filters": "Match filters",
"Limit": "Limit",
"Query Options": "Query Options",
"Refresh off": "Refresh off",
"{{count}} second": "{{count}} second",
"{{count}} second_plural": "{{count}} second",
"{{count}} minute": "{{count}} minute",
"{{count}} minute_plural": "{{count}} minute",
"{{count}} hour": "{{count}} hour",
"{{count}} hour_plural": "{{count}} hour",
"{{count}} day": "{{count}} day",
"{{count}} day_plural": "{{count}} day",
"Specify a single port number or name.": "Specify a single port number or name.",
"Specify a single port following one of these rules:": "Specify a single port following one of these rules:",
"A port number like 80, 21": "A port number like 80, 21",
Expand Down Expand Up @@ -62,8 +82,6 @@
"Export": "Export",
"Following query will be exported as CSV format:": "Following query will be exported as CSV format:",
"Time Range": "Time Range",
"Reporter node": "Reporter node",
"Limit": "Limit",
"Close": "Close",
"Export all datas": "Export all datas",
"Use this option to export every fields and labels from flows.": "Use this option to export every fields and labels from flows.",
Expand All @@ -86,27 +104,13 @@
"Unable to get flows": "Unable to get flows",
"No results found": "No results found",
"Clear all filters and try again.": "Clear all filters and try again.",
"Network Traffic": "Network Traffic",
"Unable to get topology": "Unable to get topology",
"TODO": "TODO",
"Flow Table": "Flow Table",
"Topology": "Topology",
"Column management": "Column management",
"Export management": "Export management",
"Source": "Source",
"Destination": "Destination",
"Both": "Both",
"Match all": "Match all",
"Match any": "Match any",
"Every flow can be reported from the source node and/or the destination node. For in-cluster traffic, usually both source and destination nodes report flows, resulting in duplicated data. Cluster ingress traffic is only reported by destination nodes, and cluster egress by source nodes.": "Every flow can be reported from the source node and/or the destination node. For in-cluster traffic, usually both source and destination nodes report flows, resulting in duplicated data. Cluster ingress traffic is only reported by destination nodes, and cluster egress by source nodes.",
"Whether each query result has to match all the filters or just any of them": "Whether each query result has to match all the filters or just any of them",
"Match filters": "Match filters",
"Query Options": "Query Options",
"Refresh off": "Refresh off",
"{{count}} second": "{{count}} second",
"{{count}} second_plural": "{{count}} second",
"{{count}} minute": "{{count}} minute",
"{{count}} minute_plural": "{{count}} minute",
"{{count}} hour": "{{count}} hour",
"{{count}} hour_plural": "{{count}} hour",
"{{count}} day": "{{count}} day",
"{{count}} day_plural": "{{count}} day",
"Network Traffic": "Network Traffic",
"Names": "Names",
"Kinds": "Kinds",
"Owners": "Owners",
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/__tests__/filters-toolbar.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('<FiltersToolbar />', () => {
const wrapper = shallow(<FiltersToolbar {...props} />);
expect(wrapper.find(FiltersToolbar)).toBeTruthy();
expect(wrapper.find(Toolbar)).toBeTruthy();
expect(wrapper.find(ToolbarItem)).toHaveLength(3);
expect(wrapper.find(ToolbarItem)).toHaveLength(2);
expect(wrapper.find(Dropdown)).toBeTruthy();
expect(wrapper.find(Button)).toBeTruthy();
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Radio, Select } from '@patternfly/react-core';
import { shallow } from 'enzyme';
import { act } from 'react-dom/test-utils';
import QueryOptionsDropdown, { QueryOptionsDropdownProps, QueryOptionsPanel } from '../query-options-dropdown';
import { QueryOptions } from '../../model/query-options';
import { QueryOptions } from '../../../model/query-options';

describe('<QueryOptionsDropdown />', () => {
const props: QueryOptionsDropdownProps = {
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Radio, Select, Tooltip } from '@patternfly/react-core';
import { InfoAltIcon } from '@patternfly/react-icons';
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { Match, QueryOptions, Reporter } from '../model/query-options';
import { Match, QueryOptions, Reporter } from '../../model/query-options';

export interface QueryOptionsDropdownProps {
options: QueryOptions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { Dropdown, DropdownToggle, DropdownItem } from '@patternfly/react-core';
import * as _ from 'lodash';
import { parseDuration, formatDuration } from '../utils/duration';
import { parseDuration, formatDuration } from '../../utils/duration';

export type RefreshDropdownProps = {
interval?: number;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as React from 'react';
import { useTranslation } from 'react-i18next';
import { Dropdown, DropdownToggle, DropdownItem } from '@patternfly/react-core';
import { parseDuration, formatDuration, getDateMsInSeconds, getDateSInMiliseconds } from '../utils/duration';
import { getTimeRangeOptions } from '../utils/datetime';
import { parseDuration, formatDuration, getDateMsInSeconds, getDateSInMiliseconds } from '../../utils/duration';
import { getTimeRangeOptions } from '../../utils/datetime';
import * as _ from 'lodash';

export type TimeRangeDropdownProps = {
Expand Down
5 changes: 5 additions & 0 deletions web/src/components/filters-toolbar.css
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,9 @@ button.pf-c-button.pf-m-link.pf-m-inline:empty {
/* stick "Learn more" text */
#more {
padding: 5px 0px 0px 5px;
}

/* force new row for forced filters group*/
#forced-filters {
flex-basis: 100%;
}
70 changes: 34 additions & 36 deletions web/src/components/filters-toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
Toolbar,
ToolbarContent,
ToolbarFilter,
ToolbarGroup,
ToolbarItem,
Tooltip,
ValidatedOptions
Expand Down Expand Up @@ -50,7 +51,7 @@ import {
import './filters-toolbar.css';
import { validateIPFilter } from '../utils/ip';
import { QueryOptions } from '../model/query-options';
import { QueryOptionsDropdown } from './query-options-dropdown';
import { QueryOptionsDropdown } from './dropdowns/query-options-dropdown';
import { getPathWithParams, NETFLOW_TRAFFIC_PATH } from '../utils/router';
import { useHistory } from 'react-router-dom';
import { validateK8SName } from '../utils/label';
Expand Down Expand Up @@ -524,8 +525,8 @@ export const FiltersToolbar: React.FC<FiltersToolbarProps> = ({
<ToolbarItem className="flex-start">
<QueryOptionsDropdown options={props.queryOptions} setOptions={props.setQueryOptions} />
</ToolbarItem>
<ToolbarItem className="flex-start">
{_.isEmpty(forcedFilters) ? (
{_.isEmpty(forcedFilters) && (
<ToolbarItem className="flex-start">
<Tooltip
//css hide tooltip here to avoid render issue
className={`filters-tooltip${_.isEmpty(message) ? '-empty' : ''}`}
Expand Down Expand Up @@ -563,39 +564,9 @@ export const FiltersToolbar: React.FC<FiltersToolbarProps> = ({
<FilterHints type={selectedFilterColumn.filterType} name={selectedFilterColumn.name} />
</div>
</Tooltip>
) : (
forcedFilters &&
forcedFilters.map((forcedFilter, ffIndex) => (
<ChipGroup
key={ffIndex}
isClosable={false}
categoryName={getFullColumnName(columns.find(c => c.id === forcedFilter.colId))}
>
{forcedFilter.values.map((forcedValue, fvIndex) => (
<Chip key={fvIndex} isReadOnly={true}>
{forcedValue.display ? forcedValue.display : forcedValue.v}
</Chip>
))}
</ChipGroup>
))
)}
</ToolbarItem>
{!_.isEmpty(forcedFilters) && (
<ToolbarItem className="flex-start">
<OverflowMenu breakpoint="md">
<OverflowMenuGroup groupType="button" isPersistent>
<Button onClick={() => push(getPathWithParams(NETFLOW_TRAFFIC_PATH))}>{t('Edit filters')}</Button>
</OverflowMenuGroup>
</OverflowMenu>
</ToolbarItem>
)}
<ToolbarItem className="flex-start">
<OverflowMenu breakpoint="md">
<OverflowMenuGroup groupType="button" isPersistent>
{props.children}
</OverflowMenuGroup>
</OverflowMenu>
</ToolbarItem>
{props.children && <ToolbarItem className="flex-start">{props.children}</ToolbarItem>}
{actions && (
<ToolbarItem className="flex-start" alignment={{ default: 'alignRight' }}>
<OverflowMenu breakpoint="md">
Expand All @@ -605,7 +576,7 @@ export const FiltersToolbar: React.FC<FiltersToolbarProps> = ({
</OverflowMenu>
</ToolbarItem>
)}
{_.isEmpty(forcedFilters) &&
{_.isEmpty(forcedFilters) ? (
filters &&
filters.map((filter, index) => (
<ToolbarFilter
Expand All @@ -629,7 +600,34 @@ export const FiltersToolbar: React.FC<FiltersToolbarProps> = ({
<div></div>
}
</ToolbarFilter>
))}
))
) : (
<ToolbarGroup id="forced-filters" variant="filter-group">
<ToolbarItem className="flex-start">
{forcedFilters &&
forcedFilters.map((forcedFilter, ffIndex) => (
<ChipGroup
key={ffIndex}
isClosable={false}
categoryName={getFullColumnName(columns.find(c => c.id === forcedFilter.colId))}
>
{forcedFilter.values.map((forcedValue, fvIndex) => (
<Chip key={fvIndex} isReadOnly={true}>
{forcedValue.display ? forcedValue.display : forcedValue.v}
</Chip>
))}
</ChipGroup>
))}
</ToolbarItem>
<ToolbarItem className="flex-start">
<OverflowMenu breakpoint="md">
<OverflowMenuGroup groupType="button" isPersistent>
<Button onClick={() => push(getPathWithParams(NETFLOW_TRAFFIC_PATH))}>{t('Edit filters')}</Button>
</OverflowMenuGroup>
</OverflowMenu>
</ToolbarItem>
</ToolbarGroup>
)}
{/* TODO : NETOBSERV-104
<ToolbarItem variant="pagination">
<Pagination
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Button } from '@patternfly/react-core';
import { shallow } from 'enzyme';
import * as React from 'react';
import { Size } from '../../display-dropdown';
import { DefaultColumns } from '../../__tests-data__/columns';
import { FlowsSample } from '../../__tests-data__/flows';
import RecordField, { RecordFieldFilter } from '../record-field';
import { Size } from '../../dropdowns/display-dropdown';

describe('<RecordField />', () => {
const filterMock: RecordFieldFilter = {
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/netflow-record/record-field.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { FlowDirection, Record } from '../../api/ipfix';
import { Column, ColumnsId, getFullColumnName } from '../../utils/columns';
import { formatPort } from '../../utils/port';
import { formatProtocol } from '../../utils/protocol';
import { Size } from '../display-dropdown';
import { Size } from '../dropdowns/display-dropdown';
import './record-field.css';

export type RecordFieldFilter = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import NetflowTableRow from '../netflow-table-row';
import { Record } from '../../../api/ipfix';
import { DefaultColumns } from '../../__tests-data__/columns';
import { FlowsSample } from '../../__tests-data__/flows';
import { Size } from '../../display-dropdown';
import { Size } from '../../dropdowns/display-dropdown';

describe('<NetflowTableRow />', () => {
let flows: Record[] = [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { NetflowTableHeader } from '../netflow-table-header';

import { ShuffledDefaultColumns } from '../../__tests-data__/columns';
import { FlowsSample } from '../../__tests-data__/flows';
import { Size } from '../../display-dropdown';
import { Size } from '../../dropdowns/display-dropdown';

const errorStateQuery = `EmptyState[data-test="error-state"]`;
const loadingContentsQuery = `Bullseye[data-test="loading-contents"]`;
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/netflow-table/netflow-table-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Td, Tr } from '@patternfly/react-table';
import * as React from 'react';
import { Record } from '../../api/ipfix';
import { Column } from '../../utils/columns';
import { Size } from '../display-dropdown';
import { Size } from '../dropdowns/display-dropdown';
import { RecordField } from '../netflow-record/record-field';
import './netflow-table-row.css';
import CSSTransition from 'react-transition-group/CSSTransition';
Expand Down
2 changes: 1 addition & 1 deletion web/src/components/netflow-table/netflow-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { Record } from '../../api/ipfix';
import { NetflowTableHeader } from './netflow-table-header';
import NetflowTableRow from './netflow-table-row';
import { Column } from '../../utils/columns';
import { Size } from '../display-dropdown';
import { Size } from '../dropdowns/display-dropdown';

const NetflowTable: React.FC<{
flows: Record[];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { shallow } from 'enzyme';
import * as React from 'react';
import NetflowTopology from '../netflow-topology';

describe('<NetflowTopology />', () => {
it('should render component', async () => {
const wrapper = shallow(<NetflowTopology />);
expect(wrapper.find(NetflowTopology)).toBeTruthy();
});
});
31 changes: 31 additions & 0 deletions web/src/components/netflow-topology/netflow-topology.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Bullseye, EmptyState, EmptyStateBody, EmptyStateVariant, Spinner, Title } from '@patternfly/react-core';
import * as React from 'react';
import { useTranslation } from 'react-i18next';

const NetflowTopology: React.FC<{
loading?: boolean;
error?: string;
}> = ({ error, loading }) => {
const { t } = useTranslation('plugin__network-observability-plugin');

if (error) {
return (
<EmptyState data-test="error-state" variant={EmptyStateVariant.small}>
<Title headingLevel="h2" size="lg">
{t('Unable to get topology')}
</Title>
<EmptyStateBody>{error}</EmptyStateBody>
</EmptyState>
);
} else if (loading) {
return (
<Bullseye data-test="loading-contents">
<Spinner size="xl" />
</Bullseye>
);
}

return <div>{t('TODO')}</div>;
};

export default NetflowTopology;
19 changes: 19 additions & 0 deletions web/src/components/netflow-traffic.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
.actions {
display: flex;
flex-direction: row;
align-items: baseline;
}

/*hack to keep refresh button size while loading*/

.co-action-refresh-button {
Expand All @@ -16,6 +22,7 @@ span.pf-c-button__icon.pf-m-start {
from {
transform: rotate(0deg);
}

to {
transform: rotate(360deg);
}
Expand All @@ -36,4 +43,16 @@ span.pf-c-button__icon.pf-m-start {

#drawer {
z-index: 0;
}

/* flex page header */
#pageHeader {
display: flex;
flex-direction: row;
margin-bottom: 10px;
padding-right: var(--pf-global--spacer--md);
}

.flex {
flex: 1;
}
Loading

0 comments on commit 07c5945

Please sign in to comment.