diff --git a/src/app/networkDiscovery/components/NetworkForm/NetworkForm.test.tsx b/src/app/networkDiscovery/components/NetworkForm/NetworkForm.test.tsx new file mode 100644 index 0000000000..20b0af38f4 --- /dev/null +++ b/src/app/networkDiscovery/components/NetworkForm/NetworkForm.test.tsx @@ -0,0 +1,163 @@ +import configureStore from "redux-mock-store"; + +import type { NetworkDiscoverySidePanelContent } from "../../views/constants"; +import { NetworkDiscoverySidePanelViews } from "../../views/constants"; + +import NetworkForm from "./NetworkForm"; + +import type { Discovery } from "@/app/store/discovery/types"; +import type { RootState } from "@/app/store/root/types"; +import { + NodeStatus, + NodeStatusCode, + TestStatusStatus, +} from "@/app/store/types/node"; +import { callId, enableCallIdMocks } from "@/testing/callId-mock"; +import { + discovery as discoveryFactory, + domain as domainFactory, + device as deviceFactory, + machine as machineFactory, + testStatus as testStatusFactory, + modelRef as modelRefFactory, + discoveryState as discoveryStateFactory, + deviceState as deviceStateFactory, + domainState as domainStateFactory, + machineState as machineStateFactory, + subnetState as subnetStateFactory, + vlanState as vlanStateFactory, + rootState as rootStateFactory, + machineStateList as machineStateListFactory, + machineStateListGroup as machineStateListGroupFactory, +} from "@/testing/factories"; +import { renderWithBrowserRouter, screen } from "@/testing/utils"; + +const mockStore = configureStore(); +enableCallIdMocks(); + +let state: RootState; +let discovery: Discovery; + +beforeEach(() => { + const machines = [ + machineFactory({ + actions: [], + architecture: "amd64/generic", + cpu_count: 4, + cpu_test_status: testStatusFactory({ + status: TestStatusStatus.RUNNING, + }), + distro_series: "bionic", + domain: modelRefFactory({ + name: "example", + }), + extra_macs: [], + fqdn: "koala.example", + hostname: "koala", + ip_addresses: [], + memory: 8, + memory_test_status: testStatusFactory({ + status: TestStatusStatus.PASSED, + }), + network_test_status: testStatusFactory({ + status: TestStatusStatus.PASSED, + }), + osystem: "ubuntu", + owner: "admin", + permissions: ["edit", "delete"], + physical_disk_count: 1, + pool: modelRefFactory(), + pxe_mac: "00:11:22:33:44:55", + spaces: [], + status: NodeStatus.DEPLOYED, + status_code: NodeStatusCode.DEPLOYED, + status_message: "", + storage: 8, + storage_test_status: testStatusFactory({ + status: TestStatusStatus.PASSED, + }), + testing_status: TestStatusStatus.PASSED, + system_id: "abc123", + zone: modelRefFactory(), + }), + ]; + discovery = discoveryFactory({ + ip: "1.2.3.4", + mac_address: "aa:bb:cc", + subnet: 9, + vlan: 8, + }); + state = rootStateFactory({ + device: deviceStateFactory({ + loaded: true, + items: [deviceFactory({ system_id: "abc123", fqdn: "abc123.example" })], + }), + discovery: discoveryStateFactory({ + loaded: true, + items: [discovery], + }), + domain: domainStateFactory({ + loaded: true, + items: [domainFactory({ name: "local" })], + }), + machine: machineStateFactory({ + loaded: true, + items: machines, + lists: { + [callId]: machineStateListFactory({ + loaded: true, + groups: [ + machineStateListGroupFactory({ + items: [machines[0].system_id], + name: "Deployed", + }), + ], + }), + }, + }), + subnet: subnetStateFactory({ loaded: true }), + vlan: vlanStateFactory({ loaded: true }), + }); +}); + +afterAll(() => { + vi.restoreAllMocks(); +}); + +it("renders the clear discovery form when the sidepanel view is provided", () => { + const sidePanelContent: NetworkDiscoverySidePanelContent = { + view: NetworkDiscoverySidePanelViews.CLEAR_ALL_DISCOVERIES, + }; + renderWithBrowserRouter( + + ); + + expect( + screen.getByRole("form", { name: "Clear all discoveries" }) + ).toBeInTheDocument(); +}); + +it("renders the add discovery form given the sidepanel view", () => { + const store = mockStore(state); + const sidePanelContent: NetworkDiscoverySidePanelContent = { + view: NetworkDiscoverySidePanelViews.ADD_DISCOVERY, + extras: { + discovery, + }, + }; + + renderWithBrowserRouter( + , + { store } + ); + + expect( + screen.getByRole("form", { name: "Add discovery" }) + ).toBeInTheDocument(); +}); diff --git a/src/app/networkDiscovery/components/NetworkForm/NetworkForm.tsx b/src/app/networkDiscovery/components/NetworkForm/NetworkForm.tsx new file mode 100644 index 0000000000..9ff172c78e --- /dev/null +++ b/src/app/networkDiscovery/components/NetworkForm/NetworkForm.tsx @@ -0,0 +1,49 @@ +import { useCallback } from "react"; + +import type { SidePanelContentTypes } from "@/app/base/side-panel-context"; +import DiscoveryAddForm from "@/app/networkDiscovery/views/DiscoveryAddForm"; +import DiscoveryDeleteForm from "@/app/networkDiscovery/views/DiscoveryDeleteForm"; +import ClearAllForm from "@/app/networkDiscovery/views/NetworkDiscoveryHeader/ClearAllForm"; +import { NetworkDiscoverySidePanelViews } from "@/app/networkDiscovery/views/constants"; + +type Props = SidePanelContentTypes & {}; + +const NetworkForm = ({ sidePanelContent, setSidePanelContent }: Props) => { + const clearSidePanelContent = useCallback( + () => setSidePanelContent(null), + [setSidePanelContent] + ); + + if (!sidePanelContent) return null; + const discovery = + sidePanelContent.extras && "discovery" in sidePanelContent.extras + ? sidePanelContent.extras.discovery + : null; + + switch (sidePanelContent.view) { + case NetworkDiscoverySidePanelViews.ADD_DISCOVERY: { + if (!discovery) return null; + return ( + + ); + } + case NetworkDiscoverySidePanelViews.CLEAR_ALL_DISCOVERIES: + return ; + case NetworkDiscoverySidePanelViews.DELETE_DISCOVERY: { + if (!discovery) return null; + return ( + + ); + } + default: + return null; + } +}; + +export default NetworkForm; diff --git a/src/app/networkDiscovery/components/NetworkForm/index.ts b/src/app/networkDiscovery/components/NetworkForm/index.ts new file mode 100644 index 0000000000..9239013912 --- /dev/null +++ b/src/app/networkDiscovery/components/NetworkForm/index.ts @@ -0,0 +1 @@ +export { default } from "./NetworkForm"; diff --git a/src/app/networkDiscovery/views/DiscoveriesList/DiscoveriesList.test.tsx b/src/app/networkDiscovery/views/DiscoveriesList/DiscoveriesList.test.tsx index db076b6f1a..1d513cfda7 100644 --- a/src/app/networkDiscovery/views/DiscoveriesList/DiscoveriesList.test.tsx +++ b/src/app/networkDiscovery/views/DiscoveriesList/DiscoveriesList.test.tsx @@ -1,9 +1,10 @@ -import configureStore from "redux-mock-store"; +import { NetworkDiscoverySidePanelViews } from "../constants"; import DiscoveriesList, { Labels as DiscoveriesListLabels, } from "./DiscoveriesList"; +import * as sidePanelHooks from "@/app/base/side-panel-context"; import * as query from "@/app/store/machine/utils/query"; import type { RootState } from "@/app/store/root/types"; import { @@ -35,12 +36,18 @@ import { renderWithBrowserRouter, } from "@/testing/utils"; -const mockStore = configureStore(); const route = "/network-discovery"; describe("DiscoveriesList", () => { let state: RootState; + const setSidePanelContent = vi.fn(); beforeEach(() => { + vi.spyOn(sidePanelHooks, "useSidePanel").mockReturnValue({ + setSidePanelContent, + sidePanelContent: null, + setSidePanelSize: vi.fn(), + sidePanelSize: "regular", + }); vi.spyOn(query, "generateCallId").mockReturnValueOnce("123456"); const machines = [ machineFactory({ @@ -170,30 +177,26 @@ describe("DiscoveriesList", () => { ).not.toBeInTheDocument(); }); - it("can display the add form", async () => { + it("can trigger the add form sidepanel", async () => { renderWithBrowserRouter(, { route: route, state, }); const row = screen.getByRole("row", { name: "my-discovery-test" }); - expect( - screen.queryByRole("form", { name: "Add discovery" }) - ).not.toBeInTheDocument(); await userEvent.click( within(within(row).getByTestId("row-menu")).getByRole("button") ); await userEvent.click( screen.getByRole("button", { name: DiscoveriesListLabels.AddDiscovery }) ); - - await vi.waitFor(() => - expect( - screen.getByRole("form", { name: /Add discovery/ }) - ).toBeInTheDocument() + expect(setSidePanelContent).toHaveBeenCalledWith( + expect.objectContaining({ + view: NetworkDiscoverySidePanelViews.ADD_DISCOVERY, + }) ); }); - it("can display the delete form", async () => { + it("can trigger the delete form sidepanel", async () => { renderWithBrowserRouter(, { route: route, state, @@ -209,39 +212,10 @@ describe("DiscoveriesList", () => { }) ); - expect( - screen.getByText( - 'Are you sure you want to delete discovery "my-discovery-test"?' - ) - ).toBeInTheDocument(); - - expect(screen.getByRole("button", { name: "Delete" })).toBeInTheDocument(); - }); - - it("can delete a discovery", async () => { - const store = mockStore(state); - renderWithBrowserRouter(, { - route: route, - store, - }); - const row = screen.getByRole("row", { name: "my-discovery-test" }); - - // Open the action menu. - await userEvent.click( - within(within(row).getByTestId("row-menu")).getByRole("button") - ); - - // Click on the delete link. - await userEvent.click( - screen.getByRole("button", { - name: DiscoveriesListLabels.DeleteDiscovery, + expect(setSidePanelContent).toHaveBeenCalledWith( + expect.objectContaining({ + view: NetworkDiscoverySidePanelViews.DELETE_DISCOVERY, }) ); - - // Click on the confirm button. - await userEvent.click(screen.getByRole("button", { name: "Delete" })); - expect( - store.getActions().some((action) => action.type === "discovery/delete") - ).toBe(true); }); }); diff --git a/src/app/networkDiscovery/views/DiscoveriesList/DiscoveriesList.tsx b/src/app/networkDiscovery/views/DiscoveriesList/DiscoveriesList.tsx index 6d55242a96..bcb3276fa4 100644 --- a/src/app/networkDiscovery/views/DiscoveriesList/DiscoveriesList.tsx +++ b/src/app/networkDiscovery/views/DiscoveriesList/DiscoveriesList.tsx @@ -1,5 +1,4 @@ import { useState } from "react"; -import type { ReactNode } from "react"; import { Col, @@ -7,20 +6,19 @@ import { MainTable, Row, } from "@canonical/react-components"; -import classNames from "classnames"; -import { useSelector, useDispatch } from "react-redux"; -import type { Dispatch } from "redux"; +import { useSelector } from "react-redux"; -import DiscoveryAddForm from "../DiscoveryAddForm"; +import { NetworkDiscoverySidePanelViews } from "../constants"; import DiscoveriesFilterAccordion from "./DiscoveriesFilterAccordion"; import DoubleRow from "@/app/base/components/DoubleRow"; import MacAddressDisplay from "@/app/base/components/MacAddressDisplay"; import SearchBox from "@/app/base/components/SearchBox"; -import TableDeleteConfirm from "@/app/base/components/TableDeleteConfirm"; import TooltipButton from "@/app/base/components/TooltipButton"; import { useFetchActions, useWindowTitle } from "@/app/base/hooks"; +import type { SetSidePanelContent } from "@/app/base/side-panel-context"; +import { useSidePanel } from "@/app/base/side-panel-context"; import { actions as discoveryActions } from "@/app/store/discovery"; import discoverySelectors from "@/app/store/discovery/selectors"; import type { Discovery } from "@/app/store/discovery/types"; @@ -38,67 +36,16 @@ export enum Labels { EmptyList = "No discoveries available.", } -enum ExpandedType { - ADD = "add", - DELETE = "delete", -} - -type ExpandedRow = { - id: Discovery[DiscoveryMeta.PK]; - type: ExpandedType; -}; - const generateRows = ( discoveries: Discovery[], - expandedRow: ExpandedRow | null, - setExpandedRow: (expandedRow: ExpandedRow | null) => void, - saved: boolean, - saving: boolean, - dispatch: Dispatch + setSidePanelContent: SetSidePanelContent ) => discoveries.map((discovery) => { - const isExpanded = expandedRow?.id === discovery[DiscoveryMeta.PK]; const name = discovery.hostname || "Unknown"; - let expandedContent: ReactNode = null; - if (isExpanded && expandedRow?.type === ExpandedType.ADD) { - expandedContent = ( - { - setExpandedRow(null); - }} - /> - ); - } else if (isExpanded && expandedRow?.type === ExpandedType.DELETE) { - expandedContent = ( - { - setExpandedRow(null); - }} - onConfirm={() => { - dispatch( - discoveryActions.delete({ - ip: discovery.ip, - mac: discovery.mac_address, - }) - ); - }} - sidebar={false} - /> - ); - } return { key: discovery[DiscoveryMeta.PK], "aria-label": name, - className: classNames("p-table__row", { - "is-active": isExpanded, - }), + className: "p-table__row", columns: [ { content: ( @@ -142,27 +89,28 @@ const generateRows = ( { children: Labels.AddDiscovery, "data-testid": "add-discovery-link", - onClick: () => { - setExpandedRow({ - id: discovery[DiscoveryMeta.PK], - type: ExpandedType.ADD, - }); - }, + onClick: () => + setSidePanelContent({ + view: NetworkDiscoverySidePanelViews.ADD_DISCOVERY, + extras: { + discovery, + }, + }), }, { children: "Delete discovery...", "data-testid": "delete-discovery-link", - onClick: () => { - setExpandedRow({ - id: discovery[DiscoveryMeta.PK], - type: ExpandedType.DELETE, - }); - }, + onClick: () => + setSidePanelContent({ + view: NetworkDiscoverySidePanelViews.DELETE_DISCOVERY, + extras: { + discovery, + }, + }), }, ]} toggleAppearance="base" toggleClassName="row-menu-toggle u-no-margin--bottom" - toggleDisabled={isExpanded} /> ), className: "u-align--right", @@ -175,22 +123,17 @@ const generateRows = ( macAddress: discovery.mac_address, rack: discovery.observer_hostname, }, - expanded: isExpanded, - expandedContent, }; }); const DiscoveriesList = (): JSX.Element => { - const dispatch = useDispatch(); const [searchString, setSearchString] = useState(""); - const [expandedRow, setExpandedRow] = useState(null); const discoveries = useSelector((state: RootState) => discoverySelectors.search(state, searchString) ); + const { setSidePanelContent } = useSidePanel(); const loading = useSelector(discoverySelectors.loading); const loaded = useSelector(discoverySelectors.loaded); - const saving = useSelector(discoverySelectors.saving); - const saved = useSelector(discoverySelectors.saved); useWindowTitle("Network Discovery"); @@ -261,14 +204,7 @@ const DiscoveriesList = (): JSX.Element => { })} expanding headers={headers} - rows={generateRows( - discoveries, - expandedRow, - setExpandedRow, - saved, - saving, - dispatch - )} + rows={generateRows(discoveries, setSidePanelContent)} sortable /> diff --git a/src/app/networkDiscovery/views/DiscoveryAddForm/DiscoveryAddFormFields/DiscoveryAddFormFields.tsx b/src/app/networkDiscovery/views/DiscoveryAddForm/DiscoveryAddFormFields/DiscoveryAddFormFields.tsx index 7f967502fd..47bb170216 100644 --- a/src/app/networkDiscovery/views/DiscoveryAddForm/DiscoveryAddFormFields/DiscoveryAddFormFields.tsx +++ b/src/app/networkDiscovery/views/DiscoveryAddForm/DiscoveryAddFormFields/DiscoveryAddFormFields.tsx @@ -71,7 +71,7 @@ const DiscoveryAddFormFields = ({ return ( <> - + )} - + (); +enableCallIdMocks(); + +let state: RootState; +let discovery: Discovery; + +beforeEach(() => { + const machines = [ + machineFactory({ + actions: [], + architecture: "amd64/generic", + cpu_count: 4, + cpu_test_status: testStatusFactory({ + status: TestStatusStatus.RUNNING, + }), + distro_series: "bionic", + domain: modelRefFactory({ + name: "example", + }), + extra_macs: [], + fqdn: "koala.example", + hostname: "koala", + ip_addresses: [], + memory: 8, + memory_test_status: testStatusFactory({ + status: TestStatusStatus.PASSED, + }), + network_test_status: testStatusFactory({ + status: TestStatusStatus.PASSED, + }), + osystem: "ubuntu", + owner: "admin", + permissions: ["edit", "delete"], + physical_disk_count: 1, + pool: modelRefFactory(), + pxe_mac: "00:11:22:33:44:55", + spaces: [], + status: NodeStatus.DEPLOYED, + status_code: NodeStatusCode.DEPLOYED, + status_message: "", + storage: 8, + storage_test_status: testStatusFactory({ + status: TestStatusStatus.PASSED, + }), + testing_status: TestStatusStatus.PASSED, + system_id: "abc123", + zone: modelRefFactory(), + }), + ]; + discovery = discoveryFactory({ + ip: "1.2.3.4", + mac_address: "aa:bb:cc", + subnet: 9, + vlan: 8, + }); + state = rootStateFactory({ + device: deviceStateFactory({ + loaded: true, + items: [deviceFactory({ system_id: "abc123", fqdn: "abc123.example" })], + }), + discovery: discoveryStateFactory({ + loaded: true, + items: [discovery], + }), + domain: domainStateFactory({ + loaded: true, + items: [domainFactory({ name: "local" })], + }), + machine: machineStateFactory({ + loaded: true, + items: machines, + lists: { + [callId]: machineStateListFactory({ + loaded: true, + groups: [ + machineStateListGroupFactory({ + items: [machines[0].system_id], + name: "Deployed", + }), + ], + }), + }, + }), + subnet: subnetStateFactory({ loaded: true }), + vlan: vlanStateFactory({ loaded: true }), + }); +}); + +afterAll(() => { + vi.restoreAllMocks(); +}); + +it("renders", () => { + const store = mockStore(state); + renderWithBrowserRouter( + , + { store } + ); +}); + +it("can dispatch an action to delete a discovery", async () => { + const store = mockStore(state); + renderWithBrowserRouter( + , + { store } + ); + + await userEvent.click(screen.getByRole("button", { name: /delete/i })); + + expect( + store.getActions().find((action) => action.type === "discovery/delete") + ).toStrictEqual( + discoveryActions.delete({ ip: discovery.ip, mac: discovery.mac_address }) + ); +}); diff --git a/src/app/networkDiscovery/views/DiscoveryDeleteForm/DiscoveryDeleteForm.tsx b/src/app/networkDiscovery/views/DiscoveryDeleteForm/DiscoveryDeleteForm.tsx new file mode 100644 index 0000000000..159511311e --- /dev/null +++ b/src/app/networkDiscovery/views/DiscoveryDeleteForm/DiscoveryDeleteForm.tsx @@ -0,0 +1,40 @@ +import { useDispatch, useSelector } from "react-redux"; + +import ModelDeleteForm from "@/app/base/components/ModelDeleteForm"; +import { actions as discoveryActions } from "@/app/store/discovery"; +import discoverySelectors from "@/app/store/discovery/selectors"; +import type { Discovery } from "@/app/store/discovery/types"; + +type Props = { + discovery: Discovery; + onClose: () => void; +}; + +const DiscoveryDeleteForm = ({ discovery, onClose }: Props) => { + const dispatch = useDispatch(); + const saving = useSelector(discoverySelectors.saving); + const saved = useSelector(discoverySelectors.saved); + return ( + { + dispatch( + discoveryActions.delete({ + ip: discovery.ip, + mac: discovery.mac_address, + }) + ); + }} + saved={saved} + saving={saving} + /> + ); +}; + +export default DiscoveryDeleteForm; diff --git a/src/app/networkDiscovery/views/DiscoveryDeleteForm/index.ts b/src/app/networkDiscovery/views/DiscoveryDeleteForm/index.ts new file mode 100644 index 0000000000..05efa1d1a3 --- /dev/null +++ b/src/app/networkDiscovery/views/DiscoveryDeleteForm/index.ts @@ -0,0 +1 @@ +export { default } from "./DiscoveryDeleteForm"; diff --git a/src/app/networkDiscovery/views/NetworkDiscovery.tsx b/src/app/networkDiscovery/views/NetworkDiscovery.tsx index 94233f9c4e..6ae547cefd 100644 --- a/src/app/networkDiscovery/views/NetworkDiscovery.tsx +++ b/src/app/networkDiscovery/views/NetworkDiscovery.tsx @@ -2,11 +2,11 @@ import { Notification } from "@canonical/react-components"; import { useSelector } from "react-redux"; import { Route, Routes } from "react-router-dom-v5-compat"; +import NetworkForm from "../components/NetworkForm"; + import DiscoveriesList from "./DiscoveriesList"; import NetworkDiscoveryConfigurationForm from "./NetworkDiscoveryConfigurationForm"; import NetworkDiscoveryHeader from "./NetworkDiscoveryHeader"; -import ClearAllForm from "./NetworkDiscoveryHeader/ClearAllForm"; -import { NetworkDiscoverySidePanelViews } from "./constants"; import PageContent from "@/app/base/components/PageContent"; import SectionHeader from "@/app/base/components/SectionHeader"; @@ -15,6 +15,7 @@ import urls from "@/app/base/urls"; import NotFound from "@/app/base/views/NotFound"; import authSelectors from "@/app/store/auth/selectors"; import configSelectors from "@/app/store/config/selectors"; +import { getSidePanelTitle } from "@/app/store/utils/node/base"; import { getRelativeRoute } from "@/app/utils"; export enum Label { @@ -37,29 +38,21 @@ const NetworkDiscovery = (): JSX.Element => { ); } - let content: JSX.Element | null = null; - - if ( - sidePanelContent?.view === - NetworkDiscoverySidePanelViews.CLEAR_ALL_DISCOVERIES - ) { - content = ( - { - setSidePanelContent(null); - }} - /> - ); - } - const base = urls.networkDiscovery.index; return ( } - sidePanelContent={content} - sidePanelTitle="Clear all discoveries" + sidePanelContent={ + sidePanelContent && ( + + ) + } + sidePanelTitle={getSidePanelTitle("Network discovery", sidePanelContent)} // "Clear all discoveries" > {networkDiscovery === "disabled" && ( {Label.Disabled} diff --git a/src/app/networkDiscovery/views/NetworkDiscoveryHeader/ClearAllForm/ClearAllForm.tsx b/src/app/networkDiscovery/views/NetworkDiscoveryHeader/ClearAllForm/ClearAllForm.tsx index 59453b0b87..d5e8b0b86a 100644 --- a/src/app/networkDiscovery/views/NetworkDiscoveryHeader/ClearAllForm/ClearAllForm.tsx +++ b/src/app/networkDiscovery/views/NetworkDiscoveryHeader/ClearAllForm/ClearAllForm.tsx @@ -63,6 +63,7 @@ const ClearAllForm = ({ closeForm }: Props): JSX.Element => { } return ( + aria-label="Clear all discoveries" cleanup={cleanup} errors={errors} initialValues={{}} diff --git a/src/app/networkDiscovery/views/constants.ts b/src/app/networkDiscovery/views/constants.ts index ce6ae18f57..4056be0acd 100644 --- a/src/app/networkDiscovery/views/constants.ts +++ b/src/app/networkDiscovery/views/constants.ts @@ -1,11 +1,15 @@ import type { ValueOf } from "@canonical/react-components"; import type { SidePanelContent } from "@/app/base/types"; +import type { Discovery } from "@/app/store/discovery/types"; export const NetworkDiscoverySidePanelViews = { + ADD_DISCOVERY: ["", "addDiscovery"], CLEAR_ALL_DISCOVERIES: ["", "clearAllDiscoveries"], + DELETE_DISCOVERY: ["", "deleteDiscovery"], } as const; export type NetworkDiscoverySidePanelContent = SidePanelContent< - ValueOf + ValueOf, + { discovery?: Discovery } >; diff --git a/src/app/store/utils/node/base.ts b/src/app/store/utils/node/base.ts index 0c148c1022..89d717607b 100644 --- a/src/app/store/utils/node/base.ts +++ b/src/app/store/utils/node/base.ts @@ -200,6 +200,8 @@ export const getSidePanelTitle = ( return "Add controller"; case SidePanelViews.ADD_CHASSIS[1]: return "Add chassis"; + case SidePanelViews.ADD_DISCOVERY[1]: + return "Add discovery"; case SidePanelViews.ADD_INTERFACE[1]: return "Add interface"; case SidePanelViews.ADD_MACHINE[1]: @@ -214,12 +216,16 @@ export const getSidePanelTitle = ( return "Add VLAN"; case SidePanelViews.CHANGE_SOURCE[1]: return "Change source"; + case SidePanelViews.CLEAR_ALL_DISCOVERIES[1]: + return "Clear all discoveries"; case SidePanelViews.CREATE_DATASTORE[1]: return "Create datastore"; case SidePanelViews.CREATE_RAID[1]: return "Create raid"; case SidePanelViews.CREATE_VOLUME_GROUP[1]: return "Create volume group"; + case SidePanelViews.DELETE_DISCOVERY[1]: + return "Delete discovery"; case SidePanelViews.DeleteTag[1]: return "Delete tag"; case SidePanelViews.EDIT_INTERFACE[1]: