mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-08-12 07:08:58 +08:00
feat: improve empty hosts, incorrect metrics and no filter views (#6530)
* feat: improve empty hosts, incorrect metrics and no filter views * feat: add infra monitoring - host lists - usage events (#6536) * feat: add usasge events * feat: add reqrest early access events --------- Co-authored-by: Srikanth Chekuri <srikanth.chekuri92@gmail.com>
This commit is contained in:
parent
486632b64e
commit
2bfd31841e
@ -2,6 +2,7 @@
|
||||
"containers_visualization_message": "The ability to visualise containers is in active development and should be available to you soon.",
|
||||
"processes_visualization_message": "The ability to visualise processes is in active development and should be available to you soon.",
|
||||
"working_message": "We're working to extend infrastructure monitoring to take care of a bunch of different cases. Thank you for your patience.",
|
||||
"waitlist_message": "Join the waitlist for early access or contact support.",
|
||||
"waitlist_message": "Join the waitlist for early access.",
|
||||
"waitlist_success_message": "We have received your request for early access. We will get back to you as soon as we launch the feature.",
|
||||
"contact_support": "Contact Support"
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
"containers_visualization_message": "The ability to visualise containers is in active development and should be available to you soon.",
|
||||
"processes_visualization_message": "The ability to visualise processes is in active development and should be available to you soon.",
|
||||
"working_message": "We're working to extend infrastructure monitoring to take care of a bunch of different cases. Thank you for your patience.",
|
||||
"waitlist_message": "Join the waitlist for early access or contact support.",
|
||||
"waitlist_message": "Join the waitlist for early access.",
|
||||
"waitlist_success_message": "We have received your request for early access. We will get back to you as soon as we launch the feature.",
|
||||
"contact_support": "Contact Support"
|
||||
}
|
||||
|
@ -48,6 +48,8 @@ export interface HostListResponse {
|
||||
records: HostData[];
|
||||
groups: null;
|
||||
total: number;
|
||||
sentAnyHostMetricsData: boolean;
|
||||
isSendingK8SAgentMetrics: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1,7 +1,24 @@
|
||||
.host-containers {
|
||||
max-width: 600px;
|
||||
margin: 150px auto;
|
||||
padding: 0 16px;
|
||||
gap: 24px;
|
||||
height: 60vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
|
||||
.infra-container-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.dev-status-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.infra-container-card {
|
||||
display: flex;
|
||||
@ -17,6 +34,7 @@
|
||||
width: 400px;
|
||||
font-family: 'Inter';
|
||||
margin-top: 12px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.infra-container-working-msg {
|
||||
|
@ -3,6 +3,8 @@ import './Containers.styles.scss';
|
||||
import { Space, Typography } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import WaitlistFragment from '../WaitlistFragment/WaitlistFragment';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
function Containers(): JSX.Element {
|
||||
@ -10,24 +12,30 @@ function Containers(): JSX.Element {
|
||||
|
||||
return (
|
||||
<Space direction="vertical" className="host-containers" size={24}>
|
||||
<div className="infra-container-card">
|
||||
<img
|
||||
src="/Icons/infraContainers.svg"
|
||||
alt="infra-container"
|
||||
width={32}
|
||||
height={32}
|
||||
/>
|
||||
<div className="infra-container-card-container">
|
||||
<div className="dev-status-container">
|
||||
<div className="infra-container-card">
|
||||
<img
|
||||
src="/Icons/infraContainers.svg"
|
||||
alt="infra-container"
|
||||
width={32}
|
||||
height={32}
|
||||
/>
|
||||
|
||||
<Text className="infra-container-card-text">
|
||||
{t('containers_visualization_message')}
|
||||
</Text>
|
||||
</div>
|
||||
<Text className="infra-container-card-text">
|
||||
{t('containers_visualization_message')}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div className="infra-container-working-msg">
|
||||
<Space>
|
||||
<img src="/Icons/broom.svg" alt="broom" width={16} height={16} />
|
||||
<Text className="infra-container-card-text">{t('working_message')}</Text>
|
||||
</Space>
|
||||
<div className="infra-container-working-msg">
|
||||
<Space>
|
||||
<img src="/Icons/broom.svg" alt="broom" width={24} height={24} />
|
||||
<Text className="infra-container-card-text">{t('working_message')}</Text>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<WaitlistFragment entityType="containers" />
|
||||
</div>
|
||||
</Space>
|
||||
);
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { RadioChangeEvent } from 'antd/lib';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { QueryParams } from 'constants/query';
|
||||
import {
|
||||
initialQueryBuilderFormValuesMap,
|
||||
@ -118,6 +119,13 @@ function HostMetricsDetails({
|
||||
initialFilters,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
logEvent('Infra Monitoring: Hosts list details page visited', {
|
||||
host: host?.hostName,
|
||||
});
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
setLogFilters(initialFilters);
|
||||
setTracesFilters(initialFilters);
|
||||
@ -143,6 +151,7 @@ function HostMetricsDetails({
|
||||
const handleTimeChange = useCallback(
|
||||
(interval: Time | CustomTimeType, dateTimeRange?: [number, number]): void => {
|
||||
setSelectedInterval(interval as Time);
|
||||
|
||||
if (interval === 'custom' && dateTimeRange) {
|
||||
setModalTimeRange({
|
||||
startTime: Math.floor(dateTimeRange[0] / 1000),
|
||||
@ -156,7 +165,13 @@ function HostMetricsDetails({
|
||||
endTime: Math.floor(maxTime / 1000000000),
|
||||
});
|
||||
}
|
||||
|
||||
logEvent('Infra Monitoring: Hosts list details time updated', {
|
||||
host: host?.hostName,
|
||||
interval,
|
||||
});
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[],
|
||||
);
|
||||
|
||||
@ -171,6 +186,10 @@ function HostMetricsDetails({
|
||||
(item) => item.key?.key !== 'id' && item.key?.key !== 'host.name',
|
||||
);
|
||||
|
||||
logEvent('Infra Monitoring: Hosts list details logs filters applied', {
|
||||
host: host?.hostName,
|
||||
});
|
||||
|
||||
return {
|
||||
op: 'AND',
|
||||
items: [
|
||||
@ -181,6 +200,7 @@ function HostMetricsDetails({
|
||||
};
|
||||
});
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[],
|
||||
);
|
||||
|
||||
@ -190,6 +210,11 @@ function HostMetricsDetails({
|
||||
const hostNameFilter = prevFilters.items.find(
|
||||
(item) => item.key?.key === 'host.name',
|
||||
);
|
||||
|
||||
logEvent('Infra Monitoring: Hosts list details traces filters applied', {
|
||||
host: host?.hostName,
|
||||
});
|
||||
|
||||
return {
|
||||
op: 'AND',
|
||||
items: [
|
||||
@ -199,6 +224,7 @@ function HostMetricsDetails({
|
||||
};
|
||||
});
|
||||
},
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
[],
|
||||
);
|
||||
|
||||
@ -211,6 +237,11 @@ function HostMetricsDetails({
|
||||
urlQuery.set(QueryParams.endTime, modalTimeRange.endTime.toString());
|
||||
}
|
||||
|
||||
logEvent('Infra Monitoring: Hosts list details explore clicked', {
|
||||
host: host?.hostName,
|
||||
view: selectedView,
|
||||
});
|
||||
|
||||
if (selectedView === VIEW_TYPES.LOGS) {
|
||||
const filtersWithoutPagination = {
|
||||
...logFilters,
|
||||
|
@ -1,7 +1,24 @@
|
||||
.host-processes {
|
||||
max-width: 600px;
|
||||
margin: 150px auto;
|
||||
padding: 0 16px;
|
||||
gap: 24px;
|
||||
height: 60vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
margin: 0 auto;
|
||||
box-sizing: border-box;
|
||||
|
||||
.infra-container-card-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 24px;
|
||||
}
|
||||
|
||||
.dev-status-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.infra-container-card {
|
||||
display: flex;
|
||||
@ -17,6 +34,7 @@
|
||||
width: 400px;
|
||||
font-family: 'Inter';
|
||||
margin-top: 12px;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.infra-container-working-msg {
|
||||
|
@ -3,6 +3,8 @@ import './Processes.styles.scss';
|
||||
import { Space, Typography } from 'antd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import WaitlistFragment from '../WaitlistFragment/WaitlistFragment';
|
||||
|
||||
const { Text } = Typography;
|
||||
|
||||
function Processes(): JSX.Element {
|
||||
@ -10,23 +12,29 @@ function Processes(): JSX.Element {
|
||||
|
||||
return (
|
||||
<Space direction="vertical" className="host-processes" size={24}>
|
||||
<div className="infra-container-card">
|
||||
<img
|
||||
src="/Icons/infraContainers.svg"
|
||||
alt="infra-container"
|
||||
width={32}
|
||||
height={32}
|
||||
/>
|
||||
<Text className="infra-container-card-text">
|
||||
{t('processes_visualization_message')}
|
||||
</Text>
|
||||
</div>
|
||||
<div className="infra-container-card-container">
|
||||
<div className="dev-status-container">
|
||||
<div className="infra-container-card">
|
||||
<img
|
||||
src="/Icons/infraContainers.svg"
|
||||
alt="infra-container"
|
||||
width={32}
|
||||
height={32}
|
||||
/>
|
||||
<Text className="infra-container-card-text">
|
||||
{t('processes_visualization_message')}
|
||||
</Text>
|
||||
</div>
|
||||
|
||||
<div className="infra-container-working-msg">
|
||||
<Space>
|
||||
<img src="/Icons/broom.svg" alt="broom" width={16} height={16} />
|
||||
<Text className="infra-container-card-text">{t('working_message')}</Text>
|
||||
</Space>
|
||||
<div className="infra-container-working-msg">
|
||||
<Space>
|
||||
<img src="/Icons/broom.svg" alt="broom" width={24} height={24} />
|
||||
<Text className="infra-container-card-text">{t('working_message')}</Text>
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<WaitlistFragment entityType="processes" />
|
||||
</div>
|
||||
</Space>
|
||||
);
|
||||
|
@ -0,0 +1,15 @@
|
||||
.wait-list-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
|
||||
.wait-list-text {
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.join-waitlist-btn {
|
||||
width: 160px;
|
||||
border-radius: 2px;
|
||||
background: var(--slate-500);
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
import './WaitListFragment.styles.scss';
|
||||
|
||||
import { Color } from '@signozhq/design-tokens';
|
||||
import { Button, Typography } from 'antd';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { useNotifications } from 'hooks/useNotifications';
|
||||
import { CheckCircle2, HandPlatter } from 'lucide-react';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import AppReducer from 'types/reducer/app';
|
||||
|
||||
export default function WaitlistFragment({
|
||||
entityType,
|
||||
}: {
|
||||
entityType: string;
|
||||
}): JSX.Element {
|
||||
const { user } = useSelector<AppState, AppReducer>((state) => state.app);
|
||||
const { t } = useTranslation(['infraMonitoring']);
|
||||
const { notifications } = useNotifications();
|
||||
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [isSuccess, setIsSuccess] = useState(false);
|
||||
|
||||
const handleJoinWaitlist = (): void => {
|
||||
if (!user || !user.email) return;
|
||||
|
||||
setIsSubmitting(true);
|
||||
|
||||
logEvent('Infra Monitoring: Get Early Access Clicked', {
|
||||
entity_type: entityType,
|
||||
userEmail: user.email,
|
||||
})
|
||||
.then(() => {
|
||||
notifications.success({
|
||||
message: t('waitlist_success_message'),
|
||||
});
|
||||
|
||||
setIsSubmitting(false);
|
||||
setIsSuccess(true);
|
||||
|
||||
setTimeout(() => {
|
||||
setIsSuccess(false);
|
||||
}, 4000);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error logging event:', error);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="wait-list-container">
|
||||
<Typography.Text className="wait-list-text">
|
||||
{t('waitlist_message')}
|
||||
</Typography.Text>
|
||||
|
||||
<Button
|
||||
className="periscope-btn join-waitlist-btn"
|
||||
type="default"
|
||||
loading={isSubmitting}
|
||||
icon={
|
||||
isSuccess ? (
|
||||
<CheckCircle2 size={16} color={Color.BG_FOREST_500} />
|
||||
) : (
|
||||
<HandPlatter size={16} />
|
||||
)
|
||||
}
|
||||
onClick={handleJoinWaitlist}
|
||||
>
|
||||
Get early access
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
import { Typography } from 'antd';
|
||||
|
||||
export default function HostsEmptyOrIncorrectMetrics({
|
||||
noData,
|
||||
incorrectData,
|
||||
}: {
|
||||
noData: boolean;
|
||||
incorrectData: boolean;
|
||||
}): JSX.Element {
|
||||
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" />
|
||||
|
||||
{noData && (
|
||||
<div className="no-hosts-message">
|
||||
<Typography.Title level={5} className="no-hosts-message-title">
|
||||
No host metrics data received yet.
|
||||
</Typography.Title>
|
||||
|
||||
<Typography.Text className="no-hosts-message-text">
|
||||
Infrastructure monitoring requires the{' '}
|
||||
<a
|
||||
href="https://github.com/open-telemetry/semantic-conventions/blob/main/docs/system/system-metrics.md"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
OpenTelemetry system metrics
|
||||
</a>
|
||||
. Please refer to{' '}
|
||||
<a
|
||||
href="https://signoz.io/docs/userguide/hostmetrics"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
this
|
||||
</a>{' '}
|
||||
to learn how to send host metrics to SigNoz.
|
||||
</Typography.Text>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{incorrectData && (
|
||||
<Typography.Text className="incorrect-metrics-message">
|
||||
To see host metrics, upgrade to the latest version of SigNoz k8s-infra
|
||||
chart. Please contact support if you need help.
|
||||
</Typography.Text>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -2,6 +2,7 @@ import './InfraMonitoring.styles.scss';
|
||||
|
||||
import { LoadingOutlined } from '@ant-design/icons';
|
||||
import {
|
||||
Skeleton,
|
||||
Spin,
|
||||
Table,
|
||||
TablePaginationConfig,
|
||||
@ -9,17 +10,17 @@ import {
|
||||
Typography,
|
||||
} from 'antd';
|
||||
import { SorterResult } from 'antd/es/table/interface';
|
||||
import logEvent from 'api/common/logEvent';
|
||||
import { HostListPayload } from 'api/infraMonitoring/getHostLists';
|
||||
import HostMetricDetail from 'components/HostMetricsDetail';
|
||||
import NoLogs from 'container/NoLogs/NoLogs';
|
||||
import { useGetHostList } from 'hooks/infraMonitoring/useGetHostList';
|
||||
import { useCallback, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { AppState } from 'store/reducers';
|
||||
import { IBuilderQuery } from 'types/api/queryBuilder/queryBuilderData';
|
||||
import { DataSource } from 'types/common/queryBuilder';
|
||||
import { GlobalReducer } from 'types/reducer/globalTime';
|
||||
|
||||
import HostsEmptyOrIncorrectMetrics from './HostsEmptyOrIncorrectMetrics';
|
||||
import HostsListControls from './HostsListControls';
|
||||
import {
|
||||
formatDataForTable,
|
||||
@ -28,6 +29,7 @@ import {
|
||||
HostRowData,
|
||||
} from './utils';
|
||||
|
||||
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||
function HostsList(): JSX.Element {
|
||||
const { maxTime, minTime } = useSelector<AppState, GlobalReducer>(
|
||||
(state) => state.globalTime,
|
||||
@ -69,6 +71,16 @@ function HostsList(): JSX.Element {
|
||||
},
|
||||
);
|
||||
|
||||
const sentAnyHostMetricsData = useMemo(
|
||||
() => data?.payload?.data?.sentAnyHostMetricsData || false,
|
||||
[data],
|
||||
);
|
||||
|
||||
const isSendingIncorrectK8SAgentMetrics = useMemo(
|
||||
() => data?.payload?.data?.isSendingK8SAgentMetrics || false,
|
||||
[data],
|
||||
);
|
||||
|
||||
const hostMetricsData = useMemo(() => data?.payload?.data?.records || [], [
|
||||
data,
|
||||
]);
|
||||
@ -81,9 +93,6 @@ function HostsList(): JSX.Element {
|
||||
|
||||
const columns = useMemo(() => getHostsListColumns(), []);
|
||||
|
||||
const isDataPresent =
|
||||
!isLoading && !isFetching && !isError && hostMetricsData.length === 0;
|
||||
|
||||
const handleTableChange: TableProps<HostRowData>['onChange'] = useCallback(
|
||||
(
|
||||
pagination: TablePaginationConfig,
|
||||
@ -112,11 +121,19 @@ function HostsList(): JSX.Element {
|
||||
if (isNewFilterAdded) {
|
||||
setFilters(value);
|
||||
setCurrentPage(1);
|
||||
|
||||
logEvent('Infra Monitoring: Hosts list filters applied', {
|
||||
filters: value,
|
||||
});
|
||||
}
|
||||
},
|
||||
[filters],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
logEvent('Infra Monitoring: Hosts list page visited', {});
|
||||
}, []);
|
||||
|
||||
const selectedHostData = useMemo(() => {
|
||||
if (!selectedHostName) return null;
|
||||
return (
|
||||
@ -126,29 +143,85 @@ function HostsList(): JSX.Element {
|
||||
|
||||
const handleRowClick = (record: HostRowData): void => {
|
||||
setSelectedHostName(record.hostName);
|
||||
|
||||
logEvent('Infra Monitoring: Hosts list item clicked', {
|
||||
host: record.hostName,
|
||||
});
|
||||
};
|
||||
|
||||
const handleCloseHostDetail = (): void => {
|
||||
setSelectedHostName(null);
|
||||
};
|
||||
|
||||
const showHostsTable =
|
||||
!isError &&
|
||||
sentAnyHostMetricsData &&
|
||||
!isSendingIncorrectK8SAgentMetrics &&
|
||||
!(formattedHostMetricsData.length === 0 && filters.items.length > 0);
|
||||
|
||||
const showNoFilteredHostsMessage =
|
||||
!isFetching &&
|
||||
!isLoading &&
|
||||
formattedHostMetricsData.length === 0 &&
|
||||
filters.items.length > 0;
|
||||
|
||||
const showHostsEmptyState =
|
||||
!isFetching &&
|
||||
!isLoading &&
|
||||
(!sentAnyHostMetricsData || isSendingIncorrectK8SAgentMetrics);
|
||||
|
||||
return (
|
||||
<div className="hosts-list">
|
||||
<HostsListControls handleFiltersChange={handleFiltersChange} />
|
||||
{isError && <Typography>{data?.error || 'Something went wrong'}</Typography>}
|
||||
|
||||
{isDataPresent && filters.items.length === 0 && (
|
||||
<NoLogs dataSource={DataSource.METRICS} />
|
||||
{showHostsEmptyState && (
|
||||
<HostsEmptyOrIncorrectMetrics
|
||||
noData={!sentAnyHostMetricsData}
|
||||
incorrectData={isSendingIncorrectK8SAgentMetrics}
|
||||
/>
|
||||
)}
|
||||
|
||||
{!isFetching &&
|
||||
!isLoading &&
|
||||
formattedHostMetricsData.length === 0 &&
|
||||
filters.items.length > 0 && (
|
||||
<div className="no-hosts-message">No hosts match the applied filters.</div>
|
||||
)}
|
||||
{showNoFilteredHostsMessage && (
|
||||
<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"
|
||||
/>
|
||||
|
||||
{!isError && (
|
||||
<Typography.Text className="no-filtered-hosts-message">
|
||||
This query had no results. Edit your query and try again!
|
||||
</Typography.Text>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{(isFetching || isLoading) && (
|
||||
<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>
|
||||
)}
|
||||
|
||||
{showHostsTable && (
|
||||
<Table
|
||||
className="hosts-list-table"
|
||||
dataSource={isFetching || isLoading ? [] : formattedHostMetricsData}
|
||||
|
@ -10,10 +10,6 @@
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
|
||||
.no-hosts-message {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
.hosts-list-controls {
|
||||
padding: 8px;
|
||||
|
||||
@ -210,6 +206,68 @@
|
||||
}
|
||||
}
|
||||
|
||||
.hosts-list-loading-state {
|
||||
padding: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
|
||||
.hosts-list-loading-state-item {
|
||||
height: 48px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.no-filtered-hosts-message-container {
|
||||
height: 30vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.no-filtered-hosts-message-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
|
||||
width: fit-content;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.no-filtered-hosts-message {
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.hosts-empty-state-container {
|
||||
padding: 16px;
|
||||
height: 40vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
.hosts-empty-state-container-content {
|
||||
padding: 16px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
|
||||
width: fit-content;
|
||||
|
||||
.no-hosts-message {
|
||||
margin-bottom: 16px;
|
||||
|
||||
.no-hosts-message-title {
|
||||
margin-top: 8px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lightMode {
|
||||
.infra-monitoring-container {
|
||||
.ant-table-thead > tr > th {
|
||||
|
@ -16,7 +16,7 @@ export default function NavItem({
|
||||
isActive: boolean;
|
||||
onClick: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||
}): JSX.Element {
|
||||
const { label, icon, isBeta } = item;
|
||||
const { label, icon, isBeta, isNew } = item;
|
||||
|
||||
return (
|
||||
<div
|
||||
@ -36,6 +36,14 @@ export default function NavItem({
|
||||
</Tag>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isNew && (
|
||||
<div className="nav-item-new">
|
||||
<Tag bordered={false} className="sidenav-new-tag">
|
||||
New
|
||||
</Tag>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -184,10 +184,16 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
.nav-item-beta {
|
||||
.nav-item-beta,
|
||||
.nav-item-new {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sidenav-new-tag {
|
||||
background-color: rgba(37, 225, 146, 0.1);
|
||||
color: var(--text-forest-500);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
flex: 0 0 240px;
|
||||
max-width: 240px;
|
||||
@ -221,7 +227,8 @@
|
||||
display: block;
|
||||
}
|
||||
|
||||
.nav-item-beta {
|
||||
.nav-item-beta,
|
||||
.nav-item-new {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ import ROUTES from 'constants/routes';
|
||||
import {
|
||||
BarChart2,
|
||||
BellDot,
|
||||
Boxes,
|
||||
BugIcon,
|
||||
Cloudy,
|
||||
DraftingCompass,
|
||||
@ -11,7 +12,6 @@ import {
|
||||
LayoutGrid,
|
||||
ListMinus,
|
||||
MessageSquare,
|
||||
PackagePlus,
|
||||
Receipt,
|
||||
Route,
|
||||
ScrollText,
|
||||
@ -82,6 +82,12 @@ const menuItems: SidebarItem[] = [
|
||||
label: 'Logs',
|
||||
icon: <ScrollText size={16} />,
|
||||
},
|
||||
{
|
||||
key: ROUTES.INFRASTRUCTURE_MONITORING_HOSTS,
|
||||
label: 'Infra Monitoring',
|
||||
icon: <Boxes size={16} />,
|
||||
isNew: true,
|
||||
},
|
||||
{
|
||||
key: ROUTES.ALL_DASHBOARD,
|
||||
label: 'Dashboards',
|
||||
@ -91,7 +97,6 @@ const menuItems: SidebarItem[] = [
|
||||
key: ROUTES.MESSAGING_QUEUES,
|
||||
label: 'Messaging Queues',
|
||||
icon: <ListMinus size={16} />,
|
||||
isBeta: true,
|
||||
},
|
||||
{
|
||||
key: ROUTES.LIST_ALL_ALERT,
|
||||
@ -119,12 +124,6 @@ const menuItems: SidebarItem[] = [
|
||||
label: 'Billing',
|
||||
icon: <Receipt size={16} />,
|
||||
},
|
||||
{
|
||||
key: ROUTES.INFRASTRUCTURE_MONITORING_HOSTS,
|
||||
label: 'Infra Monitoring',
|
||||
icon: <PackagePlus size={16} />,
|
||||
isBeta: true,
|
||||
},
|
||||
{
|
||||
key: ROUTES.SETTINGS,
|
||||
label: 'Settings',
|
||||
|
@ -13,6 +13,7 @@ export interface SidebarItem {
|
||||
key: string | number;
|
||||
label?: ReactNode;
|
||||
isBeta?: boolean;
|
||||
isNew?: boolean;
|
||||
}
|
||||
|
||||
export enum SecondaryMenuItemKey {
|
||||
|
Loading…
x
Reference in New Issue
Block a user