Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat: show warning on unrecognized idp group and role mapping claims#16485

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
aslilac merged 25 commits intomainfromlilac/group-role-sync-missing-given-warning
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
25 commits
Select commitHold shift + click to select a range
5c09338
hoot
aslilacFeb 5, 2025
c52982e
feat: show warning on unrecognized idp org mapping claims
aslilacFeb 6, 2025
5634be1
Merge branch 'main' into lilac/idp-sync-missing-given-warning
aslilacFeb 6, 2025
63ca763
🧹
aslilacFeb 6, 2025
e55e0a8
add warning description
aslilacFeb 6, 2025
72a7986
toolptipp
aslilacFeb 6, 2025
eedf797
tweak text colors
aslilacFeb 6, 2025
06ba32d
Update site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyn…
aslilacFeb 6, 2025
9600624
this is something
aslilacFeb 6, 2025
6ffcc94
- `toString()`
aslilacFeb 6, 2025
506cca1
polish
aslilacFeb 6, 2025
c91cd1a
🧼
aslilacFeb 6, 2025
97de7f4
rename
aslilacFeb 6, 2025
06715fa
sad moment
aslilacFeb 6, 2025
42ceb1b
cntnd.
aslilacFeb 6, 2025
820cca3
huh
aslilacFeb 6, 2025
da68f4b
Merge branch 'lilac/idp-sync-missing-given-warning' into lilac/group-…
aslilacFeb 6, 2025
7a1bee3
Merge branch 'main' into lilac/group-role-sync-missing-given-warning
aslilacFeb 6, 2025
b955e4b
yet again
aslilacFeb 6, 2025
d3873ab
group tooltip thing too
aslilacFeb 7, 2025
a743cea
🧹
aslilacFeb 7, 2025
5948a61
who did this, you must be held ACCOUNTABLE (it was me)
aslilacFeb 7, 2025
ce46b06
thank you typescript I love you typescript
aslilacFeb 7, 2025
a76a243
fix tooltip positioning
aslilacFeb 7, 2025
e9a5bff
one last bit of polish
aslilacFeb 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletionsite/src/api/api.ts
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -804,7 +804,7 @@ class ApiMethods {
) => {
const params = new URLSearchParams();
params.set("claimField", field);
const response = await this.axios.get<TypesGen.Response>(
const response = await this.axios.get<readonly string[]>(
`/api/v2/organizations/${organization}/settings/idpsync/field-values?${params}`,
);
return response.data;
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
import type { Meta, StoryObj } from "@storybook/react";
import { userEvent, within } from "@storybook/test";
import {expect,userEvent, within } from "@storybook/test";
import {
MockOrganization,
MockOrganization2,
Expand DownExpand Up@@ -45,10 +45,16 @@ export const MissingGroups: Story = {
},
};

export constMissingClaim: Story = {
export constMissingClaims: Story = {
args: {
claimFieldValues: [],
},
play: async ({ canvasElement }) => {
const user = userEvent.setup();
const warning = canvasElement.querySelector(".lucide-triangle-alert")!;
expect(warning).not.toBe(null);
await user.hover(warning);
},
};

export const AssignDefaultOrgWarningDialog: Story = {
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
import { TooltipProvider } from "@radix-ui/react-tooltip";
import type {
Organization,
OrganizationSyncSettings,
Expand DownExpand Up@@ -30,7 +29,6 @@ import {
type Option,
} from "components/MultiSelectCombobox/MultiSelectCombobox";
import { Spinner } from "components/Spinner/Spinner";
import { Stack } from "components/Stack/Stack";
import { Switch } from "components/Switch/Switch";
import {
Table,
Expand All@@ -42,6 +40,7 @@ import {
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "components/Tooltip/Tooltip";
import { useFormik } from "formik";
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,8 +22,14 @@ import {
} from "components/MultiSelectCombobox/MultiSelectCombobox";
import { Spinner } from "components/Spinner/Spinner";
import { Switch } from "components/Switch/Switch";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "components/Tooltip/Tooltip";
import { useFormik } from "formik";
import { Plus, Trash } from "lucide-react";
import { Plus, Trash, TriangleAlert } from "lucide-react";
import { type FC, useId, useState } from "react";
import { docs } from "utils/docs";
import { isUUID } from "utils/uuid";
Expand All@@ -32,16 +38,6 @@ import { ExportPolicyButton } from "./ExportPolicyButton";
import { IdpMappingTable } from "./IdpMappingTable";
import { IdpPillList } from "./IdpPillList";

interface IdpGroupSyncFormProps {
groupSyncSettings: GroupSyncSettings;
groupsMap: Map<string, string>;
groups: Group[];
groupMappingCount: number;
legacyGroupMappingCount: number;
organization: Organization;
onSubmit: (data: GroupSyncSettings) => void;
}

const groupSyncValidationSchema = Yup.object({
field: Yup.string().trim(),
regex_filter: Yup.string().trim(),
Expand All@@ -65,15 +61,27 @@ const groupSyncValidationSchema = Yup.object({
.default({}),
});

export const IdpGroupSyncForm = ({
interface IdpGroupSyncFormProps {
groupSyncSettings: GroupSyncSettings;
claimFieldValues: readonly string[] | undefined;
groupsMap: Map<string, string>;
groups: Group[];
groupMappingCount: number;
legacyGroupMappingCount: number;
organization: Organization;
onSubmit: (data: GroupSyncSettings) => void;
}

export const IdpGroupSyncForm: FC<IdpGroupSyncFormProps> = ({
groupSyncSettings,
claimFieldValues,
groupMappingCount,
legacyGroupMappingCount,
groups,
groupsMap,
organization,
onSubmit,
}: IdpGroupSyncFormProps) => {
}) => {
const form = useFormik<GroupSyncSettings>({
initialValues: {
field: groupSyncSettings?.field ?? "",
Expand DownExpand Up@@ -270,6 +278,7 @@ export const IdpGroupSyncForm = ({
<GroupRow
key={idpGroup}
idpGroup={idpGroup}
exists={claimFieldValues?.includes(idpGroup)}
coderGroup={getGroupNames(groups)}
onDelete={handleDelete}
/>
Expand All@@ -288,6 +297,7 @@ export const IdpGroupSyncForm = ({
<GroupRow
key={groupId}
idpGroup={idpGroup}
exists={claimFieldValues?.includes(idpGroup)}
coderGroup={getGroupNames([groupId])}
onDelete={handleDelete}
/>
Expand All@@ -303,17 +313,48 @@ export const IdpGroupSyncForm = ({

interface GroupRowProps {
idpGroup: string;
exists: boolean | undefined;
coderGroup: readonly string[];
onDelete: (idpOrg: string) => void;
}

const GroupRow: FC<GroupRowProps> = ({ idpGroup, coderGroup, onDelete }) => {
const GroupRow: FC<GroupRowProps> = ({
idpGroup,
exists = true,
coderGroup,
onDelete,
}) => {
return (
<TableRow data-testid={`group-${idpGroup}`}>
<TableCell>{idpGroup}</TableCell>
<TableCell>
<div className="flex flex-row items-center gap-2 text-content-primary">
{idpGroup}
{!exists && (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<TriangleAlert className="size-icon-xs cursor-pointer text-content-warning" />
</TooltipTrigger>
<TooltipContent
align="start"
alignOffset={-8}
sideOffset={8}
className="p-2 text-xs text-content-secondary max-w-sm"
>
This value has not be seen in the specified claim field
before. You might want to check your IdP configuration and
ensure that this value is not misspelled.
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
</TableCell>

<TableCell>
<IdpPillList roles={coderGroup} />
</TableCell>

<TableCell>
<Button
variant="outline"
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,22 +9,20 @@ import {
type Option,
} from "components/MultiSelectCombobox/MultiSelectCombobox";
import { Spinner } from "components/Spinner/Spinner";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "components/Tooltip/Tooltip";
import { useFormik } from "formik";
import { Plus, Trash } from "lucide-react";
import { Plus, Trash, TriangleAlert } from "lucide-react";
import { type FC, useId, useState } from "react";
import * as Yup from "yup";
import { ExportPolicyButton } from "./ExportPolicyButton";
import { IdpMappingTable } from "./IdpMappingTable";
import { IdpPillList } from "./IdpPillList";

interface IdpRoleSyncFormProps {
roleSyncSettings: RoleSyncSettings;
roleMappingCount: number;
organization: Organization;
roles: Role[];
onSubmit: (data: RoleSyncSettings) => void;
}

const roleSyncValidationSchema = Yup.object({
field: Yup.string().trim(),
regex_filter: Yup.string().trim(),
Expand All@@ -48,13 +46,23 @@ const roleSyncValidationSchema = Yup.object({
.default({}),
});

export const IdpRoleSyncForm = ({
interface IdpRoleSyncFormProps {
roleSyncSettings: RoleSyncSettings;
claimFieldValues: readonly string[] | undefined;
roleMappingCount: number;
organization: Organization;
roles: Role[];
onSubmit: (data: RoleSyncSettings) => void;
}

export const IdpRoleSyncForm: FC<IdpRoleSyncFormProps> = ({
roleSyncSettings,
claimFieldValues,
roleMappingCount,
organization,
roles,
onSubmit,
}: IdpRoleSyncFormProps) => {
}) => {
const form = useFormik<RoleSyncSettings>({
initialValues: {
field: roleSyncSettings?.field ?? "",
Expand DownExpand Up@@ -210,6 +218,7 @@ export const IdpRoleSyncForm = ({
<RoleRow
key={idpRole}
idpRole={idpRole}
exists={claimFieldValues?.includes(idpRole)}
coderRoles={roles}
onDelete={handleDelete}
/>
Expand All@@ -222,17 +231,48 @@ export const IdpRoleSyncForm = ({

interface RoleRowProps {
idpRole: string;
exists: boolean | undefined;
coderRoles: readonly string[];
onDelete: (idpOrg: string) => void;
}

const RoleRow: FC<RoleRowProps> = ({ idpRole, coderRoles, onDelete }) => {
const RoleRow: FC<RoleRowProps> = ({
idpRole,
exists = true,
coderRoles,
onDelete,
}) => {
return (
<TableRow data-testid={`role-${idpRole}`}>
<TableCell>{idpRole}</TableCell>
<TableCell>
<div className="flex flex-row items-center gap-2 text-content-primary">
{idpRole}
{!exists && (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<TriangleAlert className="size-icon-xs cursor-pointer text-content-warning" />
</TooltipTrigger>
<TooltipContent
align="start"
alignOffset={-8}
sideOffset={8}
className="p-2 text-xs text-content-secondary max-w-sm"
>
This value has not be seen in the specified claim field
before. You might want to check your IdP configuration and
ensure that this value is not misspelled.
</TooltipContent>
</Tooltip>
</TooltipProvider>
)}
</div>
</TableCell>

<TableCell>
<IdpPillList roles={coderRoles} />
</TableCell>

<TableCell>
<Button
variant="outline"
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,6 +2,7 @@ import { getErrorMessage } from "api/errors";
import { groupsByOrganization } from "api/queries/groups";
import {
groupIdpSyncSettings,
organizationIdpSyncClaimFieldValues,
patchGroupSyncSettings,
patchRoleSyncSettings,
roleIdpSyncSettings,
Expand All@@ -17,8 +18,8 @@ import { useFeatureVisibility } from "modules/dashboard/useFeatureVisibility";
import { useOrganizationSettings } from "modules/management/OrganizationSettingsLayout";
import type { FC } from "react";
import { Helmet } from "react-helmet-async";
import { useMutation, useQueries, useQueryClient } from "react-query";
import { useParams } from "react-router-dom";
import { useMutation, useQueries,useQuery,useQueryClient } from "react-query";
import { useParams, useSearchParams } from "react-router-dom";
import { docs } from "utils/docs";
import { pageTitle } from "utils/page";
import IdpSyncPageView from "./IdpSyncPageView";
Expand DownExpand Up@@ -47,6 +48,19 @@ export const IdpSyncPage: FC = () => {
],
});

const [searchParams] = useSearchParams();
const tab = searchParams.get("tab") || "groups";
const field =
tab === "groups"
? groupIdpSyncSettingsQuery.data?.field
: roleIdpSyncSettingsQuery.data?.field;

const fieldValuesQuery = useQuery(
field
? organizationIdpSyncClaimFieldValues(organizationName, field)
: { enabled: false },
);

if (!organization) {
return <EmptyState message="Organization not found" />;
}
Expand DownExpand Up@@ -99,8 +113,10 @@ export const IdpSyncPage: FC = () => {
</Cond>
<Cond>
<IdpSyncPageView
tab={tab}
groupSyncSettings={groupIdpSyncSettingsQuery.data}
roleSyncSettings={roleIdpSyncSettingsQuery.data}
claimFieldValues={fieldValuesQuery.data}
groups={groupsQuery.data}
groupsMap={groupsMap}
roles={rolesQuery.data}
Expand Down
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp