Compare commits

...

2 Commits

Author SHA1 Message Date
root
14388e8186 fix: persist chapter-names results into job payload from sync SSE handler
All checks were successful
Release / Test backend (push) Successful in 48s
Release / Check ui (push) Successful in 1m56s
Release / Docker (push) Successful in 5m35s
Release / Gitea Release (push) Successful in 23s
The SSE (non-async) chapter-names handler streamed results to the client
but never wrote them into the PocketBase job payload — only the initial
{pattern} stub was stored. The Review button then fetched the job and
found no results, showing 'No results found in this job's payload.'

Fix: accumulate allResults across batches (same as the async handler) and
write the full {pattern, slug, results:[...]} payload when marking done.
2026-04-12 18:44:09 +05:00
root
5cebbb1692 fix: restore pointer-events on ListeningMode and ChapterPickerOverlay
The wrapper div in +layout.svelte had pointer-events:none which blocked
all taps inside ListeningMode (chapter rows, buttons, scrolling). Removed
the wrapper div and moved the fly transition onto ListeningMode's own root
element so the slide-in animation works without stealing pointer events.
2026-04-12 18:31:50 +05:00
3 changed files with 13 additions and 7 deletions

View File

@@ -233,6 +233,7 @@ func (s *Server) handleAdminTextGenChapterNames(w http.ResponseWriter, r *http.R
}
}
var allResults []proposedChapterTitle
chaptersDone := resumeFrom
firstEvent := true
for i, batch := range batches {
@@ -287,6 +288,7 @@ func (s *Server) handleAdminTextGenChapterNames(w http.ResponseWriter, r *http.R
NewTitle: p.Title,
})
}
allResults = append(allResults, result...)
chaptersDone += len(batch)
if jobID != "" && s.deps.AIJobStore != nil {
@@ -310,16 +312,20 @@ func (s *Server) handleAdminTextGenChapterNames(w http.ResponseWriter, r *http.R
sseWrite(evt)
}
// Mark job as done in PB.
// Mark job as done in PB, persisting results so the Review button works.
if jobID != "" && s.deps.AIJobStore != nil {
status := domain.TaskStatusDone
if jobCtx.Err() != nil {
status = domain.TaskStatusCancelled
}
resultsJSON, _ := json.Marshal(allResults)
finalPayload := fmt.Sprintf(`{"pattern":%q,"slug":%q,"results":%s}`,
req.Pattern, req.Slug, string(resultsJSON))
_ = s.deps.AIJobStore.UpdateAIJob(r.Context(), jobID, map[string]any{
"status": string(status),
"items_done": chaptersDone,
"finished": time.Now().Format(time.RFC3339),
"payload": finalPayload,
})
}

View File

@@ -2,6 +2,7 @@
import { audioStore } from '$lib/audio.svelte';
import { cn } from '$lib/utils';
import { goto } from '$app/navigation';
import { fly } from 'svelte/transition';
import type { Voice } from '$lib/types';
import ChapterPickerOverlay from '$lib/components/ChapterPickerOverlay.svelte';
@@ -229,6 +230,7 @@
<!-- Full-screen listening mode overlay -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div
transition:fly={{ y: '100%', duration: 320, opacity: 1 }}
bind:this={overlayEl}
class="fixed inset-0 z-60 flex flex-col overflow-hidden"
style="

View File

@@ -1137,12 +1137,10 @@
<!-- Listening mode — mounted at root level, independent of audioStore.active,
so closing/pausing audio never tears it down and loses context. -->
{#if listeningModeOpen}
<div transition:fly={{ y: '100%', duration: 320, opacity: 1 }} style="pointer-events: none;">
<ListeningMode
onclose={() => { listeningModeOpen = false; listeningModeChapters = false; }}
openChapters={listeningModeChapters}
/>
</div>
<ListeningMode
onclose={() => { listeningModeOpen = false; listeningModeChapters = false; }}
openChapters={listeningModeChapters}
/>
{/if}
<!-- Universal search modal — shown from anywhere except focus mode / listening mode -->