diff --git a/PROGRESS.md b/PROGRESS.md index 27d6ef6..66539f1 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -62,6 +62,7 @@ 18. **Persistent Workspace Settings:** Added a `Workspace` database model to persist global dashboard settings like Name and Timezone. 19. **Dynamic UI Integration:** Completely refactored the navigation and boards to build columns and tabs dynamically from the live database user list. 20. **Functional Search:** Implemented a real-time task search feature. Clicking the search icon now reveals an inline search bar that filters tasks by title, description, or tags across all views. +21. **Advanced Audit Filtering:** Upgraded the Audit Log for Admins with a search bar and a granular event type filter. Admins can now filter the history by specific actions (e.g., "deleted tasks", "moved tasks", "user management") and search through summaries in real-time. ### Phase 3: Advanced Features - **Real-time Notifications:** Explore WebSockets for task assignments. diff --git a/screens.jsx b/screens.jsx index 883b974..4a55f1d 100644 --- a/screens.jsx +++ b/screens.jsx @@ -636,33 +636,96 @@ function Field({ label, children }) { } function AuditScreen({ entries, onOpen }) { - const [filter, setFilter] = React.useState('all'); + const [actorFilter, setActorFilter] = React.useState('all'); + const [eventFilter, setEventFilter] = React.useState('all'); + const [auditSearch, setAuditSearch] = React.useState(''); + + const EVENT_TYPES = [ + { value: 'all', label: 'All events' }, + { value: 'task', label: 'Tasks (all)' }, + { value: 'task_created', label: 'Created' }, + { value: 'task_moved', label: 'Moved' }, + { value: 'task_completed', label: 'Completed' }, + { value: 'task_deleted', label: 'Deleted' }, + { value: 'task_restored', label: 'Restored' }, + { value: 'user', label: 'User management' }, + { value: 'workspace_updated', label: 'Workspace' }, + ]; + const groups = React.useMemo(() => { - const filtered = filter === 'all' - ? entries - : filter === 'system' - ? entries.filter(e => e.actor === 'system') - : entries.filter(e => e.actor === filter); + let filtered = entries; + + // 1. Actor Filter + if (actorFilter !== 'all') { + filtered = actorFilter === 'system' + ? filtered.filter(e => e.actor === 'system') + : filtered.filter(e => e.actor === actorFilter); + } + + // 2. Event Type Filter + if (eventFilter !== 'all') { + if (eventFilter === 'task') { + filtered = filtered.filter(e => e.action.startsWith('task_')); + } else if (eventFilter === 'user') { + filtered = filtered.filter(e => e.action.startsWith('user_') || e.action === 'password_changed'); + } else { + filtered = filtered.filter(e => e.action === eventFilter); + } + } + + // 3. Search Query + if (auditSearch.trim()) { + const q = auditSearch.toLowerCase(); + filtered = filtered.filter(e => + e.summary.toLowerCase().includes(q) || + e.action.toLowerCase().includes(q) || + (e.actor !== 'system' && (findUser(e.actor) || {}).name?.toLowerCase().includes(q)) + ); + } + const out = {}; filtered.forEach(e => { const day = new Date(e.at).toDateString(); (out[day] = out[day] || []).push(e); }); return out; - }, [filter, entries]); + }, [actorFilter, eventFilter, auditSearch, entries]); return (
-
-
+
+

Audit log

-

Everything that's happened in the workspace · last 7 days

+

History of the workspace · last 7 days

+ +
+
+ + setAuditSearch(e.target.value)} + /> + {auditSearch && setAuditSearch('')}>} +
+ + +
-
- setFilter('all')}>All - setFilter('system')}>System + +
+ setActorFilter('all')}>All actors + setActorFilter('system')}>System {dbUsers.map(u => ( - setFilter(u.id)}> + setActorFilter(u.id)}> {u.name} ))}