170 lines
6.4 KiB
TypeScript
170 lines
6.4 KiB
TypeScript
"use client"
|
|
|
|
import { OrgSettingsSection } from "@/components/admin/settings/org-settings-form"
|
|
import { DeployLockedHint, useDeployFieldLocked } from "@/components/admin/settings/deploy-locked-hint"
|
|
import { useOrgSettingsStore } from "@/lib/admin-settings/org-settings-store"
|
|
import { Input } from "@/components/ui/input"
|
|
import { Label } from "@/components/ui/label"
|
|
import { Switch } from "@/components/ui/switch"
|
|
import {
|
|
Select,
|
|
SelectContent,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from "@/components/ui/select"
|
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
|
|
|
|
export function SearchSection() {
|
|
const search = useOrgSettingsStore((s) => s.search)
|
|
const setSearch = useOrgSettingsStore((s) => s.setSearch)
|
|
const effective = useOrgSettingsStore((s) => s.meta?.effective.search)
|
|
const brave = search.web_search.providers[0]
|
|
|
|
const engineLocked = useDeployFieldLocked("search", "suite_engine")
|
|
const meiliURLLocked = useDeployFieldLocked("search", "meilisearch_url")
|
|
const meiliKeyLocked = useDeployFieldLocked("search", "meilisearch_api_key")
|
|
const typesenseURLLocked = useDeployFieldLocked("search", "typesense_url")
|
|
const typesenseKeyLocked = useDeployFieldLocked("search", "typesense_api_key")
|
|
|
|
const suiteEngine = engineLocked
|
|
? ((effective?.suite_engine as typeof search.suite_engine) ?? search.suite_engine)
|
|
: search.suite_engine
|
|
const meiliURL = meiliURLLocked
|
|
? (effective?.meilisearch_url ?? search.meilisearch_url)
|
|
: search.meilisearch_url
|
|
const typesenseURL = typesenseURLLocked
|
|
? (effective?.typesense_url ?? search.typesense_url)
|
|
: search.typesense_url
|
|
|
|
return (
|
|
<OrgSettingsSection
|
|
title="Moteur de recherche"
|
|
description="Index de recherche suite (mail, drive) et recherche web pour l'IA contacts."
|
|
policySection="search"
|
|
>
|
|
<Card>
|
|
<CardHeader className="pb-3">
|
|
<CardTitle className="text-sm font-medium">Recherche suite</CardTitle>
|
|
<CardDescription>
|
|
Moteur d'indexation pour la recherche globale (variables SEARCH_ENGINE côté serveur).
|
|
</CardDescription>
|
|
{engineLocked ? <DeployLockedHint section="search" field="suite_engine" /> : null}
|
|
</CardHeader>
|
|
<CardContent className="space-y-4">
|
|
<div>
|
|
<Label>Moteur</Label>
|
|
<Select
|
|
value={suiteEngine}
|
|
disabled={engineLocked}
|
|
onValueChange={(suite_engine) =>
|
|
setSearch({
|
|
suite_engine: suite_engine as typeof search.suite_engine,
|
|
})
|
|
}
|
|
>
|
|
<SelectTrigger className="mt-1 h-9">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectItem value="postgres">PostgreSQL (full-text)</SelectItem>
|
|
<SelectItem value="meilisearch">Meilisearch</SelectItem>
|
|
<SelectItem value="typesense">Typesense</SelectItem>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
{suiteEngine === "meilisearch" ? (
|
|
<div className="grid gap-3 sm:grid-cols-2">
|
|
<div>
|
|
<Label>URL Meilisearch</Label>
|
|
<Input
|
|
className="mt-1 h-9"
|
|
value={meiliURL}
|
|
disabled={meiliURLLocked}
|
|
onChange={(e) => setSearch({ meilisearch_url: e.target.value })}
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label>Clé API</Label>
|
|
<Input
|
|
className="mt-1 h-9"
|
|
type="password"
|
|
value={search.meilisearch_api_key}
|
|
disabled={meiliKeyLocked}
|
|
onChange={(e) => setSearch({ meilisearch_api_key: e.target.value })}
|
|
placeholder={meiliKeyLocked ? "Défini via MEILISEARCH_API_KEY" : undefined}
|
|
/>
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
{suiteEngine === "typesense" ? (
|
|
<div className="grid gap-3 sm:grid-cols-2">
|
|
<div>
|
|
<Label>URL Typesense</Label>
|
|
<Input
|
|
className="mt-1 h-9"
|
|
value={typesenseURL}
|
|
disabled={typesenseURLLocked}
|
|
onChange={(e) => setSearch({ typesense_url: e.target.value })}
|
|
/>
|
|
</div>
|
|
<div>
|
|
<Label>Clé API</Label>
|
|
<Input
|
|
className="mt-1 h-9"
|
|
type="password"
|
|
value={search.typesense_api_key}
|
|
disabled={typesenseKeyLocked}
|
|
onChange={(e) => setSearch({ typesense_api_key: e.target.value })}
|
|
placeholder={typesenseKeyLocked ? "Défini via TYPESENSE_API_KEY" : undefined}
|
|
/>
|
|
</div>
|
|
</div>
|
|
) : null}
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card>
|
|
<CardHeader className="pb-3">
|
|
<CardTitle className="text-sm font-medium">Recherche web (Brave)</CardTitle>
|
|
<CardDescription>Utilisée pour l'enrichissement IA des contacts.</CardDescription>
|
|
</CardHeader>
|
|
<CardContent className="space-y-3">
|
|
<label className="flex items-center justify-between gap-4 rounded-lg border p-3">
|
|
<div>
|
|
<p className="text-sm font-medium">Imposer la config organisation</p>
|
|
</div>
|
|
<Switch
|
|
checked={search.enforce_org_search}
|
|
onCheckedChange={(enforce_org_search) => setSearch({ enforce_org_search })}
|
|
/>
|
|
</label>
|
|
<div>
|
|
<Label>Token API Brave</Label>
|
|
<Input
|
|
className="mt-1 h-9"
|
|
type="password"
|
|
value={brave?.api_key ?? ""}
|
|
onChange={(e) =>
|
|
setSearch({
|
|
web_search: {
|
|
default_provider_id: "brave-default",
|
|
providers: [
|
|
{
|
|
id: "brave-default",
|
|
name: "Brave Search",
|
|
type: "brave",
|
|
api_key: e.target.value,
|
|
},
|
|
],
|
|
},
|
|
})
|
|
}
|
|
/>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</OrgSettingsSection>
|
|
)
|
|
}
|