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

Commitbcfeb72

Browse files
authored
feat: show warning on unrecognized idp org mapping claims (#16478)
1 parent33a89ab commitbcfeb72

File tree

10 files changed

+113
-91
lines changed

10 files changed

+113
-91
lines changed

‎site/src/api/api.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ class ApiMethods {
698698
}
699699

700700
constresponse=awaitthis.axios.get<TypesGen.ProvisionerDaemon[]>(
701-
`/api/v2/organizations/${organization}/provisionerdaemons?${params.toString()}`,
701+
`/api/v2/organizations/${organization}/provisionerdaemons?${params}`,
702702
);
703703
returnresponse.data;
704704
};
@@ -787,19 +787,25 @@ class ApiMethods {
787787
returnresponse.data;
788788
};
789789

790-
getIdpSyncClaimFieldValues=async(claimField:string)=>{
791-
constresponse=awaitthis.axios.get<string[]>(
792-
`/api/v2/settings/idpsync/field-values?claimField=${claimField}`,
790+
getDeploymentIdpSyncFieldValues=async(
791+
field:string,
792+
):Promise<readonlystring[]>=>{
793+
constparams=newURLSearchParams();
794+
params.set("claimField",field);
795+
constresponse=awaitthis.axios.get<readonlystring[]>(
796+
`/api/v2/settings/idpsync/field-values?${params}`,
793797
);
794798
returnresponse.data;
795799
};
796800

797-
getIdpSyncClaimFieldValuesByOrganization=async(
801+
getOrganizationIdpSyncClaimFieldValues=async(
798802
organization:string,
799-
claimField:string,
803+
field:string,
800804
)=>{
805+
constparams=newURLSearchParams();
806+
params.set("claimField",field);
801807
constresponse=awaitthis.axios.get<TypesGen.Response>(
802-
`/api/v2/organizations/${organization}/settings/idpsync/field-values?claimField=${claimField}`,
808+
`/api/v2/organizations/${organization}/settings/idpsync/field-values?${params}`,
803809
);
804810
returnresponse.data;
805811
};

‎site/src/api/queries/deployment.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,3 +29,10 @@ export const deploymentSSHConfig = () => {
2929
queryFn:API.getDeploymentSSHConfig,
3030
};
3131
};
32+
33+
exportconstdeploymentIdpSyncFieldValues=(field:string)=>{
34+
return{
35+
queryKey:["deployment","idpSync","fieldValues",field],
36+
queryFn:()=>API.getDeploymentIdpSyncFieldValues(field),
37+
};
38+
};

‎site/src/api/queries/organizations.ts

Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -341,32 +341,16 @@ export const organizationsPermissions = (
341341

342342
exportconstgetOrganizationIdpSyncClaimFieldValuesKey=(
343343
organization:string,
344-
claimField:string,
345-
)=>[organization,claimField,"organizationIdpSyncClaimFieldValues"];
344+
field:string,
345+
)=>[organization,"idpSync","fieldValues",field];
346346

347347
exportconstorganizationIdpSyncClaimFieldValues=(
348348
organization:string,
349-
claimField:string,
349+
field:string,
350350
)=>{
351351
return{
352-
queryKey:getOrganizationIdpSyncClaimFieldValuesKey(
353-
organization,
354-
claimField,
355-
),
352+
queryKey:getOrganizationIdpSyncClaimFieldValuesKey(organization,field),
356353
queryFn:()=>
357-
API.getIdpSyncClaimFieldValuesByOrganization(organization,claimField),
358-
};
359-
};
360-
361-
exportconstgetIdpSyncClaimFieldValuesKey=(claimField:string)=>[
362-
claimField,
363-
"idpSyncClaimFieldValues",
364-
];
365-
366-
exportconstidpSyncClaimFieldValues=(claimField:string)=>{
367-
return{
368-
queryKey:getIdpSyncClaimFieldValuesKey(claimField),
369-
queryFn:()=>API.getIdpSyncClaimFieldValues(claimField),
370-
enabled:!!claimField,
354+
API.getOrganizationIdpSyncClaimFieldValues(organization,field),
371355
};
372356
};

‎site/src/components/Combobox/Combobox.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import { cn } from "utils/cn";
1818

1919
interfaceComboboxProps{
2020
value:string;
21-
options?:string[];
21+
options?:readonlystring[];
2222
placeholder?:string;
2323
open:boolean;
2424
onOpenChange:(open:boolean)=>void;

‎site/src/components/Tooltip/Tooltip.stories.tsx

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,12 @@ const meta: Meta<typeof TooltipProvider> = {
1212
component:TooltipProvider,
1313
args:{
1414
children:(
15-
<>
16-
<TooltipProvider>
17-
<Tooltipopen>
18-
<TooltipTriggerasChild>
19-
<Buttonvariant="outline">Hover</Button>
20-
</TooltipTrigger>
21-
<TooltipContent>Add to library</TooltipContent>
22-
</Tooltip>
23-
</TooltipProvider>
24-
</>
15+
<Tooltipopen>
16+
<TooltipTriggerasChild>
17+
<Buttonvariant="outline">Hover</Button>
18+
</TooltipTrigger>
19+
<TooltipContent>Add to library</TooltipContent>
20+
</Tooltip>
2521
),
2622
},
2723
};

‎site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPage.tsx

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import{getErrorMessage}from"api/errors";
2+
import{deploymentIdpSyncFieldValues}from"api/queries/deployment";
23
import{
34
organizationIdpSyncSettings,
45
patchOrganizationSyncSettings,
56
}from"api/queries/idpsync";
6-
import{idpSyncClaimFieldValues}from"api/queries/organizations";
77
import{ChooseOne,Cond}from"components/Conditionals/ChooseOne";
88
import{displayError}from"components/GlobalSnackbar/utils";
99
import{displaySuccess}from"components/GlobalSnackbar/utils";
@@ -21,26 +21,23 @@ import { ExportPolicyButton } from "./ExportPolicyButton";
2121
importIdpOrgSyncPageViewfrom"./IdpOrgSyncPageView";
2222

2323
exportconstIdpOrgSyncPage:FC=()=>{
24-
const[claimField,setClaimField]=useState("");
2524
constqueryClient=useQueryClient();
2625
// IdP sync does not have its own entitlement and is based on templace_rbac
2726
const{template_rbac:isIdpSyncEnabled}=useFeatureVisibility();
2827
const{ organizations}=useDashboard();
29-
const{
30-
data:orgSyncSettingsData,
31-
isLoading,
32-
error,
33-
}=useQuery({
34-
...organizationIdpSyncSettings(isIdpSyncEnabled),
35-
onSuccess:(data)=>{
36-
if(data?.field){
37-
setClaimField(data.field);
38-
}
39-
},
40-
});
28+
constsettingsQuery=useQuery(organizationIdpSyncSettings(isIdpSyncEnabled));
4129

42-
const{data:claimFieldValues}=useQuery(
43-
idpSyncClaimFieldValues(claimField),
30+
const[field,setField]=useState("");
31+
useEffect(()=>{
32+
if(!settingsQuery.data){
33+
return;
34+
}
35+
36+
setField(settingsQuery.data.field);
37+
},[settingsQuery.data]);
38+
39+
constfieldValuesQuery=useQuery(
40+
field ?deploymentIdpSyncFieldValues(field) :{enabled:false},
4441
);
4542

4643
constpatchOrganizationSyncSettingsMutation=useMutation(
@@ -58,14 +55,10 @@ export const IdpOrgSyncPage: FC = () => {
5855
}
5956
},[patchOrganizationSyncSettingsMutation.error]);
6057

61-
if(isLoading){
58+
if(settingsQuery.isLoading){
6259
return<Loader/>;
6360
}
6461

65-
consthandleSyncFieldChange=(value:string)=>{
66-
setClaimField(value);
67-
};
68-
6962
return(
7063
<>
7164
<Helmet>
@@ -84,7 +77,7 @@ export const IdpOrgSyncPage: FC = () => {
8477
</Link>
8578
</p>
8679
</div>
87-
<ExportPolicyButtonsyncSettings={orgSyncSettingsData}/>
80+
<ExportPolicyButtonsyncSettings={settingsQuery.data}/>
8881
</header>
8982
<ChooseOne>
9083
<Condcondition={!isIdpSyncEnabled}>
@@ -96,8 +89,10 @@ export const IdpOrgSyncPage: FC = () => {
9689
</Cond>
9790
<Cond>
9891
<IdpOrgSyncPageView
99-
organizationSyncSettings={orgSyncSettingsData}
92+
organizationSyncSettings={settingsQuery.data}
93+
claimFieldValues={fieldValuesQuery.data}
10094
organizations={organizations}
95+
onSyncFieldChange={setField}
10196
onSubmit={async(data)=>{
10297
try{
10398
awaitpatchOrganizationSyncSettingsMutation.mutateAsync(data);
@@ -111,9 +106,7 @@ export const IdpOrgSyncPage: FC = () => {
111106
);
112107
}
113108
}}
114-
onSyncFieldChange={handleSyncFieldChange}
115-
claimFieldValues={claimFieldValues}
116-
error={error||patchOrganizationSyncSettingsMutation.error}
109+
error={settingsQuery.error||fieldValuesQuery.error}
117110
/>
118111
</Cond>
119112
</ChooseOne>

‎site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.stories.tsx

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,48 +5,49 @@ import {
55
MockOrganization2,
66
MockOrganizationSyncSettings,
77
MockOrganizationSyncSettings2,
8+
MockOrganizationSyncSettingsEmpty,
89
}from"testHelpers/entities";
910
import{IdpOrgSyncPageView}from"./IdpOrgSyncPageView";
1011

1112
constmeta:Meta<typeofIdpOrgSyncPageView>={
1213
title:"pages/IdpOrgSyncPageView",
1314
component:IdpOrgSyncPageView,
15+
args:{
16+
organizationSyncSettings:MockOrganizationSyncSettings2,
17+
claimFieldValues:Object.keys(MockOrganizationSyncSettings2.mapping),
18+
organizations:[MockOrganization,MockOrganization2],
19+
error:undefined,
20+
},
1421
};
1522

1623
exportdefaultmeta;
1724
typeStory=StoryObj<typeofIdpOrgSyncPageView>;
1825

1926
exportconstEmpty:Story={
2027
args:{
21-
organizationSyncSettings:{
22-
field:"",
23-
mapping:{},
24-
organization_assign_default:true,
25-
},
26-
organizations:[MockOrganization,MockOrganization2],
27-
error:undefined,
28+
organizationSyncSettings:MockOrganizationSyncSettingsEmpty,
2829
},
2930
};
3031

31-
exportconstDefault:Story={
32-
args:{
33-
organizationSyncSettings:MockOrganizationSyncSettings2,
34-
organizations:[MockOrganization,MockOrganization2],
35-
error:undefined,
36-
},
37-
};
32+
exportconstDefault:Story={};
3833

3934
exportconstHasError:Story={
4035
args:{
41-
...Default.args,
4236
error:"This is a test error",
4337
},
4438
};
4539

4640
exportconstMissingGroups:Story={
4741
args:{
48-
...Default.args,
4942
organizationSyncSettings:MockOrganizationSyncSettings,
43+
claimFieldValues:Object.keys(MockOrganizationSyncSettings.mapping),
44+
organizations:[],
45+
},
46+
};
47+
48+
exportconstMissingClaim:Story={
49+
args:{
50+
claimFieldValues:[],
5051
},
5152
};
5253

‎site/src/pages/DeploymentSettingsPage/IdpOrgSyncPage/IdpOrgSyncPageView.tsx

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import{TooltipProvider}from"@radix-ui/react-tooltip";
12
importtype{
23
Organization,
34
OrganizationSyncSettings,
@@ -28,12 +29,8 @@ import {
2829
MultiSelectCombobox,
2930
typeOption,
3031
}from"components/MultiSelectCombobox/MultiSelectCombobox";
31-
import{
32-
Popover,
33-
PopoverContent,
34-
PopoverTrigger,
35-
}from"components/Popover/Popover";
3632
import{Spinner}from"components/Spinner/Spinner";
33+
import{Stack}from"components/Stack/Stack";
3734
import{Switch}from"components/Switch/Switch";
3835
import{
3936
Table,
@@ -42,21 +39,25 @@ import {
4239
TableHeader,
4340
TableRow,
4441
}from"components/Table/Table";
42+
import{
43+
Tooltip,
44+
TooltipContent,
45+
TooltipTrigger,
46+
}from"components/Tooltip/Tooltip";
4547
import{useFormik}from"formik";
46-
import{Check,ChevronDown,CornerDownLeft,Plus,Trash}from"lucide-react";
48+
import{Plus,Trash,TriangleAlert}from"lucide-react";
4749
import{typeFC,typeKeyboardEventHandler,useId,useState}from"react";
48-
import{cn}from"utils/cn";
4950
import{docs}from"utils/docs";
5051
import{isUUID}from"utils/uuid";
5152
import*asYupfrom"yup";
5253
import{OrganizationPills}from"./OrganizationPills";
5354

5455
interfaceIdpSyncPageViewProps{
5556
organizationSyncSettings:OrganizationSyncSettings|undefined;
57+
claimFieldValues:readonlystring[]|undefined;
5658
organizations:readonlyOrganization[];
5759
onSubmit:(data:OrganizationSyncSettings)=>void;
5860
onSyncFieldChange:(value:string)=>void;
59-
claimFieldValues:string[]|undefined;
6061
error?:unknown;
6162
}
6263

@@ -84,10 +85,10 @@ const validationSchema = Yup.object({
8485

8586
exportconstIdpOrgSyncPageView:FC<IdpSyncPageViewProps>=({
8687
organizationSyncSettings,
88+
claimFieldValues,
8789
organizations,
8890
onSubmit,
8991
onSyncFieldChange,
90-
claimFieldValues,
9192
error,
9293
})=>{
9394
constform=useFormik<OrganizationSyncSettings>({
@@ -313,6 +314,7 @@ export const IdpOrgSyncPageView: FC<IdpSyncPageViewProps> = ({
313314
idpOrg={idpOrg}
314315
coderOrgs={getOrgNames(organizations)}
315316
onDelete={handleDelete}
317+
exists={claimFieldValues?.includes(idpOrg)}
316318
/>
317319
))}
318320
</IdpMappingTable>
@@ -398,18 +400,43 @@ const IdpMappingTable: FC<IdpMappingTableProps> = ({ isEmpty, children }) => {
398400

399401
interfaceOrganizationRowProps{
400402
idpOrg:string;
403+
exists:boolean|undefined;
401404
coderOrgs:readonlystring[];
402405
onDelete:(idpOrg:string)=>void;
403406
}
404407

405408
constOrganizationRow:FC<OrganizationRowProps>=({
406409
idpOrg,
410+
exists=true,
407411
coderOrgs,
408412
onDelete,
409413
})=>{
410414
return(
411415
<TableRowdata-testid={`idp-org-${idpOrg}`}>
412-
<TableCell>{idpOrg}</TableCell>
416+
<TableCell>
417+
<divclassName="flex flex-row items-center gap-2 text-content-primary">
418+
{idpOrg}
419+
{!exists&&(
420+
<TooltipProvider>
421+
<Tooltip>
422+
<TooltipTriggerasChild>
423+
<TriangleAlertclassName="size-icon-xs cursor-pointer text-content-warning"/>
424+
</TooltipTrigger>
425+
<TooltipContent
426+
align="start"
427+
alignOffset={-8}
428+
sideOffset={8}
429+
className="p-2 text-xs text-content-secondary max-w-sm"
430+
>
431+
This value has not be seen in the specified claim field
432+
before. You might want to check your IdP configuration and
433+
ensure that this value is not misspelled.
434+
</TooltipContent>
435+
</Tooltip>
436+
</TooltipProvider>
437+
)}
438+
</div>
439+
</TableCell>
413440
<TableCell>
414441
<OrganizationPillsorganizations={coderOrgs}/>
415442
</TableCell>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp