Skip to content

Commit 8838120

Browse files
feat(types,clerk-js): Update types; RoleSelect allows fallbackLabel (#6037)
1 parent e6395e7 commit 8838120

File tree

12 files changed

+101
-6
lines changed

12 files changed

+101
-6
lines changed

.changeset/wild-pugs-kick.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
'@clerk/clerk-js': patch
3+
'@clerk/types': patch
4+
---
5+
6+
feat(types,clerk-js): Update types; RoleSelect allows fallbackLabel
7+
- this updates OrganizationInvitation and OrganizationMembership resource+types to include `roleName` which is already present on frontend-api responses, as `role_name`.
8+
- this updates RoleSelect to allow rendering a `fallbackLabel` in the event that `value` does not map to any of the supplied roles

packages/clerk-js/src/core/resources/OrganizationInvitation.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export class OrganizationInvitation extends BaseResource implements Organization
1717
publicMetadata: OrganizationInvitationPublicMetadata = {};
1818
status!: OrganizationInvitationStatus;
1919
role!: OrganizationCustomRoleKey;
20+
roleName!: string;
2021
createdAt!: Date;
2122
updatedAt!: Date;
2223

@@ -67,6 +68,7 @@ export class OrganizationInvitation extends BaseResource implements Organization
6768
this.organizationId = data.organization_id;
6869
this.publicMetadata = data.public_metadata;
6970
this.role = data.role;
71+
this.roleName = data.role_name;
7072
this.status = data.status;
7173
this.createdAt = unixEpochToDate(data.created_at);
7274
this.updatedAt = unixEpochToDate(data.updated_at);

packages/clerk-js/src/core/resources/OrganizationMembership.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export class OrganizationMembership extends BaseResource implements Organization
2121
organization!: Organization;
2222
permissions: OrganizationPermissionKey[] = [];
2323
role!: OrganizationCustomRoleKey;
24+
roleName!: string;
2425
createdAt!: Date;
2526
updatedAt!: Date;
2627

@@ -77,6 +78,7 @@ export class OrganizationMembership extends BaseResource implements Organization
7778
}
7879
this.permissions = Array.isArray(data.permissions) ? [...data.permissions] : [];
7980
this.role = data.role;
81+
this.roleName = data.role_name;
8082
this.createdAt = unixEpochToDate(data.created_at);
8183
this.updatedAt = unixEpochToDate(data.updated_at);
8284
return this;
@@ -91,6 +93,7 @@ export class OrganizationMembership extends BaseResource implements Organization
9193
public_user_data: this.publicUserData?.__internal_toSnapshot(),
9294
permissions: this.permissions,
9395
role: this.role,
96+
role_name: this.roleName,
9497
created_at: this.createdAt.getTime(),
9598
updated_at: this.updatedAt.getTime(),
9699
};

packages/clerk-js/src/core/resources/__tests__/__snapshots__/OrganizationInvitation.test.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ OrganizationInvitation {
1212
},
1313
"revoke": [Function],
1414
"role": "basic_member",
15+
"roleName": undefined,
1516
"status": "pending",
1617
"updatedAt": 1970-01-01T00:00:05.678Z,
1718
}

packages/clerk-js/src/core/resources/__tests__/__snapshots__/OrganizationMembership.test.ts.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ OrganizationMembership {
5555
"userId": undefined,
5656
},
5757
"role": "admin",
58+
"roleName": undefined,
5859
"update": [Function],
5960
"updatedAt": 1970-01-01T00:00:05.678Z,
6061
}

