Coalesce index generation increments and add rebuild cooldown

This commit is contained in:
2026-05-26 11:42:47 -04:00
parent 0b611a8735
commit b38f3f16e4
5 changed files with 328 additions and 323 deletions
+102 -57
View File
@@ -3380,34 +3380,43 @@
// ── Dashboard Conflicts Widget ──
const DashboardConflictsWidget = {
async load() {
const section = document.getElementById("dashboard-conflicts-section");
if (!section) return;
const container = document.getElementById("dashboard-conflicts-container");
if (!container) return;
try {
const data = await api("/api/conflicts");
if (data.total === 0) { section.style.display = "none"; return; }
section.style.display = "";
document.getElementById("dashboard-conflicts-count").textContent = data.total;
this.render(data.conflicts);
} catch (err) { section.style.display = "none"; }
if (data.total === 0) { container.innerHTML = ""; return; }
this.render(data.conflicts, container);
} catch (err) { container.innerHTML = ""; }
},
render(conflicts) {
const grid = document.getElementById("dashboard-conflicts-grid");
if (!grid) return;
grid.innerHTML = conflicts.map(c => `
<div class="conflict-card">
<div class="conflict-info">
<span class="conflict-vault">${escapeHtml(c.vault)}</span>
<span class="conflict-name">${escapeHtml(c.conflict_path.split("/").pop())}</span>
<span class="conflict-date">Conflit du ${c.conflict_date.replace(/(\d{4})(\d{2})(\d{2})-(\d{2})(\d{2})/, "$3/$2/$1 $4:$5")}</span>
render(conflicts, container) {
container.innerHTML = `
<div class="dashboard-section">
<div class="dashboard-header">
<div class="dashboard-title-row">
<i data-lucide="alert-triangle" class="dashboard-icon" style="color:var(--accent-orange)"></i>
<h2>Conflits de synchronisation</h2>
<span class="dashboard-badge" style="background:var(--accent-orange)">${conflicts.length}</span>
</div>
</div>
<div class="conflict-actions">
<button class="conflict-btn keep-local" data-vault="${escapeHtml(c.vault)}" data-conflict="${escapeHtml(c.conflict_path)}" data-original="${escapeHtml(c.original_path)}">Garder l'original</button>
<button class="conflict-btn keep-conflict" data-vault="${escapeHtml(c.vault)}" data-conflict="${escapeHtml(c.conflict_path)}" data-original="${escapeHtml(c.original_path)}">Garder le conflit</button>
<div class="dashboard-conflicts-grid">
${conflicts.map(c => `
<div class="conflict-card">
<div class="conflict-info">
<span class="conflict-vault">${escapeHtml(c.vault)}</span>
<span class="conflict-name">${escapeHtml(c.conflict_path.split("/").pop())}</span>
<span class="conflict-date">Conflit du ${c.conflict_date.replace(/(\d{4})(\d{2})(\d{2})-(\d{2})(\d{2})/, "$3/$2/$1 $4:$5")}</span>
</div>
<div class="conflict-actions">
<button class="conflict-btn keep-local" data-vault="${escapeHtml(c.vault)}" data-conflict="${escapeHtml(c.conflict_path)}" data-original="${escapeHtml(c.original_path)}">Garder l'original</button>
<button class="conflict-btn keep-conflict" data-vault="${escapeHtml(c.vault)}" data-conflict="${escapeHtml(c.conflict_path)}" data-original="${escapeHtml(c.original_path)}">Garder le conflit</button>
</div>
</div>
`).join("")}
</div>
</div>
`).join("");
grid.querySelectorAll(".keep-local").forEach(btn => btn.addEventListener("click", () => this._resolve(btn.dataset, "keep_local")));
grid.querySelectorAll(".keep-conflict").forEach(btn => btn.addEventListener("click", () => this._resolve(btn.dataset, "keep_conflict")));
</div>`;
lucide.createIcons();
container.querySelectorAll(".keep-local").forEach(btn => btn.addEventListener("click", () => this._resolve(btn.dataset, "keep_local")));
container.querySelectorAll(".keep-conflict").forEach(btn => btn.addEventListener("click", () => this._resolve(btn.dataset, "keep_conflict")));
},
async _resolve(d, action) {
try {
@@ -5584,23 +5593,37 @@
function showWelcome() {
hideProgressBar();
// Ensure the dashboard container exists and has the correct structure (it might have been wiped by renderFile or be an old version)
// Restore or rebuild the dashboard with tabbed sections
const area = document.getElementById("content-area");
const home = document.getElementById("dashboard-home");
const bookmarksSection = document.getElementById("dashboard-bookmarks-section");
if (area && (!home || !bookmarksSection)) {
if (area && !home) {
area.innerHTML = `
<div id="dashboard-home" class="dashboard-home" role="region" aria-label="Tableau de bord">
<!-- Bookmarks Section -->
<div id="dashboard-bookmarks-section" class="dashboard-section">
<div class="dashboard-header">
<div class="dashboard-title-row">
<i data-lucide="bookmark" class="dashboard-icon" style="color:var(--accent-green)"></i>
<h2>Bookmarks</h2>
</div>
<!-- Dashboard Tabs -->
<div class="dashboard-tabs">
<button class="dashboard-tab active" data-tab="stats">
<i data-lucide="bar-chart-3" style="width:14px;height:14px"></i> Statistiques
</button>
<button class="dashboard-tab" data-tab="bookmarks">
<i data-lucide="bookmark" style="width:14px;height:14px"></i> Bookmarks
</button>
<button class="dashboard-tab" data-tab="recent">
<i data-lucide="clock" style="width:14px;height:14px"></i> Récents
</button>
</div>
<!-- Stats Panel -->
<div id="dashboard-panel-stats" class="dashboard-panel active">
<div id="dashboard-stats-grid" class="dashboard-stats-grid">
<div class="dashboard-stats-loading">Chargement...</div>
</div>
<div id="dashboard-conflicts-container" style="margin-top:16px"></div>
</div>
<!-- Bookmarks Panel -->
<div id="dashboard-panel-bookmarks" class="dashboard-panel">
<div id="dashboard-bookmarks-grid" class="dashboard-recent-grid"></div>
<div id="dashboard-bookmarks-empty" class="dashboard-recent-empty">
<i data-lucide="pin"></i>
@@ -5609,12 +5632,10 @@
</div>
</div>
<!-- Recently Opened Section -->
<div id="dashboard-recent-section" class="dashboard-section">
<!-- Recent Panel -->
<div id="dashboard-panel-recent" class="dashboard-panel">
<div class="dashboard-header">
<div class="dashboard-title-row">
<i data-lucide="clock" class="dashboard-icon"></i>
<h2>Derniers fichiers ouverts</h2>
<span id="dashboard-count" class="dashboard-badge"></span>
</div>
<div class="dashboard-actions">
@@ -5623,18 +5644,11 @@
</select>
</div>
</div>
<div id="dashboard-recent-grid" class="dashboard-recent-grid"></div>
<div id="dashboard-loading" class="dashboard-loading">
<div class="skeleton-card"></div>
<div class="skeleton-card"></div>
<div class="skeleton-card"></div>
<div class="skeleton-card"></div>
<div class="skeleton-card"></div>
<div class="skeleton-card"></div>
<div class="skeleton-card"></div><div class="skeleton-card"></div><div class="skeleton-card"></div>
<div class="skeleton-card"></div><div class="skeleton-card"></div><div class="skeleton-card"></div>
</div>
<div id="dashboard-recent-empty" class="dashboard-recent-empty hidden">
<i data-lucide="inbox"></i>
<span>Aucun fichier récent</span>
@@ -5642,15 +5656,36 @@
</div>
</div>
</div>`;
// Re-initialize widgets which might need to bind events to new elements
// Wire dashboard tab switching
document.querySelectorAll(".dashboard-tab").forEach(tab => {
tab.addEventListener("click", function() {
document.querySelectorAll(".dashboard-tab").forEach(t => t.classList.remove("active"));
document.querySelectorAll(".dashboard-panel").forEach(p => p.classList.remove("active"));
this.classList.add("active");
const panel = document.getElementById("dashboard-panel-" + this.dataset.tab);
if (panel) panel.classList.add("active");
});
});
// Re-initialize widgets
if (typeof DashboardRecentWidget !== "undefined") {
DashboardRecentWidget.init();
}
safeCreateIcons();
} else if (home) {
// Dashboard already exists, just show it
home.style.display = "";
// Activate default tab
document.querySelectorAll(".dashboard-tab").forEach(t => t.classList.remove("active"));
document.querySelectorAll(".dashboard-panel").forEach(p => p.classList.remove("active"));
const defaultTab = document.querySelector('.dashboard-tab[data-tab="stats"]');
const defaultPanel = document.getElementById("dashboard-panel-stats");
if (defaultTab) defaultTab.classList.add("active");
if (defaultPanel) defaultPanel.classList.add("active");
}
// Show the dashboard widgets
// Load all widgets (they handle missing elements gracefully)
if (typeof DashboardStatsWidget !== "undefined") {
DashboardStatsWidget.load();
}
@@ -7763,12 +7798,22 @@
_showDashboard() {
const area = document.getElementById("content-area");
area.innerHTML = "";
const dashboard = document.getElementById("dashboard-home");
if (dashboard) {
dashboard.style.display = "";
area.appendChild(dashboard);
// Save dashboard DOM before clearing (it may have been removed from DOM by renderFile)
let dashboard = document.getElementById("dashboard-home");
if (!dashboard) {
// Dashboard was destroyed — rebuild via showWelcome
area.innerHTML = "";
showWelcome();
return;
}
area.innerHTML = "";
dashboard.style.display = "";
area.appendChild(dashboard);
// Refresh widgets after restoring
if (typeof DashboardStatsWidget !== "undefined") DashboardStatsWidget.load();
if (typeof DashboardConflictsWidget !== "undefined") DashboardConflictsWidget.load();
if (typeof DashboardRecentWidget !== "undefined") DashboardRecentWidget.load(selectedContextVault);
if (typeof DashboardBookmarkWidget !== "undefined") DashboardBookmarkWidget.load(selectedContextVault);
if (history.pushState) {
history.pushState(null, "", "#");
}
@@ -7789,7 +7834,7 @@
this._tabs.forEach((tab, idx) => {
const el = document.createElement("div");
el.className = "tab-item" + (tab.id === this._activeTabId ? " active" : "");
el.className = "tab-item" + (tab.id === this._activeTabId ? " active" : "") + (tab.preview ? " preview" : "");
el.draggable = true;
el.dataset.tabId = tab.id;
el.dataset.index = idx;
+34
View File
@@ -5744,3 +5744,37 @@ body.popup-mode .content-area {
cursor: pointer;
font-size: 0.85rem;
}
/* ── Dashboard Tab Navigation ── */
.dashboard-tabs {
display: flex;
gap: 2px;
margin-bottom: 16px;
border-bottom: 2px solid var(--border);
}
.dashboard-tab {
padding: 8px 16px;
border: none;
background: none;
color: var(--text-muted);
cursor: pointer;
font-size: 0.85rem;
font-weight: 500;
display: flex;
align-items: center;
gap: 6px;
border-bottom: 2px solid transparent;
margin-bottom: -2px;
transition: color 0.15s, border-color 0.15s;
}
.dashboard-tab:hover { color: var(--text-primary); }
.dashboard-tab.active {
color: var(--accent);
border-bottom-color: var(--accent);
}
.dashboard-panel {
display: none;
}
.dashboard-panel.active {
display: block;
}