diff --git a/frontend/src/container/AlertHistory/Statistics/StatsCard/StatsCard.tsx b/frontend/src/container/AlertHistory/Statistics/StatsCard/StatsCard.tsx
index 22f15515709..f204579f938 100644
--- a/frontend/src/container/AlertHistory/Statistics/StatsCard/StatsCard.tsx
+++ b/frontend/src/container/AlertHistory/Statistics/StatsCard/StatsCard.tsx
@@ -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;
@@ -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 (
@@ -86,7 +111,15 @@ function StatsCard({
-
{relativeTime}
+ {relativeTime ? (
+
{displayTime}
+ ) : (
+
+ {displayTime}
+
+ )}
diff --git a/frontend/src/container/AlertHistory/Statistics/StatsCard/utils.ts b/frontend/src/container/AlertHistory/Statistics/StatsCard/utils.ts
new file mode 100644
index 00000000000..a2584aad37a
--- /dev/null
+++ b/frontend/src/container/AlertHistory/Statistics/StatsCard/utils.ts
@@ -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();
+};
diff --git a/frontend/src/container/AlertHistory/Statistics/TopContributorsCard/TopContributorsContent.tsx b/frontend/src/container/AlertHistory/Statistics/TopContributorsCard/TopContributorsContent.tsx
index 39a2f8f27ae..b458871f712 100644
--- a/frontend/src/container/AlertHistory/Statistics/TopContributorsCard/TopContributorsContent.tsx
+++ b/frontend/src/container/AlertHistory/Statistics/TopContributorsCard/TopContributorsContent.tsx
@@ -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';
@@ -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 (
ℹ️
- Add Group By Field To view top
- contributors, please add at least one group by field to your query.
-
-
-
+ Top contributors highlight the most frequently triggering group-by
+ attributes in multi-dimensional alerts
);
diff --git a/frontend/src/container/AlertHistory/Timeline/Graph/Graph.tsx b/frontend/src/container/AlertHistory/Timeline/Graph/Graph.tsx
index 684ba897f29..a0534691df8 100644
--- a/frontend/src/container/AlertHistory/Timeline/Graph/Graph.tsx
+++ b/frontend/src/container/AlertHistory/Timeline/Graph/Graph.tsx
@@ -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(
() => ({
diff --git a/frontend/src/container/AlertHistory/Timeline/Graph/constants.ts b/frontend/src/container/AlertHistory/Timeline/Graph/constants.ts
index 34a79df4862..b56499a0d0c 100644
--- a/frontend/src/container/AlertHistory/Timeline/Graph/constants.ts
+++ b/frontend/src/container/AlertHistory/Timeline/Graph/constants.ts
@@ -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,
diff --git a/frontend/src/container/AlertHistory/Timeline/Table/Table.styles.scss b/frontend/src/container/AlertHistory/Timeline/Table/Table.styles.scss
index 807bbfb4be9..9d31e0b0ea7 100644
--- a/frontend/src/container/AlertHistory/Timeline/Table/Table.styles.scss
+++ b/frontend/src/container/AlertHistory/Timeline/Table/Table.styles.scss
@@ -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;
}
}
diff --git a/frontend/src/container/AlertHistory/Timeline/Table/Table.tsx b/frontend/src/container/AlertHistory/Timeline/Table/Table.tsx
index 63d0464eb83..f3144b88e61 100644
--- a/frontend/src/container/AlertHistory/Timeline/Table/Table.tsx
+++ b/frontend/src/container/AlertHistory/Timeline/Table/Table.tsx
@@ -1,23 +1,16 @@
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
(initialFilters);
-
const {
isLoading,
isRefetching,
@@ -25,7 +18,7 @@ function TimelineTable(): JSX.Element {
data,
isValidRuleId,
ruleId,
- } = useGetAlertRuleDetailsTimelineTable({ filters });
+ } = useGetAlertRuleDetailsTimelineTable();
const { timelineData, totalItems } = useMemo(() => {
const response = data?.payload?.data;
@@ -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) {
@@ -65,7 +42,7 @@ function TimelineTable(): JSX.Element {
`${row.fingerprint}-${row.value}-${row.unixMilli}`}
- columns={timelineTableColumns(filters, setFilters, currentUnit, targetUnit)}
+ columns={timelineTableColumns()}
dataSource={timelineData}
pagination={paginationConfig}
size="middle"
diff --git a/frontend/src/container/AlertHistory/Timeline/Table/useTimelineTable.tsx b/frontend/src/container/AlertHistory/Timeline/Table/useTimelineTable.tsx
index 7dbafb83c65..5a42fcd5bd8 100644
--- a/frontend/src/container/AlertHistory/Timeline/Table/useTimelineTable.tsx
+++ b/frontend/src/container/AlertHistory/Timeline/Table/useTimelineTable.tsx
@@ -1,91 +1,11 @@
-import { Color } from '@signozhq/design-tokens';
import { ColumnsType } from 'antd/es/table';
-import { QueryParams } from 'constants/query';
-import { REACT_QUERY_KEY } from 'constants/reactQueryKeys';
import { ConditionalAlertPopover } from 'container/AlertHistory/AlertPopover/AlertPopover';
-import QueryBuilderSearch from 'container/QueryBuilder/filters/QueryBuilderSearch';
-import { useIsDarkMode } from 'hooks/useDarkMode';
-import useUrlQuery from 'hooks/useUrlQuery';
-import { convertValue } from 'lib/getConvertedValue';
-import { Search } from 'lucide-react';
import AlertLabels from 'pages/AlertDetails/AlertHeader/AlertLabels/AlertLabels';
import AlertState from 'pages/AlertDetails/AlertHeader/AlertState/AlertState';
-import { useMemo } from 'react';
-import { useQueryClient } from 'react-query';
-import { SuccessResponse } from 'types/api';
import { AlertRuleTimelineTableResponse } from 'types/api/alerts/def';
-import { PayloadProps } from 'types/api/alerts/get';
-import {
- IBuilderQuery,
- TagFilter,
-} from 'types/api/queryBuilder/queryBuilderData';
import { formatEpochTimestamp } from 'utils/timeUtils';
-function LabelFilter({
- filters,
- setFilters,
-}: {
- setFilters: (text: TagFilter) => void;
- filters: TagFilter;
-}): JSX.Element | null {
- const isDarkMode = useIsDarkMode();
-
- const queryClient = useQueryClient();
- const urlQuery = useUrlQuery();
- const ruleId = urlQuery.get(QueryParams.ruleId);
-
- const data = queryClient.getQueryData>([
- REACT_QUERY_KEY.ALERT_RULE_DETAILS,
- ruleId,
- ]);
-
- const query = useMemo(() => {
- const compositeQueries = data?.payload?.data?.condition.compositeQuery;
- const query = compositeQueries?.builderQueries?.A;
-
- return {
- ...query,
- filters,
- } as IBuilderQuery;
- }, [data?.payload?.data?.condition.compositeQuery, filters]);
-
- if (!data) {
- return null;
- }
-
- const handleSearch = (tagFilters: TagFilter): void => {
- const tagFiltersLength = tagFilters.items.length;
-
- if (
- (!tagFiltersLength && (!filters || !filters.items.length)) ||
- tagFiltersLength === filters?.items.length
- )
- return;
-
- setFilters(tagFilters);
- };
-
- return (
-
- }
- />
- );
-}
-
-export const timelineTableColumns = (
- filters: TagFilter,
- setFilters: (text: TagFilter) => void,
- currentUnit?: string,
- targetUnit?: string,
-): ColumnsType => [
+export const timelineTableColumns = (): ColumnsType => [
{
title: 'STATE',
dataIndex: 'state',
@@ -103,7 +23,7 @@ export const timelineTableColumns = (
),
},
{
- title: ,
+ title: 'LABELS',
dataIndex: 'labels',
width: '54.5%',
render: (labels, record): JSX.Element => (
@@ -117,22 +37,6 @@ export const timelineTableColumns = (
),
},
- {
- title: 'VALUE',
- dataIndex: 'value',
- width: '14%',
- render: (value, record): JSX.Element => (
-
-
- {/* convert the value based on y axis and target unit */}
- {convertValue(value.toFixed(2), currentUnit, targetUnit)}
-
-
- ),
- },
{
title: 'CREATED AT',
dataIndex: 'unixMilli',
diff --git a/frontend/src/container/TopNav/DateTimeSelectionV2/index.tsx b/frontend/src/container/TopNav/DateTimeSelectionV2/index.tsx
index 6b6a3bce682..cd4fb97d4f5 100644
--- a/frontend/src/container/TopNav/DateTimeSelectionV2/index.tsx
+++ b/frontend/src/container/TopNav/DateTimeSelectionV2/index.tsx
@@ -66,7 +66,7 @@ function DateTimeSelection({
globalTimeLoading,
showResetButton = false,
showOldExplorerCTA = false,
- defaultRelativeTime = RelativeTimeMap['30min'] as Time,
+ defaultRelativeTime = RelativeTimeMap['6hr'] as Time,
}: Props): JSX.Element {
const [formSelector] = Form.useForm();
@@ -469,6 +469,22 @@ function DateTimeSelection({
}
const currentRoute = location.pathname;
+
+ // set the default relative time for alert history and overview pages if relative time is not specified
+ if (
+ (!urlQuery.has(QueryParams.startTime) ||
+ !urlQuery.has(QueryParams.endTime)) &&
+ !urlQuery.has(QueryParams.relativeTime) &&
+ (currentRoute === ROUTES.ALERT_OVERVIEW ||
+ currentRoute === ROUTES.ALERT_HISTORY)
+ ) {
+ updateTimeInterval(defaultRelativeTime);
+ urlQuery.set(QueryParams.relativeTime, defaultRelativeTime);
+ const generatedUrl = `${location.pathname}?${urlQuery.toString()}`;
+ history.replace(generatedUrl);
+ return;
+ }
+
const time = getDefaultTime(currentRoute);
const currentOptions = getOptions(currentRoute);
@@ -710,7 +726,7 @@ DateTimeSelection.defaultProps = {
hideShareModal: false,
showOldExplorerCTA: false,
showResetButton: false,
- defaultRelativeTime: RelativeTimeMap['30min'] as Time,
+ defaultRelativeTime: RelativeTimeMap['6hr'] as Time,
};
interface DispatchProps {
updateTimeInterval: (
diff --git a/frontend/src/pages/AlertDetails/AlertHeader/ActionButtons/ActionButtons.tsx b/frontend/src/pages/AlertDetails/AlertHeader/ActionButtons/ActionButtons.tsx
index bf4ac624463..183b4d2aaae 100644
--- a/frontend/src/pages/AlertDetails/AlertHeader/ActionButtons/ActionButtons.tsx
+++ b/frontend/src/pages/AlertDetails/AlertHeader/ActionButtons/ActionButtons.tsx
@@ -1,7 +1,7 @@
import './ActionButtons.styles.scss';
import { Color } from '@signozhq/design-tokens';
-import { Button, Divider, Dropdown, MenuProps, Switch, Tooltip } from 'antd';
+import { Divider, Dropdown, MenuProps, Switch, Tooltip } from 'antd';
import { QueryParams } from 'constants/query';
import ROUTES from 'constants/routes';
import { useIsDarkMode } from 'hooks/useDarkMode';
@@ -14,65 +14,32 @@ import {
useAlertRuleStatusToggle,
} from 'pages/AlertDetails/hooks';
import CopyToClipboard from 'periscope/components/CopyToClipboard';
-import React, { useCallback, useState } from 'react';
+import { useAlertRule } from 'providers/Alert';
+import React from 'react';
+import { CSSProperties } from 'styled-components';
import { AlertDef } from 'types/api/alerts/def';
import { AlertHeaderProps } from '../AlertHeader';
-const menuStyle: React.CSSProperties = {
- padding: 0,
- boxShadow: 'none',
- fontSize: 14,
+const menuItemStyle: CSSProperties = {
+ fontSize: '14px',
+ letterSpacing: '0.14px',
};
-
-function DropdownMenuRenderer(
- menu: React.ReactNode,
- handleDelete: () => void,
-): React.ReactNode {
- return (
-
- {React.cloneElement(menu as React.ReactElement, {
- style: menuStyle,
- })}
-
-
}
- className="delete-button"
- onClick={handleDelete}
- >
- Delete
-
-
- );
-}
-
function AlertActionButtons({
ruleId,
- state,
alertDetails,
}: {
ruleId: string;
- state: string;
alertDetails: AlertHeaderProps['alertDetails'];
}): JSX.Element {
- const [dropdownOpen, setDropdownOpen] = useState(false);
-
- const {
- handleAlertStateToggle,
- isAlertRuleEnabled,
- } = useAlertRuleStatusToggle({ ruleId, state });
+ const { isAlertRuleDisabled } = useAlertRule();
+ const { handleAlertStateToggle } = useAlertRuleStatusToggle({ ruleId });
const { handleAlertDuplicate } = useAlertRuleDuplicate({
alertDetails: (alertDetails as unknown) as AlertDef,
});
const { handleAlertDelete } = useAlertRuleDelete({ ruleId: Number(ruleId) });
- const handleDeleteWithClose = useCallback(() => {
- handleAlertDelete();
- setDropdownOpen(false);
- }, [handleAlertDelete]);
-
const params = useUrlQuery();
const handleRename = React.useCallback(() => {
@@ -87,38 +54,46 @@ function AlertActionButtons({
label: 'Rename',
icon: ,
onClick: (): void => handleRename(),
+ style: menuItemStyle,
},
{
key: 'duplicate-rule',
label: 'Duplicate',
icon: ,
onClick: (): void => handleAlertDuplicate(),
+ style: menuItemStyle,
+ },
+ {
+ key: 'delete-rule',
+ label: 'Delete',
+ icon: ,
+ onClick: (): void => handleAlertDelete(),
+ style: {
+ ...menuItemStyle,
+ color: Color.BG_CHERRY_400,
+ },
},
],
- [handleAlertDuplicate, handleRename],
+ [handleAlertDelete, handleAlertDuplicate, handleRename],
);
const isDarkMode = useIsDarkMode();
return (
-
+
+ {isAlertRuleDisabled !== undefined && (
+
+ )}
+
-
- DropdownMenuRenderer(menu, handleDeleteWithClose)
- }
- >
+
;
+ disabled: boolean;
};
};
function AlertHeader({ alertDetails }: AlertHeaderProps): JSX.Element {
- const { state, alert, id, labels } = alertDetails;
+ const { state, alert, labels, disabled } = alertDetails;
+
+ const labelsWithoutSeverity = useMemo(
+ () =>
+ Object.fromEntries(
+ Object.entries(labels).filter(([key]) => key !== 'severity'),
+ ),
+ [labels],
+ );
+
+ const { isAlertRuleDisabled, setIsAlertRuleDisabled } = useAlertRule();
+
+ useEffect(() => {
+ if (isAlertRuleDisabled === undefined) {
+ setIsAlertRuleDisabled(disabled);
+ }
+ }, [disabled, setIsAlertRuleDisabled, isAlertRuleDisabled]);
return (
@@ -23,7 +43,6 @@ function AlertHeader({ alertDetails }: AlertHeaderProps): JSX.Element {
@@ -34,15 +53,11 @@ function AlertHeader({ alertDetails }: AlertHeaderProps): JSX.Element {
status="firing"
timestamp={dayjs().subtract(1, 'd').valueOf()}
/> */}
-
+
);
diff --git a/frontend/src/pages/AlertDetails/hooks.tsx b/frontend/src/pages/AlertDetails/hooks.tsx
index 78d9bd0038c..fc6219b1953 100644
--- a/frontend/src/pages/AlertDetails/hooks.tsx
+++ b/frontend/src/pages/AlertDetails/hooks.tsx
@@ -27,8 +27,9 @@ import { History, Table } from 'lucide-react';
import EditRules from 'pages/EditRules';
import { OrderPreferenceItems } from 'pages/Logs/config';
import PaginationInfoText from 'periscope/components/PaginationInfoText/PaginationInfoText';
-import { useCallback, useMemo, useState } from 'react';
-import { useMutation, useQuery } from 'react-query';
+import { useAlertRule } from 'providers/Alert';
+import { useCallback, useMemo } from 'react';
+import { useMutation, useQuery, useQueryClient } from 'react-query';
import { useSelector } from 'react-redux';
import { generatePath, useLocation } from 'react-router-dom';
import { AppState } from 'store/reducers';
@@ -42,7 +43,6 @@ import {
AlertRuleTopContributorsPayload,
} from 'types/api/alerts/def';
import { PayloadProps } from 'types/api/alerts/get';
-import { TagFilter } from 'types/api/queryBuilder/queryBuilderData';
import { GlobalReducer } from 'types/reducer/globalTime';
import { nanoToMilli } from 'utils/timeUtils';
@@ -251,17 +251,12 @@ type GetAlertRuleDetailsTimelineTableProps = GetAlertRuleDetailsApiProps & {
| undefined;
};
-export const useGetAlertRuleDetailsTimelineTable = ({
- filters,
-}: {
- filters: TagFilter;
-}): GetAlertRuleDetailsTimelineTableProps => {
+export const useGetAlertRuleDetailsTimelineTable = (): GetAlertRuleDetailsTimelineTableProps => {
const { ruleId, startTime, endTime, params } = useAlertHistoryQueryParams();
-
- const { updatedOrder, getUpdatedOffset } = useMemo(
+ const { updatedOrder, offset } = useMemo(
() => ({
updatedOrder: params.get(urlKey.order) ?? OrderPreferenceItems.ASC,
- getUpdatedOffset: params.get(urlKey.offset) ?? '0',
+ offset: parseInt(params.get(urlKey.offset) ?? '1', 10),
}),
[params],
);
@@ -279,8 +274,7 @@ export const useGetAlertRuleDetailsTimelineTable = ({
endTime,
timelineFilter,
updatedOrder,
- getUpdatedOffset,
- JSON.stringify(filters.items),
+ offset,
],
{
queryFn: () =>
@@ -290,8 +284,7 @@ export const useGetAlertRuleDetailsTimelineTable = ({
end: endTime,
limit: TIMELINE_TABLE_PAGE_SIZE,
order: updatedOrder,
- offset: parseInt(getUpdatedOffset, 10),
- filters,
+ offset,
...(timelineFilter && timelineFilter !== TimelineFilter.ALL
? {
@@ -327,7 +320,7 @@ export const useTimelineTable = ({
const params = useMemo(() => new URLSearchParams(search), [search]);
- const updatedOffset = params.get(urlKey.offset) ?? '0';
+ const offset = params.get('offset') ?? '0';
const onChangeHandler: TableProps['onChange'] = useCallback(
(
@@ -339,7 +332,7 @@ export const useTimelineTable = ({
) => {
if (!Array.isArray(sorter)) {
const { pageSize = 0, current = 0 } = pagination;
- const { columnKey = '', order } = sorter;
+ const { order } = sorter;
const updatedOrder = order === 'ascend' ? 'asc' : 'desc';
const params = new URLSearchParams(window.location.search);
@@ -347,8 +340,7 @@ export const useTimelineTable = ({
`${pathname}?${createQueryParams({
...Object.fromEntries(params),
order: updatedOrder,
- offset: current - 1,
- orderParam: columnKey,
+ offset: current * TIMELINE_TABLE_PAGE_SIZE - TIMELINE_TABLE_PAGE_SIZE,
pageSize,
})}`,
);
@@ -357,10 +349,14 @@ export const useTimelineTable = ({
[pathname],
);
+ const offsetInt = parseInt(offset, 10);
+ const pageSize = params.get('pageSize') ?? String(TIMELINE_TABLE_PAGE_SIZE);
+ const pageSizeInt = parseInt(pageSize, 10);
+
const paginationConfig: TablePaginationConfig = {
- pageSize: TIMELINE_TABLE_PAGE_SIZE,
+ pageSize: pageSizeInt,
showTotal: PaginationInfoText,
- current: parseInt(updatedOffset, 10) + 1,
+ current: offsetInt / TIMELINE_TABLE_PAGE_SIZE + 1,
showSizeChanger: false,
hideOnSinglePage: true,
total: totalItems,
@@ -370,20 +366,16 @@ export const useTimelineTable = ({
};
export const useAlertRuleStatusToggle = ({
- state,
ruleId,
}: {
- state: string;
ruleId: string;
}): {
handleAlertStateToggle: (state: boolean) => void;
- isAlertRuleEnabled: boolean;
} => {
+ const { isAlertRuleDisabled, setIsAlertRuleDisabled } = useAlertRule();
const { notifications } = useNotifications();
- const isAlertRuleInitiallyEnabled = state !== 'disabled';
- const [isAlertRuleEnabled, setIsAlertRuleEnabled] = useState(
- isAlertRuleInitiallyEnabled,
- );
+
+ const queryClient = useQueryClient();
const handleError = useAxiosError();
const { mutate: toggleAlertState } = useMutation(
@@ -391,26 +383,29 @@ export const useAlertRuleStatusToggle = ({
patchAlert,
{
onMutate: () => {
- setIsAlertRuleEnabled((prev) => !prev);
+ setIsAlertRuleDisabled((prev) => !prev);
},
onSuccess: () => {
notifications.success({
- message: `Alert has been turned ${!isAlertRuleEnabled ? 'on' : 'off'}.`,
+ message: `Alert has been ${isAlertRuleDisabled ? 'enabled' : 'disabled'}.`,
});
},
onError: (error) => {
- setIsAlertRuleEnabled(isAlertRuleInitiallyEnabled);
+ queryClient.refetchQueries([REACT_QUERY_KEY.ALERT_RULE_DETAILS]);
handleError(error);
},
},
);
- const handleAlertStateToggle = (state: boolean): void => {
- const args = { id: parseInt(ruleId, 10), data: { disabled: !state } };
+ const handleAlertStateToggle = (): void => {
+ const args = {
+ id: parseInt(ruleId, 10),
+ data: { disabled: !isAlertRuleDisabled },
+ };
toggleAlertState(args);
};
- return { handleAlertStateToggle, isAlertRuleEnabled };
+ return { handleAlertStateToggle };
};
export const useAlertRuleDuplicate = ({
diff --git a/frontend/src/providers/Alert.tsx b/frontend/src/providers/Alert.tsx
new file mode 100644
index 00000000000..337eec9ba53
--- /dev/null
+++ b/frontend/src/providers/Alert.tsx
@@ -0,0 +1,43 @@
+import React, { createContext, useContext, useState } from 'react';
+
+interface AlertRuleContextType {
+ isAlertRuleDisabled: boolean | undefined;
+ setIsAlertRuleDisabled: React.Dispatch<
+ React.SetStateAction
+ >;
+}
+
+const AlertRuleContext = createContext(
+ undefined,
+);
+
+function AlertRuleProvider({
+ children,
+}: {
+ children: React.ReactNode;
+}): JSX.Element {
+ const [isAlertRuleDisabled, setIsAlertRuleDisabled] = useState<
+ boolean | undefined
+ >(undefined);
+
+ const value = React.useMemo(
+ () => ({ isAlertRuleDisabled, setIsAlertRuleDisabled }),
+ [isAlertRuleDisabled],
+ );
+
+ return (
+
+ {children}
+
+ );
+}
+
+export const useAlertRule = (): AlertRuleContextType => {
+ const context = useContext(AlertRuleContext);
+ if (context === undefined) {
+ throw new Error('useAlertRule must be used within an AlertRuleProvider');
+ }
+ return context;
+};
+
+export default AlertRuleProvider;