-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathsearch.html
More file actions
116 lines (103 loc) · 3.99 KB
/
Copy pathsearch.html
File metadata and controls
116 lines (103 loc) · 3.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
{% extends "base.html" %}
{% block title %}Search — Cursor Chat Browser{% endblock %}
{% block content %}
<div class="search-page">
<div class="page-header">
<h1>Search</h1>
<div class="btn-group" style="align-self:center">
<button class="btn" id="filter-all" onclick="setFilter('all')">All</button>
<button class="btn btn-outline" id="filter-chat" onclick="setFilter('chat')">Ask Logs</button>
<button class="btn btn-outline" id="filter-composer" onclick="setFilter('composer')">Agent Logs</button>
</div>
</div>
<div class="form-group" style="margin-bottom:1.5rem">
<div class="search-bar">
<input type="text" id="search-input" class="input" placeholder="Search across all logs..." autofocus>
<button class="btn btn-primary" onclick="doSearch()">Search</button>
</div>
</div>
<div id="loading" class="loading" style="display:none">
<div class="spinner"></div>
<p>Searching...</p>
</div>
<p id="result-count" class="text-muted" style="display:none"></p>
<div id="results-container"></div>
</div>
<script>
let currentFilter = 'all';
document.addEventListener('DOMContentLoaded', () => {
const params = new URLSearchParams(window.location.search);
const q = params.get('q');
const t = params.get('type') || 'all';
if (q) {
document.getElementById('search-input').value = q;
currentFilter = t;
updateFilterButtons();
performSearch(q, t);
}
document.getElementById('search-input').addEventListener('keydown', e => {
if (e.key === 'Enter') doSearch();
});
});
function setFilter(type) {
currentFilter = type;
updateFilterButtons();
doSearch();
}
function updateFilterButtons() {
['all', 'chat', 'composer'].forEach(t => {
const btn = document.getElementById('filter-' + t);
btn.className = t === currentFilter ? 'btn' : 'btn btn-outline';
});
}
function doSearch() {
const q = document.getElementById('search-input').value.trim();
if (!q) return;
const url = new URL(window.location);
url.searchParams.set('q', q);
url.searchParams.set('type', currentFilter);
window.history.pushState({}, '', url);
performSearch(q, currentFilter);
}
async function performSearch(query, type) {
const loading = document.getElementById('loading');
const countEl = document.getElementById('result-count');
const container = document.getElementById('results-container');
loading.style.display = 'flex';
countEl.style.display = 'none';
container.innerHTML = '';
try {
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}&type=${type}`);
const data = await res.json();
const results = data.results || [];
loading.style.display = 'none';
countEl.style.display = 'block';
countEl.textContent = `Found ${results.length} results for "${query}"`;
let html = '';
for (const r of results) {
const badge = r.type === 'chat' ? '<span class="badge">Ask Log</span>' : '<span class="badge badge-secondary">Agent Log</span>';
const ts = formatDate(r.timestamp);
const snippet = escapeHtml((r.matchingText || '').slice(0, 300));
const folder = r.workspaceId === 'global'
? '<span class="text-sm" style="color:var(--blue)">Global Storage</span>'
: (r.workspaceFolder ? `<span class="text-sm text-muted">${escapeHtml(r.workspaceFolder)}</span>` : '');
html += `<div class="card" style="margin-bottom:1rem;padding:1rem">
<div class="flex-between">
<div>
<a href="/workspace/${r.workspaceId}?tab=${r.chatId}&type=${r.type}" class="link text-lg">${escapeHtml(r.chatTitle)}</a>
<div class="text-sm text-muted">${ts}</div>
</div>
${badge}
</div>
<div class="text-sm" style="margin-top:0.5rem">${snippet}</div>
${folder ? '<div style="margin-top:0.5rem">' + folder + '</div>' : ''}
</div>`;
}
container.innerHTML = html;
} catch (e) {
loading.style.display = 'none';
container.innerHTML = '<p class="text-danger">Search failed.</p>';
}
}
</script>
{% endblock %}