forked from baron/baron-sso
변경 RP 카드 변경자 표시 추가
This commit is contained in:
@@ -52,6 +52,7 @@ import { Textarea } from "../../components/ui/textarea";
|
||||
import {
|
||||
type ClientSummary,
|
||||
type DevAuditLog,
|
||||
fetchDevUser,
|
||||
fetchClients,
|
||||
fetchDeveloperRequestStatus,
|
||||
fetchDevStats,
|
||||
@@ -68,6 +69,7 @@ import {
|
||||
formatAuditDateParts,
|
||||
formatAuditValue,
|
||||
parseAuditDetails,
|
||||
resolveAuditActor,
|
||||
} from "../../../../common/core/audit";
|
||||
|
||||
type ClientSortKey = "application" | "id" | "type" | "status" | "createdAt";
|
||||
@@ -76,6 +78,8 @@ type RecentClientChange = {
|
||||
eventId: string;
|
||||
clientId: string;
|
||||
clientName: string;
|
||||
actorId: string;
|
||||
actorName: string;
|
||||
action: string;
|
||||
actionLabel: string;
|
||||
timestamp: string;
|
||||
@@ -488,6 +492,8 @@ function ClientsPage() {
|
||||
eventId: item.event_id,
|
||||
clientId,
|
||||
clientName: clientNameById.get(clientId) || clientId,
|
||||
actorId: resolveAuditActor(item, details),
|
||||
actorName: "",
|
||||
action,
|
||||
actionLabel: getRecentClientActionLabel(action),
|
||||
timestamp: item.timestamp,
|
||||
@@ -498,10 +504,45 @@ function ClientsPage() {
|
||||
.slice(0, 4);
|
||||
}, [clients, recentAuditData?.items]);
|
||||
|
||||
const recentChangedClientCount = useMemo(() => {
|
||||
return new Set(recentClientChanges.map((item) => item.clientId)).size;
|
||||
const recentClientActorIds = useMemo(() => {
|
||||
return Array.from(
|
||||
new Set(
|
||||
recentClientChanges
|
||||
.map((item) => item.actorId.trim())
|
||||
.filter((actorId) => actorId && actorId !== "-"),
|
||||
),
|
||||
);
|
||||
}, [recentClientChanges]);
|
||||
|
||||
const { data: recentClientActors } = useQuery({
|
||||
queryKey: ["recent-client-actors", recentClientActorIds],
|
||||
queryFn: async () => {
|
||||
const entries = await Promise.all(
|
||||
recentClientActorIds.map(async (actorId) => {
|
||||
try {
|
||||
const user = await fetchDevUser(actorId);
|
||||
return [actorId, user.name || actorId] as const;
|
||||
} catch {
|
||||
return [actorId, actorId] as const;
|
||||
}
|
||||
}),
|
||||
);
|
||||
return Object.fromEntries(entries);
|
||||
},
|
||||
enabled: recentClientActorIds.length > 0,
|
||||
});
|
||||
|
||||
const recentClientChangesWithActors = useMemo(() => {
|
||||
return recentClientChanges.map((item) => ({
|
||||
...item,
|
||||
actorName: recentClientActors?.[item.actorId] || item.actorId,
|
||||
}));
|
||||
}, [recentClientActors, recentClientChanges]);
|
||||
|
||||
const recentChangedClientCount = useMemo(() => {
|
||||
return new Set(recentClientChangesWithActors.map((item) => item.clientId)).size;
|
||||
}, [recentClientChangesWithActors]);
|
||||
|
||||
const isLoading =
|
||||
isLoadingClients ||
|
||||
isLoadingStats ||
|
||||
@@ -1052,7 +1093,7 @@ function ClientsPage() {
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
recentClientChanges.map((item) => {
|
||||
recentClientChangesWithActors.map((item) => {
|
||||
const { date, time } = formatAuditDateParts(item.timestamp);
|
||||
return (
|
||||
<div
|
||||
@@ -1070,6 +1111,12 @@ function ClientsPage() {
|
||||
<code className="rounded-md bg-secondary/60 px-2 py-1 font-mono text-xs text-muted-foreground">
|
||||
{item.clientId}
|
||||
</code>
|
||||
<span className="font-semibold">
|
||||
{item.actorName}
|
||||
</span>
|
||||
<code className="rounded-md bg-secondary/60 px-2 py-1 font-mono text-xs text-muted-foreground">
|
||||
{item.actorId}
|
||||
</code>
|
||||
<Badge variant="muted">{item.actionLabel}</Badge>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
|
||||
@@ -177,6 +177,27 @@ export type DevAssignableUserListResponse = {
|
||||
items: DevAssignableUser[];
|
||||
};
|
||||
|
||||
export type DevUserSummary = {
|
||||
id: string;
|
||||
email: string;
|
||||
loginId?: string;
|
||||
name: string;
|
||||
phone?: string;
|
||||
role: string;
|
||||
status: string;
|
||||
tenantSlug?: string;
|
||||
companyCode?: string;
|
||||
tenant?: TenantSummary;
|
||||
joinedTenants?: TenantSummary[];
|
||||
metadata?: Record<string, unknown>;
|
||||
department?: string;
|
||||
grade?: string;
|
||||
position?: string;
|
||||
jobTitle?: string;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
|
||||
export type ConsentSummary = {
|
||||
subject: string;
|
||||
userName?: string;
|
||||
@@ -290,6 +311,11 @@ export async function fetchDevUsers(
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function fetchDevUser(userId: string) {
|
||||
const { data } = await apiClient.get<DevUserSummary>(`/admin/users/${userId}`);
|
||||
return data;
|
||||
}
|
||||
|
||||
export async function addClientRelation(
|
||||
clientId: string,
|
||||
payload: ClientRelationUpsertRequest,
|
||||
|
||||
Reference in New Issue
Block a user