From b2c3e11f679e5ab36782605f1198557d7a48d676 Mon Sep 17 00:00:00 2001
From: Jaayden Halko
Date: Fri, 30 Aug 2024 20:11:44 +0000
Subject: [PATCH 01/14] feat: initial commit for idp skeleton page
---
site/src/components/EmptyState/EmptyState.tsx | 6 +-
.../IdpSyncPage/IdpSyncPage.tsx | 83 ++++++++
.../IdpSyncPage/IdpSyncPageView.tsx | 181 ++++++++++++++++++
.../ManagementSettingsPage/SidebarView.tsx | 7 +
site/src/router.tsx | 4 +
5 files changed, 279 insertions(+), 2 deletions(-)
create mode 100644 site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage.tsx
create mode 100644 site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
diff --git a/site/src/components/EmptyState/EmptyState.tsx b/site/src/components/EmptyState/EmptyState.tsx
index c34f634d71bab..a6d27169b9fce 100644
--- a/site/src/components/EmptyState/EmptyState.tsx
+++ b/site/src/components/EmptyState/EmptyState.tsx
@@ -7,6 +7,7 @@ export interface EmptyStateProps extends HTMLAttributes {
description?: string | ReactNode;
cta?: ReactNode;
image?: ReactNode;
+ isCompact?: boolean;
}
/**
@@ -19,6 +20,7 @@ export const EmptyState: FC = ({
description,
cta,
image,
+ isCompact,
...attrs
}) => {
return (
@@ -30,8 +32,8 @@ export const EmptyState: FC = ({
justifyContent: "center",
alignItems: "center",
textAlign: "center",
- minHeight: 360,
- padding: "80px 40px",
+ minHeight: isCompact ? 180 : 360,
+ padding: isCompact ? "10px 40px" : "80px 40px",
position: "relative",
}}
{...attrs}
diff --git a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage.tsx b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage.tsx
new file mode 100644
index 0000000000000..07a6dc7485839
--- /dev/null
+++ b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage.tsx
@@ -0,0 +1,83 @@
+import AddIcon from "@mui/icons-material/AddOutlined";
+import LaunchOutlined from "@mui/icons-material/LaunchOutlined";
+import Button from "@mui/material/Button";
+import { getErrorMessage } from "api/errors";
+import { organizationPermissions } from "api/queries/organizations";
+import { organizationRoles } from "api/queries/roles";
+import { displayError, displaySuccess } from "components/GlobalSnackbar/utils";
+import { Loader } from "components/Loader/Loader";
+import { SettingsHeader } from "components/SettingsHeader/SettingsHeader";
+import { Stack } from "components/Stack/Stack";
+import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility";
+import { type FC, useEffect, useState } from "react";
+import { Helmet } from "react-helmet-async";
+import { useQuery, useQueryClient } from "react-query";
+import { Link as RouterLink, useParams } from "react-router-dom";
+import { pageTitle } from "utils/page";
+import { useOrganizationSettings } from "../ManagementSettingsLayout";
+import { docs } from "utils/docs";
+import IdpSyncPageView from "./IdpSyncPageView";
+
+export const IdpSyncPage: FC = () => {
+ const queryClient = useQueryClient();
+ // const { custom_roles: isCustomRolesEnabled } = useFeatureVisibility();
+ const { organization: organizationName } = useParams() as {
+ organization: string;
+ };
+ const { organizations } = useOrganizationSettings();
+ const organization = organizations?.find((o) => o.name === organizationName);
+ const permissionsQuery = useQuery(organizationPermissions(organization?.id));
+ const organizationRolesQuery = useQuery(organizationRoles(organizationName));
+ const permissions = permissionsQuery.data;
+
+ useEffect(() => {
+ if (organizationRolesQuery.error) {
+ displayError(
+ getErrorMessage(
+ organizationRolesQuery.error,
+ "Error loading custom roles.",
+ ),
+ );
+ }
+ }, [organizationRolesQuery.error]);
+
+ if (!permissions) {
+ return ;
+ }
+
+ return (
+ <>
+
+ {pageTitle("IdP Sync")}
+
+
+
+
+
+ }
+ component="a"
+ href={docs("/cli/server#--notifications-webhook-endpoint")}
+ target="_blank"
+ >
+ Setup IdP Sync
+
+ } to="export">
+ Export Policy
+
+
+
+
+
+ >
+ );
+};
+
+export default IdpSyncPage;
diff --git a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
new file mode 100644
index 0000000000000..d4503810cba2d
--- /dev/null
+++ b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
@@ -0,0 +1,181 @@
+import type { Interpolation, Theme } from "@emotion/react";
+import LaunchOutlined from "@mui/icons-material/LaunchOutlined";
+import Button from "@mui/material/Button";
+import Skeleton from "@mui/material/Skeleton";
+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 type { Role } from "api/typesGenerated";
+import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
+import { EmptyState } from "components/EmptyState/EmptyState";
+import { Paywall } from "components/Paywall/Paywall";
+import { Stack } from "components/Stack/Stack";
+import {
+ TableLoaderSkeleton,
+ TableRowSkeleton,
+} from "components/TableLoader/TableLoader";
+import type { FC } from "react";
+import { docs } from "utils/docs";
+
+export type IdpSyncPageViewProps = {
+ roles: Role[] | undefined;
+};
+
+export const IdpSyncPageView: FC = ({ roles }) => {
+ return (
+ <>
+
+
+
+
+
+
+ {/* Semantically fieldset is used for forms. In the future this screen will allow
+ updates to these fields in a form */}
+
+
+
+
+
+
+
+
+
+ >
+ );
+};
+
+interface RoleTableProps {
+ roles: Role[] | undefined;
+}
+
+const RoleTable: FC = ({ roles }) => {
+ const isLoading = false;
+ const isEmpty = Boolean(roles && roles.length === 0);
+ return (
+
+
+
+
+ Idp Role
+ Coder Role
+
+
+
+
+
+
+
+
+
+
+
+ }
+ component="a"
+ href={docs(
+ "/cli/server#--notifications-webhook-endpoint",
+ )}
+ target="_blank"
+ >
+ How to setup IdP role sync
+
+ }
+ />
+
+
+
+
+
+ {roles?.map((role) => (
+
+ ))}
+
+
+
+
+
+ );
+};
+
+interface RoleRowProps {
+ role: Role;
+}
+
+const RoleRow: FC = ({ role }) => {
+ return (
+
+ {role.display_name || role.name}
+ test
+
+ );
+};
+
+const TableLoader = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+const styles = {
+ secondary: (theme) => ({
+ color: theme.palette.text.secondary,
+ }),
+ fields: (theme) => ({
+ marginBottom: "60px",
+ }),
+ legend: (theme) => ({
+ padding: "0px 6px",
+ fontWeight: 600,
+ }),
+ box: (theme) => ({
+ border: "1px solid",
+ borderColor: theme.palette.divider,
+ padding: "0px 20px",
+ borderRadius: 8,
+ }),
+} satisfies Record>;
+
+export default IdpSyncPageView;
diff --git a/site/src/pages/ManagementSettingsPage/SidebarView.tsx b/site/src/pages/ManagementSettingsPage/SidebarView.tsx
index d635279a4d94a..7b0cce8468573 100644
--- a/site/src/pages/ManagementSettingsPage/SidebarView.tsx
+++ b/site/src/pages/ManagementSettingsPage/SidebarView.tsx
@@ -282,6 +282,13 @@ const OrganizationSettingsNavigation: FC<
Provisioners
)}
+ {organization.permissions.editMembers && (
+
+ Idp Sync
+
+ )}
)}
>
diff --git a/site/src/router.tsx b/site/src/router.tsx
index a85cdb9a31bfb..c5c9e68f0f314 100644
--- a/site/src/router.tsx
+++ b/site/src/router.tsx
@@ -247,6 +247,9 @@ const OrganizationCustomRolesPage = lazy(
() =>
import("./pages/ManagementSettingsPage/CustomRolesPage/CustomRolesPage"),
);
+const OrganizationIdPSyncPage = lazy(
+ () => import("./pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage"),
+);
const CreateEditRolePage = lazy(
() =>
import("./pages/ManagementSettingsPage/CustomRolesPage/CreateEditRolePage"),
@@ -406,6 +409,7 @@ export const router = createBrowserRouter(
path="provisioners"
element={}
/>
+ } />
From 2de6bfcdf4210201cba2ffca3bfa5acb90bc00f9 Mon Sep 17 00:00:00 2001
From: Jaayden Halko
Date: Sun, 1 Sep 2024 19:21:52 +0000
Subject: [PATCH 02/14] feat: add optional tooltip icon to settings header
---
.../SettingsHeader/SettingsHeader.tsx | 45 ++++++++++---------
1 file changed, 25 insertions(+), 20 deletions(-)
diff --git a/site/src/components/SettingsHeader/SettingsHeader.tsx b/site/src/components/SettingsHeader/SettingsHeader.tsx
index 954c7b6a64341..ea68415cc1e5b 100644
--- a/site/src/components/SettingsHeader/SettingsHeader.tsx
+++ b/site/src/components/SettingsHeader/SettingsHeader.tsx
@@ -9,6 +9,7 @@ interface HeaderProps {
description?: ReactNode;
secondary?: boolean;
docsHref?: string;
+ tooltip?: ReactNode;
}
export const SettingsHeader: FC = ({
@@ -16,32 +17,36 @@ export const SettingsHeader: FC = ({
description,
docsHref,
secondary,
+ tooltip,
}) => {
const theme = useTheme();
return (
-
- {title}
-
+
+
+ {title}
+
+ {tooltip}
+
{description && (
Date: Sun, 1 Sep 2024 19:22:47 +0000
Subject: [PATCH 03/14] feat: add help tooltip
---
.../IdpSyncPage/IdpSyncHelpTooltip.tsx | 31 +++++++++++++++++++
.../IdpSyncPage/IdpSyncPage.tsx | 6 ++--
.../IdpSyncPage/IdpSyncPageView.tsx | 4 +--
.../ManagementSettingsPage/SidebarView.tsx | 2 +-
4 files changed, 37 insertions(+), 6 deletions(-)
create mode 100644 site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncHelpTooltip.tsx
diff --git a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncHelpTooltip.tsx b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncHelpTooltip.tsx
new file mode 100644
index 0000000000000..d2907e4d192f7
--- /dev/null
+++ b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncHelpTooltip.tsx
@@ -0,0 +1,31 @@
+import {
+ HelpTooltip,
+ HelpTooltipContent,
+ HelpTooltipLink,
+ HelpTooltipLinksGroup,
+ HelpTooltipText,
+ HelpTooltipTitle,
+ HelpTooltipTrigger,
+} from "components/HelpTooltip/HelpTooltip";
+import type { FC } from "react";
+import { docs } from "utils/docs";
+
+export const IdpSyncHelpTooltip: FC = () => {
+ return (
+
+
+
+ What is IdP Sync?
+
+ View the current mappings between your external OIDC provider and
+ Coder. Use the Coder CLI to configure these mappings.
+
+
+
+ Configure IdP Sync
+
+
+
+
+ );
+};
diff --git a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage.tsx b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage.tsx
index 07a6dc7485839..a115cd2f61406 100644
--- a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage.tsx
+++ b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage.tsx
@@ -13,9 +13,10 @@ import { type FC, useEffect, useState } from "react";
import { Helmet } from "react-helmet-async";
import { useQuery, useQueryClient } from "react-query";
import { Link as RouterLink, useParams } from "react-router-dom";
+import { docs } from "utils/docs";
import { pageTitle } from "utils/page";
import { useOrganizationSettings } from "../ManagementSettingsLayout";
-import { docs } from "utils/docs";
+import { IdpSyncHelpTooltip } from "./IdpSyncHelpTooltip";
import IdpSyncPageView from "./IdpSyncPageView";
export const IdpSyncPage: FC = () => {
@@ -59,12 +60,13 @@ export const IdpSyncPage: FC = () => {
}
/>
}
component="a"
- href={docs("/cli/server#--notifications-webhook-endpoint")}
+ href={docs("/admin/auth#group-sync-enterprise")}
target="_blank"
>
Setup IdP Sync
diff --git a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
index d4503810cba2d..9df60a75e75f1 100644
--- a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
+++ b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
@@ -103,9 +103,7 @@ const RoleTable: FC = ({ roles }) => {
}
component="a"
- href={docs(
- "/cli/server#--notifications-webhook-endpoint",
- )}
+ href={docs("/admin/auth#group-sync-enterprise")}
target="_blank"
>
How to setup IdP role sync
diff --git a/site/src/pages/ManagementSettingsPage/SidebarView.tsx b/site/src/pages/ManagementSettingsPage/SidebarView.tsx
index 7b0cce8468573..795458794bc53 100644
--- a/site/src/pages/ManagementSettingsPage/SidebarView.tsx
+++ b/site/src/pages/ManagementSettingsPage/SidebarView.tsx
@@ -286,7 +286,7 @@ const OrganizationSettingsNavigation: FC<
- Idp Sync
+ IdP Sync
)}
From a75ad856e5eaf97d5d541da297c40826e97b08d4 Mon Sep 17 00:00:00 2001
From: Jaayden Halko
Date: Mon, 2 Sep 2024 18:16:47 +0000
Subject: [PATCH 04/14] feat: add mock data and update pageview for mock data
---
.../IdpSyncPage/IdpSyncPage.tsx | 34 ++++-
.../IdpSyncPage/IdpSyncPageView.tsx | 122 +++++++++++++-----
2 files changed, 122 insertions(+), 34 deletions(-)
diff --git a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage.tsx b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage.tsx
index a115cd2f61406..f48a775625be9 100644
--- a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage.tsx
+++ b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPage.tsx
@@ -19,6 +19,38 @@ import { useOrganizationSettings } from "../ManagementSettingsLayout";
import { IdpSyncHelpTooltip } from "./IdpSyncHelpTooltip";
import IdpSyncPageView from "./IdpSyncPageView";
+const mockOIDCConfig = {
+ allow_signups: true,
+ client_id: "test",
+ client_secret: "test",
+ client_key_file: "test",
+ client_cert_file: "test",
+ email_domain: [],
+ issuer_url: "test",
+ scopes: [],
+ ignore_email_verified: true,
+ username_field: "",
+ name_field: "",
+ email_field: "",
+ auth_url_params: {},
+ ignore_user_info: true,
+ organization_field: "",
+ organization_mapping: {},
+ organization_assign_default: true,
+ group_auto_create: false,
+ group_regex_filter: "^Coder-.*$",
+ group_allow_list: [],
+ groups_field: "groups",
+ group_mapping: { group1: "developers", group2: "admin", group3: "auditors" },
+ user_role_field: "roles",
+ user_role_mapping: { role1: ["role1", "role2"] },
+ user_roles_default: [],
+ sign_in_text: "",
+ icon_url: "",
+ signups_disabled_text: "string",
+ skip_issuer_checks: true,
+};
+
export const IdpSyncPage: FC = () => {
const queryClient = useQueryClient();
// const { custom_roles: isCustomRolesEnabled } = useFeatureVisibility();
@@ -77,7 +109,7 @@ export const IdpSyncPage: FC = () => {
-
+
>
);
};
diff --git a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
index 9df60a75e75f1..47e43d4921753 100644
--- a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
+++ b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
@@ -8,7 +8,7 @@ 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 type { Role } from "api/typesGenerated";
+import type { OIDCConfig } from "api/typesGenerated";
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne";
import { EmptyState } from "components/EmptyState/EmptyState";
import { Paywall } from "components/Paywall/Paywall";
@@ -21,10 +21,10 @@ import type { FC } from "react";
import { docs } from "utils/docs";
export type IdpSyncPageViewProps = {
- roles: Role[] | undefined;
+ oidcConfig: OIDCConfig | undefined;
};
-export const IdpSyncPageView: FC = ({ roles }) => {
+export const IdpSyncPageView: FC = ({ oidcConfig }) => {
return (
<>
@@ -43,24 +43,66 @@ export const IdpSyncPageView: FC = ({ roles }) => {
Sync Field
- groups
+ {oidcConfig?.groups_field}
Regex Filter
- ^Coder-.*$
+ {oidcConfig?.group_regex_filter}
Auto Create
- false
+
+ {oidcConfig?.group_auto_create.toString()}
+
-
-
-
+
+
+ <>
+ {oidcConfig?.user_role_mapping &&
+ Object.entries(oidcConfig.user_role_mapping).map(
+ ([idpRole, roles]) => (
+
+ ),
+ )}
+ >
+
+
+ <>
+ {oidcConfig?.user_role_mapping &&
+ Object.entries(oidcConfig.group_mapping).map(
+ ([idpGroup, group]) => (
+
+ ),
+ )}
+ >
+
@@ -68,20 +110,26 @@ export const IdpSyncPageView: FC = ({ roles }) => {
);
};
-interface RoleTableProps {
- roles: Role[] | undefined;
+interface IdpMappingTableProps {
+ type: "Role" | "Group";
+ isEmpty: boolean;
+ children: React.ReactNode;
}
-const RoleTable: FC = ({ roles }) => {
+const IdpMappingTable: FC = ({
+ type,
+ isEmpty,
+ children,
+}) => {
const isLoading = false;
- const isEmpty = Boolean(roles && roles.length === 0);
+
return (
- Idp Role
- Coder Role
+ Idp {type}
+ Coder {type}
@@ -94,10 +142,7 @@ const RoleTable: FC = ({ roles }) => {
= ({ roles }) => {
href={docs("/admin/auth#group-sync-enterprise")}
target="_blank"
>
- How to setup IdP role sync
+ How to setup IdP {type} sync
}
/>
@@ -114,11 +159,7 @@ const RoleTable: FC = ({ roles }) => {
-
- {roles?.map((role) => (
-
- ))}
-
+ {children}
@@ -126,15 +167,30 @@ const RoleTable: FC = ({ roles }) => {
);
};
+interface GroupRowProps {
+ idpGroup: string;
+ coderGroup: string;
+}
+
+const GroupRow: FC = ({ idpGroup, coderGroup }) => {
+ return (
+
+ {idpGroup}
+ {coderGroup}
+
+ );
+};
+
interface RoleRowProps {
- role: Role;
+ idpRole: string;
+ coderRoles: ReadonlyArray;
}
-const RoleRow: FC = ({ role }) => {
+const RoleRow: FC = ({ idpRole, coderRoles }) => {
return (
-
- {role.display_name || role.name}
- test
+
+ {idpRole}
+ coderRoles Placeholder
);
};
@@ -161,10 +217,10 @@ const styles = {
secondary: (theme) => ({
color: theme.palette.text.secondary,
}),
- fields: (theme) => ({
+ fields: () => ({
marginBottom: "60px",
}),
- legend: (theme) => ({
+ legend: () => ({
padding: "0px 6px",
fontWeight: 600,
}),
From 492ca5fbb4f6f8a8649d9e1acf339b478aae312d Mon Sep 17 00:00:00 2001
From: Jaayden Halko
Date: Mon, 2 Sep 2024 18:57:33 +0000
Subject: [PATCH 05/14] feat: initial stories
---
.../IdpSyncPage/IdpSyncPageView.stories.tsx | 19 +++++++++++
site/src/testHelpers/entities.ts | 32 +++++++++++++++++++
2 files changed, 51 insertions(+)
create mode 100644 site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.stories.tsx
diff --git a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.stories.tsx b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.stories.tsx
new file mode 100644
index 0000000000000..47952edc61c95
--- /dev/null
+++ b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.stories.tsx
@@ -0,0 +1,19 @@
+import type { Meta, StoryObj } from "@storybook/react";
+import { MockOIDCConfig } from "testHelpers/entities";
+import { IdpSyncPageView } from "./IdpSyncPageView";
+
+const meta: Meta = {
+ title: "pages/OrganizationIdpSyncPage",
+ component: IdpSyncPageView,
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Empty: Story = {
+ args: { oidcConfig: undefined },
+};
+
+export const Default: Story = {
+ args: { oidcConfig: MockOIDCConfig },
+};
diff --git a/site/src/testHelpers/entities.ts b/site/src/testHelpers/entities.ts
index 3948dc148927a..f77bae6c5a1b4 100644
--- a/site/src/testHelpers/entities.ts
+++ b/site/src/testHelpers/entities.ts
@@ -451,6 +451,38 @@ export const MockAssignableSiteRoles = [
assignableRole(MockAuditorRole, true),
];
+export const MockOIDCConfig: TypesGen.OIDCConfig = {
+ allow_signups: true,
+ client_id: "test",
+ client_secret: "test",
+ client_key_file: "test",
+ client_cert_file: "test",
+ email_domain: [],
+ issuer_url: "test",
+ scopes: [],
+ ignore_email_verified: true,
+ username_field: "",
+ name_field: "",
+ email_field: "",
+ auth_url_params: {},
+ ignore_user_info: true,
+ organization_field: "",
+ organization_mapping: {},
+ organization_assign_default: true,
+ group_auto_create: false,
+ group_regex_filter: "^Coder-.*$",
+ group_allow_list: [],
+ groups_field: "groups",
+ group_mapping: { group1: "developers", group2: "admin", group3: "auditors" },
+ user_role_field: "roles",
+ user_role_mapping: { role1: ["role1", "role2"] },
+ user_roles_default: [],
+ sign_in_text: "",
+ icon_url: "",
+ signups_disabled_text: "string",
+ skip_issuer_checks: true,
+};
+
export const MockMemberPermissions = {
viewAuditLog: false,
};
From b73ad32b8b839ac5f28ab2bbd0ff0624839560df Mon Sep 17 00:00:00 2001
From: Jaayden Halko
Date: Mon, 2 Sep 2024 18:57:48 +0000
Subject: [PATCH 06/14] feat: error circle
---
.../IdpSyncPage/IdpSyncPageView.tsx | 69 +++++++++++++++++--
1 file changed, 62 insertions(+), 7 deletions(-)
diff --git a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
index 47e43d4921753..ab4c59c600d8e 100644
--- a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
+++ b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
@@ -1,4 +1,5 @@
import type { Interpolation, Theme } from "@emotion/react";
+import { useTheme } from "@emotion/react";
import LaunchOutlined from "@mui/icons-material/LaunchOutlined";
import Button from "@mui/material/Button";
import Skeleton from "@mui/material/Skeleton";
@@ -24,7 +25,34 @@ export type IdpSyncPageViewProps = {
oidcConfig: OIDCConfig | undefined;
};
+type CircleProps = {
+ color: string;
+ variant?: "solid" | "outlined";
+};
+
+const Circle: FC = ({ color, variant = "solid" }) => {
+ return (
+
+ );
+};
+
export const IdpSyncPageView: FC = ({ oidcConfig }) => {
+ const theme = useTheme();
+ const {
+ groups_field,
+ user_role_field,
+ group_regex_filter,
+ group_auto_create,
+ } = oidcConfig || {};
return (
<>
@@ -43,9 +71,21 @@ export const IdpSyncPageView: FC = ({ oidcConfig }) => {
Sync Field
- {oidcConfig?.groups_field}
+
+ {groups_field || (
+
+
+ disabled
+
+ )}
+
Regex Filter
- {oidcConfig?.group_regex_filter}
+ {group_regex_filter || "none"}
Auto Create
{oidcConfig?.group_auto_create.toString()}
@@ -56,7 +96,19 @@ export const IdpSyncPageView: FC = ({ oidcConfig }) => {
Sync Field
- {oidcConfig?.user_role_field}
+
+ {user_role_field || (
+
+
+ disabled
+
+ )}
+
@@ -64,8 +116,10 @@ export const IdpSyncPageView: FC = ({ oidcConfig }) => {
@@ -85,8 +139,9 @@ export const IdpSyncPageView: FC = ({ oidcConfig }) => {
From 6e39fcfeb159f1c7157394867dda7f2769193530 Mon Sep 17 00:00:00 2001
From: Jaayden Halko
Date: Mon, 2 Sep 2024 18:58:51 +0000
Subject: [PATCH 07/14] feat: cleanup
---
.../ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
index ab4c59c600d8e..60785635288aa 100644
--- a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
+++ b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
@@ -87,9 +87,7 @@ export const IdpSyncPageView: FC = ({ oidcConfig }) => {
Regex Filter
{group_regex_filter || "none"}
Auto Create
-
- {oidcConfig?.group_auto_create.toString()}
-
+ {group_auto_create?.toString()}
)}
@@ -96,45 +100,40 @@ export const IdpSyncPageView: FC = ({ oidcConfig }) => {
type="Role"
isEmpty={Boolean(
!oidcConfig?.user_role_mapping ||
- (oidcConfig?.user_role_mapping &&
- Object.entries(oidcConfig?.user_role_mapping).length ===
- 0) ||
- false,
+ Object.entries(oidcConfig?.user_role_mapping).length === 0,
)}
>
<>
{oidcConfig?.user_role_mapping &&
- Object.entries(oidcConfig.user_role_mapping).map(
- ([idpRole, roles]) => (
+ Object.entries(oidcConfig.user_role_mapping)
+ .sort()
+ .map(([idpRole, roles]) => (
- ),
- )}
+ ))}
>
<>
{oidcConfig?.user_role_mapping &&
- Object.entries(oidcConfig.group_mapping).map(
- ([idpGroup, group]) => (
+ Object.entries(oidcConfig.group_mapping)
+ .sort()
+ .map(([idpGroup, group]) => (
- ),
- )}
+ ))}
>
From 2059be82011c609dfa8eed86b0bf31d85c08e258 Mon Sep 17 00:00:00 2001
From: Jaayden Halko
Date: Thu, 5 Sep 2024 21:02:31 +0000
Subject: [PATCH 13/14] chore: add story for compact empty state
---
site/src/components/EmptyState/EmptyState.stories.tsx | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/site/src/components/EmptyState/EmptyState.stories.tsx b/site/src/components/EmptyState/EmptyState.stories.tsx
index cda4f69a01db7..1e4c5eb183076 100644
--- a/site/src/components/EmptyState/EmptyState.stories.tsx
+++ b/site/src/components/EmptyState/EmptyState.stories.tsx
@@ -13,11 +13,17 @@ const meta: Meta = {
export default meta;
type Story = StoryObj;
-const Example: Story = {
+export const Example: Story = {
args: {
description: "It is easy, just click the button below",
cta: ,
},
};
-export { Example as EmptyState };
+export const Compact: Story = {
+ args: {
+ description: "It is easy, just click the button below",
+ cta: ,
+ isCompact: true,
+ },
+};
From 1523025e9de578b9f5b9efebfb56fc5117a8f996 Mon Sep 17 00:00:00 2001
From: Jaayden Halko
Date: Thu, 5 Sep 2024 23:01:20 +0000
Subject: [PATCH 14/14] feat: extract IdpField and improve field spacing
---
.../IdpSyncPage/IdpSyncPageView.tsx | 90 +++++++++++--------
1 file changed, 53 insertions(+), 37 deletions(-)
diff --git a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
index cd24a264ea74f..44552f11f7429 100644
--- a/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
+++ b/site/src/pages/ManagementSettingsPage/IdpSyncPage/IdpSyncPageView.tsx
@@ -50,48 +50,30 @@ export const IdpSyncPageView: FC = ({ oidcConfig }) => {
updates to these fields in a form */}
@@ -143,6 +125,40 @@ export const IdpSyncPageView: FC = ({ oidcConfig }) => {
);
};
+interface IdpFieldProps {
+ name: string;
+ fieldText: string | undefined;
+ showStatusIndicator?: boolean;
+}
+
+const IdpField: FC = ({
+ name,
+ fieldText,
+ showStatusIndicator = false,
+}) => {
+ return (
+
+ {name}
+
+ {fieldText ||
+ (showStatusIndicator && (
+
+ ))}
+
+
+ );
+};
+
interface IdpMappingTableProps {
type: "Role" | "Group";
isEmpty: boolean;