/** * K-hub «Мультисервер»: manual conflict resolution (orchestrator vs farm hub). */ (function (global) { const API = "/api/v1/sync/conflicts"; function escapeHtml(value) { return String(value) .replace(/&/g, "&") .replace(//g, ">") .replace(/"/g, """); } function renderList(root, items, enterpriseId) { if (!items.length) { root.innerHTML = '

Нет конфликтов синхронизации.

'; return; } root.innerHTML = '' + "" + items .map( (c) => `` + `` + `` + `` + `` + "", ) .join("") + "
ТаблицаЗаписьФерма
${escapeHtml(c.table_name)}${escapeHtml(c.record_id)}${escapeHtml(c.farm_hub_id || "—")}
"; root.querySelectorAll("[data-action=open-conflict]").forEach((btn) => { btn.addEventListener("click", () => { const row = btn.closest("tr"); const id = row && row.getAttribute("data-conflict-id"); if (id) openDetail(root, id, enterpriseId); }); }); } function openDetail(root, conflictId, enterpriseId) { fetch(`${API}/${conflictId}?enterprise_id=${encodeURIComponent(enterpriseId)}`) .then((r) => r.json()) .then((detail) => { root.innerHTML = `
` + `

${escapeHtml(detail.table_name)} · ${escapeHtml(detail.record_id)}

` + `
Оркестр
${escapeHtml(JSON.stringify(detail.orchestrator_snapshot, null, 2))}
` + `
Сервер
${escapeHtml(JSON.stringify(detail.hub_snapshot, null, 2))}
` + `
` + ` ` + ` ` + `` + `
`; root.querySelector("[data-action=back-list]")?.addEventListener("click", () => load(root, enterpriseId)); root.querySelectorAll("[data-resolution]").forEach((btn) => { btn.addEventListener("click", () => { const resolution = btn.getAttribute("data-resolution"); fetch(`${API}/${conflictId}/resolve?enterprise_id=${encodeURIComponent(enterpriseId)}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ resolution }), }).then(() => load(root, enterpriseId)); }); }); }); } function load(root, enterpriseId) { root.innerHTML = '

Загрузка конфликтов…

'; const orch = global.__WESP_ORCH__ || {}; if (orch.configured === false) { root.innerHTML = '

Orchestrator не настроен. Укажите upstream, hub_site_id и api_key в админке.

'; return; } if (orch.reachable === false) { const host = orch.upstream ? ` (${orch.upstream})` : ""; root.innerHTML = `

Orchestrator недоступен${escapeHtml(host)}. Проверьте upstream URL и что сервис запущен.

`; return; } fetch(`${API}?enterprise_id=${encodeURIComponent(enterpriseId)}`) .then((r) => { if (!r.ok) { return r.json().catch(() => ({})).then((body) => { throw new Error(body.message || `HTTP ${r.status}`); }); } return r.json(); }) .then((items) => { if (items && items.error) { throw new Error(items.message || "Orchestrator error"); } renderList(root, Array.isArray(items) ? items : [], enterpriseId); }) .catch((err) => { const msg = err && err.message ? err.message : "Не удалось загрузить конфликты."; root.innerHTML = `

${escapeHtml(msg)}

`; }); } global.WespMultiserverPanel = { mount(rootEl, enterpriseId) { if (!rootEl) return; load(rootEl, enterpriseId || ""); }, pendingCount(enterpriseId) { return fetch(`${API}?enterprise_id=${encodeURIComponent(enterpriseId)}`) .then((r) => r.json()) .then((items) => (Array.isArray(items) ? items.length : 0)) .catch(() => 0); }, }; })(window);