bethaus-app/static/search_db_analyzer.js
2026-01-26 15:14:31 +00:00

238 lines
7.7 KiB
JavaScript

(() => {
function initSearchDbAnalyzer() {
const form = document.getElementById('analyzer-form');
if (!form || form.dataset.bound) return;
form.dataset.bound = '1';
const dataScript = document.getElementById('search-db-analyzer-data');
let foldersUrl = '';
let queryUrl = '';
if (dataScript) {
try {
const parsed = JSON.parse(dataScript.textContent || '{}');
foldersUrl = parsed.folders_url || '';
queryUrl = parsed.query_url || '';
} catch (err) {
console.error('Failed to parse analyzer data', err);
}
}
const feedback = document.getElementById('analyzer-feedback');
const resultWrapper = document.getElementById('analyzer-result');
const resultBody = document.getElementById('result-body');
const totalCount = document.getElementById('totalCount');
const levelsContainer = document.getElementById('folder-levels');
const levelSelects = [];
const createSelect = (level, options) => {
const wrapper = document.createElement('div');
wrapper.className = 'folder-level';
const select = document.createElement('select');
select.className = 'form-select';
select.dataset.level = level;
select.required = level === 0;
const placeholder = document.createElement('option');
placeholder.value = '';
placeholder.textContent = level === 0 ? 'Bitte auswählen' : 'Optionaler Unterordner';
select.appendChild(placeholder);
options.forEach((opt) => {
const option = document.createElement('option');
option.value = opt;
option.textContent = opt;
select.appendChild(option);
});
select.addEventListener('change', () => {
removeLevelsFrom(level + 1);
updateControlButtons();
});
const controls = document.createElement('div');
controls.className = 'd-flex gap-2 align-items-center';
const btnGroup = document.createElement('div');
btnGroup.className = 'btn-group btn-group-sm';
const addBtn = document.createElement('button');
addBtn.type = 'button';
addBtn.className = 'btn btn-outline-secondary';
addBtn.textContent = '+';
addBtn.addEventListener('click', () => handleAddLevel());
btnGroup.appendChild(addBtn);
let removeBtn = null;
if (level > 0) {
removeBtn = document.createElement('button');
removeBtn.type = 'button';
removeBtn.className = 'btn btn-outline-danger';
removeBtn.textContent = '-';
removeBtn.addEventListener('click', () => {
removeLevelsFrom(level);
updateControlButtons();
});
btnGroup.appendChild(removeBtn);
}
controls.append(select, btnGroup);
wrapper.append(controls);
levelsContainer.appendChild(wrapper);
levelSelects.push({ wrapper, select, addBtn, removeBtn, btnGroup });
};
const removeLevelsFrom = (startIndex) => {
while (levelSelects.length > startIndex) {
const item = levelSelects.pop();
levelsContainer.removeChild(item.wrapper);
}
};
const currentPath = () => {
const parts = levelSelects
.map(({ select }) => select.value)
.filter((v) => v && v.trim() !== '');
return parts.join('/');
};
const fetchChildren = async (parentPath = '') => {
if (!foldersUrl) throw new Error('Ordner-Endpoint fehlt.');
const params = parentPath ? `?parent=${encodeURIComponent(parentPath)}` : '';
const response = await fetch(`${foldersUrl}${params}`);
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Ordner konnten nicht geladen werden.');
}
return data.children || [];
};
const updateControlButtons = () => {
if (!levelSelects.length) {
return;
}
levelSelects.forEach((item, idx) => {
const isLast = idx === levelSelects.length - 1;
if (item.btnGroup) {
item.btnGroup.classList.toggle('d-none', !isLast);
}
if (item.addBtn) {
item.addBtn.disabled = !item.select.value;
}
if (item.removeBtn) {
const hideRemove = !isLast || idx === 0;
item.removeBtn.classList.toggle('d-none', hideRemove);
item.removeBtn.disabled = hideRemove;
}
});
};
const initBaseLevel = async () => {
try {
const children = await fetchChildren('');
if (!children.length) {
feedback.textContent = 'Keine Ordner in der Datenbank gefunden.';
feedback.style.display = 'block';
return;
}
createSelect(0, children);
updateControlButtons();
} catch (error) {
feedback.textContent = error.message;
feedback.style.display = 'block';
}
};
const handleAddLevel = async () => {
feedback.style.display = 'none';
const path = currentPath();
if (!path) {
feedback.textContent = 'Bitte zuerst einen Hauptordner auswählen.';
feedback.style.display = 'block';
return;
}
try {
const children = await fetchChildren(path);
if (!children.length) {
feedback.textContent = 'Keine weiteren Unterordner vorhanden.';
feedback.style.display = 'block';
return;
}
createSelect(levelSelects.length, children);
updateControlButtons();
} catch (error) {
feedback.textContent = error.message;
feedback.style.display = 'block';
}
};
initBaseLevel();
form.addEventListener('submit', async (event) => {
event.preventDefault();
feedback.style.display = 'none';
resultWrapper.style.display = 'none';
const folderPath = currentPath();
if (!folderPath) {
feedback.textContent = 'Bitte einen Ordner auswählen.';
feedback.style.display = 'block';
return;
}
const submitButton = form.querySelector('button[type="submit"]');
submitButton.disabled = true;
submitButton.textContent = 'Wird geladen...';
try {
if (!queryUrl) throw new Error('Abfrage-Endpoint fehlt.');
const response = await fetch(queryUrl, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ folder_path: folderPath })
});
const data = await response.json();
if (!response.ok) {
throw new Error(data.error || 'Abfrage fehlgeschlagen.');
}
resultBody.innerHTML = '';
if (data.categories && data.categories.length) {
data.categories.forEach((row) => {
const tr = document.createElement('tr');
const cat = document.createElement('td');
const cnt = document.createElement('td');
cat.textContent = row.category || 'Keine Kategorie';
cnt.textContent = row.count;
tr.append(cat, cnt);
resultBody.appendChild(tr);
});
} else {
const tr = document.createElement('tr');
const td = document.createElement('td');
td.colSpan = 2;
td.textContent = 'Keine Treffer gefunden.';
tr.appendChild(td);
resultBody.appendChild(tr);
}
totalCount.textContent = `${data.total || 0} Dateien`;
resultWrapper.style.display = 'block';
} catch (error) {
feedback.textContent = error.message;
feedback.style.display = 'block';
} finally {
submitButton.disabled = false;
submitButton.textContent = 'Abfrage starten';
}
});
}
if (window.PageRegistry && typeof window.PageRegistry.register === 'function') {
window.PageRegistry.register('search_db_analyzer', { init: initSearchDbAnalyzer });
}
})();