feat(#76): ingest button in Studio Prepare mode
Add one-click ingest button in the Studio topbar when mode=prepare, ingestion pipeline is available, and chunks exist. Wires to IngestionService via ingestionStore.ingest(). Availability checked on mount. Green ingest button styled consistent with topbar actions.
This commit is contained in:
parent
f35afdca2c
commit
62e5efb790
1 changed files with 48 additions and 0 deletions
|
|
@ -94,6 +94,25 @@
|
||||||
</svg>
|
</svg>
|
||||||
{{ analysisStore.running ? t('studio.analyzing') : t('studio.run') }}
|
{{ analysisStore.running ? t('studio.analyzing') : t('studio.run') }}
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
v-if="
|
||||||
|
mode === 'prepare' && ingestionStore.available && analysisStore.currentChunks.length > 0
|
||||||
|
"
|
||||||
|
class="topbar-btn ingest"
|
||||||
|
data-e2e="ingest-btn"
|
||||||
|
:disabled="ingestionStore.ingesting"
|
||||||
|
@click="handleIngest"
|
||||||
|
>
|
||||||
|
<div v-if="ingestionStore.ingesting" class="spinner-sm" />
|
||||||
|
<svg v-else viewBox="0 0 20 20" fill="currentColor" class="btn-icon">
|
||||||
|
<path
|
||||||
|
fill-rule="evenodd"
|
||||||
|
d="M3 17a1 1 0 011-1h12a1 1 0 110 2H4a1 1 0 01-1-1zm3.293-7.707a1 1 0 011.414 0L9 10.586V3a1 1 0 112 0v7.586l1.293-1.293a1 1 0 111.414 1.414l-3 3a1 1 0 01-1.414 0l-3-3a1 1 0 010-1.414z"
|
||||||
|
clip-rule="evenodd"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
{{ ingestionStore.ingesting ? t('ingestion.ingesting') : t('ingestion.ingest') }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -465,6 +484,7 @@ import BboxOverlay from '../features/analysis/ui/BboxOverlay.vue'
|
||||||
import { ChunkPanel } from '../features/chunking'
|
import { ChunkPanel } from '../features/chunking'
|
||||||
import { useFeatureFlag } from '../features/feature-flags'
|
import { useFeatureFlag } from '../features/feature-flags'
|
||||||
import { getPreviewUrl } from '../features/document/api'
|
import { getPreviewUrl } from '../features/document/api'
|
||||||
|
import { useIngestionStore } from '../features/ingestion/store'
|
||||||
import { useI18n } from '../shared/i18n'
|
import { useI18n } from '../shared/i18n'
|
||||||
import type { ChunkBbox, PipelineOptions } from '../shared/types'
|
import type { ChunkBbox, PipelineOptions } from '../shared/types'
|
||||||
|
|
||||||
|
|
@ -472,6 +492,7 @@ const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const documentStore = useDocumentStore()
|
const documentStore = useDocumentStore()
|
||||||
const analysisStore = useAnalysisStore()
|
const analysisStore = useAnalysisStore()
|
||||||
|
const ingestionStore = useIngestionStore()
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const chunkingEnabled = useFeatureFlag('chunking')
|
const chunkingEnabled = useFeatureFlag('chunking')
|
||||||
|
|
||||||
|
|
@ -595,9 +616,21 @@ watch(
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
async function handleIngest(): Promise<void> {
|
||||||
|
const analysis = analysisStore.currentAnalysis
|
||||||
|
if (!analysis || !selectedDoc.value) return
|
||||||
|
try {
|
||||||
|
const count = await ingestionStore.ingest(analysis.id, selectedDoc.value.id)
|
||||||
|
console.warn(`Ingestion complete — ${count} chunks indexed.`)
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Ingestion failed', e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(async () => {
|
onMounted(async () => {
|
||||||
await documentStore.load()
|
await documentStore.load()
|
||||||
analysisStore.load()
|
analysisStore.load()
|
||||||
|
ingestionStore.checkAvailability()
|
||||||
|
|
||||||
// Restore analysis from history via query param
|
// Restore analysis from history via query param
|
||||||
const analysisId = route.query.analysisId
|
const analysisId = route.query.analysisId
|
||||||
|
|
@ -811,6 +844,21 @@ onBeforeUnmount(() => {
|
||||||
cursor: not-allowed;
|
cursor: not-allowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.topbar-btn.ingest {
|
||||||
|
background: var(--success, #22c55e);
|
||||||
|
border-color: var(--success, #22c55e);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-btn.ingest:hover:not(:disabled) {
|
||||||
|
background: color-mix(in srgb, var(--success, #22c55e) 85%, black);
|
||||||
|
}
|
||||||
|
|
||||||
|
.topbar-btn.ingest:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
.topbar-btn .btn-icon {
|
.topbar-btn .btn-icon {
|
||||||
width: 16px;
|
width: 16px;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue