docling-studio/frontend/src/features/store/api.ts
Pier-Jean Malandrino 7ad25aeb2a feat(#251): API client typé create/update/delete + StoreForm + Create/Edit pages
Frontend store API client :
- Types StoreInfo (avec slug + isDefault + embedder), StoreDetail, StoreCreatePayload, StoreUpdatePayload
- Fonctions createStore (POST), updateStore (PATCH), deleteStore (DELETE), fetchStore (GET /:slug)
- Tests Vitest étendus pour les 4 nouveaux endpoints

Composants formulaire (features/store/ui/) :
- StoreForm : champs communs (name/slug/kind/embedder/isDefault) avec validation slug locale, lock du slug pour 'default'
- StoreConfigForm : dispatcher dynamique par kind (extensible)
- OpenSearchConfigForm : champ indexName, validation requise

Pages CRUD :
- StoreCreatePage (/index/new) : formulaire + redirect liste
- StoreEditPage (/index/:store/edit) : préremplit via fetchStore, redirige vers la fiche

Routes + i18n :
- Routes ROUTES.STORE_CREATE et ROUTES.STORE_EDIT ajoutées (names + routes.ts)
- Clés i18n FR/EN sous stores.* et storeForm.*
2026-05-05 09:38:39 +02:00

104 lines
2.5 KiB
TypeScript

import { apiFetch } from '../../shared/api/http'
import type { DocumentLifecycleState } from '../../shared/types'
export interface StoreInfo {
name: string
slug: string
type: string
embedder: string
isDefault: boolean
connected: boolean
documentCount: number
chunkCount: number
errorMessage?: string
}
export interface StoreDetail {
id: string
name: string
slug: string
kind: string
embedder: string
isDefault: boolean
config: Record<string, unknown>
createdAt: string
}
export interface StoreCreatePayload {
name: string
slug: string
kind: string
embedder: string
config: Record<string, unknown>
isDefault?: boolean
}
export interface StoreUpdatePayload {
name?: string
slug?: string
kind?: string
embedder?: string
config?: Record<string, unknown>
isDefault?: boolean
}
export interface StoreDocEntry {
docId: string
filename: string
state: DocumentLifecycleState
chunkCount: number
pushedAt: string
}
export interface QueryResult {
chunkId: string
docId: string
filename: string
text: string
score: number
pageRange?: [number, number]
}
export function fetchStores(): Promise<StoreInfo[]> {
return apiFetch<StoreInfo[]>('/api/stores')
}
export function fetchStore(slug: string): Promise<StoreDetail> {
return apiFetch<StoreDetail>(`/api/stores/${encodeURIComponent(slug)}`)
}
export function createStore(payload: StoreCreatePayload): Promise<StoreDetail> {
return apiFetch<StoreDetail>('/api/stores', {
method: 'POST',
body: JSON.stringify(payload),
})
}
export function updateStore(slug: string, payload: StoreUpdatePayload): Promise<StoreDetail> {
return apiFetch<StoreDetail>(`/api/stores/${encodeURIComponent(slug)}`, {
method: 'PATCH',
body: JSON.stringify(payload),
})
}
export function deleteStore(slug: string): Promise<void> {
return apiFetch<void>(`/api/stores/${encodeURIComponent(slug)}`, { method: 'DELETE' })
}
export function fetchStoreDocuments(store: string): Promise<StoreDocEntry[]> {
return apiFetch<StoreDocEntry[]>(`/api/stores/${encodeURIComponent(store)}/documents`)
}
export function removeDocumentFromStore(store: string, docId: string): Promise<void> {
return apiFetch<void>(
`/api/stores/${encodeURIComponent(store)}/documents/${encodeURIComponent(docId)}`,
{ method: 'DELETE' },
)
}
export function queryStore(store: string, query: string, topK = 5): Promise<QueryResult[]> {
return apiFetch<QueryResult[]>(`/api/stores/${encodeURIComponent(store)}/query`, {
method: 'POST',
body: JSON.stringify({ query, top_k: topK }),
})
}