Skip to content

Commit

Permalink
fix: properly handle preserving alert toggle between overview and his…
Browse files Browse the repository at this point in the history
…tory tabs
  • Loading branch information
ahmadshaheer committed Sep 4, 2024
1 parent 9381730 commit df46918
Show file tree
Hide file tree
Showing 5 changed files with 98 additions and 52 deletions.
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 @@ -14,6 +14,7 @@ import {
useAlertRuleStatusToggle,
} from 'pages/AlertDetails/hooks';
import CopyToClipboard from 'periscope/components/CopyToClipboard';
import { useAlertRule } from 'providers/Alert';
import React, { useCallback, useState } from 'react';
import { AlertDef } from 'types/api/alerts/def';

Expand Down Expand Up @@ -49,19 +50,14 @@ function DropdownMenuRenderer(

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,
Expand Down Expand Up @@ -101,12 +97,14 @@ function AlertActionButtons({

return (
<div className="alert-action-buttons">
<Tooltip title={!isAlertRuleEnabled ? 'Enable alert' : 'Disable alert'}>
<Switch
size="small"
onChange={handleAlertStateToggle}
checked={isAlertRuleEnabled}
/>
<Tooltip title={isAlertRuleDisabled ? 'Enable alert' : 'Disable alert'}>
{isAlertRuleDisabled !== undefined && (
<Switch
size="small"
onChange={handleAlertStateToggle}
checked={!isAlertRuleDisabled}
/>
)}
</Tooltip>
<CopyToClipboard textToCopy={window.location.href} />

Expand Down
20 changes: 13 additions & 7 deletions frontend/src/pages/AlertDetails/AlertHeader/AlertHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import './AlertHeader.styles.scss';

import { useMemo } from 'react';
import { useAlertRule } from 'providers/Alert';
import { useEffect, useMemo } from 'react';

import AlertActionButtons from './ActionButtons/ActionButtons';
import AlertLabels from './AlertLabels/AlertLabels';
Expand All @@ -13,10 +14,11 @@ export type AlertHeaderProps = {
alert: string;
id: string;
labels: Record<string, string>;
disabled: boolean;
};
};
function AlertHeader({ alertDetails }: AlertHeaderProps): JSX.Element {
const { state, alert, labels } = alertDetails;
const { state, alert, labels, disabled } = alertDetails;

const labelsWithoutSeverity = useMemo(
() =>
Expand All @@ -26,6 +28,14 @@ function AlertHeader({ alertDetails }: AlertHeaderProps): JSX.Element {
[labels],
);

const { isAlertRuleDisabled, setIsAlertRuleDisabled } = useAlertRule();

useEffect(() => {
if (isAlertRuleDisabled === undefined) {
setIsAlertRuleDisabled(disabled);
}
}, [disabled, setIsAlertRuleDisabled, isAlertRuleDisabled]);

return (
<div className="alert-info">
<div className="alert-info__info-wrapper">
Expand All @@ -47,11 +57,7 @@ function AlertHeader({ alertDetails }: AlertHeaderProps): JSX.Element {
</div>
</div>
<div className="alert-info__action-buttons">
<AlertActionButtons
alertDetails={alertDetails}
ruleId={alertDetails.id}
state={state}
/>
<AlertActionButtons alertDetails={alertDetails} ruleId={alertDetails.id} />
</div>
</div>
);
Expand Down
28 changes: 12 additions & 16 deletions frontend/src/pages/AlertDetails/hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ 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 { 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';
Expand Down Expand Up @@ -363,20 +364,14 @@ 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();
Expand All @@ -386,28 +381,29 @@ export const useAlertRuleStatusToggle = ({
patchAlert,
{
onMutate: () => {
setIsAlertRuleEnabled((prev) => !prev);
setIsAlertRuleDisabled((prev) => !prev);
},
onSuccess: () => {
notifications.success({
message: `Alert has been ${!isAlertRuleEnabled ? 'enabled' : 'disabled'}.`,
message: `Alert has been ${isAlertRuleDisabled ? 'enabled' : 'disabled'}.`,
});

queryClient.refetchQueries([REACT_QUERY_KEY.ALERT_RULE_DETAILS]);
},
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 = ({
Expand Down
43 changes: 43 additions & 0 deletions frontend/src/providers/Alert.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React, { createContext, useContext, useState } from 'react';

interface AlertRuleContextType {
isAlertRuleDisabled: boolean | undefined;
setIsAlertRuleDisabled: React.Dispatch<
React.SetStateAction<boolean | undefined>
>;
}

const AlertRuleContext = createContext<AlertRuleContextType | undefined>(
undefined,
);

function AlertRuleProvider({
children,
}: {
children: React.ReactNode;
}): JSX.Element {
const [isAlertRuleDisabled, setIsAlertRuleDisabled] = useState<
boolean | undefined
>(undefined);

const value = React.useMemo(
() => ({ isAlertRuleDisabled, setIsAlertRuleDisabled }),
[isAlertRuleDisabled],
);

return (
<AlertRuleContext.Provider value={value}>
{children}
</AlertRuleContext.Provider>
);
}

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;

0 comments on commit df46918

Please sign in to comment.