64 lines
2.1 KiB
TypeScript
64 lines
2.1 KiB
TypeScript
"use client"
|
|
|
|
// Upload and index: the browser sends the file to the files module (the kit's `uploadFile`), then
|
|
// asks this module to index it (`knowledge.document.index`). The indexing itself is a worker job;
|
|
// this form only ever waits on the request, which resolves once the live stream has seen the document's
|
|
// row, so the collection's live list already shows it queued.
|
|
|
|
import type { ProjectSlugs } from "@conusai-kit/ui"
|
|
import { useUpload, useWrite } from "@conusai-kit/ui/data"
|
|
import { FormLayout, PageSection, TextField } from "@conusai-kit/ui/patterns"
|
|
import { type ReactElement, useState } from "react"
|
|
import { INDEXABLE_CONTENT_TYPES, MAX_INDEX_BYTES } from "../contract/index.js"
|
|
|
|
export interface IndexFormLabels {
|
|
readonly heading: string
|
|
readonly label: string
|
|
readonly hint: string
|
|
readonly submit: string
|
|
readonly busy: string
|
|
readonly done: string
|
|
}
|
|
|
|
export function IndexForm({
|
|
slugs,
|
|
collectionName,
|
|
labels,
|
|
}: {
|
|
slugs: ProjectSlugs
|
|
collectionName: string
|
|
labels: IndexFormLabels
|
|
}): ReactElement {
|
|
const upload = useUpload()
|
|
const indexDocument = useWrite<ProjectSlugs & { collectionName: string; fileId: string }, unknown>(
|
|
"knowledge.document.index",
|
|
{ org: slugs.org },
|
|
)
|
|
const [done, setDone] = useState(false)
|
|
|
|
const index = async (_: unknown, data: FormData): Promise<void> => {
|
|
const file = data.get("file")
|
|
if (!(file instanceof File) || file.size === 0) return
|
|
setDone(false)
|
|
const stored = await upload(slugs, file)
|
|
await indexDocument.mutate({ ...slugs, collectionName, fileId: stored.fileId })
|
|
setDone(true)
|
|
}
|
|
|
|
return (
|
|
<PageSection title={labels.heading} level={3} variant="card">
|
|
<FormLayout submitLabel={labels.submit} busyLabel={labels.busy} onSubmit={index}>
|
|
<TextField
|
|
name="file"
|
|
type="file"
|
|
label={labels.label}
|
|
description={`${labels.hint} · ${Math.round(MAX_INDEX_BYTES / 1024)} KB.`}
|
|
accept={INDEXABLE_CONTENT_TYPES.join(",")}
|
|
required
|
|
/>
|
|
</FormLayout>
|
|
{done ? <p role="status">{labels.done}</p> : null}
|
|
</PageSection>
|
|
)
|
|
}
|