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

Commitd9d4cc0

Browse files
committed
feat: add combobox using claim field values
1 parent323559b commitd9d4cc0

File tree

4 files changed

+126
-21
lines changed

4 files changed

+126
-21
lines changed

‎site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpGroupSyncForm.tsx

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
Organization,
77
}from"api/typesGenerated";
88
import{Button}from"components/Button/Button";
9+
import{Combobox}from"components/Combobox/Combobox";
910
import{
1011
HelpTooltip,
1112
HelpTooltipContent,
@@ -30,7 +31,7 @@ import {
3031
}from"components/Tooltip/Tooltip";
3132
import{useFormik}from"formik";
3233
import{Plus,Trash,TriangleAlert}from"lucide-react";
33-
import{typeFC,useId,useState}from"react";
34+
import{typeFC,useId,useState,typeKeyboardEventHandler}from"react";
3435
import{docs}from"utils/docs";
3536
import{isUUID}from"utils/uuid";
3637
import*asYupfrom"yup";
@@ -70,6 +71,7 @@ interface IdpGroupSyncFormProps {
7071
legacyGroupMappingCount:number;
7172
organization:Organization;
7273
onSubmit:(data:GroupSyncSettings)=>void;
74+
onSyncFieldChange:(value:string)=>void;
7375
}
7476

7577
exportconstIdpGroupSyncForm:FC<IdpGroupSyncFormProps>=({
@@ -81,6 +83,7 @@ export const IdpGroupSyncForm: FC<IdpGroupSyncFormProps> = ({
8183
groupsMap,
8284
organization,
8385
onSubmit,
86+
onSyncFieldChange,
8487
})=>{
8588
constform=useFormik<GroupSyncSettings>({
8689
initialValues:{
@@ -97,6 +100,8 @@ export const IdpGroupSyncForm: FC<IdpGroupSyncFormProps> = ({
97100
const[idpGroupName,setIdpGroupName]=useState("");
98101
const[coderGroups,setCoderGroups]=useState<Option[]>([]);
99102
constid=useId();
103+
const[comboInputValue,setComboInputValue]=useState("");
104+
const[open,setOpen]=useState(false);
100105

101106
constgetGroupNames=(groupIds:readonlystring[])=>{
102107
returngroupIds.map((groupId)=>groupsMap.get(groupId)||groupId);
@@ -116,6 +121,19 @@ export const IdpGroupSyncForm: FC<IdpGroupSyncFormProps> = ({
116121
form.handleSubmit();
117122
};
118123

124+
consthandleKeyDown:KeyboardEventHandler<HTMLInputElement>=(event)=>{
125+
if(
126+
event.key==="Enter"&&
127+
comboInputValue&&
128+
!claimFieldValues?.some((value)=>value===comboInputValue.toLowerCase())
129+
){
130+
event.preventDefault();
131+
setIdpGroupName(comboInputValue);
132+
setComboInputValue("");
133+
setOpen(false);
134+
}
135+
};
136+
119137
return(
120138
<formonSubmit={form.handleSubmit}>
121139
<fieldset
@@ -143,6 +161,7 @@ export const IdpGroupSyncForm: FC<IdpGroupSyncFormProps> = ({
143161
value={form.values.field}
144162
onChange={(event)=>{
145163
voidform.setFieldValue("field",event.target.value);
164+
onSyncFieldChange(event.target.value);
146165
}}
147166
className="w-72"
148167
/>
@@ -202,14 +221,31 @@ export const IdpGroupSyncForm: FC<IdpGroupSyncFormProps> = ({
202221
<LabelclassName="text-sm"htmlFor={`${id}-idp-group-name`}>
203222
IdP group name
204223
</Label>
205-
<Input
206-
id={`${id}-idp-group-name`}
207-
value={idpGroupName}
208-
className="w-72"
209-
onChange={(event)=>{
210-
setIdpGroupName(event.target.value);
211-
}}
212-
/>
224+
{claimFieldValues ?(
225+
<Combobox
226+
value={idpGroupName}
227+
options={claimFieldValues}
228+
placeholder="Select IdP organization"
229+
open={open}
230+
onOpenChange={setOpen}
231+
inputValue={comboInputValue}
232+
onInputChange={setComboInputValue}
233+
onKeyDown={handleKeyDown}
234+
onSelect={(value:string)=>{
235+
setIdpGroupName(value);
236+
setOpen(false);
237+
}}
238+
/>
239+
) :(
240+
<Input
241+
id={`${id}-idp-group-name`}
242+
value={idpGroupName}
243+
className="w-72"
244+
onChange={(event)=>{
245+
setIdpGroupName(event.target.value);
246+
}}
247+
/>
248+
)}
213249
</div>
214250
<divclassName="grid items-center gap-1 flex-1">
215251
<LabelclassName="text-sm"htmlFor={`${id}-coder-group`}>

‎site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpRoleSyncForm.tsx

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import TableCell from "@mui/material/TableCell";
22
importTableRowfrom"@mui/material/TableRow";
33
importtype{Organization,Role,RoleSyncSettings}from"api/typesGenerated";
44
import{Button}from"components/Button/Button";
5+
import{Combobox}from"components/Combobox/Combobox";
56
import{Input}from"components/Input/Input";
67
import{Label}from"components/Label/Label";
78
import{
@@ -17,7 +18,7 @@ import {
1718
}from"components/Tooltip/Tooltip";
1819
import{useFormik}from"formik";
1920
import{Plus,Trash,TriangleAlert}from"lucide-react";
20-
import{typeFC,useId,useState}from"react";
21+
import{typeFC,typeKeyboardEventHandler,useId,useState}from"react";
2122
import*asYupfrom"yup";
2223
import{ExportPolicyButton}from"./ExportPolicyButton";
2324
import{IdpMappingTable}from"./IdpMappingTable";
@@ -53,6 +54,7 @@ interface IdpRoleSyncFormProps {
5354
organization:Organization;
5455
roles:Role[];
5556
onSubmit:(data:RoleSyncSettings)=>void;
57+
onSyncFieldChange:(value:string)=>void;
5658
}
5759

5860
exportconstIdpRoleSyncForm:FC<IdpRoleSyncFormProps>=({
@@ -62,6 +64,7 @@ export const IdpRoleSyncForm: FC<IdpRoleSyncFormProps> = ({
6264
organization,
6365
roles,
6466
onSubmit,
67+
onSyncFieldChange,
6568
})=>{
6669
constform=useFormik<RoleSyncSettings>({
6770
initialValues:{
@@ -75,6 +78,8 @@ export const IdpRoleSyncForm: FC<IdpRoleSyncFormProps> = ({
7578
const[idpRoleName,setIdpRoleName]=useState("");
7679
const[coderRoles,setCoderRoles]=useState<Option[]>([]);
7780
constid=useId();
81+
const[comboInputValue,setComboInputValue]=useState("");
82+
const[open,setOpen]=useState(false);
7883

7984
consthandleDelete=async(idpOrg:string)=>{
8085
constnewMapping=Object.fromEntries(
@@ -90,6 +95,19 @@ export const IdpRoleSyncForm: FC<IdpRoleSyncFormProps> = ({
9095
form.handleSubmit();
9196
};
9297

98+
consthandleKeyDown:KeyboardEventHandler<HTMLInputElement>=(event)=>{
99+
if(
100+
event.key==="Enter"&&
101+
comboInputValue&&
102+
!claimFieldValues?.some((value)=>value===comboInputValue.toLowerCase())
103+
){
104+
event.preventDefault();
105+
setIdpRoleName(comboInputValue);
106+
setComboInputValue("");
107+
setOpen(false);
108+
}
109+
};
110+
93111
return(
94112
<formonSubmit={form.handleSubmit}>
95113
<fieldset
@@ -114,6 +132,7 @@ export const IdpRoleSyncForm: FC<IdpRoleSyncFormProps> = ({
114132
value={form.values.field}
115133
onChange={(event)=>{
116134
voidform.setFieldValue("field",event.target.value);
135+
onSyncFieldChange(event.target.value);
117136
}}
118137
className="w-72"
119138
/>
@@ -143,14 +162,31 @@ export const IdpRoleSyncForm: FC<IdpRoleSyncFormProps> = ({
143162
<LabelclassName="text-sm"htmlFor={`${id}-idp-role-name`}>
144163
IdP role name
145164
</Label>
146-
<Input
147-
id={`${id}-idp-role-name`}
148-
value={idpRoleName}
149-
className="w-72"
150-
onChange={(event)=>{
151-
setIdpRoleName(event.target.value);
152-
}}
153-
/>
165+
{claimFieldValues ?(
166+
<Combobox
167+
value={idpRoleName}
168+
options={claimFieldValues}
169+
placeholder="Select IdP organization"
170+
open={open}
171+
onOpenChange={setOpen}
172+
inputValue={comboInputValue}
173+
onInputChange={setComboInputValue}
174+
onKeyDown={handleKeyDown}
175+
onSelect={(value:string)=>{
176+
setIdpRoleName(value);
177+
setOpen(false);
178+
}}
179+
/>
180+
) :(
181+
<Input
182+
id={`${id}-idp-role-name`}
183+
value={idpRoleName}
184+
className="w-72"
185+
onChange={(event)=>{
186+
setIdpRoleName(event.target.value);
187+
}}
188+
/>
189+
)}
154190
</div>
155191
<divclassName="grid items-center gap-1 flex-1">
156192
<LabelclassName="text-sm"htmlFor={`${id}-coder-role`}>

‎site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
roleIdpSyncSettings,
99
}from"api/queries/organizations";
1010
import{organizationRoles}from"api/queries/roles";
11+
importtype{GroupSyncSettings,RoleSyncSettings}from"api/typesGenerated";
1112
import{ChooseOne,Cond}from"components/Conditionals/ChooseOne";
1213
import{EmptyState}from"components/EmptyState/EmptyState";
1314
import{displayError}from"components/GlobalSnackbar/utils";
@@ -16,7 +17,7 @@ import { Link } from "components/Link/Link";
1617
import{Paywall}from"components/Paywall/Paywall";
1718
import{useFeatureVisibility}from"modules/dashboard/useFeatureVisibility";
1819
import{useOrganizationSettings}from"modules/management/OrganizationSettingsLayout";
19-
importtype{FC}from"react";
20+
import{typeFC,useState}from"react";
2021
import{Helmet}from"react-helmet-async";
2122
import{useMutation,useQueries,useQuery,useQueryClient}from"react-query";
2223
import{useParams,useSearchParams}from"react-router-dom";
@@ -29,6 +30,8 @@ export const IdpSyncPage: FC = () => {
2930
const{organization:organizationName}=useParams()as{
3031
organization:string;
3132
};
33+
const[groupClaimField,setGroupClaimField]=useState("");
34+
const[roleClaimField,setRoleClaimField]=useState("");
3235
// IdP sync does not have its own entitlement and is based on templace_rbac
3336
const{template_rbac:isIdpSyncEnabled}=useFeatureVisibility();
3437
const{ organizations}=useOrganizationSettings();
@@ -41,8 +44,22 @@ export const IdpSyncPage: FC = () => {
4144
rolesQuery,
4245
]=useQueries({
4346
queries:[
44-
groupIdpSyncSettings(organizationName),
45-
roleIdpSyncSettings(organizationName),
47+
{
48+
...groupIdpSyncSettings(organizationName),
49+
onSuccess:(data:GroupSyncSettings)=>{
50+
if(data?.field){
51+
setGroupClaimField(data.field);
52+
}
53+
},
54+
},
55+
{
56+
...roleIdpSyncSettings(organizationName),
57+
onSuccess:(data:RoleSyncSettings)=>{
58+
if(data?.field){
59+
setRoleClaimField(data.field);
60+
}
61+
},
62+
},
4663
groupsByOrganization(organizationName),
4764
organizationRoles(organizationName),
4865
],
@@ -86,6 +103,14 @@ export const IdpSyncPage: FC = () => {
86103
}
87104
}
88105

106+
consthandleGroupSyncFieldChange=(value:string)=>{
107+
setGroupClaimField(value);
108+
};
109+
110+
consthandleRoleSyncFieldChange=(value:string)=>{
111+
setRoleClaimField(value);
112+
};
113+
89114
return(
90115
<>
91116
<Helmet>
@@ -121,6 +146,8 @@ export const IdpSyncPage: FC = () => {
121146
groupsMap={groupsMap}
122147
roles={rolesQuery.data}
123148
organization={organization}
149+
onGroupSyncFieldChange={handleGroupSyncFieldChange}
150+
onRoleSyncFieldChange={handleRoleSyncFieldChange}
124151
error={error}
125152
onSubmitGroupSyncSettings={async(data)=>{
126153
try{

‎site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPageView.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ interface IdpSyncPageViewProps {
2121
groupsMap:Map<string,string>;
2222
roles:Role[]|undefined;
2323
organization:Organization;
24+
onGroupSyncFieldChange:(value:string)=>void;
25+
onRoleSyncFieldChange:(value:string)=>void;
2426
error?:unknown;
2527
onSubmitGroupSyncSettings:(data:GroupSyncSettings)=>void;
2628
onSubmitRoleSyncSettings:(data:RoleSyncSettings)=>void;
@@ -35,6 +37,8 @@ export const IdpSyncPageView: FC<IdpSyncPageViewProps> = ({
3537
groupsMap,
3638
roles,
3739
organization,
40+
onGroupSyncFieldChange,
41+
onRoleSyncFieldChange,
3842
error,
3943
onSubmitGroupSyncSettings,
4044
onSubmitRoleSyncSettings,
@@ -76,6 +80,7 @@ export const IdpSyncPageView: FC<IdpSyncPageViewProps> = ({
7680
groupsMap={groupsMap}
7781
organization={organization}
7882
onSubmit={onSubmitGroupSyncSettings}
83+
onSyncFieldChange={onGroupSyncFieldChange}
7984
/>
8085
) :(
8186
<IdpRoleSyncForm
@@ -85,6 +90,7 @@ export const IdpSyncPageView: FC<IdpSyncPageViewProps> = ({
8590
roles={roles||[]}
8691
organization={organization}
8792
onSubmit={onSubmitRoleSyncSettings}
93+
onSyncFieldChange={onRoleSyncFieldChange}
8894
/>
8995
)}
9096
</div>

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp