Increase security and reformat
This commit is contained in:
@@ -129,7 +129,7 @@
|
||||
class="button is-small is-info is-light"
|
||||
onclick="giaWorkspaceQueueSelectedDraft('{{ person.id }}'); return false;">
|
||||
<span class="icon is-small"><i class="fa-solid fa-inbox-in"></i></span>
|
||||
<span>Add To Queue</span>
|
||||
<span>Queue For Approval</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -399,8 +399,8 @@
|
||||
return String(value || "")
|
||||
.split(",")
|
||||
.map(function (item) {
|
||||
return item.trim();
|
||||
})
|
||||
return item.trim();
|
||||
})
|
||||
.filter(Boolean);
|
||||
};
|
||||
|
||||
|
||||
@@ -475,7 +475,7 @@
|
||||
</button>
|
||||
<button type="submit" class="button is-info is-light" onclick="giaEngageSetAction('{{ person.id }}', 'queue');">
|
||||
<span class="icon is-small"><i class="fa-solid fa-inbox-in"></i></span>
|
||||
<span>Add To Queue</span>
|
||||
<span>Queue For Approval</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -867,35 +867,35 @@
|
||||
};
|
||||
|
||||
defineGlobal("giaMitigationToggleEdit", function(button) {
|
||||
const form = button && button.closest ? button.closest("form") : null;
|
||||
if (!form) return;
|
||||
const editing = button.dataset.editState === "edit";
|
||||
if (!editing) {
|
||||
form.querySelectorAll('[data-editable="1"]').forEach(function(field) { field.removeAttribute("readonly"); });
|
||||
form.querySelectorAll('[data-editable-toggle="1"]').forEach(function(field) { field.removeAttribute("disabled"); });
|
||||
const card = form.closest(".mitigation-artifact-card");
|
||||
if (card) card.classList.add("is-editing");
|
||||
button.dataset.editState = "edit";
|
||||
button.classList.remove("is-light");
|
||||
button.title = "Save";
|
||||
button.innerHTML = '<span class="icon is-small"><i class="fa-solid fa-check"></i></span>';
|
||||
resizeEditableTextareas(form);
|
||||
return;
|
||||
}
|
||||
form.requestSubmit();
|
||||
const form = button && button.closest ? button.closest("form") : null;
|
||||
if (!form) return;
|
||||
const editing = button.dataset.editState === "edit";
|
||||
if (!editing) {
|
||||
form.querySelectorAll('[data-editable="1"]').forEach(function(field) { field.removeAttribute("readonly"); });
|
||||
form.querySelectorAll('[data-editable-toggle="1"]').forEach(function(field) { field.removeAttribute("disabled"); });
|
||||
const card = form.closest(".mitigation-artifact-card");
|
||||
if (card) card.classList.add("is-editing");
|
||||
button.dataset.editState = "edit";
|
||||
button.classList.remove("is-light");
|
||||
button.title = "Save";
|
||||
button.innerHTML = '<span class="icon is-small"><i class="fa-solid fa-check"></i></span>';
|
||||
resizeEditableTextareas(form);
|
||||
return;
|
||||
}
|
||||
form.requestSubmit();
|
||||
});
|
||||
|
||||
defineGlobal("giaEngageSetAction", function(pid, action) {
|
||||
const actionInput = document.getElementById("engage-action-input-" + pid);
|
||||
if (actionInput) actionInput.value = action;
|
||||
if (action === "send") window.giaEngageSyncSendOverride(pid);
|
||||
const actionInput = document.getElementById("engage-action-input-" + pid);
|
||||
if (actionInput) actionInput.value = action;
|
||||
if (action === "send") window.giaEngageSyncSendOverride(pid);
|
||||
});
|
||||
|
||||
defineGlobal("giaEngageAutoPreview", function(pid) {
|
||||
const form = document.getElementById("engage-form-" + pid);
|
||||
if (!form) return;
|
||||
window.giaEngageSetAction(pid, "preview");
|
||||
form.requestSubmit();
|
||||
const form = document.getElementById("engage-form-" + pid);
|
||||
if (!form) return;
|
||||
window.giaEngageSetAction(pid, "preview");
|
||||
form.requestSubmit();
|
||||
});
|
||||
|
||||
window.giaEngageSetTarget = function(pid, targetId) {
|
||||
@@ -908,14 +908,14 @@
|
||||
};
|
||||
|
||||
defineGlobal("giaEngageSelect", function(pid, kind, value, node) {
|
||||
const inputId = kind === "share" ? ("engage-share-input-" + pid) : (kind === "framing" ? ("engage-framing-input-" + pid) : "");
|
||||
const input = inputId ? document.getElementById(inputId) : null;
|
||||
if (input) input.value = value;
|
||||
const li = node && node.closest ? node.closest("li") : null;
|
||||
if (!li || !li.parentElement) return;
|
||||
Array.from(li.parentElement.children).forEach(function(child) { child.classList.remove("is-active"); });
|
||||
li.classList.add("is-active");
|
||||
window.giaEngageAutoPreview(pid);
|
||||
const inputId = kind === "share" ? ("engage-share-input-" + pid) : (kind === "framing" ? ("engage-framing-input-" + pid) : "");
|
||||
const input = inputId ? document.getElementById(inputId) : null;
|
||||
if (input) input.value = value;
|
||||
const li = node && node.closest ? node.closest("li") : null;
|
||||
if (!li || !li.parentElement) return;
|
||||
Array.from(li.parentElement.children).forEach(function(child) { child.classList.remove("is-active"); });
|
||||
li.classList.add("is-active");
|
||||
window.giaEngageAutoPreview(pid);
|
||||
});
|
||||
|
||||
window.giaMitigationShowTab(personId, "{{ active_tab|default:'plan_board' }}");
|
||||
|
||||
@@ -536,8 +536,8 @@
|
||||
showOperationPane(operation);
|
||||
const activeTab = tabKey || (
|
||||
operation === "artifacts"
|
||||
? ((window.giaWorkspaceState[personId] || {}).currentMitigationTab || "plan_board")
|
||||
: operation
|
||||
? ((window.giaWorkspaceState[personId] || {}).currentMitigationTab || "plan_board")
|
||||
: operation
|
||||
);
|
||||
setTopCapsuleActive(activeTab);
|
||||
const hydrated = hydrateCachedIfAvailable(operation);
|
||||
@@ -573,8 +573,8 @@
|
||||
const currentState = window.giaWorkspaceState[personId] || {};
|
||||
const targetTabKey = currentState.pendingTabKey || (
|
||||
operation === "artifacts"
|
||||
? (currentState.currentMitigationTab || "plan_board")
|
||||
: operation
|
||||
? (currentState.currentMitigationTab || "plan_board")
|
||||
: operation
|
||||
);
|
||||
if (!forceRefresh && currentState.current === operation && pane.dataset.loaded === "1") {
|
||||
window.giaWorkspaceShowTab(personId, operation, targetTabKey);
|
||||
@@ -622,38 +622,38 @@
|
||||
fetch(url, { method: "GET" })
|
||||
.then(function(resp) { return resp.text(); })
|
||||
.then(function(html) {
|
||||
pane.innerHTML = html;
|
||||
pane.dataset.loaded = "1";
|
||||
executeInlineScripts(pane);
|
||||
pane.classList.remove("ai-animate-in");
|
||||
void pane.offsetWidth;
|
||||
pane.classList.add("ai-animate-in");
|
||||
if (cacheAllowed) {
|
||||
window.giaWorkspaceCache[key] = {
|
||||
html: html,
|
||||
ts: Date.now(),
|
||||
};
|
||||
persistCache();
|
||||
setCachedIndicator(true, window.giaWorkspaceCache[key].ts);
|
||||
} else {
|
||||
setCachedIndicator(false, null);
|
||||
}
|
||||
if (window.htmx) {
|
||||
window.htmx.process(pane);
|
||||
}
|
||||
if (operation === "draft_reply" && typeof window.giaWorkspaceUseDraft === "function") {
|
||||
window.giaWorkspaceUseDraft(personId, operation, 0);
|
||||
}
|
||||
if (operation === "artifacts") {
|
||||
applyMitigationTabSelection();
|
||||
}
|
||||
if (window.giaWorkspaceState[personId]) {
|
||||
window.giaWorkspaceState[personId].pendingTabKey = "";
|
||||
}
|
||||
})
|
||||
pane.innerHTML = html;
|
||||
pane.dataset.loaded = "1";
|
||||
executeInlineScripts(pane);
|
||||
pane.classList.remove("ai-animate-in");
|
||||
void pane.offsetWidth;
|
||||
pane.classList.add("ai-animate-in");
|
||||
if (cacheAllowed) {
|
||||
window.giaWorkspaceCache[key] = {
|
||||
html: html,
|
||||
ts: Date.now(),
|
||||
};
|
||||
persistCache();
|
||||
setCachedIndicator(true, window.giaWorkspaceCache[key].ts);
|
||||
} else {
|
||||
setCachedIndicator(false, null);
|
||||
}
|
||||
if (window.htmx) {
|
||||
window.htmx.process(pane);
|
||||
}
|
||||
if (operation === "draft_reply" && typeof window.giaWorkspaceUseDraft === "function") {
|
||||
window.giaWorkspaceUseDraft(personId, operation, 0);
|
||||
}
|
||||
if (operation === "artifacts") {
|
||||
applyMitigationTabSelection();
|
||||
}
|
||||
if (window.giaWorkspaceState[personId]) {
|
||||
window.giaWorkspaceState[personId].pendingTabKey = "";
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
pane.innerHTML = '<div class="notification is-danger is-light ai-animate-in">Failed to load AI response.</div>';
|
||||
});
|
||||
pane.innerHTML = '<div class="notification is-danger is-light ai-animate-in">Failed to load AI response.</div>';
|
||||
});
|
||||
};
|
||||
|
||||
window.giaWorkspaceRefresh = function(pid) {
|
||||
@@ -663,8 +663,8 @@
|
||||
const state = window.giaWorkspaceState[personId] || {};
|
||||
const currentTab = state.currentTab || (
|
||||
state.current === "artifacts"
|
||||
? (state.currentMitigationTab || "plan_board")
|
||||
: (state.current || "plan_board")
|
||||
? (state.currentMitigationTab || "plan_board")
|
||||
: (state.current || "plan_board")
|
||||
);
|
||||
window.giaWorkspaceOpenTab(personId, currentTab, true);
|
||||
};
|
||||
@@ -754,15 +754,15 @@
|
||||
})
|
||||
.then(function(resp) { return resp.text(); })
|
||||
.then(function(html) {
|
||||
if (statusHost) {
|
||||
statusHost.innerHTML = html;
|
||||
}
|
||||
})
|
||||
if (statusHost) {
|
||||
statusHost.innerHTML = html;
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
if (statusHost) {
|
||||
statusHost.innerHTML = '<div class="notification is-danger is-light" style="padding: 0.45rem 0.6rem;">Failed to queue draft.</div>';
|
||||
}
|
||||
});
|
||||
if (statusHost) {
|
||||
statusHost.innerHTML = '<div class="notification is-danger is-light" style="padding: 0.45rem 0.6rem;">Failed to queue draft.</div>';
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function getSelectedTargetId() {
|
||||
@@ -841,92 +841,92 @@
|
||||
};
|
||||
|
||||
defineGlobal("giaMitigationShowTab", function(pid, tabName) {
|
||||
const names = ["plan_board", "corrections", "engage", "fundamentals", "ask_ai"];
|
||||
names.forEach(function(name) {
|
||||
const pane = document.getElementById("mitigation-tab-" + pid + "-" + name);
|
||||
const tab = document.getElementById("mitigation-tab-btn-" + pid + "-" + name);
|
||||
if (!pane) {
|
||||
return;
|
||||
}
|
||||
const active = (name === tabName);
|
||||
pane.style.display = active ? "block" : "none";
|
||||
if (tab) {
|
||||
tab.classList.toggle("is-active", active);
|
||||
}
|
||||
});
|
||||
const shell = document.getElementById("mitigation-shell-" + pid);
|
||||
if (!shell) {
|
||||
const names = ["plan_board", "corrections", "engage", "fundamentals", "ask_ai"];
|
||||
names.forEach(function(name) {
|
||||
const pane = document.getElementById("mitigation-tab-" + pid + "-" + name);
|
||||
const tab = document.getElementById("mitigation-tab-btn-" + pid + "-" + name);
|
||||
if (!pane) {
|
||||
return;
|
||||
}
|
||||
shell.querySelectorAll('input[name="active_tab"]').forEach(function(input) {
|
||||
input.value = tabName;
|
||||
});
|
||||
const active = (name === tabName);
|
||||
pane.style.display = active ? "block" : "none";
|
||||
if (tab) {
|
||||
tab.classList.toggle("is-active", active);
|
||||
}
|
||||
});
|
||||
const shell = document.getElementById("mitigation-shell-" + pid);
|
||||
if (!shell) {
|
||||
return;
|
||||
}
|
||||
shell.querySelectorAll('input[name="active_tab"]').forEach(function(input) {
|
||||
input.value = tabName;
|
||||
});
|
||||
});
|
||||
|
||||
defineGlobal("giaMitigationToggleEdit", function(button) {
|
||||
const form = button ? button.closest("form") : null;
|
||||
if (!form) {
|
||||
return;
|
||||
const form = button ? button.closest("form") : null;
|
||||
if (!form) {
|
||||
return;
|
||||
}
|
||||
const card = form.closest(".mitigation-artifact-card");
|
||||
const editing = button.dataset.editState === "edit";
|
||||
const fields = form.querySelectorAll('[data-editable="1"]');
|
||||
const toggles = form.querySelectorAll('[data-editable-toggle="1"]');
|
||||
if (!editing) {
|
||||
fields.forEach(function(field) {
|
||||
field.removeAttribute("readonly");
|
||||
});
|
||||
toggles.forEach(function(field) {
|
||||
field.removeAttribute("disabled");
|
||||
});
|
||||
if (card) {
|
||||
card.classList.add("is-editing");
|
||||
}
|
||||
const card = form.closest(".mitigation-artifact-card");
|
||||
const editing = button.dataset.editState === "edit";
|
||||
const fields = form.querySelectorAll('[data-editable="1"]');
|
||||
const toggles = form.querySelectorAll('[data-editable-toggle="1"]');
|
||||
if (!editing) {
|
||||
fields.forEach(function(field) {
|
||||
field.removeAttribute("readonly");
|
||||
});
|
||||
toggles.forEach(function(field) {
|
||||
field.removeAttribute("disabled");
|
||||
});
|
||||
if (card) {
|
||||
card.classList.add("is-editing");
|
||||
}
|
||||
button.dataset.editState = "edit";
|
||||
button.classList.remove("is-light");
|
||||
button.title = "Save";
|
||||
button.innerHTML = '<span class="icon is-small"><i class="fa-solid fa-check"></i></span>';
|
||||
} else {
|
||||
form.requestSubmit();
|
||||
}
|
||||
});
|
||||
button.dataset.editState = "edit";
|
||||
button.classList.remove("is-light");
|
||||
button.title = "Save";
|
||||
button.innerHTML = '<span class="icon is-small"><i class="fa-solid fa-check"></i></span>';
|
||||
} else {
|
||||
form.requestSubmit();
|
||||
}
|
||||
});
|
||||
|
||||
defineGlobal("giaEngageSetAction", function(pid, action) {
|
||||
const actionInput = document.getElementById("engage-action-input-" + pid);
|
||||
if (actionInput) {
|
||||
actionInput.value = action;
|
||||
}
|
||||
});
|
||||
const actionInput = document.getElementById("engage-action-input-" + pid);
|
||||
if (actionInput) {
|
||||
actionInput.value = action;
|
||||
}
|
||||
});
|
||||
|
||||
defineGlobal("giaEngageAutoPreview", function(pid) {
|
||||
const form = document.getElementById("engage-form-" + pid);
|
||||
if (!form) {
|
||||
return;
|
||||
}
|
||||
window.giaEngageSetAction(pid, "preview");
|
||||
form.requestSubmit();
|
||||
});
|
||||
const form = document.getElementById("engage-form-" + pid);
|
||||
if (!form) {
|
||||
return;
|
||||
}
|
||||
window.giaEngageSetAction(pid, "preview");
|
||||
form.requestSubmit();
|
||||
});
|
||||
|
||||
defineGlobal("giaEngageSelect", function(pid, kind, value, node) {
|
||||
let inputId = "";
|
||||
if (kind === "share") {
|
||||
inputId = "engage-share-input-" + pid;
|
||||
} else if (kind === "framing") {
|
||||
inputId = "engage-framing-input-" + pid;
|
||||
}
|
||||
const input = inputId ? document.getElementById(inputId) : null;
|
||||
if (input) {
|
||||
input.value = value;
|
||||
}
|
||||
const li = node && node.closest ? node.closest("li") : null;
|
||||
if (li && li.parentElement) {
|
||||
Array.from(li.parentElement.children).forEach(function(child) {
|
||||
child.classList.remove("is-active");
|
||||
});
|
||||
li.classList.add("is-active");
|
||||
}
|
||||
window.giaEngageAutoPreview(pid);
|
||||
});
|
||||
let inputId = "";
|
||||
if (kind === "share") {
|
||||
inputId = "engage-share-input-" + pid;
|
||||
} else if (kind === "framing") {
|
||||
inputId = "engage-framing-input-" + pid;
|
||||
}
|
||||
const input = inputId ? document.getElementById(inputId) : null;
|
||||
if (input) {
|
||||
input.value = value;
|
||||
}
|
||||
const li = node && node.closest ? node.closest("li") : null;
|
||||
if (li && li.parentElement) {
|
||||
Array.from(li.parentElement.children).forEach(function(child) {
|
||||
child.classList.remove("is-active");
|
||||
});
|
||||
li.classList.add("is-active");
|
||||
}
|
||||
window.giaEngageAutoPreview(pid);
|
||||
});
|
||||
|
||||
window.giaWorkspaceOpenTab(personId, "plan_board", false);
|
||||
syncTargetInputs();
|
||||
|
||||
@@ -2323,8 +2323,8 @@
|
||||
glanceState && glanceState.gap ? glanceState.gap.lag_ms : 0
|
||||
);
|
||||
const baselineMs = baselineFromGapMs > 0
|
||||
? baselineFromGapMs
|
||||
: toInt(snapshot.counterpartBaselineMs);
|
||||
? baselineFromGapMs
|
||||
: toInt(snapshot.counterpartBaselineMs);
|
||||
if (!baselineMs) {
|
||||
replyTimingState = {
|
||||
sinceLabel: sinceLabel,
|
||||
@@ -2758,13 +2758,13 @@
|
||||
const safe = Array.isArray(items) ? items.slice(0, 3) : [];
|
||||
const ordered = safe
|
||||
.filter(function (item) {
|
||||
return /^delay$/i.test(String(item && item.label ? item.label : ""));
|
||||
})
|
||||
.concat(
|
||||
safe.filter(function (item) {
|
||||
return !/^delay$/i.test(String(item && item.label ? item.label : ""));
|
||||
return /^delay$/i.test(String(item && item.label ? item.label : ""));
|
||||
})
|
||||
);
|
||||
.concat(
|
||||
safe.filter(function (item) {
|
||||
return !/^delay$/i.test(String(item && item.label ? item.label : ""));
|
||||
})
|
||||
);
|
||||
glanceNode.innerHTML = "";
|
||||
ordered.forEach(function (item) {
|
||||
const url = String(item.url || "").trim();
|
||||
@@ -3326,11 +3326,11 @@
|
||||
bubble.appendChild(blockGap);
|
||||
}
|
||||
const imageCandidatesFromPayload = Array.isArray(msg.image_urls) && msg.image_urls.length
|
||||
? msg.image_urls
|
||||
: (msg.image_url ? [msg.image_url] : []);
|
||||
? msg.image_urls
|
||||
: (msg.image_url ? [msg.image_url] : []);
|
||||
const imageCandidates = imageCandidatesFromPayload.length
|
||||
? imageCandidatesFromPayload
|
||||
: extractUrlCandidates(msg.text || msg.display_text || "");
|
||||
? imageCandidatesFromPayload
|
||||
: extractUrlCandidates(msg.text || msg.display_text || "");
|
||||
appendImageCandidates(bubble, imageCandidates);
|
||||
|
||||
if (!msg.hide_text) {
|
||||
@@ -3376,8 +3376,8 @@
|
||||
const deletedFlag = document.createElement("span");
|
||||
deletedFlag.className = "compose-msg-flag is-deleted";
|
||||
deletedFlag.title = "Deleted"
|
||||
+ (msg.deleted_display ? (" at " + String(msg.deleted_display)) : "")
|
||||
+ (msg.deleted_actor ? (" by " + String(msg.deleted_actor)) : "");
|
||||
+ (msg.deleted_display ? (" at " + String(msg.deleted_display)) : "")
|
||||
+ (msg.deleted_actor ? (" by " + String(msg.deleted_actor)) : "");
|
||||
deletedFlag.textContent = "deleted";
|
||||
meta.appendChild(deletedFlag);
|
||||
}
|
||||
@@ -5184,7 +5184,7 @@
|
||||
} catch (err) {
|
||||
setCardLoading(card, false);
|
||||
card.querySelector(".compose-ai-content").textContent =
|
||||
"Failed to load quick insights.";
|
||||
"Failed to load quick insights.";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -5203,8 +5203,8 @@
|
||||
const customText = card.querySelector(".engage-custom-text");
|
||||
const selectedSource = (
|
||||
preferredSource !== undefined
|
||||
? preferredSource
|
||||
: (sourceSelect ? sourceSelect.value : "")
|
||||
? preferredSource
|
||||
: (sourceSelect ? sourceSelect.value : "")
|
||||
);
|
||||
const customValue = customText ? String(customText.value || "").trim() : "";
|
||||
const showCustom = selectedSource === "custom";
|
||||
@@ -5382,8 +5382,8 @@
|
||||
const selectedPerson = selected.dataset.person || thread.dataset.person || "";
|
||||
const selectedPageUrl = (
|
||||
renderMode === "page"
|
||||
? selected.dataset.pageUrl
|
||||
: selected.dataset.widgetUrl
|
||||
? selected.dataset.pageUrl
|
||||
: selected.dataset.widgetUrl
|
||||
) || "";
|
||||
switchThreadContext(
|
||||
selectedService,
|
||||
@@ -5412,8 +5412,8 @@
|
||||
const selectedPerson = selected.dataset.person || "";
|
||||
let selectedPageUrl = (
|
||||
renderMode === "page"
|
||||
? selected.dataset[servicePageUrlKey]
|
||||
: selected.dataset[serviceWidgetUrlKey]
|
||||
? selected.dataset[servicePageUrlKey]
|
||||
: selected.dataset[serviceWidgetUrlKey]
|
||||
) || "";
|
||||
if (!selectedIdentifier) {
|
||||
selectedService = selected.dataset.service || selectedService;
|
||||
@@ -5422,8 +5422,8 @@
|
||||
if (!selectedPageUrl) {
|
||||
selectedPageUrl = (
|
||||
renderMode === "page"
|
||||
? selected.dataset.pageUrl
|
||||
: selected.dataset.widgetUrl
|
||||
? selected.dataset.pageUrl
|
||||
: selected.dataset.widgetUrl
|
||||
) || "";
|
||||
}
|
||||
switchThreadContext(
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
<div class="column is-12-mobile is-12-tablet">
|
||||
<div
|
||||
style="
|
||||
margin-bottom: 0.75rem;
|
||||
padding: 0.5rem 0.25rem;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||
">
|
||||
margin-bottom: 0.75rem;
|
||||
padding: 0.5rem 0.25rem;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||
">
|
||||
<p class="is-size-7 has-text-weight-semibold">Manual Workspace</p>
|
||||
<h3 class="title is-6" style="margin-bottom: 0.5rem;">Choose A Contact</h3>
|
||||
<p class="is-size-7">
|
||||
@@ -17,10 +17,10 @@
|
||||
<form
|
||||
id="compose-workspace-window-form"
|
||||
style="
|
||||
margin-bottom: 0.75rem;
|
||||
padding: 0.5rem 0.25rem;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||
">
|
||||
margin-bottom: 0.75rem;
|
||||
padding: 0.5rem 0.25rem;
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
|
||||
">
|
||||
<label class="label is-small" for="compose-workspace-limit">Window</label>
|
||||
<div class="select is-fullwidth is-small">
|
||||
<select id="compose-workspace-limit" name="limit">
|
||||
@@ -43,12 +43,12 @@
|
||||
<button
|
||||
class="button is-fullwidth"
|
||||
style="
|
||||
border-radius: 8px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
"
|
||||
border-radius: 8px;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
"
|
||||
hx-get="{{ row.compose_widget_url }}"
|
||||
hx-include="#compose-workspace-window-form"
|
||||
hx-target="#widgets-here"
|
||||
@@ -56,42 +56,42 @@
|
||||
<span
|
||||
class="tags has-addons"
|
||||
style="
|
||||
display: inline-flex;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
">
|
||||
display: inline-flex;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
">
|
||||
<span
|
||||
class="tag is-white"
|
||||
style="
|
||||
flex: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
padding-left: 0.7rem;
|
||||
padding-right: 0.7rem;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
min-width: 0;
|
||||
">
|
||||
flex: 1;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
padding-left: 0.7rem;
|
||||
padding-right: 0.7rem;
|
||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
||||
min-width: 0;
|
||||
">
|
||||
<span
|
||||
style="
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 0.45rem;
|
||||
min-width: 0;
|
||||
">
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 0.45rem;
|
||||
min-width: 0;
|
||||
">
|
||||
<strong>{{ row.person_name }}</strong>
|
||||
<small class="has-text-grey">{{ row.service|title }}</small>
|
||||
</span>
|
||||
<small
|
||||
class="has-text-grey"
|
||||
style="
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-all;
|
||||
text-align: right;
|
||||
">
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
word-break: break-all;
|
||||
text-align: right;
|
||||
">
|
||||
{{ row.identifier }}
|
||||
</small>
|
||||
</span>
|
||||
|
||||
@@ -153,14 +153,14 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content is-size-7" style="margin-top: 0.2rem;">
|
||||
<ul>
|
||||
<li><strong>Min/Max Sent.</strong>: sentiment bounds for people/contact results (-1 to 1).</li>
|
||||
<li><strong>Annotate snippets</strong>: shows contextual snippets around query hits.</li>
|
||||
<li><strong>Deduplicate</strong>: removes near-identical repeated rows.</li>
|
||||
<li><strong>Reverse output</strong>: reverses final result order after sorting.</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="content is-size-7" style="margin-top: 0.2rem;">
|
||||
<ul>
|
||||
<li><strong>Min/Max Sent.</strong>: sentiment bounds for people/contact results (-1 to 1).</li>
|
||||
<li><strong>Annotate snippets</strong>: shows contextual snippets around query hits.</li>
|
||||
<li><strong>Deduplicate</strong>: removes near-identical repeated rows.</li>
|
||||
<li><strong>Reverse output</strong>: reverses final result order after sorting.</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</form>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
<div class="is-flex is-justify-content-space-between is-align-items-center" style="margin-bottom: 0.75rem; gap: 0.5rem; flex-wrap: wrap;">
|
||||
<div>
|
||||
<h3 class="title is-6" style="margin-bottom: 0.15rem;">Outgoing Queue</h3>
|
||||
<h3 class="title is-6" style="margin-bottom: 0.15rem;">Approvals Queue</h3>
|
||||
<p class="is-size-7">Review queued drafts and approve or reject each message.</p>
|
||||
</div>
|
||||
<span class="tag is-dark is-medium">{{ object_list|length }} pending</span>
|
||||
@@ -57,7 +57,7 @@
|
||||
</div>
|
||||
|
||||
<div class="is-flex is-justify-content-space-between is-align-items-center" style="gap: 0.5rem; flex-wrap: wrap;">
|
||||
<small class="has-text-grey">Queue ID: {{ item.id }}</small>
|
||||
<small class="has-text-grey">Approval ID: {{ item.id }}</small>
|
||||
<div class="buttons are-small" style="margin: 0;">
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
@@ -92,7 +92,7 @@
|
||||
</div>
|
||||
{% else %}
|
||||
<article class="box" style="padding: 0.8rem; border: 1px dashed rgba(0, 0, 0, 0.25); box-shadow: none;">
|
||||
<p class="is-size-7 has-text-grey">Queue is empty.</p>
|
||||
<p class="is-size-7 has-text-grey">Approvals Queue is empty.</p>
|
||||
</article>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
<div class="tabs is-boxed is-small mb-4 security-page-tabs">
|
||||
<ul>
|
||||
{% for tab in settings_nav.tabs %}
|
||||
<li class="{% if tab.active %}is-active{% endif %}">
|
||||
<a href="{{ tab.href }}">{{ tab.label }}</a>
|
||||
</li>
|
||||
<li class="{% if tab.active %}is-active{% endif %}">
|
||||
<a href="{{ tab.href }}">{{ tab.label }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1,154 +1,154 @@
|
||||
{% include 'mixins/partials/notify.html' %}
|
||||
<table
|
||||
class="table is-fullwidth is-hoverable"
|
||||
hx-target="#{{ context_object_name }}-table"
|
||||
id="{{ context_object_name }}-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-trigger="{{ context_object_name_singular }}Event from:body"
|
||||
hx-get="{{ list_url }}">
|
||||
<thead>
|
||||
<th>number</th>
|
||||
<th>uuid</th>
|
||||
<th>account</th>
|
||||
<th>name</th>
|
||||
<th>person</th>
|
||||
<th>availability</th>
|
||||
<th>actions</th>
|
||||
</thead>
|
||||
{% for item in object_list %}
|
||||
<tr>
|
||||
<td>{% if item.chat %}{{ item.chat.source_number }}{% endif %}</td>
|
||||
<td>
|
||||
{% if item.chat %}
|
||||
<a
|
||||
class="has-text-grey button nowrap-child"
|
||||
onclick="window.prompt('Copy to clipboard: Ctrl+C, Enter', '{{ item.chat.source_uuid }}');">
|
||||
<span class="icon" data-tooltip="Copy to clipboard">
|
||||
<i class="fa-solid fa-copy" aria-hidden="true"></i>
|
||||
</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{% if item.chat %}{{ item.chat.account }}{% endif %}</td>
|
||||
<td>
|
||||
{% if item.is_group %}
|
||||
<span class="tag is-info is-light is-small mr-1"><i class="fa-solid fa-users"></i></span>
|
||||
{% endif %}
|
||||
{% if item.chat %}{{ item.chat.source_name }}{% else %}{{ item.name }}{% endif %}
|
||||
</td>
|
||||
<td>{{ item.person_name|default:"-" }}</td>
|
||||
<td>
|
||||
{% if item.availability_label %}
|
||||
<span class="tag is-light">{{ item.availability_label }}</span>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="buttons">
|
||||
{% if not item.is_group %}
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-delete="{# url 'account_delete' type=type pk=item.id #}"
|
||||
hx-trigger="click"
|
||||
hx-target="#modals-here"
|
||||
hx-swap="innerHTML"
|
||||
hx-confirm="Are you sure you wish to unlink {{ item.chat }}?"
|
||||
class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</span>
|
||||
<table
|
||||
class="table is-fullwidth is-hoverable"
|
||||
hx-target="#{{ context_object_name }}-table"
|
||||
id="{{ context_object_name }}-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-trigger="{{ context_object_name_singular }}Event from:body"
|
||||
hx-get="{{ list_url }}">
|
||||
<thead>
|
||||
<th>number</th>
|
||||
<th>uuid</th>
|
||||
<th>account</th>
|
||||
<th>name</th>
|
||||
<th>person</th>
|
||||
<th>availability</th>
|
||||
<th>actions</th>
|
||||
</thead>
|
||||
{% for item in object_list %}
|
||||
<tr>
|
||||
<td>{% if item.chat %}{{ item.chat.source_number }}{% endif %}</td>
|
||||
<td>
|
||||
{% if item.chat %}
|
||||
<a
|
||||
class="has-text-grey button nowrap-child"
|
||||
onclick="window.prompt('Copy to clipboard: Ctrl+C, Enter', '{{ item.chat.source_uuid }}');">
|
||||
<span class="icon" data-tooltip="Copy to clipboard">
|
||||
<i class="fa-solid fa-copy" aria-hidden="true"></i>
|
||||
</span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{% if item.chat %}{{ item.chat.account }}{% endif %}</td>
|
||||
<td>
|
||||
{% if item.is_group %}
|
||||
<span class="tag is-info is-light is-small mr-1"><i class="fa-solid fa-users"></i></span>
|
||||
{% endif %}
|
||||
{% if item.chat %}{{ item.chat.source_name }}{% else %}{{ item.name }}{% endif %}
|
||||
</td>
|
||||
<td>{{ item.person_name|default:"-" }}</td>
|
||||
<td>
|
||||
{% if item.availability_label %}
|
||||
<span class="tag is-light">{{ item.availability_label }}</span>
|
||||
{% else %}
|
||||
-
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
<div class="buttons">
|
||||
{% if not item.is_group %}
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-delete="{# url 'account_delete' type=type pk=item.id #}"
|
||||
hx-trigger="click"
|
||||
hx-target="#modals-here"
|
||||
hx-swap="innerHTML"
|
||||
hx-confirm="Are you sure you wish to unlink {{ item.chat }}?"
|
||||
class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-xmark"></i>
|
||||
</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if type == 'page' %}
|
||||
{% if item.can_compose %}
|
||||
<a href="{{ item.compose_page_url }}"><button
|
||||
class="button"
|
||||
title="Manual text mode">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="{{ item.manual_icon_class }}"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
{% else %}
|
||||
<button class="button" disabled title="No identifier available for manual send">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="{{ item.manual_icon_class }}"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if not item.is_group %}
|
||||
<a href="{{ item.match_url }}"><button
|
||||
class="button"
|
||||
title="Match identifier to person">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-link"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{{ item.ai_url }}"><button
|
||||
</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if type == 'page' %}
|
||||
{% if item.can_compose %}
|
||||
<a href="{{ item.compose_page_url }}"><button
|
||||
class="button"
|
||||
title="Open AI workspace">
|
||||
title="Manual text mode">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-brain-circuit"></i>
|
||||
<i class="{{ item.manual_icon_class }}"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
{% else %}
|
||||
{% if item.can_compose %}
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-get="{{ item.compose_widget_url }}"
|
||||
hx-trigger="click"
|
||||
hx-target="#widgets-here"
|
||||
hx-swap="afterend"
|
||||
class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="{{ item.manual_icon_class }}"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
{% else %}
|
||||
<button class="button" disabled title="No identifier available for manual send">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="{{ item.manual_icon_class }}"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if not item.is_group %}
|
||||
<a href="{{ item.match_url }}"><button class="button" title="Match identifier to person">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-link"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button></a>
|
||||
{% endif %}
|
||||
<a href="{{ item.ai_url }}"><button class="button">
|
||||
<button class="button" disabled title="No identifier available for manual send">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-brain-circuit"></i>
|
||||
<i class="{{ item.manual_icon_class }}"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if not item.is_group %}
|
||||
<a href="{{ item.match_url }}"><button
|
||||
class="button"
|
||||
title="Match identifier to person">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-link"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{{ item.ai_url }}"><button
|
||||
class="button"
|
||||
title="Open AI workspace">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-brain-circuit"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</a>
|
||||
{% else %}
|
||||
{% if item.can_compose %}
|
||||
<button
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token }}"}'
|
||||
hx-get="{{ item.compose_widget_url }}"
|
||||
hx-trigger="click"
|
||||
hx-target="#widgets-here"
|
||||
hx-swap="afterend"
|
||||
class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="{{ item.manual_icon_class }}"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
{% else %}
|
||||
<button class="button" disabled title="No identifier available for manual send">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="{{ item.manual_icon_class }}"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
{% endif %}
|
||||
{% if not item.is_group %}
|
||||
<a href="{{ item.match_url }}"><button class="button" title="Match identifier to person">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-link"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
<a href="{{ item.ai_url }}"><button class="button">
|
||||
<span class="icon-text">
|
||||
<span class="icon">
|
||||
<i class="fa-solid fa-brain-circuit"></i>
|
||||
</span>
|
||||
</span>
|
||||
</button></a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</table>
|
||||
</table>
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
src="data:image/png;base64, {{ object.image_b64 }}"
|
||||
alt="WhatsApp QR code"
|
||||
style="
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
height: auto;
|
||||
margin: 0 auto;
|
||||
" />
|
||||
display: block;
|
||||
width: 100%;
|
||||
max-width: 420px;
|
||||
height: auto;
|
||||
margin: 0 auto;
|
||||
" />
|
||||
{% if object.warning %}
|
||||
<p class="is-size-7" style="margin-top: 0.6rem;">{{ object.warning }}</p>
|
||||
{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user