@phren/cli 0.0.20 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/mcp/dist/generated/memory-ui-graph.browser.js +22 -22
- package/mcp/dist/hooks.js +51 -14
- package/mcp/dist/mcp-data.js +4 -5
- package/mcp/dist/memory-ui-assets.js +2 -2
- package/mcp/dist/memory-ui-data.js +1 -1
- package/mcp/dist/memory-ui-graph.runtime.js +22 -22
- package/mcp/dist/memory-ui-page.js +71 -44
- package/mcp/dist/memory-ui-scripts.js +37 -555
- package/mcp/dist/memory-ui-server.js +0 -34
- package/mcp/dist/memory-ui-styles.js +137 -136
- package/mcp/dist/profile-store.js +1 -13
- package/mcp/dist/shared-ollama.js +1 -12
- package/mcp/dist/shell-state-store.js +2 -14
- package/package.json +1 -1
|
@@ -588,9 +588,7 @@ export function renderProjectReferenceEnhancementScript(_authToken) {
|
|
|
588
588
|
});
|
|
589
589
|
})();`;
|
|
590
590
|
}
|
|
591
|
-
|
|
592
|
-
return "";
|
|
593
|
-
}
|
|
591
|
+
// renderReviewQueueEditSyncScript removed — was dead code returning ""
|
|
594
592
|
export function renderTasksAndSettingsScript(authToken) {
|
|
595
593
|
const safeToken = JSON.stringify(authToken).slice(1, -1);
|
|
596
594
|
return `(function() {
|
|
@@ -606,27 +604,11 @@ export function renderTasksAndSettingsScript(authToken) {
|
|
|
606
604
|
return fetch(url).then(function(r) { return r.json(); });
|
|
607
605
|
}
|
|
608
606
|
|
|
609
|
-
var _taskViewMode = 'list';
|
|
610
|
-
|
|
611
607
|
function priorityBadge(p) {
|
|
612
608
|
if (!p) return '';
|
|
613
|
-
var colors = { high: '#ef4444', medium: '#f59e0b', low: '#6b7280' };
|
|
614
|
-
var color = colors[p] || '#6b7280';
|
|
615
609
|
return '<span class="task-priority-badge task-priority-' + esc(p) + '">' + esc(p) + '</span>';
|
|
616
610
|
}
|
|
617
611
|
|
|
618
|
-
function sessionBadge(sessionId) {
|
|
619
|
-
if (!sessionId) return '';
|
|
620
|
-
var short = sessionId.length > 8 ? sessionId.slice(0, 8) : sessionId;
|
|
621
|
-
return '<span class="task-session-badge" title="Session ' + esc(sessionId) + '">' + esc(short) + '</span>';
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
function statusChip(section, checked) {
|
|
625
|
-
if (checked || section === 'Done') return '<span class="task-status-chip task-status-done" title="Done"><svg width="12" height="12" viewBox="0 0 16 16" fill="none"><path d="M3 8.5l3.5 3.5 6.5-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg> Done</span>';
|
|
626
|
-
if (section === 'Active') return '<span class="task-status-chip task-status-active" title="In Progress">In Progress</span>';
|
|
627
|
-
return '<span class="task-status-chip task-status-pending" title="Pending">Pending</span>';
|
|
628
|
-
}
|
|
629
|
-
|
|
630
612
|
function projectBadge(proj) {
|
|
631
613
|
return '<span class="task-project-badge">' + esc(proj) + '</span>';
|
|
632
614
|
}
|
|
@@ -733,55 +715,40 @@ export function renderTasksAndSettingsScript(authToken) {
|
|
|
733
715
|
var container = document.getElementById('tasks-list');
|
|
734
716
|
if (!container) return;
|
|
735
717
|
if (!tasks.length && !doneTasks.length) {
|
|
736
|
-
container.innerHTML = '<div class="task-empty-state"><svg viewBox="0 0 48 48" width="
|
|
718
|
+
container.innerHTML = '<div class="task-empty-state"><svg viewBox="0 0 48 48" width="48" height="48" style="display:block;margin:0 auto 12px"><ellipse cx="24" cy="24" rx="16" ry="15" fill="#7B68AE" opacity="0.25"/><ellipse cx="24" cy="24" rx="12" ry="11.5" fill="#7B68AE" opacity="0.4"/><circle cx="19" cy="22" r="1.5" fill="#2D2255"/><circle cx="29" cy="22" r="1.5" fill="#2D2255"/><path d="M21 28c1 1.2 2.5 1.5 3.5 1.3 1-.2 2-1 2.5-1.3" stroke="#2D2255" stroke-width="1" fill="none" stroke-linecap="round"/></svg><div style="font-size:var(--text-md);font-weight:600;color:var(--ink);margin-bottom:4px">Nothing to do!</div><div style="color:var(--muted);font-size:var(--text-sm)">Add a task to get started.</div></div>';
|
|
737
719
|
return;
|
|
738
720
|
}
|
|
739
721
|
|
|
740
|
-
// Group by priority within sections
|
|
741
722
|
var priorityOrder = { high: 0, medium: 1, low: 2 };
|
|
742
723
|
function sortByPriority(a, b) {
|
|
743
|
-
// Unchecked before checked
|
|
744
|
-
var aChecked = a.checked || a.section === 'Done' ? 1 : 0;
|
|
745
|
-
var bChecked = b.checked || b.section === 'Done' ? 1 : 0;
|
|
746
|
-
if (aChecked !== bChecked) return aChecked - bChecked;
|
|
747
|
-
// Pinned first
|
|
748
724
|
if (a.pinned && !b.pinned) return -1;
|
|
749
725
|
if (!a.pinned && b.pinned) return 1;
|
|
750
|
-
// Then by priority
|
|
751
726
|
var pa = priorityOrder[a.priority] !== undefined ? priorityOrder[a.priority] : 1;
|
|
752
727
|
var pb = priorityOrder[b.priority] !== undefined ? priorityOrder[b.priority] : 1;
|
|
753
728
|
return pa - pb;
|
|
754
729
|
}
|
|
755
730
|
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
var html = '<div class="task-card' + borderClass + doneClass + '">';
|
|
768
|
-
html += '<div class="task-card-top">';
|
|
769
|
-
html += statusChip(t.section, t.checked);
|
|
770
|
-
html += projectBadge(t.project);
|
|
731
|
+
function isNotDone(t) { return t.section !== 'Done' && !t.checked; }
|
|
732
|
+
|
|
733
|
+
function renderTaskRow(t) {
|
|
734
|
+
var isDone = t.section === 'Done' || t.checked;
|
|
735
|
+
var priClass = t.priority ? 'task-row-priority-' + esc(t.priority) : 'task-row-priority-none';
|
|
736
|
+
var html = '<div class="task-row' + (isDone ? ' task-row-done' : '') + '">';
|
|
737
|
+
html += '<div class="task-row-priority ' + priClass + '"></div>';
|
|
738
|
+
html += '<div class="task-row-content">';
|
|
739
|
+
html += '<span class="task-row-text">' + esc(t.line) + '</span>';
|
|
740
|
+
html += '</div>';
|
|
741
|
+
html += '<div class="task-row-meta">';
|
|
771
742
|
html += pinIndicator(t.pinned);
|
|
772
743
|
html += githubBadge(t.githubIssue, t.githubUrl);
|
|
773
744
|
html += priorityBadge(t.priority);
|
|
774
|
-
html +=
|
|
775
|
-
html += '</div>';
|
|
776
|
-
html += '<div class="task-card-body">';
|
|
777
|
-
html += '<span class="task-card-text">' + esc(t.line) + '</span>';
|
|
778
|
-
if (t.context) html += '<span class="task-card-context">' + esc(t.context) + '</span>';
|
|
745
|
+
html += projectBadge(t.project);
|
|
779
746
|
html += '</div>';
|
|
780
|
-
html += '<div class="task-
|
|
781
|
-
if (
|
|
782
|
-
html += '<button class="task-
|
|
747
|
+
html += '<div class="task-row-actions">';
|
|
748
|
+
if (!isDone) {
|
|
749
|
+
html += '<button class="task-action-btn task-action-complete" data-ts-action="completeTask" data-project="' + esc(t.project) + '" data-item="' + esc(t.line) + '" title="Mark done"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M3 8.5l3.5 3.5 6.5-7" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></button>';
|
|
783
750
|
}
|
|
784
|
-
html += '<button class="task-
|
|
751
|
+
html += '<button class="task-action-btn task-action-delete" data-ts-action="removeTask" data-project="' + esc(t.project) + '" data-item="' + esc(t.line) + '" title="Delete task"><svg width="12" height="12" viewBox="0 0 16 16" fill="none"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg></button>';
|
|
785
752
|
html += '</div>';
|
|
786
753
|
html += '</div>';
|
|
787
754
|
return html;
|
|
@@ -807,49 +774,42 @@ export function renderTasksAndSettingsScript(authToken) {
|
|
|
807
774
|
topProjects.forEach(function(p) { html += '<span class="task-summary-project">' + esc(p) + ' (' + projectCounts[p] + ')</span>'; });
|
|
808
775
|
html += '</span>';
|
|
809
776
|
}
|
|
810
|
-
html += '<span class="task-view-toggle" style="margin-left:auto">';
|
|
811
|
-
html += '<button class="task-view-btn' + (_taskViewMode === 'list' ? ' active' : '') + '" data-ts-action="setTaskView" data-mode="list" title="List view"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M2 4h12M2 8h12M2 12h12" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/></svg></button>';
|
|
812
|
-
html += '<button class="task-view-btn' + (_taskViewMode === 'compact' ? ' active' : '') + '" data-ts-action="setTaskView" data-mode="compact" title="Compact view"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><rect x="1" y="2" width="6" height="5" rx="1" stroke="currentColor" stroke-width="1.2"/><rect x="9" y="2" width="6" height="5" rx="1" stroke="currentColor" stroke-width="1.2"/><rect x="1" y="9" width="6" height="5" rx="1" stroke="currentColor" stroke-width="1.2"/><rect x="9" y="9" width="6" height="5" rx="1" stroke="currentColor" stroke-width="1.2"/></svg></button>';
|
|
813
|
-
html += '</span>';
|
|
814
777
|
html += '</div>';
|
|
815
778
|
|
|
816
779
|
// Add task input at top (only when a specific project is selected)
|
|
817
|
-
|
|
818
|
-
projects.forEach(function(proj) {
|
|
780
|
+
if (projectFilter) {
|
|
819
781
|
html += '<div class="task-add-bar">';
|
|
820
|
-
html += '<input id="task-add-input-' + esc(
|
|
821
|
-
html += '<button class="task-add-btn" data-ts-action="addTask" data-project="' + esc(
|
|
782
|
+
html += '<input id="task-add-input-' + esc(projectFilter) + '" type="text" class="task-add-input" placeholder="Add a task to ' + esc(projectFilter) + '\u2026" data-ts-action="addTaskKeydown" data-project="' + esc(projectFilter) + '">';
|
|
783
|
+
html += '<button class="task-add-btn" data-ts-action="addTask" data-project="' + esc(projectFilter) + '"><svg width="14" height="14" viewBox="0 0 16 16" fill="none"><path d="M8 3v10M3 8h10" stroke="currentColor" stroke-width="2" stroke-linecap="round"/></svg> Add</button>';
|
|
822
784
|
html += '</div>';
|
|
823
|
-
}
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
// Group by section: Active first, then Queue
|
|
788
|
+
var activeTasks = tasks.filter(function(t) { return t.section === 'Active' && isNotDone(t); }).sort(sortByPriority);
|
|
789
|
+
var queueTasks = tasks.filter(function(t) { return t.section !== 'Active' && isNotDone(t); }).sort(sortByPriority);
|
|
824
790
|
|
|
825
|
-
|
|
826
|
-
function renderSection(title, items, icon) {
|
|
791
|
+
function renderSection(title, items) {
|
|
827
792
|
if (!items.length) return '';
|
|
828
|
-
var
|
|
829
|
-
|
|
830
|
-
shtml += '<div class="task-
|
|
831
|
-
shtml +=
|
|
832
|
-
items.forEach(function(t) { shtml += renderTaskCard(t); });
|
|
793
|
+
var shtml = '<div class="task-section-group">';
|
|
794
|
+
shtml += '<div class="task-section-header">' + title + ' <span class="task-section-count">' + items.length + '</span></div>';
|
|
795
|
+
shtml += '<div class="task-list">';
|
|
796
|
+
items.forEach(function(t) { shtml += renderTaskRow(t); });
|
|
833
797
|
shtml += '</div></div>';
|
|
834
798
|
return shtml;
|
|
835
799
|
}
|
|
836
800
|
|
|
837
|
-
html += renderSection('
|
|
838
|
-
html += renderSection('
|
|
839
|
-
html += renderSection('Low Priority', low, '<svg width="10" height="10" viewBox="0 0 10 10"><circle cx="5" cy="5" r="5" fill="#6b7280"/></svg>');
|
|
840
|
-
if (noPriority.length) {
|
|
841
|
-
html += renderSection('Tasks', noPriority, '<svg width="10" height="10" viewBox="0 0 10 10"><circle cx="5" cy="5" r="5" fill="var(--accent)"/></svg>');
|
|
842
|
-
}
|
|
801
|
+
html += renderSection('Active', activeTasks);
|
|
802
|
+
html += renderSection('Queue', queueTasks);
|
|
843
803
|
|
|
844
804
|
// Done section (collapsible)
|
|
845
|
-
var allDone = showDone ?
|
|
805
|
+
var allDone = showDone ? tasks.filter(function(t) { return t.section === 'Done' || t.checked; }) : doneTasks;
|
|
846
806
|
if (allDone.length) {
|
|
847
807
|
html += '<div class="task-done-section">';
|
|
848
808
|
html += '<button class="task-done-toggle" data-ts-action="toggleDoneSection">';
|
|
849
809
|
html += '<span class="task-toggle-arrow">\u25B6</span> Completed <span class="task-section-count">' + allDone.length + '</span></button>';
|
|
850
810
|
html += '<div class="task-done-list" style="display:none">';
|
|
851
|
-
html += '<div class="task-
|
|
852
|
-
allDone.forEach(function(t) { html +=
|
|
811
|
+
html += '<div class="task-list">';
|
|
812
|
+
allDone.forEach(function(t) { html += renderTaskRow(t); });
|
|
853
813
|
html += '</div></div></div>';
|
|
854
814
|
}
|
|
855
815
|
|
|
@@ -1172,122 +1132,13 @@ export function renderTasksAndSettingsScript(authToken) {
|
|
|
1172
1132
|
var _origSwitchTab = window.switchTab;
|
|
1173
1133
|
var _tasksLoaded = false;
|
|
1174
1134
|
var _settingsLoaded = false;
|
|
1175
|
-
var _sessionsLoaded = false;
|
|
1176
1135
|
window.switchTab = function(tab) {
|
|
1177
1136
|
if (typeof _origSwitchTab === 'function') _origSwitchTab(tab);
|
|
1178
1137
|
if (tab === 'tasks' && !_tasksLoaded) { _tasksLoaded = true; loadTasks(); }
|
|
1179
1138
|
if (tab === 'settings' && !_settingsLoaded) { _settingsLoaded = true; loadSettings(); }
|
|
1180
|
-
if (tab === 'sessions' && !_sessionsLoaded) { _sessionsLoaded = true; loadSessions(); }
|
|
1181
|
-
};
|
|
1182
|
-
|
|
1183
|
-
var _sessionsData = [];
|
|
1184
|
-
window.loadSessions = function() {
|
|
1185
|
-
var projectFilter = document.getElementById('sessions-filter-project');
|
|
1186
|
-
var project = projectFilter ? projectFilter.value : '';
|
|
1187
|
-
var apiUrl = _tsAuthToken ? tsAuthUrl('/api/sessions') : '/api/sessions';
|
|
1188
|
-
if (project) apiUrl += (apiUrl.includes('?') ? '&' : '?') + 'project=' + encodeURIComponent(project);
|
|
1189
|
-
loadJson(apiUrl).then(function(data) {
|
|
1190
|
-
if (!data.ok) throw new Error(data.error || 'Failed to load sessions');
|
|
1191
|
-
_sessionsData = data.sessions || [];
|
|
1192
|
-
renderSessionsList(_sessionsData);
|
|
1193
|
-
// Populate project filter
|
|
1194
|
-
if (projectFilter && projectFilter.options.length <= 1) {
|
|
1195
|
-
var projects = {};
|
|
1196
|
-
_sessionsData.forEach(function(s) { if (s.project) projects[s.project] = true; });
|
|
1197
|
-
Object.keys(projects).sort().forEach(function(p) {
|
|
1198
|
-
var opt = document.createElement('option');
|
|
1199
|
-
opt.value = p; opt.textContent = p;
|
|
1200
|
-
projectFilter.appendChild(opt);
|
|
1201
|
-
});
|
|
1202
|
-
}
|
|
1203
|
-
}).catch(function(err) {
|
|
1204
|
-
var list = document.getElementById('sessions-list');
|
|
1205
|
-
if (list) list.innerHTML = '<div style="padding:40px;color:var(--muted);text-align:center">' + esc(err.message) + '</div>';
|
|
1206
|
-
});
|
|
1207
|
-
};
|
|
1208
|
-
|
|
1209
|
-
function renderSessionsList(sessions) {
|
|
1210
|
-
var list = document.getElementById('sessions-list');
|
|
1211
|
-
var detail = document.getElementById('session-detail');
|
|
1212
|
-
var countEl = document.getElementById('sessions-count');
|
|
1213
|
-
if (detail) detail.style.display = 'none';
|
|
1214
|
-
if (countEl) countEl.textContent = sessions.length + ' session(s)';
|
|
1215
|
-
if (!list) return;
|
|
1216
|
-
if (sessions.length === 0) {
|
|
1217
|
-
list.innerHTML = '<div style="padding:40px;color:var(--muted);text-align:center"><svg viewBox="0 0 32 32" width="32" height="32" style="display:block;margin:0 auto 12px"><ellipse cx="16" cy="16" rx="10" ry="9.5" fill="#7B68AE" opacity="0.4"/><path d="M12 15l1-1 1 1-1 1z" fill="#2D2255"/><path d="M18 15l1-1 1 1-1 1z" fill="#2D2255"/><path d="M15 18.5c0.3-0.3 0.7-0.3 1 0" stroke="#2D2255" stroke-width="0.6" fill="none"/></svg>No sessions found.</div>';
|
|
1218
|
-
return;
|
|
1219
|
-
}
|
|
1220
|
-
list.innerHTML = '<table style="width:100%;border-collapse:collapse;font-size:var(--text-sm)">' +
|
|
1221
|
-
'<thead><tr style="border-bottom:1px solid var(--border);text-align:left">' +
|
|
1222
|
-
'<th style="padding:8px">Session</th><th style="padding:8px">Project</th><th style="padding:8px">Started</th>' +
|
|
1223
|
-
'<th style="padding:8px">Ended</th><th style="padding:8px">Duration</th><th style="padding:8px">Findings</th></tr></thead><tbody>' +
|
|
1224
|
-
sessions.map(function(s) {
|
|
1225
|
-
var id = s.sessionId.slice(0, 8);
|
|
1226
|
-
var startDate = (s.startedAt || '').slice(0, 16).replace('T', ' ');
|
|
1227
|
-
var endDate = s.endedAt ? (s.endedAt || '').slice(0, 16).replace('T', ' ') : '<span style="color:var(--green)">active</span>';
|
|
1228
|
-
var dur = s.durationMins != null ? s.durationMins + 'm' : '—';
|
|
1229
|
-
var summarySnip = s.summary ? '<div class="text-muted" style="font-size:var(--text-xs);max-width:300px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">' + esc(s.summary.slice(0, 80)) + '</div>' : '';
|
|
1230
|
-
return '<tr style="border-bottom:1px solid var(--border);cursor:pointer" data-ts-action="showSessionDetail" data-session-id="' + esc(s.sessionId) + '">' +
|
|
1231
|
-
'<td style="padding:8px;font-family:monospace">' + esc(id) + summarySnip + '</td>' +
|
|
1232
|
-
'<td style="padding:8px">' + esc(s.project || '—') + '</td>' +
|
|
1233
|
-
'<td style="padding:8px">' + esc(startDate) + '</td>' +
|
|
1234
|
-
'<td style="padding:8px">' + endDate + '</td>' +
|
|
1235
|
-
'<td style="padding:8px">' + esc(dur) + '</td>' +
|
|
1236
|
-
'<td style="padding:8px">' + (s.findingsAdded || 0) + '</td></tr>';
|
|
1237
|
-
}).join('') + '</tbody></table>';
|
|
1238
|
-
}
|
|
1239
|
-
|
|
1240
|
-
window.showSessionDetail = function(sessionId) {
|
|
1241
|
-
var apiUrl = _tsAuthToken ? tsAuthUrl('/api/sessions') : '/api/sessions';
|
|
1242
|
-
apiUrl += (apiUrl.includes('?') ? '&' : '?') + 'sessionId=' + encodeURIComponent(sessionId);
|
|
1243
|
-
var list = document.getElementById('sessions-list');
|
|
1244
|
-
var detail = document.getElementById('session-detail');
|
|
1245
|
-
if (list) list.style.display = 'none';
|
|
1246
|
-
if (detail) { detail.style.display = 'block'; detail.innerHTML = '<div style="padding:20px;color:var(--muted)">Loading session...</div>'; }
|
|
1247
|
-
loadJson(apiUrl).then(function(data) {
|
|
1248
|
-
if (!data.ok) throw new Error(data.error || 'Session not found');
|
|
1249
|
-
var s = data.session;
|
|
1250
|
-
var findings = data.findings || [];
|
|
1251
|
-
var tasks = data.tasks || [];
|
|
1252
|
-
var date = (s.startedAt || '').slice(0, 16).replace('T', ' ');
|
|
1253
|
-
var dur = s.durationMins != null ? s.durationMins + ' min' : '—';
|
|
1254
|
-
var html = '<div style="margin-bottom:12px"><button class="btn btn-sm" data-ts-action="backToSessionsList">← Back</button></div>' +
|
|
1255
|
-
'<div class="card" style="margin-bottom:16px"><div class="card-body">' +
|
|
1256
|
-
'<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:12px">' +
|
|
1257
|
-
'<div><strong>Session</strong><div class="text-muted" style="font-family:monospace">' + esc(s.sessionId.slice(0, 8)) + '</div></div>' +
|
|
1258
|
-
'<div><strong>Project</strong><div class="text-muted">' + esc(s.project || '—') + '</div></div>' +
|
|
1259
|
-
'<div><strong>Date</strong><div class="text-muted">' + esc(date) + '</div></div>' +
|
|
1260
|
-
'<div><strong>Duration</strong><div class="text-muted">' + esc(dur) + '</div></div>' +
|
|
1261
|
-
'<div><strong>Findings</strong><div class="text-muted">' + findings.length + '</div></div>' +
|
|
1262
|
-
'<div><strong>Tasks</strong><div class="text-muted">' + tasks.length + '</div></div>' +
|
|
1263
|
-
'<div><strong>Status</strong><div class="text-muted">' + esc(s.status) + '</div></div>' +
|
|
1264
|
-
'</div>' +
|
|
1265
|
-
(s.summary ? '<div style="margin-top:12px;padding:12px;background:var(--bg);border-radius:var(--radius-sm)"><strong>Summary</strong><div style="margin-top:4px">' + esc(s.summary) + '</div></div>' : '') +
|
|
1266
|
-
'</div></div>';
|
|
1267
|
-
if (findings.length > 0) {
|
|
1268
|
-
html += '<div class="card" style="margin-bottom:16px"><div class="card-header"><h3>Findings (' + findings.length + ')</h3></div><div class="card-body"><ul style="margin:0;padding-left:20px">';
|
|
1269
|
-
findings.forEach(function(f) { html += '<li style="margin-bottom:4px"><span class="text-muted">[' + esc(f.project) + ']</span> ' + esc(f.text) + '</li>'; });
|
|
1270
|
-
html += '</ul></div></div>';
|
|
1271
|
-
}
|
|
1272
|
-
if (tasks.length > 0) {
|
|
1273
|
-
html += '<div class="card" style="margin-bottom:16px"><div class="card-header"><h3>Tasks (' + tasks.length + ')</h3></div><div class="card-body"><ul style="margin:0;padding-left:20px">';
|
|
1274
|
-
tasks.forEach(function(t) { html += '<li style="margin-bottom:4px"><span class="text-muted">[' + esc(t.project) + '/' + esc(t.section) + ']</span> ' + esc(t.text) + '</li>'; });
|
|
1275
|
-
html += '</ul></div></div>';
|
|
1276
|
-
}
|
|
1277
|
-
if (detail) detail.innerHTML = html;
|
|
1278
|
-
}).catch(function(err) {
|
|
1279
|
-
if (detail) detail.innerHTML = '<div style="padding:20px;color:var(--muted)">' + esc(err.message) + '</div>';
|
|
1280
|
-
});
|
|
1281
|
-
};
|
|
1282
|
-
|
|
1283
|
-
window.backToSessionsList = function() {
|
|
1284
|
-
var list = document.getElementById('sessions-list');
|
|
1285
|
-
var detail = document.getElementById('session-detail');
|
|
1286
|
-
if (list) list.style.display = 'block';
|
|
1287
|
-
if (detail) detail.style.display = 'none';
|
|
1288
1139
|
};
|
|
1289
1140
|
|
|
1290
|
-
// Event delegation for dynamically generated tasks/settings
|
|
1141
|
+
// Event delegation for dynamically generated tasks/settings UI
|
|
1291
1142
|
document.addEventListener('click', function(e) {
|
|
1292
1143
|
var target = e.target;
|
|
1293
1144
|
if (!target || typeof target.closest !== 'function') return;
|
|
@@ -1298,15 +1149,12 @@ export function renderTasksAndSettingsScript(authToken) {
|
|
|
1298
1149
|
else if (action === 'completeTask') { completeTaskFromUi(actionEl.getAttribute('data-project'), actionEl.getAttribute('data-item')); }
|
|
1299
1150
|
else if (action === 'removeTask') { removeTaskFromUi(actionEl.getAttribute('data-project'), actionEl.getAttribute('data-item')); }
|
|
1300
1151
|
else if (action === 'addTask') { addTaskFromUi(actionEl.getAttribute('data-project')); }
|
|
1301
|
-
else if (action === 'setTaskView') { _taskViewMode = actionEl.getAttribute('data-mode') || 'list'; filterTasks(); }
|
|
1302
1152
|
else if (action === 'setFindingSensitivity') { setFindingSensitivity(actionEl.getAttribute('data-level')); }
|
|
1303
1153
|
else if (action === 'toggleAutoCapture') { setAutoCapture(actionEl.getAttribute('data-enabled') !== 'true'); }
|
|
1304
1154
|
else if (action === 'setTaskMode') { setTaskMode(actionEl.getAttribute('data-mode')); }
|
|
1305
1155
|
else if (action === 'setProactivity') { setProactivity(actionEl.getAttribute('data-level')); }
|
|
1306
1156
|
else if (action === 'toggleMcpEnabled') { setMcpEnabled(actionEl.getAttribute('data-enabled') !== 'true'); }
|
|
1307
1157
|
else if (action === 'toggleIntegrationTool') { toggleIntegrationTool(actionEl.getAttribute('data-tool')); }
|
|
1308
|
-
else if (action === 'showSessionDetail') { showSessionDetail(actionEl.getAttribute('data-session-id')); }
|
|
1309
|
-
else if (action === 'backToSessionsList') { backToSessionsList(); }
|
|
1310
1158
|
else if (action === 'setProjectFindingSensitivity') {
|
|
1311
1159
|
var proj = getSettingsProject();
|
|
1312
1160
|
var level = actionEl.getAttribute('data-level');
|
|
@@ -1567,368 +1415,6 @@ export function renderSearchScript(authToken) {
|
|
|
1567
1415
|
};
|
|
1568
1416
|
})();`;
|
|
1569
1417
|
}
|
|
1570
|
-
// renderGraphPopupScript removed — replaced by renderGraphHostScript + sigma popover
|
|
1571
|
-
function __removed_renderGraphPopupScript() {
|
|
1572
|
-
return `(function() {
|
|
1573
|
-
var popup = document.getElementById('graph-popup');
|
|
1574
|
-
var popupCard = document.getElementById('graph-popup-card');
|
|
1575
|
-
var popupLabel = document.getElementById('graph-popup-label');
|
|
1576
|
-
var popupTitle = document.getElementById('graph-popup-title');
|
|
1577
|
-
var popupMeta = document.getElementById('graph-popup-meta');
|
|
1578
|
-
var popupBody = document.getElementById('graph-popup-body');
|
|
1579
|
-
var popupClose = document.getElementById('graph-popup-close');
|
|
1580
|
-
var esc = window._phrenEsc || function(s) { return String(s); };
|
|
1581
|
-
var authUrl = window._phrenAuthUrl || function(path) { return path; };
|
|
1582
|
-
var authBody = window._phrenAuthBody || function(body) { return body; };
|
|
1583
|
-
var fetchCsrfToken = window._phrenFetchCsrfToken || function(cb) { cb(null); };
|
|
1584
|
-
var currentDetail = null;
|
|
1585
|
-
var isEditing = false;
|
|
1586
|
-
|
|
1587
|
-
function showToast(msg, type) {
|
|
1588
|
-
var container = document.getElementById('toast-container');
|
|
1589
|
-
if (!container) return;
|
|
1590
|
-
var toast = document.createElement('div');
|
|
1591
|
-
toast.className = 'toast' + (type ? ' ' + type : '');
|
|
1592
|
-
toast.textContent = msg;
|
|
1593
|
-
container.appendChild(toast);
|
|
1594
|
-
setTimeout(function() {
|
|
1595
|
-
if (toast.parentNode) toast.parentNode.removeChild(toast);
|
|
1596
|
-
}, 2800);
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
|
-
function typeLabel(kind) {
|
|
1600
|
-
if (kind === 'finding') return 'Finding';
|
|
1601
|
-
if (kind === 'task') return 'Task';
|
|
1602
|
-
if (kind === 'entity') return 'Fragment';
|
|
1603
|
-
if (kind === 'reference') return 'Reference';
|
|
1604
|
-
return 'Project';
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
function popupPoint(point) {
|
|
1608
|
-
return point || { x: 28, y: 28 };
|
|
1609
|
-
}
|
|
1610
|
-
|
|
1611
|
-
function renderMeta(detail) {
|
|
1612
|
-
if (!popupMeta) return;
|
|
1613
|
-
var parts = [];
|
|
1614
|
-
if (detail.project) parts.push('<span class="graph-pill">' + esc(detail.project) + '</span>');
|
|
1615
|
-
if (detail.section) parts.push('<span class="graph-pill">' + esc(detail.section) + '</span>');
|
|
1616
|
-
if (detail.priority) parts.push('<span class="graph-pill">' + esc(detail.priority + ' priority') + '</span>');
|
|
1617
|
-
if (detail.entityType) parts.push('<span class="graph-pill">' + esc(detail.entityType) + '</span>');
|
|
1618
|
-
if (detail.topicLabel) parts.push('<span class="graph-pill">' + esc(detail.topicLabel) + '</span>');
|
|
1619
|
-
if (detail.health) parts.push('<span class="graph-pill graph-pill-' + esc(detail.health) + '">' + esc(detail.health) + '</span>');
|
|
1620
|
-
popupMeta.innerHTML = parts.join('');
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
function statLine(label, value) {
|
|
1624
|
-
return '<div class="graph-popup-line"><span>' + esc(label) + '</span><strong>' + esc(value) + '</strong></div>';
|
|
1625
|
-
}
|
|
1626
|
-
|
|
1627
|
-
function renderDocs(detail) {
|
|
1628
|
-
if (!detail.refDocs || !detail.refDocs.length) return '';
|
|
1629
|
-
var docs = detail.refDocs.slice(0, 8).map(function(ref) {
|
|
1630
|
-
var doc = typeof ref === 'string' ? ref : (ref.doc || '');
|
|
1631
|
-
return '<div class="graph-popup-doc">' + esc(doc) + '</div>';
|
|
1632
|
-
}).join('');
|
|
1633
|
-
return '<div class="graph-popup-section"><h4>Linked docs</h4><div class="graph-popup-docs">' + docs + '</div></div>';
|
|
1634
|
-
}
|
|
1635
|
-
|
|
1636
|
-
function renderProject(detail) {
|
|
1637
|
-
var counts = detail.connections || {};
|
|
1638
|
-
return '' +
|
|
1639
|
-
'<div class="graph-popup-summary">' + esc(detail.fullLabel || detail.label || detail.id) + '</div>' +
|
|
1640
|
-
'<div class="graph-popup-stats">' +
|
|
1641
|
-
statLine('Neighbors', counts.total || 0) +
|
|
1642
|
-
statLine('Findings', counts.findings || 0) +
|
|
1643
|
-
statLine('Tasks', counts.tasks || 0) +
|
|
1644
|
-
statLine('Fragments', counts.entities || 0) +
|
|
1645
|
-
statLine('References', counts.references || 0) +
|
|
1646
|
-
'</div>';
|
|
1647
|
-
}
|
|
1648
|
-
|
|
1649
|
-
function renderFinding(detail) {
|
|
1650
|
-
return '' +
|
|
1651
|
-
'<div class="graph-popup-summary" id="graph-popup-text">' + esc(detail.fullLabel || detail.label) + '</div>' +
|
|
1652
|
-
'<div class="graph-popup-actions">' +
|
|
1653
|
-
'<button class="btn btn-sm" data-graph-action="edit">Edit</button>' +
|
|
1654
|
-
'<button class="btn btn-sm" data-graph-action="delete" style="border-color:var(--danger);color:var(--danger)">Delete</button>' +
|
|
1655
|
-
'</div>' +
|
|
1656
|
-
renderDocs(detail);
|
|
1657
|
-
}
|
|
1658
|
-
|
|
1659
|
-
function renderTask(detail) {
|
|
1660
|
-
var section = detail.section || 'Queue';
|
|
1661
|
-
var priority = detail.priority || 'none';
|
|
1662
|
-
return '' +
|
|
1663
|
-
'<div class="graph-popup-summary" id="graph-popup-text">' + esc(detail.fullLabel || detail.label) + '</div>' +
|
|
1664
|
-
'<div class="graph-popup-section"><h4>Status</h4><div class="graph-popup-actions">' +
|
|
1665
|
-
'<button class="btn btn-sm' + (section === 'Active' ? ' active' : '') + '" data-graph-action="task-status" data-status="Active">Active</button>' +
|
|
1666
|
-
'<button class="btn btn-sm' + (section === 'Queue' ? ' active' : '') + '" data-graph-action="task-status" data-status="Queue">Queue</button>' +
|
|
1667
|
-
'<button class="btn btn-sm" data-graph-action="task-status" data-status="Done">Done</button>' +
|
|
1668
|
-
'</div></div>' +
|
|
1669
|
-
'<div class="graph-popup-section"><h4>Priority</h4><div class="graph-popup-actions">' +
|
|
1670
|
-
'<button class="btn btn-sm' + (priority === 'high' ? ' active' : '') + '" data-graph-action="task-priority" data-priority="high">High</button>' +
|
|
1671
|
-
'<button class="btn btn-sm' + (priority === 'medium' ? ' active' : '') + '" data-graph-action="task-priority" data-priority="medium">Medium</button>' +
|
|
1672
|
-
'<button class="btn btn-sm' + (priority === 'low' ? ' active' : '') + '" data-graph-action="task-priority" data-priority="low">Low</button>' +
|
|
1673
|
-
'</div></div>' +
|
|
1674
|
-
'<div class="graph-popup-actions">' +
|
|
1675
|
-
'<button class="btn btn-sm" data-graph-action="edit">Edit</button>' +
|
|
1676
|
-
'<button class="btn btn-sm" data-graph-action="delete" style="border-color:var(--danger);color:var(--danger)">Delete</button>' +
|
|
1677
|
-
'</div>';
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
|
-
function renderEntity(detail) {
|
|
1681
|
-
var projects = (detail.connectedProjects || []).map(function(project) {
|
|
1682
|
-
return '<span class="graph-pill">' + esc(project) + '</span>';
|
|
1683
|
-
}).join('');
|
|
1684
|
-
return '' +
|
|
1685
|
-
'<div class="graph-popup-summary">' + esc(detail.fullLabel || detail.label) + '</div>' +
|
|
1686
|
-
'<div class="graph-popup-stats">' +
|
|
1687
|
-
statLine('References', detail.refCount || 0) +
|
|
1688
|
-
statLine('Projects', (detail.connectedProjects || []).length) +
|
|
1689
|
-
statLine('Neighbors', (detail.connections && detail.connections.total) || 0) +
|
|
1690
|
-
'</div>' +
|
|
1691
|
-
(projects ? '<div class="graph-popup-section"><h4>Projects</h4><div class="graph-popup-pills">' + projects + '</div></div>' : '') +
|
|
1692
|
-
renderDocs(detail);
|
|
1693
|
-
}
|
|
1694
|
-
|
|
1695
|
-
function renderReference(detail) {
|
|
1696
|
-
return '' +
|
|
1697
|
-
'<div class="graph-popup-summary">' + esc(detail.fullLabel || detail.label) + '</div>' +
|
|
1698
|
-
'<div class="graph-popup-stats">' +
|
|
1699
|
-
statLine('Project', detail.project || 'shared') +
|
|
1700
|
-
statLine('Neighbors', (detail.connections && detail.connections.total) || 0) +
|
|
1701
|
-
'</div>' +
|
|
1702
|
-
renderDocs(detail);
|
|
1703
|
-
}
|
|
1704
|
-
|
|
1705
|
-
function renderEditor(detail) {
|
|
1706
|
-
return '' +
|
|
1707
|
-
'<div class="graph-popup-editor">' +
|
|
1708
|
-
'<textarea id="graph-popup-editor-input">' + esc(detail.fullLabel || detail.label) + '</textarea>' +
|
|
1709
|
-
'<div class="graph-popup-actions">' +
|
|
1710
|
-
'<button class="btn btn-sm btn-primary" data-graph-action="save-edit">Save</button>' +
|
|
1711
|
-
'<button class="btn btn-sm" data-graph-action="cancel-edit">Cancel</button>' +
|
|
1712
|
-
'</div>' +
|
|
1713
|
-
'</div>';
|
|
1714
|
-
}
|
|
1715
|
-
|
|
1716
|
-
function renderBody(detail) {
|
|
1717
|
-
if (!popupBody) return;
|
|
1718
|
-
if (isEditing && (detail.kind === 'finding' || detail.kind === 'task')) {
|
|
1719
|
-
popupBody.innerHTML = renderEditor(detail);
|
|
1720
|
-
return;
|
|
1721
|
-
}
|
|
1722
|
-
if (detail.kind === 'project') popupBody.innerHTML = renderProject(detail);
|
|
1723
|
-
else if (detail.kind === 'finding') popupBody.innerHTML = renderFinding(detail);
|
|
1724
|
-
else if (detail.kind === 'task') popupBody.innerHTML = renderTask(detail);
|
|
1725
|
-
else if (detail.kind === 'entity') popupBody.innerHTML = renderEntity(detail);
|
|
1726
|
-
else popupBody.innerHTML = renderReference(detail);
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
function positionPopup(point) {
|
|
1730
|
-
if (!popupCard) return;
|
|
1731
|
-
var container = document.querySelector('#tab-graph .graph-container');
|
|
1732
|
-
if (!container) return;
|
|
1733
|
-
var rect = container.getBoundingClientRect();
|
|
1734
|
-
var width = popupCard.offsetWidth || 360;
|
|
1735
|
-
var height = popupCard.offsetHeight || 260;
|
|
1736
|
-
var safe = popupPoint(point);
|
|
1737
|
-
var left = Math.max(14, Math.min(safe.x + 18, rect.width - width - 14));
|
|
1738
|
-
var top = Math.max(14, Math.min(safe.y + 18, rect.height - height - 14));
|
|
1739
|
-
popupCard.style.left = left + 'px';
|
|
1740
|
-
popupCard.style.top = top + 'px';
|
|
1741
|
-
}
|
|
1742
|
-
|
|
1743
|
-
function renderPopup(detail, point) {
|
|
1744
|
-
if (!popup || !popupLabel || !popupTitle) return;
|
|
1745
|
-
currentDetail = detail;
|
|
1746
|
-
popupLabel.textContent = typeLabel(detail.kind);
|
|
1747
|
-
popupTitle.textContent = detail.label || detail.fullLabel || detail.id;
|
|
1748
|
-
renderMeta(detail);
|
|
1749
|
-
renderBody(detail);
|
|
1750
|
-
popup.classList.add('open');
|
|
1751
|
-
requestAnimationFrame(function() { positionPopup(point); });
|
|
1752
|
-
}
|
|
1753
|
-
|
|
1754
|
-
function closePopup(skipSelectionClear) {
|
|
1755
|
-
currentDetail = null;
|
|
1756
|
-
isEditing = false;
|
|
1757
|
-
if (popup) popup.classList.remove('open');
|
|
1758
|
-
if (!skipSelectionClear && typeof window.graphClearSelection === 'function') window.graphClearSelection();
|
|
1759
|
-
}
|
|
1760
|
-
|
|
1761
|
-
function refetchGraph(keepNodeId) {
|
|
1762
|
-
if (typeof window.loadGraph !== 'function') return;
|
|
1763
|
-
window.loadGraph();
|
|
1764
|
-
if (keepNodeId && window.phrenGraph && typeof window.phrenGraph.selectNode === 'function') {
|
|
1765
|
-
var attempts = 0;
|
|
1766
|
-
var timer = setInterval(function() {
|
|
1767
|
-
attempts++;
|
|
1768
|
-
if (window.phrenGraph.selectNode(keepNodeId) || attempts > 18) clearInterval(timer);
|
|
1769
|
-
}, 120);
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
1772
|
-
|
|
1773
|
-
function postForm(url, method, body, onOk) {
|
|
1774
|
-
fetchCsrfToken(function(csrfToken) {
|
|
1775
|
-
var nextBody = authBody(body);
|
|
1776
|
-
if (csrfToken) nextBody += '&_csrf=' + encodeURIComponent(csrfToken);
|
|
1777
|
-
fetch(url, {
|
|
1778
|
-
method: method,
|
|
1779
|
-
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
1780
|
-
body: nextBody
|
|
1781
|
-
}).then(function(r) { return r.json(); }).then(function(data) {
|
|
1782
|
-
if (!data.ok) throw new Error(data.error || 'Request failed');
|
|
1783
|
-
onOk(data);
|
|
1784
|
-
}).catch(function(err) {
|
|
1785
|
-
showToast(String((err && err.message) || err || 'Request failed'), 'err');
|
|
1786
|
-
});
|
|
1787
|
-
});
|
|
1788
|
-
}
|
|
1789
|
-
|
|
1790
|
-
function saveFindingEdit(nextText) {
|
|
1791
|
-
postForm(authUrl('/api/findings/' + encodeURIComponent(currentDetail.project)), 'PUT',
|
|
1792
|
-
'old_text=' + encodeURIComponent(currentDetail.fullLabel || currentDetail.label) + '&new_text=' + encodeURIComponent(nextText),
|
|
1793
|
-
function() {
|
|
1794
|
-
currentDetail.fullLabel = nextText;
|
|
1795
|
-
currentDetail.label = nextText.length > 55 ? nextText.slice(0, 52) + '...' : nextText;
|
|
1796
|
-
isEditing = false;
|
|
1797
|
-
renderPopup(currentDetail);
|
|
1798
|
-
refetchGraph(currentDetail.id);
|
|
1799
|
-
showToast('Finding updated', 'ok');
|
|
1800
|
-
}
|
|
1801
|
-
);
|
|
1802
|
-
}
|
|
1803
|
-
|
|
1804
|
-
function saveTaskEdit(nextText) {
|
|
1805
|
-
postForm('/api/tasks/update', 'POST',
|
|
1806
|
-
'project=' + encodeURIComponent(currentDetail.project) + '&item=' + encodeURIComponent(currentDetail.fullLabel || currentDetail.label) + '&text=' + encodeURIComponent(nextText),
|
|
1807
|
-
function() {
|
|
1808
|
-
currentDetail.fullLabel = nextText;
|
|
1809
|
-
currentDetail.label = nextText.length > 55 ? nextText.slice(0, 52) + '...' : nextText;
|
|
1810
|
-
isEditing = false;
|
|
1811
|
-
renderPopup(currentDetail);
|
|
1812
|
-
refetchGraph(currentDetail.id);
|
|
1813
|
-
showToast('Task updated', 'ok');
|
|
1814
|
-
}
|
|
1815
|
-
);
|
|
1816
|
-
}
|
|
1817
|
-
|
|
1818
|
-
function updateTask(payload) {
|
|
1819
|
-
var body = 'project=' + encodeURIComponent(currentDetail.project) + '&item=' + encodeURIComponent(currentDetail.fullLabel || currentDetail.label);
|
|
1820
|
-
Object.keys(payload).forEach(function(key) {
|
|
1821
|
-
body += '&' + encodeURIComponent(key) + '=' + encodeURIComponent(payload[key]);
|
|
1822
|
-
});
|
|
1823
|
-
postForm('/api/tasks/update', 'POST', body, function() {
|
|
1824
|
-
if (payload.section) currentDetail.section = payload.section;
|
|
1825
|
-
if (payload.priority) currentDetail.priority = payload.priority;
|
|
1826
|
-
renderPopup(currentDetail);
|
|
1827
|
-
refetchGraph(payload.section === 'Done' ? null : currentDetail.id);
|
|
1828
|
-
if (payload.section === 'Done') closePopup(true);
|
|
1829
|
-
showToast('Task updated', 'ok');
|
|
1830
|
-
});
|
|
1831
|
-
}
|
|
1832
|
-
|
|
1833
|
-
function completeTask() {
|
|
1834
|
-
postForm('/api/tasks/complete', 'POST',
|
|
1835
|
-
'project=' + encodeURIComponent(currentDetail.project) + '&item=' + encodeURIComponent(currentDetail.fullLabel || currentDetail.label),
|
|
1836
|
-
function() {
|
|
1837
|
-
closePopup(true);
|
|
1838
|
-
refetchGraph(null);
|
|
1839
|
-
showToast('Task completed', 'ok');
|
|
1840
|
-
}
|
|
1841
|
-
);
|
|
1842
|
-
}
|
|
1843
|
-
|
|
1844
|
-
function deleteCurrent() {
|
|
1845
|
-
if (!currentDetail) return;
|
|
1846
|
-
if (currentDetail.kind === 'finding') {
|
|
1847
|
-
postForm(authUrl('/api/findings/' + encodeURIComponent(currentDetail.project)), 'DELETE',
|
|
1848
|
-
'text=' + encodeURIComponent(currentDetail.fullLabel || currentDetail.label),
|
|
1849
|
-
function() {
|
|
1850
|
-
closePopup(true);
|
|
1851
|
-
refetchGraph(null);
|
|
1852
|
-
showToast('Finding deleted', 'ok');
|
|
1853
|
-
}
|
|
1854
|
-
);
|
|
1855
|
-
} else if (currentDetail.kind === 'task') {
|
|
1856
|
-
postForm('/api/tasks/remove', 'POST',
|
|
1857
|
-
'project=' + encodeURIComponent(currentDetail.project) + '&item=' + encodeURIComponent(currentDetail.fullLabel || currentDetail.label),
|
|
1858
|
-
function() {
|
|
1859
|
-
closePopup(true);
|
|
1860
|
-
refetchGraph(null);
|
|
1861
|
-
showToast('Task deleted', 'ok');
|
|
1862
|
-
}
|
|
1863
|
-
);
|
|
1864
|
-
}
|
|
1865
|
-
}
|
|
1866
|
-
|
|
1867
|
-
if (popupClose) popupClose.addEventListener('click', function(e) {
|
|
1868
|
-
e.preventDefault();
|
|
1869
|
-
e.stopPropagation();
|
|
1870
|
-
closePopup(false);
|
|
1871
|
-
});
|
|
1872
|
-
|
|
1873
|
-
if (popupCard) {
|
|
1874
|
-
popupCard.addEventListener('click', function(e) {
|
|
1875
|
-
var target = e.target;
|
|
1876
|
-
if (!target || typeof target.closest !== 'function' || !currentDetail) return;
|
|
1877
|
-
var actionEl = target.closest('[data-graph-action]');
|
|
1878
|
-
if (!actionEl) return;
|
|
1879
|
-
var action = actionEl.getAttribute('data-graph-action');
|
|
1880
|
-
if (action === 'edit') {
|
|
1881
|
-
isEditing = true;
|
|
1882
|
-
renderPopup(currentDetail);
|
|
1883
|
-
} else if (action === 'cancel-edit') {
|
|
1884
|
-
isEditing = false;
|
|
1885
|
-
renderPopup(currentDetail);
|
|
1886
|
-
} else if (action === 'save-edit') {
|
|
1887
|
-
var input = document.getElementById('graph-popup-editor-input');
|
|
1888
|
-
var nextText = input ? input.value.trim() : '';
|
|
1889
|
-
if (!nextText) {
|
|
1890
|
-
showToast('Text cannot be empty', 'err');
|
|
1891
|
-
return;
|
|
1892
|
-
}
|
|
1893
|
-
if (currentDetail.kind === 'finding') saveFindingEdit(nextText);
|
|
1894
|
-
else if (currentDetail.kind === 'task') saveTaskEdit(nextText);
|
|
1895
|
-
} else if (action === 'delete') {
|
|
1896
|
-
deleteCurrent();
|
|
1897
|
-
} else if (action === 'task-status') {
|
|
1898
|
-
var status = actionEl.getAttribute('data-status') || 'Queue';
|
|
1899
|
-
if (status === 'Done') completeTask();
|
|
1900
|
-
else updateTask({ section: status });
|
|
1901
|
-
} else if (action === 'task-priority') {
|
|
1902
|
-
updateTask({ priority: actionEl.getAttribute('data-priority') || 'medium' });
|
|
1903
|
-
}
|
|
1904
|
-
});
|
|
1905
|
-
}
|
|
1906
|
-
|
|
1907
|
-
document.addEventListener('pointerdown', function(e) {
|
|
1908
|
-
if (!popup || !popup.classList.contains('open')) return;
|
|
1909
|
-
var target = e.target;
|
|
1910
|
-
if (!target || typeof target.closest !== 'function') return;
|
|
1911
|
-
if (popupCard && popupCard.contains(target)) return;
|
|
1912
|
-
if (target.closest('.graph-filters') || target.closest('.graph-controls')) return;
|
|
1913
|
-
closePopup(false);
|
|
1914
|
-
});
|
|
1915
|
-
|
|
1916
|
-
if (window.phrenGraph && typeof window.phrenGraph.onNodeSelect === 'function') {
|
|
1917
|
-
window.phrenGraph.onNodeSelect(function(detail, point) {
|
|
1918
|
-
isEditing = false;
|
|
1919
|
-
renderPopup(detail, point);
|
|
1920
|
-
});
|
|
1921
|
-
}
|
|
1922
|
-
|
|
1923
|
-
if (window.phrenGraph && typeof window.phrenGraph.onSelectionClear === 'function') {
|
|
1924
|
-
window.phrenGraph.onSelectionClear(function() {
|
|
1925
|
-
currentDetail = null;
|
|
1926
|
-
isEditing = false;
|
|
1927
|
-
if (popup) popup.classList.remove('open');
|
|
1928
|
-
});
|
|
1929
|
-
}
|
|
1930
|
-
})();`;
|
|
1931
|
-
}
|
|
1932
1418
|
export function renderEventWiringScript() {
|
|
1933
1419
|
return `(function() {
|
|
1934
1420
|
// --- Navigation tabs ---
|
|
@@ -1987,10 +1473,6 @@ export function renderEventWiringScript() {
|
|
|
1987
1473
|
var tasksFilterSection = document.getElementById('tasks-filter-section');
|
|
1988
1474
|
if (tasksFilterSection) tasksFilterSection.addEventListener('change', function() { filterTasks(); });
|
|
1989
1475
|
|
|
1990
|
-
// --- Sessions filter ---
|
|
1991
|
-
var sessionsFilterProject = document.getElementById('sessions-filter-project');
|
|
1992
|
-
if (sessionsFilterProject) sessionsFilterProject.addEventListener('change', function() { loadSessions(); });
|
|
1993
|
-
|
|
1994
1476
|
// --- Mascot click animation ---
|
|
1995
1477
|
var mascotSvg = document.querySelector('.header-brand svg');
|
|
1996
1478
|
if (mascotSvg) {
|