Show synced to qdrant status on Browse Jobs
This commit is contained in:
@@ -4,7 +4,7 @@ import { useModels } from '../hooks/useModels'
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
import {
|
||||
Search, ChevronLeft, ChevronRight, CheckCircle2, Clock,
|
||||
FileText, Loader2, Save, RefreshCw, Trash2, Sparkles,
|
||||
FileText, Loader2, Save, RefreshCw, Trash2, Sparkles, Cloud, CloudOff,
|
||||
} from 'lucide-react'
|
||||
import axios from 'axios'
|
||||
|
||||
@@ -29,6 +29,38 @@ function StatusBadge({ status }) {
|
||||
)
|
||||
}
|
||||
|
||||
// A job is synced "in its most recent state" when it was pushed to Qdrant at or
|
||||
// after its last update. `updated_at` is bumped by a DB trigger on every change,
|
||||
// so any edit after a sync makes the job stale until it's re-synced.
|
||||
function isSynced(job) {
|
||||
if (!job.qdrant_synced_at) return false
|
||||
if (!job.updated_at) return true
|
||||
return new Date(job.qdrant_synced_at).getTime() >= new Date(job.updated_at).getTime()
|
||||
}
|
||||
|
||||
function SyncBadge({ job }) {
|
||||
const synced = isSynced(job)
|
||||
const Icon = synced ? Cloud : CloudOff
|
||||
const title = synced
|
||||
? 'Synced with Qdrant'
|
||||
: job.qdrant_synced_at
|
||||
? 'Changed since last Qdrant sync — needs re-sync'
|
||||
: 'Never synced with Qdrant'
|
||||
return (
|
||||
<span
|
||||
title={title}
|
||||
className={`inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs border ${
|
||||
synced
|
||||
? 'text-green-400 bg-green-400/10 border-green-400/30'
|
||||
: 'text-orange-400 bg-orange-400/10 border-orange-400/30'
|
||||
}`}
|
||||
>
|
||||
<Icon className="w-3 h-3" />
|
||||
{synced ? 'Synced' : 'Not synced'}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
// Full-screen Job Detail
|
||||
// ─────────────────────────────────────────────────────────────
|
||||
@@ -210,6 +242,7 @@ function JobDetail({ jobId, onClose, onReviewed, onDeleted, suggestions = {} })
|
||||
{job && (
|
||||
<>
|
||||
<StatusBadge status={job.status} />
|
||||
<SyncBadge job={job} />
|
||||
<motion.button
|
||||
onClick={handleToggleStatus}
|
||||
disabled={togglingStatus}
|
||||
@@ -631,8 +664,9 @@ export default function JobsPanel() {
|
||||
whileTap={{ scale: 0.98 }}
|
||||
layout
|
||||
>
|
||||
<div className="flex items-start justify-between gap-2 mb-2">
|
||||
<div className="flex items-center flex-wrap gap-2 mb-2">
|
||||
<StatusBadge status={job.status} />
|
||||
<SyncBadge job={job} />
|
||||
</div>
|
||||
{job.book && <p className="text-sm font-medium text-gray-200 truncate">{job.book}</p>}
|
||||
<div className="flex items-center gap-2 mt-0.5">
|
||||
|
||||
Reference in New Issue
Block a user