diff --git a/package.json b/package.json index b8a8f104c9..249362b5a8 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "private": true, "homepage": "/dashboard", "dependencies": { - "@devtron-labs/devtron-fe-common-lib": "1.1.4-beta-11", + "@devtron-labs/devtron-fe-common-lib": "1.1.6", "@esbuild-plugins/node-globals-polyfill": "0.2.3", "@rjsf/core": "^5.13.3", "@rjsf/utils": "^5.13.3", diff --git a/src/Pages/GlobalConfigurations/Authorization/Shared/components/K8sObjectPermissions/K8sListItemCard.tsx b/src/Pages/GlobalConfigurations/Authorization/Shared/components/K8sObjectPermissions/K8sListItemCard.tsx index a94728ab54..9f68bd3ee8 100644 --- a/src/Pages/GlobalConfigurations/Authorization/Shared/components/K8sObjectPermissions/K8sListItemCard.tsx +++ b/src/Pages/GlobalConfigurations/Authorization/Shared/components/K8sObjectPermissions/K8sListItemCard.tsx @@ -30,6 +30,7 @@ import { GVKType, getK8sResourceList, EntityTypes, + ApiResourceGroupType, } from '@devtron-labs/devtron-fe-common-lib' import CreatableSelect from 'react-select/creatable' import Tippy from '@tippyjs/react' @@ -177,13 +178,16 @@ const K8sListItemCard = ({ const createKindData = (selected, _allKindMapping, _k8SObjectMap = null) => { const kind = [] let selectedGvk: GVKType + const isAllNamespaceSelected = k8sPermission.namespace.some((option) => option.value === SELECT_ALL_VALUE) if (_k8SObjectMap ?? processedData) { if (selected.value === SELECT_ALL_VALUE) { // eslint-disable-next-line no-restricted-syntax for (const value of (_k8SObjectMap ?? processedData).values()) { // eslint-disable-next-line no-loop-func - value?.child.forEach((ele: { gvk: GVKType }) => { - kind.push({ value: ele.gvk.Kind, label: ele.gvk.Kind, gvk: ele.gvk }) + value?.child.forEach((ele: ApiResourceGroupType) => { + if (isAllNamespaceSelected || ele.namespaced) { + kind.push({ label: ele.gvk.Kind, value: ele.gvk.Kind, gvk: ele.gvk }) + } if (!selectedGvk && ele.gvk.Kind === k8sPermission.kind?.value) { selectedGvk = ele.gvk } @@ -192,7 +196,7 @@ const K8sListItemCard = ({ } else { const data = (_k8SObjectMap ?? processedData).get(selected.value === 'k8sempty' ? '' : selected.value) data?.child?.forEach((ele) => { - if (ele.namespaced) { + if (isAllNamespaceSelected || ele.namespaced) { kind.push({ label: ele.gvk.Kind, value: ele.gvk.Kind, gvk: ele.gvk }) } if (!selectedGvk && ele.gvk.Kind === k8sPermission.kind?.value) { diff --git a/src/Pages/Releases/Detail/Configurations/Configurations.tsx b/src/Pages/Releases/Detail/Configurations/Configurations.tsx index 5cc30439af..bc365c6745 100644 --- a/src/Pages/Releases/Detail/Configurations/Configurations.tsx +++ b/src/Pages/Releases/Detail/Configurations/Configurations.tsx @@ -88,10 +88,9 @@ export const Configurations = () => { const renderConfig = () => ( - -
+ +
{ />
- -
+ +
{ />
- -
+ +
- + - + { ) } -function ClusterOverview({ isSuperAdmin, selectedCluster, addTab }: ClusterOverviewProps) { +function ClusterOverview({ selectedCluster, addTab }: ClusterOverviewProps) { const { clusterId, namespace } = useParams<{ clusterId: string namespace: string @@ -132,7 +133,7 @@ function ClusterOverview({ isSuperAdmin, selectedCluster, addTab }: ClusterOverv }) } } catch (error) { - setErrorCode(error['code']) + showError(error) throw error } } @@ -512,7 +513,6 @@ function ClusterOverview({ isSuperAdmin, selectedCluster, addTab }: ClusterOverv ({ const ClusterSelectionList: React.FC = ({ clusterOptions, - isSuperAdmin, clusterListLoader, initialLoading, refreshData, @@ -190,7 +189,7 @@ const ClusterSelectionList: React.FC = ({ {/* NOTE: visible-hover plays with display prop; therefore need to set display: flex on a new div */}
- {!!clusterData.nodeCount && !clusterListLoader && isSuperAdmin && ( + {!!clusterData.nodeCount && !clusterListLoader && (
{ +const NodeDetails = ({ addTab, lowercaseKindToResourceGroupMap, updateTabUrl }: ClusterListType) => { const { clusterId, node } = useParams<{ clusterId: string; nodeType: string; node: string }>() const [loader, setLoader] = useState(true) const [apiInProgress, setApiInProgress] = useState(false) @@ -799,12 +799,10 @@ const NodeDetails = ({ isSuperAdmin, addTab, lowercaseKindToResourceGroupMap, up return (
- {isSuperAdmin && ( - - - {NODE_DETAILS_TABS.debug} - - )} + + + {NODE_DETAILS_TABS.debug} + | {renderTabControls()}
@@ -996,21 +994,8 @@ const NodeDetails = ({ isSuperAdmin, addTab, lowercaseKindToResourceGroupMap, up return renderSummary() } - const isAuthorized = (): boolean => { - if (!isSuperAdmin) { - ToastManager.showToast({ - variant: ToastVariantType.notAuthorized, - description: TOAST_ACCESS_DENIED.SUBTITLE, - }) - return false - } - return true - } - const showCordonNodeModal = (): void => { - if (isAuthorized()) { - setCordonNodeDialog(true) - } + setCordonNodeDialog(true) } const hideCordonNodeModal = (refreshData?: boolean): void => { @@ -1021,9 +1006,7 @@ const NodeDetails = ({ isSuperAdmin, addTab, lowercaseKindToResourceGroupMap, up } const showDrainNodeModal = (): void => { - if (isAuthorized()) { - setDrainNodeDialog(true) - } + setDrainNodeDialog(true) } const hideDrainNodeModal = (refreshData?: boolean): void => { @@ -1034,9 +1017,7 @@ const NodeDetails = ({ isSuperAdmin, addTab, lowercaseKindToResourceGroupMap, up } const showDeleteNodeModal = (): void => { - if (isAuthorized()) { - setDeleteNodeDialog(true) - } + setDeleteNodeDialog(true) } const hideDeleteNodeModal = (refreshData?: boolean): void => { @@ -1047,9 +1028,7 @@ const NodeDetails = ({ isSuperAdmin, addTab, lowercaseKindToResourceGroupMap, up } const showEditTaintsModal = (): void => { - if (isAuthorized()) { - setShowEditTaints(true) - } + setShowEditTaints(true) } const hideEditTaintsModal = (refreshData?: boolean): void => { diff --git a/src/components/ClusterNodes/types.ts b/src/components/ClusterNodes/types.ts index 49b5ed8863..cba282716a 100644 --- a/src/components/ClusterNodes/types.ts +++ b/src/components/ClusterNodes/types.ts @@ -161,7 +161,6 @@ export interface ColumnMetadataType { } export interface ClusterListType extends Pick { - isSuperAdmin: boolean addTab?: ReturnType['addTab'] updateTabUrl: (params: Omit) => void } @@ -344,7 +343,6 @@ export interface ClusterErrorType { filterText: string[] } export interface ClusterOverviewProps { - isSuperAdmin: boolean selectedCluster: ClusterOptionType addTab: ReturnType['addTab'] } diff --git a/src/components/ResourceBrowser/Constants.ts b/src/components/ResourceBrowser/Constants.ts index 5a343b5b93..a22b078ad4 100644 --- a/src/components/ResourceBrowser/Constants.ts +++ b/src/components/ResourceBrowser/Constants.ts @@ -114,6 +114,7 @@ export const NAMESPACE_NOT_APPLICABLE_TEXT = 'Namespace is not applicable for th export const CLUSTER_NOT_REACHABLE = 'Cluster is not reachable' export const ORDERED_AGGREGATORS: AggregationKeysType[] = [ + AggregationKeys.Nodes, AggregationKeys.Events, AggregationKeys.Namespaces, AggregationKeys.Workloads, @@ -222,7 +223,7 @@ export const UPGRADE_CLUSTER_CONSTANTS = { export const JUMP_TO_KIND_SHORT_NAMES: Record = { events: null, - nodes: ['no'], // NOTE: hardcoding cuz backend doesn't send nodeGVK + nodes: null, namespaces: null, } diff --git a/src/components/ResourceBrowser/ResourceBrowser.tsx b/src/components/ResourceBrowser/ResourceBrowser.tsx index 19f7079aa9..50a14bfd9e 100644 --- a/src/components/ResourceBrowser/ResourceBrowser.tsx +++ b/src/components/ResourceBrowser/ResourceBrowser.tsx @@ -17,7 +17,6 @@ import React, { useEffect, useMemo, useRef } from 'react' import { showError, - getUserRole, DevtronProgressing, useAsync, PageHeader, @@ -44,11 +43,7 @@ const ResourceBrowser: React.FC = () => { return null } }) - const [initialLoading, data, error] = useAsync(() => - Promise.all([getClusterListMin(), window._env_?.K8S_CLIENT ? null : getUserRole()]), - ) - /* transpose the data */ - const [clusterListMinData = null, userRoleData = null] = data || [] + const [initialLoading, clusterListMinData, error] = useAsync(() => getClusterListMin()) useEffect( () => () => { @@ -67,8 +62,6 @@ const ResourceBrowser: React.FC = () => { [detailClusterList, clusterListMinData], ) - const isSuperAdmin = userRoleData?.result.superAdmin || false - const renderContent = () => { if (error) { return @@ -77,7 +70,6 @@ const ResourceBrowser: React.FC = () => { return ( = ({ isSuperAdmin, updateTerminalTabUrl }: AdminTerminalProps) => { +const AdminTerminal: React.FC = ({ updateTerminalTabUrl }: AdminTerminalProps) => { const { clusterId } = useParams() const [loading, data, error] = useAsync( @@ -65,7 +65,7 @@ const AdminTerminal: React.FC = ({ isSuperAdmin, updateTermi const errCode = error?.code || 403 return (
- {isSuperAdmin ? : } +
) } diff --git a/src/components/ResourceBrowser/ResourceList/BaseResourceList.tsx b/src/components/ResourceBrowser/ResourceList/BaseResourceList.tsx index 075f3924f7..b79aab8f01 100644 --- a/src/components/ResourceBrowser/ResourceList/BaseResourceList.tsx +++ b/src/components/ResourceBrowser/ResourceList/BaseResourceList.tsx @@ -115,7 +115,7 @@ const BaseResourceListContent = ({ const { searchParams } = useSearchString() - const isNodeListing = selectedResource.gvk.Kind === SIDEBAR_KEYS.nodeGVK.Kind + const isNodeListing = selectedResource?.gvk.Kind === SIDEBAR_KEYS.nodeGVK.Kind const { selectedIdentifiers: bulkSelectionState, @@ -261,7 +261,7 @@ const BaseResourceListContent = ({ handleFilterChanges(searchText) setResourceListOffset(0) - }, [resourceList, sortBy, sortOrder, location.search]) + }, [resourceList, sortBy, sortOrder, location.search, isOpen]) const getHandleCheckedForId = (resourceData: K8sResourceDetailDataType) => () => { const { id } = resourceData as Record<'id', string> @@ -431,7 +431,7 @@ const BaseResourceListContent = ({ {headers.map((columnName) => columnName === 'name' ? (
@@ -505,7 +505,7 @@ const BaseResourceListContent = ({
) : (
{ - if (!resourceListError && (isLoading || !resourceList || !filteredResourceList)) { + if (!resourceListError && (isLoading || !resourceList || !filteredResourceList || !selectedResource)) { return } @@ -639,7 +639,6 @@ const BaseResourceListContent = ({ )} ) : ( - abortPreviousRequests( - async () => - getResourceData({ selectedResource, selectedNamespace, clusterId, filters, abortControllerRef }), - abortControllerRef, - ), + abortPreviousRequests(async () => { + if (selectedResource) { + return getResourceData({ + selectedResource, + selectedNamespace, + clusterId, + filters, + abortControllerRef, + }) + } + + return null + }, abortControllerRef), [selectedResource, clusterId, selectedNamespace, filters], ) @@ -88,7 +96,10 @@ export const K8SResourceList = ({ } // NOTE: for namespaced resource name+namespace will be unique // while for non-namespaced resources name will be unique - result.data = result.data.map((data) => ({ id: `${data.name}-${data.namespace}`, ...data })) + result.data = result.data.map((data, index) => ({ + id: `${selectedResource?.gvk?.Kind}-${data.name}-${data.namespace}-${index}`, + ...data, + })) return result }, [_resourceList]) diff --git a/src/components/ResourceBrowser/ResourceList/NodeActionsMenu.tsx b/src/components/ResourceBrowser/ResourceList/NodeActionsMenu.tsx index 8634373e8d..bcd1215e11 100644 --- a/src/components/ResourceBrowser/ResourceList/NodeActionsMenu.tsx +++ b/src/components/ResourceBrowser/ResourceList/NodeActionsMenu.tsx @@ -16,14 +16,7 @@ import { useState } from 'react' import { useHistory, useLocation, useRouteMatch } from 'react-router-dom' -import { - noop, - PopupMenu, - TOAST_ACCESS_DENIED, - ToastManager, - ToastVariantType, - useMainContext, -} from '@devtron-labs/devtron-fe-common-lib' +import { noop, PopupMenu } from '@devtron-labs/devtron-fe-common-lib' import { AppDetailsTabs } from '@Components/v2/appDetails/appDetails.store' import { TaintType } from '@Components/ClusterNodes/types' import { ReactComponent as TerminalIcon } from '../../../assets/icons/ic-terminal-fill.svg' @@ -55,42 +48,23 @@ const NodeActionsMenu = ({ nodeData, getNodeListData, addTab }: NodeActionsMenuP const { name, version, kind } = nodeData as Record - const { isSuperAdmin } = useMainContext() - - const isAuthorized = (): boolean => { - if (!isSuperAdmin) { - ToastManager.showToast({ - variant: ToastVariantType.notAuthorized, - description: TOAST_ACCESS_DENIED.SUBTITLE, - }) - return false - } - return true - } - const handleOpenTerminalAction = () => { - if (isAuthorized()) { - const queryParams = new URLSearchParams(location.search) - queryParams.set('node', name) - history.push( - `${location.pathname.split('/').slice(0, -2).join('/')}/${AppDetailsTabs.terminal}/${K8S_EMPTY_GROUP}?${queryParams.toString()}`, - ) - } + const queryParams = new URLSearchParams(location.search) + queryParams.set('node', name) + history.push( + `${location.pathname.split('/').slice(0, -2).join('/')}/${AppDetailsTabs.terminal}/${K8S_EMPTY_GROUP}?${queryParams.toString()}`, + ) } const handleEditYamlAction = () => { - if (isAuthorized()) { - const _url = `${url.split('/').slice(0, -2).join('/')}/node/${K8S_EMPTY_GROUP}/${nodeData.name}?tab=yaml` - addTab({ idPrefix: K8S_EMPTY_GROUP, kind: 'node', name, url: _url }) - .then(() => history.push(_url)) - .catch(noop) - } + const _url = `${url.split('/').slice(0, -2).join('/')}/node/${K8S_EMPTY_GROUP}/${nodeData.name}?tab=yaml` + addTab({ idPrefix: K8S_EMPTY_GROUP, kind: 'node', name, url: _url }) + .then(() => history.push(_url)) + .catch(noop) } const showCordonNodeModal = (): void => { - if (isAuthorized()) { - setShowCordonNodeDialog(true) - } + setShowCordonNodeDialog(true) } const hideCordonNodeModal = (refreshData?: boolean): void => { @@ -101,9 +75,7 @@ const NodeActionsMenu = ({ nodeData, getNodeListData, addTab }: NodeActionsMenuP } const showDrainNodeModal = (): void => { - if (isAuthorized()) { - setShowDrainNodeDialog(true) - } + setShowDrainNodeDialog(true) } const hideDrainNodeModal = (refreshData?: boolean): void => { @@ -114,9 +86,7 @@ const NodeActionsMenu = ({ nodeData, getNodeListData, addTab }: NodeActionsMenuP } const showDeleteNodeModal = (): void => { - if (isAuthorized()) { - setShowDeleteNodeDialog(true) - } + setShowDeleteNodeDialog(true) } const hideDeleteNodeModal = (refreshData?: boolean): void => { @@ -127,9 +97,7 @@ const NodeActionsMenu = ({ nodeData, getNodeListData, addTab }: NodeActionsMenuP } const showEditTaintsModal = (): void => { - if (isAuthorized()) { - setShowEditTaintNodeDialog(true) - } + setShowEditTaintNodeDialog(true) } const hideEditTaintsModal = (refreshData?: boolean): void => { diff --git a/src/components/ResourceBrowser/ResourceList/ResourceList.tsx b/src/components/ResourceBrowser/ResourceList/ResourceList.tsx index c265a2fdc6..ca0f4fb0a7 100644 --- a/src/components/ResourceBrowser/ResourceList/ResourceList.tsx +++ b/src/components/ResourceBrowser/ResourceList/ResourceList.tsx @@ -17,7 +17,6 @@ import { useState, useEffect, useMemo, useRef } from 'react' import { useHistory, useParams, useRouteMatch, useLocation } from 'react-router-dom' import { - getUserRole, BreadCrumb, useBreadcrumb, ErrorScreenManager, @@ -89,20 +88,12 @@ const ResourceList = () => { const [logSearchTerms, setLogSearchTerms] = useState>() const [widgetEventDetails, setWidgetEventDetails] = useState(null) const [isDataStale, setIsDataStale] = useState(false) - const [selectedResource, setSelectedResource] = useState({ - gvk: SIDEBAR_KEYS.nodeGVK, - namespaced: false, - isGrouped: false, - }) + const [selectedResource, setSelectedResource] = useState(null) const { targetK8sVersion } = useUrlFilters({ parseSearchParams }) const [rawGVKLoader, k8SObjectMapRaw] = useAsync(() => getResourceGroupListRaw(clusterId), [clusterId]) - const [loading, data, error] = useAsync(() => - Promise.all([getClusterListMin(), window._env_.K8S_CLIENT ? null : getUserRole()]), - ) - - const [clusterListData = null, userRole = null] = data || [] + const [loading, clusterListData, error] = useAsync(() => getClusterListMin()) const clusterList = clusterListData?.result || null @@ -144,8 +135,6 @@ const ResourceList = () => { [k8SObjectMapRaw], ) - const isSuperAdmin = !!userRole?.result.superAdmin - const isOverviewNodeType = nodeType === SIDEBAR_KEYS.overviewGVK.Kind.toLowerCase() const isMonitoringNodeType = nodeType === SIDEBAR_KEYS.monitoringGVK.Kind.toLowerCase() const isTerminalNodeType = nodeType === AppDetailsTabs.terminal @@ -200,25 +189,33 @@ const ResourceList = () => { }) const initTabsBasedOnRole = (reInit: boolean) => { - /* NOTE: selectedCluster is not in useEffect dep list since it arrives with isSuperAdmin (Promise.all) */ const _tabs = getTabsBasedOnRole({ selectedCluster, namespace, - isSuperAdmin, /* NOTE: if node is available in url but no associated dynamicTab we create a dynamicTab */ dynamicTabData: (node || isUpgradeClusterNodeType) && getDynamicTabData(), isTerminalSelected: isTerminalNodeType, isOverviewSelected: isOverviewNodeType, isMonitoringDashBoardSelected: isMonitoringNodeType, }) - initTabs( - _tabs, - reInit, - !isSuperAdmin ? [getTabId(ResourceBrowserTabsId.terminal, AppDetailsTabs.terminal, '')] : null, - ) + initTabs(_tabs, reInit) } - useEffect(() => initTabsBasedOnRole(false), [isSuperAdmin]) + useEffect(() => initTabsBasedOnRole(false), []) + useEffect(() => { + const terminalTab = getTabById(ResourceBrowserTabsId.terminal) + const newLabel = `Terminal '${selectedCluster.label}'` + + // NOTE: we don't have cluster name on mount therefore need + // to update the dynamicTitle once we have fetched the cluster name + if (terminalTab && terminalTab.dynamicTitle !== newLabel) { + updateTabUrl({ + id: terminalTab.id, + url: terminalTab.url, + dynamicTitle: newLabel, + }) + } + }, [getTabById(ResourceBrowserTabsId.terminal)?.dynamicTitle, selectedCluster]) useEffectAfterMount(() => initTabsBasedOnRole(true), [clusterId]) useEffectAfterMount(() => { @@ -358,10 +355,10 @@ const ResourceList = () => { const handleResourceClick = (e, shouldOverrideSelectedResourceKind: boolean) => { const { name, tab, namespace: currentNamespace, origin, kind: kindFromResource } = e.currentTarget.dataset const lowercaseKindFromResource = shouldOverrideSelectedResourceKind ? kindFromResource.toLowerCase() : null - const _group: string = + let _group: string = (shouldOverrideSelectedResourceKind ? lowercaseKindToResourceGroupMap[lowercaseKindFromResource]?.gvk?.Group?.toLowerCase() - : selectedResource?.gvk.Group.toLowerCase()) || K8S_EMPTY_GROUP + : selectedResource.gvk.Group.toLowerCase()) || K8S_EMPTY_GROUP const _namespace = currentNamespace ?? ALL_NAMESPACE_OPTION.value let resourceParam: string @@ -371,6 +368,9 @@ const ResourceList = () => { if (origin === 'event') { const [_kind, _resourceName] = name.split('/') const eventKind = shouldOverrideSelectedResourceKind ? lowercaseKindFromResource : _kind + // For event, we should read the group for kind from the resource group map else fallback to empty group + _group = lowercaseKindToResourceGroupMap[eventKind]?.gvk?.Group || K8S_EMPTY_GROUP + resourceParam = `${eventKind}/${_group}/${_resourceName}` kind = eventKind resourceName = _resourceName @@ -413,7 +413,6 @@ const ResourceList = () => { return nodeType.toLowerCase() === SIDEBAR_KEYS.nodeGVK.Kind.toLowerCase() ? ( { } const fixedTabComponents = [ - , + , { getTabById(ResourceBrowserTabsId.k8s_Resources)?.lastSyncMoment?.toString(), refreshData, )} - isSuperAdmin={isSuperAdmin} isOpen={!!getTabById(ResourceBrowserTabsId.k8s_Resources)?.isSelected} showStaleDataWarning={isDataStale} updateK8sResourceTab={getUpdateTabUrlForId(getTabById(ResourceBrowserTabsId.k8s_Resources)?.id)} @@ -458,8 +456,8 @@ const ResourceList = () => { lowercaseKindToResourceGroupMap={lowercaseKindToResourceGroupMap} />, ...(MonitoringDashboard ? [] : []), - ...(isSuperAdmin && getTabById(ResourceBrowserTabsId.terminal)?.isAlive - ? [] + ...(getTabById(ResourceBrowserTabsId.terminal)?.isAlive + ? [] : []), ] @@ -468,7 +466,7 @@ const ResourceList = () => { return } - if (loading) { + if (loading || !tabs.length) { return } diff --git a/src/components/ResourceBrowser/ResourceList/Sidebar.tsx b/src/components/ResourceBrowser/ResourceList/Sidebar.tsx index ada9246fd1..d746268ff1 100644 --- a/src/components/ResourceBrowser/ResourceList/Sidebar.tsx +++ b/src/components/ResourceBrowser/ResourceList/Sidebar.tsx @@ -151,15 +151,13 @@ const Sidebar = ({ useEffect(() => { /* NOTE: this effect accommodates for user navigating through browser history (push) */ - if (!isOpen || nodeType === selectedResource.gvk.Kind.toLowerCase()) { + if (!isOpen || nodeType === selectedResource?.gvk.Kind.toLowerCase() || !k8sObjectOptionsList.length) { return } /* NOTE: match will never be null; due to node fallback */ const match = - k8sObjectOptionsList.find((option) => option.dataset.kind.toLowerCase() === nodeType) || - k8sObjectOptionsList.find( - (option) => option.dataset.kind.toLowerCase() === SIDEBAR_KEYS.nodeGVK.Kind.toLowerCase(), - ) + k8sObjectOptionsList.find((option) => option.dataset.kind.toLowerCase() === nodeType) ?? + k8sObjectOptionsList[0] /* NOTE: if nodeType doesn't match the selectedResource kind, set it accordingly */ selectNode( { @@ -169,9 +167,9 @@ const Sidebar = ({ }, match.groupName, /* NOTE: if we push here the history will be lost */ - false, + !selectedResource, ) - }, [nodeType]) + }, [nodeType, k8sObjectOptionsList]) const selectedChildRef: React.Ref = (node) => { /** @@ -342,17 +340,19 @@ const Sidebar = ({
- - {list?.size && list.get(AggregationKeys.Events) && ( + {!!list?.size && !!list.get(AggregationKeys.Nodes) && ( + + )} + {!!list?.size && !!list.get(AggregationKeys.Events) && ( )} - {list?.size && list.get(AggregationKeys.Namespaces) && ( + {!!list?.size && !!list.get(AggregationKeys.Namespaces) && ( )}
- {list?.size && + {!!list?.size && [...list.values()].map((k8sObject) => k8sObject.name === AggregationKeys.Events || - k8sObject.name === AggregationKeys.Namespaces ? null : ( + k8sObject.name === AggregationKeys.Namespaces || + k8sObject.name === AggregationKeys.Nodes ? null : (