mirror of
https://github.com/fosrl/pangolin.git
synced 2026-06-19 05:42:47 +00:00
show user idp in devices
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { z } from "zod";
|
||||
import { db, olms, users } from "@server/db";
|
||||
import { db, idp, idpOidcConfig, olms, users } from "@server/db";
|
||||
import { clients, currentFingerprint } from "@server/db";
|
||||
import { eq, and } from "drizzle-orm";
|
||||
import { and, eq } from "drizzle-orm";
|
||||
import response from "@server/lib/response";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
import createHttpError from "http-errors";
|
||||
@@ -236,6 +236,9 @@ export type GetClientResponse = NonNullable<
|
||||
lastSeen: number | null;
|
||||
} | null;
|
||||
posture: PostureData | null;
|
||||
userType: string | null;
|
||||
idpName: string | null;
|
||||
idpVariant: string | null;
|
||||
};
|
||||
|
||||
registry.registerPath({
|
||||
@@ -337,6 +340,30 @@ export async function getClient(
|
||||
: maskPostureDataWithPlaceholder(rawPosture)
|
||||
: null;
|
||||
|
||||
let userType: string | null = null;
|
||||
let idpName: string | null = null;
|
||||
let idpVariant: string | null = null;
|
||||
|
||||
if (client.clients.userId) {
|
||||
const [idpRow] = await db
|
||||
.select({
|
||||
userType: users.type,
|
||||
idpName: idp.name,
|
||||
idpVariant: idpOidcConfig.variant
|
||||
})
|
||||
.from(users)
|
||||
.leftJoin(idp, eq(users.idpId, idp.idpId))
|
||||
.leftJoin(idpOidcConfig, eq(idpOidcConfig.idpId, idp.idpId))
|
||||
.where(eq(users.userId, client.clients.userId))
|
||||
.limit(1);
|
||||
|
||||
if (idpRow) {
|
||||
userType = idpRow.userType;
|
||||
idpName = idpRow.idpName;
|
||||
idpVariant = idpRow.idpVariant;
|
||||
}
|
||||
}
|
||||
|
||||
const data: GetClientResponse = {
|
||||
...client.clients,
|
||||
name: clientName,
|
||||
@@ -347,7 +374,10 @@ export async function getClient(
|
||||
userName: client.user?.name ?? null,
|
||||
userUsername: client.user?.username ?? null,
|
||||
fingerprint: fingerprintData,
|
||||
posture: postureData
|
||||
posture: postureData,
|
||||
userType,
|
||||
idpName,
|
||||
idpVariant
|
||||
};
|
||||
|
||||
return response<GetClientResponse>(res, {
|
||||
|
||||
@@ -3,6 +3,8 @@ import {
|
||||
clients,
|
||||
currentFingerprint,
|
||||
db,
|
||||
idp,
|
||||
idpOidcConfig,
|
||||
olms,
|
||||
orgs,
|
||||
roleClients,
|
||||
@@ -165,6 +167,9 @@ function queryUserDevicesBase() {
|
||||
userId: clients.userId,
|
||||
username: users.username,
|
||||
userEmail: users.email,
|
||||
userType: users.type,
|
||||
idpName: idp.name,
|
||||
idpVariant: idpOidcConfig.variant,
|
||||
niceId: clients.niceId,
|
||||
agent: olms.agent,
|
||||
approvalState: clients.approvalState,
|
||||
@@ -184,6 +189,8 @@ function queryUserDevicesBase() {
|
||||
.leftJoin(orgs, eq(clients.orgId, orgs.orgId))
|
||||
.leftJoin(olms, eq(clients.clientId, olms.clientId))
|
||||
.leftJoin(users, eq(clients.userId, users.userId))
|
||||
.leftJoin(idp, eq(users.idpId, idp.idpId))
|
||||
.leftJoin(idpOidcConfig, eq(idpOidcConfig.idpId, idp.idpId))
|
||||
.leftJoin(currentFingerprint, eq(olms.olmId, currentFingerprint.olmId));
|
||||
}
|
||||
|
||||
|
||||
@@ -96,6 +96,9 @@ export default async function ClientsPage(props: ClientsPageProps) {
|
||||
userId: client.userId,
|
||||
username: client.username,
|
||||
userEmail: client.userEmail,
|
||||
userType: client.userType ?? null,
|
||||
idpName: client.idpName ?? null,
|
||||
idpVariant: client.idpVariant ?? null,
|
||||
niceId: client.niceId,
|
||||
agent: client.agent,
|
||||
archived: Boolean(client.archived),
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
InfoSections,
|
||||
InfoSectionTitle
|
||||
} from "@app/components/InfoSection";
|
||||
import IdpTypeBadge from "@app/components/IdpTypeBadge";
|
||||
import { getUserDisplayName } from "@app/lib/getUserDisplayName";
|
||||
import { useTranslations } from "next-intl";
|
||||
|
||||
@@ -36,7 +37,24 @@ export default function SiteInfoCard({}: ClientInfoCardProps) {
|
||||
{userDisplayName ? t("user") : t("identifier")}
|
||||
</InfoSectionTitle>
|
||||
<InfoSectionContent>
|
||||
{userDisplayName || client.niceId}
|
||||
<div className="flex flex-wrap items-center gap-2">
|
||||
<span>{userDisplayName || client.niceId}</span>
|
||||
{userDisplayName &&
|
||||
(client.userType ?? "internal") !==
|
||||
"internal" && (
|
||||
<IdpTypeBadge
|
||||
type={client.userType ?? "oidc"}
|
||||
name={
|
||||
client.idpName?.trim()
|
||||
? client.idpName
|
||||
: t("idpNameInternal")
|
||||
}
|
||||
variant={
|
||||
client.idpVariant ?? undefined
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</InfoSectionContent>
|
||||
</InfoSection>
|
||||
<InfoSection>
|
||||
|
||||
@@ -35,6 +35,7 @@ import { useMemo, useState, useTransition } from "react";
|
||||
import { useDebouncedCallback } from "use-debounce";
|
||||
import ClientDownloadBanner from "./ClientDownloadBanner";
|
||||
import { ColumnFilterButton } from "./ColumnFilterButton";
|
||||
import IdpTypeBadge from "./IdpTypeBadge";
|
||||
import { Badge } from "./ui/badge";
|
||||
import { ControlledDataTable } from "./ui/controlled-data-table";
|
||||
|
||||
@@ -52,6 +53,9 @@ export type ClientRow = {
|
||||
userId: string | null;
|
||||
username: string | null;
|
||||
userEmail: string | null;
|
||||
userType: string | null;
|
||||
idpName: string | null;
|
||||
idpVariant: string | null;
|
||||
niceId: string;
|
||||
agent: string | null;
|
||||
approvalState: "approved" | "pending" | "denied" | null;
|
||||
@@ -370,17 +374,30 @@ export default function UserDevicesTable({
|
||||
cell: ({ row }) => {
|
||||
const r = row.original;
|
||||
return r.userId ? (
|
||||
<Link
|
||||
href={`/${r.orgId}/settings/access/users/${r.userId}`}
|
||||
>
|
||||
<Button variant="outline" size="sm">
|
||||
{getUserDisplayName({
|
||||
email: r.userEmail,
|
||||
username: r.username
|
||||
}) || r.userId}
|
||||
<ArrowUpRight className="ml-2 h-3 w-3" />
|
||||
</Button>
|
||||
</Link>
|
||||
<div className="flex items-center gap-2">
|
||||
<Link
|
||||
href={`/${r.orgId}/settings/access/users/${r.userId}`}
|
||||
>
|
||||
<Button variant="outline" size="sm">
|
||||
{getUserDisplayName({
|
||||
email: r.userEmail,
|
||||
username: r.username
|
||||
}) || r.userId}
|
||||
<ArrowUpRight className="ml-2 h-3 w-3" />
|
||||
</Button>
|
||||
</Link>
|
||||
{(r.userType ?? "internal") !== "internal" && (
|
||||
<IdpTypeBadge
|
||||
type={r.userType ?? "oidc"}
|
||||
name={
|
||||
r.idpName?.trim()
|
||||
? r.idpName
|
||||
: t("idpNameInternal")
|
||||
}
|
||||
variant={r.idpVariant ?? undefined}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
"-"
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user