From d9d4cc0b2c9c3ef3333a3c6448b8a401c7d4e977 Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Wed, 5 Feb 2025 18:02:54 +0000 Subject: [PATCH 1/6] feat: add combobox using claim field values --- .../IdpSyncPage/IdpGroupSyncForm.tsx | 54 +++++++++++++++---- .../IdpSyncPage/IdpRoleSyncForm.tsx | 54 +++++++++++++++---- .../IdpSyncPage/IdpSyncPage.tsx | 33 ++++++++++-- .../IdpSyncPage/IdpSyncPageView.tsx | 6 +++ 4 files changed, 126 insertions(+), 21 deletions(-) diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx index 9d63baf180fbc..3f8de7e4ad0db 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx @@ -6,6 +6,7 @@ import type { Organization, } from "api/typesGenerated"; import { Button } from "components/Button/Button"; +import { Combobox } from "components/Combobox/Combobox"; import { HelpTooltip, HelpTooltipContent, @@ -30,7 +31,7 @@ import { } from "components/Tooltip/Tooltip"; import { useFormik } from "formik"; import { Plus, Trash, TriangleAlert } from "lucide-react"; -import { type FC, useId, useState } from "react"; +import { type FC, useId, useState, type KeyboardEventHandler } from "react"; import { docs } from "utils/docs"; import { isUUID } from "utils/uuid"; import * as Yup from "yup"; @@ -70,6 +71,7 @@ interface IdpGroupSyncFormProps { legacyGroupMappingCount: number; organization: Organization; onSubmit: (data: GroupSyncSettings) => void; + onSyncFieldChange: (value: string) => void; } export const IdpGroupSyncForm: FC = ({ @@ -81,6 +83,7 @@ export const IdpGroupSyncForm: FC = ({ groupsMap, organization, onSubmit, + onSyncFieldChange, }) => { const form = useFormik({ initialValues: { @@ -97,6 +100,8 @@ export const IdpGroupSyncForm: FC = ({ const [idpGroupName, setIdpGroupName] = useState(""); const [coderGroups, setCoderGroups] = useState([]); const id = useId(); + const [comboInputValue, setComboInputValue] = useState(""); + const [open, setOpen] = useState(false); const getGroupNames = (groupIds: readonly string[]) => { return groupIds.map((groupId) => groupsMap.get(groupId) || groupId); @@ -116,6 +121,19 @@ export const IdpGroupSyncForm: FC = ({ form.handleSubmit(); }; + const handleKeyDown: KeyboardEventHandler = (event) => { + if ( + event.key === "Enter" && + comboInputValue && + !claimFieldValues?.some((value) => value === comboInputValue.toLowerCase()) + ) { + event.preventDefault(); + setIdpGroupName(comboInputValue); + setComboInputValue(""); + setOpen(false); + } + }; + return (
= ({ value={form.values.field} onChange={(event) => { void form.setFieldValue("field", event.target.value); + onSyncFieldChange(event.target.value); }} className="w-72" /> @@ -202,14 +221,31 @@ export const IdpGroupSyncForm: FC = ({ - { - setIdpGroupName(event.target.value); - }} - /> + {claimFieldValues ? ( + { + setIdpGroupName(value); + setOpen(false); + }} + /> + ) : ( + { + setIdpGroupName(event.target.value); + }} + /> + )}
From dd2a6fffe7ee4359613768589e001724b48969b1 Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Wed, 5 Feb 2025 19:25:40 +0000 Subject: [PATCH 2/6] chore: update to new table component --- site/src/components/Table/Table.tsx | 2 +- .../IdpOrgSyncPage/IdpOrgSyncPageView.tsx | 2 +- .../IdpSyncPage/IdpGroupSyncForm.tsx | 7 +- .../IdpSyncPage/IdpMappingTable.tsx | 85 +++++++++---------- .../IdpSyncPage/IdpRoleSyncForm.tsx | 7 +- 5 files changed, 51 insertions(+), 52 deletions(-) diff --git a/site/src/components/Table/Table.tsx b/site/src/components/Table/Table.tsx index 8daf0b57f91a7..604fc3d4f4196 100644 --- a/site/src/components/Table/Table.tsx +++ b/site/src/components/Table/Table.tsx @@ -68,7 +68,7 @@ export const TableRow = React.forwardRef< ref={ref} className={cn( "border-0 border-b border-solid border-border transition-colors", - "hover:bg-muted/50 data-[state=selected]:bg-muted", + "data-[state=selected]:bg-muted", className, )} {...props} diff --git a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx index bdcc65b89aaba..5871cf98f21a5 100644 --- a/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx +++ b/site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx @@ -367,7 +367,7 @@ const IdpMappingTable: FC = ({ isEmpty, children }) => { IdP organization Coder organization - + diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx index 3f8de7e4ad0db..d34180e18f3eb 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx @@ -1,5 +1,3 @@ -import TableCell from "@mui/material/TableCell"; -import TableRow from "@mui/material/TableRow"; import type { Group, GroupSyncSettings, @@ -29,6 +27,7 @@ import { TooltipProvider, TooltipTrigger, } from "components/Tooltip/Tooltip"; +import { TableCell, TableRow } from "components/Table/Table"; import { useFormik } from "formik"; import { Plus, Trash, TriangleAlert } from "lucide-react"; import { type FC, useId, useState, type KeyboardEventHandler } from "react"; @@ -125,7 +124,9 @@ export const IdpGroupSyncForm: FC = ({ if ( event.key === "Enter" && comboInputValue && - !claimFieldValues?.some((value) => value === comboInputValue.toLowerCase()) + !claimFieldValues?.some( + (value) => value === comboInputValue.toLowerCase(), + ) ) { event.preventDefault(); setIdpGroupName(comboInputValue); diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpMappingTable.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpMappingTable.tsx index c277c7a14e1c9..26db62e130459 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpMappingTable.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpMappingTable.tsx @@ -1,12 +1,13 @@ -import Table from "@mui/material/Table"; -import TableBody from "@mui/material/TableBody"; -import TableCell from "@mui/material/TableCell"; -import TableContainer from "@mui/material/TableContainer"; -import TableHead from "@mui/material/TableHead"; -import TableRow from "@mui/material/TableRow"; import { ChooseOne, Cond } from "components/Conditionals/ChooseOne"; import { EmptyState } from "components/EmptyState/EmptyState"; import { Link } from "components/Link/Link"; +import { + Table, + TableBody, + TableCell, + TableHeader, + TableRow, +} from "components/Table/Table"; import type { FC } from "react"; import { docs } from "utils/docs"; @@ -22,44 +23,40 @@ export const IdpMappingTable: FC = ({ children, }) => { return ( -
- - - - - IdP {type.toLocaleLowerCase()} - - Coder {type.toLocaleLowerCase()} - - - - - - - - - - - How to setup IdP {type.toLocaleLowerCase()} sync - - } - /> - - - - {children} - - -
-
+
+ + + + IdP {type.toLocaleLowerCase()} + Coder {type.toLocaleLowerCase()} + + + + + + + + + + How to setup IdP {type.toLocaleLowerCase()} sync + + } + /> + + + + {children} + + +
Showing {rowCount}{" "} diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx index 98bae0122b071..cc2bab6001c48 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx @@ -1,5 +1,3 @@ -import TableCell from "@mui/material/TableCell"; -import TableRow from "@mui/material/TableRow"; import type { Organization, Role, RoleSyncSettings } from "api/typesGenerated"; import { Button } from "components/Button/Button"; import { Combobox } from "components/Combobox/Combobox"; @@ -16,6 +14,7 @@ import { TooltipProvider, TooltipTrigger, } from "components/Tooltip/Tooltip"; +import { TableCell, TableRow } from "components/Table/Table"; import { useFormik } from "formik"; import { Plus, Trash, TriangleAlert } from "lucide-react"; import { type FC, type KeyboardEventHandler, useId, useState } from "react"; @@ -99,7 +98,9 @@ export const IdpRoleSyncForm: FC = ({ if ( event.key === "Enter" && comboInputValue && - !claimFieldValues?.some((value) => value === comboInputValue.toLowerCase()) + !claimFieldValues?.some( + (value) => value === comboInputValue.toLowerCase(), + ) ) { event.preventDefault(); setIdpRoleName(comboInputValue); From 48d885674eac71e844c7a19c8467107fd73a973e Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Wed, 5 Feb 2025 20:49:57 +0000 Subject: [PATCH 3/6] fix: fix text --- .../OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx | 2 +- .../OrganizationSettingsPage/IdpSyncPage/IdpMappingTable.tsx | 2 +- .../OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx index d34180e18f3eb..214bb21ee4a14 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx @@ -226,7 +226,7 @@ export const IdpGroupSyncForm: FC = ({ = ({
Showing {rowCount}{" "} - groups + {type.toLocaleLowerCase()}{(rowCount === 0 || rowCount > 1) && "s"}
diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx index cc2bab6001c48..173eb3f267376 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx @@ -167,7 +167,7 @@ export const IdpRoleSyncForm: FC = ({ Date: Wed, 5 Feb 2025 20:50:20 +0000 Subject: [PATCH 4/6] fix: format --- .../OrganizationSettingsPage/IdpSyncPage/IdpMappingTable.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpMappingTable.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpMappingTable.tsx index 1973d81d41155..07785038f9a73 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpMappingTable.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpMappingTable.tsx @@ -60,7 +60,8 @@ export const IdpMappingTable: FC = ({
Showing {rowCount}{" "} - {type.toLocaleLowerCase()}{(rowCount === 0 || rowCount > 1) && "s"} + {type.toLocaleLowerCase()} + {(rowCount === 0 || rowCount > 1) && "s"}
From 447cad7d09c4a70c2cb1f55af27f9924ec7b4d37 Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Fri, 7 Feb 2025 20:37:37 +0000 Subject: [PATCH 5/6] chore: cleanup --- .../IdpSyncPage/IdpGroupSyncForm.tsx | 4 +- .../IdpSyncPage/IdpRoleSyncForm.tsx | 2 +- .../IdpSyncPage/IdpSyncPage.tsx | 47 ++++++++++--------- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx index 214bb21ee4a14..506f003043f6e 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx @@ -21,16 +21,16 @@ import { } from "components/MultiSelectCombobox/MultiSelectCombobox"; import { Spinner } from "components/Spinner/Spinner"; import { Switch } from "components/Switch/Switch"; +import { TableCell, TableRow } from "components/Table/Table"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "components/Tooltip/Tooltip"; -import { TableCell, TableRow } from "components/Table/Table"; import { useFormik } from "formik"; import { Plus, Trash, TriangleAlert } from "lucide-react"; -import { type FC, useId, useState, type KeyboardEventHandler } from "react"; +import { type FC, type KeyboardEventHandler, useId, useState } from "react"; import { docs } from "utils/docs"; import { isUUID } from "utils/uuid"; import * as Yup from "yup"; diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx index 173eb3f267376..154f944e5b904 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx @@ -8,13 +8,13 @@ import { type Option, } from "components/MultiSelectCombobox/MultiSelectCombobox"; import { Spinner } from "components/Spinner/Spinner"; +import { TableCell, TableRow } from "components/Table/Table"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, } from "components/Tooltip/Tooltip"; -import { TableCell, TableRow } from "components/Table/Table"; import { useFormik } from "formik"; import { Plus, Trash, TriangleAlert } from "lucide-react"; import { type FC, type KeyboardEventHandler, useId, useState } from "react"; diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx index f0e98b6e68a5c..d14cf43b68fcb 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx @@ -17,7 +17,7 @@ import { Link } from "components/Link/Link"; import { Paywall } from "components/Paywall/Paywall"; import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility"; import { useOrganizationSettings } from "modules/management/OrganizationSettingsLayout"; -import { type FC, useState } from "react"; +import { type FC, useEffect, useState } from "react"; import { Helmet } from "react-helmet-async"; import { useMutation, useQueries, useQuery, useQueryClient } from "react-query"; import { useParams, useSearchParams } from "react-router-dom"; @@ -27,15 +27,15 @@ import IdpSyncPageView from "./IdpSyncPageView"; export const IdpSyncPage: FC = () => { const queryClient = useQueryClient(); + // IdP sync does not have its own entitlement and is based on templace_rbac + const { template_rbac: isIdpSyncEnabled } = useFeatureVisibility(); const { organization: organizationName } = useParams() as { organization: string; }; - const [groupClaimField, setGroupClaimField] = useState(""); - const [roleClaimField, setRoleClaimField] = useState(""); - // IdP sync does not have its own entitlement and is based on templace_rbac - const { template_rbac: isIdpSyncEnabled } = useFeatureVisibility(); const { organizations } = useOrganizationSettings(); const organization = organizations?.find((o) => o.name === organizationName); + const [groupField, setGroupField] = useState(""); + const [roleField, setRoleField] = useState(""); const [ groupIdpSyncSettingsQuery, @@ -48,7 +48,7 @@ export const IdpSyncPage: FC = () => { ...groupIdpSyncSettings(organizationName), onSuccess: (data: GroupSyncSettings) => { if (data?.field) { - setGroupClaimField(data.field); + setGroupField(data.field); } }, }, @@ -56,7 +56,7 @@ export const IdpSyncPage: FC = () => { ...roleIdpSyncSettings(organizationName), onSuccess: (data: RoleSyncSettings) => { if (data?.field) { - setRoleClaimField(data.field); + setRoleField(data.field); } }, }, @@ -65,12 +65,25 @@ export const IdpSyncPage: FC = () => { ], }); + useEffect(() => { + if (!groupIdpSyncSettingsQuery.data) { + return; + } + + setGroupField(groupIdpSyncSettingsQuery.data.field); + }, [groupIdpSyncSettingsQuery.data]); + + useEffect(() => { + if (!roleIdpSyncSettingsQuery.data) { + return; + } + + setRoleField(roleIdpSyncSettingsQuery.data.field); + }, [roleIdpSyncSettingsQuery.data]); + const [searchParams] = useSearchParams(); const tab = searchParams.get("tab") || "groups"; - const field = - tab === "groups" - ? groupIdpSyncSettingsQuery.data?.field - : roleIdpSyncSettingsQuery.data?.field; + const field = tab === "groups" ? groupField : roleField; const fieldValuesQuery = useQuery( field @@ -103,14 +116,6 @@ export const IdpSyncPage: FC = () => { } } - const handleGroupSyncFieldChange = (value: string) => { - setGroupClaimField(value); - }; - - const handleRoleSyncFieldChange = (value: string) => { - setRoleClaimField(value); - }; - return ( <> @@ -146,8 +151,8 @@ export const IdpSyncPage: FC = () => { groupsMap={groupsMap} roles={rolesQuery.data} organization={organization} - onGroupSyncFieldChange={handleGroupSyncFieldChange} - onRoleSyncFieldChange={handleRoleSyncFieldChange} + onGroupSyncFieldChange={setGroupField} + onRoleSyncFieldChange={setRoleField} error={error} onSubmitGroupSyncSettings={async (data) => { try { From 4356123f7ba6e94369c44c706278999194f02a0c Mon Sep 17 00:00:00 2001 From: Jaayden Halko Date: Fri, 7 Feb 2025 20:48:31 +0000 Subject: [PATCH 6/6] chore: more cleanup --- .../IdpSyncPage/IdpGroupSyncForm.tsx | 2 +- .../IdpSyncPage/IdpRoleSyncForm.tsx | 2 +- .../IdpSyncPage/IdpSyncPage.tsx | 18 ++---------------- 3 files changed, 4 insertions(+), 18 deletions(-) diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx index 506f003043f6e..5340ec99dda79 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx @@ -232,7 +232,7 @@ export const IdpGroupSyncForm: FC = ({ inputValue={comboInputValue} onInputChange={setComboInputValue} onKeyDown={handleKeyDown} - onSelect={(value: string) => { + onSelect={(value) => { setIdpGroupName(value); setOpen(false); }} diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx index 154f944e5b904..faeaf0773dffd 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx @@ -173,7 +173,7 @@ export const IdpRoleSyncForm: FC = ({ inputValue={comboInputValue} onInputChange={setComboInputValue} onKeyDown={handleKeyDown} - onSelect={(value: string) => { + onSelect={(value) => { setIdpRoleName(value); setOpen(false); }} diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx index d14cf43b68fcb..769510d4bf22f 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx @@ -44,22 +44,8 @@ export const IdpSyncPage: FC = () => { rolesQuery, ] = useQueries({ queries: [ - { - ...groupIdpSyncSettings(organizationName), - onSuccess: (data: GroupSyncSettings) => { - if (data?.field) { - setGroupField(data.field); - } - }, - }, - { - ...roleIdpSyncSettings(organizationName), - onSuccess: (data: RoleSyncSettings) => { - if (data?.field) { - setRoleField(data.field); - } - }, - }, + groupIdpSyncSettings(organizationName), + roleIdpSyncSettings(organizationName), groupsByOrganization(organizationName), organizationRoles(organizationName), ], pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy