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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"homepage": "/dashboard",
"dependencies": {
"@devtron-labs/devtron-fe-common-lib": "4.0.4-pre-0",
"@devtron-labs/devtron-fe-common-lib": "4.0.4-beta-7",
"@esbuild-plugins/node-globals-polyfill": "0.2.3",
"@sentry/browser": "7.119.1",
"@sentry/integrations": "7.50.0",
Expand Down
71 changes: 41 additions & 30 deletions src/Pages/Shared/CommandBar/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {

import { QueryParams as ChartStoreQueryParams } from '@Components/charts/constants'
import { getNavigationList } from '@Components/Navigation'
import { hasNavigationGroupItems } from '@Components/Navigation/utils'
import { getClusterChangeRedirectionUrl } from '@Components/ResourceBrowser/Utils'
import { URLS } from '@Config/routes'

Expand Down Expand Up @@ -103,36 +104,46 @@ const getNavItemBreakdownItems = (

export const getNavigationGroups = (serverMode: SERVER_MODE, isSuperAdmin: boolean): CommandBarGroupType[] =>
getNavigationList(serverMode).map<CommandBarGroupType>((group) => {
const parsedItems = group.items.flatMap<CommandBarGroupType['items'][number]>(
({ hasSubMenu, subItems, title, href, id, icon, keywords }) => {
if (hasSubMenu && subItems?.length) {
return subItems.map<CommandBarGroupType['items'][number]>((subItem) => ({
title: `${title} / ${subItem.title}`,
id: subItem.id,
// Since icon is not present for some subItems, using from group
icon: NAV_SUB_ITEMS_ICON_MAPPING[id] || group.icon,
// TODO: No href present for some subItems
href: subItem.href ?? null,
keywords: subItem.keywords || [],
}))
}

const breakdownItems = getNavItemBreakdownItems(id, serverMode, isSuperAdmin)

if (breakdownItems.length) {
return breakdownItems
}

return {
title,
id,
icon: icon || 'ic-arrow-right',
// TODO: No href present for some items
href: href ?? null,
keywords: keywords || [],
}
},
)
const parsedItems = hasNavigationGroupItems(group)
? group.items.flatMap<CommandBarGroupType['items'][number]>(
({ hasSubMenu, subItems, title, href, id, icon, keywords }) => {
if (hasSubMenu && subItems?.length) {
return subItems.map<CommandBarGroupType['items'][number]>((subItem) => ({
title: `${title} / ${subItem.title}`,
id: subItem.id,
// Since icon is not present for some subItems, using from group
icon: NAV_SUB_ITEMS_ICON_MAPPING[id] || group.icon,
// TODO: No href present for some subItems
href: subItem.href ?? null,
keywords: subItem.keywords || [],
}))
}

const breakdownItems = getNavItemBreakdownItems(id, serverMode, isSuperAdmin)

if (breakdownItems.length) {
return breakdownItems
}

return {
title,
id,
icon: icon || 'ic-arrow-right',
// TODO: No href present for some items
href: href ?? null,
keywords: keywords || [],
}
},
)
: [
{
title: group.title,
id: group.id,
icon: group.icon,
href: group.href,
keywords: [],
} as CommandBarGroupType['items'][number],
]

return {
title: group.title,
Expand Down
70 changes: 50 additions & 20 deletions src/components/Navigation/Navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,13 @@ import { NavGroup } from './NavGroup'
import { NavigationLogo, NavigationLogoExpanded } from './NavigationLogo'
import { NavItem } from './NavItem'
import { NavGroupProps, NavigationProps } from './types'
import { doesNavigationItemMatchPath, filterNavigationItems, findActiveNavigationItemOfNavGroup } from './utils'
import {
doesNavigationGroupMatchPath,
doesNavigationItemMatchPath,
filterNavigationItems,
findActiveNavigationItemOfNavGroup,
hasNavigationGroupItems,
} from './utils'

import './styles.scss'

Expand Down Expand Up @@ -143,17 +149,23 @@ export const Navigation = ({
const NAVIGATION_LIST = useMemo(() => getNavigationList(serverMode), [serverMode])

const selectedNavGroup = useMemo(
() => NAVIGATION_LIST.find(({ items }) => items.some((item) => doesNavigationItemMatchPath(item, pathname))),
[pathname],
() => NAVIGATION_LIST.find((group) => doesNavigationGroupMatchPath(group, pathname)),
[NAVIGATION_LIST, pathname],
)

const selectedExpandableNavGroup = useMemo(
() => (hasNavigationGroupItems(selectedNavGroup) ? selectedNavGroup : null),
[selectedNavGroup],
)

// The current navigation group is the one that is hovered or the one that is active, \
// this is used to determine which nav group items are to be shown in expanded state.
const currentNavGroup = hoveredNavGroup || selectedNavGroup
const currentNavGroup = hoveredNavGroup || selectedExpandableNavGroup
const isExpanded = !!hoveredNavGroup

const navItems = useMemo<NavigationGroupType['items']>(
() => (currentNavGroup ? filterNavigationItems(currentNavGroup.items, searchText) : []),
() =>
hasNavigationGroupItems(currentNavGroup) ? filterNavigationItems(currentNavGroup.items, searchText) : [],
[currentNavGroup, searchText],
)

Expand All @@ -164,6 +176,7 @@ export const Navigation = ({
// Prevent navigation, if the item is already active
if (
selectedNavGroup?.id === navItem.id &&
hasNavigationGroupItems(selectedNavGroup) &&
doesNavigationItemMatchPath(findActiveNavigationItemOfNavGroup(selectedNavGroup.items), pathname)
) {
e.preventDefault()
Expand All @@ -172,6 +185,13 @@ export const Navigation = ({
category: 'Navigation',
action: `nav-${navItem.id}`,
})

if (!hasNavigationGroupItems(navItem)) {
setHoveredNavGroup(null)
setSearchText('')
return
}

setHoveredNavGroup(navItem)
setSearchText('')
}
Expand All @@ -186,25 +206,27 @@ export const Navigation = ({
setSearchText('')
}

const handleNavGroupHover = (navGroup: typeof hoveredNavGroup) => (isHovered: boolean) => {
clearTimeout(timeoutRef.current)
const handleNavGroupHover =
(navGroup: NavigationGroupType & { items: NonNullable<NavigationGroupType['items']> }) =>
(isHovered: boolean) => {
clearTimeout(timeoutRef.current)

if (isHovered) {
if (!hoveredNavGroup) {
setHoveredNavGroup(navGroup)
return
}
if (isHovered) {
if (!hoveredNavGroup) {
setHoveredNavGroup(navGroup)
return
}

timeoutRef.current = setTimeout(() => {
setHoveredNavGroup(navGroup)
setSearchText('')
}, 50)
timeoutRef.current = setTimeout(() => {
setHoveredNavGroup(navGroup)
setSearchText('')
}, 50)
}
}
}

const handleOpenExpandedNavigation = (e: MouseEvent<HTMLDivElement>) => {
if (!hoveredNavGroup && e.target === e.currentTarget) {
setHoveredNavGroup(selectedNavGroup)
setHoveredNavGroup(selectedExpandableNavGroup)
}
}

Expand Down Expand Up @@ -253,8 +275,16 @@ export const Navigation = ({
isExpanded={isExpanded}
isSelected={hoveredNavGroup?.id === item.id || selectedNavGroup?.id === item.id}
onClick={handleNavGroupClick(item)}
to={findActiveNavigationItemOfNavGroup(item.items)?.href}
onHover={handleNavGroupHover(item)}
to={
hasNavigationGroupItems(item)
? findActiveNavigationItemOfNavGroup(item.items)?.href
: item.href
}
onHover={
hasNavigationGroupItems(item)
? handleNavGroupHover(item)
: handleCloseExpandedNavigation(true)
}
showTooltip={item.disabled}
/>
))}
Expand Down
76 changes: 43 additions & 33 deletions src/components/Navigation/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { NavigationGroupType, NavigationItemType, ROUTER_URLS, SERVER_MODE } fro

import { importComponentFromFELibrary } from '@Components/common'

import { filterNavGroupAndItem } from './utils'
import { filterNavGroupAndItem, hasNavigationGroupItems } from './utils'

const APPLICATION_MANAGEMENT_POLICIES_NAV_ITEM: NavigationItemType = importComponentFromFELibrary(
'APPLICATION_MANAGEMENT_POLICIES_NAV_ITEM',
Expand Down Expand Up @@ -322,6 +322,12 @@ const NAVIGATION_LIST: NavigationGroupType[] = [
],
isAvailableInEA: true,
},
{
id: 'audit-logs',
title: 'Audit logs',
icon: 'ic-file-log-search',
href: ROUTER_URLS.AUDIT_LOGS,
},
]

export const getNavigationList = (serverMode: SERVER_MODE): NavigationGroupType[] => {
Expand All @@ -332,37 +338,41 @@ export const getNavigationList = (serverMode: SERVER_MODE): NavigationGroupType[
),
)

const filteredNavItems = filteredNavGroup.map((group) => {
const filteredItems = group.items.filter((item) =>
filterNavGroupAndItem(
{
forceHideEnvKey: item.forceHideEnvKey,
hideNav: item.hideNav,
isAvailableInEA: item.isAvailableInEA,
},
serverMode,
),
)
return { ...group, items: filteredItems }
})
return filteredNavGroup.map((group) => {
if (!hasNavigationGroupItems(group)) {
return group
}

const filteredItems = group.items
.filter((item) =>
filterNavGroupAndItem(
{
forceHideEnvKey: item.forceHideEnvKey,
hideNav: item.hideNav,
isAvailableInEA: item.isAvailableInEA,
},
serverMode,
),
)
.map((item) => {
if (item.hasSubMenu && item.subItems) {
const filteredSubItems = item.subItems.filter((subItem) =>
filterNavGroupAndItem(
{
forceHideEnvKey: subItem.forceHideEnvKey,
hideNav: subItem.hideNav,
isAvailableInEA: subItem.isAvailableInEA,
},
serverMode,
),
)

return filteredNavItems.map((group) => ({
...group,
items: group.items.map((item) => {
if (item.hasSubMenu && item.subItems) {
const filteredSubItems = item.subItems.filter((subItem) =>
filterNavGroupAndItem(
{
forceHideEnvKey: subItem.forceHideEnvKey,
hideNav: subItem.hideNav,
isAvailableInEA: subItem.isAvailableInEA,
},
serverMode,
),
)
return { ...item, subItems: filteredSubItems }
}
return item
}),
}))
return { ...item, subItems: filteredSubItems }
}

return item
})

return { ...group, items: filteredItems } as NavigationGroupType
})
}
13 changes: 13 additions & 0 deletions src/components/Navigation/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
CommonNavigationItemType,
NavigationGroupType,
NavigationItemType,
SERVER_MODE,
TreeNode,
Expand Down Expand Up @@ -108,6 +109,10 @@ export const doesNavigationItemMatchPath = (
return !navItem.disabled && item.href && isSubPath(item.href, pathname)
}

export const hasNavigationGroupItems = (
group: NavigationGroupType | null | undefined,
): group is NavigationGroupType & { items: NavigationItemType[] } => Array.isArray(group?.items)

/**
* Finds the first enabled navigation item within a group.
* @param items The navigation item group to search.
Expand All @@ -116,6 +121,14 @@ export const doesNavigationItemMatchPath = (
export const findActiveNavigationItemOfNavGroup = (items: NavigationItemType[]) =>
items.find(({ disabled }) => !disabled)

export const doesNavigationGroupMatchPath = (group: NavigationGroupType, pathname: string): boolean => {
if (hasNavigationGroupItems(group)) {
return group.items.some((item) => doesNavigationItemMatchPath(item, pathname))
}

return !group.disabled && isSubPath(group.href, pathname)
}

export const filterNavGroupAndItem = (
item: Pick<CommonNavigationItemType, 'hideNav' | 'forceHideEnvKey' | 'isAvailableInEA'>,
serverMode: SERVER_MODE,
Expand Down
9 changes: 9 additions & 0 deletions src/components/common/navigation/NavigationRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ const CostVisibilityRouter = importComponentFromFELibrary('CostVisibilityRouter'
const AIRecommendations = importComponentFromFELibrary('AIRecommendations', null, 'function')
const AIChatProvider = importComponentFromFELibrary('AIChatProvider', null, 'function')

const AuditLogsRouter = importComponentFromFELibrary('AuditLogs', null, 'function')

const NavigationRoutes = ({ reloadVersionConfig }: Readonly<NavigationRoutesTypes>) => {
const navigate = useNavigate()
const location = useLocation()
Expand Down Expand Up @@ -564,6 +566,13 @@ const NavigationRoutes = ({ reloadVersionConfig }: Readonly<NavigationRoutesType
path={`${BASE_ROUTES.INFRASTRUCTURE_MANAGEMENT.ROOT}/*`}
element={<InfrastructureManagementRouter isSuperAdmin={isSuperAdmin} />}
/>
{serverMode === SERVER_MODE.FULL && AuditLogsRouter && (
<Route
key={BASE_ROUTES.AUDIT_LOGS.ROOT}
path={`${BASE_ROUTES.AUDIT_LOGS.ROOT}/*`}
element={<AuditLogsRouter />}
/>
)}
{!window._env_.K8S_CLIENT
? [
...(serverMode === SERVER_MODE.FULL
Expand Down
1 change: 1 addition & 0 deletions src/config/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export const Routes = {
EPHEMERAL_CONTAINERS: 'k8s/resources/ephemeralContainers',
APP_EDIT: 'app/edit',
APPLICATION_EXTERNAL_HELM_RELEASE: 'application/external-helm-release',
AUDIT_LOG: 'audit-log',

JOB_CI_DETAIL: 'job/ci-pipeline/list',

Expand Down
Loading
Loading