Skip to content

Commit 5d790ae

Browse files
committed
Not enough permissions tooltip
1 parent a607b6c commit 5d790ae

1 file changed

Lines changed: 50 additions & 36 deletions

File tree

  • apps/webapp/app/routes/_app.orgs.$organizationSlug.settings.team

apps/webapp/app/routes/_app.orgs.$organizationSlug.settings.team/route.tsx

Lines changed: 50 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -593,44 +593,58 @@ function RolePicker({
593593
const error =
594594
fetcher.data && "error" in fetcher.data && fetcher.data.error ? fetcher.data.error : null;
595595

596+
const picker = (
597+
<Select
598+
defaultValue={currentRoleId ?? ""}
599+
items={roles}
600+
variant="tertiary/small"
601+
disabled={!canManageMembers || isSubmitting}
602+
dropdownIcon
603+
text={(v) => roles.find((r) => r.id === v)?.name ?? "No role"}
604+
setValue={(next) => {
605+
if (typeof next !== "string" || next === (currentRoleId ?? "")) return;
606+
// Upgrade-link rows have a value too (Ariakit needs one to
607+
// make the row interactive — without it the Link inside
608+
// doesn't even register the click), but they shouldn't
609+
// submit the role-change form. The Link navigates the user
610+
// to the plan-selection page; we just bail here.
611+
if (!assignable.has(next)) return;
612+
fetcher.submit(
613+
{ _formType: "set-role", userId: memberUserId, roleId: next },
614+
{ method: "post" }
615+
);
616+
}}
617+
>
618+
{(items) =>
619+
items.map((role) => {
620+
const isAssignable = assignable.has(role.id);
621+
return isAssignable ? (
622+
<SelectItem key={role.id} value={role.id}>
623+
{role.name}
624+
</SelectItem>
625+
) : (
626+
<SelectLinkItem key={role.id} value={role.id} to={v3BillingPath(organization)}>
627+
{role.name} (upgrade)
628+
</SelectLinkItem>
629+
);
630+
})
631+
}
632+
</Select>
633+
);
634+
596635
return (
597636
<div className="flex flex-col items-end gap-1">
598-
<Select
599-
defaultValue={currentRoleId ?? ""}
600-
items={roles}
601-
variant="tertiary/small"
602-
disabled={!canManageMembers || isSubmitting}
603-
dropdownIcon
604-
text={(v) => roles.find((r) => r.id === v)?.name ?? "No role"}
605-
setValue={(next) => {
606-
if (typeof next !== "string" || next === (currentRoleId ?? "")) return;
607-
// Upgrade-link rows have a value too (Ariakit needs one to
608-
// make the row interactive — without it the Link inside
609-
// doesn't even register the click), but they shouldn't
610-
// submit the role-change form. The Link navigates the user
611-
// to the plan-selection page; we just bail here.
612-
if (!assignable.has(next)) return;
613-
fetcher.submit(
614-
{ _formType: "set-role", userId: memberUserId, roleId: next },
615-
{ method: "post" }
616-
);
617-
}}
618-
>
619-
{(items) =>
620-
items.map((role) => {
621-
const isAssignable = assignable.has(role.id);
622-
return isAssignable ? (
623-
<SelectItem key={role.id} value={role.id}>
624-
{role.name}
625-
</SelectItem>
626-
) : (
627-
<SelectLinkItem key={role.id} value={role.id} to={v3BillingPath(organization)}>
628-
{role.name} (upgrade)
629-
</SelectLinkItem>
630-
);
631-
})
632-
}
633-
</Select>
637+
{canManageMembers ? (
638+
picker
639+
) : (
640+
// Disabled <Select> swallows hover events on its own, so wrap it
641+
// in a div the tooltip can attach to.
642+
<SimpleTooltip
643+
button={<div className="cursor-not-allowed">{picker}</div>}
644+
content="You don't have permission to change roles"
645+
disableHoverableContent
646+
/>
647+
)}
634648
{error ? (
635649
<span className="text-xs text-error" role="alert">
636650
{error}

0 commit comments

Comments
 (0)