// ==================================================================================
// HISTORY VERSIONS BUTTON COMPONENT
// Smart button that only shows when history exists
// ==================================================================================
const HistoryVersionsButton = ({ doc, currentUser, onOpenModal, variant = 'default' }) => {
const { useState, useEffect } = React;
const [hasHistory, setHasHistory] = useState(false);
const [isChecking, setIsChecking] = useState(true);
// Check if history exists on mount
useEffect(() => {
let mounted = true;
const checkHistory = async () => {
try {
const res = await fetch(`/api/knowledge-base/${doc.id}/history`, {
headers: window.getApiHeaders ? window.getApiHeaders(currentUser.Username) : { 'X-OTO-User': currentUser.Username }
});
if (!mounted) return;
if (res.ok) {
const data = await res.json();
const historyCount = (data.history || []).length;
setHasHistory(historyCount > 0);
}
} catch (error) {
console.error('Error checking history:', error);
} finally {
if (mounted) setIsChecking(false);
}
};
// Only check if versioning is enabled
if (doc.versioning_mode === 'history' || doc.versioning_mode === 'parallel') {
checkHistory();
} else {
setIsChecking(false);
}
return () => { mounted = false; };
}, [doc.id, doc.versioning_mode, currentUser.Username]);
// Don't show button if checking, no versioning, or no history
if (isChecking) return null;
if (doc.versioning_mode !== 'history' && doc.versioning_mode !== 'parallel') return null;
if (!hasHistory) return null;
const handleClick = async () => {
try {
// Fetch fresh article data
const articleRes = await fetch(`/api/knowledge-base/${doc.id}`, {
headers: window.getApiHeaders ? window.getApiHeaders(currentUser.Username) : { 'X-OTO-User': currentUser.Username }
});
let freshArticle = doc;
if (articleRes.ok) {
const articleData = await articleRes.json();
freshArticle = articleData.article || doc;
}
// Fetch history
const historyRes = await fetch(`/api/knowledge-base/${doc.id}/history`, {
headers: window.getApiHeaders ? window.getApiHeaders(currentUser.Username) : { 'X-OTO-User': currentUser.Username }
});
if (!historyRes.ok) {
window.otoNotify?.toast('Could not load version history', 'error');
return;
}
const historyData = await historyRes.json();
const history = historyData.history || [];
if (history.length === 0) {
return;
}
// Get max version number
const maxVersion = Math.max(...history.map(h => h.version));
// Check if current article was updated after last history entry
const lastHistoryDate = new Date(history[0].changed_at || history[0].modified_at);
const articleUpdateDate = new Date(freshArticle.updated_at || freshArticle.created_at);
let allVersions = [];
if (articleUpdateDate > lastHistoryDate) {
// Article was modified after last history save - add current version
const currentVersion = {
id: `current-${freshArticle.id}`,
kb_id: freshArticle.id,
version: maxVersion + 1,
title: freshArticle.title,
content: freshArticle.content,
category: freshArticle.category,
status: freshArticle.status,
visibility: freshArticle.visibility,
tags: freshArticle.tags || [],
attachments: freshArticle.attachments || [],
attachments_snapshot: JSON.stringify(freshArticle.attachments || []),
changed_by: freshArticle.modified_by || currentUser.Username,
changed_by_name: freshArticle.modified_by_name || (currentUser.FirstName + ' ' + currentUser.LastName),
changed_at: freshArticle.updated_at || freshArticle.created_at,
modified_at: freshArticle.updated_at || freshArticle.created_at,
is_current: true
};
allVersions = [currentVersion, ...history];
} else {
// Last history IS current - just use history
allVersions = history;
}
// Open modal with versions
onOpenModal(doc.id, allVersions, freshArticle);
} catch (error) {
console.error('Error loading history:', error);
window.otoNotify?.toast('Error loading version history', 'error');
}
};
const label = doc.versioning_mode === 'parallel' ? '📂 Versions' : '📚 History';
// Menu variant: used inside dropdown menus (e.g. Actions menu). Full-width, aligned with other items.
if (variant === 'menu') {
return (
);
}
// Default standalone button (e.g. inline in forms or detail views)
return (
);
};
if (typeof window !== 'undefined') window.HistoryVersionsButton = HistoryVersionsButton;