Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: bugfixes and overall improvements to alert history #5841

Merged
merged 28 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
54298d9
fix: don't display severity label
ahmadshaheer Sep 3, 2024
c706386
chore: remove id from alert header
ahmadshaheer Sep 3, 2024
1b5997f
chore: add tooltip to enable/disable alert toggle
ahmadshaheer Sep 3, 2024
bdd224d
chore: update enable/disbale toast message
ahmadshaheer Sep 3, 2024
802be79
fix: set default relative time to 6h if relative time is not provided
ahmadshaheer Sep 3, 2024
bd9dbe2
chore: update empty top contributors text and remove configure alert
ahmadshaheer Sep 3, 2024
f6295f8
chore: temporarily hide value column from timeline column
ahmadshaheer Sep 3, 2024
db1692b
fix: use correct links for logs and traces in alert popover
ahmadshaheer Sep 3, 2024
3447fa6
fix: properly set timeline table offset
ahmadshaheer Sep 3, 2024
7567910
fix: display all values in graph
ahmadshaheer Sep 3, 2024
08e8429
fix: resolve conflicts
ahmadshaheer Sep 4, 2024
992e63c
chore: remove style for value column in timeline table
ahmadshaheer Sep 3, 2024
20f19ee
chore: temporarily hide labels search
ahmadshaheer Sep 3, 2024
5cbb432
fix: incorrect current page in pagination info text
ahmadshaheer Sep 3, 2024
ba81af5
chore: remove label QB search
ahmadshaheer Sep 3, 2024
43eb8b6
chore: remove value column
ahmadshaheer Sep 3, 2024
72239c8
chore: remove commented code
ahmadshaheer Sep 3, 2024
8932ffe
fix: show traces button when trace link is available
ahmadshaheer Sep 3, 2024
b809670
fix: display horizontal chart even for a single entry
ahmadshaheer Sep 3, 2024
bc53f2d
fix: show inactive state in horizontal similar to normal state
ahmadshaheer Sep 3, 2024
9381730
fix: properly render inactive state in horizontal chart
ahmadshaheer Sep 3, 2024
df46918
fix: properly handle preserving alert toggle between overview and his…
ahmadshaheer Sep 3, 2024
d813146
feat: get page size from query param
ahmadshaheer Sep 4, 2024
3cae368
chore: remove commented code + minor refactor
ahmadshaheer Sep 4, 2024
d19e593
chore: remove tsconfi.tmp
ahmadshaheer Sep 4, 2024
53dfbd8
fix: don't add default relative time if start and times exist in the url
ahmadshaheer Sep 4, 2024
1b74947
feat: display date range preview for stat cards
ahmadshaheer Sep 4, 2024
3b60559
chore: remove custom dropdown renderer component
ahmadshaheer Sep 4, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 19 additions & 16 deletions frontend/src/AppRoutes/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { ResourceProvider } from 'hooks/useResourceAttribute';
import history from 'lib/history';
import { identity, pick, pickBy } from 'lodash-es';
import posthog from 'posthog-js';
import AlertRuleProvider from 'providers/Alert';
import { DashboardProvider } from 'providers/Dashboard/Dashboard';
import { QueryBuilderProvider } from 'providers/QueryBuilder';
import { Suspense, useEffect, useState } from 'react';
Expand Down Expand Up @@ -236,22 +237,24 @@ function App(): JSX.Element {
<QueryBuilderProvider>
<DashboardProvider>
<KeyboardHotkeysProvider>
<AppLayout>
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
<Switch>
{routes.map(({ path, component, exact }) => (
<Route
key={`${path}`}
exact={exact}
path={path}
component={component}
/>
))}

<Route path="*" component={NotFound} />
</Switch>
</Suspense>
</AppLayout>
<AlertRuleProvider>
<AppLayout>
<Suspense fallback={<Spinner size="large" tip="Loading..." />}>
<Switch>
{routes.map(({ path, component, exact }) => (
<Route
key={`${path}`}
exact={exact}
path={path}
component={component}
/>
))}

<Route path="*" component={NotFound} />
</Switch>
</Suspense>
</AppLayout>
</AlertRuleProvider>
</KeyboardHotkeysProvider>
</DashboardProvider>
</QueryBuilderProvider>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ function PopoverContent({
const isDarkMode = useIsDarkMode();
return (
<div className="contributor-row-popover-buttons">
{!!relatedTracesLink && (
{!!relatedLogsLink && (
<Link
to={`${ROUTES.LOGS_EXPLORER}?${relatedTracesLink}`}
to={`${ROUTES.LOGS_EXPLORER}?${relatedLogsLink}`}
className="contributor-row-popover-buttons__button"
>
<div className="icon">
Expand All @@ -36,9 +36,9 @@ function PopoverContent({
<div className="text">View Logs</div>
</Link>
)}
{!!relatedLogsLink && (
{!!relatedTracesLink && (
<Link
to={`${ROUTES.TRACES_EXPLORER}?${relatedLogsLink}`}
to={`${ROUTES.TRACES_EXPLORER}?${relatedTracesLink}`}
className="contributor-row-popover-buttons__button"
>
<div className="icon">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import './StatsCard.styles.scss';

import { Color } from '@signozhq/design-tokens';
import { Tooltip } from 'antd';
import { QueryParams } from 'constants/query';
import useUrlQuery from 'hooks/useUrlQuery';
import { ArrowDownLeft, ArrowUpRight, Calendar } from 'lucide-react';
import { AlertRuleStats } from 'types/api/alerts/def';
import { calculateChange } from 'utils/calculateChange';

import StatsGraph from './StatsGraph/StatsGraph';
import {
convertTimestampToLocaleDateString,
extractDayFromTimestamp,
} from './utils';

type ChangePercentageProps = {
percentage: number;
Expand Down Expand Up @@ -78,6 +84,25 @@ function StatsCard({
totalPastCount,
);

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

let displayTime = relativeTime;

if (!displayTime && startTime && endTime) {
const formattedStartDate = extractDayFromTimestamp(startTime);
const formattedEndDate = extractDayFromTimestamp(endTime);
displayTime = `${formattedStartDate} to ${formattedEndDate}`;
}

if (!displayTime) {
displayTime = '';
}
const formattedStartTimeForTooltip = convertTimestampToLocaleDateString(
startTime,
);
const formattedEndTimeForTooltip = convertTimestampToLocaleDateString(endTime);

return (
<div className={`stats-card ${isEmpty ? 'stats-card--empty' : ''}`}>
<div className="stats-card__title-wrapper">
Expand All @@ -86,7 +111,15 @@ function StatsCard({
<div className="icon">
<Calendar size={14} color={Color.BG_SLATE_200} />
</div>
<div className="text">{relativeTime}</div>
{relativeTime ? (
<div className="text">{displayTime}</div>
) : (
<Tooltip
title={`From ${formattedStartTimeForTooltip} to ${formattedEndTimeForTooltip}`}
>
<div className="text">{displayTime}</div>
</Tooltip>
)}
</div>
</div>

Expand Down
12 changes: 12 additions & 0 deletions frontend/src/container/AlertHistory/Statistics/StatsCard/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const extractDayFromTimestamp = (timestamp: string | null): string => {
if (!timestamp) return '';
const date = new Date(parseInt(timestamp, 10));
return date.getDate().toString();
};

export const convertTimestampToLocaleDateString = (
timestamp: string | null,
): string => {
if (!timestamp) return '';
return new Date(parseInt(timestamp, 10)).toLocaleString();
};
Original file line number Diff line number Diff line change
@@ -1,9 +1,3 @@
import { Button } from 'antd';
import { QueryParams } from 'constants/query';
import ROUTES from 'constants/routes';
import useUrlQuery from 'hooks/useUrlQuery';
import history from 'lib/history';

import TopContributorsRows from './TopContributorsRows';
import { TopContributorsCardProps } from './types';

Expand All @@ -13,34 +7,13 @@ function TopContributorsContent({
}: TopContributorsCardProps): JSX.Element {
const isEmpty = !topContributorsData.length;

const urlQuery = useUrlQuery();
const ruleIdKey = QueryParams.ruleId;
const relativeTimeKey = QueryParams.relativeTime;

const handleRedirectToOverview = (): void => {
const params = `${ruleIdKey}=${urlQuery.get(
ruleIdKey,
)}&${relativeTimeKey}=${urlQuery.get(relativeTimeKey)}`;

history.push(`${ROUTES.ALERT_OVERVIEW}?${params}`);
};

if (isEmpty) {
return (
<div className="empty-content">
<div className="empty-content__icon">ℹ️</div>
<div className="empty-content__text">
<span className="bold-text">Add Group By Field</span> To view top
contributors, please add at least one group by field to your query.
</div>
<div className="empty-content__button-wrapper">
<Button
type="default"
className="configure-alert-rule-button"
onClick={handleRedirectToOverview}
>
Configure Alert Rule
</Button>
Top contributors highlight the most frequently triggering group-by
attributes in multi-dimensional alerts
</div>
</div>
);
Expand Down
35 changes: 22 additions & 13 deletions frontend/src/container/AlertHistory/Timeline/Graph/Graph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,28 @@ function HorizontalTimelineGraph({
isDarkMode: boolean;
data: AlertRuleTimelineGraphResponse[];
}): JSX.Element {
const transformedData: AlignedData = useMemo(
() =>
data?.length > 1
? [
data.map((item: AlertRuleTimelineGraphResponse) => item.start / 1000),
data.map(
(item: AlertRuleTimelineGraphResponse) => ALERT_STATUS[item.state],
),
]
: [[], []],

[data],
);
const transformedData: AlignedData = useMemo(() => {
if (!data?.length) {
return [[], []];
}

// add a first and last entry to make sure the graph displays all the data
const FIVE_MINUTES_IN_SECONDS = 300;

const timestamps = [
data[0].start / 1000 - FIVE_MINUTES_IN_SECONDS, // 5 minutes before the first entry
...data.map((item) => item.start / 1000),
data[data.length - 1].end / 1000, // end value of last entry
];

const states = [
ALERT_STATUS[data[0].state], // Same state as the first entry
...data.map((item) => ALERT_STATUS[item.state]),
ALERT_STATUS[data[data.length - 1].state], // Same state as the last entry
];

return [timestamps, states];
}, [data]);

const options: uPlot.Options = useMemo(
() => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Color } from '@signozhq/design-tokens';

export const ALERT_STATUS: { [key: string]: number } = {
firing: 0,
inactive: 1,
normal: 1,
'no-data': 2,
disabled: 3,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@
font-size: 12px;
font-weight: 500;
padding: 12px 16px 8px !important;
&:last-of-type,
&:nth-last-of-type(2) {
&:last-of-type
// TODO(shaheer): uncomment when we display value column
// ,
// &:nth-last-of-type(2)
{
text-align: right;
}
}
Expand Down
29 changes: 3 additions & 26 deletions frontend/src/container/AlertHistory/Timeline/Table/Table.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,24 @@
import './Table.styles.scss';

import { Table } from 'antd';
import { initialFilters } from 'constants/queryBuilder';
import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import {
useGetAlertRuleDetailsTimelineTable,
useTimelineTable,
} from 'pages/AlertDetails/hooks';
import { useMemo, useState } from 'react';
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useQueryClient } from 'react-query';
import { PayloadProps } from 'types/api/alerts/get';
import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';

import { timelineTableColumns } from './useTimelineTable';

function TimelineTable(): JSX.Element {
const [filters, setFilters] = useState<TagFilter>(initialFilters);

const {
isLoading,
isRefetching,
isError,
data,
isValidRuleId,
ruleId,
} = useGetAlertRuleDetailsTimelineTable({ filters });
} = useGetAlertRuleDetailsTimelineTable();

const { timelineData, totalItems } = useMemo(() => {
const response = data?.payload?.data;
Expand All @@ -39,22 +32,6 @@ function TimelineTable(): JSX.Element {
totalItems: totalItems ?? 0,
});

const queryClient = useQueryClient();

const { currentUnit, targetUnit } = useMemo(() => {
const alertDetailsQuery = queryClient.getQueryData([
REACT_QUERY_KEY.ALERT_RULE_DETAILS,
ruleId,
]) as {
payload: PayloadProps;
};
const condition = alertDetailsQuery?.payload?.data?.condition;
const { targetUnit } = condition ?? {};
const { unit: currentUnit } = condition?.compositeQuery ?? {};

return { currentUnit, targetUnit };
}, [queryClient, ruleId]);

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

if (isError || !isValidRuleId || !ruleId) {
Expand All @@ -65,7 +42,7 @@ function TimelineTable(): JSX.Element {
<div className="timeline-table">
<Table
rowKey={(row): string => `${row.fingerprint}-${row.value}-${row.unixMilli}`}
columns={timelineTableColumns(filters, setFilters, currentUnit, targetUnit)}
columns={timelineTableColumns()}
dataSource={timelineData}
pagination={paginationConfig}
size="middle"
Expand Down
Loading
Loading