add idp auto provision override on user

This commit is contained in:
miloschwartz
2025-09-05 16:14:01 -07:00
parent 90456339ca
commit b0bd9279fc
24 changed files with 744 additions and 317 deletions

View File

@@ -20,12 +20,14 @@ import {
} from "@app/components/ui/dropdown-menu";
import Link from "next/link";
import { useTranslations } from "next-intl";
import IdpTypeBadge from "./IdpTypeBadge";
export type IdpRow = {
idpId: number;
name: string;
type: string;
orgCount: number;
variant?: string;
};
type Props = {
@@ -57,15 +59,6 @@ export default function IdpTable({ idps }: Props) {
}
};
const getTypeDisplay = (type: string) => {
switch (type) {
case "oidc":
return "OAuth2/OIDC";
default:
return type;
}
};
const columns: ColumnDef<IdpRow>[] = [
{
accessorKey: "idpId",
@@ -116,9 +109,8 @@ export default function IdpTable({ idps }: Props) {
},
cell: ({ row }) => {
const type = row.original.type;
return (
<Badge variant="secondary">{getTypeDisplay(type)}</Badge>
);
const variant = row.original.variant;
return <IdpTypeBadge type={type} variant={variant} />;
}
},
{

View File

@@ -0,0 +1,62 @@
"use client";
import { Badge } from "@app/components/ui/badge";
import Image from "next/image";
type IdpTypeBadgeProps = {
type: string;
variant?: string;
name?: string;
};
export default function IdpTypeBadge({
type,
variant,
name
}: IdpTypeBadgeProps) {
const effectiveType = variant || type;
const effectiveName = name || formatType(effectiveType);
function formatType(type: string) {
if (type === "google") return "Google";
if (type === "azure") return "Azure";
if (type === "oidc") return "OAuth2/OIDC";
return type.charAt(0).toUpperCase() + type.slice(1);
}
return (
<Badge
variant="secondary"
className="inline-flex items-center space-x-1 w-fit"
>
{effectiveType === "google" && (
<>
<Image
src="/idp/google.png"
alt="Google"
width={16}
height={16}
className="rounded"
/>
<span>{effectiveName}</span>
</>
)}
{effectiveType === "azure" && (
<>
<Image
src="/idp/azure.png"
alt="Azure"
width={16}
height={16}
className="rounded"
/>
<span>{effectiveName}</span>
</>
)}
{effectiveType === "oidc" && <span>{effectiveName}</span>}
{!["google", "azure", "oidc"].includes(effectiveType) && (
<span>{effectiveName}</span>
)}
</Badge>
);
}

View File

@@ -46,6 +46,7 @@ import { startAuthentication } from "@simplewebauthn/browser";
export type LoginFormIDP = {
idpId: number;
name: string;
variant?: string;
};
type LoginFormProps = {
@@ -496,19 +497,41 @@ export default function LoginForm({ redirect, onLogin, idps }: LoginFormProps) {
</div>
</div>
{idps.map((idp) => (
<Button
key={idp.idpId}
type="button"
variant="outline"
className="w-full"
onClick={() => {
loginWithIdp(idp.idpId);
}}
>
{idp.name}
</Button>
))}
{idps.map((idp) => {
const effectiveType = idp.variant || idp.name.toLowerCase();
return (
<Button
key={idp.idpId}
type="button"
variant="outline"
className="w-full inline-flex items-center space-x-2"
onClick={() => {
loginWithIdp(idp.idpId);
}}
>
{effectiveType === "google" && (
<Image
src="/idp/google.png"
alt="Google"
width={16}
height={16}
className="rounded"
/>
)}
{effectiveType === "azure" && (
<Image
src="/idp/azure.png"
alt="Azure"
width={16}
height={16}
className="rounded"
/>
)}
<span>{idp.name}</span>
</Button>
);
})}
</>
)}
</>

View File

@@ -27,7 +27,9 @@ function getActionsCategories(root: boolean) {
[t('actionListInvitations')]: "listInvitations",
[t('actionRemoveUser')]: "removeUser",
[t('actionListUsers')]: "listUsers",
[t('actionListOrgDomains')]: "listOrgDomains"
[t('actionListOrgDomains')]: "listOrgDomains",
[t('updateOrgUser')]: "updateOrgUser",
[t('createOrgUser')]: "createOrgUser"
},
Site: {

View File

@@ -21,6 +21,7 @@ import { createApiClient } from "@app/lib/api";
import { useEnvContext } from "@app/hooks/useEnvContext";
import { useUserContext } from "@app/hooks/useUserContext";
import { useTranslations } from "next-intl";
import IdpTypeBadge from "./IdpTypeBadge";
export type UserRow = {
id: string;
@@ -31,6 +32,7 @@ export type UserRow = {
idpId: number | null;
idpName: string;
type: string;
idpVariant: string | null;
status: string;
role: string;
isOwner: boolean;
@@ -81,6 +83,16 @@ export default function UsersTable({ users: u }: UsersTableProps) {
<ArrowUpDown className="ml-2 h-4 w-4" />
</Button>
);
},
cell: ({ row }) => {
const userRow = row.original;
return (
<IdpTypeBadge
type={userRow.type}
name={userRow.idpName}
variant={userRow.idpVariant || undefined}
/>
);
}
},
{