feat: add notifications troubleshooting tab (#16650)

This commit is contained in:
Marcin Tojek
2025-02-21 14:34:48 +01:00
committed by GitHub
parent fcc9b05d29
commit e8a7b7e8cb
4 changed files with 137 additions and 39 deletions
+4
View File
@@ -2297,6 +2297,10 @@ class ApiMethods {
return res.data;
};
postTestNotification = async () => {
await this.axios.post<void>("/api/v2/notifications/test");
};
requestOneTimePassword = async (
req: TypesGen.RequestOneTimePasscodeRequest,
) => {
@@ -4,7 +4,9 @@ import {
selectTemplatesByGroup,
systemNotificationTemplates,
} from "api/queries/notifications";
import { FeatureStageBadge } from "components/FeatureStageBadge/FeatureStageBadge";
import { Loader } from "components/Loader/Loader";
import { SettingsHeader } from "components/SettingsHeader/SettingsHeader";
import { TabLink, Tabs, TabsList } from "components/Tabs/Tabs";
import { useSearchParamsKey } from "hooks/useSearchParamsKey";
import { useDeploymentSettings } from "modules/management/DeploymentSettingsProvider";
@@ -14,9 +16,11 @@ import type { FC } from "react";
import { Helmet } from "react-helmet-async";
import { useQueries } from "react-query";
import { deploymentGroupHasParent } from "utils/deployOptions";
import { docs } from "utils/docs";
import { pageTitle } from "utils/page";
import OptionsTable from "../OptionsTable";
import { NotificationEvents } from "./NotificationEvents";
import { Troubleshooting } from "./Troubleshooting";
export const NotificationsPage: FC = () => {
const { deploymentConfig } = useDeploymentSettings();
@@ -40,48 +44,62 @@ export const NotificationsPage: FC = () => {
<Helmet>
<title>{pageTitle("Notifications Settings")}</title>
</Helmet>
<Section
title="Notifications"
<SettingsHeader
title={
<>
Notifications
<span css={{ position: "relative", top: "-6px" }}>
<FeatureStageBadge
contentType={"beta"}
size="lg"
css={{ marginBottom: "5px", fontSize: "0.75rem" }}
/>
</span>
</>
}
description="Control delivery methods for notifications on this deployment."
layout="fluid"
featureStage={"beta"}
>
<Tabs active={tabState.value}>
<TabsList>
<TabLink to="?tab=events" value="events">
Events
</TabLink>
<TabLink to="?tab=settings" value="settings">
Settings
</TabLink>
</TabsList>
</Tabs>
docsHref={docs("/admin/monitoring/notifications")}
/>
<Tabs active={tabState.value}>
<TabsList>
<TabLink to="?tab=events" value="events">
Events
</TabLink>
<TabLink to="?tab=settings" value="settings">
Settings
</TabLink>
<TabLink to="?tab=troubleshooting" value="troubleshooting">
Troubleshooting
</TabLink>
</TabsList>
</Tabs>
<div css={styles.content}>
{ready ? (
tabState.value === "events" ? (
<NotificationEvents
templatesByGroup={templatesByGroup.data}
deploymentConfig={deploymentConfig.config}
defaultMethod={castNotificationMethod(
dispatchMethods.data.default,
)}
availableMethods={dispatchMethods.data.available.map(
castNotificationMethod,
)}
/>
) : (
<OptionsTable
options={deploymentConfig.options.filter((o) =>
deploymentGroupHasParent(o.group, "Notifications"),
)}
/>
)
<div css={styles.content}>
{ready ? (
tabState.value === "events" ? (
<NotificationEvents
templatesByGroup={templatesByGroup.data}
deploymentConfig={deploymentConfig.config}
defaultMethod={castNotificationMethod(
dispatchMethods.data.default,
)}
availableMethods={dispatchMethods.data.available.map(
castNotificationMethod,
)}
/>
) : tabState.value === "troubleshooting" ? (
<Troubleshooting />
) : (
<Loader />
)}
</div>
</Section>
<OptionsTable
options={deploymentConfig.options.filter((o) =>
deploymentGroupHasParent(o.group, "Notifications"),
)}
/>
)
) : (
<Loader />
)}
</div>
</>
);
};
@@ -0,0 +1,29 @@
import type { Meta, StoryObj } from "@storybook/react";
import { spyOn, userEvent, within } from "@storybook/test";
import { API } from "api/api";
import { Troubleshooting } from "./Troubleshooting";
import { baseMeta } from "./storybookUtils";
const meta: Meta<typeof Troubleshooting> = {
title: "pages/DeploymentSettingsPage/NotificationsPage/Troubleshooting",
component: Troubleshooting,
...baseMeta,
};
export default meta;
type Story = StoryObj<typeof Troubleshooting>;
export const TestNotification: Story = {
play: async ({ canvasElement }) => {
spyOn(API, "postTestNotification").mockResolvedValue();
const user = userEvent.setup();
const canvas = within(canvasElement);
const sendButton = canvas.getByRole("button", {
name: "Send notification",
});
await user.click(sendButton);
await within(document.body).findByText("Test notification sent");
},
};
@@ -0,0 +1,47 @@
import { useTheme } from "@emotion/react";
import LoadingButton from "@mui/lab/LoadingButton";
import { API } from "api/api";
import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
import type { FC } from "react";
import { useMutation } from "react-query";
export const Troubleshooting: FC = () => {
const { mutate: sendTestNotificationApi, isLoading } = useMutation(
API.postTestNotification,
{
onSuccess: () => displaySuccess("Test notification sent"),
onError: () => displayError("Failed to send test notification"),
},
);
const theme = useTheme();
return (
<>
<div
css={{
fontSize: 14,
color: theme.palette.text.secondary,
lineHeight: "160%",
marginBottom: 16,
}}
>
Send a test notification to troubleshoot your notification settings.
</div>
<div>
<span>
<LoadingButton
variant="outlined"
loading={isLoading}
size="small"
css={{ minWidth: "auto", aspectRatio: "1" }}
onClick={() => {
sendTestNotificationApi();
}}
>
Send notification
</LoadingButton>
</span>
</div>
</>
);
};