access logs + audio

This commit is contained in:
hamid zarghami
2025-09-02 17:00:37 +03:30
parent 860f7c446f
commit 0e16af827f
25 changed files with 3394 additions and 83 deletions
+293
View File
@@ -0,0 +1,293 @@
import React, { useState } from "react";
import {
Shield,
Refresh,
InfoCircle,
TickCircle,
CloseCircle
} from "iconsax-react";
import Button from "../../components/Button";
import Pagination from "../../components/Pagination";
import TitleLine from "../../components/TitleLine";
import PageLoading from "../../components/PageLoading";
import FilterPanel from "./components/FilterPanel";
import AccessLogsTable from "./components/AccessLogsTable";
import LogDetailsModal from "./components/LogDetailsModal";
import { useErrorLogs, useAccessLogDetail } from "./hooks/useAccessLogs";
import { AccessLog } from "./types/AccessLogTypes";
const PermissionLogs: React.FC = () => {
const {
errorLogs,
loading,
error,
total,
filters,
updateFilters,
refetch,
} = useErrorLogs();
const { log: selectedLog, fetchLog, clearLog } = useAccessLogDetail();
const [isDetailsModalOpen, setIsDetailsModalOpen] = useState(false);
const handleViewDetails = async (log: AccessLog) => {
await fetchLog(log.id);
setIsDetailsModalOpen(true);
};
const handleCloseDetailsModal = () => {
setIsDetailsModalOpen(false);
clearLog();
};
const handleSort = (field: string, order: "ASC" | "DESC") => {
updateFilters({ sortBy: field, sortOrder: order });
};
const handlePageChange = (page: number) => {
updateFilters({ page });
};
const resetFilters = () => {
updateFilters({
page: 1,
limit: 20,
sortBy: "createdAt",
sortOrder: "DESC",
operationType: undefined,
userType: undefined,
entityName: "",
entityId: "",
userId: "",
ipAddress: "",
endpoint: "",
httpMethod: undefined,
statusCode: undefined,
startDate: "",
endDate: "",
search: "",
minExecutionTime: undefined,
maxExecutionTime: undefined,
});
};
// Filter permission-related logs (assuming they have specific operation types or endpoints)
const permissionLogs = (errorLogs || []).filter((log: AccessLog) => {
return log.operationType?.includes('permission') ||
log.endpoint?.includes('permission') ||
log.entityName?.includes('role') ||
log.entityName?.includes('permission');
});
// Count permission actions
const permissionStats = permissionLogs.reduce((acc: Record<string, number>, log: AccessLog) => {
const action = log.operationType || 'unknown';
acc[action] = (acc[action] || 0) + 1;
return acc;
}, {} as Record<string, number>);
// Count recent permission changes (last 24 hours)
const recentPermissions = permissionLogs.filter((log: AccessLog) => {
const logDate = new Date(log.createdAt);
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
return logDate > oneDayAgo;
}).length;
if (error) {
return (
<div className="p-6">
<TitleLine title="لاگ‌های مجوز" />
<div className="bg-red-50 border border-red-200 rounded-lg p-4">
<div className="flex items-center justify-between">
<p className="text-red-800">{error}</p>
<Button
onClick={refetch}
className="bg-red-600 text-white hover:bg-red-700"
>
تلاش مجدد
</Button>
</div>
</div>
</div>
);
}
return (
<div className="p-6 space-y-6">
{/* Header */}
<div className="flex items-center justify-between">
<div>
<TitleLine title="لاگ‌های مجوز" />
<p className="text-gray-600 mt-2">
مشاهده و تحلیل تغییرات مجوزها و نقشهای کاربری
</p>
</div>
<div className="flex items-center gap-3">
<Button
onClick={refetch}
disabled={loading}
className="flex items-center gap-2 border border-gray-300 bg-white text-gray-700 hover:bg-gray-50"
>
<Refresh size={16} className={loading ? "animate-spin" : ""} />
بروزرسانی
</Button>
</div>
</div>
{/* Permission Stats */}
<div className="grid grid-cols-1 md:grid-cols-4 gap-4">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
<div className="flex items-center gap-3">
<div className="flex-shrink-0 p-2 bg-blue-100 rounded-lg">
<Shield size={20} className="text-blue-600" />
</div>
<div>
<p className="text-sm font-medium text-gray-600">کل تغییرات مجوز</p>
<p className="text-xl font-bold text-gray-900">
{permissionLogs.length.toLocaleString('fa-IR')}
</p>
</div>
</div>
</div>
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
<div className="flex items-center gap-3">
<div className="flex-shrink-0 p-2 bg-green-100 rounded-lg">
<TickCircle size={20} className="text-green-600" />
</div>
<div>
<p className="text-sm font-medium text-gray-600">مجوزهای اعطا شده</p>
<p className="text-xl font-bold text-gray-900">
{(permissionStats['grant'] || 0).toLocaleString('fa-IR')}
</p>
</div>
</div>
</div>
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
<div className="flex items-center gap-3">
<div className="flex-shrink-0 p-2 bg-red-100 rounded-lg">
<CloseCircle size={20} className="text-red-600" />
</div>
<div>
<p className="text-sm font-medium text-gray-600">مجوزهای لغو شده</p>
<p className="text-xl font-bold text-gray-900">
{(permissionStats['revoke'] || 0).toLocaleString('fa-IR')}
</p>
</div>
</div>
</div>
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
<div className="flex items-center gap-3">
<div className="flex-shrink-0 p-2 bg-yellow-100 rounded-lg">
<InfoCircle size={20} className="text-yellow-600" />
</div>
<div>
<p className="text-sm font-medium text-gray-600">24 ساعت گذشته</p>
<p className="text-xl font-bold text-gray-900">
{recentPermissions.toLocaleString('fa-IR')}
</p>
</div>
</div>
</div>
</div>
{/* Security Alert */}
{recentPermissions > 5 && (
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-4">
<div className="flex items-center gap-3">
<Shield size={20} className="text-yellow-600" />
<div>
<h3 className="text-sm font-medium text-yellow-900">تغییرات زیاد مجوز</h3>
<p className="text-sm text-yellow-700 mt-1">
{recentPermissions} تغییر مجوز در 24 ساعت گذشته رخ داده است.
لطفاً این تغییرات را بررسی کنید.
</p>
</div>
</div>
</div>
)}
{/* Filter Panel */}
<FilterPanel
filters={filters}
onFiltersChange={updateFilters}
onReset={resetFilters}
loading={loading}
/>
{/* Loading State */}
{loading && <PageLoading />}
{/* Table */}
{!loading && (
<>
<AccessLogsTable
logs={permissionLogs}
loading={loading}
onViewDetails={handleViewDetails}
onSort={handleSort}
sortBy={filters.sortBy}
sortOrder={filters.sortOrder}
/>
{/* Pagination */}
{total > (filters.limit || 20) && (
<div className="flex justify-center">
<Pagination
currentPage={filters.page || 1}
totalPages={Math.ceil(total / (filters.limit || 20))}
onPageChange={handlePageChange}
/>
</div>
)}
</>
)}
{/* Details Modal */}
<LogDetailsModal
log={selectedLog}
isOpen={isDetailsModalOpen}
onClose={handleCloseDetailsModal}
/>
{/* Empty State Info */}
{!loading && (!permissionLogs || permissionLogs.length === 0) && !error && (
<div className="bg-green-50 border border-green-200 rounded-lg p-6">
<div className="flex items-center gap-3">
<InfoCircle size={24} className="text-green-600" />
<div>
<h3 className="text-lg font-medium text-green-900">هیچ تغییر مجوزی یافت نشد</h3>
<p className="text-green-700 mt-1">
در بازه زمانی و فیلترهای انتخاب شده، هیچ تغییر مجوزی ثبت نشده است.
</p>
</div>
</div>
</div>
)}
{/* Permission Analysis Tips */}
{!loading && permissionLogs && permissionLogs.length > 0 && (
<div className="bg-blue-50 border border-blue-200 rounded-lg p-6">
<div className="flex items-start gap-3">
<InfoCircle size={24} className="text-blue-600 flex-shrink-0 mt-0.5" />
<div>
<h3 className="text-lg font-medium text-blue-900 mb-2">راهنمای تحلیل مجوزها</h3>
<div className="text-blue-700 space-y-2">
<p> <strong>تغییرات نقش:</strong> بررسی تغییرات نقشهای کاربری و مجوزهای مربوطه</p>
<p> <strong>دسترسیهای حساس:</strong> نظارت بر دسترسیهای مهم و حساس سیستم</p>
<p> <strong>الگوهای دسترسی:</strong> شناسایی الگوهای غیرعادی در دسترسیها</p>
<p> <strong>زمانبندی:</strong> توجه به زمان تغییرات مجوزها</p>
<p> <strong>کاربران:</strong> شناسایی کاربرانی که تغییرات مجوز زیادی دارند</p>
</div>
</div>
</div>
</div>
)}
</div>
);
};
export default PermissionLogs;