Compare commits

...

19 Commits

Author SHA1 Message Date
Nikhil Mantri
aa2e0d8104 Merge branch 'main' into feat/infraM_list_apis_request_time_check 2026-02-26 20:12:42 +05:30
nikhilmantri0902
ea5d89e72c chore: added 3 cases handling for all list apis 2026-02-26 14:00:23 +05:30
nikhilmantri0902
a518b1688b chore: rename func 2026-02-26 13:17:05 +05:30
Nikhil Mantri
44a94e7746 Merge branch 'main' into feat/update_hosts_list_error_messaging 2026-02-26 11:04:38 +05:30
Nikhil Mantri
38d334b9aa Merge branch 'main' into feat/update_hosts_list_error_messaging 2026-02-24 20:36:14 +05:30
Nikhil Mantri
3f27e49eac Merge branch 'main' into feat/update_hosts_list_error_messaging 2026-02-20 12:57:03 +05:30
nikhilmantri0902
0b8e87ec96 chore: added test case and final comment resolve 2026-02-19 16:51:58 +05:30
nikhilmantri0902
df2916bf7f chore: review comments 1 2026-02-19 16:15:30 +05:30
Nikhil Mantri
0c62c075f9 Merge branch 'main' into feat/update_hosts_list_error_messaging 2026-02-19 15:54:14 +05:30
nikhilmantri0902
f42d95d5f5 chore: title updated for no host metrics found 2026-02-18 12:32:32 +05:30
nikhilmantri0902
32c0dfa28f chore: title for end time before earliest metadata time 2026-02-18 12:25:09 +05:30
Nikhil Mantri
68e831c4b0 Merge branch 'main' into feat/update_hosts_list_error_messaging 2026-02-17 15:51:27 +05:30
Nikhil Mantri
ed79d40492 Merge branch 'main' into feat/update_hosts_list_error_messaging 2026-02-17 14:16:13 +05:30
nikhilmantri0902
ad8223c792 chore: refactor and conditions combine 2026-02-17 13:46:55 +05:30
nikhilmantri0902
5d691476b1 chore: rearrangement 2026-02-17 12:46:38 +05:30
nikhilmantri0902
358977e203 chore: frontend messaging test fix 2026-02-16 14:37:03 +05:30
nikhilmantri0902
7ffb3e30b5 chore: improved messaging and comment 2026-02-16 14:19:12 +05:30
nikhilmantri0902
ded7b78360 chore: use named query 2026-02-16 13:43:43 +05:30
nikhilmantri0902
76e9074ca7 chore: initial logical changes 2026-02-15 19:04:44 +05:30
30 changed files with 944 additions and 487 deletions

View File

@@ -37,8 +37,8 @@ export interface K8sClustersListResponse {
records: K8sClustersData[];
groups: null;
total: number;
sentAnyHostMetricsData: boolean;
isSendingK8SAgentMetrics: boolean;
sentAnyMetricsData: boolean;
endTimeBeforeRetention: boolean;
};
}

View File

@@ -43,8 +43,8 @@ export interface K8sDaemonSetsListResponse {
records: K8sDaemonSetsData[];
groups: null;
total: number;
sentAnyHostMetricsData: boolean;
isSendingK8SAgentMetrics: boolean;
sentAnyMetricsData: boolean;
endTimeBeforeRetention: boolean;
};
}

View File

@@ -43,8 +43,8 @@ export interface K8sDeploymentsListResponse {
records: K8sDeploymentsData[];
groups: null;
total: number;
sentAnyHostMetricsData: boolean;
isSendingK8SAgentMetrics: boolean;
sentAnyMetricsData: boolean;
endTimeBeforeRetention: boolean;
};
}

View File

@@ -45,8 +45,8 @@ export interface K8sJobsListResponse {
records: K8sJobsData[];
groups: null;
total: number;
sentAnyHostMetricsData: boolean;
isSendingK8SAgentMetrics: boolean;
sentAnyMetricsData: boolean;
endTimeBeforeRetention: boolean;
};
}

View File

@@ -35,8 +35,8 @@ export interface K8sNamespacesListResponse {
records: K8sNamespacesData[];
groups: null;
total: number;
sentAnyHostMetricsData: boolean;
isSendingK8SAgentMetrics: boolean;
sentAnyMetricsData: boolean;
endTimeBeforeRetention: boolean;
};
}

View File

@@ -38,8 +38,8 @@ export interface K8sNodesListResponse {
records: K8sNodesData[];
groups: null;
total: number;
sentAnyHostMetricsData: boolean;
isSendingK8SAgentMetrics: boolean;
sentAnyMetricsData: boolean;
endTimeBeforeRetention: boolean;
};
}

View File

@@ -66,8 +66,8 @@ export interface K8sPodsListResponse {
records: K8sPodsData[];
groups: null;
total: number;
sentAnyHostMetricsData: boolean;
isSendingK8SAgentMetrics: boolean;
sentAnyMetricsData: boolean;
endTimeBeforeRetention: boolean;
};
}

View File

@@ -44,8 +44,8 @@ export interface K8sVolumesListResponse {
records: K8sVolumesData[];
groups: null;
total: number;
sentAnyHostMetricsData: boolean;
isSendingK8SAgentMetrics: boolean;
sentAnyMetricsData: boolean;
endTimeBeforeRetention: boolean;
};
}

View File

@@ -42,8 +42,8 @@ export interface K8sStatefulSetsListResponse {
records: K8sStatefulSetsData[];
groups: null;
total: number;
sentAnyHostMetricsData: boolean;
isSendingK8SAgentMetrics: boolean;
sentAnyMetricsData: boolean;
endTimeBeforeRetention: boolean;
};
}

View File

