Rebuild workspace widgets and behavioral graph views
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
const replyBanner = config.replyBanner;
|
||||
const replyBannerText = config.replyBannerText;
|
||||
const replyClearBtn = config.replyClearBtn;
|
||||
const historyLoader = config.historyLoader;
|
||||
const platformSelect = config.platformSelect;
|
||||
const contactSelect = config.contactSelect;
|
||||
const hiddenService = config.hiddenService;
|
||||
@@ -29,6 +30,9 @@
|
||||
let lastTs = core.toInt(thread.dataset.lastTs);
|
||||
let beforeContextReset = null;
|
||||
|
||||
state.loadingOlder = false;
|
||||
state.olderExhausted = false;
|
||||
|
||||
const nearBottom = function () {
|
||||
return thread.scrollHeight - thread.scrollTop - thread.clientHeight < 120;
|
||||
};
|
||||
@@ -39,6 +43,21 @@
|
||||
}
|
||||
};
|
||||
|
||||
const setHistoryLoader = function (message, hidden) {
|
||||
if (!historyLoader) {
|
||||
return;
|
||||
}
|
||||
historyLoader.textContent = String(
|
||||
message || "Scroll up to load older messages."
|
||||
);
|
||||
historyLoader.classList.toggle("is-hidden", !!hidden);
|
||||
};
|
||||
|
||||
const getOldestTs = function () {
|
||||
const firstRow = thread.querySelector(".compose-row");
|
||||
return core.toInt(firstRow && firstRow.dataset ? firstRow.dataset.ts : 0);
|
||||
};
|
||||
|
||||
const queryParams = function (extraParams) {
|
||||
const params = new URLSearchParams();
|
||||
params.set("service", thread.dataset.service || "");
|
||||
@@ -204,8 +223,28 @@
|
||||
});
|
||||
if (rows.length) {
|
||||
scrollToBottom(shouldStick);
|
||||
setHistoryLoader("", false);
|
||||
}
|
||||
ensureEmptyState();
|
||||
if (!thread.querySelector(".compose-row")) {
|
||||
setHistoryLoader("", true);
|
||||
}
|
||||
};
|
||||
|
||||
const prependMessageHtml = function (html) {
|
||||
const rows = parseMessageRows(html);
|
||||
if (!rows.length) {
|
||||
return 0;
|
||||
}
|
||||
const previousHeight = thread.scrollHeight;
|
||||
const previousTop = thread.scrollTop;
|
||||
rows.forEach(function (msg) {
|
||||
upsertMessageRow(msg);
|
||||
});
|
||||
thread.scrollTop = previousTop + (thread.scrollHeight - previousHeight);
|
||||
setHistoryLoader("", false);
|
||||
ensureEmptyState();
|
||||
return rows.length;
|
||||
};
|
||||
|
||||
const applyTyping = function (payload) {
|
||||
@@ -267,6 +306,47 @@
|
||||
}
|
||||
};
|
||||
|
||||
const loadOlder = async function () {
|
||||
if (state.loadingOlder || state.olderExhausted) {
|
||||
return;
|
||||
}
|
||||
const oldestTs = getOldestTs();
|
||||
if (!oldestTs) {
|
||||
state.olderExhausted = true;
|
||||
setHistoryLoader("Start of conversation.", false);
|
||||
return;
|
||||
}
|
||||
state.loadingOlder = true;
|
||||
setHistoryLoader("Loading older messages...", false);
|
||||
try {
|
||||
const response = await fetch(
|
||||
thread.dataset.pollUrl + "?" + queryParams({ before_ts: String(oldestTs) }),
|
||||
{
|
||||
method: "GET",
|
||||
credentials: "same-origin",
|
||||
headers: { Accept: "application/json" },
|
||||
}
|
||||
);
|
||||
if (!response.ok) {
|
||||
setHistoryLoader("Could not load older messages.", false);
|
||||
return;
|
||||
}
|
||||
const payload = await response.json();
|
||||
const inserted = prependMessageHtml(payload.messages_html || "");
|
||||
state.olderExhausted = !payload.has_older || inserted === 0;
|
||||
setHistoryLoader(
|
||||
state.olderExhausted
|
||||
? "Start of conversation."
|
||||
: "Scroll up to load older messages.",
|
||||
false
|
||||
);
|
||||
} catch (_err) {
|
||||
setHistoryLoader("Could not load older messages.", false);
|
||||
} finally {
|
||||
state.loadingOlder = false;
|
||||
}
|
||||
};
|
||||
|
||||
const setupWebSocket = function () {
|
||||
const wsPath = String(thread.dataset.wsUrl || "").trim();
|
||||
if (!wsPath || !window.WebSocket) {
|
||||
@@ -359,8 +439,14 @@
|
||||
clearReplyTarget();
|
||||
closeSocket();
|
||||
lastTs = 0;
|
||||
state.loadingOlder = false;
|
||||
state.olderExhausted = false;
|
||||
thread.dataset.lastTs = "0";
|
||||
thread.innerHTML = "";
|
||||
if (historyLoader) {
|
||||
thread.appendChild(historyLoader);
|
||||
}
|
||||
setHistoryLoader("Loading recent messages...", false);
|
||||
ensureEmptyState("Loading messages...");
|
||||
applyTyping({ typing: false });
|
||||
poll(true);
|
||||
@@ -466,6 +552,12 @@
|
||||
setReplyTarget(row.dataset.messageId || "", row.dataset.replySnippet || "");
|
||||
textarea.focus();
|
||||
});
|
||||
|
||||
thread.addEventListener("scroll", function () {
|
||||
if (thread.scrollTop <= 48) {
|
||||
loadOlder();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const init = function () {
|
||||
@@ -473,6 +565,7 @@
|
||||
bindContextSelectors();
|
||||
applyTyping(core.parseJsonSafe(panel.dataset.initialTyping || "{}", {}));
|
||||
ensureEmptyState();
|
||||
setHistoryLoader("", !thread.querySelector(".compose-row"));
|
||||
scrollToBottom(true);
|
||||
setupWebSocket();
|
||||
|
||||
@@ -492,6 +585,9 @@
|
||||
init: init,
|
||||
poll: poll,
|
||||
queryParams: queryParams,
|
||||
scrollToLatest: function () {
|
||||
scrollToBottom(true);
|
||||
},
|
||||
setBeforeContextReset: function (callback) {
|
||||
beforeContextReset = callback;
|
||||
},
|
||||
|
||||
@@ -119,6 +119,7 @@
|
||||
const threadController = threadModule.createController({
|
||||
contactSelect: document.getElementById(panelId + "-contact-select"),
|
||||
hiddenIdentifier: document.getElementById(panelId + "-input-identifier"),
|
||||
historyLoader: document.getElementById(panelId + "-history-loader"),
|
||||
hiddenPerson: document.getElementById(panelId + "-input-person"),
|
||||
hiddenReplyTo: form.querySelector('input[name="reply_to_message_id"]'),
|
||||
hiddenService: document.getElementById(panelId + "-input-service"),
|
||||
@@ -135,6 +136,7 @@
|
||||
thread: thread,
|
||||
typingNode: document.getElementById(panelId + "-typing"),
|
||||
});
|
||||
state.threadController = threadController;
|
||||
|
||||
const sendController = sendModule.createController({
|
||||
armInput: form.querySelector('input[name="failsafe_arm"]'),
|
||||
@@ -177,6 +179,25 @@
|
||||
},
|
||||
initAll: initAll,
|
||||
initPanel: initPanel,
|
||||
scrollWidgetToLatest: function (widgetId) {
|
||||
const widgetNode = widgetId ? document.getElementById(String(widgetId)) : null;
|
||||
if (!widgetNode) {
|
||||
return;
|
||||
}
|
||||
const panel = widgetNode.querySelector("[data-compose-panel]");
|
||||
const panelId = String(panel && panel.id ? panel.id : "").trim();
|
||||
if (!panelId) {
|
||||
return;
|
||||
}
|
||||
const state = window.giaComposePanels[panelId];
|
||||
if (
|
||||
state
|
||||
&& state.threadController
|
||||
&& typeof state.threadController.scrollToLatest === "function"
|
||||
) {
|
||||
state.threadController.scrollToLatest();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user