Spaces:
Paused
fix: eview refinements for memory dashboard
Browse filesAdressed:
1) When selecting memories using checkbox, it unchecks one second later automatically (Brave+Firefox)
2) Area filter does not work. When All is selecter, it shows me memories from fragments, solutions, etc., but when I select an area, no memories are shown.
3) Modal does not have a title, it shows a path
4) In light mode, buttons and some labels are almost invisible - we should not use custom colors anywhere, we should always use one of the color vars in the screenshot, those are automatically adjusted based on current theme. Also in light mode there's a lot of gray areas that blend, again, we should use our color vars.
5) The loading spinner is stretched into an oval
6) We should merge the first div (title and memory counts) with the third one (pagination) to save space. + we should also show the total number of memories in the DB (unfiltered, just the total count of docs)
7) Action buttons should stack vertically, we can remove the title to make it more narrow
8) We should not use emojis for icons, they break the design, it's used in the source badge (knowledge, conversation...)
|
@@ -253,10 +253,11 @@ class MemoryDashboard(ApiHandler):
|
|
| 253 |
threshold = 0.6 # Lower threshold for broader search in dashboard
|
| 254 |
comparator = Memory._get_comparator(f"area == '{area_filter}'") if area_filter else None
|
| 255 |
|
|
|
|
| 256 |
docs = await myFaiss_db.asearch(
|
| 257 |
search_query,
|
| 258 |
search_type="similarity_score_threshold",
|
| 259 |
-
k=
|
| 260 |
score_threshold=threshold,
|
| 261 |
filter=comparator,
|
| 262 |
)
|
|
@@ -272,10 +273,6 @@ class MemoryDashboard(ApiHandler):
|
|
| 272 |
|
| 273 |
memories.append(doc)
|
| 274 |
|
| 275 |
-
# Apply limit
|
| 276 |
-
if len(memories) >= limit:
|
| 277 |
-
break
|
| 278 |
-
|
| 279 |
# Format memories for the dashboard
|
| 280 |
formatted_memories: list[dict] = []
|
| 281 |
for memory in memories:
|
|
@@ -298,7 +295,7 @@ class MemoryDashboard(ApiHandler):
|
|
| 298 |
|
| 299 |
formatted_memories.append(memory_data)
|
| 300 |
|
| 301 |
-
# Sort by timestamp (newest first) - handle "unknown" timestamps
|
| 302 |
def get_sort_key(memory):
|
| 303 |
timestamp = memory["timestamp"]
|
| 304 |
if timestamp == "unknown" or not timestamp:
|
|
@@ -307,11 +304,19 @@ class MemoryDashboard(ApiHandler):
|
|
| 307 |
|
| 308 |
formatted_memories.sort(key=get_sort_key, reverse=True)
|
| 309 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 310 |
# Get summary statistics
|
| 311 |
total_memories = len(formatted_memories)
|
| 312 |
knowledge_count = sum(1 for m in formatted_memories if m["knowledge_source"])
|
| 313 |
conversation_count = total_memories - knowledge_count
|
| 314 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 315 |
areas_count: dict[str, int] = {}
|
| 316 |
for memory_dict in formatted_memories:
|
| 317 |
area = memory_dict["area"]
|
|
@@ -321,6 +326,7 @@ class MemoryDashboard(ApiHandler):
|
|
| 321 |
"success": True,
|
| 322 |
"memories": formatted_memories,
|
| 323 |
"total_count": total_memories,
|
|
|
|
| 324 |
"knowledge_count": knowledge_count,
|
| 325 |
"conversation_count": conversation_count,
|
| 326 |
"areas_count": areas_count,
|
|
|
|
| 253 |
threshold = 0.6 # Lower threshold for broader search in dashboard
|
| 254 |
comparator = Memory._get_comparator(f"area == '{area_filter}'") if area_filter else None
|
| 255 |
|
| 256 |
+
# Get ALL matching results, don't limit in query
|
| 257 |
docs = await myFaiss_db.asearch(
|
| 258 |
search_query,
|
| 259 |
search_type="similarity_score_threshold",
|
| 260 |
+
k=10000, # Get all matches up to reasonable max
|
| 261 |
score_threshold=threshold,
|
| 262 |
filter=comparator,
|
| 263 |
)
|
|
|
|
| 273 |
|
| 274 |
memories.append(doc)
|
| 275 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 276 |
# Format memories for the dashboard
|
| 277 |
formatted_memories: list[dict] = []
|
| 278 |
for memory in memories:
|
|
|
|
| 295 |
|
| 296 |
formatted_memories.append(memory_data)
|
| 297 |
|
| 298 |
+
# Sort ALL results by timestamp (newest first) - handle "unknown" timestamps
|
| 299 |
def get_sort_key(memory):
|
| 300 |
timestamp = memory["timestamp"]
|
| 301 |
if timestamp == "unknown" or not timestamp:
|
|
|
|
| 304 |
|
| 305 |
formatted_memories.sort(key=get_sort_key, reverse=True)
|
| 306 |
|
| 307 |
+
# Apply limit AFTER sorting to get the newest entries
|
| 308 |
+
if limit and len(formatted_memories) > limit:
|
| 309 |
+
formatted_memories = formatted_memories[:limit]
|
| 310 |
+
|
| 311 |
# Get summary statistics
|
| 312 |
total_memories = len(formatted_memories)
|
| 313 |
knowledge_count = sum(1 for m in formatted_memories if m["knowledge_source"])
|
| 314 |
conversation_count = total_memories - knowledge_count
|
| 315 |
|
| 316 |
+
# Get total count of all memories in database (unfiltered)
|
| 317 |
+
all_docs = myFaiss_db.get_all_docs()
|
| 318 |
+
total_db_count = len(all_docs)
|
| 319 |
+
|
| 320 |
areas_count: dict[str, int] = {}
|
| 321 |
for memory_dict in formatted_memories:
|
| 322 |
area = memory_dict["area"]
|
|
|
|
| 326 |
"success": True,
|
| 327 |
"memories": formatted_memories,
|
| 328 |
"total_count": total_memories,
|
| 329 |
+
"total_db_count": total_db_count,
|
| 330 |
"knowledge_count": knowledge_count,
|
| 331 |
"conversation_count": conversation_count,
|
| 332 |
"areas_count": areas_count,
|
|
@@ -2,6 +2,12 @@ import { createStore } from "/js/AlpineStore.js";
|
|
| 2 |
import { getContext } from "/index.js";
|
| 3 |
import * as API from "/js/api.js";
|
| 4 |
import { openModal, closeModal } from "/js/modals.js";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
// Memory Dashboard Store
|
| 7 |
const memoryDashboardStore = {
|
|
@@ -29,6 +35,7 @@ const memoryDashboardStore = {
|
|
| 29 |
|
| 30 |
// Stats
|
| 31 |
totalCount: 0,
|
|
|
|
| 32 |
knowledgeCount: 0,
|
| 33 |
conversationCount: 0,
|
| 34 |
areasCount: {},
|
|
@@ -147,13 +154,25 @@ const memoryDashboardStore = {
|
|
| 147 |
limit: this.limit
|
| 148 |
});
|
| 149 |
|
| 150 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 151 |
// Add selected property to each memory item for mass selection
|
| 152 |
this.memories = (response.memories || []).map(memory => ({
|
| 153 |
...memory,
|
| 154 |
-
selected: memory.
|
| 155 |
}));
|
| 156 |
this.totalCount = response.total_count || 0;
|
|
|
|
| 157 |
this.knowledgeCount = response.knowledge_count || 0;
|
| 158 |
this.conversationCount = response.conversation_count || 0;
|
| 159 |
this.areasCount = response.areas_count || {};
|
|
@@ -290,16 +309,16 @@ const memoryDashboardStore = {
|
|
| 290 |
});
|
| 291 |
|
| 292 |
if (response.success) {
|
| 293 |
-
|
| 294 |
|
| 295 |
// Let polling refresh the data instead of manual manipulation
|
| 296 |
// Trigger an immediate refresh to get updated state from backend
|
| 297 |
await this.searchMemories(true); // silent refresh
|
| 298 |
} else {
|
| 299 |
-
|
| 300 |
}
|
| 301 |
} catch (error) {
|
| 302 |
-
|
| 303 |
} finally {
|
| 304 |
this.loading = false;
|
| 305 |
}
|
|
@@ -337,7 +356,7 @@ ${memory.content_full}
|
|
| 337 |
const content = selectedMemories.map(memory => this.formatMemoryForCopy(memory)).join('\n');
|
| 338 |
|
| 339 |
this.copyToClipboard(content);
|
| 340 |
-
|
| 341 |
},
|
| 342 |
|
| 343 |
bulkExportMemories() {
|
|
@@ -375,7 +394,7 @@ ${memory.content_full}
|
|
| 375 |
document.body.removeChild(a);
|
| 376 |
URL.revokeObjectURL(url);
|
| 377 |
|
| 378 |
-
|
| 379 |
},
|
| 380 |
|
| 381 |
// Memory detail modal (standard approach)
|
|
@@ -431,18 +450,18 @@ ${memory.content_full}
|
|
| 431 |
|
| 432 |
getAreaColor(area) {
|
| 433 |
const colors = {
|
| 434 |
-
"
|
| 435 |
-
"
|
| 436 |
-
"
|
| 437 |
-
"
|
| 438 |
};
|
| 439 |
-
return colors[area] || "#
|
| 440 |
},
|
| 441 |
|
| 442 |
copyToClipboard(text) {
|
| 443 |
if (navigator.clipboard && window.isSecureContext) {
|
| 444 |
navigator.clipboard.writeText(text).then(() => {
|
| 445 |
-
|
| 446 |
}).catch(err => {
|
| 447 |
console.error("Clipboard copy failed:", err);
|
| 448 |
this.fallbackCopyToClipboard(text);
|
|
@@ -463,10 +482,10 @@ ${memory.content_full}
|
|
| 463 |
textArea.select();
|
| 464 |
try {
|
| 465 |
document.execCommand('copy');
|
| 466 |
-
|
| 467 |
} catch (err) {
|
| 468 |
console.error("Fallback clipboard copy failed:", err);
|
| 469 |
-
|
| 470 |
}
|
| 471 |
document.body.removeChild(textArea);
|
| 472 |
},
|
|
@@ -487,7 +506,7 @@ ${memory.content_full}
|
|
| 487 |
});
|
| 488 |
|
| 489 |
if (response.success) {
|
| 490 |
-
|
| 491 |
|
| 492 |
// If we were viewing this memory in detail modal, close it
|
| 493 |
if (isViewingThisMemory) {
|
|
@@ -499,17 +518,17 @@ ${memory.content_full}
|
|
| 499 |
// Trigger an immediate refresh to get updated state from backend
|
| 500 |
await this.searchMemories(true); // silent refresh
|
| 501 |
} else {
|
| 502 |
-
|
| 503 |
}
|
| 504 |
} catch (error) {
|
| 505 |
console.error("Memory deletion error:", error);
|
| 506 |
-
|
| 507 |
}
|
| 508 |
},
|
| 509 |
|
| 510 |
exportMemories() {
|
| 511 |
if (this.memories.length === 0) {
|
| 512 |
-
|
| 513 |
return;
|
| 514 |
}
|
| 515 |
|
|
@@ -541,10 +560,10 @@ ${memory.content_full}
|
|
| 541 |
document.body.removeChild(a);
|
| 542 |
URL.revokeObjectURL(url);
|
| 543 |
|
| 544 |
-
|
| 545 |
} catch (error) {
|
| 546 |
console.error("Memory export error:", error);
|
| 547 |
-
|
| 548 |
}
|
| 549 |
},
|
| 550 |
|
|
@@ -574,6 +593,7 @@ ${memory.content_full}
|
|
| 574 |
this.searchQuery = "";
|
| 575 |
this.memories = [];
|
| 576 |
this.totalCount = 0;
|
|
|
|
| 577 |
this.knowledgeCount = 0;
|
| 578 |
this.conversationCount = 0;
|
| 579 |
this.areasCount = {};
|
|
@@ -581,14 +601,7 @@ ${memory.content_full}
|
|
| 581 |
this.currentPage = 1;
|
| 582 |
},
|
| 583 |
|
| 584 |
-
|
| 585 |
-
// Use global toast function if available
|
| 586 |
-
if (typeof toast === 'function') {
|
| 587 |
-
toast(message, type);
|
| 588 |
-
} else {
|
| 589 |
-
console.log(`[${type.toUpperCase()}] ${message}`);
|
| 590 |
-
}
|
| 591 |
-
}
|
| 592 |
};
|
| 593 |
|
| 594 |
const store = createStore("memoryDashboardStore", memoryDashboardStore);
|
|
|
|
| 2 |
import { getContext } from "/index.js";
|
| 3 |
import * as API from "/js/api.js";
|
| 4 |
import { openModal, closeModal } from "/js/modals.js";
|
| 5 |
+
import { store as notificationStore } from "/components/notifications/notification-store.js";
|
| 6 |
+
|
| 7 |
+
// Helper function for toasts
|
| 8 |
+
function justToast(text, type = "info", timeout = 5000) {
|
| 9 |
+
notificationStore.addFrontendToastOnly(type, text, "", timeout / 1000);
|
| 10 |
+
}
|
| 11 |
|
| 12 |
// Memory Dashboard Store
|
| 13 |
const memoryDashboardStore = {
|
|
|
|
| 35 |
|
| 36 |
// Stats
|
| 37 |
totalCount: 0,
|
| 38 |
+
totalDbCount: 0,
|
| 39 |
knowledgeCount: 0,
|
| 40 |
conversationCount: 0,
|
| 41 |
areasCount: {},
|
|
|
|
| 154 |
limit: this.limit
|
| 155 |
});
|
| 156 |
|
| 157 |
+
if (response.success) {
|
| 158 |
+
// Preserve existing selections when updating memories during polling
|
| 159 |
+
const existingSelections = {};
|
| 160 |
+
if (silent && this.memories) {
|
| 161 |
+
// Build a map of existing selections by memory ID
|
| 162 |
+
this.memories.forEach(memory => {
|
| 163 |
+
if (memory.selected) {
|
| 164 |
+
existingSelections[memory.id] = true;
|
| 165 |
+
}
|
| 166 |
+
});
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
// Add selected property to each memory item for mass selection
|
| 170 |
this.memories = (response.memories || []).map(memory => ({
|
| 171 |
...memory,
|
| 172 |
+
selected: existingSelections[memory.id] || false
|
| 173 |
}));
|
| 174 |
this.totalCount = response.total_count || 0;
|
| 175 |
+
this.totalDbCount = response.total_db_count || 0;
|
| 176 |
this.knowledgeCount = response.knowledge_count || 0;
|
| 177 |
this.conversationCount = response.conversation_count || 0;
|
| 178 |
this.areasCount = response.areas_count || {};
|
|
|
|
| 309 |
});
|
| 310 |
|
| 311 |
if (response.success) {
|
| 312 |
+
justToast(`Successfully deleted ${selectedMemories.length} memories`, "success");
|
| 313 |
|
| 314 |
// Let polling refresh the data instead of manual manipulation
|
| 315 |
// Trigger an immediate refresh to get updated state from backend
|
| 316 |
await this.searchMemories(true); // silent refresh
|
| 317 |
} else {
|
| 318 |
+
justToast(response.error || "Failed to delete selected memories", "error");
|
| 319 |
}
|
| 320 |
} catch (error) {
|
| 321 |
+
justToast(error.message || "Failed to delete selected memories", "error");
|
| 322 |
} finally {
|
| 323 |
this.loading = false;
|
| 324 |
}
|
|
|
|
| 356 |
const content = selectedMemories.map(memory => this.formatMemoryForCopy(memory)).join('\n');
|
| 357 |
|
| 358 |
this.copyToClipboard(content);
|
| 359 |
+
justToast(`Copied ${selectedMemories.length} memories with metadata to clipboard`, "success");
|
| 360 |
},
|
| 361 |
|
| 362 |
bulkExportMemories() {
|
|
|
|
| 394 |
document.body.removeChild(a);
|
| 395 |
URL.revokeObjectURL(url);
|
| 396 |
|
| 397 |
+
justToast(`Exported ${selectedMemories.length} selected memories to ${filename}`, "success");
|
| 398 |
},
|
| 399 |
|
| 400 |
// Memory detail modal (standard approach)
|
|
|
|
| 450 |
|
| 451 |
getAreaColor(area) {
|
| 452 |
const colors = {
|
| 453 |
+
"main": "#3b82f6",
|
| 454 |
+
"fragments": "#10b981",
|
| 455 |
+
"solutions": "#8b5cf6",
|
| 456 |
+
"instruments": "#f59e0b"
|
| 457 |
};
|
| 458 |
+
return colors[area] || "#6c757d";
|
| 459 |
},
|
| 460 |
|
| 461 |
copyToClipboard(text) {
|
| 462 |
if (navigator.clipboard && window.isSecureContext) {
|
| 463 |
navigator.clipboard.writeText(text).then(() => {
|
| 464 |
+
justToast("Copied to clipboard!", "success");
|
| 465 |
}).catch(err => {
|
| 466 |
console.error("Clipboard copy failed:", err);
|
| 467 |
this.fallbackCopyToClipboard(text);
|
|
|
|
| 482 |
textArea.select();
|
| 483 |
try {
|
| 484 |
document.execCommand('copy');
|
| 485 |
+
justToast("Copied to clipboard!", "success");
|
| 486 |
} catch (err) {
|
| 487 |
console.error("Fallback clipboard copy failed:", err);
|
| 488 |
+
justToast("Failed to copy to clipboard", "error");
|
| 489 |
}
|
| 490 |
document.body.removeChild(textArea);
|
| 491 |
},
|
|
|
|
| 506 |
});
|
| 507 |
|
| 508 |
if (response.success) {
|
| 509 |
+
justToast("Memory deleted successfully", "success");
|
| 510 |
|
| 511 |
// If we were viewing this memory in detail modal, close it
|
| 512 |
if (isViewingThisMemory) {
|
|
|
|
| 518 |
// Trigger an immediate refresh to get updated state from backend
|
| 519 |
await this.searchMemories(true); // silent refresh
|
| 520 |
} else {
|
| 521 |
+
justToast(`Failed to delete memory: ${response.error}`, "error");
|
| 522 |
}
|
| 523 |
} catch (error) {
|
| 524 |
console.error("Memory deletion error:", error);
|
| 525 |
+
justToast("Failed to delete memory", "error");
|
| 526 |
}
|
| 527 |
},
|
| 528 |
|
| 529 |
exportMemories() {
|
| 530 |
if (this.memories.length === 0) {
|
| 531 |
+
justToast("No memories to export", "warning");
|
| 532 |
return;
|
| 533 |
}
|
| 534 |
|
|
|
|
| 560 |
document.body.removeChild(a);
|
| 561 |
URL.revokeObjectURL(url);
|
| 562 |
|
| 563 |
+
justToast("Memory export completed", "success");
|
| 564 |
} catch (error) {
|
| 565 |
console.error("Memory export error:", error);
|
| 566 |
+
justToast("Failed to export memories", "error");
|
| 567 |
}
|
| 568 |
},
|
| 569 |
|
|
|
|
| 593 |
this.searchQuery = "";
|
| 594 |
this.memories = [];
|
| 595 |
this.totalCount = 0;
|
| 596 |
+
this.totalDbCount = 0;
|
| 597 |
this.knowledgeCount = 0;
|
| 598 |
this.conversationCount = 0;
|
| 599 |
this.areasCount = {};
|
|
|
|
| 601 |
this.currentPage = 1;
|
| 602 |
},
|
| 603 |
|
| 604 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 605 |
};
|
| 606 |
|
| 607 |
const store = createStore("memoryDashboardStore", memoryDashboardStore);
|
|
@@ -1,29 +1,39 @@
|
|
| 1 |
-
<
|
| 2 |
-
|
| 3 |
-
</
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
<div x-data>
|
| 6 |
<template x-if="$store.memoryDashboardStore">
|
| 7 |
-
<div x-init="
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
<!-- Search and Filters -->
|
| 29 |
<div class="filters-section">
|
|
@@ -45,10 +55,10 @@
|
|
| 45 |
<label for="area-filter">Area:</label>
|
| 46 |
<select id="area-filter" x-model="$store.memoryDashboardStore.areaFilter">
|
| 47 |
<option value="">All Areas</option>
|
| 48 |
-
<option value="
|
| 49 |
-
<option value="
|
| 50 |
-
<option value="
|
| 51 |
-
<option value="
|
| 52 |
</select>
|
| 53 |
</div>
|
| 54 |
|
|
@@ -95,33 +105,55 @@
|
|
| 95 |
<div x-show="!$store.memoryDashboardStore.loading && !$store.memoryDashboardStore.error"
|
| 96 |
class="memory-table-container">
|
| 97 |
|
| 98 |
-
<!--
|
| 99 |
-
<div class="pagination-
|
| 100 |
-
<
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
</div>
|
| 106 |
|
| 107 |
-
<
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
| 111 |
-
|
| 112 |
-
|
| 113 |
-
<
|
| 114 |
-
|
| 115 |
-
|
| 116 |
-
<
|
| 117 |
-
|
| 118 |
-
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
|
| 124 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 125 |
</div>
|
| 126 |
</div>
|
| 127 |
|
|
@@ -186,7 +218,7 @@
|
|
| 186 |
</th>
|
| 187 |
<th class="col-metadata">Metadata</th>
|
| 188 |
<th class="col-preview">Preview</th>
|
| 189 |
-
<th class="col-actions">
|
| 190 |
</tr>
|
| 191 |
</thead>
|
| 192 |
<tbody>
|
|
@@ -204,9 +236,9 @@
|
|
| 204 |
<td class="metadata-cell">
|
| 205 |
<div class="metadata-info">
|
| 206 |
<div class="metadata-row">
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
|
| 210 |
</div>
|
| 211 |
<div class="metadata-row metadata-timestamp">
|
| 212 |
<span x-text="$store.memoryDashboardStore.formatTimestamp(memory.timestamp, true)"
|
|
@@ -214,10 +246,10 @@
|
|
| 214 |
</div>
|
| 215 |
<div class="metadata-row">
|
| 216 |
<template x-if="memory.knowledge_source">
|
| 217 |
-
<span class="source-type knowledge">
|
| 218 |
</template>
|
| 219 |
<template x-if="!memory.knowledge_source">
|
| 220 |
-
<span class="source-type conversation">
|
| 221 |
</template>
|
| 222 |
</div>
|
| 223 |
</div>
|
|
@@ -235,58 +267,32 @@
|
|
| 235 |
|
| 236 |
<!-- Actions -->
|
| 237 |
<td class="actions-cell" @click.stop>
|
| 238 |
-
<
|
| 239 |
-
|
| 240 |
-
|
| 241 |
-
<
|
| 242 |
-
|
| 243 |
-
|
| 244 |
-
|
| 245 |
-
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
| 249 |
-
<
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
-
|
| 254 |
-
|
|
|
|
|
|
|
| 255 |
</td>
|
| 256 |
</tr>
|
| 257 |
</template>
|
| 258 |
</tbody>
|
| 259 |
</table>
|
| 260 |
|
| 261 |
-
<!-- Pagination controls at bottom -->
|
| 262 |
-
<div class="pagination-controls-bottom" x-show="$store.memoryDashboardStore.totalPages > 1">
|
| 263 |
-
<div class="pagination-info-inline">
|
| 264 |
-
<span>Page <span x-text="$store.memoryDashboardStore.currentPage"></span>
|
| 265 |
-
of <span x-text="$store.memoryDashboardStore.totalPages"></span>
|
| 266 |
-
(<span x-text="$store.memoryDashboardStore.memories.length"></span> total memories)
|
| 267 |
-
</span>
|
| 268 |
-
</div>
|
| 269 |
|
| 270 |
-
<div class="pagination-controls">
|
| 271 |
-
<button class="btn slim" @click="$store.memoryDashboardStore.prevPage()"
|
| 272 |
-
:disabled="$store.memoryDashboardStore.currentPage === 1">
|
| 273 |
-
Previous
|
| 274 |
-
</button>
|
| 275 |
-
|
| 276 |
-
<select class="page-select"
|
| 277 |
-
x-model.number="$store.memoryDashboardStore.currentPage"
|
| 278 |
-
@change="$store.memoryDashboardStore.goToPage($store.memoryDashboardStore.currentPage)">
|
| 279 |
-
<template x-for="page in Array.from({length: $store.memoryDashboardStore.totalPages}, (_, i) => i + 1)" :key="page">
|
| 280 |
-
<option :value="page" x-text="'Page ' + page"></option>
|
| 281 |
-
</template>
|
| 282 |
-
</select>
|
| 283 |
-
|
| 284 |
-
<button class="btn slim" @click="$store.memoryDashboardStore.nextPage()"
|
| 285 |
-
:disabled="$store.memoryDashboardStore.currentPage === $store.memoryDashboardStore.totalPages">
|
| 286 |
-
Next
|
| 287 |
-
</button>
|
| 288 |
-
</div>
|
| 289 |
-
</div>
|
| 290 |
|
| 291 |
</div>
|
| 292 |
|
|
@@ -328,18 +334,38 @@
|
|
| 328 |
color: var(--color-text);
|
| 329 |
}
|
| 330 |
|
| 331 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 332 |
display: flex;
|
| 333 |
justify-content: space-between;
|
| 334 |
align-items: center;
|
| 335 |
-
|
| 336 |
-
|
| 337 |
-
border
|
|
|
|
|
|
|
|
|
|
|
|
|
| 338 |
}
|
| 339 |
|
| 340 |
-
.memory-stats {
|
| 341 |
display: flex;
|
| 342 |
gap: 1rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 343 |
}
|
| 344 |
|
| 345 |
.stat-item {
|
|
@@ -355,10 +381,15 @@
|
|
| 355 |
|
| 356 |
.stat-label {
|
| 357 |
font-size: 0.8rem;
|
| 358 |
-
color: var(--color-
|
|
|
|
| 359 |
margin-bottom: 0.25rem;
|
| 360 |
}
|
| 361 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 362 |
.stat-value {
|
| 363 |
font-size: 1.1rem;
|
| 364 |
font-weight: bold;
|
|
@@ -407,7 +438,13 @@
|
|
| 407 |
.filter-group input:focus, .filter-group select:focus {
|
| 408 |
outline: none;
|
| 409 |
border-color: var(--color-primary);
|
| 410 |
-
box-shadow: 0 0 0 2px rgba(115, 122, 129, 0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 411 |
}
|
| 412 |
|
| 413 |
.filter-actions {
|
|
@@ -425,14 +462,16 @@
|
|
| 425 |
|
| 426 |
.loading-text {
|
| 427 |
font-size: 0.85rem;
|
| 428 |
-
color: var(--color-
|
|
|
|
| 429 |
font-style: italic;
|
| 430 |
}
|
| 431 |
|
| 432 |
.loading-state, .error-state, .no-memories, .init-message {
|
| 433 |
text-align: center;
|
| 434 |
padding: 2rem;
|
| 435 |
-
color: var(--color-
|
|
|
|
| 436 |
background: var(--color-panel);
|
| 437 |
border: 1px solid var(--color-border);
|
| 438 |
border-radius: 8px;
|
|
@@ -441,24 +480,41 @@
|
|
| 441 |
|
| 442 |
.init-message {
|
| 443 |
color: var(--color-primary);
|
| 444 |
-
background: rgba(115, 122, 129, 0.
|
| 445 |
border-color: var(--color-primary);
|
| 446 |
}
|
| 447 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 448 |
.error-state {
|
| 449 |
color: var(--color-accent);
|
| 450 |
-
background: rgba(207, 102, 121, 0.
|
| 451 |
border-color: var(--color-accent);
|
| 452 |
}
|
| 453 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 454 |
.loading-spinner {
|
| 455 |
-
width:
|
| 456 |
-
height:
|
| 457 |
-
|
| 458 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 459 |
border-radius: 50%;
|
| 460 |
animation: spin 1s linear infinite;
|
| 461 |
margin: 0 auto 0.5rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 462 |
}
|
| 463 |
|
| 464 |
@keyframes spin {
|
|
@@ -487,8 +543,8 @@
|
|
| 487 |
/* Fixed column widths for proper fit */
|
| 488 |
.col-select { width: 5%; }
|
| 489 |
.col-metadata { width: 25%; }
|
| 490 |
-
.col-preview { width:
|
| 491 |
-
.col-actions { width:
|
| 492 |
|
| 493 |
.memory-table th,
|
| 494 |
.memory-table td {
|
|
@@ -544,12 +600,12 @@
|
|
| 544 |
|
| 545 |
/* Selected row styling */
|
| 546 |
.memory-row.selected {
|
| 547 |
-
background: rgba(115, 122, 129, 0.
|
| 548 |
border-left: 3px solid var(--color-primary);
|
| 549 |
}
|
| 550 |
|
| 551 |
.light-mode .memory-row.selected {
|
| 552 |
-
background: rgba(
|
| 553 |
}
|
| 554 |
|
| 555 |
/* Mass action toolbar */
|
|
@@ -558,7 +614,7 @@
|
|
| 558 |
justify-content: space-between;
|
| 559 |
align-items: center;
|
| 560 |
padding: 1rem;
|
| 561 |
-
background: rgba(115, 122, 129, 0.
|
| 562 |
border: 1px solid var(--color-primary);
|
| 563 |
border-radius: 8px;
|
| 564 |
margin: 1rem 0;
|
|
@@ -566,7 +622,7 @@
|
|
| 566 |
}
|
| 567 |
|
| 568 |
.light-mode .mass-action-toolbar {
|
| 569 |
-
background: rgba(
|
| 570 |
}
|
| 571 |
|
| 572 |
.selection-info {
|
|
@@ -596,27 +652,27 @@
|
|
| 596 |
|
| 597 |
.btn-mass:hover {
|
| 598 |
border-color: var(--color-primary);
|
| 599 |
-
background:
|
| 600 |
}
|
| 601 |
|
| 602 |
.btn-mass.copy:hover {
|
| 603 |
-
border-color:
|
| 604 |
-
color:
|
| 605 |
}
|
| 606 |
|
| 607 |
.btn-mass.export:hover {
|
| 608 |
-
border-color:
|
| 609 |
-
color:
|
| 610 |
}
|
| 611 |
|
| 612 |
.btn-mass.delete:hover {
|
| 613 |
-
border-color:
|
| 614 |
-
color:
|
| 615 |
}
|
| 616 |
|
| 617 |
.btn-mass.clear:hover {
|
| 618 |
-
border-color:
|
| 619 |
-
color:
|
| 620 |
}
|
| 621 |
|
| 622 |
@keyframes slideDown {
|
|
@@ -650,7 +706,7 @@
|
|
| 650 |
}
|
| 651 |
|
| 652 |
.memory-table tbody tr:hover {
|
| 653 |
-
background:
|
| 654 |
}
|
| 655 |
|
| 656 |
.memory-table tbody tr:last-child {
|
|
@@ -663,12 +719,19 @@
|
|
| 663 |
color: white;
|
| 664 |
font-size: 0.75rem;
|
| 665 |
font-weight: bold;
|
| 666 |
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 667 |
}
|
| 668 |
|
| 669 |
.timestamp-cell {
|
| 670 |
font-size: 0.85rem;
|
| 671 |
-
color: var(--color-
|
|
|
|
| 672 |
white-space: normal;
|
| 673 |
word-break: break-word;
|
| 674 |
font-family: monospace;
|
|
@@ -694,20 +757,33 @@
|
|
| 694 |
}
|
| 695 |
|
| 696 |
.source-type.knowledge {
|
| 697 |
-
background: rgba(115, 122, 129, 0.
|
| 698 |
color: var(--color-primary);
|
| 699 |
border-color: var(--color-primary);
|
| 700 |
}
|
| 701 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 702 |
.source-type.conversation {
|
| 703 |
-
background: rgba(101, 101, 101, 0.
|
| 704 |
-
color: var(--color-
|
| 705 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 706 |
}
|
| 707 |
|
| 708 |
.source-file {
|
| 709 |
font-size: 0.7rem;
|
| 710 |
-
color: var(--color-
|
|
|
|
| 711 |
font-family: monospace;
|
| 712 |
background: var(--color-panel);
|
| 713 |
padding: 0.2rem 0.4rem;
|
|
@@ -743,14 +819,35 @@
|
|
| 743 |
padding: 0.2rem 0.4rem;
|
| 744 |
border-radius: 6px;
|
| 745 |
font-size: 0.7rem;
|
| 746 |
-
color: var(--color-
|
|
|
|
| 747 |
}
|
| 748 |
|
| 749 |
.actions-cell {
|
| 750 |
-
|
| 751 |
-
|
| 752 |
-
|
| 753 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 754 |
}
|
| 755 |
|
| 756 |
.btn-action {
|
|
@@ -760,7 +857,8 @@
|
|
| 760 |
margin: 0 0.1rem;
|
| 761 |
cursor: pointer;
|
| 762 |
border-radius: 6px;
|
| 763 |
-
color: var(--color-
|
|
|
|
| 764 |
transition: all 0.2s ease;
|
| 765 |
display: inline-flex;
|
| 766 |
align-items: center;
|
|
@@ -770,56 +868,43 @@
|
|
| 770 |
}
|
| 771 |
|
| 772 |
.btn-action:hover {
|
| 773 |
-
|
| 774 |
-
|
| 775 |
-
color: var(--color-
|
|
|
|
| 776 |
transform: translateY(-1px);
|
| 777 |
}
|
| 778 |
|
| 779 |
.btn-action.view:hover {
|
| 780 |
-
background:
|
| 781 |
-
border-color:
|
| 782 |
-
color:
|
| 783 |
}
|
| 784 |
|
| 785 |
.btn-action.copy:hover {
|
| 786 |
-
background:
|
| 787 |
-
border-color:
|
| 788 |
-
color:
|
| 789 |
}
|
| 790 |
|
| 791 |
.btn-action.delete:hover {
|
| 792 |
-
background: rgba(244, 67, 54, 0.1);
|
| 793 |
-
border-color: #f44336;
|
| 794 |
-
color: #f44336;
|
| 795 |
-
}
|
| 796 |
-
|
| 797 |
-
.pagination-controls-top {
|
| 798 |
-
display: flex;
|
| 799 |
-
justify-content: space-between;
|
| 800 |
-
align-items: center;
|
| 801 |
-
margin-bottom: 1rem;
|
| 802 |
-
padding: 1rem;
|
| 803 |
background: var(--color-panel);
|
| 804 |
-
border:
|
| 805 |
-
|
| 806 |
}
|
| 807 |
|
|
|
|
|
|
|
| 808 |
.pagination-info-inline {
|
| 809 |
-
color: var(--color-
|
|
|
|
| 810 |
font-size: 0.9rem;
|
| 811 |
}
|
| 812 |
|
| 813 |
.pagination-controls {
|
| 814 |
display: flex;
|
| 815 |
-
justify-content: center;
|
| 816 |
align-items: center;
|
| 817 |
gap: 0.5rem;
|
| 818 |
-
margin: 1rem 0;
|
| 819 |
-
padding: 1rem;
|
| 820 |
-
background: var(--color-panel);
|
| 821 |
-
border: 1px solid var(--color-border);
|
| 822 |
-
border-radius: 8px;
|
| 823 |
}
|
| 824 |
|
| 825 |
.page-select {
|
|
@@ -836,22 +921,15 @@
|
|
| 836 |
.page-select:focus {
|
| 837 |
outline: none;
|
| 838 |
border-color: var(--color-primary);
|
| 839 |
-
box-shadow: 0 0 0 2px rgba(115, 122, 129, 0.
|
|
|
|
| 840 |
}
|
| 841 |
|
| 842 |
-
.
|
| 843 |
-
|
| 844 |
-
justify-content: space-between;
|
| 845 |
-
align-items: center;
|
| 846 |
-
padding: 1rem;
|
| 847 |
-
background: var(--color-panel);
|
| 848 |
-
border-bottom: 1px solid var(--color-border);
|
| 849 |
}
|
| 850 |
|
| 851 |
-
|
| 852 |
-
border-top: 1px solid var(--color-border);
|
| 853 |
-
border-bottom: none;
|
| 854 |
-
}
|
| 855 |
|
| 856 |
.export-section {
|
| 857 |
text-align: center;
|
|
@@ -979,7 +1057,8 @@
|
|
| 979 |
.timestamp-badge {
|
| 980 |
background: var(--color-panel);
|
| 981 |
border: 1px solid var(--color-border);
|
| 982 |
-
color: var(--color-
|
|
|
|
| 983 |
padding: 0.25rem 0.75rem;
|
| 984 |
border-radius: 12px;
|
| 985 |
font-size: 0.8rem;
|
|
@@ -1002,8 +1081,9 @@
|
|
| 1002 |
|
| 1003 |
.source-badge.conversation {
|
| 1004 |
background: rgba(101, 101, 101, 0.1);
|
| 1005 |
-
color: var(--color-
|
| 1006 |
-
|
|
|
|
| 1007 |
}
|
| 1008 |
|
| 1009 |
.header-actions {
|
|
@@ -1189,17 +1269,22 @@
|
|
| 1189 |
padding: 0.5rem;
|
| 1190 |
}
|
| 1191 |
|
| 1192 |
-
.
|
| 1193 |
flex-direction: column;
|
| 1194 |
align-items: flex-start;
|
| 1195 |
gap: 1rem;
|
| 1196 |
}
|
| 1197 |
|
| 1198 |
-
.memory-stats {
|
| 1199 |
width: 100%;
|
| 1200 |
justify-content: space-between;
|
| 1201 |
}
|
| 1202 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1203 |
.filter-row {
|
| 1204 |
flex-direction: column;
|
| 1205 |
align-items: stretch;
|
|
@@ -1217,14 +1302,14 @@
|
|
| 1217 |
}
|
| 1218 |
|
| 1219 |
.actions-cell {
|
| 1220 |
-
min-width:
|
|
|
|
| 1221 |
}
|
| 1222 |
|
| 1223 |
-
.col-
|
| 1224 |
-
.col-
|
| 1225 |
-
.col-
|
| 1226 |
-
.col-
|
| 1227 |
-
.col-actions { width: 20%; }
|
| 1228 |
|
| 1229 |
.memory-detail-modal {
|
| 1230 |
width: 98%;
|
|
@@ -1258,20 +1343,10 @@
|
|
| 1258 |
padding: 1rem;
|
| 1259 |
}
|
| 1260 |
|
| 1261 |
-
.pagination-controls-top {
|
| 1262 |
-
flex-direction: column;
|
| 1263 |
-
gap: 1rem;
|
| 1264 |
-
align-items: stretch;
|
| 1265 |
-
}
|
| 1266 |
|
| 1267 |
-
.pagination-controls {
|
| 1268 |
-
flex-wrap: wrap;
|
| 1269 |
-
justify-content: center;
|
| 1270 |
-
}
|
| 1271 |
|
| 1272 |
-
.
|
| 1273 |
flex-wrap: wrap;
|
| 1274 |
-
justify-content: center;
|
| 1275 |
}
|
| 1276 |
}
|
| 1277 |
|
|
@@ -1324,8 +1399,9 @@
|
|
| 1324 |
|
| 1325 |
.source-badge.conversation {
|
| 1326 |
background: rgba(101, 101, 101, 0.1);
|
| 1327 |
-
color: var(--color-
|
| 1328 |
-
|
|
|
|
| 1329 |
}
|
| 1330 |
|
| 1331 |
.header-actions {
|
|
@@ -1423,7 +1499,8 @@
|
|
| 1423 |
|
| 1424 |
.metadata-group h5 {
|
| 1425 |
margin: 0 0 0.75rem 0;
|
| 1426 |
-
color: var(--color-
|
|
|
|
| 1427 |
font-size: 0.9rem;
|
| 1428 |
font-weight: 600;
|
| 1429 |
text-transform: uppercase;
|
|
@@ -1444,7 +1521,8 @@
|
|
| 1444 |
.metadata-label {
|
| 1445 |
font-size: 0.8rem;
|
| 1446 |
font-weight: 600;
|
| 1447 |
-
color: var(--color-
|
|
|
|
| 1448 |
text-transform: uppercase;
|
| 1449 |
letter-spacing: 0.3px;
|
| 1450 |
}
|
|
@@ -1528,4 +1606,5 @@
|
|
| 1528 |
|
| 1529 |
</template>
|
| 1530 |
</div>
|
| 1531 |
-
</
|
|
|
|
|
|
| 1 |
+
<html>
|
| 2 |
+
<head>
|
| 3 |
+
<title>Memory Dashboard</title>
|
| 4 |
+
<script type="module">
|
| 5 |
+
import { store } from "/components/settings/memory/memory-dashboard-store.js";
|
| 6 |
+
</script>
|
| 7 |
+
</head>
|
| 8 |
+
<body>
|
| 9 |
<div x-data>
|
| 10 |
<template x-if="$store.memoryDashboardStore">
|
| 11 |
+
<div x-init="
|
| 12 |
+
$store.memoryDashboardStore.initialize();
|
| 13 |
+
|
| 14 |
+
// Setup cleanup when component is removed from DOM
|
| 15 |
+
const observer = new MutationObserver((mutations) => {
|
| 16 |
+
mutations.forEach((mutation) => {
|
| 17 |
+
if (mutation.type === 'childList') {
|
| 18 |
+
mutation.removedNodes.forEach((node) => {
|
| 19 |
+
if (node.contains && node.contains($el)) {
|
| 20 |
+
// Dashboard is being removed, cleanup polling
|
| 21 |
+
$store.memoryDashboardStore.cleanup();
|
| 22 |
+
observer.disconnect();
|
| 23 |
+
}
|
| 24 |
+
});
|
| 25 |
+
}
|
| 26 |
+
});
|
| 27 |
+
});
|
| 28 |
+
|
| 29 |
+
// Watch for DOM changes
|
| 30 |
+
observer.observe(document.body, {
|
| 31 |
+
childList: true,
|
| 32 |
+
subtree: true
|
| 33 |
+
});
|
| 34 |
+
" class="memory-dashboard">
|
| 35 |
+
|
| 36 |
+
|
| 37 |
|
| 38 |
<!-- Search and Filters -->
|
| 39 |
<div class="filters-section">
|
|
|
|
| 55 |
<label for="area-filter">Area:</label>
|
| 56 |
<select id="area-filter" x-model="$store.memoryDashboardStore.areaFilter">
|
| 57 |
<option value="">All Areas</option>
|
| 58 |
+
<option value="main">Main</option>
|
| 59 |
+
<option value="fragments">Fragments</option>
|
| 60 |
+
<option value="solutions">Solutions</option>
|
| 61 |
+
<option value="instruments">Instruments</option>
|
| 62 |
</select>
|
| 63 |
</div>
|
| 64 |
|
|
|
|
| 105 |
<div x-show="!$store.memoryDashboardStore.loading && !$store.memoryDashboardStore.error"
|
| 106 |
class="memory-table-container">
|
| 107 |
|
| 108 |
+
<!-- Combined stats and pagination header -->
|
| 109 |
+
<div class="stats-pagination-header" x-show="!$store.memoryDashboardStore.loading">
|
| 110 |
+
<!-- Statistics -->
|
| 111 |
+
<div class="memory-stats-compact">
|
| 112 |
+
<div class="stat-item">
|
| 113 |
+
<span class="stat-label">DB Total:</span>
|
| 114 |
+
<span class="stat-value" x-text="$store.memoryDashboardStore.totalDbCount"></span>
|
| 115 |
+
</div>
|
| 116 |
+
<div class="stat-item">
|
| 117 |
+
<span class="stat-label">Filtered:</span>
|
| 118 |
+
<span class="stat-value" x-text="$store.memoryDashboardStore.totalCount"></span>
|
| 119 |
+
</div>
|
| 120 |
+
<div class="stat-item">
|
| 121 |
+
<span class="stat-label">Knowledge:</span>
|
| 122 |
+
<span class="stat-value" x-text="$store.memoryDashboardStore.knowledgeCount"></span>
|
| 123 |
+
</div>
|
| 124 |
+
<div class="stat-item">
|
| 125 |
+
<span class="stat-label">Conversation:</span>
|
| 126 |
+
<span class="stat-value" x-text="$store.memoryDashboardStore.conversationCount"></span>
|
| 127 |
+
</div>
|
| 128 |
</div>
|
| 129 |
|
| 130 |
+
<!-- Pagination controls -->
|
| 131 |
+
<div class="pagination-controls-compact" x-show="$store.memoryDashboardStore.totalPages > 1">
|
| 132 |
+
<div class="pagination-info-inline">
|
| 133 |
+
<span>Page <span x-text="$store.memoryDashboardStore.currentPage"></span>
|
| 134 |
+
of <span x-text="$store.memoryDashboardStore.totalPages"></span>
|
| 135 |
+
</span>
|
| 136 |
+
</div>
|
| 137 |
+
|
| 138 |
+
<div class="pagination-controls">
|
| 139 |
+
<button class="btn slim" @click="$store.memoryDashboardStore.prevPage()"
|
| 140 |
+
:disabled="$store.memoryDashboardStore.currentPage === 1">
|
| 141 |
+
Previous
|
| 142 |
+
</button>
|
| 143 |
+
|
| 144 |
+
<select class="page-select"
|
| 145 |
+
x-model.number="$store.memoryDashboardStore.currentPage"
|
| 146 |
+
@change="$store.memoryDashboardStore.goToPage($store.memoryDashboardStore.currentPage)">
|
| 147 |
+
<template x-for="page in Array.from({length: $store.memoryDashboardStore.totalPages}, (_, i) => i + 1)" :key="page">
|
| 148 |
+
<option :value="page" x-text="'Page ' + page"></option>
|
| 149 |
+
</template>
|
| 150 |
+
</select>
|
| 151 |
+
|
| 152 |
+
<button class="btn slim" @click="$store.memoryDashboardStore.nextPage()"
|
| 153 |
+
:disabled="$store.memoryDashboardStore.currentPage === $store.memoryDashboardStore.totalPages">
|
| 154 |
+
Next
|
| 155 |
+
</button>
|
| 156 |
+
</div>
|
| 157 |
</div>
|
| 158 |
</div>
|
| 159 |
|
|
|
|
| 218 |
</th>
|
| 219 |
<th class="col-metadata">Metadata</th>
|
| 220 |
<th class="col-preview">Preview</th>
|
| 221 |
+
<th class="col-actions"></th>
|
| 222 |
</tr>
|
| 223 |
</thead>
|
| 224 |
<tbody>
|
|
|
|
| 236 |
<td class="metadata-cell">
|
| 237 |
<div class="metadata-info">
|
| 238 |
<div class="metadata-row">
|
| 239 |
+
<span class="area-badge"
|
| 240 |
+
:style="`background-color: ${$store.memoryDashboardStore.getAreaColor(memory.area)}`"
|
| 241 |
+
x-text="(memory.area || 'UNKNOWN').toUpperCase()"></span>
|
| 242 |
</div>
|
| 243 |
<div class="metadata-row metadata-timestamp">
|
| 244 |
<span x-text="$store.memoryDashboardStore.formatTimestamp(memory.timestamp, true)"
|
|
|
|
| 246 |
</div>
|
| 247 |
<div class="metadata-row">
|
| 248 |
<template x-if="memory.knowledge_source">
|
| 249 |
+
<span class="source-type knowledge">Knowledge</span>
|
| 250 |
</template>
|
| 251 |
<template x-if="!memory.knowledge_source">
|
| 252 |
+
<span class="source-type conversation">Conversation</span>
|
| 253 |
</template>
|
| 254 |
</div>
|
| 255 |
</div>
|
|
|
|
| 267 |
|
| 268 |
<!-- Actions -->
|
| 269 |
<td class="actions-cell" @click.stop>
|
| 270 |
+
<div class="actions-wrapper">
|
| 271 |
+
<button class="btn-action copy" @click="$store.memoryDashboardStore.copyToClipboard($store.memoryDashboardStore.formatMemoryForCopy(memory))"
|
| 272 |
+
title="Copy Memory">
|
| 273 |
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 274 |
+
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
| 275 |
+
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
| 276 |
+
</svg>
|
| 277 |
+
</button>
|
| 278 |
+
|
| 279 |
+
<button class="btn-action delete" @click="$store.memoryDashboardStore.deleteMemory(memory)"
|
| 280 |
+
title="Delete Memory">
|
| 281 |
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
| 282 |
+
<polyline points="3,6 5,6 21,6"></polyline>
|
| 283 |
+
<path d="M19,6V20a2,2,0,0,1-2,2H7a2,2,0,0,1-2-2V6M8,6V4a2,2,0,0,1,2-2h4a2,2,0,0,1,2,2V6"></path>
|
| 284 |
+
<line x1="10" y1="11" x2="10" y2="17"></line>
|
| 285 |
+
<line x1="14" y1="11" x2="14" y2="17"></line>
|
| 286 |
+
</svg>
|
| 287 |
+
</button>
|
| 288 |
+
</div>
|
| 289 |
</td>
|
| 290 |
</tr>
|
| 291 |
</template>
|
| 292 |
</tbody>
|
| 293 |
</table>
|
| 294 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 295 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 296 |
|
| 297 |
</div>
|
| 298 |
|
|
|
|
| 334 |
color: var(--color-text);
|
| 335 |
}
|
| 336 |
|
| 337 |
+
.memory-dashboard h3 {
|
| 338 |
+
color: var(--color-text);
|
| 339 |
+
margin: 0;
|
| 340 |
+
font-size: 1.5rem;
|
| 341 |
+
font-weight: 600;
|
| 342 |
+
}
|
| 343 |
+
|
| 344 |
+
|
| 345 |
+
|
| 346 |
+
.stats-pagination-header {
|
| 347 |
display: flex;
|
| 348 |
justify-content: space-between;
|
| 349 |
align-items: center;
|
| 350 |
+
padding: 1rem;
|
| 351 |
+
background: var(--color-panel);
|
| 352 |
+
border: 1px solid var(--color-border);
|
| 353 |
+
border-radius: 8px;
|
| 354 |
+
border-bottom: none;
|
| 355 |
+
border-bottom-left-radius: 0;
|
| 356 |
+
border-bottom-right-radius: 0;
|
| 357 |
}
|
| 358 |
|
| 359 |
+
.memory-stats-compact {
|
| 360 |
display: flex;
|
| 361 |
gap: 1rem;
|
| 362 |
+
flex-wrap: wrap;
|
| 363 |
+
}
|
| 364 |
+
|
| 365 |
+
.pagination-controls-compact {
|
| 366 |
+
display: flex;
|
| 367 |
+
align-items: center;
|
| 368 |
+
gap: 1rem;
|
| 369 |
}
|
| 370 |
|
| 371 |
.stat-item {
|
|
|
|
| 381 |
|
| 382 |
.stat-label {
|
| 383 |
font-size: 0.8rem;
|
| 384 |
+
color: var(--color-text);
|
| 385 |
+
opacity: 0.7;
|
| 386 |
margin-bottom: 0.25rem;
|
| 387 |
}
|
| 388 |
|
| 389 |
+
.light-mode .stat-label {
|
| 390 |
+
opacity: 0.8;
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
.stat-value {
|
| 394 |
font-size: 1.1rem;
|
| 395 |
font-weight: bold;
|
|
|
|
| 438 |
.filter-group input:focus, .filter-group select:focus {
|
| 439 |
outline: none;
|
| 440 |
border-color: var(--color-primary);
|
| 441 |
+
box-shadow: 0 0 0 2px rgba(115, 122, 129, 0.2);
|
| 442 |
+
background: var(--color-input-focus);
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
.light-mode .filter-group input:focus,
|
| 446 |
+
.light-mode .filter-group select:focus {
|
| 447 |
+
box-shadow: 0 0 0 2px rgba(56, 70, 83, 0.1);
|
| 448 |
}
|
| 449 |
|
| 450 |
.filter-actions {
|
|
|
|
| 462 |
|
| 463 |
.loading-text {
|
| 464 |
font-size: 0.85rem;
|
| 465 |
+
color: var(--color-text);
|
| 466 |
+
opacity: 0.7;
|
| 467 |
font-style: italic;
|
| 468 |
}
|
| 469 |
|
| 470 |
.loading-state, .error-state, .no-memories, .init-message {
|
| 471 |
text-align: center;
|
| 472 |
padding: 2rem;
|
| 473 |
+
color: var(--color-text);
|
| 474 |
+
opacity: 0.8;
|
| 475 |
background: var(--color-panel);
|
| 476 |
border: 1px solid var(--color-border);
|
| 477 |
border-radius: 8px;
|
|
|
|
| 480 |
|
| 481 |
.init-message {
|
| 482 |
color: var(--color-primary);
|
| 483 |
+
background: rgba(115, 122, 129, 0.2);
|
| 484 |
border-color: var(--color-primary);
|
| 485 |
}
|
| 486 |
|
| 487 |
+
.light-mode .init-message {
|
| 488 |
+
background: rgba(56, 70, 83, 0.1);
|
| 489 |
+
}
|
| 490 |
+
|
| 491 |
.error-state {
|
| 492 |
color: var(--color-accent);
|
| 493 |
+
background: rgba(207, 102, 121, 0.2);
|
| 494 |
border-color: var(--color-accent);
|
| 495 |
}
|
| 496 |
|
| 497 |
+
.light-mode .error-state {
|
| 498 |
+
background: rgba(176, 0, 32, 0.1);
|
| 499 |
+
}
|
| 500 |
+
|
| 501 |
.loading-spinner {
|
| 502 |
+
width: 24px;
|
| 503 |
+
height: 24px;
|
| 504 |
+
min-width: 24px;
|
| 505 |
+
min-height: 24px;
|
| 506 |
+
max-width: 24px;
|
| 507 |
+
max-height: 24px;
|
| 508 |
+
border: 3px solid var(--color-border);
|
| 509 |
+
border-top-color: var(--color-primary);
|
| 510 |
border-radius: 50%;
|
| 511 |
animation: spin 1s linear infinite;
|
| 512 |
margin: 0 auto 0.5rem;
|
| 513 |
+
flex-shrink: 0;
|
| 514 |
+
flex-grow: 0;
|
| 515 |
+
display: inline-block;
|
| 516 |
+
position: relative;
|
| 517 |
+
box-sizing: border-box;
|
| 518 |
}
|
| 519 |
|
| 520 |
@keyframes spin {
|
|
|
|
| 543 |
/* Fixed column widths for proper fit */
|
| 544 |
.col-select { width: 5%; }
|
| 545 |
.col-metadata { width: 25%; }
|
| 546 |
+
.col-preview { width: 60%; }
|
| 547 |
+
.col-actions { width: 10%; }
|
| 548 |
|
| 549 |
.memory-table th,
|
| 550 |
.memory-table td {
|
|
|
|
| 600 |
|
| 601 |
/* Selected row styling */
|
| 602 |
.memory-row.selected {
|
| 603 |
+
background: rgba(115, 122, 129, 0.2);
|
| 604 |
border-left: 3px solid var(--color-primary);
|
| 605 |
}
|
| 606 |
|
| 607 |
.light-mode .memory-row.selected {
|
| 608 |
+
background: rgba(56, 70, 83, 0.1);
|
| 609 |
}
|
| 610 |
|
| 611 |
/* Mass action toolbar */
|
|
|
|
| 614 |
justify-content: space-between;
|
| 615 |
align-items: center;
|
| 616 |
padding: 1rem;
|
| 617 |
+
background: rgba(115, 122, 129, 0.2);
|
| 618 |
border: 1px solid var(--color-primary);
|
| 619 |
border-radius: 8px;
|
| 620 |
margin: 1rem 0;
|
|
|
|
| 622 |
}
|
| 623 |
|
| 624 |
.light-mode .mass-action-toolbar {
|
| 625 |
+
background: rgba(56, 70, 83, 0.1);
|
| 626 |
}
|
| 627 |
|
| 628 |
.selection-info {
|
|
|
|
| 652 |
|
| 653 |
.btn-mass:hover {
|
| 654 |
border-color: var(--color-primary);
|
| 655 |
+
background: var(--color-panel);
|
| 656 |
}
|
| 657 |
|
| 658 |
.btn-mass.copy:hover {
|
| 659 |
+
border-color: var(--color-primary);
|
| 660 |
+
color: var(--color-primary);
|
| 661 |
}
|
| 662 |
|
| 663 |
.btn-mass.export:hover {
|
| 664 |
+
border-color: var(--color-primary);
|
| 665 |
+
color: var(--color-primary);
|
| 666 |
}
|
| 667 |
|
| 668 |
.btn-mass.delete:hover {
|
| 669 |
+
border-color: var(--color-accent);
|
| 670 |
+
color: var(--color-accent);
|
| 671 |
}
|
| 672 |
|
| 673 |
.btn-mass.clear:hover {
|
| 674 |
+
border-color: var(--color-primary);
|
| 675 |
+
color: var(--color-primary);
|
| 676 |
}
|
| 677 |
|
| 678 |
@keyframes slideDown {
|
|
|
|
| 706 |
}
|
| 707 |
|
| 708 |
.memory-table tbody tr:hover {
|
| 709 |
+
background: var(--color-panel);
|
| 710 |
}
|
| 711 |
|
| 712 |
.memory-table tbody tr:last-child {
|
|
|
|
| 719 |
color: white;
|
| 720 |
font-size: 0.75rem;
|
| 721 |
font-weight: bold;
|
| 722 |
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
| 723 |
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
| 724 |
+
}
|
| 725 |
+
|
| 726 |
+
.light-mode .area-badge {
|
| 727 |
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
|
| 728 |
+
border: 1px solid rgba(0, 0, 0, 0.1);
|
| 729 |
}
|
| 730 |
|
| 731 |
.timestamp-cell {
|
| 732 |
font-size: 0.85rem;
|
| 733 |
+
color: var(--color-text);
|
| 734 |
+
opacity: 0.7;
|
| 735 |
white-space: normal;
|
| 736 |
word-break: break-word;
|
| 737 |
font-family: monospace;
|
|
|
|
| 757 |
}
|
| 758 |
|
| 759 |
.source-type.knowledge {
|
| 760 |
+
background: rgba(115, 122, 129, 0.2);
|
| 761 |
color: var(--color-primary);
|
| 762 |
border-color: var(--color-primary);
|
| 763 |
}
|
| 764 |
|
| 765 |
+
.light-mode .source-type.knowledge {
|
| 766 |
+
background: rgba(56, 70, 83, 0.1);
|
| 767 |
+
color: var(--color-primary);
|
| 768 |
+
}
|
| 769 |
+
|
| 770 |
.source-type.conversation {
|
| 771 |
+
background: rgba(101, 101, 101, 0.2);
|
| 772 |
+
color: var(--color-text);
|
| 773 |
+
opacity: 0.8;
|
| 774 |
+
border-color: var(--color-border);
|
| 775 |
+
}
|
| 776 |
+
|
| 777 |
+
.light-mode .source-type.conversation {
|
| 778 |
+
background: rgba(232, 234, 246, 0.5);
|
| 779 |
+
color: var(--color-text);
|
| 780 |
+
opacity: 0.9;
|
| 781 |
}
|
| 782 |
|
| 783 |
.source-file {
|
| 784 |
font-size: 0.7rem;
|
| 785 |
+
color: var(--color-text);
|
| 786 |
+
opacity: 0.7;
|
| 787 |
font-family: monospace;
|
| 788 |
background: var(--color-panel);
|
| 789 |
padding: 0.2rem 0.4rem;
|
|
|
|
| 819 |
padding: 0.2rem 0.4rem;
|
| 820 |
border-radius: 6px;
|
| 821 |
font-size: 0.7rem;
|
| 822 |
+
color: var(--color-text);
|
| 823 |
+
opacity: 0.8;
|
| 824 |
}
|
| 825 |
|
| 826 |
.actions-cell {
|
| 827 |
+
min-width: 60px;
|
| 828 |
+
width: 60px;
|
| 829 |
+
padding: 0 !important;
|
| 830 |
+
height: 60px;
|
| 831 |
+
position: relative;
|
| 832 |
+
}
|
| 833 |
+
|
| 834 |
+
.actions-wrapper {
|
| 835 |
+
position: absolute;
|
| 836 |
+
top: 0;
|
| 837 |
+
left: 0;
|
| 838 |
+
right: 0;
|
| 839 |
+
bottom: 0;
|
| 840 |
+
display: flex;
|
| 841 |
+
flex-direction: column;
|
| 842 |
+
align-items: center;
|
| 843 |
+
justify-content: center;
|
| 844 |
+
}
|
| 845 |
+
|
| 846 |
+
.actions-cell .btn-action {
|
| 847 |
+
display: block;
|
| 848 |
+
margin: 0.1rem 0;
|
| 849 |
+
width: 28px;
|
| 850 |
+
height: 28px;
|
| 851 |
}
|
| 852 |
|
| 853 |
.btn-action {
|
|
|
|
| 857 |
margin: 0 0.1rem;
|
| 858 |
cursor: pointer;
|
| 859 |
border-radius: 6px;
|
| 860 |
+
color: var(--color-text);
|
| 861 |
+
opacity: 0.7;
|
| 862 |
transition: all 0.2s ease;
|
| 863 |
display: inline-flex;
|
| 864 |
align-items: center;
|
|
|
|
| 868 |
}
|
| 869 |
|
| 870 |
.btn-action:hover {
|
| 871 |
+
opacity: 1;
|
| 872 |
+
background: var(--color-panel);
|
| 873 |
+
border-color: var(--color-primary);
|
| 874 |
+
color: var(--color-primary);
|
| 875 |
transform: translateY(-1px);
|
| 876 |
}
|
| 877 |
|
| 878 |
.btn-action.view:hover {
|
| 879 |
+
background: var(--color-panel);
|
| 880 |
+
border-color: var(--color-primary);
|
| 881 |
+
color: var(--color-primary);
|
| 882 |
}
|
| 883 |
|
| 884 |
.btn-action.copy:hover {
|
| 885 |
+
background: var(--color-panel);
|
| 886 |
+
border-color: var(--color-primary);
|
| 887 |
+
color: var(--color-primary);
|
| 888 |
}
|
| 889 |
|
| 890 |
.btn-action.delete:hover {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 891 |
background: var(--color-panel);
|
| 892 |
+
border-color: var(--color-accent);
|
| 893 |
+
color: var(--color-accent);
|
| 894 |
}
|
| 895 |
|
| 896 |
+
|
| 897 |
+
|
| 898 |
.pagination-info-inline {
|
| 899 |
+
color: var(--color-text);
|
| 900 |
+
opacity: 0.7;
|
| 901 |
font-size: 0.9rem;
|
| 902 |
}
|
| 903 |
|
| 904 |
.pagination-controls {
|
| 905 |
display: flex;
|
|
|
|
| 906 |
align-items: center;
|
| 907 |
gap: 0.5rem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 908 |
}
|
| 909 |
|
| 910 |
.page-select {
|
|
|
|
| 921 |
.page-select:focus {
|
| 922 |
outline: none;
|
| 923 |
border-color: var(--color-primary);
|
| 924 |
+
box-shadow: 0 0 0 2px rgba(115, 122, 129, 0.2);
|
| 925 |
+
background: var(--color-input-focus);
|
| 926 |
}
|
| 927 |
|
| 928 |
+
.light-mode .page-select:focus {
|
| 929 |
+
box-shadow: 0 0 0 2px rgba(56, 70, 83, 0.1);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 930 |
}
|
| 931 |
|
| 932 |
+
|
|
|
|
|
|
|
|
|
|
| 933 |
|
| 934 |
.export-section {
|
| 935 |
text-align: center;
|
|
|
|
| 1057 |
.timestamp-badge {
|
| 1058 |
background: var(--color-panel);
|
| 1059 |
border: 1px solid var(--color-border);
|
| 1060 |
+
color: var(--color-text);
|
| 1061 |
+
opacity: 0.8;
|
| 1062 |
padding: 0.25rem 0.75rem;
|
| 1063 |
border-radius: 12px;
|
| 1064 |
font-size: 0.8rem;
|
|
|
|
| 1081 |
|
| 1082 |
.source-badge.conversation {
|
| 1083 |
background: rgba(101, 101, 101, 0.1);
|
| 1084 |
+
color: var(--color-text);
|
| 1085 |
+
opacity: 0.8;
|
| 1086 |
+
border-color: var(--color-border);
|
| 1087 |
}
|
| 1088 |
|
| 1089 |
.header-actions {
|
|
|
|
| 1269 |
padding: 0.5rem;
|
| 1270 |
}
|
| 1271 |
|
| 1272 |
+
.stats-pagination-header {
|
| 1273 |
flex-direction: column;
|
| 1274 |
align-items: flex-start;
|
| 1275 |
gap: 1rem;
|
| 1276 |
}
|
| 1277 |
|
| 1278 |
+
.memory-stats-compact {
|
| 1279 |
width: 100%;
|
| 1280 |
justify-content: space-between;
|
| 1281 |
}
|
| 1282 |
|
| 1283 |
+
.pagination-controls-compact {
|
| 1284 |
+
align-self: stretch;
|
| 1285 |
+
justify-content: center;
|
| 1286 |
+
}
|
| 1287 |
+
|
| 1288 |
.filter-row {
|
| 1289 |
flex-direction: column;
|
| 1290 |
align-items: stretch;
|
|
|
|
| 1302 |
}
|
| 1303 |
|
| 1304 |
.actions-cell {
|
| 1305 |
+
min-width: 60px;
|
| 1306 |
+
width: 60px;
|
| 1307 |
}
|
| 1308 |
|
| 1309 |
+
.col-select { width: 8%; }
|
| 1310 |
+
.col-metadata { width: 27%; }
|
| 1311 |
+
.col-preview { width: 55%; }
|
| 1312 |
+
.col-actions { width: 10%; }
|
|
|
|
| 1313 |
|
| 1314 |
.memory-detail-modal {
|
| 1315 |
width: 98%;
|
|
|
|
| 1343 |
padding: 1rem;
|
| 1344 |
}
|
| 1345 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1346 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1347 |
|
| 1348 |
+
.pagination-controls {
|
| 1349 |
flex-wrap: wrap;
|
|
|
|
| 1350 |
}
|
| 1351 |
}
|
| 1352 |
|
|
|
|
| 1399 |
|
| 1400 |
.source-badge.conversation {
|
| 1401 |
background: rgba(101, 101, 101, 0.1);
|
| 1402 |
+
color: var(--color-text);
|
| 1403 |
+
opacity: 0.8;
|
| 1404 |
+
border-color: var(--color-border);
|
| 1405 |
}
|
| 1406 |
|
| 1407 |
.header-actions {
|
|
|
|
| 1499 |
|
| 1500 |
.metadata-group h5 {
|
| 1501 |
margin: 0 0 0.75rem 0;
|
| 1502 |
+
color: var(--color-text);
|
| 1503 |
+
opacity: 0.7;
|
| 1504 |
font-size: 0.9rem;
|
| 1505 |
font-weight: 600;
|
| 1506 |
text-transform: uppercase;
|
|
|
|
| 1521 |
.metadata-label {
|
| 1522 |
font-size: 0.8rem;
|
| 1523 |
font-weight: 600;
|
| 1524 |
+
color: var(--color-text);
|
| 1525 |
+
opacity: 0.7;
|
| 1526 |
text-transform: uppercase;
|
| 1527 |
letter-spacing: 0.3px;
|
| 1528 |
}
|
|
|
|
| 1606 |
|
| 1607 |
</template>
|
| 1608 |
</div>
|
| 1609 |
+
</body>
|
| 1610 |
+
</html>
|
|
@@ -1,14 +1,261 @@
|
|
| 1 |
-
<
|
| 2 |
-
|
| 3 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
<!-- Modal Header with Memory Info -->
|
| 5 |
<div class="modal-header-enhanced">
|
| 6 |
<div class="header-left">
|
| 7 |
<div class="memory-title">
|
| 8 |
<span class="area-badge-large"
|
| 9 |
-
:style="`background:
|
| 10 |
x-text="$store.memoryDashboardStore.detailMemory?.area?.toUpperCase() || 'UNKNOWN'"></span>
|
| 11 |
-
<h3>Memory Details</h3>
|
| 12 |
</div>
|
| 13 |
<div class="memory-meta-quick">
|
| 14 |
<span class="timestamp-badge" x-text="$store.memoryDashboardStore.formatTimestamp($store.memoryDashboardStore.detailMemory?.timestamp, true)"></span>
|
|
@@ -34,7 +281,7 @@
|
|
| 34 |
<div class="content-section-main">
|
| 35 |
<div class="content-block">
|
| 36 |
<h4>Memory Content</h4>
|
| 37 |
-
<div class="memory-content-display" x-
|
| 38 |
</div>
|
| 39 |
|
| 40 |
<!-- Tags Section -->
|
|
@@ -133,5 +380,6 @@
|
|
| 133 |
</div>
|
| 134 |
</template>
|
| 135 |
</div>
|
| 136 |
-
</
|
| 137 |
-
|
|
|
|
|
|
| 1 |
+
<html>
|
| 2 |
+
|
| 3 |
+
<head>
|
| 4 |
+
<title>Memory Details</title>
|
| 5 |
+
</head>
|
| 6 |
+
|
| 7 |
+
<style>
|
| 8 |
+
/* Memory Detail Modal Styles */
|
| 9 |
+
.modal-header-enhanced {
|
| 10 |
+
display: flex;
|
| 11 |
+
justify-content: space-between;
|
| 12 |
+
align-items: flex-start;
|
| 13 |
+
padding: 1.5rem;
|
| 14 |
+
border-bottom: 2px solid var(--color-border);
|
| 15 |
+
background: var(--color-panel);
|
| 16 |
+
}
|
| 17 |
+
|
| 18 |
+
.memory-title {
|
| 19 |
+
display: flex;
|
| 20 |
+
align-items: center;
|
| 21 |
+
gap: 1rem;
|
| 22 |
+
margin-bottom: 0.5rem;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
.area-badge-large {
|
| 26 |
+
color: white;
|
| 27 |
+
padding: 0.5rem 1rem;
|
| 28 |
+
border-radius: 20px;
|
| 29 |
+
font-size: 0.8rem;
|
| 30 |
+
font-weight: bold;
|
| 31 |
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
.memory-meta-quick {
|
| 35 |
+
display: flex;
|
| 36 |
+
gap: 1rem;
|
| 37 |
+
align-items: center;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
.timestamp-badge, .source-badge {
|
| 41 |
+
padding: 0.25rem 0.75rem;
|
| 42 |
+
border-radius: 12px;
|
| 43 |
+
font-size: 0.75rem;
|
| 44 |
+
font-weight: 500;
|
| 45 |
+
background: var(--color-panel);
|
| 46 |
+
border: 1px solid var(--color-border);
|
| 47 |
+
color: var(--color-text);
|
| 48 |
+
opacity: 0.8;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
.source-badge.knowledge {
|
| 52 |
+
background: rgba(115, 122, 129, 0.1);
|
| 53 |
+
color: var(--color-primary);
|
| 54 |
+
border-color: var(--color-primary);
|
| 55 |
+
opacity: 1;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
.source-badge.conversation {
|
| 59 |
+
background: rgba(101, 101, 101, 0.1);
|
| 60 |
+
color: var(--color-text);
|
| 61 |
+
opacity: 0.8;
|
| 62 |
+
border-color: var(--color-border);
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
.header-actions {
|
| 66 |
+
display: flex;
|
| 67 |
+
gap: 0.5rem;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
.btn-action-header {
|
| 71 |
+
background: var(--color-background);
|
| 72 |
+
border: 1px solid var(--color-border);
|
| 73 |
+
color: var(--color-text);
|
| 74 |
+
padding: 0.5rem;
|
| 75 |
+
border-radius: 8px;
|
| 76 |
+
cursor: pointer;
|
| 77 |
+
transition: all 0.2s ease;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
.btn-action-header:hover {
|
| 81 |
+
border-color: var(--color-primary);
|
| 82 |
+
background: var(--color-panel);
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
.modal-body-enhanced {
|
| 86 |
+
display: flex;
|
| 87 |
+
min-height: 60vh;
|
| 88 |
+
max-height: 70vh;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
.content-section-main {
|
| 92 |
+
flex: 1;
|
| 93 |
+
padding: 1.5rem;
|
| 94 |
+
overflow-y: auto;
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
.content-block {
|
| 98 |
+
margin-bottom: 2rem;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
.content-block h4 {
|
| 102 |
+
margin: 0 0 1rem 0;
|
| 103 |
+
color: var(--color-text);
|
| 104 |
+
font-size: 1.1rem;
|
| 105 |
+
font-weight: 600;
|
| 106 |
+
border-bottom: 1px solid var(--color-border);
|
| 107 |
+
padding-bottom: 0.5rem;
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
.memory-content-display {
|
| 111 |
+
background: var(--color-panel);
|
| 112 |
+
border: 1px solid var(--color-border);
|
| 113 |
+
border-radius: 8px;
|
| 114 |
+
padding: 1.5rem;
|
| 115 |
+
line-height: 1.6;
|
| 116 |
+
color: var(--color-text);
|
| 117 |
+
white-space: pre-wrap;
|
| 118 |
+
word-break: break-word;
|
| 119 |
+
max-height: 300px;
|
| 120 |
+
overflow-y: auto;
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
.tags-display {
|
| 124 |
+
display: flex;
|
| 125 |
+
flex-wrap: wrap;
|
| 126 |
+
gap: 0.5rem;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
.tag-display {
|
| 130 |
+
background: var(--color-primary);
|
| 131 |
+
color: white;
|
| 132 |
+
padding: 0.25rem 0.75rem;
|
| 133 |
+
border-radius: 12px;
|
| 134 |
+
font-size: 0.75rem;
|
| 135 |
+
font-weight: 500;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
.metadata-sidebar {
|
| 139 |
+
min-width: 300px;
|
| 140 |
+
max-width: 350px;
|
| 141 |
+
background: var(--color-panel);
|
| 142 |
+
border-left: 1px solid var(--color-border);
|
| 143 |
+
padding: 1.5rem;
|
| 144 |
+
overflow-y: auto;
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
.metadata-sidebar h4 {
|
| 148 |
+
margin: 0 0 1rem 0;
|
| 149 |
+
color: var(--color-text);
|
| 150 |
+
font-size: 1.1rem;
|
| 151 |
+
font-weight: 600;
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
.metadata-group {
|
| 155 |
+
margin-bottom: 1.5rem;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
.metadata-group h5 {
|
| 159 |
+
margin: 0 0 0.75rem 0;
|
| 160 |
+
color: var(--color-text);
|
| 161 |
+
opacity: 0.7;
|
| 162 |
+
font-size: 0.9rem;
|
| 163 |
+
font-weight: 600;
|
| 164 |
+
text-transform: uppercase;
|
| 165 |
+
letter-spacing: 0.5px;
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
.metadata-item {
|
| 169 |
+
display: flex;
|
| 170 |
+
flex-direction: column;
|
| 171 |
+
gap: 0.25rem;
|
| 172 |
+
margin-bottom: 0.75rem;
|
| 173 |
+
padding: 0.5rem;
|
| 174 |
+
background: var(--color-background);
|
| 175 |
+
border: 1px solid var(--color-border);
|
| 176 |
+
border-radius: 6px;
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
.metadata-label {
|
| 180 |
+
font-size: 0.8rem;
|
| 181 |
+
font-weight: 600;
|
| 182 |
+
color: var(--color-text);
|
| 183 |
+
opacity: 0.7;
|
| 184 |
+
text-transform: uppercase;
|
| 185 |
+
letter-spacing: 0.3px;
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
.metadata-value {
|
| 189 |
+
font-size: 0.9rem;
|
| 190 |
+
color: var(--color-text);
|
| 191 |
+
word-break: break-all;
|
| 192 |
+
line-height: 1.4;
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
.source-file-display {
|
| 196 |
+
font-family: monospace;
|
| 197 |
+
background: var(--color-panel);
|
| 198 |
+
padding: 0.5rem;
|
| 199 |
+
border-radius: 4px;
|
| 200 |
+
border: 1px solid var(--color-border);
|
| 201 |
+
}
|
| 202 |
+
|
| 203 |
+
.metadata-actions {
|
| 204 |
+
display: flex;
|
| 205 |
+
flex-direction: column;
|
| 206 |
+
gap: 0.5rem;
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
.metadata-actions .btn {
|
| 210 |
+
display: flex;
|
| 211 |
+
align-items: center;
|
| 212 |
+
gap: 0.5rem;
|
| 213 |
+
justify-content: flex-start;
|
| 214 |
+
font-size: 0.9rem;
|
| 215 |
+
}
|
| 216 |
+
|
| 217 |
+
/* Responsive design for modal */
|
| 218 |
+
@media (max-width: 768px) {
|
| 219 |
+
.modal-body-enhanced {
|
| 220 |
+
flex-direction: column;
|
| 221 |
+
max-height: 80vh;
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
.metadata-sidebar {
|
| 225 |
+
min-width: unset;
|
| 226 |
+
max-width: unset;
|
| 227 |
+
border-left: none;
|
| 228 |
+
border-top: 1px solid var(--color-border);
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
.modal-header-enhanced {
|
| 232 |
+
padding: 1rem;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
.memory-title {
|
| 236 |
+
flex-direction: column;
|
| 237 |
+
align-items: flex-start;
|
| 238 |
+
gap: 0.5rem;
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
.content-section-main,
|
| 242 |
+
.metadata-sidebar {
|
| 243 |
+
padding: 1rem;
|
| 244 |
+
}
|
| 245 |
+
}
|
| 246 |
+
</style>
|
| 247 |
+
|
| 248 |
+
<body>
|
| 249 |
+
<div x-data>
|
| 250 |
+
<template x-if="$store.memoryDashboardStore && $store.memoryDashboardStore.detailMemory">
|
| 251 |
+
<div>
|
| 252 |
<!-- Modal Header with Memory Info -->
|
| 253 |
<div class="modal-header-enhanced">
|
| 254 |
<div class="header-left">
|
| 255 |
<div class="memory-title">
|
| 256 |
<span class="area-badge-large"
|
| 257 |
+
:style="`background-color: ${$store.memoryDashboardStore.getAreaColor($store.memoryDashboardStore.detailMemory?.area)}`"
|
| 258 |
x-text="$store.memoryDashboardStore.detailMemory?.area?.toUpperCase() || 'UNKNOWN'"></span>
|
|
|
|
| 259 |
</div>
|
| 260 |
<div class="memory-meta-quick">
|
| 261 |
<span class="timestamp-badge" x-text="$store.memoryDashboardStore.formatTimestamp($store.memoryDashboardStore.detailMemory?.timestamp, true)"></span>
|
|
|
|
| 281 |
<div class="content-section-main">
|
| 282 |
<div class="content-block">
|
| 283 |
<h4>Memory Content</h4>
|
| 284 |
+
<div class="memory-content-display" x-text="$store.memoryDashboardStore.detailMemory?.content_full"></div>
|
| 285 |
</div>
|
| 286 |
|
| 287 |
<!-- Tags Section -->
|
|
|
|
| 380 |
</div>
|
| 381 |
</template>
|
| 382 |
</div>
|
| 383 |
+
</body>
|
| 384 |
+
|
| 385 |
+
</html>
|
|
@@ -1606,7 +1606,7 @@
|
|
| 1606 |
<script>
|
| 1607 |
if ('serviceWorker' in navigator) {
|
| 1608 |
window.addEventListener('load', () => {
|
| 1609 |
-
navigator.
|
| 1610 |
console.log('SW registered: ', registration);
|
| 1611 |
}).catch(registrationError => {
|
| 1612 |
console.log('SW registration failed: ', registrationError);
|
|
|
|
| 1606 |
<script>
|
| 1607 |
if ('serviceWorker' in navigator) {
|
| 1608 |
window.addEventListener('load', () => {
|
| 1609 |
+
navigator.serviceWorker.register('js/sw.js').then(registration => {
|
| 1610 |
console.log('SW registered: ', registration);
|
| 1611 |
}).catch(registrationError => {
|
| 1612 |
console.log('SW registration failed: ', registrationError);
|