index.html Repository Demand-Radar Original path index.htmlRole SOURCE Size 133270 bytes Lines 4046 SHA-256 bece94e1f815694e3db00dfa1480618e6692d3f0ab5c0ce667fb22f2bd33f6e4Displayed range 3501–4000 Previous file/page · Project index · Next file/page
headers: { 'Content-Type': 'application/json' },
body: '{}',
});
const payload = await res.json();
if (!res.ok || !payload.ok) {
throw new Error(payload.error || `HTTP ${res.status}`);
}
}
async function startMetaResearch() {
$('queryPlanActionOk').textContent = '';
$('queryPlanActionErr').textContent = '';
if (!currentQueryPlan || currentQueryPlan.status !== 'APPROVED') {
$('queryPlanActionErr').textContent = 'Najpierw zatwierdz Query Plan (APPROVED).';
return;
}
const active = getActiveQueryPlanProject();
$('metaResearchStartBtn').disabled = true;
try {
const res = await fetch(`/api/projects/${encodeURIComponent(active.projectId)}/meta-research`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
queryPlanId: currentQueryPlan.id,
}),
});
const payload = await res.json();
if (!res.ok || !payload.ok) {
throw new Error(payload.error || `HTTP ${res.status}`);
}
currentMetaResearchRun = payload.run;
$('queryPlanActionOk').textContent = `✓ Uruchomiono badanie: ${currentMetaResearchRun.id}`;
renderMetaResearchSummary(currentMetaResearchRun);
stopMetaResearchPolling();
metaResearchPollHandle = setInterval(() => loadMetaResearchRun(currentMetaResearchRun.id), 4000);
await loadMetaResearchRun(currentMetaResearchRun.id);
} catch (error) {
$('queryPlanActionErr').textContent = `BLAD uruchomienia badania: ${error.message}`;
$('metaResearchStartBtn').disabled = currentQueryPlan?.status !== 'APPROVED' || currentQueryPlanDirty;
}
}
async function checkN8nStatus() {
try {
const res = await fetch('/api/status');
const data = await res.json();
const el = $('n8nStatus');
el.className = `status ${data.reachable ? 'good' : 'bad'}`;
el.innerHTML = `<span class="dot"></span>${data.reachable ? 'n8n dostepny' : 'n8n niedostepny'} · ${escapeHtml(data.baseUrl)}`;
} catch {
const el = $('n8nStatus');
el.className = 'status bad';
el.innerHTML = '<span class="dot"></span>blad statusu';
}
}
async function refreshDbSize() {
try {
const res = await fetch('/api/db-size');
const data = await res.json();
const el = $('dbSizeStatus');
if (!res.ok || !data.ok) {
throw new Error(data.error || `HTTP ${res.status}`);
}
el.className = 'status db-size-chip';
el.innerHTML = `<span class="dot"></span>SQL: ${escapeHtml(formatBytes(data.bytes))}`;
} catch {
const el = $('dbSizeStatus');
el.className = 'status bad';
el.innerHTML = '<span class="dot"></span>SQL: blad';
}
}
for (const tabButton of document.querySelectorAll('.tab-btn')) {
tabButton.addEventListener('click', () => setActiveTab(tabButton.dataset.tab));
}
$('seedTableBody').addEventListener('change', event => {
const target = event.target;
const seedId = target.dataset.seedId;
if (!seedId) return;
if (target.classList.contains('seed-enabled')) {
updateSeed(seedId, { enabled: target.checked });
} else if (target.classList.contains('seed-priority')) {
updateSeed(seedId, { priority: target.value });
}
});
$('seedTableBody').addEventListener('input', event => {
const target = event.target;
const seedId = target.dataset.seedId;
if (!seedId) return;
const seed = findSeed(seedId);
if (!seed) return;
if (target.classList.contains('seed-query')) {
seed.query = target.value;
} else if (target.classList.contains('seed-rationale')) {
seed.rationale = target.value;
} else {
return;
}
markPlanDirty('MANUAL_REVISION');
$('currentPlanOutput').textContent = JSON.stringify(currentPlan, null, 2);
const check = basicContractCheck(currentPlan);
setContract(check);
$('reviseBtn').disabled = !check.ok;
});
$('seedTableBody').addEventListener('click', event => {
if (!event.target.classList.contains('seed-delete')) return;
deleteSeed(event.target.dataset.seedId);
});
$('addSeedBtn').addEventListener('click', createUserSeed);
$('enableAllSeedsBtn').addEventListener('click', () => {
if (!currentPlan?.seedQueries) return;
currentPlan.seedQueries.forEach(seed => { seed.enabled = true; });
markPlanDirty('MANUAL_REVISION');
syncPlanViews();
});
$('disableAllSeedsBtn').addEventListener('click', () => {
if (!currentPlan?.seedQueries) return;
currentPlan.seedQueries.forEach(seed => { seed.enabled = false; });
markPlanDirty('MANUAL_REVISION');
syncPlanViews();
});
$('copyEnabledSeedsBtn').addEventListener('click', async () => {
if (!currentPlan?.seedQueries) return;
const enabled = currentPlan.seedQueries.filter(seed => seed.enabled);
await navigator.clipboard.writeText(JSON.stringify(enabled, null, 2));
const old = $('copyEnabledSeedsBtn').textContent;
$('copyEnabledSeedsBtn').textContent = `Skopiowano ${enabled.length}`;
setTimeout(() => { $('copyEnabledSeedsBtn').textContent = old; }, 1000);
});
$('generateBtn').addEventListener('click', async () => {
$('saveResult').textContent = '';
$('saveError').textContent = '';
const requestId = uuid();
$('requestIdText').textContent = requestId;
const payload = {
requestId,
projectId,
brief: collectBriefFromForm(),
availableDiscoveryCapabilities: capabilities(),
};
try {
const { plan } = await callWorkflow('/api/mr01', payload);
if (plan) {
conversation = [];
revisionNumber = 0;
setCurrentPlan(plan, {
sourceLabel: 'MR-01 generation',
origin: 'LLM_GENERATION',
persistedVersionId: null,
persistedVersionNumber: null,
dirty: true,
addHistory: true,
});
}
} catch (error) {
$('output').textContent = error.stack || error.message;
setContract({ ok: false, reason: error.message });
}
});
$('reviseBtn').addEventListener('click', async () => {
$('saveResult').textContent = '';
$('saveError').textContent = '';
if (!currentPlan) return;
const instruction = $('instruction').value.trim();
if (!instruction) return;
const requestId = uuid();
$('requestIdText').textContent = requestId;
const payload = {
requestId,
projectId,
currentPlan,
userInstruction: instruction,
recentConversation: conversation.slice(-8),
availableDiscoveryCapabilities: capabilities(),
};
try {
const { plan } = await callWorkflow('/api/mr02', payload);
if (plan) {
conversation.push({ role: 'user', content: instruction });
conversation.push({ role: 'assistant', content: plan.changeSummary || 'Plan revised.' });
setCurrentPlan(plan, {
sourceLabel: 'MR-02 revision',
origin: 'LLM_REVISION',
dirty: true,
addHistory: true,
});
}
} catch (error) {
$('output').textContent = error.stack || error.message;
setContract({ ok: false, reason: error.message });
}
});
$('newProjectBtn').addEventListener('click', () => {
projectId = uuid();
localStorage.setItem('marketRadarProjectId', projectId);
$('projectIdText').textContent = projectId;
currentPlan = null;
currentPlanOrigin = null;
currentPersistedVersionId = null;
currentPersistedVersionNumber = null;
currentPlanDirty = false;
conversation = [];
revisionNumber = 0;
syncPlanViews();
$('planStateText').textContent = 'Najpierw wygeneruj poprawny plan MR-01.';
$('history').className = 'muted';
$('history').textContent = 'Brak.';
$('versionPreview').textContent = 'Kliknij POKAZ przy wybranej wersji.';
});
$('clearPlanBtn').addEventListener('click', () => {
currentPlan = null;
currentPlanOrigin = null;
currentPlanDirty = false;
conversation = [];
revisionNumber = 0;
syncPlanViews();
$('planStateText').textContent = 'currentPlan wyczyszczony.';
});
$('loadPlanBtn').addEventListener('click', () => {
try {
const value = JSON.parse($('manualPlan').value);
const check = basicContractCheck(value);
setContract(check);
if (!check.ok) throw new Error(check.reason);
setCurrentPlan(value, {
sourceLabel: 'manual JSON load',
origin: 'MANUAL_REVISION',
dirty: true,
addHistory: true,
});
} catch (error) {
setContract({ ok: false, reason: `Nie mozna wczytac planu: ${error.message}` });
}
});
$('copyBtn').addEventListener('click', async () => {
if (lastResponseData == null) return;
await navigator.clipboard.writeText(JSON.stringify(lastResponseData, null, 2));
const old = $('copyBtn').textContent;
$('copyBtn').textContent = 'Skopiowano';
setTimeout(() => { $('copyBtn').textContent = old; }, 900);
});
$('saveProjectBtn').addEventListener('click', saveCurrentProject);
$('refreshProjectsBtn').addEventListener('click', refreshProjects);
$('savedProjectsBody').addEventListener('click', event => {
const button = event.target.closest('.open-project-btn');
if (!button) return;
openProject(button.dataset.projectId);
});
$('selectedProjectVersions').addEventListener('click', event => {
const previewBtn = event.target.closest('.preview-version-btn');
if (previewBtn) {
previewVersion(previewBtn.dataset.versionId);
return;
}
const loadBtn = event.target.closest('.load-version-btn');
if (loadBtn) {
loadVersionIntoWorkbench(loadBtn.dataset.versionId);
}
});
$('queryPlanGenerateBtn').addEventListener('click', generateQueryPlan);
$('queryPlanRefreshBtn').addEventListener('click', refreshQueryPlanContext);
$('queryPlanSaveBtn').addEventListener('click', saveQueryPlanDraft);
$('queryPlanApproveBtn').addEventListener('click', approveQueryPlan);
$('metaResearchStartBtn').addEventListener('click', startMetaResearch);
$('metaRunRelevanceBtn').addEventListener('click', runMetaRelevanceFilter);
$('metaApplyFiltersBtn').addEventListener('click', loadMetaResearchAds);
$('metaExportFullCsvBtn').addEventListener('click', exportMetaAdsFullCsv);
$('metaExportShortCsvBtn').addEventListener('click', exportMetaAdsShortCsv);
$('queryPlanSelectAllSeedsBtn').addEventListener('click', () => {
if (!queryPlanContext?.seeds?.length) return;
queryPlanSelectedSeedIds = new Set(queryPlanContext.seeds.map(seed => String(seed.seedId)));
renderQueryPlanSeedSourceList();
});
$('queryPlanClearSeedSelectionBtn').addEventListener('click', () => {
queryPlanSelectedSeedIds = new Set();
renderQueryPlanSeedSourceList();
});
$('queryPlanSeedSourceList').addEventListener('change', event => {
const target = event.target;
if (!target.classList.contains('query-plan-seed-checkbox')) return;
const seedId = String(target.dataset.seedId || '');
if (!seedId) return;
if (target.checked) {
queryPlanSelectedSeedIds.add(seedId);
} else {
queryPlanSelectedSeedIds.delete(seedId);
}
renderQueryPlanSeedSourceList();
});
$('queryPlanSeedSourceList').addEventListener('click', event => {
const removeBtn = event.target.closest('.seed-remove-btn');
if (!removeBtn) return;
const seedId = String(removeBtn.dataset.removeSeedId || '');
if (!seedId) return;
queryPlanContext.seeds = (queryPlanContext.seeds || []).filter(seed => String(seed.seedId) !== seedId);
queryPlanSelectedSeedIds.delete(seedId);
renderQueryPlanSeedSourceList();
});
$('metaFilterHelpBtn').addEventListener('click', event => {
event.stopPropagation();
$('metaFilterHelpBubble').classList.toggle('hidden');
});
$('metaLifecycleHelpBtn').addEventListener('click', event => {
event.stopPropagation();
$('metaLifecycleHelpBubble').classList.toggle('hidden');
});
document.addEventListener('click', event => {
const wrap = event.target.closest('.filter-help-wrap');
const lifecycleWrap = event.target.closest('#metaLifecycleFilterWrap');
if (!wrap) {
$('metaFilterHelpBubble').classList.add('hidden');
}
if (!lifecycleWrap) {
$('metaLifecycleHelpBubble').classList.add('hidden');
}
});
[
'metaFilterRelevance',
'metaFilterQuery',
'metaFilterSeed',
'metaFilterPage',
'metaFilterVisible',
'metaFilterActive',
'metaFilterMinReach',
'metaFilterStartDate',
'metaSortBy',
'metaFamilyClassFilter',
'metaFamilyStatusFilter',
'metaFamilyPatternFilter',
].forEach(id => {
$(id).addEventListener('change', loadMetaResearchAds);
});
$('metaLifecycleAllBtn').addEventListener('click', () => {
setLifecycleFiltersSelected(true);
loadMetaResearchAds();
});
$('metaLifecycleNoneBtn').addEventListener('click', () => {
setLifecycleFiltersSelected(false);
loadMetaResearchAds();
});
$('metaLifecycleCheckboxes').addEventListener('change', () => {
loadMetaResearchAds();
});
$('metaAdsBody').addEventListener('change', async event => {
const select = event.target.closest('.ad-relevance-select');
if (!select) return;
const adArchiveId = String(select.dataset.adArchiveId || '').trim();
if (!adArchiveId) return;
const nextStatus = String(select.value || '').trim().toUpperCase();
try {
await setManualAdRelevance(adArchiveId, nextStatus);
$('metaRelevanceRunStatus').textContent = `Zapisano manual override: ${adArchiveId} -> ${nextStatus}`;
await loadMetaResearchAds();
} catch (error) {
$('metaRelevanceRunStatus').textContent = `BLAD manual override: ${error.message}`;
}
});
$('metaAdsBody').addEventListener('click', async event => {
const detailsButton = event.target.closest('.ad-details-btn');
if (detailsButton) {
const adArchiveId = String(detailsButton.dataset.adArchiveId || '').trim();
if (adArchiveId) {
openAdDetailsModal(adArchiveId);
}
return;
}
const restoreButton = event.target.closest('.ad-relevance-restore');
if (!restoreButton) return;
const adArchiveId = String(restoreButton.dataset.adArchiveId || '').trim();
if (!adArchiveId) return;
try {
await restoreAdRelevanceFromMr04(adArchiveId);
$('metaRelevanceRunStatus').textContent = `Przywrocono decyzje MR04 dla reklamy ${adArchiveId}.`;
await loadMetaResearchAds();
} catch (error) {
$('metaRelevanceRunStatus').textContent = `BLAD przywracania MR04: ${error.message}`;
}
});
$('adDetailsCloseBtn').addEventListener('click', closeAdDetailsModal);
$('adDetailsModalBackdrop').addEventListener('click', event => {
if (event.target === $('adDetailsModalBackdrop')) {
closeAdDetailsModal();
}
});
$('queryPlanEditor').addEventListener('input', event => {
const target = event.target;
const seedIndex = Number(target.dataset.seedIndex);
const queryIndex = Number(target.dataset.queryIndex);
if (!Number.isFinite(seedIndex) || !Number.isFinite(queryIndex)) return;
const query = getEditableQuery(seedIndex, queryIndex);
if (!query) return;
if (target.classList.contains('query-text')) {
query.text = target.value;
query.termCount = countQueryTerms(target.value);
} else if (target.classList.contains('query-rationale')) {
query.rationale = target.value;
} else if (target.classList.contains('query-priority')) {
query.priority = Number(target.value);
} else {
return;
}
markQueryPlanDirty();
});
$('queryPlanEditor').addEventListener('change', event => {
const target = event.target;
const seedIndex = Number(target.dataset.seedIndex);
const queryIndex = Number(target.dataset.queryIndex);
if (!Number.isFinite(seedIndex) || !Number.isFinite(queryIndex)) return;
const query = getEditableQuery(seedIndex, queryIndex);
if (!query) return;
if (target.classList.contains('query-enabled')) {
query.enabled = target.checked;
} else if (target.classList.contains('query-type')) {
query.queryType = target.value;
} else {
return;
}
markQueryPlanDirty();
});