@@ -33,6 +33,7 @@ import {
INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory,
} from '../constants';
import { getK8sEmptyState } from '../K8sEmptyState';
import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer';
import { usePageSize } from '../utils';
@@ -331,6 +332,9 @@ function K8sClustersList({
const clustersData = useMemo(() => data?.payload?.data?.records || [], [data]);
const totalCount = data?.payload?.data?.total || 0;
const sentAnyMetricsData = data?.payload?.data?.sentAnyMetricsData ?? false;
const endTimeBeforeRetention =
data?.payload?.data?.endTimeBeforeRetention ?? false;
const formattedClustersData = useMemo(
() => formatDataForTable(clustersData, groupBy),
@@ -655,6 +659,18 @@ function K8sClustersList({
const showTableLoadingState =
(isFetching || isLoading) && formattedClustersData.length === 0;
const emptyState = getK8sEmptyState({
sentAnyMetricsData,
endTimeBeforeRetention,
entityName: 'cluster',
isLoading,
isFetching,
hasRecords: formattedClustersData.length > 0,
hasFilters: queryFilters?.items?.length > 0,
isError,
errorMessage: data?.error ?? '',
});
return (
<div className="k8s-list">
<K8sHeader
@@ -669,54 +685,42 @@ function K8sClustersList({
entity={K8sCategory.NODES}
showAutoRefresh={!selectedClusterData}
/>
{isError && <Typography>{data?.error || 'Something went wrong'}</Typography>}
{emptyState}
<Table
className="k8s-list-table clusters-list-table"
dataSource={showTableLoadingState ? [] : formattedClustersData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: showTableLoadingState ? null : (
<div className="no-filtered-hosts-message-container">
<div className="no-filtered-hosts-message-content">
<img
src="/Icons/emptyState.svg"
alt="thinking-emoji"
className="empty-state-svg"
/>
<Typography.Text className="no-filtered-hosts-message">
This query had no results. Edit your query and try again!
</Typography.Text>
</div>
</div>
),
}}
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,
}}
/>
{!emptyState && (
<Table
className="k8s-list-table clusters-list-table"
dataSource={showTableLoadingState ? [] : formattedClustersData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: null,
}}
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,
}}
/>
)}
<ClusterDetails
cluster={selectedClusterData}

View File

@@ -34,6 +34,7 @@ import {
INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory,
} from '../constants';
import { getK8sEmptyState } from '../K8sEmptyState';
import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer';
import { usePageSize } from '../utils';
@@ -328,6 +329,9 @@ function K8sDaemonSetsList({
data,
]);
const totalCount = data?.payload?.data?.total || 0;
const sentAnyMetricsData = data?.payload?.data?.sentAnyMetricsData ?? false;
const endTimeBeforeRetention =
data?.payload?.data?.endTimeBeforeRetention ?? false;
const formattedDaemonSetsData = useMemo(
() => formatDataForTable(daemonSetsData, groupBy),
@@ -661,6 +665,18 @@ function K8sDaemonSetsList({
const showTableLoadingState =
(isFetching || isLoading) && formattedDaemonSetsData.length === 0;
const emptyState = getK8sEmptyState({
sentAnyMetricsData,
endTimeBeforeRetention,
entityName: 'daemon set',
isLoading,
isFetching,
hasRecords: formattedDaemonSetsData.length > 0,
hasFilters: queryFilters?.items?.length > 0,
isError,
errorMessage: data?.error ?? '',
});
return (
<div className="k8s-list">
<K8sHeader
@@ -675,56 +691,44 @@ function K8sDaemonSetsList({
entity={K8sCategory.DAEMONSETS}
showAutoRefresh={!selectedDaemonSetData}
/>
{isError && <Typography>{data?.error || 'Something went wrong'}</Typography>}
{emptyState}
<Table
className={classNames('k8s-list-table', 'daemonSets-list-table', {
'expanded-daemonsets-list-table': isGroupedByAttribute,
})}
dataSource={showTableLoadingState ? [] : formattedDaemonSetsData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: showTableLoadingState ? null : (
<div className="no-filtered-hosts-message-container">
<div className="no-filtered-hosts-message-content">
<img
src="/Icons/emptyState.svg"
alt="thinking-emoji"
className="empty-state-svg"
/>
<Typography.Text className="no-filtered-hosts-message">
This query had no results. Edit your query and try again!
</Typography.Text>
</div>
</div>
),
}}
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,
}}
/>
{!emptyState && (
<Table
className={classNames('k8s-list-table', 'daemonSets-list-table', {
'expanded-daemonsets-list-table': isGroupedByAttribute,
})}
dataSource={showTableLoadingState ? [] : formattedDaemonSetsData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: null,
}}
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,
}}
/>
)}
<DaemonSetDetails
daemonSet={selectedDaemonSetData}

View File

@@ -34,6 +34,7 @@ import {
INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory,
} from '../constants';
import { getK8sEmptyState } from '../K8sEmptyState';
import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer';
import { usePageSize } from '../utils';
@@ -329,6 +330,9 @@ function K8sDeploymentsList({
data,
]);
const totalCount = data?.payload?.data?.total || 0;
const sentAnyMetricsData = data?.payload?.data?.sentAnyMetricsData ?? false;
const endTimeBeforeRetention =
data?.payload?.data?.endTimeBeforeRetention ?? false;
const formattedDeploymentsData = useMemo(
() => formatDataForTable(deploymentsData, groupBy),
@@ -668,6 +672,18 @@ function K8sDeploymentsList({
const showTableLoadingState =
(isFetching || isLoading) && formattedDeploymentsData.length === 0;
const emptyState = getK8sEmptyState({
sentAnyMetricsData,
endTimeBeforeRetention,
entityName: 'deployment',
isLoading,
isFetching,
hasRecords: formattedDeploymentsData.length > 0,
hasFilters: queryFilters?.items?.length > 0,
isError,
errorMessage: data?.error ?? '',
});
return (
<div className="k8s-list">
<K8sHeader
@@ -682,56 +698,44 @@ function K8sDeploymentsList({
entity={K8sCategory.NODES}
showAutoRefresh={!selectedDeploymentData}
/>
{isError && <Typography>{data?.error || 'Something went wrong'}</Typography>}
{emptyState}
<Table
className={classNames('k8s-list-table', 'deployments-list-table', {
'expanded-deployments-list-table': isGroupedByAttribute,
})}
dataSource={showTableLoadingState ? [] : formattedDeploymentsData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: showTableLoadingState ? null : (
<div className="no-filtered-hosts-message-container">
<div className="no-filtered-hosts-message-content">
<img
src="/Icons/emptyState.svg"
alt="thinking-emoji"
className="empty-state-svg"
/>
<Typography.Text className="no-filtered-hosts-message">
This query had no results. Edit your query and try again!
</Typography.Text>
</div>
</div>
),
}}
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,
}}
/>
{!emptyState && (
<Table
className={classNames('k8s-list-table', 'deployments-list-table', {
'expanded-deployments-list-table': isGroupedByAttribute,
})}
dataSource={showTableLoadingState ? [] : formattedDeploymentsData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: null,
}}
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,
}}
/>
)}
<DeploymentDetails
deployment={selectedDeploymentData}

View File

@@ -34,6 +34,7 @@ import {
INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory,
} from '../constants';
import { getK8sEmptyState } from '../K8sEmptyState';
import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer';
import { usePageSize } from '../utils';
@@ -321,6 +322,9 @@ function K8sJobsList({
const jobsData = useMemo(() => data?.payload?.data?.records || [], [data]);
const totalCount = data?.payload?.data?.total || 0;
const sentAnyMetricsData = data?.payload?.data?.sentAnyMetricsData ?? false;
const endTimeBeforeRetention =
data?.payload?.data?.endTimeBeforeRetention ?? false;
const formattedJobsData = useMemo(
() => formatDataForTable(jobsData, groupBy),
@@ -629,6 +633,18 @@ function K8sJobsList({
});
};
const emptyState = getK8sEmptyState({
sentAnyMetricsData,
endTimeBeforeRetention,
entityName: 'job',
isLoading,
isFetching,
hasRecords: formattedJobsData.length > 0,
hasFilters: queryFilters?.items?.length > 0,
isError,
errorMessage: data?.error ?? '',
});
return (
<div className="k8s-list">
<K8sHeader
@@ -643,57 +659,44 @@ function K8sJobsList({
entity={K8sCategory.JOBS}
showAutoRefresh={!selectedJobData}
/>
{isError && <Typography>{data?.error || 'Something went wrong'}</Typography>}
{emptyState}
<Table
className={classNames('k8s-list-table', 'jobs-list-table', {
'expanded-jobs-list-table': isGroupedByAttribute,
})}
dataSource={isFetching || isLoading ? [] : formattedJobsData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: isFetching || isLoading,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText:
isFetching || isLoading ? null : (
<div className="no-filtered-hosts-message-container">
<div className="no-filtered-hosts-message-content">
<img
src="/Icons/emptyState.svg"
alt="thinking-emoji"
className="empty-state-svg"
/>
<Typography.Text className="no-filtered-hosts-message">
This query had no results. Edit your query and try again!
</Typography.Text>
</div>
</div>
),
}}
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,
}}
/>
{!emptyState && (
<Table
className={classNames('k8s-list-table', 'jobs-list-table', {
'expanded-jobs-list-table': isGroupedByAttribute,
})}
dataSource={isFetching || isLoading ? [] : formattedJobsData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: isFetching || isLoading,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: null,
}}
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,
}}
/>
)}
<JobDetails
job={selectedJobData}

View File

@@ -0,0 +1,150 @@
import { LoadingOutlined } from '@ant-design/icons';
import { Skeleton, Spin, Typography } from 'antd';
interface K8sEmptyStateProps {
sentAnyMetricsData: boolean;
endTimeBeforeRetention: boolean;
entityName: string;
isLoading: boolean;
isFetching: boolean;
hasRecords: boolean;
hasFilters: boolean;
isError: boolean;
errorMessage: string;
}
export function getK8sEmptyState({
sentAnyMetricsData,
endTimeBeforeRetention,
entityName,
isLoading,
isFetching,
hasRecords,
hasFilters,
isError,
errorMessage,
}: K8sEmptyStateProps): React.ReactNode {
if (isError) {
return <Typography>{errorMessage || 'Something went wrong'}</Typography>;
}
const showTableLoadingState = (isLoading || isFetching) && !hasRecords;
if (showTableLoadingState) {
return (
<div className="hosts-list-loading-state">
<Skeleton.Input
className="hosts-list-loading-state-item"
size="large"
block
active
/>
<Skeleton.Input
className="hosts-list-loading-state-item"
size="large"
block
active
/>
<Skeleton.Input
className="hosts-list-loading-state-item"
size="large"
block
active
/>
</div>
);
}
const showEmptyState =
!isFetching &&
!isLoading &&
!hasRecords &&
!sentAnyMetricsData &&
!hasFilters;
if (showEmptyState) {
return (
<div className="hosts-empty-state-container">
<div className="hosts-empty-state-container-content">
<img className="eyes-emoji" src="/Images/eyesEmoji.svg" alt="eyes emoji" />
<div className="no-hosts-message">
<Typography.Title level={5} className="no-hosts-message-title">
No {entityName} metrics data received yet.
</Typography.Title>
<Typography.Text className="no-hosts-message-text">
Please refer to the{' '}
<a
href="https://signoz.io/docs/infrastructure-monitoring/k8s-metrics/"
target="_blank"
rel="noreferrer"
>
Kubernetes Infrastructure Monitoring docs
</a>{' '}
to learn how to send K8s metrics to SigNoz.
</Typography.Text>
</div>
</div>
</div>
);
}
const showEndTimeBeforeRetentionMessage =
!isFetching &&
!isLoading &&
!hasRecords &&
endTimeBeforeRetention &&
!hasFilters;
if (showEndTimeBeforeRetentionMessage) {
return (
<div className="hosts-empty-state-container">
<div className="hosts-empty-state-container-content">
<img className="eyes-emoji" src="/Images/eyesEmoji.svg" alt="eyes emoji" />
<div className="no-hosts-message">
<Typography.Title level={5} className="no-hosts-message-title">
Queried time range is before earliest {entityName} metrics
</Typography.Title>
<Typography.Text className="no-hosts-message-text">
Your requested end time is earlier than the earliest detected time of{' '}
{entityName} metrics data, please adjust your end time.
</Typography.Text>
</div>
</div>
</div>
);
}
const showNoRecordsMessage =
!isFetching &&
!isLoading &&
!hasRecords &&
!showEmptyState &&
!showEndTimeBeforeRetentionMessage;
if (showNoRecordsMessage) {
return (
<div className="no-filtered-hosts-message-container">
<div className="no-filtered-hosts-message-content">
<img
src="/Icons/emptyState.svg"
alt="thinking-emoji"
className="empty-state-svg"
/>
<Typography.Title level={5} className="no-filtered-hosts-title">
No {entityName} metrics found
</Typography.Title>
<Typography.Text className="no-filtered-hosts-message">
No {entityName} metrics in the selected time range and filters. Please
adjust your time range or filters.
</Typography.Text>
</div>
</div>
);
}
return null;
}
export function K8sTableLoadingIndicator(): JSX.Element {
return <Spin indicator={<LoadingOutlined size={14} spin />} />;
}

View File

@@ -33,6 +33,7 @@ import {
INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory,
} from '../constants';
import { getK8sEmptyState } from '../K8sEmptyState';
import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer';
import { usePageSize } from '../utils';
@@ -327,6 +328,9 @@ function K8sNamespacesList({
data,
]);
const totalCount = data?.payload?.data?.total || 0;
const sentAnyMetricsData = data?.payload?.data?.sentAnyMetricsData ?? false;
const endTimeBeforeRetention =
data?.payload?.data?.endTimeBeforeRetention ?? false;
const formattedNamespacesData = useMemo(
() => formatDataForTable(namespacesData, groupBy),
@@ -664,6 +668,18 @@ function K8sNamespacesList({
const showTableLoadingState =
(isFetching || isLoading) && formattedNamespacesData.length === 0;
const emptyState = getK8sEmptyState({
sentAnyMetricsData,
endTimeBeforeRetention,
entityName: 'namespace',
isLoading,
isFetching,
hasRecords: formattedNamespacesData.length > 0,
hasFilters: queryFilters?.items?.length > 0,
isError,
errorMessage: data?.error ?? '',
});
return (
<div className="k8s-list">
<K8sHeader
@@ -678,54 +694,42 @@ function K8sNamespacesList({
entity={K8sCategory.NODES}
showAutoRefresh={!selectedNamespaceData}
/>
{isError && <Typography>{data?.error || 'Something went wrong'}</Typography>}
<Table
className="k8s-list-table namespaces-list-table"
dataSource={showTableLoadingState ? [] : formattedNamespacesData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: showTableLoadingState ? null : (
<div className="no-filtered-hosts-message-container">
<div className="no-filtered-hosts-message-content">
<img
src="/Icons/emptyState.svg"
alt="thinking-emoji"
className="empty-state-svg"
/>
<Typography.Text className="no-filtered-hosts-message">
This query had no results. Edit your query and try again!
</Typography.Text>
</div>
</div>
),
}}
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,
}}
/>
{emptyState ? (
<>{emptyState}</>
) : (
<Table
className="k8s-list-table namespaces-list-table"
dataSource={showTableLoadingState ? [] : formattedNamespacesData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: null,
}}
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,
}}
/>
)}
<NamespaceDetails
namespace={selectedNamespaceData}
isModalTimeSelection

View File

@@ -33,6 +33,7 @@ import {
INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory,
} from '../constants';
import { getK8sEmptyState } from '../K8sEmptyState';
import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer';
import { usePageSize } from '../utils';
@@ -326,6 +327,9 @@ function K8sNodesList({
const nodesData = useMemo(() => data?.payload?.data?.records || [], [data]);
const totalCount = data?.payload?.data?.total || 0;
const sentAnyMetricsData = data?.payload?.data?.sentAnyMetricsData ?? false;
const endTimeBeforeRetention =
data?.payload?.data?.endTimeBeforeRetention ?? false;
const formattedNodesData = useMemo(
() => formatDataForTable(nodesData, groupBy),
@@ -643,6 +647,18 @@ function K8sNodesList({
const showTableLoadingState =
(isFetching || isLoading) && formattedNodesData.length === 0;
const emptyState = getK8sEmptyState({
sentAnyMetricsData,
endTimeBeforeRetention,
entityName: 'node',
isLoading,
isFetching,
hasRecords: formattedNodesData.length > 0,
hasFilters: queryFilters?.items?.length > 0,
isError,
errorMessage: data?.error ?? '',
});
return (
<div className="k8s-list">
<K8sHeader
@@ -657,54 +673,42 @@ function K8sNodesList({
entity={K8sCategory.NODES}
showAutoRefresh={!selectedNodeData}
/>
{isError && <Typography>{data?.error || 'Something went wrong'}</Typography>}
<Table
className="k8s-list-table nodes-list-table"
dataSource={showTableLoadingState ? [] : formattedNodesData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: showTableLoadingState ? null : (
<div className="no-filtered-hosts-message-container">
<div className="no-filtered-hosts-message-content">
<img
src="/Icons/emptyState.svg"
alt="thinking-emoji"
className="empty-state-svg"
/>
<Typography.Text className="no-filtered-hosts-message">
This query had no results. Edit your query and try again!
</Typography.Text>
</div>
</div>
),
}}
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,
}}
/>
{emptyState ? (
<>{emptyState}</>
) : (
<Table
className="k8s-list-table nodes-list-table"
dataSource={showTableLoadingState ? [] : formattedNodesData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: null,
}}
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,
}}
/>
)}
<NodeDetails
node={selectedNodeData}

View File

@@ -35,6 +35,7 @@ import {
INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory,
} from '../constants';
import { getK8sEmptyState } from '../K8sEmptyState';
import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer';
import {
@@ -335,6 +336,9 @@ function K8sPodsList({
const podsData = useMemo(() => data?.payload?.data?.records || [], [data]);
const totalCount = data?.payload?.data?.total || 0;
const sentAnyMetricsData = data?.payload?.data?.sentAnyMetricsData ?? false;
const endTimeBeforeRetention =
data?.payload?.data?.endTimeBeforeRetention ?? false;
const nestedPodsData = useMemo(() => {
if (!selectedRowData || !groupedByRowData?.payload?.data.records) {
@@ -694,6 +698,18 @@ function K8sPodsList({
const showTableLoadingState =
(isFetching || isLoading) && formattedPodsData.length === 0;
const emptyState = getK8sEmptyState({
sentAnyMetricsData,
endTimeBeforeRetention,
entityName: 'pod',
isLoading,
isFetching,
hasRecords: formattedPodsData.length > 0,
hasFilters: queryFilters?.items?.length > 0,
isError,
errorMessage: data?.error ?? '',
});
return (
<div className="k8s-list">
<K8sHeader
@@ -712,56 +728,44 @@ function K8sPodsList({
entity={K8sCategory.PODS}
showAutoRefresh={!selectedPodData}
/>
{isError && <Typography>{data?.error || 'Something went wrong'}</Typography>}
<Table
className={classNames('k8s-list-table', {
'expanded-k8s-list-table': isGroupedByAttribute,
})}
dataSource={showTableLoadingState ? [] : formattedPodsData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: showTableLoadingState ? null : (
<div className="no-filtered-hosts-message-container">
<div className="no-filtered-hosts-message-content">
<img
src="/Icons/emptyState.svg"
alt="thinking-emoji"
className="empty-state-svg"
/>
<Typography.Text className="no-filtered-hosts-message">
This query had no results. Edit your query and try again!
</Typography.Text>
</div>
</div>
),
}}
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,
}}
/>
{emptyState ? (
<>{emptyState}</>
) : (
<Table
className={classNames('k8s-list-table', {
'expanded-k8s-list-table': isGroupedByAttribute,
})}
dataSource={showTableLoadingState ? [] : formattedPodsData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: null,
}}
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 && (
<PodDetails

View File

@@ -34,6 +34,7 @@ import {
INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory,
} from '../constants';
import { getK8sEmptyState } from '../K8sEmptyState';
import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer';
import { usePageSize } from '../utils';
@@ -335,6 +336,9 @@ function K8sStatefulSetsList({
data,
]);
const totalCount = data?.payload?.data?.total || 0;
const sentAnyMetricsData = data?.payload?.data?.sentAnyMetricsData ?? false;
const endTimeBeforeRetention =
data?.payload?.data?.endTimeBeforeRetention ?? false;
const formattedStatefulSetsData = useMemo(
() => formatDataForTable(statefulSetsData, groupBy),
@@ -664,6 +668,18 @@ function K8sStatefulSetsList({
const showTableLoadingState =
(isFetching || isLoading) && formattedStatefulSetsData.length === 0;
const emptyState = getK8sEmptyState({
sentAnyMetricsData,
endTimeBeforeRetention,
entityName: 'stateful set',
isLoading,
isFetching,
hasRecords: formattedStatefulSetsData.length > 0,
hasFilters: queryFilters?.items?.length > 0,
isError,
errorMessage: data?.error ?? '',
});
return (
<div className="k8s-list">
<K8sHeader
@@ -678,56 +694,44 @@ function K8sStatefulSetsList({
entity={K8sCategory.STATEFULSETS}
showAutoRefresh={!selectedStatefulSetData}
/>
{isError && <Typography>{data?.error || 'Something went wrong'}</Typography>}
{emptyState}
<Table
className={classNames('k8s-list-table', 'statefulSets-list-table', {
'expanded-statefulsets-list-table': isGroupedByAttribute,
})}
dataSource={showTableLoadingState ? [] : formattedStatefulSetsData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: showTableLoadingState ? null : (
<div className="no-filtered-hosts-message-container">
<div className="no-filtered-hosts-message-content">
<img
src="/Icons/emptyState.svg"
alt="thinking-emoji"
className="empty-state-svg"
/>
<Typography.Text className="no-filtered-hosts-message">
This query had no results. Edit your query and try again!
</Typography.Text>
</div>
</div>
),
}}
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,
}}
/>
{!emptyState && (
<Table
className={classNames('k8s-list-table', 'statefulSets-list-table', {
'expanded-statefulsets-list-table': isGroupedByAttribute,
})}
dataSource={showTableLoadingState ? [] : formattedStatefulSetsData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: null,
}}
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,
}}
/>
)}
<StatefulSetDetails
statefulSet={selectedStatefulSetData}

View File

@@ -34,6 +34,7 @@ import {
INFRA_MONITORING_K8S_PARAMS_KEYS,
K8sCategory,
} from '../constants';
import { getK8sEmptyState } from '../K8sEmptyState';
import K8sHeader from '../K8sHeader';
import LoadingContainer from '../LoadingContainer';
import { usePageSize } from '../utils';
@@ -274,6 +275,9 @@ function K8sVolumesList({
const volumesData = useMemo(() => data?.payload?.data?.records || [], [data]);
const totalCount = data?.payload?.data?.total || 0;
const sentAnyMetricsData = data?.payload?.data?.sentAnyMetricsData ?? false;
const endTimeBeforeRetention =
data?.payload?.data?.endTimeBeforeRetention ?? false;
const formattedVolumesData = useMemo(
() => formatDataForTable(volumesData, groupBy),
@@ -587,6 +591,18 @@ function K8sVolumesList({
const showTableLoadingState =
(isFetching || isLoading) && formattedVolumesData.length === 0;
const emptyState = getK8sEmptyState({
sentAnyMetricsData,
endTimeBeforeRetention,
entityName: 'volume',
isLoading,
isFetching,
hasRecords: formattedVolumesData.length > 0,
hasFilters: queryFilters?.items?.length > 0,
isError,
errorMessage: data?.error ?? '',
});
return (
<div className="k8s-list">
<K8sHeader
@@ -601,56 +617,44 @@ function K8sVolumesList({
entity={K8sCategory.NODES}
showAutoRefresh={!selectedVolumeData}
/>
{isError && <Typography>{data?.error || 'Something went wrong'}</Typography>}
{emptyState}
<Table
className={classNames('k8s-list-table', 'volumes-list-table', {
'expanded-volumes-list-table': isGroupedByAttribute,
})}
dataSource={showTableLoadingState ? [] : formattedVolumesData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: showTableLoadingState ? null : (
<div className="no-filtered-hosts-message-container">
<div className="no-filtered-hosts-message-content">
<img
src="/Icons/emptyState.svg"
alt="thinking-emoji"
className="empty-state-svg"
/>
<Typography.Text className="no-filtered-hosts-message">
This query had no results. Edit your query and try again!
</Typography.Text>
</div>
</div>
),
}}
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,
}}
/>
{!emptyState && (
<Table
className={classNames('k8s-list-table', 'volumes-list-table', {
'expanded-volumes-list-table': isGroupedByAttribute,
})}
dataSource={showTableLoadingState ? [] : formattedVolumesData}
columns={columns}
pagination={{
current: currentPage,
pageSize,
total: totalCount,
showSizeChanger: true,
hideOnSinglePage: false,
onChange: onPaginationChange,
}}
scroll={{ x: true }}
loading={{
spinning: showTableLoadingState,
indicator: <Spin indicator={<LoadingOutlined size={14} spin />} />,
}}
locale={{
emptyText: null,
}}
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,
}}
/>
)}
<VolumeDetails
volume={selectedVolumeData}

View File

@@ -202,6 +202,14 @@ func (p *ClustersRepo) getTopClusterGroups(ctx context.Context, orgID valuer.UUI
return topClusterGroups, allClusterGroups, nil
}
func (p *ClustersRepo) GetMetricsExistenceAndEarliestTime(ctx context.Context) (uint64, uint64, error) {
names := []string{}
for _, metricName := range metricNamesForNodes {
names = append(names, metricName)
}
return p.reader.GetMetricsExistenceAndEarliestTime(ctx, names)
}
func (p *ClustersRepo) GetClusterList(ctx context.Context, orgID valuer.UUID, req model.ClusterListRequest) (model.ClusterListResponse, error) {
resp := model.ClusterListResponse{}
@@ -220,6 +228,22 @@ func (p *ClustersRepo) GetClusterList(ctx context.Context, orgID valuer.UUID, re
resp.Type = model.ResponseTypeGroupedList
}
if count, minFirstReportedUnixMilli, err := p.GetMetricsExistenceAndEarliestTime(ctx); err == nil {
if count == 0 {
resp.SentAnyMetricsData = false
resp.Records = []model.ClusterListRecord{}
resp.Total = 0
return resp, nil
}
resp.SentAnyMetricsData = true
if req.End < int64(minFirstReportedUnixMilli) {
resp.EndTimeBeforeRetention = true
resp.Records = []model.ClusterListRecord{}
resp.Total = 0
return resp, nil
}
}
step := int64(math.Max(float64(common.MinAllowedStepInterval(req.Start, req.End)), 60))
query := NodesTableListQuery.Clone()

View File

@@ -269,6 +269,17 @@ func (d *DaemonSetsRepo) getTopDaemonSetGroups(ctx context.Context, orgID valuer
return topDaemonSetGroups, allDaemonSetGroups, nil
}
func (d *DaemonSetsRepo) GetMetricsExistenceAndEarliestTime(ctx context.Context) (uint64, uint64, error) {
names := []string{}
for _, metricName := range metricNamesForWorkloads {
names = append(names, metricName)
}
for _, metricName := range metricNamesForDaemonSets {
names = append(names, metricName)
}
return d.reader.GetMetricsExistenceAndEarliestTime(ctx, names)
}
func (d *DaemonSetsRepo) GetDaemonSetList(ctx context.Context, orgID valuer.UUID, req model.DaemonSetListRequest) (model.DaemonSetListResponse, error) {
resp := model.DaemonSetListResponse{}
@@ -287,6 +298,22 @@ func (d *DaemonSetsRepo) GetDaemonSetList(ctx context.Context, orgID valuer.UUID
resp.Type = model.ResponseTypeGroupedList
}
if count, minFirstReportedUnixMilli, err := d.GetMetricsExistenceAndEarliestTime(ctx); err == nil {
if count == 0 {
resp.SentAnyMetricsData = false
resp.Records = []model.DaemonSetListRecord{}
resp.Total = 0
return resp, nil
}
resp.SentAnyMetricsData = true
if req.End < int64(minFirstReportedUnixMilli) {
resp.EndTimeBeforeRetention = true
resp.Records = []model.DaemonSetListRecord{}
resp.Total = 0
return resp, nil
}
}
step := int64(math.Max(float64(common.MinAllowedStepInterval(req.Start, req.End)), 60))
query := WorkloadTableListQuery.Clone()

View File

@@ -269,6 +269,17 @@ func (d *DeploymentsRepo) getTopDeploymentGroups(ctx context.Context, orgID valu
return topDeploymentGroups, allDeploymentGroups, nil
}
func (d *DeploymentsRepo) GetMetricsExistenceAndEarliestTime(ctx context.Context) (uint64, uint64, error) {
names := []string{}
for _, metricName := range metricNamesForWorkloads {
names = append(names, metricName)
}
for _, metricName := range metricNamesForDeployments {
names = append(names, metricName)
}
return d.reader.GetMetricsExistenceAndEarliestTime(ctx, names)
}
func (d *DeploymentsRepo) GetDeploymentList(ctx context.Context, orgID valuer.UUID, req model.DeploymentListRequest) (model.DeploymentListResponse, error) {
resp := model.DeploymentListResponse{}
@@ -287,6 +298,22 @@ func (d *DeploymentsRepo) GetDeploymentList(ctx context.Context, orgID valuer.UU
resp.Type = model.ResponseTypeGroupedList
}
if count, minFirstReportedUnixMilli, err := d.GetMetricsExistenceAndEarliestTime(ctx); err == nil {
if count == 0 {
resp.SentAnyMetricsData = false
resp.Records = []model.DeploymentListRecord{}
resp.Total = 0
return resp, nil
}
resp.SentAnyMetricsData = true
if req.End < int64(minFirstReportedUnixMilli) {
resp.EndTimeBeforeRetention = true
resp.Records = []model.DeploymentListRecord{}
resp.Total = 0
return resp, nil
}
}
step := int64(math.Max(float64(common.MinAllowedStepInterval(req.Start, req.End)), 60))
query := WorkloadTableListQuery.Clone()

View File

@@ -313,6 +313,17 @@ func (d *JobsRepo) getTopJobGroups(ctx context.Context, orgID valuer.UUID, req m
return topJobGroups, allJobGroups, nil
}
func (d *JobsRepo) GetMetricsExistenceAndEarliestTime(ctx context.Context) (uint64, uint64, error) {
names := []string{}
for _, metricName := range metricNamesForWorkloads {
names = append(names, metricName)
}
for _, metricName := range metricNamesForJobs {
names = append(names, metricName)
}
return d.reader.GetMetricsExistenceAndEarliestTime(ctx, names)
}
func (d *JobsRepo) GetJobList(ctx context.Context, orgID valuer.UUID, req model.JobListRequest) (model.JobListResponse, error) {
resp := model.JobListResponse{}
@@ -331,6 +342,22 @@ func (d *JobsRepo) GetJobList(ctx context.Context, orgID valuer.UUID, req model.
resp.Type = model.ResponseTypeGroupedList
}
if count, minFirstReportedUnixMilli, err := d.GetMetricsExistenceAndEarliestTime(ctx); err == nil {
if count == 0 {
resp.SentAnyMetricsData = false
resp.Records = []model.JobListRecord{}
resp.Total = 0
return resp, nil
}
resp.SentAnyMetricsData = true
if req.End < int64(minFirstReportedUnixMilli) {
resp.EndTimeBeforeRetention = true
resp.Records = []model.JobListRecord{}
resp.Total = 0
return resp, nil
}
}
step := int64(math.Max(float64(common.MinAllowedStepInterval(req.Start, req.End)), 60))
query := WorkloadTableListQuery.Clone()

View File

@@ -196,6 +196,14 @@ func (p *NamespacesRepo) getTopNamespaceGroups(ctx context.Context, orgID valuer
return topNamespaceGroups, allNamespaceGroups, nil
}
func (p *NamespacesRepo) GetMetricsExistenceAndEarliestTime(ctx context.Context) (uint64, uint64, error) {
names := []string{}
for _, metricName := range metricNamesForPods {
names = append(names, metricName)
}
return p.reader.GetMetricsExistenceAndEarliestTime(ctx, names)
}
func (p *NamespacesRepo) GetNamespaceList(ctx context.Context, orgID valuer.UUID, req model.NamespaceListRequest) (model.NamespaceListResponse, error) {
resp := model.NamespaceListResponse{}
@@ -214,6 +222,22 @@ func (p *NamespacesRepo) GetNamespaceList(ctx context.Context, orgID valuer.UUID
resp.Type = model.ResponseTypeGroupedList
}
if count, minFirstReportedUnixMilli, err := p.GetMetricsExistenceAndEarliestTime(ctx); err == nil {
if count == 0 {
resp.SentAnyMetricsData = false
resp.Records = []model.NamespaceListRecord{}
resp.Total = 0
return resp, nil
}
resp.SentAnyMetricsData = true
if req.End < int64(minFirstReportedUnixMilli) {
resp.EndTimeBeforeRetention = true
resp.Records = []model.NamespaceListRecord{}
resp.Total = 0
return resp, nil
}
}
step := int64(math.Max(float64(common.MinAllowedStepInterval(req.Start, req.End)), 60))
query := PodsTableListQuery.Clone()

View File

@@ -226,6 +226,14 @@ func (p *NodesRepo) getTopNodeGroups(ctx context.Context, orgID valuer.UUID, req
return topNodeGroups, allNodeGroups, nil
}
func (p *NodesRepo) GetMetricsExistenceAndEarliestTime(ctx context.Context) (uint64, uint64, error) {
names := []string{}
for _, metricName := range metricNamesForNodes {
names = append(names, metricName)
}
return p.reader.GetMetricsExistenceAndEarliestTime(ctx, names)
}
func (p *NodesRepo) GetNodeList(ctx context.Context, orgID valuer.UUID, req model.NodeListRequest) (model.NodeListResponse, error) {
resp := model.NodeListResponse{}
@@ -244,6 +252,22 @@ func (p *NodesRepo) GetNodeList(ctx context.Context, orgID valuer.UUID, req mode
resp.Type = model.ResponseTypeGroupedList
}
if count, minFirstReportedUnixMilli, err := p.GetMetricsExistenceAndEarliestTime(ctx); err == nil {
if count == 0 {
resp.SentAnyMetricsData = false
resp.Records = []model.NodeListRecord{}
resp.Total = 0
return resp, nil
}
resp.SentAnyMetricsData = true
if req.End < int64(minFirstReportedUnixMilli) {
resp.EndTimeBeforeRetention = true
resp.Records = []model.NodeListRecord{}
resp.Total = 0
return resp, nil
}
}
step := int64(math.Max(float64(common.MinAllowedStepInterval(req.Start, req.End)), 60))
query := NodesTableListQuery.Clone()

View File

@@ -371,6 +371,14 @@ func (p *PodsRepo) getTopPodGroups(ctx context.Context, orgID valuer.UUID, req m
return topPodGroups, allPodGroups, nil
}
func (p *PodsRepo) GetMetricsExistenceAndEarliestTime(ctx context.Context) (uint64, uint64, error) {
names := []string{}
for _, metricName := range metricNamesForPods {
names = append(names, metricName)
}
return p.reader.GetMetricsExistenceAndEarliestTime(ctx, names)
}
func (p *PodsRepo) GetPodList(ctx context.Context, orgID valuer.UUID, req model.PodListRequest) (model.PodListResponse, error) {
resp := model.PodListResponse{}
@@ -389,6 +397,22 @@ func (p *PodsRepo) GetPodList(ctx context.Context, orgID valuer.UUID, req model.
resp.Type = model.ResponseTypeGroupedList
}
if count, minFirstReportedUnixMilli, err := p.GetMetricsExistenceAndEarliestTime(ctx); err == nil {
if count == 0 {
resp.SentAnyMetricsData = false
resp.Records = []model.PodListRecord{}
resp.Total = 0
return resp, nil
}
resp.SentAnyMetricsData = true
if req.End < int64(minFirstReportedUnixMilli) {
resp.EndTimeBeforeRetention = true
resp.Records = []model.PodListRecord{}
resp.Total = 0
return resp, nil
}
}
step := int64(math.Max(float64(common.MinAllowedStepInterval(req.Start, req.End)), 60))
query := PodsTableListQuery.Clone()

View File

@@ -210,6 +210,14 @@ func (p *ProcessesRepo) getTopProcessGroups(ctx context.Context, orgID valuer.UU
return topProcessGroups, allProcessGroups, nil
}
func (p *ProcessesRepo) GetMetricsExistenceAndEarliestTime(ctx context.Context) (uint64, uint64, error) {
names := []string{}
for _, metricName := range metricNamesForProcesses {
names = append(names, metricName)
}
return p.reader.GetMetricsExistenceAndEarliestTime(ctx, names)
}
func (p *ProcessesRepo) GetProcessList(ctx context.Context, orgID valuer.UUID, req model.ProcessListRequest) (model.ProcessListResponse, error) {
resp := model.ProcessListResponse{}
if req.Limit == 0 {
@@ -229,6 +237,22 @@ func (p *ProcessesRepo) GetProcessList(ctx context.Context, orgID valuer.UUID, r
resp.Type = model.ResponseTypeGroupedList
}
if count, minFirstReportedUnixMilli, err := p.GetMetricsExistenceAndEarliestTime(ctx); err == nil {
if count == 0 {
resp.SentAnyMetricsData = false
resp.Records = []model.ProcessListRecord{}
resp.Total = 0
return resp, nil
}
resp.SentAnyMetricsData = true
if req.End < int64(minFirstReportedUnixMilli) {
resp.EndTimeBeforeRetention = true
resp.Records = []model.ProcessListRecord{}
resp.Total = 0
return resp, nil
}
}
step := int64(math.Max(float64(common.MinAllowedStepInterval(req.Start, req.End)), 60))
query := ProcessesTableListQuery.Clone()

View File

@@ -229,6 +229,14 @@ func (p *PvcsRepo) getTopVolumeGroups(ctx context.Context, orgID valuer.UUID, re
return topVolumeGroups, allVolumeGroups, nil
}
func (p *PvcsRepo) GetMetricsExistenceAndEarliestTime(ctx context.Context) (uint64, uint64, error) {
names := []string{}
for _, metricName := range metricNamesForVolumes {
names = append(names, metricName)
}
return p.reader.GetMetricsExistenceAndEarliestTime(ctx, names)
}
func (p *PvcsRepo) GetPvcList(ctx context.Context, orgID valuer.UUID, req model.VolumeListRequest) (model.VolumeListResponse, error) {
resp := model.VolumeListResponse{}
@@ -247,6 +255,22 @@ func (p *PvcsRepo) GetPvcList(ctx context.Context, orgID valuer.UUID, req model.
resp.Type = model.ResponseTypeGroupedList
}
if count, minFirstReportedUnixMilli, err := p.GetMetricsExistenceAndEarliestTime(ctx); err == nil {
if count == 0 {
resp.SentAnyMetricsData = false
resp.Records = []model.VolumeListRecord{}
resp.Total = 0
return resp, nil
}
resp.SentAnyMetricsData = true
if req.End < int64(minFirstReportedUnixMilli) {
resp.EndTimeBeforeRetention = true
resp.Records = []model.VolumeListRecord{}
resp.Total = 0
return resp, nil
}
}
step := int64(math.Max(float64(common.MinAllowedStepInterval(req.Start, req.End)), 60))
query := PvcsTableListQuery.Clone()

View File

@@ -269,6 +269,17 @@ func (d *StatefulSetsRepo) getTopStatefulSetGroups(ctx context.Context, orgID va
return topStatefulSetGroups, allStatefulSetGroups, nil
}
func (d *StatefulSetsRepo) GetMetricsExistenceAndEarliestTime(ctx context.Context) (uint64, uint64, error) {
names := []string{}
for _, metricName := range metricNamesForWorkloads {
names = append(names, metricName)
}
for _, metricName := range metricNamesForStatefulSets {
names = append(names, metricName)
}
return d.reader.GetMetricsExistenceAndEarliestTime(ctx, names)
}
func (d *StatefulSetsRepo) GetStatefulSetList(ctx context.Context, orgID valuer.UUID, req model.StatefulSetListRequest) (model.StatefulSetListResponse, error) {
resp := model.StatefulSetListResponse{}
@@ -287,6 +298,22 @@ func (d *StatefulSetsRepo) GetStatefulSetList(ctx context.Context, orgID valuer.
resp.Type = model.ResponseTypeGroupedList
}
if count, minFirstReportedUnixMilli, err := d.GetMetricsExistenceAndEarliestTime(ctx); err == nil {
if count == 0 {
resp.SentAnyMetricsData = false
resp.Records = []model.StatefulSetListRecord{}
resp.Total = 0
return resp, nil
}
resp.SentAnyMetricsData = true
if req.End < int64(minFirstReportedUnixMilli) {
resp.EndTimeBeforeRetention = true
resp.Records = []model.StatefulSetListRecord{}
resp.Total = 0
return resp, nil
}
}
step := int64(math.Max(float64(common.MinAllowedStepInterval(req.Start, req.End)), 60))
query := WorkloadTableListQuery.Clone()

View File

@@ -86,9 +86,11 @@ type ProcessListRequest struct {
}
type ProcessListResponse struct {
Type ResponseType `json:"type"`
Records []ProcessListRecord `json:"records"`
Total int `json:"total"`
Type ResponseType `json:"type"`
Records []ProcessListRecord `json:"records"`
Total int `json:"total"`
SentAnyMetricsData bool `json:"sentAnyMetricsData"`
EndTimeBeforeRetention bool `json:"endTimeBeforeRetention"`
}
type ProcessListRecord struct {
@@ -112,9 +114,11 @@ type PodListRequest struct {
}
type PodListResponse struct {
Type ResponseType `json:"type"`
Records []PodListRecord `json:"records"`
Total int `json:"total"`
Type ResponseType `json:"type"`
Records []PodListRecord `json:"records"`
Total int `json:"total"`
SentAnyMetricsData bool `json:"sentAnyMetricsData"`
EndTimeBeforeRetention bool `json:"endTimeBeforeRetention"`
}
func (r *PodListResponse) SortBy(orderBy *v3.OrderBy) {
@@ -190,9 +194,11 @@ type NodeListRequest struct {
}
type NodeListResponse struct {
Type ResponseType `json:"type"`
Records []NodeListRecord `json:"records"`
Total int `json:"total"`
Type ResponseType `json:"type"`
Records []NodeListRecord `json:"records"`
Total int `json:"total"`
SentAnyMetricsData bool `json:"sentAnyMetricsData"`
EndTimeBeforeRetention bool `json:"endTimeBeforeRetention"`
}
func (r *NodeListResponse) SortBy(orderBy *v3.OrderBy) {
@@ -251,9 +257,11 @@ type NamespaceListRequest struct {
}
type NamespaceListResponse struct {
Type ResponseType `json:"type"`
Records []NamespaceListRecord `json:"records"`
Total int `json:"total"`
Type ResponseType `json:"type"`
Records []NamespaceListRecord `json:"records"`
Total int `json:"total"`
SentAnyMetricsData bool `json:"sentAnyMetricsData"`
EndTimeBeforeRetention bool `json:"endTimeBeforeRetention"`
}
func (r *NamespaceListResponse) SortBy(orderBy *v3.OrderBy) {
@@ -300,9 +308,11 @@ type ClusterListRequest struct {
}
type ClusterListResponse struct {
Type ResponseType `json:"type"`
Records []ClusterListRecord `json:"records"`
Total int `json:"total"`
Type ResponseType `json:"type"`
Records []ClusterListRecord `json:"records"`
Total int `json:"total"`
SentAnyMetricsData bool `json:"sentAnyMetricsData"`
EndTimeBeforeRetention bool `json:"endTimeBeforeRetention"`
}
func (r *ClusterListResponse) SortBy(orderBy *v3.OrderBy) {
@@ -354,9 +364,11 @@ type DeploymentListRequest struct {
}
type DeploymentListResponse struct {
Type ResponseType `json:"type"`
Records []DeploymentListRecord `json:"records"`
Total int `json:"total"`
Type ResponseType `json:"type"`
Records []DeploymentListRecord `json:"records"`
Total int `json:"total"`
SentAnyMetricsData bool `json:"sentAnyMetricsData"`
EndTimeBeforeRetention bool `json:"endTimeBeforeRetention"`
}
func (r *DeploymentListResponse) SortBy(orderBy *v3.OrderBy) {
@@ -433,9 +445,11 @@ type DaemonSetListRequest struct {
}
type DaemonSetListResponse struct {
Type ResponseType `json:"type"`
Records []DaemonSetListRecord `json:"records"`
Total int `json:"total"`
Type ResponseType `json:"type"`
Records []DaemonSetListRecord `json:"records"`
Total int `json:"total"`
SentAnyMetricsData bool `json:"sentAnyMetricsData"`
EndTimeBeforeRetention bool `json:"endTimeBeforeRetention"`
}
func (r *DaemonSetListResponse) SortBy(orderBy *v3.OrderBy) {
@@ -512,9 +526,11 @@ type StatefulSetListRequest struct {
}
type StatefulSetListResponse struct {
Type ResponseType `json:"type"`
Records []StatefulSetListRecord `json:"records"`
Total int `json:"total"`
Type ResponseType `json:"type"`
Records []StatefulSetListRecord `json:"records"`
Total int `json:"total"`
SentAnyMetricsData bool `json:"sentAnyMetricsData"`
EndTimeBeforeRetention bool `json:"endTimeBeforeRetention"`
}
func (r *StatefulSetListResponse) SortBy(orderBy *v3.OrderBy) {
@@ -591,9 +607,11 @@ type JobListRequest struct {
}
type JobListResponse struct {
Type ResponseType `json:"type"`
Records []JobListRecord `json:"records"`
Total int `json:"total"`
Type ResponseType `json:"type"`
Records []JobListRecord `json:"records"`
Total int `json:"total"`
SentAnyMetricsData bool `json:"sentAnyMetricsData"`
EndTimeBeforeRetention bool `json:"endTimeBeforeRetention"`
}
func (r *JobListResponse) SortBy(orderBy *v3.OrderBy) {
@@ -680,9 +698,11 @@ type VolumeListRequest struct {
}
type VolumeListResponse struct {
Type ResponseType `json:"type"`
Records []VolumeListRecord `json:"records"`
Total int `json:"total"`
Type ResponseType `json:"type"`
Records []VolumeListRecord `json:"records"`
Total int `json:"total"`
SentAnyMetricsData bool `json:"sentAnyMetricsData"`
EndTimeBeforeRetention bool `json:"endTimeBeforeRetention"`
}
func (r *VolumeListResponse) SortBy(orderBy *v3.OrderBy) {