diff --git a/site/src/api/api.ts b/site/src/api/api.ts index 3da968bd8aa69..0bdd0cfac892f 100644 --- a/site/src/api/api.ts +++ b/site/src/api/api.ts @@ -2297,6 +2297,10 @@ class ApiMethods { return res.data; }; + postTestNotification = async () => { + await this.axios.post("/api/v2/notifications/test"); + }; + requestOneTimePassword = async ( req: TypesGen.RequestOneTimePasscodeRequest, ) => { diff --git a/site/src/pages/DeploymentSettingsPage/NotificationsPage/NotificationsPage.tsx b/site/src/pages/DeploymentSettingsPage/NotificationsPage/NotificationsPage.tsx index 23f8e6b42651e..a68013b0bfef3 100644 --- a/site/src/pages/DeploymentSettingsPage/NotificationsPage/NotificationsPage.tsx +++ b/site/src/pages/DeploymentSettingsPage/NotificationsPage/NotificationsPage.tsx @@ -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 = () => { {pageTitle("Notifications Settings")} -
+ Notifications + + + + + } description="Control delivery methods for notifications on this deployment." - layout="fluid" - featureStage={"beta"} - > - - - - Events - - - Settings - - - + docsHref={docs("/admin/monitoring/notifications")} + /> + + + + Events + + + Settings + + + Troubleshooting + + + -
- {ready ? ( - tabState.value === "events" ? ( - - ) : ( - - deploymentGroupHasParent(o.group, "Notifications"), - )} - /> - ) +
+ {ready ? ( + tabState.value === "events" ? ( + + ) : tabState.value === "troubleshooting" ? ( + ) : ( - - )} -
-
+ + deploymentGroupHasParent(o.group, "Notifications"), + )} + /> + ) + ) : ( + + )} + ); }; diff --git a/site/src/pages/DeploymentSettingsPage/NotificationsPage/Troubleshooting.stories.tsx b/site/src/pages/DeploymentSettingsPage/NotificationsPage/Troubleshooting.stories.tsx new file mode 100644 index 0000000000000..052e855b284a9 --- /dev/null +++ b/site/src/pages/DeploymentSettingsPage/NotificationsPage/Troubleshooting.stories.tsx @@ -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 = { + title: "pages/DeploymentSettingsPage/NotificationsPage/Troubleshooting", + component: Troubleshooting, + ...baseMeta, +}; + +export default meta; + +type Story = StoryObj; + +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"); + }, +}; diff --git a/site/src/pages/DeploymentSettingsPage/NotificationsPage/Troubleshooting.tsx b/site/src/pages/DeploymentSettingsPage/NotificationsPage/Troubleshooting.tsx new file mode 100644 index 0000000000000..c9a4362427cf7 --- /dev/null +++ b/site/src/pages/DeploymentSettingsPage/NotificationsPage/Troubleshooting.tsx @@ -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 ( + <> +
+ Send a test notification to troubleshoot your notification settings. +
+
+ + { + sendTestNotificationApi(); + }} + > + Send notification + + +
+ + ); +};