mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add notifications troubleshooting tab (#16650)
This commit is contained in:
@@ -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>
|
||||
</>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user