1
0
forked from baron/baron-sso

변경 RP 카드 변경자 표시 추가

This commit is contained in:
2026-05-27 14:44:52 +09:00
parent 262c5959cf
commit addded8942
2 changed files with 76 additions and 3 deletions

View File

@@ -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">

View File

@@ -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,