Skip to content

Commit

Permalink
Fix/alert history UI fixes (#5776)
Browse files Browse the repository at this point in the history
* fix: remove extra padding from alert overview query section tabs

* fix: add padding to alert overview container

* fix: improve breadcrumb click behavior

* chore: temporarily hide reset button from alert details timepicker

* fix: improve breadcrumb click behavior

* chore: hide alert firing since

* fix: don't use the data state renderer for timeline table
  • Loading branch information
ahmadshaheer committed Sep 2, 2024
1 parent 0b89601 commit d37410a
Show file tree
Hide file tree
Showing 10 changed files with 158 additions and 105 deletions.
35 changes: 15 additions & 20 deletions frontend/src/components/AlertDetailsFilters/Filters.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,25 @@
import './filters.styles.scss';

import { Button } from 'antd';
import { QueryParams } from 'constants/query';
import { RelativeTimeMap } from 'container/TopNav/DateTimeSelection/config';
import DateTimeSelector from 'container/TopNav/DateTimeSelectionV2';
import useUrlQuery from 'hooks/useUrlQuery';
import { Undo } from 'lucide-react';
import { useHistory } from 'react-router-dom';

export function Filters(): JSX.Element {
const urlQuery = useUrlQuery();
const history = useHistory();
const relativeTime = urlQuery.get(QueryParams.relativeTime);
// const urlQuery = useUrlQuery();
// const history = useHistory();
// const relativeTime = urlQuery.get(QueryParams.relativeTime);

const handleFiltersReset = (): void => {
urlQuery.set(QueryParams.relativeTime, RelativeTimeMap['30min']);
urlQuery.delete(QueryParams.startTime);
urlQuery.delete(QueryParams.endTime);
history.replace({
pathname: history.location.pathname,
search: `?${urlQuery.toString()}`,
});
};
// const handleFiltersReset = (): void => {
// urlQuery.set(QueryParams.relativeTime, RelativeTimeMap['30min']);
// urlQuery.delete(QueryParams.startTime);
// urlQuery.delete(QueryParams.endTime);
// history.replace({
// pathname: history.location.pathname,
// search: `?${urlQuery.toString()}`,
// });
// };
return (
<div className="filters">
{relativeTime !== RelativeTimeMap['30min'] && (
{/* TODO(shaheer): re-enable reset button after fixing the issue w.r.t. updated timeInterval not updating in time picker */}
{/* {relativeTime !== RelativeTimeMap['30min'] && (
<Button
type="default"
className="reset-button"
Expand All @@ -33,7 +28,7 @@ export function Filters(): JSX.Element {
>
Reset
</Button>
)}
)} */}
<DateTimeSelector showAutoRefresh={false} hideShareModal />
</div>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import '../Graph/graph.styles.scss';

import { BarChartOutlined } from '@ant-design/icons';
import { QueryParams } from 'constants/query';
import useUrlQuery from 'hooks/useUrlQuery';
import { useGetAlertRuleDetailsTimelineGraphData } from 'pages/AlertDetails/hooks';
import DataStateRenderer from 'periscope/components/DataStateRenderer/DataStateRenderer';
import { useEffect, useState } from 'react';

import Graph from '../Graph/Graph';

Expand All @@ -24,20 +27,44 @@ function GraphWrapper({
ruleId,
} = useGetAlertRuleDetailsTimelineGraphData();

const startTime = urlQuery.get(QueryParams.startTime);

const [isPlaceholder, setIsPlaceholder] = useState(false);

useEffect(() => {
if (startTime) {
const startTimeDate = new Date(startTime);
const now = new Date();
const twentyFourHoursAgo = new Date(now.getTime() - 24 * 60 * 60 * 1000);

if (startTimeDate < twentyFourHoursAgo) {
setIsPlaceholder(true);
} else {
setIsPlaceholder(false);
}
}
}, [startTime]);

return (
<div className="timeline-graph">
<div className="timeline-graph__title">
{totalCurrentTriggers} triggers in {relativeTime}
</div>
<div className="timeline-graph__chart">
<DataStateRenderer
isLoading={isLoading}
isError={isError || !isValidRuleId || !ruleId}
isRefetching={isRefetching}
data={data?.payload?.data || null}
>
{(data): JSX.Element => <Graph type="horizontal" data={data} />}
</DataStateRenderer>
{isPlaceholder ? (
<div className="chart-placeholder">
<BarChartOutlined className="chart-icon" />
</div>
) : (
<DataStateRenderer
isLoading={isLoading}
isError={isError || !isValidRuleId || !ruleId}
isRefetching={isRefetching}
data={data?.payload?.data || null}
>
{(data): JSX.Element => <Graph type="horizontal" data={data} />}
</DataStateRenderer>
)}
</div>
</div>
);
Expand Down
49 changes: 34 additions & 15 deletions frontend/src/container/AlertHistory/Timeline/Table/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,52 @@
import './table.styles.scss';

import { Table } from 'antd';
import { QueryParams } from 'constants/query';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { useTimelineTable } from 'pages/AlertDetails/hooks';
import {
useGetAlertRuleDetailsTimelineTable,
useTimelineTable,
} from 'pages/AlertDetails/hooks';
import { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useQueryClient } from 'react-query';
import { useLocation } from 'react-router-dom';
import { PayloadProps } from 'types/api/alerts/get';

import { TimelineTableProps } from './types';
import { timelineTableColumns } from './useTimelineTable';

function TimelineTable({
timelineData,
totalItems,
}: TimelineTableProps): JSX.Element {
function TimelineTable(): JSX.Element {
const {
isLoading,
isRefetching,
isError,
data,
isValidRuleId,
ruleId,
} = useGetAlertRuleDetailsTimelineTable();

const { timelineData, totalItems } = useMemo(() => {
const response = data?.payload?.data;
return {
timelineData: response?.items,
totalItems: response?.total,
};
}, [data?.payload?.data]);

const [searchText, setSearchText] = useState('');
const { paginationConfig, onChangeHandler } = useTimelineTable({ totalItems });
const { paginationConfig, onChangeHandler } = useTimelineTable({
totalItems: totalItems ?? 0,
});

const visibleTimelineData = useMemo(() => {
if (searchText === '') {
return timelineData;
}
return timelineData.filter((data) =>
return timelineData?.filter((data) =>
JSON.stringify(data.labels).toLowerCase().includes(searchText.toLowerCase()),
);
}, [searchText, timelineData]);

const queryClient = useQueryClient();

const { search } = useLocation();
const params = new URLSearchParams(search);

const ruleId = params.get(QueryParams.ruleId);

const { currentUnit, targetUnit } = useMemo(() => {
const alertDetailsQuery = queryClient.getQueryData([
REACT_QUERY_KEY.ALERT_RULE_DETAILS,
Expand All @@ -49,6 +61,12 @@ function TimelineTable({
return { currentUnit, targetUnit };
}, [queryClient, ruleId]);

const { t } = useTranslation('common');

if (isError || !isValidRuleId || !ruleId) {
return <div>{t('something_went_wrong')}</div>;
}

return (
<div className="timeline-table">
<Table
Expand All @@ -58,6 +76,7 @@ function TimelineTable({
pagination={paginationConfig}
size="middle"
onChange={onChangeHandler}
loading={isLoading || isRefetching}
/>
</div>
);
Expand Down
28 changes: 1 addition & 27 deletions frontend/src/container/AlertHistory/Timeline/Timeline.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,11 @@
import './timeline.styles.scss';

import { useGetAlertRuleDetailsTimelineTable } from 'pages/AlertDetails/hooks';
import DataStateRenderer from 'periscope/components/DataStateRenderer/DataStateRenderer';

import GraphWrapper from './GraphWrapper/GraphWrapper';
import TimelineTable from './Table/Table';
import TabsAndFilters from './TabsAndFilters/TabsAndFilters';

function TimelineTableRenderer(): JSX.Element {
const {
isLoading,
isRefetching,
isError,
data,
isValidRuleId,
ruleId,
} = useGetAlertRuleDetailsTimelineTable();

return (
<DataStateRenderer
isLoading={isLoading}
isRefetching={isRefetching}
isError={isError || !isValidRuleId || !ruleId}
data={data?.payload?.data || null}
>
{(timelineData): JSX.Element => (
<TimelineTable
timelineData={timelineData.items}
totalItems={timelineData.total}
/>
)}
</DataStateRenderer>
);
return <TimelineTable />;
}

function Timeline({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@
display: flex;
align-items: center;
}

.ant-tabs-tab-btn {
padding: 0 !important;
}
}

.lightMode {
Expand All @@ -57,8 +61,5 @@
background: var(--bg-vanilla-300) !important;
}
}
.ant-tabs-tab-btn {
padding: 0;
}
}
}
9 changes: 3 additions & 6 deletions frontend/src/pages/AlertDetails/AlertHeader/AlertHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import './alertHeader.styles.scss';

import dayjs from 'dayjs';

import AlertActionButtons from './ActionButtons';
import AlertLabels from './AlertLabels/AlertLabels';
import AlertSeverity from './AlertSeverity/AlertSeverity';
import AlertState from './AlertState/AlertState';
import AlertStatus from './AlertStatus/AlertStatus';

type AlertHeaderProps = {
alertDetails: {
Expand All @@ -32,11 +29,11 @@ function AlertHeader({ alertDetails }: AlertHeaderProps): JSX.Element {
<div className="bottom-section">
<AlertSeverity severity="warning" />

{/* // TODO(shaheer): Get actual data when we are able to get alert status from API */}
<AlertStatus
{/* // TODO(shaheer): Get actual data when we are able to get alert firing from state from API */}
{/* <AlertStatus
status="firing"
timestamp={dayjs().subtract(1, 'd').valueOf()}
/>
/> */}
<AlertLabels labels={labels} />
</div>
</div>
Expand Down
8 changes: 6 additions & 2 deletions frontend/src/pages/AlertDetails/alertDetails.styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,20 @@
margin-top: 10px;
}
&__breadcrumb {
ol {
align-items: center;
}
padding-left: 16px;
.ant-breadcrumb-link {
.breadcrumb-item {
color: var(--text-vanilla-400);
font-size: 14px;
line-height: 20px;
letter-spacing: 0.25px;
padding: 0;
}

.ant-breadcrumb-separator,
span.ant-breadcrumb-link {
.breadcrumb-item--last {
color: var(--var-vanilla-500);
font-family: 'Geist Mono';
}
Expand Down
41 changes: 37 additions & 4 deletions frontend/src/pages/AlertDetails/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import './alertDetails.styles.scss';

import { Breadcrumb, Divider } from 'antd';
import { Breadcrumb, Button, Divider } from 'antd';
import { Filters } from 'components/AlertDetailsFilters/Filters';
import NotFound from 'components/NotFound';
import RouteTab from 'components/RouteTab';
Expand Down Expand Up @@ -38,6 +38,38 @@ function AlertDetailsStatusRenderer({

return <AlertHeader alertDetails={alertRuleDetails} />;
}

function BreadCrumbItem({
title,
isLast,
route,
}: {
title: string | null;
isLast?: boolean;
route?: string;
}): JSX.Element {
if (isLast) {
return <div className="breadcrumb-item breadcrumb-item--last">{title}</div>;
}
const handleNavigate = (): void => {
if (!route) {
return;
}
history.push(ROUTES.LIST_ALL_ALERT);
};

return (
<Button type="text" className="breadcrumb-item" onClick={handleNavigate}>
{title}
</Button>
);
}

BreadCrumbItem.defaultProps = {
isLast: false,
route: '',
};

function AlertDetails(): JSX.Element {
const { pathname } = useLocation();
const { routes } = useRouteTabUtils();
Expand All @@ -60,11 +92,12 @@ function AlertDetails(): JSX.Element {
className="alert-details__breadcrumb"
items={[
{
title: 'Alert Rules',
href: ROUTES.LIST_ALL_ALERT,
title: (
<BreadCrumbItem title="Alert Rules" route={ROUTES.LIST_ALL_ALERT} />
),
},
{
title: ruleId,
title: <BreadCrumbItem title={ruleId} isLast />,
},
]}
/>
Expand Down
Loading

0 comments on commit d37410a

Please sign in to comment.