packages/clerk-js/src/ui/components/OrganizationProfile/ActiveMembersList.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ const MemberRow = (props: {
110110
<RoleSelect
111111
isDisabled={card.isLoading || !onRoleChange}
112112
value={membership.role}
113+
fallbackLabel={membership.roleName}
113114
onChange={onRoleChange}
114115
roles={options}
115116
/>

packages/clerk-js/src/ui/components/OrganizationProfile/MemberListTable.tsx

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,20 @@ export const RowContainer = (props: PropsOfComponent<typeof Tr>) => {
134134
export const RoleSelect = (props: {
135135
roles: { label: string; value: string }[] | undefined;
136136
value: string;
137+
fallbackLabel?: string;
137138
onChange: (params: string) => unknown;
138139
isDisabled?: boolean;
139140
triggerSx?: ThemableCssProp;
140141
optionListSx?: ThemableCssProp;
141142
prefixLocalizationKey?: LocalizationKey | string;
142143
}) => {
143-
const { value, roles, onChange, isDisabled, triggerSx, optionListSx, prefixLocalizationKey } = props;
144+
const { value, fallbackLabel, roles, onChange, isDisabled, triggerSx, optionListSx, prefixLocalizationKey } = props;
144145

145146
const { localizeCustomRole } = useLocalizeCustomRoles();
146147

147148
const fetchedRoles = useMemo(() => [...(roles || [])], [roles]);
148149

149-
const selectedRole = useMemo(() => fetchedRoles.find(r => r.value === value), [fetchedRoles]);
150+
const selectedRole = useMemo(() => fetchedRoles.find(r => r.value === value), [fetchedRoles, value]);
150151
const { t } = useLocalizations();
151152

152153
const localizedOptions = useMemo(
@@ -195,9 +196,9 @@ export const RoleSelect = (props: {
195196
textWrap: 'nowrap',
196197
}))
197198
}
198-
isDisabled={isDisabled}
199+
isDisabled={isDisabled || (!!value && fetchedRoles.length > 0 && !selectedRole)}
199200
>
200-
{(selectedRole?.label || selectedRole?.value) && (
201+
{selectedRole?.label || selectedRole?.value ? (
201202
<Flex
202203
as='span'
203204
gap={1}
@@ -211,12 +212,19 @@ export const RoleSelect = (props: {
211212
)}
212213
<Text
213214
as='span'
214-
sx={t => ({ color: t.colors.$colorText })}
215+
colorScheme='body'
215216
>
216217
{localizeCustomRole(selectedRole?.value) || selectedRole?.label}
217218
</Text>
218219
</Flex>
219-
)}
220+
) : fallbackLabel ? (
221+
<Text
222+
as='span'
223+
colorScheme='body'
224+
>
225+
{fallbackLabel}
226+
</Text>
227+
) : null}
220228
</SelectButton>
221229
<SelectOptionList sx={optionListSx} />
222230
</Select>

packages/clerk-js/src/ui/components/OrganizationProfile/__tests__/OrganizationMembers.test.tsx

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,69 @@ describe('OrganizationMembers', () => {
474474
expect(fixtures.clerk.organization?.getMemberships).toHaveBeenCalled();
475475
expect(getByText('You')).toBeInTheDocument();
476476
});
477+
it('disables the role select when the membership role does not map to fetched roles', async () => {
478+
const membersList: OrganizationMembershipResource[] = [
479+
createFakeMember({ id: '1', orgId: '1', role: 'admin', identifier: 'test_user1' }),
480+
createFakeMember({
481+
id: '2',
482+
orgId: '1',
483+
role: 'org:managed_admin',
484+
roleName: 'Managed Admin',
485+
identifier: 'test_user2',
486+
}),
487+
];
488+
const { wrapper, fixtures } = await createFixtures(f => {
489+
f.withOrganizations();
490+
f.withUser({
491+
id: '1',
492+
email_addresses: ['[email protected]'],
493+
organization_memberships: [{ name: 'Org1', id: '1' }],
494+
});
495+
});
496+
497+
fixtures.clerk.organization?.getMemberships.mockReturnValue(
498+
Promise.resolve({
499+
data: membersList,
500+
total_count: 2,
501+
}),
502+
);
503+
fixtures.clerk.organization?.getRoles.mockResolvedValue({
504+
total_count: 2,
505+
data: [
506+
{
507+
pathRoot: '',
508+
reload: jest.fn(),
509+
id: 'member',
510+
key: 'member',
511+
name: 'Member',
512+
description: '',
513+
permissions: [],
514+
createdAt: new Date(),
515+
updatedAt: new Date(),
516+
},
517+
{
518+
pathRoot: '',
519+
reload: jest.fn(),
520+
id: 'admin',
521+
key: 'admin',
522+
name: 'Admin',
523+
description: '',
524+
permissions: [],
525+
createdAt: new Date(),
526+
updatedAt: new Date(),
527+
},
528+
],
529+
});
530+
531+
const { container, getByText, getByRole } = render(<OrganizationMembers />, { wrapper });
532+
533+
await waitForLoadingCompleted(container);
534+
535+
expect(fixtures.clerk.organization?.getMemberships).toHaveBeenCalled();
536+
expect(getByText('You')).toBeInTheDocument();
537+
expect(getByText('Managed Admin')).toBeInTheDocument();
538+
await waitFor(() => expect(getByRole('button', { name: 'Managed Admin' })).toBeDisabled());
539+
});
477540

478541
describe('InviteMembersScreen', () => {
479542
it('shows the invite screen when user clicks on Invite button', async () => {

packages/clerk-js/src/ui/components/OrganizationProfile/__tests__/utils.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ type FakeMemberParams = {
1616
id: string;
1717
orgId: string;
1818
role?: OrganizationCustomRoleKey;
19+
roleName?: string;
1920
identifier?: string;
2021
firstName?: string;
2122
lastName?: string;
@@ -30,6 +31,7 @@ export const createFakeMember = (params: FakeMemberParams): OrganizationMembersh
3031
organization: { id: params.orgId } as any as OrganizationResource,
3132
id: params.id,
3233
role: params?.role || 'admin',
34+
roleName: params?.roleName || 'Admin',
3335
createdAt: params?.createdAt || new Date(),
3436
updatedAt: new Date(),
3537
publicMetadata: {},
@@ -79,6 +81,7 @@ export const createFakeDomain = (params: FakeDomainParams): OrganizationDomainRe
7981
type FakeInvitationParams = {
8082
id: string;
8183
role?: OrganizationCustomRoleKey;
84+
roleName?: string;
8285
status?: OrganizationInvitationStatus;
8386
emailAddress: string;
8487
organizationId: string;
@@ -93,6 +96,7 @@ export const createFakeOrganizationInvitation = (params: FakeInvitationParams):
9396
organizationId: params.organizationId,
9497
publicMetadata: {} as any,
9598
role: params.role || 'basic_member',
99+
roleName: params.roleName || 'Basic Member',
96100
status: params.status || 'pending',
97101
createdAt: params?.createdAt || new Date(),
98102
updatedAt: new Date(),

packages/types/src/json.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ export interface OrganizationMembershipJSON extends ClerkResourceJSON {
392392
public_metadata: OrganizationMembershipPublicMetadata;
393393
public_user_data?: PublicUserDataJSON;
394394
role: OrganizationCustomRoleKey;
395+
role_name: string;
395396
created_at: number;
396397
updated_at: number;
397398
}
@@ -404,6 +405,7 @@ export interface OrganizationInvitationJSON extends ClerkResourceJSON {
404405
public_metadata: OrganizationInvitationPublicMetadata;
405406
status: OrganizationInvitationStatus;
406407
role: OrganizationCustomRoleKey;
408+
role_name: string;
407409
created_at: number;
408410
updated_at: number;
409411
}

0 commit comments

Comments
 (0)