Refactor to reduce lines
This commit is contained in:
@@ -27,74 +27,63 @@
|
|||||||
<script src="{% static 'js/gridstack-all.js' %}"></script>
|
<script src="{% static 'js/gridstack-all.js' %}"></script>
|
||||||
<script defer src="{% static 'js/magnet.min.js' %}"></script>
|
<script defer src="{% static 'js/magnet.min.js' %}"></script>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener("restore-scroll", function(event) {
|
document.addEventListener("restore-scroll", function () {
|
||||||
var scrollpos = localStorage.getItem('scrollpos');
|
var scrollpos = localStorage.getItem("scrollpos");
|
||||||
if (scrollpos) {
|
if (scrollpos) {
|
||||||
window.scrollTo(0, scrollpos)
|
window.scrollTo(0, scrollpos);
|
||||||
};
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener("htmx:beforeSwap", function(event) {
|
document.addEventListener("htmx:beforeSwap", function () {
|
||||||
localStorage.setItem('scrollpos', window.scrollY);
|
localStorage.setItem("scrollpos", window.scrollY);
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
|
|
||||||
// Get all "navbar-burger" elements
|
|
||||||
const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0);
|
|
||||||
|
|
||||||
// Add a click event on each of them
|
|
||||||
$navbarBurgers.forEach( el => {
|
|
||||||
el.addEventListener('click', () => {
|
|
||||||
|
|
||||||
// Get the target from the "data-target" attribute
|
|
||||||
const target = el.dataset.target;
|
|
||||||
const $target = document.getElementById(target);
|
|
||||||
|
|
||||||
// Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu"
|
|
||||||
el.classList.toggle('is-active');
|
|
||||||
$target.classList.toggle('is-active');
|
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
|
document.querySelectorAll(".navbar-burger").forEach(function (el) {
|
||||||
|
el.addEventListener("click", function () {
|
||||||
|
var target = document.getElementById(el.dataset.target);
|
||||||
|
el.classList.toggle("is-active");
|
||||||
|
if (target) {
|
||||||
|
target.classList.toggle("is-active");
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
const composeLink = document.getElementById('nav-compose-link');
|
var composeLink = document.getElementById("nav-compose-link");
|
||||||
const composeDropdown = document.getElementById('nav-compose-contacts');
|
var composeDropdown = document.getElementById("nav-compose-contacts");
|
||||||
let composePreviewLoaded = false;
|
var composePreviewLoaded = false;
|
||||||
let composePreviewLoading = false;
|
var composePreviewLoading = false;
|
||||||
if (composeLink && composeDropdown) {
|
if (!composeLink || !composeDropdown) {
|
||||||
composeLink.addEventListener('mouseenter', () => {
|
return;
|
||||||
const previewUrl = composeLink.dataset.previewUrl || '';
|
}
|
||||||
if (!previewUrl || composePreviewLoaded || composePreviewLoading) {
|
composeLink.addEventListener("mouseenter", function () {
|
||||||
return;
|
var previewUrl = composeLink.dataset.previewUrl || "";
|
||||||
}
|
if (!previewUrl || composePreviewLoaded || composePreviewLoading) {
|
||||||
composePreviewLoading = true;
|
return;
|
||||||
fetch(previewUrl, {
|
}
|
||||||
method: 'GET',
|
composePreviewLoading = true;
|
||||||
credentials: 'same-origin',
|
fetch(previewUrl, {
|
||||||
headers: { 'HX-Request': 'true' },
|
method: "GET",
|
||||||
})
|
credentials: "same-origin",
|
||||||
.then((response) => {
|
headers: { "HX-Request": "true" },
|
||||||
|
})
|
||||||
|
.then(function (response) {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error('Failed contacts preview fetch.');
|
throw new Error("Failed contacts preview fetch.");
|
||||||
}
|
}
|
||||||
return response.text();
|
return response.text();
|
||||||
})
|
})
|
||||||
.then((html) => {
|
.then(function (html) {
|
||||||
composeDropdown.innerHTML = html;
|
composeDropdown.innerHTML = html;
|
||||||
composePreviewLoaded = true;
|
composePreviewLoaded = true;
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(function () {
|
||||||
composePreviewLoaded = false;
|
composePreviewLoaded = false;
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(function () {
|
||||||
composePreviewLoading = false;
|
composePreviewLoading = false;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
@@ -112,9 +101,7 @@
|
|||||||
opacity:0;
|
opacity:0;
|
||||||
transition: opacity 500ms ease-in;
|
transition: opacity 500ms ease-in;
|
||||||
}
|
}
|
||||||
.htmx-request .htmx-indicator{
|
.htmx-request .htmx-indicator,
|
||||||
opacity:1
|
|
||||||
}
|
|
||||||
.htmx-request.htmx-indicator{
|
.htmx-request.htmx-indicator{
|
||||||
opacity:1
|
opacity:1
|
||||||
}
|
}
|
||||||
@@ -142,15 +129,11 @@
|
|||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
tr:hover {
|
|
||||||
cursor:pointer;
|
|
||||||
background-color:rgba(221, 224, 255, 0.3) !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
a.panel-block {
|
a.panel-block {
|
||||||
transition: all 0.2s ease-in-out;
|
transition: all 0.2s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tr:hover,
|
||||||
a.panel-block:hover {
|
a.panel-block:hover {
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
background-color:rgba(221, 224, 255, 0.3) !important;
|
background-color:rgba(221, 224, 255, 0.3) !important;
|
||||||
@@ -180,11 +163,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.panel, .box, .modal {
|
.panel, .box, .modal {
|
||||||
/* background-color:rgba(250, 250, 250, 0.5) !important; */
|
|
||||||
background-color: var(--modal-color) !important;
|
background-color: var(--modal-color) !important;
|
||||||
}
|
}
|
||||||
.modal, .modal.box{
|
.modal, .modal.box{
|
||||||
/* background-color:rgba(210, 210, 210, 0.9) !important; */
|
|
||||||
background-color: var(--background-color) !important;
|
background-color: var(--background-color) !important;
|
||||||
}
|
}
|
||||||
.modal-background{
|
.modal-background{
|
||||||
@@ -218,7 +199,8 @@
|
|||||||
background-color:rgba(0, 0, 0, 0.03) !important;
|
background-color:rgba(0, 0, 0, 0.03) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.grid-stack-item-content {
|
.grid-stack-item-content,
|
||||||
|
.floating-window {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
flex-direction: column !important;
|
flex-direction: column !important;
|
||||||
overflow-x: hidden !important;
|
overflow-x: hidden !important;
|
||||||
@@ -239,11 +221,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.floating-window {
|
.floating-window {
|
||||||
/* background-color:rgba(210, 210, 210, 0.6) !important; */
|
|
||||||
display: flex !important;
|
|
||||||
flex-direction: column !important;
|
|
||||||
overflow-x: hidden !important;
|
|
||||||
overflow-y: hidden !important;
|
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
z-index: 9000;
|
z-index: 9000;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -257,8 +234,7 @@
|
|||||||
|
|
||||||
.float-right {
|
.float-right {
|
||||||
float: right;
|
float: right;
|
||||||
padding-right: 5px;
|
padding: 0 5px;
|
||||||
padding-left: 5px;
|
|
||||||
}
|
}
|
||||||
.grid-stack-item:hover .ui-resizable-handle {
|
.grid-stack-item:hover .ui-resizable-handle {
|
||||||
display: block !important;
|
display: block !important;
|
||||||
|
|||||||
@@ -819,135 +819,104 @@
|
|||||||
(function() {
|
(function() {
|
||||||
const personId = "{{ person.id }}";
|
const personId = "{{ person.id }}";
|
||||||
const canSend = "{{ send_state.can_send|yesno:'1,0' }}" === "1";
|
const canSend = "{{ send_state.can_send|yesno:'1,0' }}" === "1";
|
||||||
function resizeEditableTextareas(root) {
|
const TAB_NAMES = ["plan_board", "corrections", "engage", "fundamentals", "auto", "ask_ai"];
|
||||||
|
const defineGlobal = function(name, handler) {
|
||||||
|
if (typeof window[name] !== "function") {
|
||||||
|
window[name] = handler;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const resizeEditableTextareas = function(root) {
|
||||||
if (!root) return;
|
if (!root) return;
|
||||||
root.querySelectorAll('textarea[data-editable="1"]').forEach(function(area) {
|
root.querySelectorAll('textarea[data-editable="1"]').forEach(function(area) {
|
||||||
area.style.height = "auto";
|
area.style.height = "auto";
|
||||||
area.style.height = Math.max(area.scrollHeight, 72) + "px";
|
area.style.height = Math.max(area.scrollHeight, 72) + "px";
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
window.giaEngageSyncSendOverride = function(pid) {
|
|
||||||
if (pid !== personId) return;
|
|
||||||
const forceInput = document.getElementById("engage-force-send-" + pid);
|
|
||||||
const sendBtn = document.getElementById("engage-send-btn-" + pid);
|
|
||||||
const force =
|
|
||||||
!!(window.giaWorkspaceState
|
|
||||||
&& window.giaWorkspaceState[pid]
|
|
||||||
&& window.giaWorkspaceState[pid].forceSend);
|
|
||||||
if (forceInput) {
|
|
||||||
forceInput.value = force ? "1" : "0";
|
|
||||||
}
|
|
||||||
if (sendBtn) {
|
|
||||||
sendBtn.disabled = !canSend && !force;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function setActiveTabHiddenFields(tabName) {
|
const syncActiveTab = function(tabName) {
|
||||||
const root = document.getElementById("mitigation-shell-" + personId);
|
const root = document.getElementById("mitigation-shell-" + personId);
|
||||||
if (!root) return;
|
if (!root) return;
|
||||||
root.querySelectorAll('input[name="active_tab"]').forEach(function(input) {
|
root.querySelectorAll('input[name="active_tab"]').forEach(function(input) {
|
||||||
input.value = tabName;
|
input.value = tabName;
|
||||||
});
|
});
|
||||||
resizeEditableTextareas(root);
|
resizeEditableTextareas(root);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
window.giaEngageSyncSendOverride = function(pid) {
|
||||||
|
if (pid !== personId) return;
|
||||||
|
const forceInput = document.getElementById("engage-force-send-" + pid);
|
||||||
|
const sendBtn = document.getElementById("engage-send-btn-" + pid);
|
||||||
|
const force = !!(window.giaWorkspaceState && window.giaWorkspaceState[pid] && window.giaWorkspaceState[pid].forceSend);
|
||||||
|
if (forceInput) forceInput.value = force ? "1" : "0";
|
||||||
|
if (sendBtn) {
|
||||||
|
sendBtn.disabled = !canSend && !force;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
window.giaMitigationShowTab = function(pid, tabName) {
|
window.giaMitigationShowTab = function(pid, tabName) {
|
||||||
if (pid !== personId) return;
|
if (pid !== personId) return;
|
||||||
["plan_board", "corrections", "engage", "fundamentals", "auto", "ask_ai"].forEach(function(name) {
|
TAB_NAMES.forEach(function(name) {
|
||||||
const pane = document.getElementById("mitigation-tab-" + personId + "-" + name);
|
const pane = document.getElementById("mitigation-tab-" + personId + "-" + name);
|
||||||
const tab = document.getElementById("mitigation-tab-btn-" + personId + "-" + name);
|
const tab = document.getElementById("mitigation-tab-btn-" + personId + "-" + name);
|
||||||
if (!pane) return;
|
if (!pane) return;
|
||||||
const active = name === tabName;
|
const active = name === tabName;
|
||||||
pane.style.display = active ? "block" : "none";
|
pane.style.display = active ? "block" : "none";
|
||||||
if (tab) {
|
if (tab) tab.classList.toggle("is-active", active);
|
||||||
tab.classList.toggle("is-active", active);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
setActiveTabHiddenFields(tabName);
|
syncActiveTab(tabName);
|
||||||
};
|
};
|
||||||
|
|
||||||
window.giaMitigationToggleEdit = function(button) {
|
defineGlobal("giaMitigationToggleEdit", function(button) {
|
||||||
const form = button.closest("form");
|
const form = button && button.closest ? button.closest("form") : null;
|
||||||
if (!form) return;
|
if (!form) return;
|
||||||
const card = form.closest(".mitigation-artifact-card");
|
const editing = button.dataset.editState === "edit";
|
||||||
const editing = button.dataset.editState === "edit";
|
if (!editing) {
|
||||||
const fields = form.querySelectorAll('[data-editable="1"]');
|
form.querySelectorAll('[data-editable="1"]').forEach(function(field) { field.removeAttribute("readonly"); });
|
||||||
const toggles = form.querySelectorAll('[data-editable-toggle="1"]');
|
form.querySelectorAll('[data-editable-toggle="1"]').forEach(function(field) { field.removeAttribute("disabled"); });
|
||||||
if (!editing) {
|
const card = form.closest(".mitigation-artifact-card");
|
||||||
fields.forEach(function(field) {
|
if (card) card.classList.add("is-editing");
|
||||||
field.removeAttribute("readonly");
|
button.dataset.editState = "edit";
|
||||||
});
|
button.classList.remove("is-light");
|
||||||
toggles.forEach(function(field) {
|
button.title = "Save";
|
||||||
field.removeAttribute("disabled");
|
button.innerHTML = '<span class="icon is-small"><i class="fa-solid fa-check"></i></span>';
|
||||||
});
|
resizeEditableTextareas(form);
|
||||||
if (card) {
|
return;
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
form.requestSubmit();
|
form.requestSubmit();
|
||||||
}
|
});
|
||||||
};
|
|
||||||
|
|
||||||
window.giaEngageSetAction = function(pid, action) {
|
defineGlobal("giaEngageSetAction", function(pid, action) {
|
||||||
if (pid !== personId) return;
|
const actionInput = document.getElementById("engage-action-input-" + pid);
|
||||||
const actionInput = document.getElementById("engage-action-input-" + pid);
|
if (actionInput) actionInput.value = action;
|
||||||
if (actionInput) {
|
if (action === "send") window.giaEngageSyncSendOverride(pid);
|
||||||
actionInput.value = action;
|
});
|
||||||
}
|
|
||||||
if (action === "send") {
|
|
||||||
window.giaEngageSyncSendOverride(pid);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.giaEngageAutoPreview = function(pid) {
|
defineGlobal("giaEngageAutoPreview", function(pid) {
|
||||||
if (pid !== personId) return;
|
const form = document.getElementById("engage-form-" + pid);
|
||||||
const form = document.getElementById("engage-form-" + pid);
|
if (!form) return;
|
||||||
if (!form) return;
|
window.giaEngageSetAction(pid, "preview");
|
||||||
window.giaEngageSetAction(pid, "preview");
|
form.requestSubmit();
|
||||||
form.requestSubmit();
|
});
|
||||||
};
|
|
||||||
|
|
||||||
window.giaEngageSetTarget = function(pid, targetId) {
|
window.giaEngageSetTarget = function(pid, targetId) {
|
||||||
if (pid !== personId) return;
|
if (pid !== personId) return;
|
||||||
const normalized = String(targetId || "").trim();
|
const normalized = String(targetId || "").trim();
|
||||||
const input = document.getElementById("engage-target-input-" + pid);
|
const input = document.getElementById("engage-target-input-" + pid);
|
||||||
if (input) {
|
if (input) input.value = normalized;
|
||||||
input.value = normalized;
|
|
||||||
}
|
|
||||||
const parentSelect = document.getElementById("ai-target-select-" + pid);
|
const parentSelect = document.getElementById("ai-target-select-" + pid);
|
||||||
if (parentSelect && normalized) {
|
if (parentSelect && normalized) parentSelect.value = normalized;
|
||||||
parentSelect.value = normalized;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
window.giaEngageSelect = function(pid, kind, value, node) {
|
defineGlobal("giaEngageSelect", function(pid, kind, value, node) {
|
||||||
if (pid !== personId) return;
|
const inputId = kind === "share" ? ("engage-share-input-" + pid) : (kind === "framing" ? ("engage-framing-input-" + pid) : "");
|
||||||
let inputId = "";
|
const input = inputId ? document.getElementById(inputId) : null;
|
||||||
if (kind === "share") {
|
if (input) input.value = value;
|
||||||
inputId = "engage-share-input-" + pid;
|
const li = node && node.closest ? node.closest("li") : null;
|
||||||
} else if (kind === "framing") {
|
if (!li || !li.parentElement) return;
|
||||||
inputId = "engage-framing-input-" + pid;
|
Array.from(li.parentElement.children).forEach(function(child) { child.classList.remove("is-active"); });
|
||||||
}
|
li.classList.add("is-active");
|
||||||
const input = inputId ? document.getElementById(inputId) : null;
|
window.giaEngageAutoPreview(pid);
|
||||||
if (input) {
|
});
|
||||||
input.value = value;
|
|
||||||
}
|
|
||||||
const li = node && node.closest ? node.closest("li") : null;
|
|
||||||
if (!li) return;
|
|
||||||
const ul = li.parentElement;
|
|
||||||
if (!ul) return;
|
|
||||||
Array.from(ul.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' }}");
|
window.giaMitigationShowTab(personId, "{{ active_tab|default:'plan_board' }}");
|
||||||
resizeEditableTextareas(document.getElementById("mitigation-shell-" + personId));
|
resizeEditableTextareas(document.getElementById("mitigation-shell-" + personId));
|
||||||
|
|||||||
@@ -833,8 +833,14 @@
|
|||||||
syncTargetInputs();
|
syncTargetInputs();
|
||||||
});
|
});
|
||||||
|
|
||||||
if (typeof window.giaMitigationShowTab !== "function") {
|
const defineGlobal = function(name, handler) {
|
||||||
window.giaMitigationShowTab = function(pid, tabName) {
|
if (typeof window[name] === "function") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window[name] = handler;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineGlobal("giaMitigationShowTab", function(pid, tabName) {
|
||||||
const names = ["plan_board", "corrections", "engage", "fundamentals", "ask_ai"];
|
const names = ["plan_board", "corrections", "engage", "fundamentals", "ask_ai"];
|
||||||
names.forEach(function(name) {
|
names.forEach(function(name) {
|
||||||
const pane = document.getElementById("mitigation-tab-" + pid + "-" + name);
|
const pane = document.getElementById("mitigation-tab-" + pid + "-" + name);
|
||||||
@@ -855,11 +861,9 @@
|
|||||||
shell.querySelectorAll('input[name="active_tab"]').forEach(function(input) {
|
shell.querySelectorAll('input[name="active_tab"]').forEach(function(input) {
|
||||||
input.value = tabName;
|
input.value = tabName;
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof window.giaMitigationToggleEdit !== "function") {
|
defineGlobal("giaMitigationToggleEdit", function(button) {
|
||||||
window.giaMitigationToggleEdit = function(button) {
|
|
||||||
const form = button ? button.closest("form") : null;
|
const form = button ? button.closest("form") : null;
|
||||||
if (!form) {
|
if (!form) {
|
||||||
return;
|
return;
|
||||||
@@ -885,31 +889,25 @@
|
|||||||
} else {
|
} else {
|
||||||
form.requestSubmit();
|
form.requestSubmit();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof window.giaEngageSetAction !== "function") {
|
defineGlobal("giaEngageSetAction", function(pid, action) {
|
||||||
window.giaEngageSetAction = function(pid, action) {
|
|
||||||
const actionInput = document.getElementById("engage-action-input-" + pid);
|
const actionInput = document.getElementById("engage-action-input-" + pid);
|
||||||
if (actionInput) {
|
if (actionInput) {
|
||||||
actionInput.value = action;
|
actionInput.value = action;
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof window.giaEngageAutoPreview !== "function") {
|
defineGlobal("giaEngageAutoPreview", function(pid) {
|
||||||
window.giaEngageAutoPreview = function(pid) {
|
|
||||||
const form = document.getElementById("engage-form-" + pid);
|
const form = document.getElementById("engage-form-" + pid);
|
||||||
if (!form) {
|
if (!form) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
window.giaEngageSetAction(pid, "preview");
|
window.giaEngageSetAction(pid, "preview");
|
||||||
form.requestSubmit();
|
form.requestSubmit();
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof window.giaEngageSelect !== "function") {
|
defineGlobal("giaEngageSelect", function(pid, kind, value, node) {
|
||||||
window.giaEngageSelect = function(pid, kind, value, node) {
|
|
||||||
let inputId = "";
|
let inputId = "";
|
||||||
if (kind === "share") {
|
if (kind === "share") {
|
||||||
inputId = "engage-share-input-" + pid;
|
inputId = "engage-share-input-" + pid;
|
||||||
@@ -928,8 +926,7 @@
|
|||||||
li.classList.add("is-active");
|
li.classList.add("is-active");
|
||||||
}
|
}
|
||||||
window.giaEngageAutoPreview(pid);
|
window.giaEngageAutoPreview(pid);
|
||||||
};
|
});
|
||||||
}
|
|
||||||
|
|
||||||
window.giaWorkspaceOpenTab(personId, "plan_board", false);
|
window.giaWorkspaceOpenTab(personId, "plan_board", false);
|
||||||
syncTargetInputs();
|
syncTargetInputs();
|
||||||
|
|||||||
@@ -1650,24 +1650,7 @@
|
|||||||
button.classList.add("is-loading");
|
button.classList.add("is-loading");
|
||||||
setStatus("Requesting history sync…", "info");
|
setStatus("Requesting history sync…", "info");
|
||||||
try {
|
try {
|
||||||
const payload = new URLSearchParams();
|
const result = await postFormJson(historySyncUrl, queryParams());
|
||||||
payload.set("service", thread.dataset.service || "");
|
|
||||||
payload.set("identifier", thread.dataset.identifier || "");
|
|
||||||
if (thread.dataset.person) {
|
|
||||||
payload.set("person", thread.dataset.person);
|
|
||||||
}
|
|
||||||
payload.set("limit", thread.dataset.limit || "60");
|
|
||||||
const response = await fetch(historySyncUrl, {
|
|
||||||
method: "POST",
|
|
||||||
credentials: "same-origin",
|
|
||||||
headers: {
|
|
||||||
"X-CSRFToken": csrfToken,
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
|
||||||
Accept: "application/json"
|
|
||||||
},
|
|
||||||
body: payload.toString(),
|
|
||||||
});
|
|
||||||
const result = await response.json();
|
|
||||||
if (!result.ok) {
|
if (!result.ok) {
|
||||||
setStatus(
|
setStatus(
|
||||||
String(result.message || result.error || "History sync failed."),
|
String(result.message || result.error || "History sync failed."),
|
||||||
@@ -2352,14 +2335,7 @@
|
|||||||
}
|
}
|
||||||
panelState.polling = true;
|
panelState.polling = true;
|
||||||
try {
|
try {
|
||||||
const params = new URLSearchParams();
|
const params = queryParams({ after_ts: String(lastTs) });
|
||||||
params.set("service", thread.dataset.service || "");
|
|
||||||
params.set("identifier", thread.dataset.identifier || "");
|
|
||||||
if (thread.dataset.person) {
|
|
||||||
params.set("person", thread.dataset.person);
|
|
||||||
}
|
|
||||||
params.set("limit", thread.dataset.limit || "60");
|
|
||||||
params.set("after_ts", String(lastTs));
|
|
||||||
const response = await fetch(thread.dataset.pollUrl + "?" + params.toString(), {
|
const response = await fetch(thread.dataset.pollUrl + "?" + params.toString(), {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
credentials: "same-origin",
|
credentials: "same-origin",
|
||||||
@@ -2532,7 +2508,7 @@
|
|||||||
return active;
|
return active;
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryParams = function () {
|
const queryParams = function (extraParams) {
|
||||||
const params = new URLSearchParams();
|
const params = new URLSearchParams();
|
||||||
params.set("service", thread.dataset.service || "");
|
params.set("service", thread.dataset.service || "");
|
||||||
params.set("identifier", thread.dataset.identifier || "");
|
params.set("identifier", thread.dataset.identifier || "");
|
||||||
@@ -2540,9 +2516,47 @@
|
|||||||
params.set("person", thread.dataset.person);
|
params.set("person", thread.dataset.person);
|
||||||
}
|
}
|
||||||
params.set("limit", thread.dataset.limit || "60");
|
params.set("limit", thread.dataset.limit || "60");
|
||||||
|
const extras =
|
||||||
|
extraParams && typeof extraParams === "object" ? extraParams : {};
|
||||||
|
Object.keys(extras).forEach(function (key) {
|
||||||
|
const value = extras[key];
|
||||||
|
if (value === undefined || value === null || value === "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
params.set(String(key), String(value));
|
||||||
|
});
|
||||||
return params;
|
return params;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const postFormJson = async function (url, params) {
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "POST",
|
||||||
|
credentials: "same-origin",
|
||||||
|
headers: {
|
||||||
|
"X-CSRFToken": csrfToken,
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
Accept: "application/json"
|
||||||
|
},
|
||||||
|
body: params.toString(),
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Request failed");
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getJson = async function (url) {
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: "GET",
|
||||||
|
credentials: "same-origin",
|
||||||
|
headers: { Accept: "application/json" }
|
||||||
|
});
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error("Request failed");
|
||||||
|
}
|
||||||
|
return response.json();
|
||||||
|
};
|
||||||
|
|
||||||
const titleCase = function (value) {
|
const titleCase = function (value) {
|
||||||
const raw = String(value || "").trim().toLowerCase();
|
const raw = String(value || "").trim().toLowerCase();
|
||||||
if (!raw) {
|
if (!raw) {
|
||||||
@@ -2625,6 +2639,17 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const cardContentNode = function (card) {
|
||||||
|
return card ? card.querySelector(".compose-ai-content") : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setCardMessage = function (card, message) {
|
||||||
|
const node = cardContentNode(card);
|
||||||
|
if (node) {
|
||||||
|
node.textContent = String(message || "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const openEngage = function (sourceRef) {
|
const openEngage = function (sourceRef) {
|
||||||
const engageCard = showCard("engage");
|
const engageCard = showCard("engage");
|
||||||
if (!engageCard) {
|
if (!engageCard) {
|
||||||
@@ -2644,19 +2669,19 @@
|
|||||||
}
|
}
|
||||||
setCardLoading(card, true);
|
setCardLoading(card, true);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(thread.dataset.draftsUrl + "?" + queryParams().toString(), {
|
const payload = await getJson(
|
||||||
method: "GET",
|
thread.dataset.draftsUrl + "?" + queryParams().toString()
|
||||||
credentials: "same-origin",
|
);
|
||||||
headers: { Accept: "application/json" }
|
|
||||||
});
|
|
||||||
const payload = await response.json();
|
|
||||||
setCardLoading(card, false);
|
setCardLoading(card, false);
|
||||||
if (!payload.ok) {
|
if (!payload.ok) {
|
||||||
card.querySelector(".compose-ai-content").textContent = payload.error || "Failed to load drafts.";
|
setCardMessage(card, payload.error || "Failed to load drafts.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const drafts = Array.isArray(payload.drafts) ? payload.drafts : [];
|
const drafts = Array.isArray(payload.drafts) ? payload.drafts : [];
|
||||||
const container = card.querySelector(".compose-ai-content");
|
const container = cardContentNode(card);
|
||||||
|
if (!container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
container.innerHTML = "";
|
container.innerHTML = "";
|
||||||
const engageButton = document.createElement("button");
|
const engageButton = document.createElement("button");
|
||||||
engageButton.type = "button";
|
engageButton.type = "button";
|
||||||
@@ -2695,7 +2720,7 @@
|
|||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setCardLoading(card, false);
|
setCardLoading(card, false);
|
||||||
card.querySelector(".compose-ai-content").textContent = "Failed to load drafts.";
|
setCardMessage(card, "Failed to load drafts.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2706,21 +2731,18 @@
|
|||||||
}
|
}
|
||||||
setCardLoading(card, true);
|
setCardLoading(card, true);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(thread.dataset.summaryUrl + "?" + queryParams().toString(), {
|
const payload = await getJson(
|
||||||
method: "GET",
|
thread.dataset.summaryUrl + "?" + queryParams().toString()
|
||||||
credentials: "same-origin",
|
);
|
||||||
headers: { Accept: "application/json" }
|
|
||||||
});
|
|
||||||
const payload = await response.json();
|
|
||||||
setCardLoading(card, false);
|
setCardLoading(card, false);
|
||||||
if (!payload.ok) {
|
if (!payload.ok) {
|
||||||
card.querySelector(".compose-ai-content").textContent = payload.error || "Failed to load summary.";
|
setCardMessage(card, payload.error || "Failed to load summary.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
card.querySelector(".compose-ai-content").textContent = String(payload.summary || "");
|
setCardMessage(card, String(payload.summary || ""));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setCardLoading(card, false);
|
setCardLoading(card, false);
|
||||||
card.querySelector(".compose-ai-content").textContent = "Failed to load summary.";
|
setCardMessage(card, "Failed to load summary.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2731,17 +2753,14 @@
|
|||||||
}
|
}
|
||||||
setCardLoading(card, true);
|
setCardLoading(card, true);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(
|
const payload = await getJson(
|
||||||
thread.dataset.quickInsightsUrl + "?" + queryParams().toString(),
|
thread.dataset.quickInsightsUrl + "?" + queryParams().toString()
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
credentials: "same-origin",
|
|
||||||
headers: { Accept: "application/json" }
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
const payload = await response.json();
|
|
||||||
setCardLoading(card, false);
|
setCardLoading(card, false);
|
||||||
const container = card.querySelector(".compose-ai-content");
|
const container = cardContentNode(card);
|
||||||
|
if (!container) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!payload.ok) {
|
if (!payload.ok) {
|
||||||
container.textContent = payload.error || "Failed to load quick insights.";
|
container.textContent = payload.error || "Failed to load quick insights.";
|
||||||
return;
|
return;
|
||||||
@@ -2994,8 +3013,7 @@
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setCardLoading(card, false);
|
setCardLoading(card, false);
|
||||||
card.querySelector(".compose-ai-content").textContent =
|
setCardMessage(card, "Failed to load quick insights.");
|
||||||
"Failed to load quick insights.";
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3035,18 +3053,12 @@
|
|||||||
if (showCustom && customValue) {
|
if (showCustom && customValue) {
|
||||||
params.set("custom_text", customValue);
|
params.set("custom_text", customValue);
|
||||||
}
|
}
|
||||||
const response = await fetch(
|
const payload = await getJson(
|
||||||
thread.dataset.engagePreviewUrl + "?" + params.toString(),
|
thread.dataset.engagePreviewUrl + "?" + params.toString()
|
||||||
{
|
|
||||||
method: "GET",
|
|
||||||
credentials: "same-origin",
|
|
||||||
headers: { Accept: "application/json" }
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
const payload = await response.json();
|
|
||||||
setCardLoading(card, false);
|
setCardLoading(card, false);
|
||||||
if (!payload.ok) {
|
if (!payload.ok) {
|
||||||
card.querySelector(".compose-ai-content").textContent = payload.error || "Failed to load engage preview.";
|
setCardMessage(card, payload.error || "Failed to load engage preview.");
|
||||||
panelState.engageToken = "";
|
panelState.engageToken = "";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -3081,11 +3093,11 @@
|
|||||||
if (payload.artifact) {
|
if (payload.artifact) {
|
||||||
text = text + "\n\nSource: " + String(payload.artifact);
|
text = text + "\n\nSource: " + String(payload.artifact);
|
||||||
}
|
}
|
||||||
card.querySelector(".compose-ai-content").textContent = text;
|
setCardMessage(card, text);
|
||||||
sendBtn.disabled = !(confirm.checked && panelState.engageToken);
|
sendBtn.disabled = !(confirm.checked && panelState.engageToken);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setCardLoading(card, false);
|
setCardLoading(card, false);
|
||||||
card.querySelector(".compose-ai-content").textContent = "Failed to load engage preview.";
|
setCardMessage(card, "Failed to load engage preview.");
|
||||||
panelState.engageToken = "";
|
panelState.engageToken = "";
|
||||||
} finally {
|
} finally {
|
||||||
if (refreshBtn) {
|
if (refreshBtn) {
|
||||||
@@ -3141,27 +3153,13 @@
|
|||||||
if (!panelState.engageToken) {
|
if (!panelState.engageToken) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const formData = new URLSearchParams();
|
const formData = queryParams({
|
||||||
formData.set("service", thread.dataset.service || "");
|
engage_token: panelState.engageToken,
|
||||||
formData.set("identifier", thread.dataset.identifier || "");
|
failsafe_arm: confirm.checked ? "1" : "0",
|
||||||
if (thread.dataset.person) {
|
failsafe_confirm: confirm.checked ? "1" : "0",
|
||||||
formData.set("person", thread.dataset.person);
|
});
|
||||||
}
|
|
||||||
formData.set("engage_token", panelState.engageToken);
|
|
||||||
formData.set("failsafe_arm", confirm.checked ? "1" : "0");
|
|
||||||
formData.set("failsafe_confirm", confirm.checked ? "1" : "0");
|
|
||||||
try {
|
try {
|
||||||
const response = await fetch(thread.dataset.engageSendUrl, {
|
const payload = await postFormJson(thread.dataset.engageSendUrl, formData);
|
||||||
method: "POST",
|
|
||||||
credentials: "same-origin",
|
|
||||||
headers: {
|
|
||||||
"X-CSRFToken": csrfToken,
|
|
||||||
"Content-Type": "application/x-www-form-urlencoded",
|
|
||||||
Accept: "application/json"
|
|
||||||
},
|
|
||||||
body: formData.toString()
|
|
||||||
});
|
|
||||||
const payload = await response.json();
|
|
||||||
if (!payload.ok) {
|
if (!payload.ok) {
|
||||||
flashCompose("is-send-fail");
|
flashCompose("is-send-fail");
|
||||||
setStatus(payload.error || "Engage send failed.", "danger");
|
setStatus(payload.error || "Engage send failed.", "danger");
|
||||||
@@ -3352,28 +3350,26 @@
|
|||||||
|
|
||||||
// Cancel send support: show a cancel button while the form request is pending.
|
// Cancel send support: show a cancel button while the form request is pending.
|
||||||
let cancelBtn = null;
|
let cancelBtn = null;
|
||||||
|
const cancelSendRequest = function (commandId) {
|
||||||
|
return postFormJson(
|
||||||
|
'{% url "compose_cancel_send" %}',
|
||||||
|
queryParams({ command_id: String(commandId || "") })
|
||||||
|
);
|
||||||
|
};
|
||||||
const showCancelButton = function () {
|
const showCancelButton = function () {
|
||||||
if (cancelBtn) return;
|
if (cancelBtn) return;
|
||||||
cancelBtn = document.createElement('button');
|
cancelBtn = document.createElement('button');
|
||||||
cancelBtn.type = 'button';
|
cancelBtn.type = 'button';
|
||||||
cancelBtn.className = 'button is-danger is-light is-small compose-cancel-send-btn';
|
cancelBtn.className = 'button is-danger is-light is-small compose-cancel-send-btn';
|
||||||
cancelBtn.textContent = 'Cancel Send';
|
cancelBtn.textContent = 'Cancel Send';
|
||||||
cancelBtn.addEventListener('click', function () {
|
cancelBtn.addEventListener('click', async function () {
|
||||||
// Post cancel by service+identifier
|
try {
|
||||||
const payload = new URLSearchParams();
|
await cancelSendRequest("");
|
||||||
payload.set('service', thread.dataset.service || '');
|
} catch (e) {
|
||||||
payload.set('identifier', thread.dataset.identifier || '');
|
// Ignore cancel failures.
|
||||||
fetch('{% url "compose_cancel_send" %}', {
|
} finally {
|
||||||
method: 'POST',
|
|
||||||
credentials: 'same-origin',
|
|
||||||
headers: { 'X-CSRFToken': '{{ csrf_token }}', 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
||||||
body: payload.toString(),
|
|
||||||
}).then(function (resp) {
|
|
||||||
// Hide cancel once requested
|
|
||||||
hideCancelButton();
|
hideCancelButton();
|
||||||
}).catch(function () {
|
}
|
||||||
hideCancelButton();
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
if (statusBox) {
|
if (statusBox) {
|
||||||
statusBox.appendChild(cancelBtn);
|
statusBox.appendChild(cancelBtn);
|
||||||
@@ -3498,24 +3494,16 @@
|
|||||||
btn.type = 'button';
|
btn.type = 'button';
|
||||||
btn.className = 'button is-danger is-light is-small compose-persistent-cancel-btn';
|
btn.className = 'button is-danger is-light is-small compose-persistent-cancel-btn';
|
||||||
btn.textContent = 'Cancel Queued Send';
|
btn.textContent = 'Cancel Queued Send';
|
||||||
btn.addEventListener('click', function () {
|
btn.addEventListener('click', async function () {
|
||||||
const payload = new URLSearchParams();
|
try {
|
||||||
payload.set('service', thread.dataset.service || '');
|
await cancelSendRequest(String(commandId || ''));
|
||||||
payload.set('identifier', thread.dataset.identifier || '');
|
|
||||||
payload.set('command_id', String(commandId || ''));
|
|
||||||
fetch('{% url "compose_cancel_send" %}', {
|
|
||||||
method: 'POST',
|
|
||||||
credentials: 'same-origin',
|
|
||||||
headers: { 'X-CSRFToken': '{{ csrf_token }}', 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
||||||
body: payload.toString(),
|
|
||||||
}).then(function (resp) {
|
|
||||||
stopPendingCommandPolling();
|
stopPendingCommandPolling();
|
||||||
hidePersistentCancelButton();
|
hidePersistentCancelButton();
|
||||||
setStatus('Send cancelled.', 'warning');
|
setStatus('Send cancelled.', 'warning');
|
||||||
poll(true);
|
await poll(true);
|
||||||
}).catch(function () {
|
} catch (e) {
|
||||||
hidePersistentCancelButton();
|
hidePersistentCancelButton();
|
||||||
});
|
}
|
||||||
});
|
});
|
||||||
container.appendChild(btn);
|
container.appendChild(btn);
|
||||||
if (statusBox) {
|
if (statusBox) {
|
||||||
|
|||||||
@@ -108,6 +108,17 @@ def _safe_after_ts(raw) -> int:
|
|||||||
return max(0, value)
|
return max(0, value)
|
||||||
|
|
||||||
|
|
||||||
|
def _request_scope(request, source: str = "GET"):
|
||||||
|
data = request.GET if str(source).upper() == "GET" else request.POST
|
||||||
|
service = _default_service(data.get("service"))
|
||||||
|
identifier = str(data.get("identifier") or "").strip()
|
||||||
|
person = None
|
||||||
|
person_id = data.get("person")
|
||||||
|
if person_id:
|
||||||
|
person = get_object_or_404(Person, id=person_id, user=request.user)
|
||||||
|
return service, identifier, person
|
||||||
|
|
||||||
|
|
||||||
def _format_ts_label(ts_value: int) -> str:
|
def _format_ts_label(ts_value: int) -> str:
|
||||||
try:
|
try:
|
||||||
as_dt = datetime.fromtimestamp(int(ts_value) / 1000, tz=dt_timezone.utc)
|
as_dt = datetime.fromtimestamp(int(ts_value) / 1000, tz=dt_timezone.utc)
|
||||||
@@ -2111,12 +2122,7 @@ class ComposeWorkspace(LoginRequiredMixin, View):
|
|||||||
template_name = "pages/compose-workspace.html"
|
template_name = "pages/compose-workspace.html"
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
service = _default_service(request.GET.get("service"))
|
service, identifier, person = _request_scope(request, "GET")
|
||||||
identifier = str(request.GET.get("identifier") or "").strip()
|
|
||||||
person = None
|
|
||||||
person_id = request.GET.get("person")
|
|
||||||
if person_id:
|
|
||||||
person = Person.objects.filter(id=person_id, user=request.user).first()
|
|
||||||
limit = _safe_limit(request.GET.get("limit") or 40)
|
limit = _safe_limit(request.GET.get("limit") or 40)
|
||||||
|
|
||||||
initial_widget_url = ""
|
initial_widget_url = ""
|
||||||
@@ -2307,12 +2313,7 @@ class ComposePage(LoginRequiredMixin, View):
|
|||||||
template_name = "pages/compose.html"
|
template_name = "pages/compose.html"
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
service = _default_service(request.GET.get("service"))
|
service, identifier, person = _request_scope(request, "GET")
|
||||||
identifier = str(request.GET.get("identifier") or "").strip()
|
|
||||||
person = None
|
|
||||||
person_id = request.GET.get("person")
|
|
||||||
if person_id:
|
|
||||||
person = get_object_or_404(Person, id=person_id, user=request.user)
|
|
||||||
if not identifier and person is None:
|
if not identifier and person is None:
|
||||||
return HttpResponseBadRequest("Missing contact identifier.")
|
return HttpResponseBadRequest("Missing contact identifier.")
|
||||||
|
|
||||||
@@ -2328,12 +2329,7 @@ class ComposePage(LoginRequiredMixin, View):
|
|||||||
|
|
||||||
class ComposeWidget(LoginRequiredMixin, View):
|
class ComposeWidget(LoginRequiredMixin, View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
service = _default_service(request.GET.get("service"))
|
service, identifier, person = _request_scope(request, "GET")
|
||||||
identifier = str(request.GET.get("identifier") or "").strip()
|
|
||||||
person = None
|
|
||||||
person_id = request.GET.get("person")
|
|
||||||
if person_id:
|
|
||||||
person = get_object_or_404(Person, id=person_id, user=request.user)
|
|
||||||
if not identifier and person is None:
|
if not identifier and person is None:
|
||||||
return HttpResponseBadRequest("Missing contact identifier.")
|
return HttpResponseBadRequest("Missing contact identifier.")
|
||||||
|
|
||||||
@@ -2361,12 +2357,7 @@ class ComposeWidget(LoginRequiredMixin, View):
|
|||||||
|
|
||||||
class ComposeThread(LoginRequiredMixin, View):
|
class ComposeThread(LoginRequiredMixin, View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
service = _default_service(request.GET.get("service"))
|
service, identifier, person = _request_scope(request, "GET")
|
||||||
identifier = str(request.GET.get("identifier") or "").strip()
|
|
||||||
person = None
|
|
||||||
person_id = request.GET.get("person")
|
|
||||||
if person_id:
|
|
||||||
person = get_object_or_404(Person, id=person_id, user=request.user)
|
|
||||||
if not identifier and person is None:
|
if not identifier and person is None:
|
||||||
return HttpResponseBadRequest("Missing contact identifier.")
|
return HttpResponseBadRequest("Missing contact identifier.")
|
||||||
|
|
||||||
@@ -2565,12 +2556,7 @@ class ComposeHistorySync(LoginRequiredMixin, View):
|
|||||||
return len(duplicate_ids)
|
return len(duplicate_ids)
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
service = _default_service(request.POST.get("service"))
|
service, identifier, person = _request_scope(request, "POST")
|
||||||
identifier = str(request.POST.get("identifier") or "").strip()
|
|
||||||
person = None
|
|
||||||
person_id = request.POST.get("person")
|
|
||||||
if person_id:
|
|
||||||
person = get_object_or_404(Person, id=person_id, user=request.user)
|
|
||||||
if not identifier and person is None:
|
if not identifier and person is None:
|
||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
{
|
{
|
||||||
@@ -2737,8 +2723,7 @@ class ComposeHistorySync(LoginRequiredMixin, View):
|
|||||||
|
|
||||||
class ComposeCancelSend(LoginRequiredMixin, View):
|
class ComposeCancelSend(LoginRequiredMixin, View):
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
service = _default_service(request.POST.get("service"))
|
service, identifier, _ = _request_scope(request, "POST")
|
||||||
identifier = str(request.POST.get("identifier") or "").strip()
|
|
||||||
command_id = str(request.POST.get("command_id") or "").strip()
|
command_id = str(request.POST.get("command_id") or "").strip()
|
||||||
if not identifier:
|
if not identifier:
|
||||||
return JsonResponse({"ok": False, "error": "missing_identifier"})
|
return JsonResponse({"ok": False, "error": "missing_identifier"})
|
||||||
@@ -2842,12 +2827,7 @@ class ComposeMediaBlob(LoginRequiredMixin, View):
|
|||||||
|
|
||||||
class ComposeDrafts(LoginRequiredMixin, View):
|
class ComposeDrafts(LoginRequiredMixin, View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
service = _default_service(request.GET.get("service"))
|
service, identifier, person = _request_scope(request, "GET")
|
||||||
identifier = str(request.GET.get("identifier") or "").strip()
|
|
||||||
person = None
|
|
||||||
person_id = request.GET.get("person")
|
|
||||||
if person_id:
|
|
||||||
person = get_object_or_404(Person, id=person_id, user=request.user)
|
|
||||||
if not identifier and person is None:
|
if not identifier and person is None:
|
||||||
return JsonResponse({"ok": False, "error": "Missing contact identifier."})
|
return JsonResponse({"ok": False, "error": "Missing contact identifier."})
|
||||||
|
|
||||||
@@ -2908,12 +2888,7 @@ class ComposeDrafts(LoginRequiredMixin, View):
|
|||||||
|
|
||||||
class ComposeSummary(LoginRequiredMixin, View):
|
class ComposeSummary(LoginRequiredMixin, View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
service = _default_service(request.GET.get("service"))
|
service, identifier, person = _request_scope(request, "GET")
|
||||||
identifier = str(request.GET.get("identifier") or "").strip()
|
|
||||||
person = None
|
|
||||||
person_id = request.GET.get("person")
|
|
||||||
if person_id:
|
|
||||||
person = get_object_or_404(Person, id=person_id, user=request.user)
|
|
||||||
if not identifier and person is None:
|
if not identifier and person is None:
|
||||||
return JsonResponse({"ok": False, "error": "Missing contact identifier."})
|
return JsonResponse({"ok": False, "error": "Missing contact identifier."})
|
||||||
|
|
||||||
@@ -2976,12 +2951,7 @@ class ComposeSummary(LoginRequiredMixin, View):
|
|||||||
|
|
||||||
class ComposeQuickInsights(LoginRequiredMixin, View):
|
class ComposeQuickInsights(LoginRequiredMixin, View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
service = _default_service(request.GET.get("service"))
|
service, identifier, person = _request_scope(request, "GET")
|
||||||
identifier = str(request.GET.get("identifier") or "").strip()
|
|
||||||
person = None
|
|
||||||
person_id = request.GET.get("person")
|
|
||||||
if person_id:
|
|
||||||
person = get_object_or_404(Person, id=person_id, user=request.user)
|
|
||||||
if not identifier and person is None:
|
if not identifier and person is None:
|
||||||
return JsonResponse({"ok": False, "error": "Missing contact identifier."})
|
return JsonResponse({"ok": False, "error": "Missing contact identifier."})
|
||||||
|
|
||||||
@@ -3097,12 +3067,7 @@ class ComposeQuickInsights(LoginRequiredMixin, View):
|
|||||||
|
|
||||||
class ComposeEngagePreview(LoginRequiredMixin, View):
|
class ComposeEngagePreview(LoginRequiredMixin, View):
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
service = _default_service(request.GET.get("service"))
|
service, identifier, person = _request_scope(request, "GET")
|
||||||
identifier = str(request.GET.get("identifier") or "").strip()
|
|
||||||
person = None
|
|
||||||
person_id = request.GET.get("person")
|
|
||||||
if person_id:
|
|
||||||
person = get_object_or_404(Person, id=person_id, user=request.user)
|
|
||||||
if not identifier and person is None:
|
if not identifier and person is None:
|
||||||
return JsonResponse({"ok": False, "error": "Missing contact identifier."})
|
return JsonResponse({"ok": False, "error": "Missing contact identifier."})
|
||||||
|
|
||||||
@@ -3228,12 +3193,7 @@ class ComposeEngagePreview(LoginRequiredMixin, View):
|
|||||||
|
|
||||||
class ComposeEngageSend(LoginRequiredMixin, View):
|
class ComposeEngageSend(LoginRequiredMixin, View):
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
service = _default_service(request.POST.get("service"))
|
service, identifier, person = _request_scope(request, "POST")
|
||||||
identifier = str(request.POST.get("identifier") or "").strip()
|
|
||||||
person = None
|
|
||||||
person_id = request.POST.get("person")
|
|
||||||
if person_id:
|
|
||||||
person = get_object_or_404(Person, id=person_id, user=request.user)
|
|
||||||
if not identifier and person is None:
|
if not identifier and person is None:
|
||||||
return JsonResponse({"ok": False, "error": "Missing contact identifier."})
|
return JsonResponse({"ok": False, "error": "Missing contact identifier."})
|
||||||
|
|
||||||
@@ -3319,12 +3279,7 @@ class ComposeSend(LoginRequiredMixin, View):
|
|||||||
return response
|
return response
|
||||||
|
|
||||||
def post(self, request):
|
def post(self, request):
|
||||||
service = _default_service(request.POST.get("service"))
|
service, identifier, person = _request_scope(request, "POST")
|
||||||
identifier = str(request.POST.get("identifier") or "").strip()
|
|
||||||
person = None
|
|
||||||
person_id = request.POST.get("person")
|
|
||||||
if person_id:
|
|
||||||
person = get_object_or_404(Person, id=person_id, user=request.user)
|
|
||||||
render_mode = str(request.POST.get("render_mode") or "page").strip().lower()
|
render_mode = str(request.POST.get("render_mode") or "page").strip().lower()
|
||||||
if render_mode not in {"page", "widget"}:
|
if render_mode not in {"page", "widget"}:
|
||||||
render_mode = "page"
|
render_mode = "page"
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user