fix: knowledge infinite scroll + list_events timezone handling

KnowledgeView: sentinel was OUTSIDE the card-grid div, making
IntersectionObserver (root: cardGridEl) never fire since the target must
be a descendant of the root. Moved sentinel inside card-grid with
grid-column:1/-1 + order:9999 so it spans all columns and sits at the
bottom. Fixed backup check to compare against container bounds not viewport.

tools.py list_events: apply same UTC normalization as create_event (treat
naive datetimes as UTC, handle Z suffix). Update tool description to
explicitly request full-day UTC ranges so the LLM doesn't send local time
without offsets, which caused the recall query to miss UTC-stored events.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-03 21:10:43 -04:00
parent aeb778f35a
commit 3887cab66e
2 changed files with 25 additions and 17 deletions
+16 -12
View File
@@ -83,13 +83,16 @@ async function fetchItems(reset = false) {
loading.value = false;
}
// If the sentinel is still in the viewport after appending, keep loading
// If the sentinel is still visible in the card-grid after appending, keep loading
if (!reset && items.value.length < total.value) {
await nextTick();
const rect = sentinelEl.value?.getBoundingClientRect();
if (rect && rect.top < window.innerHeight + 200) {
page.value++;
await fetchItems();
if (sentinelEl.value && cardGridEl.value) {
const containerBottom = cardGridEl.value.getBoundingClientRect().bottom;
const sentinelTop = sentinelEl.value.getBoundingClientRect().top;
if (sentinelTop < containerBottom + 200) {
page.value++;
await fetchItems();
}
}
}
}
@@ -390,8 +393,13 @@ watchEffect(() => {
<p v-else class="empty-hint">Start by creating a note, saving a person or place, or making a list.</p>
</div>
<!-- Card grid -->
<!-- Card grid (sentinel lives inside so IntersectionObserver root works) -->
<div v-else ref="cardGridEl" class="card-grid">
<!-- Infinite scroll sentinel must be inside the scrolling root -->
<div ref="sentinelEl" class="scroll-sentinel">
<span v-if="loading && items.length > 0" class="sentinel-loading">Loading</span>
</div>
<div
v-for="item in items"
:key="item.id"
@@ -456,11 +464,6 @@ watchEffect(() => {
</div>
</div>
</div>
<!-- Infinite scroll sentinel -->
<div ref="sentinelEl" class="scroll-sentinel">
<span v-if="loading && items.length > 0" class="sentinel-loading">Loading</span>
</div>
</div>
<!-- Graph panel -->
@@ -888,11 +891,12 @@ watchEffect(() => {
/* ── Infinite scroll sentinel ────────────────────────────── */
.scroll-sentinel {
grid-column: 1 / -1; /* span all grid columns */
order: 9999; /* push to end of grid items */
height: 40px;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.sentinel-loading {
font-size: 0.8rem;