From 5c45e1f7b39d439ea66d78997df274dd3cf65946 Mon Sep 17 00:00:00 2001 From: Amlan Kumar Nandy <45410599+amlannandy@users.noreply.github.com> Date: Sat, 18 Jan 2025 16:25:50 +0530 Subject: [PATCH] chore: infra monitoring bug fixes (#6795) --- .../api/infraMonitoring/getK8sNodesList.ts | 4 +- .../src/api/infraMonitoring/getK8sPodsList.ts | 4 +- .../InfraMonitoringK8s.styles.scss | 64 ++++++-- .../InfraMonitoringK8s/InfraMonitoringK8s.tsx | 21 +-- .../K8sFiltersSidePanel.tsx | 12 +- .../InfraMonitoringK8s/K8sHeader.tsx | 12 +- .../InfraMonitoringK8s/Nodes/K8sNodesList.tsx | 138 +++++++++--------- .../Nodes/NodeDetails/Events/NodeEvents.tsx | 5 +- .../Nodes/NodeDetails/NodeDetails.tsx | 42 +++--- .../InfraMonitoringK8s/Nodes/utils.tsx | 7 +- .../InfraMonitoringK8s/Pods/K8sPodLists.tsx | 129 ++++++++-------- .../Pods/PodDetails/Events/Events.tsx | 5 +- .../Pods/PodDetails/PodDetails.tsx | 48 +++--- .../Pods/PodDetails/PodTraces/PodTraces.tsx | 2 - .../InfraMonitoringK8s/commonUtils.tsx | 14 +- .../container/InfraMonitoringK8s/constants.ts | 2 + .../InfraMonitoringK8s/entityDetailUtils.ts | 18 +++ .../container/InfraMonitoringK8s/utils.tsx | 79 +++++----- .../filters/QueryBuilderSearch/index.tsx | 7 +- .../src/hooks/queryBuilder/useAutoComplete.ts | 2 + .../InfrastructureMonitoringPage.tsx | 4 +- 21 files changed, 338 insertions(+), 281 deletions(-) create mode 100644 frontend/src/container/InfraMonitoringK8s/entityDetailUtils.ts diff --git a/frontend/src/api/infraMonitoring/getK8sNodesList.ts b/frontend/src/api/infraMonitoring/getK8sNodesList.ts index e3c411b1d0..71228b030b 100644 --- a/frontend/src/api/infraMonitoring/getK8sNodesList.ts +++ b/frontend/src/api/infraMonitoring/getK8sNodesList.ts @@ -1,4 +1,4 @@ -import { ApiBaseInstance } from 'api'; +import axios from 'api'; import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { AxiosError } from 'axios'; import { ErrorResponse, SuccessResponse } from 'types/api'; @@ -47,7 +47,7 @@ export const getK8sNodesList = async ( headers?: Record, ): Promise | ErrorResponse> => { try { - const response = await ApiBaseInstance.post('/nodes/list', props, { + const response = await axios.post('/nodes/list', props, { signal, headers, }); diff --git a/frontend/src/api/infraMonitoring/getK8sPodsList.ts b/frontend/src/api/infraMonitoring/getK8sPodsList.ts index d1aa8bd1a7..05258ef166 100644 --- a/frontend/src/api/infraMonitoring/getK8sPodsList.ts +++ b/frontend/src/api/infraMonitoring/getK8sPodsList.ts @@ -1,4 +1,4 @@ -import { ApiBaseInstance } from 'api'; +import axios from 'api'; import { ErrorResponseHandler } from 'api/ErrorResponseHandler'; import { AxiosError } from 'axios'; import { ErrorResponse, SuccessResponse } from 'types/api'; @@ -75,7 +75,7 @@ export const getK8sPodsList = async ( headers?: Record, ): Promise | ErrorResponse> => { try { - const response = await ApiBaseInstance.post('/pods/list', props, { + const response = await axios.post('/pods/list', props, { signal, headers, }); diff --git a/frontend/src/container/InfraMonitoringK8s/InfraMonitoringK8s.styles.scss b/frontend/src/container/InfraMonitoringK8s/InfraMonitoringK8s.styles.scss index 26867ba094..aa2afd0c6b 100644 --- a/frontend/src/container/InfraMonitoringK8s/InfraMonitoringK8s.styles.scss +++ b/frontend/src/container/InfraMonitoringK8s/InfraMonitoringK8s.styles.scss @@ -39,10 +39,6 @@ .ant-collapse-header { border-bottom: 1px solid var(--bg-slate-400); padding: 12px 8px; - - &[aria-expanded='true'] { - background: var(--bg-ink-400); - } } .ant-collapse-content-box { @@ -271,8 +267,6 @@ .group-by-label { min-width: max-content; - - color: var(--bg-vanilla-100, #c0c1c3); font-size: 13px; font-style: normal; font-weight: 400; @@ -282,7 +276,6 @@ border-radius: 2px 0px 0px 2px; border: 1px solid var(--bg-slate-400, #1d212d); border-right: none; - background: var(--bg-ink-100, #16181d); border-top-right-radius: 0px; border-bottom-right-radius: 0px; @@ -488,7 +481,7 @@ .expanded-table-container { border: 1px solid var(--bg-ink-400); overflow-x: auto; - padding-left: 16px; + padding-left: 48px; &::-webkit-scrollbar { width: 0.1rem; @@ -710,8 +703,34 @@ } .ant-table-cell { - min-width: 170px !important; - max-width: 170px !important; + min-width: 140px !important; + max-width: 140px !important; +} + +.ant-table-cell { + &:has(.pod-name-header) { + min-width: 250px !important; + max-width: 250px !important; + } +} + +.ant-table-cell { + &:has(.med-col) { + min-width: 180px !important; + max-width: 180px !important; + } +} + +.expanded-k8s-list-table { + .ant-table-cell { + min-width: 180px !important; + max-width: 180px !important; + } + + .ant-table-row-expand-icon-cell { + min-width: 30px !important; + max-width: 30px !important; + } } .ant-table-row-expand-icon-cell { @@ -808,6 +827,24 @@ } .lightMode { + .infra-monitoring-container { + .k8s-list-table { + .ant-table-expanded-row { + &:hover { + background: var(--bg-vanilla-100) !important; + } + + .ant-table-cell { + background: var(--bg-vanilla-100) !important; + } + + .ant-table .ant-table-thead > tr > th { + padding: 4px 16px !important; + } + } + } + } + .event-content-container { .ant-table { background: var(--bg-vanilla-100); @@ -831,4 +868,11 @@ } } } + + .entity-group-header { + .ant-tag { + background-color: var(--bg-vanilla-300) !important; + color: var(--bg-slate-400) !important; + } + } } diff --git a/frontend/src/container/InfraMonitoringK8s/InfraMonitoringK8s.tsx b/frontend/src/container/InfraMonitoringK8s/InfraMonitoringK8s.tsx index f152182ca8..40b166fb3f 100644 --- a/frontend/src/container/InfraMonitoringK8s/InfraMonitoringK8s.tsx +++ b/frontend/src/container/InfraMonitoringK8s/InfraMonitoringK8s.tsx @@ -9,7 +9,7 @@ import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; import { useQueryOperations } from 'hooks/queryBuilder/useQueryBuilderOperations'; import { Container, Workflow } from 'lucide-react'; import ErrorBoundaryFallback from 'pages/ErrorBoundaryFallback/ErrorBoundaryFallback'; -import { useCallback, useState } from 'react'; +import { useState } from 'react'; import { Query } from 'types/api/queryBuilder/queryBuilderData'; import { @@ -24,6 +24,7 @@ export default function InfraMonitoringK8s(): JSX.Element { const [showFilters, setShowFilters] = useState(true); const [selectedCategory, setSelectedCategory] = useState(K8sCategories.PODS); + const [quickFiltersLastUpdated, setQuickFiltersLastUpdated] = useState(-1); const { currentQuery } = useQueryBuilder(); @@ -37,14 +38,12 @@ export default function InfraMonitoringK8s(): JSX.Element { entityVersion: '', }); - const handleFilterChange = useCallback( - (query: Query): void => { - // update the current query with the new filters - // in infra monitoring k8s, we are using only one query, hence updating the 0th index of queryData - handleChangeQueryData('filters', query.builder.queryData[0].filters); - }, - [handleChangeQueryData], - ); + const handleFilterChange = (query: Query): void => { + // update the current query with the new filters + // in infra monitoring k8s, we are using only one query, hence updating the 0th index of queryData + handleChangeQueryData('filters', query.builder.queryData[0].filters); + setQuickFiltersLastUpdated(Date.now()); + }; const items: CollapseProps['items'] = [ { @@ -262,6 +261,8 @@ export default function InfraMonitoringK8s(): JSX.Element { const handleCategoryChange = (key: string | string[]): void => { if (Array.isArray(key) && key.length > 0) { setSelectedCategory(key[0] as string); + // Reset filters + handleChangeQueryData('filters', { items: [], op: 'and' }); } }; @@ -302,6 +303,7 @@ export default function InfraMonitoringK8s(): JSX.Element { )} @@ -309,6 +311,7 @@ export default function InfraMonitoringK8s(): JSX.Element { )} diff --git a/frontend/src/container/InfraMonitoringK8s/K8sFiltersSidePanel/K8sFiltersSidePanel.tsx b/frontend/src/container/InfraMonitoringK8s/K8sFiltersSidePanel/K8sFiltersSidePanel.tsx index 8062f338b0..d042144b43 100644 --- a/frontend/src/container/InfraMonitoringK8s/K8sFiltersSidePanel/K8sFiltersSidePanel.tsx +++ b/frontend/src/container/InfraMonitoringK8s/K8sFiltersSidePanel/K8sFiltersSidePanel.tsx @@ -7,7 +7,7 @@ import { Button, Input } from 'antd'; import { GripVertical, TableColumnsSplit, X } from 'lucide-react'; import { useEffect, useRef, useState } from 'react'; -import { IPodColumn } from '../utils'; +import { IEntityColumn } from '../utils'; function K8sFiltersSidePanel({ defaultAddedColumns, @@ -17,12 +17,12 @@ function K8sFiltersSidePanel({ onAddColumn = () => {}, onRemoveColumn = () => {}, }: { - defaultAddedColumns: IPodColumn[]; + defaultAddedColumns: IEntityColumn[]; onClose: () => void; - addedColumns?: IPodColumn[]; - availableColumns?: IPodColumn[]; - onAddColumn?: (column: IPodColumn) => void; - onRemoveColumn?: (column: IPodColumn) => void; + addedColumns?: IEntityColumn[]; + availableColumns?: IEntityColumn[]; + onAddColumn?: (column: IEntityColumn) => void; + onRemoveColumn?: (column: IEntityColumn) => void; }): JSX.Element { const [searchValue, setSearchValue] = useState(''); const sidePanelRef = useRef(null); diff --git a/frontend/src/container/InfraMonitoringK8s/K8sHeader.tsx b/frontend/src/container/InfraMonitoringK8s/K8sHeader.tsx index 748cb205b3..84fd1e9964 100644 --- a/frontend/src/container/InfraMonitoringK8s/K8sHeader.tsx +++ b/frontend/src/container/InfraMonitoringK8s/K8sHeader.tsx @@ -12,7 +12,7 @@ import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData'; import { K8sCategory } from './constants'; import K8sFiltersSidePanel from './K8sFiltersSidePanel/K8sFiltersSidePanel'; -import { IPodColumn } from './utils'; +import { IEntityColumn } from './utils'; interface K8sHeaderProps { selectedGroupBy: BaseAutocompleteData[]; @@ -20,11 +20,11 @@ interface K8sHeaderProps { isLoadingGroupByFilters: boolean; handleFiltersChange: (value: IBuilderQuery['filters']) => void; handleGroupByChange: (value: IBuilderQuery['groupBy']) => void; - defaultAddedColumns: IPodColumn[]; - addedColumns?: IPodColumn[]; - availableColumns?: IPodColumn[]; - onAddColumn?: (column: IPodColumn) => void; - onRemoveColumn?: (column: IPodColumn) => void; + defaultAddedColumns: IEntityColumn[]; + addedColumns?: IEntityColumn[]; + availableColumns?: IEntityColumn[]; + onAddColumn?: (column: IEntityColumn) => void; + onRemoveColumn?: (column: IEntityColumn) => void; handleFilterVisibilityChange: () => void; isFiltersVisible: boolean; entity: K8sCategory; diff --git a/frontend/src/container/InfraMonitoringK8s/Nodes/K8sNodesList.tsx b/frontend/src/container/InfraMonitoringK8s/Nodes/K8sNodesList.tsx index ed9bfab2f1..63cd557d32 100644 --- a/frontend/src/container/InfraMonitoringK8s/Nodes/K8sNodesList.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Nodes/K8sNodesList.tsx @@ -45,9 +45,11 @@ import { function K8sNodesList({ isFiltersVisible, handleFilterVisibilityChange, + quickFiltersLastUpdated, }: { isFiltersVisible: boolean; handleFilterVisibilityChange: () => void; + quickFiltersLastUpdated: number; }): JSX.Element { const { maxTime, minTime } = useSelector( (state) => state.globalTime, @@ -60,7 +62,7 @@ function K8sNodesList({ const [orderBy, setOrderBy] = useState<{ columnName: string; order: 'asc' | 'desc'; - } | null>(null); + } | null>({ columnName: 'cpu', order: 'desc' }); const [selectedNodeUID, setselectedNodeUID] = useState(null); @@ -76,12 +78,28 @@ function K8sNodesList({ { value: string; label: string }[] >([]); + const { currentQuery } = useQueryBuilder(); + + const queryFilters = useMemo( + () => + currentQuery?.builder?.queryData[0]?.filters || { + items: [], + op: 'and', + }, + [currentQuery?.builder?.queryData], + ); + + // Reset pagination every time quick filters are changed + useEffect(() => { + setCurrentPage(1); + }, [quickFiltersLastUpdated]); + const createFiltersForSelectedRowData = ( selectedRowData: K8sNodesRowData, groupBy: IBuilderQuery['groupBy'], ): IBuilderQuery['filters'] => { const baseFilters: IBuilderQuery['filters'] = { - items: [], + items: [...queryFilters.items], op: 'and', }; @@ -120,6 +138,7 @@ function K8sNodesList({ end: Math.floor(maxTime / 1000000), orderBy, }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [minTime, maxTime, orderBy, selectedRowData, groupBy]); const { @@ -133,8 +152,6 @@ function K8sNodesList({ enabled: !!fetchGroupedByRowDataQuery && !!selectedRowData, }); - const { currentQuery } = useQueryBuilder(); - const { data: groupByFiltersData, isLoading: isLoadingGroupByFilters, @@ -153,15 +170,6 @@ function K8sNodesList({ K8sCategory.NODES, ); - const queryFilters = useMemo( - () => - currentQuery?.builder?.queryData[0]?.filters || { - items: [], - op: 'and', - }, - [currentQuery?.builder?.queryData], - ); - const query = useMemo(() => { const baseQuery = getK8sNodesListQuery(); const queryPayload = { @@ -308,6 +316,7 @@ function K8sNodesList({ ) : (
[]} dataSource={formattedGroupedByNodesData} pagination={false} @@ -382,18 +391,6 @@ function K8sNodesList({ setselectedNodeUID(null); }; - const showsNodesTable = - !isError && - !isLoading && - !isFetching && - !(formattedNodesData.length === 0 && queryFilters.items.length > 0); - - const showNoFilteredNodesMessage = - !isFetching && - !isLoading && - formattedNodesData.length === 0 && - queryFilters.items.length > 0; - const handleGroupByChange = useCallback( (value: IBuilderQuery['groupBy']) => { const groupBy = []; @@ -442,54 +439,53 @@ function K8sNodesList({ /> {isError && {data?.error || 'Something went wrong'}} - {showNoFilteredNodesMessage && ( -
-
- thinking-emoji +
} />, + }} + locale={{ + emptyText: + isFetching || isLoading ? null : ( +
+
+ thinking-emoji - - This query had no results. Edit your query and try again! - -
-
- )} + + This query had no results. Edit your query and try again! + + + + ), + }} + tableLayout="fixed" + onChange={handleTableChange} + onRow={(record): { onClick: () => void; className: string } => ({ + onClick: (): void => handleRowClick(record), + className: 'clickable-row', + })} + expandable={{ + expandedRowRender: isGroupedByAttribute ? expandedRowRender : undefined, + expandIcon: expandRowIconRenderer, + expandedRowKeys, + }} + /> - {(isFetching || isLoading) && } - - {showsNodesTable && ( -
} />, - }} - tableLayout="fixed" - onChange={handleTableChange} - onRow={(record): { onClick: () => void; className: string } => ({ - onClick: (): void => handleRowClick(record), - className: 'clickable-row', - })} - expandable={{ - expandedRowRender: isGroupedByAttribute ? expandedRowRender : undefined, - expandIcon: expandRowIconRenderer, - expandedRowKeys, - }} - /> - )} ( - + ); const handlePrev = (): void => { diff --git a/frontend/src/container/InfraMonitoringK8s/Nodes/NodeDetails/NodeDetails.tsx b/frontend/src/container/InfraMonitoringK8s/Nodes/NodeDetails/NodeDetails.tsx index a81bcfede9..33ecd20c36 100644 --- a/frontend/src/container/InfraMonitoringK8s/Nodes/NodeDetails/NodeDetails.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Nodes/NodeDetails/NodeDetails.tsx @@ -12,6 +12,7 @@ import { initialQueryState, } from 'constants/queryBuilder'; import ROUTES from 'constants/routes'; +import { filterDuplicateFilters } from 'container/InfraMonitoringK8s/entityDetailUtils'; import { CustomTimeType, Time, @@ -97,22 +98,9 @@ function NodeDetails({ op: '=', value: node?.meta.k8s_node_name || '', }, - { - id: uuidv4(), - key: { - key: QUERY_KEYS.K8S_CLUSTER_NAME, - dataType: DataTypes.String, - type: 'resource', - isColumn: false, - isJSON: false, - id: 'k8s_node_name--string--resource--false', - }, - op: '=', - value: node?.meta.k8s_cluster_name || '', - }, ], }), - [node?.meta.k8s_node_name, node?.meta.k8s_cluster_name], + [node?.meta.k8s_node_name], ); const initialEventsFilters = useMemo( @@ -239,11 +227,13 @@ function NodeDetails({ return { op: 'AND', - items: [ - ...primaryFilters, - ...newFilters, - ...(paginationFilter ? [paginationFilter] : []), - ].filter((item): item is TagFilterItem => item !== undefined), + items: filterDuplicateFilters( + [ + ...primaryFilters, + ...newFilters, + ...(paginationFilter ? [paginationFilter] : []), + ].filter((item): item is TagFilterItem => item !== undefined), + ), }; }); }, @@ -266,12 +256,14 @@ function NodeDetails({ return { op: 'AND', - items: [ - ...primaryFilters, - ...value.items.filter( - (item) => item.key?.key !== QUERY_KEYS.K8S_NODE_NAME, - ), - ].filter((item): item is TagFilterItem => item !== undefined), + items: filterDuplicateFilters( + [ + ...primaryFilters, + ...value.items.filter( + (item) => item.key?.key !== QUERY_KEYS.K8S_NODE_NAME, + ), + ].filter((item): item is TagFilterItem => item !== undefined), + ), }; }); }, diff --git a/frontend/src/container/InfraMonitoringK8s/Nodes/utils.tsx b/frontend/src/container/InfraMonitoringK8s/Nodes/utils.tsx index 6722391714..361b42b7e2 100644 --- a/frontend/src/container/InfraMonitoringK8s/Nodes/utils.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Nodes/utils.tsx @@ -64,7 +64,7 @@ export interface K8sNodesRowData { const nodeGroupColumnConfig = { title: ( -
+
NODE GROUP
), @@ -74,6 +74,7 @@ const nodeGroupColumnConfig = { width: 150, align: 'left', sorter: false, + className: 'column entity-group-header', }; export const getK8sNodesListQuery = (): K8sNodesListPayload => ({ @@ -86,7 +87,7 @@ export const getK8sNodesListQuery = (): K8sNodesListPayload => ({ const columnsConfig = [ { - title:
Node Name
, + title:
Node Name
, dataIndex: 'nodeName', key: 'nodeName', ellipsis: true, @@ -95,7 +96,7 @@ const columnsConfig = [ align: 'left', }, { - title:
Cluster Name
, + title:
Cluster Name
, dataIndex: 'clusterName', key: 'clusterName', ellipsis: true, diff --git a/frontend/src/container/InfraMonitoringK8s/Pods/K8sPodLists.tsx b/frontend/src/container/InfraMonitoringK8s/Pods/K8sPodLists.tsx index 3ea8bda71a..4628143b1b 100644 --- a/frontend/src/container/InfraMonitoringK8s/Pods/K8sPodLists.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Pods/K8sPodLists.tsx @@ -15,6 +15,7 @@ import get from 'api/browser/localstorage/get'; import set from 'api/browser/localstorage/set'; import logEvent from 'api/common/logEvent'; import { K8sPodsListPayload } from 'api/infraMonitoring/getK8sPodsList'; +import classNames from 'classnames'; import { useGetK8sPodsList } from 'hooks/infraMonitoring/useGetK8sPodsList'; import { useGetAggregateKeys } from 'hooks/queryBuilder/useGetAggregateKeys'; import { useQueryBuilder } from 'hooks/queryBuilder/useQueryBuilder'; @@ -38,7 +39,7 @@ import { formatDataForTable, getK8sPodsListColumns, getK8sPodsListQuery, - IPodColumn, + IEntityColumn, K8sPodsRowData, } from '../utils'; import PodDetails from './PodDetails/PodDetails'; @@ -47,9 +48,11 @@ import PodDetails from './PodDetails/PodDetails'; function K8sPodsList({ isFiltersVisible, handleFilterVisibilityChange, + quickFiltersLastUpdated, }: { isFiltersVisible: boolean; handleFilterVisibilityChange: () => void; + quickFiltersLastUpdated: number; }): JSX.Element { const { maxTime, minTime } = useSelector( (state) => state.globalTime, @@ -57,9 +60,9 @@ function K8sPodsList({ const [currentPage, setCurrentPage] = useState(1); - const [addedColumns, setAddedColumns] = useState([]); + const [addedColumns, setAddedColumns] = useState([]); - const [availableColumns, setAvailableColumns] = useState( + const [availableColumns, setAvailableColumns] = useState( defaultAvailableColumns, ); @@ -104,6 +107,11 @@ function K8sPodsList({ K8sCategory.PODS, // infraMonitoringEntity ); + // Reset pagination every time quick filters are changed + useEffect(() => { + setCurrentPage(1); + }, [quickFiltersLastUpdated]); + useEffect(() => { const addedColumns = JSON.parse(get('k8sPodsAddedColumns') ?? '[]'); @@ -124,7 +132,7 @@ function K8sPodsList({ const [orderBy, setOrderBy] = useState<{ columnName: string; order: 'asc' | 'desc'; - } | null>(null); + } | null>({ columnName: 'cpu', order: 'desc' }); const [selectedPodUID, setSelectedPodUID] = useState(null); @@ -162,7 +170,7 @@ function K8sPodsList({ selectedRowData: K8sPodsRowData, ): IBuilderQuery['filters'] => { const baseFilters: IBuilderQuery['filters'] = { - items: [], + items: [...query.filters.items], op: 'and', }; @@ -201,6 +209,7 @@ function K8sPodsList({ end: Math.floor(maxTime / 1000000), orderBy, }; + // eslint-disable-next-line react-hooks/exhaustive-deps }, [minTime, maxTime, orderBy, selectedRowData]); const { @@ -338,20 +347,8 @@ function K8sPodsList({ setSelectedPodUID(null); }; - const showPodsTable = - !isError && - !isLoading && - !isFetching && - !(formattedPodsData.length === 0 && queryFilters.items.length > 0); - - const showNoFilteredPodsMessage = - !isFetching && - !isLoading && - formattedPodsData.length === 0 && - queryFilters.items.length > 0; - const handleAddColumn = useCallback( - (column: IPodColumn): void => { + (column: IEntityColumn): void => { setAddedColumns((prev) => [...prev, column]); setAvailableColumns((prev) => prev.filter((c) => c.value !== column.value)); @@ -378,7 +375,7 @@ function K8sPodsList({ }, [groupByFiltersData]); const handleRemoveColumn = useCallback( - (column: IPodColumn): void => { + (column: IEntityColumn): void => { setAddedColumns((prev) => prev.filter((c) => c.value !== column.value)); setAvailableColumns((prev) => [...prev, column]); @@ -505,54 +502,54 @@ function K8sPodsList({ /> {isError && {data?.error || 'Something went wrong'}} - {showNoFilteredPodsMessage && ( -
-
- thinking-emoji +
} />, + }} + locale={{ + emptyText: + isFetching || isLoading ? null : ( +
+
+ thinking-emoji - - This query had no results. Edit your query and try again! - -
-
- )} - - {(isFetching || isLoading) && } - - {showPodsTable && ( -
} />, - }} - scroll={{ x: true }} - tableLayout="fixed" - onChange={handleTableChange} - onRow={(record): { onClick: () => void; className: string } => ({ - onClick: (): void => handleRowClick(record), - className: 'clickable-row', - })} - expandable={{ - expandedRowRender: isGroupedByAttribute ? expandedRowRender : undefined, - expandIcon: expandRowIconRenderer, - expandedRowKeys, - }} - /> - )} + + This query had no results. Edit your query and try again! + + + + ), + }} + scroll={{ x: true }} + tableLayout="fixed" + onChange={handleTableChange} + onRow={(record): { onClick: () => void; className: string } => ({ + onClick: (): void => handleRowClick(record), + className: 'clickable-row', + })} + expandable={{ + expandedRowRender: isGroupedByAttribute ? expandedRowRender : undefined, + expandIcon: expandRowIconRenderer, + expandedRowKeys, + }} + /> {selectedPodData && ( ( - + ); const handlePrev = (): void => { diff --git a/frontend/src/container/InfraMonitoringK8s/Pods/PodDetails/PodDetails.tsx b/frontend/src/container/InfraMonitoringK8s/Pods/PodDetails/PodDetails.tsx index 1da904aa6d..d13207106f 100644 --- a/frontend/src/container/InfraMonitoringK8s/Pods/PodDetails/PodDetails.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Pods/PodDetails/PodDetails.tsx @@ -13,6 +13,7 @@ import { initialQueryState, } from 'constants/queryBuilder'; import ROUTES from 'constants/routes'; +import { filterDuplicateFilters } from 'container/InfraMonitoringK8s/entityDetailUtils'; import { CustomTimeType, Time, @@ -50,7 +51,7 @@ import { PodDetailProps } from './PodDetail.interfaces'; import PodLogsDetailedView from './PodLogs/PodLogsDetailedView'; import PodTraces from './PodTraces/PodTraces'; -const TimeRangeOffset = 1000000; +const TimeRangeOffset = 1000000000; // eslint-disable-next-line sonarjs/cognitive-complexity function PodDetails({ @@ -101,19 +102,6 @@ function PodDetails({ op: '=', value: pod?.meta.k8s_pod_name || '', }, - { - id: uuidv4(), - key: { - key: QUERY_KEYS.K8S_CLUSTER_NAME, - dataType: DataTypes.String, - type: 'resource', - isColumn: false, - isJSON: false, - id: 'k8s_pod_name--string--resource--false', - }, - op: '=', - value: pod?.meta.k8s_cluster_name || '', - }, { id: uuidv4(), key: { @@ -129,11 +117,7 @@ function PodDetails({ }, ], }), - [ - pod?.meta.k8s_cluster_name, - pod?.meta.k8s_namespace_name, - pod?.meta.k8s_pod_name, - ], + [pod?.meta.k8s_namespace_name, pod?.meta.k8s_pod_name], ); const initialEventsFilters = useMemo( @@ -262,11 +246,13 @@ function PodDetails({ return { op: 'AND', - items: [ - ...primaryFilters, - ...newFilters, - ...(paginationFilter ? [paginationFilter] : []), - ].filter((item): item is TagFilterItem => item !== undefined), + items: filterDuplicateFilters( + [ + ...primaryFilters, + ...newFilters, + ...(paginationFilter ? [paginationFilter] : []), + ].filter((item): item is TagFilterItem => item !== undefined), + ), }; }); }, @@ -291,12 +277,14 @@ function PodDetails({ return { op: 'AND', - items: [ - ...primaryFilters, - ...value.items.filter( - (item) => item.key?.key !== QUERY_KEYS.K8S_POD_NAME, - ), - ].filter((item): item is TagFilterItem => item !== undefined), + items: filterDuplicateFilters( + [ + ...primaryFilters, + ...value.items.filter( + (item) => item.key?.key !== QUERY_KEYS.K8S_POD_NAME, + ), + ].filter((item): item is TagFilterItem => item !== undefined), + ), }; }); }, diff --git a/frontend/src/container/InfraMonitoringK8s/Pods/PodDetails/PodTraces/PodTraces.tsx b/frontend/src/container/InfraMonitoringK8s/Pods/PodDetails/PodTraces/PodTraces.tsx index 03c7f43b93..53b12908c8 100644 --- a/frontend/src/container/InfraMonitoringK8s/Pods/PodDetails/PodTraces/PodTraces.tsx +++ b/frontend/src/container/InfraMonitoringK8s/Pods/PodDetails/PodTraces/PodTraces.tsx @@ -78,8 +78,6 @@ function PodTraces({ [currentQuery], ); - console.log({ updatedCurrentQuery }); - const query = updatedCurrentQuery?.builder?.queryData[0] || null; const { queryData: paginationQueryData } = useUrlQueryData( diff --git a/frontend/src/container/InfraMonitoringK8s/commonUtils.tsx b/frontend/src/container/InfraMonitoringK8s/commonUtils.tsx index c7e287ad5a..e1fb2bbf4b 100644 --- a/frontend/src/container/InfraMonitoringK8s/commonUtils.tsx +++ b/frontend/src/container/InfraMonitoringK8s/commonUtils.tsx @@ -100,7 +100,13 @@ export function getStrokeColorForLimitUtilization(value: number): string { export const getProgressBarText = (percent: number): React.ReactNode => `${percent}%`; -export function EntityProgressBar({ value }: { value: number }): JSX.Element { +export function EntityProgressBar({ + value, + type, +}: { + value: number; + type: 'request' | 'limit'; +}): JSX.Element { const percentage = Number((value * 100).toFixed(1)); return ( @@ -110,7 +116,11 @@ export function EntityProgressBar({ value }: { value: number }): JSX.Element { strokeLinecap="butt" size="small" status="normal" - strokeColor={getStrokeColorForLimitUtilization(value)} + strokeColor={ + type === 'limit' + ? getStrokeColorForLimitUtilization(value) + : getStrokeColorForRequestUtilization(value) + } className="progress-bar" showInfo={false} /> diff --git a/frontend/src/container/InfraMonitoringK8s/constants.ts b/frontend/src/container/InfraMonitoringK8s/constants.ts index 097cfd7014..e97ea61f90 100644 --- a/frontend/src/container/InfraMonitoringK8s/constants.ts +++ b/frontend/src/container/InfraMonitoringK8s/constants.ts @@ -150,6 +150,8 @@ export const PodsQuickFiltersConfig: IQuickFiltersConfig[] = [ isColumn: false, isJSON: false, }, + aggregateOperator: 'noop', + aggregateAttribute: 'k8s_pod_cpu_utilization', dataSource: DataSource.METRICS, defaultOpen: false, }, diff --git a/frontend/src/container/InfraMonitoringK8s/entityDetailUtils.ts b/frontend/src/container/InfraMonitoringK8s/entityDetailUtils.ts new file mode 100644 index 0000000000..66315adb4d --- /dev/null +++ b/frontend/src/container/InfraMonitoringK8s/entityDetailUtils.ts @@ -0,0 +1,18 @@ +import { TagFilterItem } from 'types/api/queryBuilder/queryBuilderData'; + +export const filterDuplicateFilters = ( + filters: TagFilterItem[], +): TagFilterItem[] => { + const uniqueFilters = []; + const seenIds = new Set(); + + // eslint-disable-next-line no-restricted-syntax + for (const filter of filters) { + if (!seenIds.has(filter.id)) { + seenIds.add(filter.id); + uniqueFilters.push(filter); + } + } + + return uniqueFilters; +}; diff --git a/frontend/src/container/InfraMonitoringK8s/utils.tsx b/frontend/src/container/InfraMonitoringK8s/utils.tsx index 156d53aa28..d590c6273c 100644 --- a/frontend/src/container/InfraMonitoringK8s/utils.tsx +++ b/frontend/src/container/InfraMonitoringK8s/utils.tsx @@ -26,16 +26,9 @@ export interface IEntityColumn { canRemove: boolean; } -export interface IPodColumn { - label: string; - value: string; - id: string; - canRemove: boolean; -} - const columnProgressBarClassName = 'column-progress-bar'; -export const defaultAddedColumns: IPodColumn[] = [ +export const defaultAddedColumns: IEntityColumn[] = [ { label: 'Pod name', value: 'podName', @@ -78,12 +71,13 @@ export const defaultAddedColumns: IPodColumn[] = [ id: 'memory', canRemove: false, }, - { - label: 'Restarts', - value: 'restarts', - id: 'restarts', - canRemove: false, - }, + // TODO - Re-enable the column once backend issue is fixed + // { + // label: 'Restarts', + // value: 'restarts', + // id: 'restarts', + // canRemove: false, + // }, ]; export const defaultAvailableColumns = [ @@ -131,7 +125,7 @@ export const getK8sPodsListQuery = (): K8sPodsListPayload => ({ const podGroupColumnConfig = { title: ( -
+
POD GROUP
), @@ -140,7 +134,7 @@ const podGroupColumnConfig = { ellipsis: true, width: 180, sorter: false, - className: 'column column-pod-group', + className: 'column entity-group-header', }; export const dummyColumnConfig = { @@ -160,11 +154,11 @@ const columnsConfig = [ key: 'podName', width: 180, ellipsis: true, - sorter: true, + sorter: false, className: 'column column-pod-name', }, { - title:
CPU Req Usage (%)
, + title:
CPU Req Usage (%)
, dataIndex: 'cpu_request', key: 'cpu_request', width: 180, @@ -174,7 +168,7 @@ const columnsConfig = [ className: `column ${columnProgressBarClassName}`, }, { - title:
CPU Limit Usage (%)
, + title:
CPU Limit Usage (%)
, dataIndex: 'cpu_limit', key: 'cpu_limit', width: 120, @@ -192,7 +186,7 @@ const columnsConfig = [ className: `column ${columnProgressBarClassName}`, }, { - title:
Mem Req Usage (%)
, + title:
Mem Req Usage (%)
, dataIndex: 'memory_request', key: 'memory_request', width: 120, @@ -201,7 +195,7 @@ const columnsConfig = [ className: `column ${columnProgressBarClassName}`, }, { - title:
Mem Limit Usage (%)
, + title:
Mem Limit Usage (%)
, dataIndex: 'memory_limit', key: 'memory_limit', width: 120, @@ -219,20 +213,21 @@ const columnsConfig = [ align: 'left', className: `column ${columnProgressBarClassName}`, }, - { - title: ( -
- Restarts -
- ), - dataIndex: 'restarts', - key: 'restarts', - width: 40, - ellipsis: true, - sorter: true, - align: 'left', - className: `column ${columnProgressBarClassName}`, - }, + // TODO - Re-enable the column once backend issue is fixed + // { + // title: ( + //
+ // Restarts + //
+ // ), + // dataIndex: 'restarts', + // key: 'restarts', + // width: 40, + // ellipsis: true, + // sorter: true, + // align: 'left', + // className: `column ${columnProgressBarClassName}`, + // }, ]; export const namespaceColumnConfig = { @@ -251,7 +246,7 @@ export const nodeColumnConfig = { dataIndex: 'node', key: 'node', width: 100, - sorter: true, + sorter: false, ellipsis: true, align: 'left', className: 'column column-node', @@ -262,7 +257,7 @@ export const clusterColumnConfig = { dataIndex: 'cluster', key: 'cluster', width: 100, - sorter: true, + sorter: false, ellipsis: true, align: 'left', className: 'column column-cluster', @@ -275,7 +270,7 @@ export const columnConfigMap = { }; export const getK8sPodsListColumns = ( - addedColumns: IPodColumn[], + addedColumns: IEntityColumn[], groupBy: IBuilderQuery['groupBy'], ): ColumnType[] => { const updatedColumnsConfig = [...columnsConfig]; @@ -341,7 +336,7 @@ export const formatDataForTable = ( attribute="CPU Request" >
- +
), @@ -352,7 +347,7 @@ export const formatDataForTable = ( attribute="CPU Limit" >
- +
), @@ -368,7 +363,7 @@ export const formatDataForTable = ( attribute="Memory Request" >
- +
), @@ -379,7 +374,7 @@ export const formatDataForTable = ( attribute="Memory Limit" >
- +
), diff --git a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/index.tsx b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/index.tsx index 5523ac1c48..da48d74256 100644 --- a/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/index.tsx +++ b/frontend/src/container/QueryBuilder/filters/QueryBuilderSearch/index.tsx @@ -95,6 +95,7 @@ function QueryBuilderSearch({ isMulti, isFetching, setSearchKey, + setSearchValue, searchKey, key, exampleQueries, @@ -145,7 +146,11 @@ function QueryBuilderSearch({ const tagEditHandler = (value: string): void => { updateTag(value); - handleSearch(value); + if (isInfraMonitoring) { + setSearchValue(value); + } else { + handleSearch(value); + } }; const isDisabled = !!searchValue; diff --git a/frontend/src/hooks/queryBuilder/useAutoComplete.ts b/frontend/src/hooks/queryBuilder/useAutoComplete.ts index 0dab692099..e728e0fa80 100644 --- a/frontend/src/hooks/queryBuilder/useAutoComplete.ts +++ b/frontend/src/hooks/queryBuilder/useAutoComplete.ts @@ -153,6 +153,7 @@ export const useAutoComplete = ( isMulti, isFetching, setSearchKey, + setSearchValue, searchKey, key, exampleQueries, @@ -172,6 +173,7 @@ interface IAutoComplete { isMulti: boolean; isFetching: boolean; setSearchKey: (value: string) => void; + setSearchValue: (value: string) => void; searchKey: string; key: string; exampleQueries: TagFilter[]; diff --git a/frontend/src/pages/InfrastructureMonitoring/InfrastructureMonitoringPage.tsx b/frontend/src/pages/InfrastructureMonitoring/InfrastructureMonitoringPage.tsx index 99f0455be9..a86f7ec56e 100644 --- a/frontend/src/pages/InfrastructureMonitoring/InfrastructureMonitoringPage.tsx +++ b/frontend/src/pages/InfrastructureMonitoring/InfrastructureMonitoringPage.tsx @@ -5,12 +5,12 @@ import { TabRoutes } from 'components/RouteTab/types'; import history from 'lib/history'; import { useLocation } from 'react-use'; -import { Hosts } from './constants'; +import { Hosts, Kubernetes } from './constants'; export default function InfrastructureMonitoringPage(): JSX.Element { const { pathname } = useLocation(); - const routes: TabRoutes[] = [Hosts]; + const routes: TabRoutes[] = [Hosts, Kubernetes]; return (