From d15745a67f39a8267d824e78f00dd64ac1c893dc Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Thu, 12 Dec 2024 15:53:18 +0000 Subject: [PATCH 1/2] feat: display warning dialog if user switches off assign default org --- site/src/components/Button/Button.tsx | 7 +- site/src/components/Dialog/Dialog.tsx | 31 +++----- .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 79 ++++++++++++------- 3 files changed, 66 insertions(+), 51 deletions(-) diff --git a/site/src/components/Button/Button.tsx b/site/src/components/Button/Button.tsx index 8b83149e3bb1e..b0a460eca8a3c 100644 --- a/site/src/components/Button/Button.tsx +++ b/site/src/components/Button/Button.tsx @@ -8,7 +8,12 @@ import { type FC, forwardRef } from "react"; import { cn } from "utils/cn"; export const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-content-link disabled:pointer-events-none disabled:text-content-disabled [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 font-semibold border-solid cursor-pointer", + `inline-flex items-center justify-center gap-2 whitespace-nowrap + border-solid rounded-md transition-colors + text-sm font-semibold font-medium cursor-pointer + focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-content-link + disabled:pointer-events-none disabled:text-content-disabled + [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0`, { variants: { variant: { diff --git a/site/src/components/Dialog/Dialog.tsx b/site/src/components/Dialog/Dialog.tsx index dbcc0efc944cd..0770ec62ae735 100644 --- a/site/src/components/Dialog/Dialog.tsx +++ b/site/src/components/Dialog/Dialog.tsx @@ -3,7 +3,6 @@ * @see {@link https://ui.shadcn.com/docs/components/dialog} */ import * as DialogPrimitive from "@radix-ui/react-dialog"; -import { X } from "lucide-react"; import { type ComponentPropsWithoutRef, type ElementRef, @@ -46,29 +45,19 @@ export const DialogContent = forwardRef< {children} - - - Close - )); @@ -106,7 +95,7 @@ export const DialogTitle = forwardRef< (({ className, ...props }, ref) => ( )); diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index 470bf897fd90e..ae90e26c3aa7c 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -1,4 +1,3 @@ -import Skeleton from "@mui/material/Skeleton"; import Table from "@mui/material/Table"; import TableBody from "@mui/material/TableBody"; import TableCell from "@mui/material/TableCell"; @@ -12,6 +11,14 @@ import type { import { ErrorAlert } from "components/Alert/ErrorAlert"; import { Button } from "components/Button/Button"; import { ChooseOne, Cond } from "components/Conditionals/ChooseOne"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from "components/Dialog/Dialog"; import { EmptyState } from "components/EmptyState/EmptyState"; import { HelpTooltip, @@ -26,10 +33,6 @@ import { type Option, } from "components/MultiSelectCombobox/MultiSelectCombobox"; import { Switch } from "components/Switch/Switch"; -import { - TableLoaderSkeleton, - TableRowSkeleton, -} from "components/TableLoader/TableLoader"; import { useFormik } from "formik"; import { Plus, SquareArrowOutUpRight, Trash } from "lucide-react"; import { type FC, useState } from "react"; @@ -74,6 +77,7 @@ export const IdpOrgSyncPageView: FC = ({ const organizationMappingCount = form.values.mapping ? Object.entries(form.values.mapping).length : 0; + const [isDialogOpen, setIsDialogOpen] = useState(false); const getOrgNames = (orgIds: readonly string[]) => { return orgIds.map( @@ -136,11 +140,15 @@ export const IdpOrgSyncPageView: FC = ({ id={ORGANIZATION_ASSIGN_DEFAULT_ID} checked={form.values.organization_assign_default} onCheckedChange={async (checked) => { - void form.setFieldValue( - "organization_assign_default", - checked, - ); - form.handleSubmit(); + if (!checked) { + setIsDialogOpen(true); + } else { + void form.setFieldValue( + "organization_assign_default", + checked, + ); + form.handleSubmit(); + } }} /> @@ -234,6 +242,36 @@ export const IdpOrgSyncPageView: FC = ({ + + + + + + Switch off default organization assignment + + + Warning: This will remove all users from the default organization + unless otherwise specified in an organization mapping defined + below. + + + + + + + + ); }; @@ -318,31 +356,14 @@ const OrganizationRow: FC = ({ ); }; -const TableLoader = () => { - return ( - - - - - - - - - - - - - - ); -}; - export const AssignDefaultOrgHelpTooltip: FC = () => { return ( - Disabling will remove all users from the default organization. + Disabling will remove all users from the default organization if a + mapping for the default organization is not defined. From f97261d5d42e1e3b4e58ddaf4d5254c740ac1021 Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Thu, 12 Dec 2024 19:49:40 +0000 Subject: [PATCH 2/2] chore: update tests --- site/e2e/tests/deployment/idpOrgSync.spec.ts | 8 +++++++- .../IdpOrgSyncPageView.stories.tsx | 16 ++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/site/e2e/tests/deployment/idpOrgSync.spec.ts b/site/e2e/tests/deployment/idpOrgSync.spec.ts index 59fccb440400b..6d50969298301 100644 --- a/site/e2e/tests/deployment/idpOrgSync.spec.ts +++ b/site/e2e/tests/deployment/idpOrgSync.spec.ts @@ -78,7 +78,7 @@ test.describe("IdpOrgSyncPage", () => { ).toBeVisible(); }); - test("toggle default organization assignment", async ({ page }) => { + test("toggle off default organization assignment", async ({ page }) => { requiresLicense(); await page.goto("/deployment/idp-org-sync", { waitUntil: "domcontentloaded", @@ -89,6 +89,12 @@ test.describe("IdpOrgSyncPage", () => { }); await toggle.click(); + const dialog = page.getByRole("dialog"); + await expect(dialog).toBeVisible(); + + await dialog.getByRole("button", { name: "Confirm" }).click(); + await expect(dialog).not.toBeVisible(); + await expect( page.getByText("Organization sync settings updated."), ).toBeVisible(); diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx index 99742b82e6d17..8d02e1f248833 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx @@ -1,4 +1,5 @@ import type { Meta, StoryObj } from "@storybook/react"; +import { userEvent, within } from "@storybook/test"; import { MockOrganization, MockOrganization2, @@ -48,3 +49,18 @@ export const MissingGroups: Story = { organizationSyncSettings: MockOrganizationSyncSettings, }, }; + +export const AssignDefaultOrgWarningDialog: Story = { + args: { + organizationSyncSettings: MockOrganizationSyncSettings, + organizations: [MockOrganization, MockOrganization2], + }, + play: async ({ canvasElement }) => { + const canvas = within(canvasElement); + await userEvent.click( + canvas.getByRole("switch", { + name: "Assign Default Organization", + }), + ); + }, +};