+
{{ ent.get('entity_type', '?')[:3] }}
{{ ent.get('name', '') }}
@@ -413,6 +435,18 @@
if (el) el.innerHTML = marked.parse(narrativeRaw, {breaks: true, gfm: true});
}
+ // Click-to-converse: delegated handler for all [data-conversation] elements
+ var dashboard = document.querySelector('.pulse-dashboard');
+ if (dashboard) {
+ dashboard.addEventListener('click', function(e) {
+ var el = e.target.closest('[data-conversation]');
+ if (el && window.openConversation) {
+ e.preventDefault();
+ window.openConversation({ prompt: el.dataset.conversation });
+ }
+ });
+ }
+
// WebSocket live updates
if (window.appEvents) {
// Vital signs: supervisor.status, observe.observed, observe.status
diff --git a/convey/templates/app.html b/convey/templates/app.html
index 0e40dd651..c6c993aa5 100644
--- a/convey/templates/app.html
+++ b/convey/templates/app.html
@@ -190,6 +190,25 @@
// Expose for websocket navigate handler
window._closeConversationPanel = closePanel;
+ // --- Public conversation API ---
+ // Generic API for any app to open the conversation panel with a pre-filled prompt.
+ window.openConversation = function(options) {
+ options = options || {};
+ if (options.prompt) {
+ input.value = options.prompt;
+ input.dispatchEvent(new Event('input'));
+ }
+ if (options.autoSend) {
+ form.requestSubmit();
+ } else {
+ input.focus();
+ input.setSelectionRange(input.value.length, input.value.length);
+ if (options.prompt && options.prompt.length > 40) {
+ openPanel();
+ }
+ }
+ };
+
// Save state before navigation
window.addEventListener('pagehide', save);