@agenticmail/enterprise 0.5.280 → 0.5.281
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -175,9 +175,12 @@ export function DatabaseAccessPage() {
|
|
|
175
175
|
|
|
176
176
|
// Tabs
|
|
177
177
|
h('div', { style: s.tabs },
|
|
178
|
-
h('div', { style: tab === 'connections' ? s.tabActive : s.tab, onClick: function() { setTab('connections'); } },
|
|
179
|
-
|
|
180
|
-
h('div', { style: tab === '
|
|
178
|
+
h('div', { style: tab === 'connections' ? s.tabActive : s.tab, onClick: function() { setTab('connections'); } },
|
|
179
|
+
h('span', { style: css('display: inline-flex; align-items: center; gap: 6px;') }, h('span', { style: css('display: flex; transform: scale(0.7);') }, I.database()), 'Connections')),
|
|
180
|
+
h('div', { style: tab === 'agents' ? s.tabActive : s.tab, onClick: function() { setTab('agents'); } },
|
|
181
|
+
h('span', { style: css('display: inline-flex; align-items: center; gap: 6px;') }, h('span', { style: css('display: flex; transform: scale(0.7);') }, I.shield()), 'Agent Access')),
|
|
182
|
+
h('div', { style: tab === 'audit' ? s.tabActive : s.tab, onClick: function() { setTab('audit'); } },
|
|
183
|
+
h('span', { style: css('display: inline-flex; align-items: center; gap: 6px;') }, h('span', { style: css('display: flex; transform: scale(0.7);') }, I.audit()), 'Audit Log')),
|
|
181
184
|
),
|
|
182
185
|
|
|
183
186
|
// Content
|
|
@@ -305,7 +308,45 @@ function AgentAccessTab(props) {
|
|
|
305
308
|
|
|
306
309
|
// ─── Audit Tab ───────────────────────────────────────────────────────────────
|
|
307
310
|
|
|
311
|
+
var AUDIT_PAGE_SIZE = 15;
|
|
312
|
+
|
|
308
313
|
function AuditTab(props) {
|
|
314
|
+
var [search, setSearch] = useState('');
|
|
315
|
+
var [opFilter, setOpFilter] = useState('all');
|
|
316
|
+
var [statusFilter, setStatusFilter] = useState('all');
|
|
317
|
+
var [agentFilter, setAgentFilter] = useState('all');
|
|
318
|
+
var [page, setPage] = useState(0);
|
|
319
|
+
var [expanded, setExpanded] = useState(null);
|
|
320
|
+
|
|
321
|
+
// Get unique agents from audit log
|
|
322
|
+
var agents = [];
|
|
323
|
+
var agentSet = {};
|
|
324
|
+
props.auditLog.forEach(function(e) {
|
|
325
|
+
var name = e.agent_name || e.agent_id;
|
|
326
|
+
if (name && !agentSet[name]) { agentSet[name] = true; agents.push(name); }
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// Filter entries
|
|
330
|
+
var filtered = props.auditLog.filter(function(e) {
|
|
331
|
+
if (opFilter !== 'all' && e.operation !== opFilter) return false;
|
|
332
|
+
if (statusFilter === 'ok' && !e.success) return false;
|
|
333
|
+
if (statusFilter === 'fail' && e.success) return false;
|
|
334
|
+
if (agentFilter !== 'all' && (e.agent_name || e.agent_id) !== agentFilter) return false;
|
|
335
|
+
if (search) {
|
|
336
|
+
var q = search.toLowerCase();
|
|
337
|
+
var haystack = ((e.query || '') + ' ' + (e.agent_name || '') + ' ' + (e.connection_name || '') + ' ' + (e.error || '')).toLowerCase();
|
|
338
|
+
if (haystack.indexOf(q) < 0) return false;
|
|
339
|
+
}
|
|
340
|
+
return true;
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
var totalPages = Math.max(1, Math.ceil(filtered.length / AUDIT_PAGE_SIZE));
|
|
344
|
+
if (page >= totalPages) page = totalPages - 1;
|
|
345
|
+
var paged = filtered.slice(page * AUDIT_PAGE_SIZE, (page + 1) * AUDIT_PAGE_SIZE);
|
|
346
|
+
|
|
347
|
+
// Reset page when filters change
|
|
348
|
+
var resetPage = function() { setPage(0); };
|
|
349
|
+
|
|
309
350
|
if (props.auditLog.length === 0) {
|
|
310
351
|
return h('div', { style: s.emptyState },
|
|
311
352
|
h('div', { style: s.emptyIcon }, I.audit()),
|
|
@@ -314,37 +355,114 @@ function AuditTab(props) {
|
|
|
314
355
|
);
|
|
315
356
|
}
|
|
316
357
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
h('
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
358
|
+
var opColor = function(op) {
|
|
359
|
+
return op === 'read' ? 'var(--success)' : op === 'write' ? 'var(--warning)' : op === 'delete' ? 'var(--danger)' : op === 'schema' ? 'var(--accent)' : 'var(--text-muted)';
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
var filterBar = css('display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; align-items: center;');
|
|
363
|
+
var filterSelect = css('padding: 6px 10px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg-secondary); color: var(--text-primary); font-size: 12px;');
|
|
364
|
+
var searchInput = css('padding: 6px 10px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg-primary); color: var(--text-primary); font-size: 12px; flex: 1; min-width: 180px;');
|
|
365
|
+
var countBadge = css('font-size: 11px; color: var(--text-muted); margin-left: auto; white-space: nowrap;');
|
|
366
|
+
|
|
367
|
+
return h('div', null,
|
|
368
|
+
// Filter bar
|
|
369
|
+
h('div', { style: filterBar },
|
|
370
|
+
h('div', { style: css('display: flex; align-items: center; gap: 4px; color: var(--text-muted);') },
|
|
371
|
+
h('span', { style: css('display: flex; transform: scale(0.65);') }, I.search()),
|
|
372
|
+
),
|
|
373
|
+
h('input', { style: searchInput, placeholder: 'Search queries, agents, databases, errors...', value: search, onInput: function(e) { setSearch(e.target.value); resetPage(); } }),
|
|
374
|
+
h('select', { style: filterSelect, value: opFilter, onChange: function(e) { setOpFilter(e.target.value); resetPage(); } },
|
|
375
|
+
h('option', { value: 'all' }, 'All Operations'),
|
|
376
|
+
h('option', { value: 'read' }, 'Read'),
|
|
377
|
+
h('option', { value: 'write' }, 'Write'),
|
|
378
|
+
h('option', { value: 'delete' }, 'Delete'),
|
|
379
|
+
h('option', { value: 'schema' }, 'Schema'),
|
|
380
|
+
h('option', { value: 'execute' }, 'Execute'),
|
|
381
|
+
),
|
|
382
|
+
h('select', { style: filterSelect, value: statusFilter, onChange: function(e) { setStatusFilter(e.target.value); resetPage(); } },
|
|
383
|
+
h('option', { value: 'all' }, 'All Status'),
|
|
384
|
+
h('option', { value: 'ok' }, 'Success'),
|
|
385
|
+
h('option', { value: 'fail' }, 'Failed'),
|
|
386
|
+
),
|
|
387
|
+
agents.length > 1 && h('select', { style: filterSelect, value: agentFilter, onChange: function(e) { setAgentFilter(e.target.value); resetPage(); } },
|
|
388
|
+
h('option', { value: 'all' }, 'All Agents'),
|
|
389
|
+
agents.map(function(a) { return h('option', { key: a, value: a }, a); })
|
|
390
|
+
),
|
|
391
|
+
h('span', { style: countBadge }, filtered.length + ' of ' + props.auditLog.length + ' entries'),
|
|
392
|
+
h('button', { style: Object.assign({}, s.btn, { padding: '4px 10px', fontSize: '11px' }), onClick: props.onRefresh }, 'Refresh'),
|
|
393
|
+
),
|
|
394
|
+
|
|
395
|
+
// Table
|
|
396
|
+
h('div', { style: css('overflow-x: auto; border: 1px solid var(--border); border-radius: 8px;') },
|
|
397
|
+
h('table', { style: s.auditTable },
|
|
398
|
+
h('thead', null, h('tr', null,
|
|
399
|
+
h('th', { style: s.auditTh }, 'Time'),
|
|
400
|
+
h('th', { style: s.auditTh }, 'Agent'),
|
|
401
|
+
h('th', { style: s.auditTh }, 'Database'),
|
|
402
|
+
h('th', { style: s.auditTh }, 'Operation'),
|
|
403
|
+
h('th', { style: s.auditTh }, 'Query'),
|
|
404
|
+
h('th', { style: s.auditTh }, 'Rows'),
|
|
405
|
+
h('th', { style: s.auditTh }, 'Latency'),
|
|
406
|
+
h('th', { style: s.auditTh }, 'Status'),
|
|
407
|
+
)),
|
|
408
|
+
h('tbody', null,
|
|
409
|
+
paged.length === 0 && h('tr', null,
|
|
410
|
+
h('td', { colSpan: 8, style: Object.assign({}, s.auditTd, { textAlign: 'center', color: 'var(--text-muted)', padding: '24px' }) }, 'No entries match your filters')
|
|
411
|
+
),
|
|
412
|
+
paged.map(function(entry) {
|
|
413
|
+
var isExpanded = expanded === entry.id;
|
|
414
|
+
return h(Fragment, { key: entry.id },
|
|
415
|
+
h('tr', { style: css('cursor: pointer; transition: background 0.1s;'), onClick: function() { setExpanded(isExpanded ? null : entry.id); } },
|
|
416
|
+
h('td', { style: s.auditTd }, new Date(entry.timestamp).toLocaleString()),
|
|
417
|
+
h('td', { style: Object.assign({}, s.auditTd, { fontWeight: 500 }) }, entry.agent_name || (entry.agent_id ? entry.agent_id.slice(0, 8) + '...' : '—')),
|
|
418
|
+
h('td', { style: s.auditTd }, entry.connection_name || (entry.connection_id ? entry.connection_id.slice(0, 8) + '...' : '—')),
|
|
419
|
+
h('td', { style: Object.assign({}, s.auditTd, { fontWeight: 600, color: opColor(entry.operation) }) }, entry.operation),
|
|
420
|
+
h('td', { style: Object.assign({}, s.auditTd, { fontFamily: 'monospace', fontSize: '11px', maxWidth: '300px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }) }, entry.query),
|
|
421
|
+
h('td', { style: Object.assign({}, s.auditTd, { textAlign: 'right' }) }, entry.rows_affected != null ? entry.rows_affected : '—'),
|
|
422
|
+
h('td', { style: Object.assign({}, s.auditTd, { textAlign: 'right', whiteSpace: 'nowrap' }) }, entry.execution_time_ms != null ? entry.execution_time_ms + 'ms' : '—'),
|
|
423
|
+
h('td', { style: s.auditTd }, entry.success
|
|
424
|
+
? h('span', { style: Object.assign({}, s.badge, s.badgeActive) }, 'OK')
|
|
425
|
+
: h('span', { style: Object.assign({}, s.badge, s.badgeError) }, 'FAIL')
|
|
426
|
+
),
|
|
427
|
+
),
|
|
428
|
+
// Expanded row detail
|
|
429
|
+
isExpanded && h('tr', null,
|
|
430
|
+
h('td', { colSpan: 8, style: css('padding: 12px 16px; background: var(--bg-secondary); border-bottom: 1px solid var(--border);') },
|
|
431
|
+
h('div', { style: css('display: grid; grid-template-columns: 1fr 1fr; gap: 12px; font-size: 12px;') },
|
|
432
|
+
h('div', null,
|
|
433
|
+
h('div', { style: css('font-weight: 600; margin-bottom: 4px; color: var(--text-muted);') }, 'Full Query'),
|
|
434
|
+
h('pre', { style: css('margin: 0; padding: 8px; background: var(--bg-primary); border-radius: 6px; overflow-x: auto; font-size: 11px; white-space: pre-wrap; word-break: break-all; max-height: 200px;') }, entry.query || '—'),
|
|
435
|
+
),
|
|
436
|
+
h('div', null,
|
|
437
|
+
h('div', { style: css('font-weight: 600; margin-bottom: 4px; color: var(--text-muted);') }, 'Details'),
|
|
438
|
+
h('div', { style: css('display: flex; flex-direction: column; gap: 4px;') },
|
|
439
|
+
h('div', null, h('strong', null, 'Agent ID: '), entry.agent_id || '—'),
|
|
440
|
+
h('div', null, h('strong', null, 'Connection ID: '), entry.connection_id || '—'),
|
|
441
|
+
h('div', null, h('strong', null, 'Rows Affected: '), entry.rows_affected != null ? String(entry.rows_affected) : '—'),
|
|
442
|
+
h('div', null, h('strong', null, 'Execution Time: '), entry.execution_time_ms != null ? entry.execution_time_ms + 'ms' : '—'),
|
|
443
|
+
h('div', null, h('strong', null, 'IP: '), entry.ip_address || '—'),
|
|
444
|
+
!entry.success && entry.error && h('div', { style: css('margin-top: 4px; padding: 6px 8px; background: rgba(239,68,68,0.1); border-radius: 4px; color: var(--danger);') },
|
|
445
|
+
h('strong', null, 'Error: '), entry.error
|
|
446
|
+
),
|
|
447
|
+
),
|
|
448
|
+
),
|
|
449
|
+
),
|
|
450
|
+
),
|
|
451
|
+
),
|
|
452
|
+
);
|
|
453
|
+
})
|
|
454
|
+
),
|
|
346
455
|
),
|
|
347
456
|
),
|
|
457
|
+
|
|
458
|
+
// Pagination
|
|
459
|
+
totalPages > 1 && h('div', { style: css('display: flex; align-items: center; justify-content: center; gap: 8px; margin-top: 16px;') },
|
|
460
|
+
h('button', { style: Object.assign({}, s.btn, { padding: '4px 10px', fontSize: '12px' }), disabled: page === 0, onClick: function() { setPage(0); } }, '«'),
|
|
461
|
+
h('button', { style: Object.assign({}, s.btn, { padding: '4px 10px', fontSize: '12px' }), disabled: page === 0, onClick: function() { setPage(page - 1); } }, '‹'),
|
|
462
|
+
h('span', { style: css('font-size: 12px; color: var(--text-secondary);') }, 'Page ' + (page + 1) + ' of ' + totalPages),
|
|
463
|
+
h('button', { style: Object.assign({}, s.btn, { padding: '4px 10px', fontSize: '12px' }), disabled: page >= totalPages - 1, onClick: function() { setPage(page + 1); } }, '›'),
|
|
464
|
+
h('button', { style: Object.assign({}, s.btn, { padding: '4px 10px', fontSize: '12px' }), disabled: page >= totalPages - 1, onClick: function() { setPage(totalPages - 1); } }, '»'),
|
|
465
|
+
),
|
|
348
466
|
);
|
|
349
467
|
}
|
|
350
468
|
|
package/package.json
CHANGED
|
@@ -175,9 +175,12 @@ export function DatabaseAccessPage() {
|
|
|
175
175
|
|
|
176
176
|
// Tabs
|
|
177
177
|
h('div', { style: s.tabs },
|
|
178
|
-
h('div', { style: tab === 'connections' ? s.tabActive : s.tab, onClick: function() { setTab('connections'); } },
|
|
179
|
-
|
|
180
|
-
h('div', { style: tab === '
|
|
178
|
+
h('div', { style: tab === 'connections' ? s.tabActive : s.tab, onClick: function() { setTab('connections'); } },
|
|
179
|
+
h('span', { style: css('display: inline-flex; align-items: center; gap: 6px;') }, h('span', { style: css('display: flex; transform: scale(0.7);') }, I.database()), 'Connections')),
|
|
180
|
+
h('div', { style: tab === 'agents' ? s.tabActive : s.tab, onClick: function() { setTab('agents'); } },
|
|
181
|
+
h('span', { style: css('display: inline-flex; align-items: center; gap: 6px;') }, h('span', { style: css('display: flex; transform: scale(0.7);') }, I.shield()), 'Agent Access')),
|
|
182
|
+
h('div', { style: tab === 'audit' ? s.tabActive : s.tab, onClick: function() { setTab('audit'); } },
|
|
183
|
+
h('span', { style: css('display: inline-flex; align-items: center; gap: 6px;') }, h('span', { style: css('display: flex; transform: scale(0.7);') }, I.audit()), 'Audit Log')),
|
|
181
184
|
),
|
|
182
185
|
|
|
183
186
|
// Content
|
|
@@ -305,7 +308,45 @@ function AgentAccessTab(props) {
|
|
|
305
308
|
|
|
306
309
|
// ─── Audit Tab ───────────────────────────────────────────────────────────────
|
|
307
310
|
|
|
311
|
+
var AUDIT_PAGE_SIZE = 15;
|
|
312
|
+
|
|
308
313
|
function AuditTab(props) {
|
|
314
|
+
var [search, setSearch] = useState('');
|
|
315
|
+
var [opFilter, setOpFilter] = useState('all');
|
|
316
|
+
var [statusFilter, setStatusFilter] = useState('all');
|
|
317
|
+
var [agentFilter, setAgentFilter] = useState('all');
|
|
318
|
+
var [page, setPage] = useState(0);
|
|
319
|
+
var [expanded, setExpanded] = useState(null);
|
|
320
|
+
|
|
321
|
+
// Get unique agents from audit log
|
|
322
|
+
var agents = [];
|
|
323
|
+
var agentSet = {};
|
|
324
|
+
props.auditLog.forEach(function(e) {
|
|
325
|
+
var name = e.agent_name || e.agent_id;
|
|
326
|
+
if (name && !agentSet[name]) { agentSet[name] = true; agents.push(name); }
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
// Filter entries
|
|
330
|
+
var filtered = props.auditLog.filter(function(e) {
|
|
331
|
+
if (opFilter !== 'all' && e.operation !== opFilter) return false;
|
|
332
|
+
if (statusFilter === 'ok' && !e.success) return false;
|
|
333
|
+
if (statusFilter === 'fail' && e.success) return false;
|
|
334
|
+
if (agentFilter !== 'all' && (e.agent_name || e.agent_id) !== agentFilter) return false;
|
|
335
|
+
if (search) {
|
|
336
|
+
var q = search.toLowerCase();
|
|
337
|
+
var haystack = ((e.query || '') + ' ' + (e.agent_name || '') + ' ' + (e.connection_name || '') + ' ' + (e.error || '')).toLowerCase();
|
|
338
|
+
if (haystack.indexOf(q) < 0) return false;
|
|
339
|
+
}
|
|
340
|
+
return true;
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
var totalPages = Math.max(1, Math.ceil(filtered.length / AUDIT_PAGE_SIZE));
|
|
344
|
+
if (page >= totalPages) page = totalPages - 1;
|
|
345
|
+
var paged = filtered.slice(page * AUDIT_PAGE_SIZE, (page + 1) * AUDIT_PAGE_SIZE);
|
|
346
|
+
|
|
347
|
+
// Reset page when filters change
|
|
348
|
+
var resetPage = function() { setPage(0); };
|
|
349
|
+
|
|
309
350
|
if (props.auditLog.length === 0) {
|
|
310
351
|
return h('div', { style: s.emptyState },
|
|
311
352
|
h('div', { style: s.emptyIcon }, I.audit()),
|
|
@@ -314,37 +355,114 @@ function AuditTab(props) {
|
|
|
314
355
|
);
|
|
315
356
|
}
|
|
316
357
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
h('
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
358
|
+
var opColor = function(op) {
|
|
359
|
+
return op === 'read' ? 'var(--success)' : op === 'write' ? 'var(--warning)' : op === 'delete' ? 'var(--danger)' : op === 'schema' ? 'var(--accent)' : 'var(--text-muted)';
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
var filterBar = css('display: flex; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; align-items: center;');
|
|
363
|
+
var filterSelect = css('padding: 6px 10px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg-secondary); color: var(--text-primary); font-size: 12px;');
|
|
364
|
+
var searchInput = css('padding: 6px 10px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg-primary); color: var(--text-primary); font-size: 12px; flex: 1; min-width: 180px;');
|
|
365
|
+
var countBadge = css('font-size: 11px; color: var(--text-muted); margin-left: auto; white-space: nowrap;');
|
|
366
|
+
|
|
367
|
+
return h('div', null,
|
|
368
|
+
// Filter bar
|
|
369
|
+
h('div', { style: filterBar },
|
|
370
|
+
h('div', { style: css('display: flex; align-items: center; gap: 4px; color: var(--text-muted);') },
|
|
371
|
+
h('span', { style: css('display: flex; transform: scale(0.65);') }, I.search()),
|
|
372
|
+
),
|
|
373
|
+
h('input', { style: searchInput, placeholder: 'Search queries, agents, databases, errors...', value: search, onInput: function(e) { setSearch(e.target.value); resetPage(); } }),
|
|
374
|
+
h('select', { style: filterSelect, value: opFilter, onChange: function(e) { setOpFilter(e.target.value); resetPage(); } },
|
|
375
|
+
h('option', { value: 'all' }, 'All Operations'),
|
|
376
|
+
h('option', { value: 'read' }, 'Read'),
|
|
377
|
+
h('option', { value: 'write' }, 'Write'),
|
|
378
|
+
h('option', { value: 'delete' }, 'Delete'),
|
|
379
|
+
h('option', { value: 'schema' }, 'Schema'),
|
|
380
|
+
h('option', { value: 'execute' }, 'Execute'),
|
|
381
|
+
),
|
|
382
|
+
h('select', { style: filterSelect, value: statusFilter, onChange: function(e) { setStatusFilter(e.target.value); resetPage(); } },
|
|
383
|
+
h('option', { value: 'all' }, 'All Status'),
|
|
384
|
+
h('option', { value: 'ok' }, 'Success'),
|
|
385
|
+
h('option', { value: 'fail' }, 'Failed'),
|
|
386
|
+
),
|
|
387
|
+
agents.length > 1 && h('select', { style: filterSelect, value: agentFilter, onChange: function(e) { setAgentFilter(e.target.value); resetPage(); } },
|
|
388
|
+
h('option', { value: 'all' }, 'All Agents'),
|
|
389
|
+
agents.map(function(a) { return h('option', { key: a, value: a }, a); })
|
|
390
|
+
),
|
|
391
|
+
h('span', { style: countBadge }, filtered.length + ' of ' + props.auditLog.length + ' entries'),
|
|
392
|
+
h('button', { style: Object.assign({}, s.btn, { padding: '4px 10px', fontSize: '11px' }), onClick: props.onRefresh }, 'Refresh'),
|
|
393
|
+
),
|
|
394
|
+
|
|
395
|
+
// Table
|
|
396
|
+
h('div', { style: css('overflow-x: auto; border: 1px solid var(--border); border-radius: 8px;') },
|
|
397
|
+
h('table', { style: s.auditTable },
|
|
398
|
+
h('thead', null, h('tr', null,
|
|
399
|
+
h('th', { style: s.auditTh }, 'Time'),
|
|
400
|
+
h('th', { style: s.auditTh }, 'Agent'),
|
|
401
|
+
h('th', { style: s.auditTh }, 'Database'),
|
|
402
|
+
h('th', { style: s.auditTh }, 'Operation'),
|
|
403
|
+
h('th', { style: s.auditTh }, 'Query'),
|
|
404
|
+
h('th', { style: s.auditTh }, 'Rows'),
|
|
405
|
+
h('th', { style: s.auditTh }, 'Latency'),
|
|
406
|
+
h('th', { style: s.auditTh }, 'Status'),
|
|
407
|
+
)),
|
|
408
|
+
h('tbody', null,
|
|
409
|
+
paged.length === 0 && h('tr', null,
|
|
410
|
+
h('td', { colSpan: 8, style: Object.assign({}, s.auditTd, { textAlign: 'center', color: 'var(--text-muted)', padding: '24px' }) }, 'No entries match your filters')
|
|
411
|
+
),
|
|
412
|
+
paged.map(function(entry) {
|
|
413
|
+
var isExpanded = expanded === entry.id;
|
|
414
|
+
return h(Fragment, { key: entry.id },
|
|
415
|
+
h('tr', { style: css('cursor: pointer; transition: background 0.1s;'), onClick: function() { setExpanded(isExpanded ? null : entry.id); } },
|
|
416
|
+
h('td', { style: s.auditTd }, new Date(entry.timestamp).toLocaleString()),
|
|
417
|
+
h('td', { style: Object.assign({}, s.auditTd, { fontWeight: 500 }) }, entry.agent_name || (entry.agent_id ? entry.agent_id.slice(0, 8) + '...' : '—')),
|
|
418
|
+
h('td', { style: s.auditTd }, entry.connection_name || (entry.connection_id ? entry.connection_id.slice(0, 8) + '...' : '—')),
|
|
419
|
+
h('td', { style: Object.assign({}, s.auditTd, { fontWeight: 600, color: opColor(entry.operation) }) }, entry.operation),
|
|
420
|
+
h('td', { style: Object.assign({}, s.auditTd, { fontFamily: 'monospace', fontSize: '11px', maxWidth: '300px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }) }, entry.query),
|
|
421
|
+
h('td', { style: Object.assign({}, s.auditTd, { textAlign: 'right' }) }, entry.rows_affected != null ? entry.rows_affected : '—'),
|
|
422
|
+
h('td', { style: Object.assign({}, s.auditTd, { textAlign: 'right', whiteSpace: 'nowrap' }) }, entry.execution_time_ms != null ? entry.execution_time_ms + 'ms' : '—'),
|
|
423
|
+
h('td', { style: s.auditTd }, entry.success
|
|
424
|
+
? h('span', { style: Object.assign({}, s.badge, s.badgeActive) }, 'OK')
|
|
425
|
+
: h('span', { style: Object.assign({}, s.badge, s.badgeError) }, 'FAIL')
|
|
426
|
+
),
|
|
427
|
+
),
|
|
428
|
+
// Expanded row detail
|
|
429
|
+
isExpanded && h('tr', null,
|
|
430
|
+
h('td', { colSpan: 8, style: css('padding: 12px 16px; background: var(--bg-secondary); border-bottom: 1px solid var(--border);') },
|
|
431
|
+
h('div', { style: css('display: grid; grid-template-columns: 1fr 1fr; gap: 12px; font-size: 12px;') },
|
|
432
|
+
h('div', null,
|
|
433
|
+
h('div', { style: css('font-weight: 600; margin-bottom: 4px; color: var(--text-muted);') }, 'Full Query'),
|
|
434
|
+
h('pre', { style: css('margin: 0; padding: 8px; background: var(--bg-primary); border-radius: 6px; overflow-x: auto; font-size: 11px; white-space: pre-wrap; word-break: break-all; max-height: 200px;') }, entry.query || '—'),
|
|
435
|
+
),
|
|
436
|
+
h('div', null,
|
|
437
|
+
h('div', { style: css('font-weight: 600; margin-bottom: 4px; color: var(--text-muted);') }, 'Details'),
|
|
438
|
+
h('div', { style: css('display: flex; flex-direction: column; gap: 4px;') },
|
|
439
|
+
h('div', null, h('strong', null, 'Agent ID: '), entry.agent_id || '—'),
|
|
440
|
+
h('div', null, h('strong', null, 'Connection ID: '), entry.connection_id || '—'),
|
|
441
|
+
h('div', null, h('strong', null, 'Rows Affected: '), entry.rows_affected != null ? String(entry.rows_affected) : '—'),
|
|
442
|
+
h('div', null, h('strong', null, 'Execution Time: '), entry.execution_time_ms != null ? entry.execution_time_ms + 'ms' : '—'),
|
|
443
|
+
h('div', null, h('strong', null, 'IP: '), entry.ip_address || '—'),
|
|
444
|
+
!entry.success && entry.error && h('div', { style: css('margin-top: 4px; padding: 6px 8px; background: rgba(239,68,68,0.1); border-radius: 4px; color: var(--danger);') },
|
|
445
|
+
h('strong', null, 'Error: '), entry.error
|
|
446
|
+
),
|
|
447
|
+
),
|
|
448
|
+
),
|
|
449
|
+
),
|
|
450
|
+
),
|
|
451
|
+
),
|
|
452
|
+
);
|
|
453
|
+
})
|
|
454
|
+
),
|
|
346
455
|
),
|
|
347
456
|
),
|
|
457
|
+
|
|
458
|
+
// Pagination
|
|
459
|
+
totalPages > 1 && h('div', { style: css('display: flex; align-items: center; justify-content: center; gap: 8px; margin-top: 16px;') },
|
|
460
|
+
h('button', { style: Object.assign({}, s.btn, { padding: '4px 10px', fontSize: '12px' }), disabled: page === 0, onClick: function() { setPage(0); } }, '«'),
|
|
461
|
+
h('button', { style: Object.assign({}, s.btn, { padding: '4px 10px', fontSize: '12px' }), disabled: page === 0, onClick: function() { setPage(page - 1); } }, '‹'),
|
|
462
|
+
h('span', { style: css('font-size: 12px; color: var(--text-secondary);') }, 'Page ' + (page + 1) + ' of ' + totalPages),
|
|
463
|
+
h('button', { style: Object.assign({}, s.btn, { padding: '4px 10px', fontSize: '12px' }), disabled: page >= totalPages - 1, onClick: function() { setPage(page + 1); } }, '›'),
|
|
464
|
+
h('button', { style: Object.assign({}, s.btn, { padding: '4px 10px', fontSize: '12px' }), disabled: page >= totalPages - 1, onClick: function() { setPage(totalPages - 1); } }, '»'),
|
|
465
|
+
),
|
|
348
466
|
);
|
|
349
467
|
}
|
|
350
468
|
|