Phase 8 Complete: Sync Audit Log + Frontend Integration
- Thêm audit/sync_audit.py: Ghi lịch sử sync vào audit/sync_log.json
- Thêm API endpoints: /sync/history, /sync/history/{run_id}
- Frontend: Nút 'Lịch sử đồng bộ' + panel expand chi tiết từng file
- Sửa frontend served từ backend (http://localhost:8000)
- Cập nhật DEPLOYMENT_GUIDE với hướng dẫn chạy localhost
- Cập nhật ARCHITECTURE_MAP: Phase 8 hoàn thành
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// API Base URL
|
||||
const API_BASE = 'http://localhost:8000';
|
||||
// API Base URL (relative khi served từ backend)
|
||||
const API_BASE = window.location.origin;
|
||||
|
||||
// DOM Elements
|
||||
const loginScreen = document.getElementById('login-screen');
|
||||
@@ -19,6 +19,10 @@ const logoutBtn = document.getElementById('logout-btn');
|
||||
const syncBtn = document.getElementById('sync-btn');
|
||||
const syncStatus = document.getElementById('sync-status');
|
||||
const ssoBtn = document.getElementById('sso-btn');
|
||||
const historyBtn = document.getElementById('history-btn');
|
||||
const historyPanel = document.getElementById('history-panel');
|
||||
const historyList = document.getElementById('history-list');
|
||||
const closeHistory = document.getElementById('close-history');
|
||||
|
||||
let chatHistory = [];
|
||||
let currentUser = null;
|
||||
@@ -287,5 +291,71 @@ async function pollSyncStatus() {
|
||||
|
||||
syncBtn.onclick = triggerSync;
|
||||
|
||||
// ====== SYNC HISTORY ======
|
||||
|
||||
async function loadSyncHistory() {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE}/sync/history?limit=20`);
|
||||
const data = await response.json();
|
||||
|
||||
historyList.innerHTML = '';
|
||||
|
||||
if (!data.runs || data.runs.length === 0) {
|
||||
historyList.innerHTML = '<p style="color: var(--text-muted); font-size: 13px; text-align: center; padding: 20px;">Chưa có lần đồng bộ nào.</p>';
|
||||
return;
|
||||
}
|
||||
|
||||
data.runs.forEach(run => {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'history-item';
|
||||
|
||||
const time = new Date(run.started_at).toLocaleString('vi-VN');
|
||||
const statusClass = run.status;
|
||||
const statusText = run.status === 'completed' ? 'Hoàn thành' :
|
||||
run.status === 'failed' ? 'Thất bại' : 'Đang chạy';
|
||||
|
||||
item.innerHTML = `
|
||||
<div class="history-header">
|
||||
<span class="history-time">${time}</span>
|
||||
<span class="history-status ${statusClass}">${statusText}</span>
|
||||
</div>
|
||||
<div class="history-summary">
|
||||
<span><i class="fas fa-check-circle" style="color: #10b981"></i> ${run.summary.processed} nạp</span>
|
||||
<span><i class="fas fa-forward" style="color: #eab308"></i> ${run.summary.skipped} bỏ</span>
|
||||
<span><i class="fas fa-exclamation-circle" style="color: #ef4444"></i> ${run.summary.errors} lỗi</span>
|
||||
</div>
|
||||
<div class="history-files">
|
||||
${run.files.map(f => `
|
||||
<div class="history-file">
|
||||
<span class="history-file-name" title="${f.name}">${f.name}</span>
|
||||
<span class="history-file-status ${f.status}">${f.chunks > 0 ? f.chunks + ' chunks' : f.status}</span>
|
||||
</div>
|
||||
`).join('')}
|
||||
${run.errors.length > 0 ? `
|
||||
<div style="margin-top: 8px; font-size: 11px; color: #ef4444;">
|
||||
${run.errors.map(e => `<div>⚠ ${e}</div>`).join('')}
|
||||
</div>
|
||||
` : ''}
|
||||
</div>
|
||||
`;
|
||||
|
||||
item.onclick = () => item.classList.toggle('expanded');
|
||||
historyList.appendChild(item);
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Load history error:', error);
|
||||
historyList.innerHTML = '<p style="color: #ef4444; font-size: 13px; text-align: center;">Lỗi tải lịch sử.</p>';
|
||||
}
|
||||
}
|
||||
|
||||
historyBtn.onclick = () => {
|
||||
historyPanel.classList.toggle('active');
|
||||
if (historyPanel.classList.contains('active')) {
|
||||
loadSyncHistory();
|
||||
}
|
||||
};
|
||||
|
||||
closeHistory.onclick = () => historyPanel.classList.remove('active');
|
||||
|
||||
// Init
|
||||
checkLogin();
|
||||
|
||||
Reference in New Issue
Block a user