Add the Input Interface task submission form to Tasks/Progress

New "Add a Task" card above the master-detail board: track dropdown (8
real tracks + new Unassigned/Needs Triage fallback), submitter dropdown
(Peter/Mckinley), and a task text field. Submit is disabled until all
three are filled. Posts to the Input Interface session's local Flask
backend (localhost:8507/submit-task, POST {trackId, submitter, taskText}),
which owns writing the new subtask into TASKS_DATA on disk. On success,
this page's own in-memory TASKS_DATA is patched immediately too, so the
board reflects the new task without a reload, form clears and shows
"Added to {label}". On error, shows the message inline and leaves the
form filled in.

Also adds the "Unassigned / Needs Triage" track itself (empty, pale
red/orange tint to stand out, positioned first in TASKS_DATA) as the
catch-all destination for submissions that don't fit an existing track.

Source values from that backend ("Input Interface (Peter)" / "Input
Interface (Mckinley)") needed no rendering changes on this end -- source
was already displayed as a plain string everywhere, never switched on for
styling.
This commit is contained in:
beantownbabe committed 2026-08-25 13:51:17 +02:00
1 parent ab7f8368ae
commit 7c0c169cf0
1 file changed
+105 -1
+105 -1
View File
@@ -724,6 +724,7 @@
.ab-card:hover { border-color: #2d6a9f; }
.ab-card-weekly { background: #fffbe6; }
.ab-card-progress-log { background: #eefbf1; }
.ab-card-unassigned { background: #fdecea; border-color: #e2a29b; }
.pl-cal-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; }
.pl-cal-label { font-size: 1.05rem; font-weight: 800; color: #1b3a5c; }
@@ -889,6 +890,40 @@
</div>
<div id="tab-tasks" class="tab-content">
<div class="card" style="margin-bottom: 20px;">
<h2>Add a Task</h2>
<div style="display:flex; gap:12px; flex-wrap:wrap; align-items:flex-end;">
<label style="flex:1; min-width:200px;">Track
<select id="ti-track">
<option value="">Select a track…</option>
<option value="open-items-linkedin">LinkedIn</option>
<option value="open-items-outreach">Outreach</option>
<option value="open-items-department-dash">Department Dash</option>
<option value="open-items-demographics">Demographics</option>
<option value="open-items-mail-merge">Mail Merge Interface</option>
<option value="open-items-crm-research">CRM Research</option>
<option value="open-items-opportunities">Opportunities / Conference Scout</option>
<option value="open-items-market-intelligence">Market Intelligence / Prospect Scout</option>
<option value="open-items-unassigned">Unassigned / Needs Triage</option>
</select>
</label>
<label style="min-width:160px;">Submitted by
<select id="ti-submitter">
<option value="">Select…</option>
<option value="Peter">Peter</option>
<option value="Mckinley">Mckinley</option>
</select>
</label>
</div>
<label style="display:block; margin-top:12px;">Task
<textarea id="ti-text" maxlength="2000" rows="3" style="width:100%; font-family:inherit; font-size:0.95rem; padding:8px 10px; border:1px solid #d3dbe4; border-radius:6px;" placeholder="Describe the task…"></textarea>
</label>
<div style="margin-top:12px; display:flex; align-items:center; gap:12px;">
<button type="button" id="ti-submit" disabled>Add Task</button>
<span id="ti-status" style="font-size:0.85rem;"></span>
</div>
</div>
<div class="ab-outreach" style="display: flex;">
<div class="ab-outreach-list" id="tasks-list"></div>
<div class="ab-outreach-detail" id="tasks-detail"></div>
@@ -6369,6 +6404,13 @@
Directory outreach board -- a list of arrivals on the left, full detail on the right.
Reuses .ab-card/.ab-outreach-list/.ab-outreach-detail styling for visual consistency. */
var TASKS_DATA = [
{
id: "open-items-unassigned",
label: "Unassigned / Needs Triage",
subtasks: [],
notes: [],
reports: []
},
{
id: "open-items-linkedin",
label: "LinkedIn",
@@ -6570,7 +6612,8 @@
function buildTaskSidebarCard(entry, isSelected) {
var card = document.createElement("div");
card.className = "ab-card" + (isSelected ? " selected" : "");
var unassignedClass = entry.id === "open-items-unassigned" ? " ab-card-unassigned" : "";
card.className = "ab-card" + unassignedClass + (isSelected ? " selected" : "");
card.dataset.id = entry.id;
// Three buckets, not two: "Still open" (actionable), "Ongoing" (standing/recurring,
@@ -6658,6 +6701,67 @@
renderTasksBoard();
/* ---- Input Interface: local-only task submission form, posts to a small Flask
backend (port 8507, owned by the Input Interface session) that writes the new
subtask directly into TASKS_DATA in index.html on disk. This page's own
in-memory TASKS_DATA is patched immediately on success too, so the board
reflects the new task without needing a reload. */
(function () {
var trackEl = document.getElementById("ti-track");
var submitterEl = document.getElementById("ti-submitter");
var textEl = document.getElementById("ti-text");
var submitBtn = document.getElementById("ti-submit");
var statusEl = document.getElementById("ti-status");
function updateSubmitEnabled() {
submitBtn.disabled = !(trackEl.value && submitterEl.value && textEl.value.trim());
}
trackEl.addEventListener("change", updateSubmitEnabled);
submitterEl.addEventListener("change", updateSubmitEnabled);
textEl.addEventListener("input", updateSubmitEnabled);
submitBtn.addEventListener("click", function () {
submitBtn.disabled = true;
statusEl.textContent = "Adding…";
statusEl.style.color = "#6b7a8d";
var trackId = trackEl.value;
var trackLabel = trackEl.options[trackEl.selectedIndex].text;
fetch("http://localhost:8507/submit-task", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ trackId: trackId, submitter: submitterEl.value, taskText: textEl.value.trim() })
})
.then(function (r) { return r.json().then(function (data) { return { ok: r.ok, data: data }; }); })
.then(function (result) {
if (!result.ok) {
statusEl.textContent = (result.data && result.data.error) || "Something went wrong.";
statusEl.style.color = "#b3261e";
updateSubmitEnabled();
return;
}
var track = TASKS_DATA.filter(function (t) { return t.id === trackId; })[0];
if (track && result.data.subtask && result.data.subtask.subtask) {
track.subtasks.push(result.data.subtask);
}
trackEl.value = "";
submitterEl.value = "";
textEl.value = "";
statusEl.textContent = "Added to " + trackLabel + ".";
statusEl.style.color = "#1a8a60";
updateSubmitEnabled();
tasksSelectedId = trackId;
renderTasksBoard();
})
.catch(function () {
statusEl.textContent = "Couldn't reach the task input backend (localhost:8507) — is it running?";
statusEl.style.color = "#b3261e";
updateSubmitEnabled();
});
});
})();
/* ---- Progress Log: a normal entry in the same sidebar list as Weekly Tasks and the
track cards, not a separate section. Its detail view is a calendar (not a list)
-- still computed from the exact same TASKS_DATA/WEEKLY_TASKS_DATA notes+reports,