Spaces:
Sleeping
Sleeping
feat: add folder filter dropdown to memories tab
Browse files- src/viewer/index.html +41 -2
src/viewer/index.html
CHANGED
|
@@ -1257,7 +1257,7 @@
|
|
| 1257 |
activeTab: 'dashboard',
|
| 1258 |
dashboard: { loaded: false, health: null, sessions: [], memories: [], graphStats: null, recentAudit: [], lessons: [], crystals: [], semantic: [], procedural: [] },
|
| 1259 |
graph: { loaded: false, nodes: [], edges: [], stats: null, filters: {}, selectedNode: null, queryError: null, truncated: false, totalNodes: 0, totalEdges: 0 },
|
| 1260 |
-
memories: { loaded: false, items: [], search: '', typeFilter: '' },
|
| 1261 |
timeline: { loaded: false, observations: [], sessionId: '', minImportance: 0, page: 0, pageSize: 50 },
|
| 1262 |
sessions: { loaded: false, items: [], selectedId: null, folderFilter: '' },
|
| 1263 |
audit: { loaded: false, entries: [], opFilter: '' },
|
|
@@ -2528,9 +2528,32 @@
|
|
| 2528 |
var items = state.memories.items;
|
| 2529 |
var search = state.memories.search.toLowerCase();
|
| 2530 |
var typeFilter = state.memories.typeFilter;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2531 |
|
| 2532 |
var filtered = items.filter(function(m) {
|
| 2533 |
if (typeFilter && m.type !== typeFilter) return false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2534 |
const normalizedSearch = (search || '').normalize("NFKC").toLowerCase();
|
| 2535 |
const normalizedTitle = (m.title || '').normalize("NFKC").toLowerCase();
|
| 2536 |
const normalizedContent = (m.content || '').normalize("NFKC").toLowerCase();
|
|
@@ -2556,7 +2579,16 @@
|
|
| 2556 |
typeOptions.forEach(function(t) {
|
| 2557 |
html += '<option value="' + esc(t) + '"' + (typeFilter === t ? ' selected' : '') + '>' + esc(t) + '</option>';
|
| 2558 |
});
|
| 2559 |
-
html += '</select>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2560 |
|
| 2561 |
if (filtered.length === 0) {
|
| 2562 |
html += '<div class="empty-state">' +
|
|
@@ -2613,6 +2645,13 @@
|
|
| 2613 |
renderMemories();
|
| 2614 |
});
|
| 2615 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2616 |
restoreSearchFocus(__focus);
|
| 2617 |
}
|
| 2618 |
|
|
|
|
| 1257 |
activeTab: 'dashboard',
|
| 1258 |
dashboard: { loaded: false, health: null, sessions: [], memories: [], graphStats: null, recentAudit: [], lessons: [], crystals: [], semantic: [], procedural: [] },
|
| 1259 |
graph: { loaded: false, nodes: [], edges: [], stats: null, filters: {}, selectedNode: null, queryError: null, truncated: false, totalNodes: 0, totalEdges: 0 },
|
| 1260 |
+
memories: { loaded: false, items: [], search: '', typeFilter: '', folderFilter: '' },
|
| 1261 |
timeline: { loaded: false, observations: [], sessionId: '', minImportance: 0, page: 0, pageSize: 50 },
|
| 1262 |
sessions: { loaded: false, items: [], selectedId: null, folderFilter: '' },
|
| 1263 |
audit: { loaded: false, entries: [], opFilter: '' },
|
|
|
|
| 2528 |
var items = state.memories.items;
|
| 2529 |
var search = state.memories.search.toLowerCase();
|
| 2530 |
var typeFilter = state.memories.typeFilter;
|
| 2531 |
+
var folderFilter = state.memories.folderFilter || '';
|
| 2532 |
+
|
| 2533 |
+
var projects = [];
|
| 2534 |
+
var hasNoFolder = false;
|
| 2535 |
+
items.forEach(function(m) {
|
| 2536 |
+
var pPath = m.project ? String(m.project).trim() : '';
|
| 2537 |
+
if (pPath) {
|
| 2538 |
+
if (!projects.includes(pPath)) {
|
| 2539 |
+
projects.push(pPath);
|
| 2540 |
+
}
|
| 2541 |
+
} else {
|
| 2542 |
+
hasNoFolder = true;
|
| 2543 |
+
}
|
| 2544 |
+
});
|
| 2545 |
+
projects.sort();
|
| 2546 |
|
| 2547 |
var filtered = items.filter(function(m) {
|
| 2548 |
if (typeFilter && m.type !== typeFilter) return false;
|
| 2549 |
+
var pPath = m.project ? String(m.project).trim() : '';
|
| 2550 |
+
if (folderFilter) {
|
| 2551 |
+
if (folderFilter === '_none_') {
|
| 2552 |
+
if (pPath) return false;
|
| 2553 |
+
} else if (pPath !== folderFilter) {
|
| 2554 |
+
return false;
|
| 2555 |
+
}
|
| 2556 |
+
}
|
| 2557 |
const normalizedSearch = (search || '').normalize("NFKC").toLowerCase();
|
| 2558 |
const normalizedTitle = (m.title || '').normalize("NFKC").toLowerCase();
|
| 2559 |
const normalizedContent = (m.content || '').normalize("NFKC").toLowerCase();
|
|
|
|
| 2579 |
typeOptions.forEach(function(t) {
|
| 2580 |
html += '<option value="' + esc(t) + '"' + (typeFilter === t ? ' selected' : '') + '>' + esc(t) + '</option>';
|
| 2581 |
});
|
| 2582 |
+
html += '</select>';
|
| 2583 |
+
html += '<select id="mem-folder-filter"><option value="">All folders</option>';
|
| 2584 |
+
if (hasNoFolder) {
|
| 2585 |
+
html += '<option value="_none_"' + (folderFilter === '_none_' ? ' selected' : '') + '>Uncategorized (No Folder)</option>';
|
| 2586 |
+
}
|
| 2587 |
+
projects.forEach(function(p) {
|
| 2588 |
+
html += '<option value="' + esc(p) + '"' + (folderFilter === p ? ' selected' : '') + '>' + esc(p) + '</option>';
|
| 2589 |
+
});
|
| 2590 |
+
html += '</select>';
|
| 2591 |
+
html += '</div>';
|
| 2592 |
|
| 2593 |
if (filtered.length === 0) {
|
| 2594 |
html += '<div class="empty-state">' +
|
|
|
|
| 2645 |
renderMemories();
|
| 2646 |
});
|
| 2647 |
}
|
| 2648 |
+
var folderSelect = document.getElementById('mem-folder-filter');
|
| 2649 |
+
if (folderSelect) {
|
| 2650 |
+
folderSelect.addEventListener('change', function() {
|
| 2651 |
+
state.memories.folderFilter = this.value;
|
| 2652 |
+
renderMemories();
|
| 2653 |
+
});
|
| 2654 |
+
}
|
| 2655 |
restoreSearchFocus(__focus);
|
| 2656 |
}
|
| 2657 |
|