Skip to content
Open
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
1 change: 1 addition & 0 deletions src/nmstate-types/react-resize-panel.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module 'react-resize-panel';
Original file line number Diff line number Diff line change
@@ -1,5 +0,0 @@
.nmstate-policy-wizard {
.pf-v6-c-wizard__main-body {
padding-left: 0;
}
}
98 changes: 54 additions & 44 deletions src/views/nodenetworkconfiguration/Topology.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { FC, useEffect, useMemo, useState } from 'react';
import { useHistory } from 'react-router';
import { NodeModelGroupVersionKind } from 'src/console-models/NodeModel';

import './components/TopologySidebar/TopologySidebar.scss';
import { IoK8sApiCoreV1Node } from '@kubevirt-ui/kubevirt-api/kubernetes/models';
import {
V1beta1NodeNetworkConfigurationEnactment,
Expand Down Expand Up @@ -37,23 +37,24 @@ import { filterPolicyAppliedNodes } from '@utils/resources/policies/utils';

import TopologyLegend from './components/TopologyLegend/TopologyLegend';
import { SELECTED_ID_QUERY_PARAM } from './components/TopologySidebar/constants';
import TopologyDrawer from './components/TopologySidebar/InterfaceDrawer/TopologyDrawer';
import { creatingPolicySignal } from './components/TopologySidebar/CreatePolicyDrawer';
import TopologySidebar from './components/TopologySidebar/TopologySidebar';
import TopologyToolbar from './components/TopologyToolbar/TopologyToolbar';
import { GRAPH_POSITIONING_EVENT, NODE_POSITIONING_EVENT } from './utils/constants';
import { componentFactory, layoutFactory } from './utils/factory';
import { restoreNodePositions, saveNodePositions } from './utils/position';
import { transformDataToTopologyModel } from './utils/utils';
import CustomDrawer from './components/TopologySidebar/CustomDrawer';

const Topology: FC = () => {
useSignals();

const [visualization, setVisualization] = useState<Visualization>(null);
const [isOpen, setIsOpen] = useState<boolean>(false);
const [selectedNodeFilters, setSelectedNodeFilters] = useState<string[]>([]);
const history = useHistory();

const queryParams = useQueryParams();

const [nodes] = useK8sWatchResource<IoK8sApiCoreV1Node[]>({
groupVersionKind: NodeModelGroupVersionKind,
isList: true,
Expand Down Expand Up @@ -134,7 +135,10 @@ const Topology: FC = () => {
creatingPolicySignal.value,
creatingPolicyNodesNames,
]);

const handleCloseDrawer = (isOpen: boolean) => {
history.push({ search: '' });
setIsOpen(isOpen);
};
if (statesError && statesError?.response?.status === 403)
return (
<>
Expand All @@ -147,47 +151,53 @@ const Topology: FC = () => {

return (
<VisualizationProvider controller={visualization}>
<TopologyView
className="nmstate-topology"
sideBar={<TopologySidebar states={states} />}
viewToolbar={
<TopologyToolbar
nodeNames={nodeNames}
selectedNodeFilters={selectedNodeFilters}
setSelectedNodeFilters={setSelectedNodeFilters}
/>
}
controlBar={
<TopologyControlBar
controlButtons={createTopologyControlButtons({
...defaultControlButtonsOptions,
zoomInCallback: action(() => {
const scale = visualization.getGraph().getScale();
visualization.getGraph().setScale(scale * 1.1);
}),
zoomOutCallback: action(() => {
const scale = visualization.getGraph().getScale();
visualization.getGraph().setScale(scale * 0.9);
}),
fitToScreenCallback: action(() => {
visualization.getGraph().fit(40);
}),
resetViewCallback: action(() => {
visualization.getGraph().reset();
visualization.getGraph().layout();
}),
})}
/>
}
<TopologyDrawer
isOpen={isOpen}
onClose={handleCloseDrawer}
panel={<CustomDrawer states={states} onClose={() => history.push({ search: '' })} />}
>
<VisualizationSurface state={queryParams} />
<Popover
aria-label="Node network configuration graph legend"
bodyContent={<TopologyLegend />}
hasAutoWidth
triggerRef={() => document.getElementById('legend') as HTMLButtonElement}
/>
</TopologyView>
<TopologyView
className="nmstate-topology"
viewToolbar={
<TopologyToolbar
nodeNames={nodeNames}
onOpen={handleCloseDrawer}
selectedNodeFilters={selectedNodeFilters}
setSelectedNodeFilters={setSelectedNodeFilters}
/>
}
controlBar={
<TopologyControlBar
controlButtons={createTopologyControlButtons({
...defaultControlButtonsOptions,
zoomInCallback: action(() => {
const scale = visualization.getGraph().getScale();
visualization.getGraph().setScale(scale * 1.1);
}),
zoomOutCallback: action(() => {
const scale = visualization.getGraph().getScale();
visualization.getGraph().setScale(scale * 0.9);
}),
fitToScreenCallback: action(() => {
visualization.getGraph().fit(40);
}),
resetViewCallback: action(() => {
visualization.getGraph().reset();
visualization.getGraph().layout();
}),
})}
/>
}
>
<VisualizationSurface state={queryParams} />
<Popover
aria-label="Node network configuration graph legend"
bodyContent={<TopologyLegend />}
hasAutoWidth
triggerRef={() => document.getElementById('legend') as HTMLButtonElement}
/>
</TopologyView>
</TopologyDrawer>
</VisualizationProvider>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import {
import { logCreationFailed, logNMStateEvent, logNNCPCreated } from '@utils/telemetry/telemetry';

type CreatePolicyDrawerProps = {
onClose?: () => void;
onClose?: (b: boolean) => void;
onSuccess?: (message: string) => void;
physicalNetworkName?: string;
resetPolicyWizard: () => void;
Expand Down Expand Up @@ -89,7 +89,7 @@ const CreatePolicyDrawer: FC<CreatePolicyDrawerProps> = ({

const closeDrawer = () => {
creatingPolicySignal.value = null;
onClose();
onClose(true);
};

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type DrawerProps = {
onSuccess?: (message: string) => void;
};

const Drawer: FC<DrawerProps> = ({ states, onClose, onSuccess }) => {
const CustomDrawer: FC<DrawerProps> = ({ states, onClose, onSuccess }) => {
const params = useQueryParams();
const [resetKey, setResetKey] = useState<number>(0);

Expand Down Expand Up @@ -57,4 +57,4 @@ const Drawer: FC<DrawerProps> = ({ states, onClose, onSuccess }) => {
return null;
};

export default Drawer;
export default CustomDrawer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React, { FC, ReactNode } from 'react';
import {
Drawer,
DrawerContent,
DrawerContentBody,
DrawerPanelContent,
DrawerPanelBody,
Button,
} from '@patternfly/react-core';
import TimesIcon from '@patternfly/react-icons/dist/esm/icons/times-icon';

type Props = {
isOpen: boolean;
onClose: (b: boolean) => void;
panel: ReactNode;
children: ReactNode;
};

const TopologyDrawer: FC<Props> = ({ isOpen, onClose, panel, children }) => (
<Drawer isExpanded={isOpen} position="left">
<DrawerContent
panelContent={
<DrawerPanelContent
isResizable
defaultSize="1000px"
minSize="150px"
role="dialog"
aria-label="Topology side panel"
className="drawerPanelContent"
>
<DrawerPanelBody>
<Button
variant="plain"
onClick={() => onClose(false)}
aria-label="Close"
style={{ position: 'absolute', top: 8, right: 8, zIndex: 1 }}
>
<TimesIcon />
</Button>
{isOpen && panel}
</DrawerPanelBody>
</DrawerPanelContent>
}
>
<DrawerContentBody>{children}</DrawerContentBody>
</DrawerContent>
</Drawer>
);

export default TopologyDrawer;
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
}
}

.nmstate-policy-wizard .pf-v6-c-wizard__main-body {
padding: 20px;
}

.pf-topology-side-bar.nmstate-topology__sidebar.big-sidebar {
@media (min-width: 768px) {
max-width: 100%;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
import React, { FC, useState } from 'react';
import { useHistory } from 'react-router';
import classNames from 'classnames';

import { V1beta1NodeNetworkState } from '@kubevirt-ui/kubevirt-api/nmstate';
import { Alert, AlertActionCloseButton, AlertVariant } from '@patternfly/react-core';
import { TopologySideBar } from '@patternfly/react-topology';
import { isEmpty } from '@utils/helpers';
import useQueryParams from '@utils/hooks/useQueryParams';

import { CREATE_POLICY_QUERY_PARAM, SELECTED_ID_QUERY_PARAM } from './constants';
import Drawer from './Drawer';

import CustomDrawer from './CustomDrawer';
import './TopologySidebar.scss';

type TopologySidebarProps = {
Expand All @@ -34,7 +32,6 @@ const TopologySidebar: FC<TopologySidebarProps> = ({ states }) => {
return (
<TopologySideBar
show={showSidebar}
onClose={selectedIDExist ? closeDrawer : null}
className={classNames('nmstate-topology__sidebar', { 'big-sidebar': createPolicyDrawer })}
>
<div className="nmstate-topology__sidebar__content">
Expand All @@ -48,7 +45,7 @@ const TopologySidebar: FC<TopologySidebarProps> = ({ states }) => {
/>
</div>
)}
<Drawer states={states} onClose={closeDrawer} onSuccess={setSuccessMessage} />
<CustomDrawer states={states} onClose={closeDrawer} onSuccess={setSuccessMessage} />
</div>
</TopologySideBar>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.pf-v6-c-toolbar__group.pf-topology-view__view-toolbar {
width: 100%;
padding-left: 200px;
.pf-v6-c-toolbar {
width: 100%;
}
Expand All @@ -10,6 +11,7 @@ div[id^='pf-topology-view-'] {
}

.topology-toolbar {
width: 100%;
padding: var(--pf-t--global--spacer--md) 0;
&__content {
padding: 0 var(--pf-t--global--spacer--md);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React, { Dispatch, FC, SetStateAction } from 'react';
import { useHistory } from 'react-router';
import { useNavigate } from 'react-router-dom-v5-compat';
import NodeNetworkConfigurationPolicyModel from 'src/console-models/NodeNetworkConfigurationPolicyModel';

import { NodeNetworkConfigurationPolicyModelRef, NodeNetworkStateModelRef } from '@models';
import { ListPageCreateDropdown } from '@openshift-console/dynamic-plugin-sdk';
import {
Expand All @@ -16,25 +15,26 @@ import {
import { ListIcon } from '@patternfly/react-icons';
import { getResourceUrl } from '@utils/helpers';
import { useNMStateTranslation } from '@utils/hooks/useNMStateTranslation';

import { CREATE_POLICY_QUERY_PARAM } from '../TopologySidebar/constants';

import TopologyToolbarFilter from './TopologyToolbarFilter';

import './TopologyToolbar.scss';

type TopologyToolbarProps = {
selectedNodeFilters: string[];
setSelectedNodeFilters: Dispatch<SetStateAction<string[]>>;
nodeNames: string[];
onOpen: (b: boolean) => void;
};

const TopologyButton: FC<TopologyToolbarProps> = (props) => {
const TopologyToolbar: FC<TopologyToolbarProps> = ({
setSelectedNodeFilters,
onOpen,
nodeNames,
selectedNodeFilters,
}) => {
const { t } = useNMStateTranslation();
const navigate = useNavigate();
const setSelectedNodeFilters = props.setSelectedNodeFilters;
const history = useHistory();

const createItems = {
form: t('From Form'),
yaml: t('With YAML'),
Expand All @@ -46,10 +46,12 @@ const TopologyButton: FC<TopologyToolbarProps> = (props) => {
});

const newParams = new URLSearchParams({ [CREATE_POLICY_QUERY_PARAM]: 'true' });

return type === 'form'
? history.push({ search: newParams.toString() })
: history.push(`${baseURL}~new`);
if (type === 'form') {
onOpen(true);
return history.push({ search: newParams.toString() });
} else {
return history.push(`${baseURL}~new`);
}
};

return (
Expand All @@ -66,7 +68,11 @@ const TopologyButton: FC<TopologyToolbarProps> = (props) => {
>
{t('Create')}
</ListPageCreateDropdown>
<TopologyToolbarFilter {...props} />
<TopologyToolbarFilter
selectedNodeFilters={selectedNodeFilters}
nodeNames={nodeNames}
setSelectedNodeFilters={setSelectedNodeFilters}
/>
</ToolbarGroup>
<ToolbarGroup>
<ToolbarItem className="list-view-btn">
Expand All @@ -83,4 +89,4 @@ const TopologyButton: FC<TopologyToolbarProps> = (props) => {
);
};

export default TopologyButton;
export default TopologyToolbar;