larxius commited on
Commit
e778b42
·
verified ·
1 Parent(s): 0e06c34

Update frontend/src/pages/LogsAndThreats.jsx

Browse files
Files changed (1) hide show
  1. frontend/src/pages/LogsAndThreats.jsx +106 -21
frontend/src/pages/LogsAndThreats.jsx CHANGED
@@ -1,7 +1,7 @@
1
  import React, { useState, useEffect } from 'react';
2
  import { Link } from 'react-router-dom';
3
  import { useAuth } from '../components/AuthContext';
4
- import { ShieldAlert, Search, Download, RefreshCw, List, ArrowLeft } from 'lucide-react';
5
 
6
  const LogsAndThreats = () => {
7
  const { user, loading: authLoading } = useAuth();
@@ -13,7 +13,11 @@ const LogsAndThreats = () => {
13
  const [isFullLogsView, setIsFullLogsView] = useState(false);
14
  const [allLogs, setAllLogs] = useState([]);
15
  const [loadingAllLogs, setLoadingAllLogs] = useState(false);
 
 
16
  const [searchQuery, setSearchQuery] = useState('');
 
 
17
 
18
  const [sortLogCol, setSortLogCol] = useState('Timestamp');
19
  const [sortLogDir, setSortLogDir] = useState('desc');
@@ -74,15 +78,50 @@ const LogsAndThreats = () => {
74
  setIsFullLogsView(false);
75
  };
76
 
 
 
 
 
 
 
77
  const filteredAllLogs = allLogs.filter(log => {
78
- if (!searchQuery) return true;
79
- const q = searchQuery.toLowerCase();
80
- return (
81
- (log.action && log.action.toLowerCase().includes(q)) ||
82
- (log.user_email && log.user_email.toLowerCase().includes(q)) ||
83
- (log.target_name && log.target_name.toLowerCase().includes(q)) ||
84
- (log.target_id && log.target_id.toLowerCase().includes(q))
85
- );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  });
87
 
88
  const handleLogSort = (column) => {
@@ -204,19 +243,65 @@ const LogsAndThreats = () => {
204
  </div>
205
 
206
  {/* Filter and Search Bar */}
207
- <div className="mb-md bg-surface-container-lowest border border-outline-variant/70 rounded-xl p-4 flex flex-col sm:flex-row items-center justify-between gap-3 shadow-2xs">
208
- <div className="relative w-full sm:w-80">
209
- <Search className="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-on-surface-variant" />
210
- <input
211
- type="text"
212
- placeholder="Search user, action, or target..."
213
- value={searchQuery}
214
- onChange={(e) => setSearchQuery(e.target.value)}
215
- className="w-full pl-9 pr-3 py-2 bg-surface border border-outline-variant/60 rounded-lg text-[13.5px] text-on-surface focus:outline-none focus:border-primary"
216
- />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
217
  </div>
218
- <div className="text-[12.5px] text-on-surface-variant font-medium">
219
- Showing <strong className="text-on-surface font-bold">{getSortedLogs().length}</strong> audit event entries
 
220
  </div>
221
  </div>
222
 
 
1
  import React, { useState, useEffect } from 'react';
2
  import { Link } from 'react-router-dom';
3
  import { useAuth } from '../components/AuthContext';
4
+ import { ShieldAlert, Search, Download, RefreshCw, List, ArrowLeft, Filter } from 'lucide-react';
5
 
6
  const LogsAndThreats = () => {
7
  const { user, loading: authLoading } = useAuth();
 
13
  const [isFullLogsView, setIsFullLogsView] = useState(false);
14
  const [allLogs, setAllLogs] = useState([]);
15
  const [loadingAllLogs, setLoadingAllLogs] = useState(false);
16
+
17
+ // Filters State
18
  const [searchQuery, setSearchQuery] = useState('');
19
+ const [actionCategory, setActionCategory] = useState('all');
20
+ const [dateFilter, setDateFilter] = useState('all');
21
 
22
  const [sortLogCol, setSortLogCol] = useState('Timestamp');
23
  const [sortLogDir, setSortLogDir] = useState('desc');
 
78
  setIsFullLogsView(false);
79
  };
80
 
81
+ const clearFilters = () => {
82
+ setSearchQuery('');
83
+ setActionCategory('all');
84
+ setDateFilter('all');
85
+ };
86
+
87
  const filteredAllLogs = allLogs.filter(log => {
88
+ // Search query filter
89
+ if (searchQuery) {
90
+ const q = searchQuery.toLowerCase();
91
+ const matchQuery = (
92
+ (log.action && log.action.toLowerCase().includes(q)) ||
93
+ (log.user_email && log.user_email.toLowerCase().includes(q)) ||
94
+ (log.target_name && log.target_name.toLowerCase().includes(q)) ||
95
+ (log.target_id && log.target_id.toLowerCase().includes(q))
96
+ );
97
+ if (!matchQuery) return false;
98
+ }
99
+
100
+ // Action Category filter
101
+ if (actionCategory !== 'all') {
102
+ const act = (log.action || '').toLowerCase();
103
+ if (actionCategory === 'logins' && !act.includes('log')) return false;
104
+ if (actionCategory === 'users' && !act.includes('user') && !act.includes('member') && !act.includes('role')) return false;
105
+ if (actionCategory === 'scans' && !act.includes('scan')) return false;
106
+ if (actionCategory === 'settings' && !act.includes('setting') && !act.includes('quota') && !act.includes('tier') && !act.includes('config')) return false;
107
+ }
108
+
109
+ // Date filter
110
+ if (dateFilter !== 'all' && log.timestamp) {
111
+ const logDate = new Date(log.timestamp);
112
+ const now = new Date();
113
+ if (dateFilter === 'today') {
114
+ if (logDate.toDateString() !== now.toDateString()) return false;
115
+ } else if (dateFilter === '7days') {
116
+ const sevenDaysAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000);
117
+ if (logDate < sevenDaysAgo) return false;
118
+ } else if (dateFilter === '30days') {
119
+ const thirtyDaysAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000);
120
+ if (logDate < thirtyDaysAgo) return false;
121
+ }
122
+ }
123
+
124
+ return true;
125
  });
126
 
127
  const handleLogSort = (column) => {
 
243
  </div>
244
 
245
  {/* Filter and Search Bar */}
246
+ <div className="mb-md bg-surface-container-lowest border border-outline-variant/70 rounded-xl p-4 flex flex-col md:flex-row items-center justify-between gap-3 shadow-2xs">
247
+ <div className="flex flex-wrap items-center gap-3 w-full md:w-auto flex-1">
248
+ {/* Search Input */}
249
+ <div className="relative w-full sm:w-64">
250
+ <Search className="w-4 h-4 absolute left-3 top-1/2 -translate-y-1/2 text-on-surface-variant" />
251
+ <input
252
+ type="text"
253
+ placeholder="Search user, action, or target..."
254
+ value={searchQuery}
255
+ onChange={(e) => setSearchQuery(e.target.value)}
256
+ className="w-full pl-9 pr-3 py-2 bg-surface border border-outline-variant/60 rounded-lg text-[13px] text-on-surface focus:outline-none focus:border-primary"
257
+ />
258
+ </div>
259
+
260
+ {/* Action Category Dropdown */}
261
+ <div className="flex items-center gap-1.5 w-full sm:w-auto">
262
+ <span className="text-[11px] font-bold text-on-surface-variant uppercase tracking-wider shrink-0">Type:</span>
263
+ <select
264
+ value={actionCategory}
265
+ onChange={(e) => setActionCategory(e.target.value)}
266
+ className="bg-surface border border-outline-variant/60 text-on-surface text-[13px] font-medium rounded-lg px-3 py-2 focus:outline-none focus:border-primary cursor-pointer w-full sm:w-auto"
267
+ >
268
+ <option value="all">All Action Types</option>
269
+ <option value="logins">Logins & Auth</option>
270
+ <option value="users">User & Role Changes</option>
271
+ <option value="scans">Scan Activity</option>
272
+ <option value="settings">Settings & Quotas</option>
273
+ </select>
274
+ </div>
275
+
276
+ {/* Date Range Dropdown */}
277
+ <div className="flex items-center gap-1.5 w-full sm:w-auto">
278
+ <span className="text-[11px] font-bold text-on-surface-variant uppercase tracking-wider shrink-0">Time:</span>
279
+ <select
280
+ value={dateFilter}
281
+ onChange={(e) => setDateFilter(e.target.value)}
282
+ className="bg-surface border border-outline-variant/60 text-on-surface text-[13px] font-medium rounded-lg px-3 py-2 focus:outline-none focus:border-primary cursor-pointer w-full sm:w-auto"
283
+ >
284
+ <option value="all">All Time</option>
285
+ <option value="today">Today</option>
286
+ <option value="7days">Last 7 Days</option>
287
+ <option value="30days">Last 30 Days</option>
288
+ </select>
289
+ </div>
290
+
291
+ {/* Clear Filters Button */}
292
+ {(searchQuery || actionCategory !== 'all' || dateFilter !== 'all') && (
293
+ <button
294
+ onClick={clearFilters}
295
+ className="text-error hover:underline text-[12.5px] font-bold flex items-center gap-1 cursor-pointer bg-transparent border-0 px-1"
296
+ >
297
+ <span className="material-symbols-outlined text-[16px]">close</span>
298
+ Reset Filters
299
+ </button>
300
+ )}
301
  </div>
302
+
303
+ <div className="text-[12.5px] text-on-surface-variant font-medium shrink-0">
304
+ Showing <strong className="text-on-surface font-bold">{getSortedLogs().length}</strong> of {allLogs.length} entries
305
  </div>
306
  </div>
307