diff --git a/src/components/organisms/HeaderSecond/HeaderSecond.tsx b/src/components/organisms/HeaderSecond/HeaderSecond.tsx index 1d0d561..10b588f 100644 --- a/src/components/organisms/HeaderSecond/HeaderSecond.tsx +++ b/src/components/organisms/HeaderSecond/HeaderSecond.tsx @@ -8,9 +8,10 @@ import { Styled } from './styled' type THeaderProps = { inside?: boolean + isSearch?: boolean } -export const HeaderSecond: FC = ({ inside }) => { +export const HeaderSecond: FC = ({ inside, isSearch }) => { // const { projectName, instanceName, clusterName, entryType, namespace, syntheticProject } = useParams() const { projectName, instanceName, clusterName, namespace, syntheticProject } = useParams() const { token } = theme.useToken() @@ -24,14 +25,14 @@ export const HeaderSecond: FC = ({ inside }) => { {inside ? : } {inside && } - {!inside && BASE_USE_NAMESPACE_NAV !== 'true' && ( + {!inside && !isSearch && BASE_USE_NAMESPACE_NAV !== 'true' && ( )} - {!inside && BASE_USE_NAMESPACE_NAV === 'true' && ( + {!inside && (isSearch || BASE_USE_NAMESPACE_NAV === 'true') && ( )} diff --git a/src/components/organisms/HeaderSecond/organisms/SelectorNamespace/SelectorNamespace.tsx b/src/components/organisms/HeaderSecond/organisms/SelectorNamespace/SelectorNamespace.tsx index 41e2a40..c3bf2a1 100644 --- a/src/components/organisms/HeaderSecond/organisms/SelectorNamespace/SelectorNamespace.tsx +++ b/src/components/organisms/HeaderSecond/organisms/SelectorNamespace/SelectorNamespace.tsx @@ -1,9 +1,12 @@ import React, { FC, useState } from 'react' import { Flex, Typography } from 'antd' -import { useNavigate } from 'react-router-dom' +import { useLocation, useNavigate } from 'react-router-dom' import { useDirectUnknownResource } from '@prorobotech/openapi-k8s-toolkit' +import { useSelector } from 'react-redux' +import type { RootState } from 'store/store' import { useNavSelectorInside } from 'hooks/useNavSelectorInside' import { useMountEffect } from 'hooks/useMountEffect' +import { useIsSearchPage } from 'hooks/useIsSearchPage' import { EntrySelect } from 'components/atoms' import { BASE_API_GROUP, @@ -19,6 +22,9 @@ type TSelectorNamespaceProps = { export const SelectorNamespace: FC = ({ clusterName, namespace }) => { const navigate = useNavigate() + const location = useLocation() + + const baseprefix = useSelector((state: RootState) => state.baseprefix.baseprefix) const [selectedClusterName, setSelectedClusterName] = useState(clusterName) const [selectedNamespace, setSelectedNamespace] = useState(namespace) @@ -34,7 +40,45 @@ export const SelectorNamespace: FC = ({ clusterName, na isEnabled: clusterName !== undefined, }) + const isSearchPage = useIsSearchPage(baseprefix || '') + const handleNamepsaceChange = (value?: string) => { + if (isSearchPage) { + const { pathname, search, hash } = location + const segs = pathname.split('/') + + // Assume pattern: /prefix/:clusterName/:namespace?/:syntheticProject?/search/* + // Find the "search" segment index + const searchIdx = segs.indexOf('search') + const clusterIdx = segs.indexOf(selectedClusterName || '') + if (clusterIdx === -1) { + return + } // bail if we can't find the cluster + + const nsIdx = clusterIdx + 1 // where namespace would live if present + const spIdx = clusterIdx + 2 // where syntheticProject would live if present + const nsExists = nsIdx < searchIdx // true if something occupies ns slot + const spExists = spIdx < searchIdx // true if something occupies sp slot + + if (value && value !== 'all') { + setSelectedNamespace(value) + + if (nsExists) { + // replace namespace in place + segs[nsIdx] = value + } else { + // insert namespace before "search" (or before syntheticProject if present) + const insertAt = spExists ? spIdx : searchIdx + segs.splice(insertAt, 0, value) + } + } else if (nsExists) { + segs.splice(nsIdx, 1) // removes namespace; syntheticProject (if any) shifts left + } + // if ns didn't exist, nothing to clear + + navigate(segs.join('/') + search + hash, { replace: true }) + return + } if (value && value !== 'all') { setSelectedNamespace(value) const changeUrl = diff --git a/src/hooks/useIsSearchPage/index.ts b/src/hooks/useIsSearchPage/index.ts new file mode 100644 index 0000000..6b84b05 --- /dev/null +++ b/src/hooks/useIsSearchPage/index.ts @@ -0,0 +1 @@ +export * from './useIsSearchPage' diff --git a/src/hooks/useIsSearchPage/useIsSearchPage.ts b/src/hooks/useIsSearchPage/useIsSearchPage.ts new file mode 100644 index 0000000..a7c3ad9 --- /dev/null +++ b/src/hooks/useIsSearchPage/useIsSearchPage.ts @@ -0,0 +1,9 @@ +import { useLocation, matchPath } from 'react-router-dom' + +export const useIsSearchPage = (prefix: string) => { + const { pathname } = useLocation() + const base = `/${prefix}`.replace(/\/{2,}/g, '/').replace(/\/$/, '') + const pattern = `${base}/:clusterName/:namespace?/:syntheticProject?/search/*` + + return Boolean(matchPath({ path: pattern }, pathname)) +} diff --git a/src/pages/SearchPage/SearchPage.tsx b/src/pages/SearchPage/SearchPage.tsx index b2ed41e..57d96d4 100644 --- a/src/pages/SearchPage/SearchPage.tsx +++ b/src/pages/SearchPage/SearchPage.tsx @@ -26,6 +26,7 @@ export const SearchPage: FC = ({ forcedTheme }) => { = ({ children, withNoCluster, forcedTheme, inside, sidebar }) => { +export const BaseTemplate: FC = ({ + children, + withNoCluster, + forcedTheme, + inside, + isSearch, + sidebar, +}) => { const navigate = useNavigate() const { clusterName } = useParams() const { useToken } = antdtheme @@ -106,7 +114,7 @@ export const BaseTemplate: FC = ({ children, withNoCluster, - + {clusterListQuery.error && ( )}