forked from baron/baron-sso
감사로그 조회 전체 새로고침 현상 수정
This commit is contained in:
@@ -126,16 +126,26 @@ function AuditLogsPage() {
|
|||||||
const [searchClientId, setSearchClientId] = React.useState("");
|
const [searchClientId, setSearchClientId] = React.useState("");
|
||||||
const [searchAction, setSearchAction] = React.useState("");
|
const [searchAction, setSearchAction] = React.useState("");
|
||||||
const [statusFilter, setStatusFilter] = React.useState("all");
|
const [statusFilter, setStatusFilter] = React.useState("all");
|
||||||
|
|
||||||
|
// Use deferred values to avoid UI lag during rapid typing
|
||||||
|
const deferredSearchClientId = React.useDeferredValue(searchClientId.trim());
|
||||||
|
const deferredSearchAction = React.useDeferredValue(searchAction.trim());
|
||||||
|
|
||||||
const [expandedRows, setExpandedRows] = React.useState<
|
const [expandedRows, setExpandedRows] = React.useState<
|
||||||
Record<string, boolean>
|
Record<string, boolean>
|
||||||
>({});
|
>({});
|
||||||
|
|
||||||
const query = useInfiniteQuery({
|
const query = useInfiniteQuery({
|
||||||
queryKey: ["dev-audit-logs", searchClientId, searchAction, statusFilter],
|
queryKey: [
|
||||||
|
"dev-audit-logs",
|
||||||
|
deferredSearchClientId,
|
||||||
|
deferredSearchAction,
|
||||||
|
statusFilter,
|
||||||
|
],
|
||||||
queryFn: ({ pageParam }) =>
|
queryFn: ({ pageParam }) =>
|
||||||
fetchDevAuditLogs(50, pageParam, {
|
fetchDevAuditLogs(50, pageParam, {
|
||||||
client_id: searchClientId.trim() || undefined,
|
client_id: deferredSearchClientId || undefined,
|
||||||
action: searchAction.trim() || undefined,
|
action: deferredSearchAction || undefined,
|
||||||
status: statusFilter !== "all" ? statusFilter : undefined,
|
status: statusFilter !== "all" ? statusFilter : undefined,
|
||||||
}),
|
}),
|
||||||
initialPageParam: undefined as string | undefined,
|
initialPageParam: undefined as string | undefined,
|
||||||
@@ -160,14 +170,6 @@ function AuditLogsPage() {
|
|||||||
downloadCsv(csv, `dev-audit-logs-${stamp}.csv`);
|
downloadCsv(csv, `dev-audit-logs-${stamp}.csv`);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (query.isLoading) {
|
|
||||||
return (
|
|
||||||
<div className="p-8 text-center">
|
|
||||||
{t("msg.dev.audit.loading", "Loading audit logs...")}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (query.error) {
|
if (query.error) {
|
||||||
const axiosError = query.error as AxiosError<{ error?: string }>;
|
const axiosError = query.error as AxiosError<{ error?: string }>;
|
||||||
if (axiosError.response?.status === 403) {
|
if (axiosError.response?.status === 403) {
|
||||||
@@ -227,7 +229,13 @@ function AuditLogsPage() {
|
|||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardContent className="space-y-4">
|
<CardContent className="space-y-4">
|
||||||
<div className="grid gap-2 md:grid-cols-[1fr,1fr,180px]">
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
query.refetch();
|
||||||
|
}}
|
||||||
|
className="grid gap-2 md:grid-cols-[1fr,1fr,180px]"
|
||||||
|
>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
<Search className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
||||||
<Input
|
<Input
|
||||||
@@ -263,8 +271,15 @@ function AuditLogsPage() {
|
|||||||
{t("ui.common.status.failure", "Failure")}
|
{t("ui.common.status.failure", "Failure")}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</form>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
query.isFetching && !query.isFetchingNextPage
|
||||||
|
? "opacity-50 transition-opacity"
|
||||||
|
: ""
|
||||||
|
}
|
||||||
|
>
|
||||||
<Table className="table-fixed">
|
<Table className="table-fixed">
|
||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
@@ -287,7 +302,16 @@ function AuditLogsPage() {
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
{logs.length === 0 && (
|
{query.isLoading && logs.length === 0 ? (
|
||||||
|
<TableRow>
|
||||||
|
<TableCell
|
||||||
|
colSpan={6}
|
||||||
|
className="py-8 text-center text-muted-foreground"
|
||||||
|
>
|
||||||
|
{t("msg.dev.audit.loading", "Loading audit logs...")}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
) : logs.length === 0 ? (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell
|
<TableCell
|
||||||
colSpan={6}
|
colSpan={6}
|
||||||
@@ -296,8 +320,8 @@ function AuditLogsPage() {
|
|||||||
{t("msg.dev.audit.empty", "No audit logs found.")}
|
{t("msg.dev.audit.empty", "No audit logs found.")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
) : (
|
||||||
{logs.map((row, index) => {
|
logs.map((row, index) => {
|
||||||
const details = parseDetails(row.details);
|
const details = parseDetails(row.details);
|
||||||
const actionLabel = details.action || row.event_type;
|
const actionLabel = details.action || row.event_type;
|
||||||
const targetValue = details.target_id || "-";
|
const targetValue = details.target_id || "-";
|
||||||
@@ -396,9 +420,11 @@ function AuditLogsPage() {
|
|||||||
) : null}
|
) : null}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
})}
|
})
|
||||||
|
)}
|
||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
|
</div>
|
||||||
|
|
||||||
{query.hasNextPage ? (
|
{query.hasNextPage ? (
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
|
|||||||
Reference in New Issue
Block a user