@indxsearch/intrface 2.1.1 → 3.0.0-alpha.20260617
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -1
- package/README.md +122 -106
- package/dist/components/FilterPanelSkeleton.d.ts +9 -0
- package/dist/components/RangeFilterPanel.d.ts +2 -0
- package/dist/components/SearchResult.d.ts +13 -0
- package/dist/components/SearchResultRow.d.ts +6 -0
- package/dist/components/SearchResultsSkeleton.d.ts +5 -0
- package/dist/context/SearchContext.d.ts +12 -7
- package/dist/context/buildFilterProxy.d.ts +6 -0
- package/dist/context/useIndxAuth.d.ts +22 -0
- package/dist/context/useSearchExecution.d.ts +18 -0
- package/dist/hooks/useHybridSearch.d.ts +15 -0
- package/dist/hooks/useVectorSearch.d.ts +18 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.d.ts +14 -2
- package/dist/index.es.js +1693 -1703
- package/dist/intrface.css +2 -1
- package/package.json +22 -12
- package/dist/index.umd.js +0 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
All notable changes to
|
|
3
|
+
All notable changes to `@indxsearch/intrface` will be documented in this file.
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [3.0.0] - 2026-05-12
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
- **BREAKING**: Package renamed from `@indxsearch/intrface` to `@indxsearch/intrface`
|
|
12
|
+
- Targets Indx v5 and IndxCloudApi v2
|
|
13
|
+
|
|
14
|
+
### Compatibility
|
|
15
|
+
- Requires IndxCloudApi v2
|
|
16
|
+
- React ^19.0.0
|
|
17
|
+
- React DOM ^19.0.0
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
8
21
|
## [2.1.1] - 2026-01-21
|
|
9
22
|
|
|
10
23
|
### Fixed
|
package/README.md
CHANGED
|
@@ -10,18 +10,18 @@ A powerful, flexible React search UI library for Indx Search with [IndxCloudApi]
|
|
|
10
10
|
- 📱 **Mobile-responsive** - Built-in responsive design
|
|
11
11
|
- ⚡ **Debounced searches** - Optimized performance
|
|
12
12
|
- 🎨 **Customizable rendering** - Full control over result display
|
|
13
|
-
- 🔒 **Secure authentication** -
|
|
13
|
+
- 🔒 **Secure authentication** - Bearer-token authentication
|
|
14
14
|
|
|
15
15
|
## Compatibility
|
|
16
16
|
|
|
17
17
|
| Package | Version |
|
|
18
18
|
|---------|---------|
|
|
19
|
-
| **IndxCloudApi** | `
|
|
19
|
+
| **IndxCloudApi** | `2.0` |
|
|
20
20
|
| **React** | `^19.0.0` |
|
|
21
21
|
| **React DOM** | `^19.0.0` |
|
|
22
|
-
| **Node.js** |
|
|
22
|
+
| **Node.js** | `^20.19.0 \|\| >=22.12.0` |
|
|
23
23
|
|
|
24
|
-
> **Note:** This library
|
|
24
|
+
> **Note:** This library targets IndxCloudApi v2.0 (powered by IndxSearchLib v5 alpha). Different API versions may have incompatible changes.
|
|
25
25
|
|
|
26
26
|
## Installation
|
|
27
27
|
|
|
@@ -37,29 +37,25 @@ npm install @indxsearch/intrface @indxsearch/systm @indxsearch/pixl
|
|
|
37
37
|
|
|
38
38
|
Create a `.env.local` file in your project root:
|
|
39
39
|
|
|
40
|
-
**Option A: Using Bearer Token (Recommended for Production)**
|
|
41
40
|
```bash
|
|
42
41
|
VITE_INDX_URL=https://your-indx-server.com
|
|
43
|
-
VITE_INDX_TOKEN=your-
|
|
42
|
+
VITE_INDX_TOKEN=your-bearer-token-here
|
|
44
43
|
```
|
|
45
44
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
VITE_INDX_EMAIL=your@email.com
|
|
50
|
-
VITE_INDX_PASSWORD=yourpassword
|
|
51
|
-
```
|
|
45
|
+
Create and monitor your bearer token on the IndxCloudApi website.
|
|
46
|
+
|
|
47
|
+
> Only the server URL and token come from the environment. Your **team** and **dataset** identify *what* you're searching, so they're passed directly as props on `SearchProvider` (shown below) — not as env vars.
|
|
52
48
|
|
|
53
49
|
**For local development:**
|
|
54
50
|
```bash
|
|
55
|
-
VITE_INDX_URL=
|
|
56
|
-
|
|
51
|
+
VITE_INDX_URL=https://localhost:5001
|
|
52
|
+
VITE_INDX_TOKEN=your-bearer-token-here
|
|
57
53
|
```
|
|
58
54
|
|
|
59
55
|
**Security Notes:**
|
|
60
56
|
- Never commit `.env.local` to version control
|
|
61
|
-
-
|
|
62
|
-
-
|
|
57
|
+
- The token is exposed in the browser — use a read-only / scoped search token
|
|
58
|
+
- Store the token in environment variables; never hardcode it
|
|
63
59
|
|
|
64
60
|
### 2. Import Styles
|
|
65
61
|
|
|
@@ -78,11 +74,11 @@ export default function SearchPage() {
|
|
|
78
74
|
return (
|
|
79
75
|
<SearchProvider
|
|
80
76
|
url={import.meta.env.VITE_INDX_URL}
|
|
81
|
-
|
|
82
|
-
|
|
77
|
+
preAuthenticatedToken={import.meta.env.VITE_INDX_TOKEN}
|
|
78
|
+
team="my-team"
|
|
83
79
|
dataset="products"
|
|
84
80
|
>
|
|
85
|
-
<SearchInput
|
|
81
|
+
<SearchInput />
|
|
86
82
|
|
|
87
83
|
<SearchResults
|
|
88
84
|
fields={['name', 'description', 'category']}
|
|
@@ -104,28 +100,24 @@ export default function SearchPage() {
|
|
|
104
100
|
|
|
105
101
|
```typescript
|
|
106
102
|
// products page
|
|
107
|
-
<SearchProvider url={url}
|
|
103
|
+
<SearchProvider url={url} preAuthenticatedToken={token} team="my-team" dataset="products">
|
|
108
104
|
{/* ... */}
|
|
109
105
|
</SearchProvider>
|
|
110
106
|
|
|
111
107
|
// articles page
|
|
112
|
-
<SearchProvider url={url}
|
|
108
|
+
<SearchProvider url={url} preAuthenticatedToken={token} team="my-team" dataset="articles">
|
|
113
109
|
{/* ... */}
|
|
114
110
|
</SearchProvider>
|
|
115
111
|
```
|
|
116
112
|
|
|
117
113
|
## Authentication
|
|
118
114
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
### Method 1: Bearer Token (Recommended for Production)
|
|
122
|
-
|
|
123
|
-
Use a pre-authenticated JWT bearer token. This is ideal when you have a backend that generates tokens for your users.
|
|
115
|
+
Authentication uses a **pre-issued bearer token**. Create and monitor tokens on the IndxCloudApi website, then provide the token to `SearchProvider`.
|
|
124
116
|
|
|
125
117
|
**Environment setup:**
|
|
126
118
|
```bash
|
|
127
119
|
VITE_INDX_URL=https://your-indx-server.com
|
|
128
|
-
VITE_INDX_TOKEN=your-
|
|
120
|
+
VITE_INDX_TOKEN=your-bearer-token-here
|
|
129
121
|
```
|
|
130
122
|
|
|
131
123
|
**Usage:**
|
|
@@ -133,57 +125,18 @@ VITE_INDX_TOKEN=your-jwt-bearer-token-here
|
|
|
133
125
|
<SearchProvider
|
|
134
126
|
url={import.meta.env.VITE_INDX_URL}
|
|
135
127
|
preAuthenticatedToken={import.meta.env.VITE_INDX_TOKEN}
|
|
128
|
+
team="my-team"
|
|
136
129
|
dataset="products"
|
|
137
130
|
>
|
|
138
131
|
{/* Your search UI */}
|
|
139
132
|
</SearchProvider>
|
|
140
133
|
```
|
|
141
134
|
|
|
142
|
-
**
|
|
143
|
-
-
|
|
144
|
-
-
|
|
145
|
-
- ✅ For better security (tokens can have expiration, limited scope)
|
|
146
|
-
- ✅ When you want to avoid storing passwords client-side
|
|
147
|
-
|
|
148
|
-
### Method 2: Email/Password (Quick Start & Development)
|
|
149
|
-
|
|
150
|
-
Automatically logs in when the app initializes using email and password.
|
|
151
|
-
|
|
152
|
-
**Environment setup:**
|
|
153
|
-
```bash
|
|
154
|
-
VITE_INDX_URL=https://your-indx-server.com
|
|
155
|
-
VITE_INDX_EMAIL=your@email.com
|
|
156
|
-
VITE_INDX_PASSWORD=yourpassword
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
**Usage:**
|
|
160
|
-
```typescript
|
|
161
|
-
<SearchProvider
|
|
162
|
-
url={import.meta.env.VITE_INDX_URL}
|
|
163
|
-
email={import.meta.env.VITE_INDX_EMAIL}
|
|
164
|
-
password={import.meta.env.VITE_INDX_PASSWORD}
|
|
165
|
-
dataset="products"
|
|
166
|
-
>
|
|
167
|
-
{/* Your search UI */}
|
|
168
|
-
</SearchProvider>
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
**How it works:**
|
|
172
|
-
1. You provide email and password to `SearchProvider`
|
|
173
|
-
2. On mount, the library automatically calls the Login API endpoint
|
|
174
|
-
3. A fresh session token is obtained and used for all subsequent requests
|
|
175
|
-
4. No manual token management required
|
|
176
|
-
|
|
177
|
-
**When to use:**
|
|
178
|
-
- ✅ Quick prototyping and development
|
|
179
|
-
- ✅ Demo applications
|
|
180
|
-
- ✅ When you don't have token infrastructure yet
|
|
181
|
-
|
|
182
|
-
**Security Best Practices:**
|
|
183
|
-
- Store credentials/tokens in environment variables (`.env.local`)
|
|
184
|
-
- Never commit `.env.local` to version control
|
|
135
|
+
**Security best practices:**
|
|
136
|
+
- Create a read-only / scoped search token for client-side use
|
|
137
|
+
- Store the token in environment variables (`.env.local`); never commit it
|
|
185
138
|
- Use secure HTTPS connections in production
|
|
186
|
-
-
|
|
139
|
+
- The token is exposed in the browser, so scope it to search only
|
|
187
140
|
|
|
188
141
|
## Error Handling
|
|
189
142
|
|
|
@@ -192,8 +145,7 @@ The library includes comprehensive error handling with helpful console messages:
|
|
|
192
145
|
### Automatic Error Detection
|
|
193
146
|
|
|
194
147
|
The SearchProvider automatically validates:
|
|
195
|
-
- ✅ Authentication (bearer token
|
|
196
|
-
- ✅ Login success and token retrieval (when using email/password)
|
|
148
|
+
- ✅ Authentication (bearer token)
|
|
197
149
|
- ✅ Dataset existence and status
|
|
198
150
|
- ✅ Dataset readiness (indexing complete)
|
|
199
151
|
- ✅ Empty dataset warnings
|
|
@@ -213,7 +165,7 @@ Wrap your search interface with `SearchErrorBoundary` for graceful error handlin
|
|
|
213
165
|
import { SearchErrorBoundary, SearchProvider } from '@indxsearch/intrface';
|
|
214
166
|
|
|
215
167
|
<SearchErrorBoundary>
|
|
216
|
-
<SearchProvider url={url}
|
|
168
|
+
<SearchProvider url={url} preAuthenticatedToken={token} team={team} dataset={dataset}>
|
|
217
169
|
{/* Your search UI */}
|
|
218
170
|
</SearchProvider>
|
|
219
171
|
</SearchErrorBoundary>
|
|
@@ -230,7 +182,7 @@ import { SearchErrorBoundary, SearchProvider } from '@indxsearch/intrface';
|
|
|
230
182
|
</div>
|
|
231
183
|
)}
|
|
232
184
|
>
|
|
233
|
-
<SearchProvider url={url}
|
|
185
|
+
<SearchProvider url={url} preAuthenticatedToken={token} team={team} dataset={dataset}>
|
|
234
186
|
{children}
|
|
235
187
|
</SearchProvider>
|
|
236
188
|
</SearchErrorBoundary>
|
|
@@ -290,8 +242,8 @@ import { RangeFilterPanel } from '@indxsearch/intrface';
|
|
|
290
242
|
<RangeFilterPanel
|
|
291
243
|
field="price"
|
|
292
244
|
label="Price Range"
|
|
293
|
-
|
|
294
|
-
|
|
245
|
+
expectedMin={0}
|
|
246
|
+
expectedMax={1000}
|
|
295
247
|
/>
|
|
296
248
|
```
|
|
297
249
|
|
|
@@ -320,8 +272,8 @@ export default function AdvancedSearch() {
|
|
|
320
272
|
return (
|
|
321
273
|
<SearchProvider
|
|
322
274
|
url={import.meta.env.VITE_INDX_URL}
|
|
323
|
-
|
|
324
|
-
|
|
275
|
+
preAuthenticatedToken={import.meta.env.VITE_INDX_TOKEN}
|
|
276
|
+
team="my-team"
|
|
325
277
|
dataset="products"
|
|
326
278
|
allowEmptySearch={true}
|
|
327
279
|
enableFacets={true}
|
|
@@ -339,7 +291,7 @@ export default function AdvancedSearch() {
|
|
|
339
291
|
|
|
340
292
|
{/* Main content */}
|
|
341
293
|
<main style={{ flex: 1 }}>
|
|
342
|
-
<SearchInput
|
|
294
|
+
<SearchInput showFocus={true} />
|
|
343
295
|
|
|
344
296
|
<SearchResults
|
|
345
297
|
fields={['name', 'description', 'price', 'category', 'brand']}
|
|
@@ -369,9 +321,8 @@ export default function AdvancedSearch() {
|
|
|
369
321
|
| Prop | Type | Required | Default | Description |
|
|
370
322
|
|------|------|----------|---------|-------------|
|
|
371
323
|
| `url` | `string` | ✅ | - | INDX server URL |
|
|
372
|
-
| `preAuthenticatedToken` | `string` |
|
|
373
|
-
| `
|
|
374
|
-
| `password` | `string` | ⚠️ | - | User password for authentication (either this OR token) |
|
|
324
|
+
| `preAuthenticatedToken` | `string` | ✅ | - | Bearer token created on the IndxCloudApi website |
|
|
325
|
+
| `team` | `string` | ✅ | - | Team that owns the dataset — scopes requests to `/api/teams/{team}/datasets/{dataset}/…` |
|
|
375
326
|
| `dataset` | `string` | ✅ | - | Dataset name |
|
|
376
327
|
| `allowEmptySearch` | `boolean` | ❌ | `false` | Show results without query |
|
|
377
328
|
| `enableFacets` | `boolean` | ❌ | `true` | Enable faceted search |
|
|
@@ -387,11 +338,12 @@ export default function AdvancedSearch() {
|
|
|
387
338
|
|
|
388
339
|
| Prop | Type | Default | Description |
|
|
389
340
|
|------|------|---------|-------------|
|
|
390
|
-
| `placeholder` | `string` | `'Search...'` | Input placeholder text |
|
|
391
341
|
| `showClear` | `boolean` | `true` | Show clear button |
|
|
392
342
|
| `showFocus` | `boolean` | `false` | Show focus ring |
|
|
393
343
|
| `inputSize` | `'micro' \| 'default'` | `'default'` | Input size |
|
|
394
344
|
|
|
345
|
+
> The placeholder text is configured on the provider via `searchSettings.placeholderText` (default `'Type to search'`), not as a prop on `SearchInput`.
|
|
346
|
+
|
|
395
347
|
### SearchResults Props
|
|
396
348
|
|
|
397
349
|
| Prop | Type | Required | Description |
|
|
@@ -406,7 +358,7 @@ export default function AdvancedSearch() {
|
|
|
406
358
|
|------|------|---------|-------------|
|
|
407
359
|
| `field` | `string` | ✅ | Field name to filter on |
|
|
408
360
|
| `label` | `string` | ❌ | Display label |
|
|
409
|
-
| `displayType` | `'checkbox' \| 'button'` | `'checkbox'` | Filter UI style |
|
|
361
|
+
| `displayType` | `'checkbox' \| 'button' \| 'toggle'` | `'checkbox'` | Filter UI style |
|
|
410
362
|
| `layout` | `'list' \| 'grid'` | `'list'` | Layout style |
|
|
411
363
|
| `limit` | `number` | `undefined` | Max filters to show |
|
|
412
364
|
| `startCollapsed` | `boolean` | `false` | Start collapsed |
|
|
@@ -418,31 +370,95 @@ export default function AdvancedSearch() {
|
|
|
418
370
|
|------|------|----------|-------------|
|
|
419
371
|
| `field` | `string` | ✅ | Field name to filter on |
|
|
420
372
|
| `label` | `string` | ❌ | Display label |
|
|
421
|
-
| `
|
|
422
|
-
| `
|
|
373
|
+
| `displayType` | `'slider' \| 'input'` | ❌ | Filter UI style (default `'input'`) |
|
|
374
|
+
| `expectedMin` | `number` | ❌ | Expected lower bound (default `0`) |
|
|
375
|
+
| `expectedMax` | `number` | ❌ | Expected upper bound (default `1000`) |
|
|
376
|
+
| `showHistogram` | `boolean` | ❌ | Show a histogram above the slider (requires the field to be facetable; default `false`) |
|
|
377
|
+
| `resolution` | `number` | ❌ | Value-range per histogram bucket (e.g. `200` → 5 bars over 0–1000). Auto-derived (~20 bars) if omitted |
|
|
378
|
+
| `collapsible` | `boolean` | ❌ | Whether the panel can collapse (default `true`) |
|
|
379
|
+
| `startCollapsed` | `boolean` | ❌ | Start collapsed (default `false`) |
|
|
423
380
|
|
|
424
|
-
|
|
381
|
+
### SortByPanel Props
|
|
425
382
|
|
|
426
|
-
|
|
383
|
+
| Prop | Type | Default | Description |
|
|
384
|
+
|------|------|---------|-------------|
|
|
385
|
+
| `displayType` | `'dropdown' \| 'radio'` | `'dropdown'` | Sort UI style |
|
|
386
|
+
| `collapsible` | `boolean` | `true` | Allow the panel to collapse |
|
|
387
|
+
| `startCollapsed` | `boolean` | `false` | Start collapsed |
|
|
427
388
|
|
|
428
|
-
|
|
389
|
+
## Hooks
|
|
429
390
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
391
|
+
All hooks must be used within a `SearchProvider`.
|
|
392
|
+
|
|
393
|
+
### useSearch / useSearchContext
|
|
394
|
+
|
|
395
|
+
Access the search state and actions (query, filters, results, facets, etc.) from anywhere in the tree. `useSearch` is an alias for `useSearchContext`.
|
|
396
|
+
|
|
397
|
+
```typescript
|
|
398
|
+
import { useSearch } from '@indxsearch/intrface';
|
|
399
|
+
|
|
400
|
+
const { state, setQuery } = useSearch();
|
|
401
|
+
// state.query, state.filters, state.facets, state.searchSettings, ...
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### useVectorSearch
|
|
405
|
+
|
|
406
|
+
Embedding-based vector search against the `VectorSearch` endpoint. You supply an `embeddingFn` that turns query text into a vector; the hook posts it and resolves the matching documents.
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
import { useVectorSearch } from '@indxsearch/intrface';
|
|
410
|
+
|
|
411
|
+
const { results, isLoading, error, search } = useVectorSearch(embeddingFn, {
|
|
412
|
+
fieldName: 'embedding', // embedding field
|
|
413
|
+
maxResults: 10, // optional, default 10
|
|
414
|
+
filter, // optional FilterProxy
|
|
415
|
+
timeoutMs, // optional
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
await search('comfortable running shoes');
|
|
419
|
+
// results: Array<{ document, documentKey, score }> | null
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### useHybridSearch
|
|
423
|
+
|
|
424
|
+
Combines full-text and vector scoring via the `HybridSearch` endpoint. Same shape as `useVectorSearch`, plus an `alpha` blend factor.
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
import { useHybridSearch } from '@indxsearch/intrface';
|
|
428
|
+
|
|
429
|
+
const { results, isLoading, error, search } = useHybridSearch(embeddingFn, {
|
|
430
|
+
fieldName: 'embedding',
|
|
431
|
+
alpha: 0.5, // optional, default 0.5 — blend of text vs. vector score
|
|
432
|
+
maxResults: 10, // optional, default 10
|
|
433
|
+
filter, // optional FilterProxy
|
|
434
|
+
timeoutMs, // optional
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
await search('comfortable running shoes');
|
|
438
|
+
// results: Array<{ document, documentKey, score }> | null
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
## Additional Components
|
|
442
|
+
|
|
443
|
+
These components are also exported and can be used for custom layouts:
|
|
444
|
+
|
|
445
|
+
- `SearchResult` — a single result row; renders `children`, an optional index/score, and a skeleton state.
|
|
446
|
+
- `SearchResultRow` — a lightweight row wrapper with `'title' | 'default'` variants for laying out result fields.
|
|
447
|
+
- `SearchResultsSkeleton` — placeholder rows shown while results load (`rows` prop).
|
|
448
|
+
- `FilterPanelSkeleton` — placeholder for a filter panel while facets load (`list` or `slider` variant).
|
|
449
|
+
- `SearchSettingsPanel` — a ready-made panel for editing `searchSettings` (max results, coverage depth, placeholder text, coverage setup, etc.).
|
|
450
|
+
|
|
451
|
+
## Troubleshooting
|
|
435
452
|
|
|
436
453
|
### "401 Unauthorized" errors
|
|
437
454
|
|
|
438
455
|
**Problem:** Authentication failed or token is invalid
|
|
439
456
|
|
|
440
457
|
**Solutions:**
|
|
441
|
-
1.
|
|
442
|
-
2.
|
|
443
|
-
3.
|
|
444
|
-
4.
|
|
445
|
-
5. Check server logs for authentication issues
|
|
458
|
+
1. Verify the token is valid and not expired; create a fresh one on the IndxCloudApi website if needed
|
|
459
|
+
2. Check that `VITE_INDX_TOKEN` is correctly set in your environment variables
|
|
460
|
+
3. Verify the server is running and accessible
|
|
461
|
+
4. Check server logs for authentication issues
|
|
446
462
|
|
|
447
463
|
### "Failed to fetch" errors
|
|
448
464
|
|
|
@@ -450,7 +466,7 @@ export default function AdvancedSearch() {
|
|
|
450
466
|
|
|
451
467
|
**Solutions:**
|
|
452
468
|
1. Verify the server URL is correct
|
|
453
|
-
2. Check if the server is running (for local: `
|
|
469
|
+
2. Check if the server is running (for local: `https://localhost:5001`)
|
|
454
470
|
3. Ensure CORS is configured on the server
|
|
455
471
|
4. Check browser console for detailed error
|
|
456
472
|
|
|
@@ -478,14 +494,14 @@ export default function AdvancedSearch() {
|
|
|
478
494
|
### Example 1: E-commerce Search
|
|
479
495
|
|
|
480
496
|
```typescript
|
|
481
|
-
<SearchProvider url={url}
|
|
497
|
+
<SearchProvider url={url} preAuthenticatedToken={token} team="my-team" dataset="products">
|
|
482
498
|
<div className="search-page">
|
|
483
|
-
<SearchInput
|
|
499
|
+
<SearchInput />
|
|
484
500
|
|
|
485
501
|
<div className="filters">
|
|
486
502
|
<ValueFilterPanel field="category" label="Category" />
|
|
487
503
|
<ValueFilterPanel field="brand" label="Brand" displayType="button" />
|
|
488
|
-
<RangeFilterPanel field="price" label="Price"
|
|
504
|
+
<RangeFilterPanel field="price" label="Price" expectedMin={0} expectedMax={1000} />
|
|
489
505
|
<ValueFilterPanel field="inStock" label="In Stock" />
|
|
490
506
|
</div>
|
|
491
507
|
|
|
@@ -505,8 +521,8 @@ export default function AdvancedSearch() {
|
|
|
505
521
|
### Example 2: Document Search
|
|
506
522
|
|
|
507
523
|
```typescript
|
|
508
|
-
<SearchProvider url={url}
|
|
509
|
-
<SearchInput
|
|
524
|
+
<SearchProvider url={url} preAuthenticatedToken={token} team="my-team" dataset="documents">
|
|
525
|
+
<SearchInput />
|
|
510
526
|
|
|
511
527
|
<ValueFilterPanel field="docType" label="Type" />
|
|
512
528
|
<ValueFilterPanel field="author" label="Author" />
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface FilterPanelSkeletonProps {
|
|
3
|
+
title?: string;
|
|
4
|
+
rows?: number;
|
|
5
|
+
variant?: 'list' | 'slider';
|
|
6
|
+
collapsible?: boolean;
|
|
7
|
+
startCollapsed?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const FilterPanelSkeleton: React.FC<FilterPanelSkeletonProps>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
export interface SearchResultProps {
|
|
3
|
+
skeleton?: boolean;
|
|
4
|
+
index?: number;
|
|
5
|
+
score?: number;
|
|
6
|
+
showScore?: boolean;
|
|
7
|
+
children?: React.ReactNode;
|
|
8
|
+
/** Animation delay for staggered skeleton rows (seconds) */
|
|
9
|
+
skeletonDelay?: number;
|
|
10
|
+
/** Width percentages [titleWidth, subtitleWidth] for skeleton bars */
|
|
11
|
+
skeletonWidths?: [number, number];
|
|
12
|
+
}
|
|
13
|
+
export declare const SearchResult: React.FC<SearchResultProps>;
|
|
@@ -24,9 +24,9 @@ export interface SearchState {
|
|
|
24
24
|
facetDebounceDelayMillis?: number;
|
|
25
25
|
error?: string;
|
|
26
26
|
facets?: any | null;
|
|
27
|
-
filterableFields
|
|
28
|
-
facetableFields
|
|
29
|
-
sortableFields
|
|
27
|
+
filterableFields: string[];
|
|
28
|
+
facetableFields: string[];
|
|
29
|
+
sortableFields: string[];
|
|
30
30
|
filters: Record<string, string[]>;
|
|
31
31
|
rangeFilters: Record<string, {
|
|
32
32
|
min: number;
|
|
@@ -36,7 +36,7 @@ export interface SearchState {
|
|
|
36
36
|
min: number;
|
|
37
37
|
max: number;
|
|
38
38
|
}>;
|
|
39
|
-
rangeBounds
|
|
39
|
+
rangeBounds: Record<string, {
|
|
40
40
|
min: number;
|
|
41
41
|
max: number;
|
|
42
42
|
}>;
|
|
@@ -50,21 +50,26 @@ export interface SearchContextType {
|
|
|
50
50
|
state: SearchState;
|
|
51
51
|
isFetchingInitial: boolean;
|
|
52
52
|
allowEmptySearch: boolean;
|
|
53
|
+
url: string;
|
|
54
|
+
team: string;
|
|
55
|
+
dataset: string;
|
|
56
|
+
authenticatedFetch: (url: string, options?: RequestInit) => Promise<Response>;
|
|
53
57
|
setQuery: (query: string) => void;
|
|
54
58
|
toggleFilter: (field: string, value: string) => void;
|
|
55
59
|
setRangeFilter: (field: string, min: number, max: number) => void;
|
|
56
60
|
resetFilters: () => void;
|
|
57
|
-
resetSingleFilter: (field: string, value
|
|
61
|
+
resetSingleFilter: (field: string, value: string, isUserAction?: boolean) => void;
|
|
62
|
+
resetRangeFilter: (field: string, isUserAction?: boolean) => void;
|
|
58
63
|
setSort: (field: string | null, ascending: boolean) => void;
|
|
59
64
|
setDebounceDelay?: (ms: number) => void;
|
|
60
65
|
setSearchSettings: (settings: Partial<SearchSettings>) => void;
|
|
61
66
|
fetchMoreResults: (newMax: number) => void;
|
|
62
67
|
}
|
|
68
|
+
export declare const SearchContext: React.Context<SearchContextType | undefined>;
|
|
63
69
|
export declare const SearchProvider: React.FC<{
|
|
64
70
|
children: React.ReactNode;
|
|
65
|
-
email?: string;
|
|
66
|
-
password?: string;
|
|
67
71
|
url: string;
|
|
72
|
+
team: string;
|
|
68
73
|
dataset: string;
|
|
69
74
|
allowEmptySearch?: boolean;
|
|
70
75
|
maxResults?: number;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
type AuthenticatedFetch = (url: string, options?: RequestInit) => Promise<Response>;
|
|
2
|
+
export declare function buildFilterProxy(filters: Record<string, string[]>, rangeFilters: Record<string, {
|
|
3
|
+
min: number;
|
|
4
|
+
max: number;
|
|
5
|
+
}>, url: string, team: string, dataset: string, authenticatedFetch: AuthenticatedFetch): Promise<any>;
|
|
6
|
+
export {};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface IndxAuthResult {
|
|
2
|
+
token: string | null;
|
|
3
|
+
isFetchingInitial: boolean;
|
|
4
|
+
initialFacetStats: Record<string, {
|
|
5
|
+
min: number;
|
|
6
|
+
max: number;
|
|
7
|
+
}>;
|
|
8
|
+
initialFacetKeys: Record<string, string[]>;
|
|
9
|
+
filterableFields: string[];
|
|
10
|
+
facetableFields: string[];
|
|
11
|
+
sortableFields: string[];
|
|
12
|
+
totalDocumentCount: number;
|
|
13
|
+
}
|
|
14
|
+
interface UseIndxAuthOptions {
|
|
15
|
+
url: string;
|
|
16
|
+
team: string;
|
|
17
|
+
dataset: string;
|
|
18
|
+
preAuthenticatedToken?: string;
|
|
19
|
+
enableDebugLogs?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare function useIndxAuth({ url, team, dataset, preAuthenticatedToken, enableDebugLogs, }: UseIndxAuthOptions): IndxAuthResult;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SearchState } from './SearchContext';
|
|
2
|
+
import { IndxAuthResult } from './useIndxAuth';
|
|
3
|
+
export interface UseSearchExecutionOptions {
|
|
4
|
+
state: SearchState;
|
|
5
|
+
setState: React.Dispatch<React.SetStateAction<SearchState>>;
|
|
6
|
+
authenticatedFetch: (url: string, options?: RequestInit) => Promise<Response>;
|
|
7
|
+
auth: IndxAuthResult;
|
|
8
|
+
url: string;
|
|
9
|
+
team: string;
|
|
10
|
+
dataset: string;
|
|
11
|
+
allowEmptySearch: boolean;
|
|
12
|
+
facetsEnabled: boolean;
|
|
13
|
+
enableDebugLogs: boolean;
|
|
14
|
+
filtersChangedByUser: React.MutableRefObject<boolean>;
|
|
15
|
+
shouldFetchMore: React.MutableRefObject<boolean>;
|
|
16
|
+
}
|
|
17
|
+
export type UseSearchExecutionResult = void;
|
|
18
|
+
export declare function useSearchExecution({ state, setState, authenticatedFetch, auth, url, team, dataset, allowEmptySearch, facetsEnabled, enableDebugLogs, filtersChangedByUser, shouldFetchMore, }: UseSearchExecutionOptions): UseSearchExecutionResult;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { FilterProxy } from '@indxsearch/indx-types';
|
|
2
|
+
import { EmbeddingResult } from './useVectorSearch';
|
|
3
|
+
export interface UseHybridSearchOptions {
|
|
4
|
+
fieldName: string;
|
|
5
|
+
alpha?: number;
|
|
6
|
+
maxResults?: number;
|
|
7
|
+
filter?: FilterProxy | null;
|
|
8
|
+
timeoutMs?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare function useHybridSearch(embeddingFn: (text: string) => Promise<number[]>, options: UseHybridSearchOptions): {
|
|
11
|
+
results: EmbeddingResult[] | null;
|
|
12
|
+
isLoading: boolean;
|
|
13
|
+
error: string | undefined;
|
|
14
|
+
search: (text: string) => Promise<void>;
|
|
15
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { FilterProxy } from '@indxsearch/indx-types';
|
|
2
|
+
export interface EmbeddingResult {
|
|
3
|
+
document: any;
|
|
4
|
+
documentKey: number;
|
|
5
|
+
score: number;
|
|
6
|
+
}
|
|
7
|
+
export interface UseVectorSearchOptions {
|
|
8
|
+
fieldName: string;
|
|
9
|
+
maxResults?: number;
|
|
10
|
+
filter?: FilterProxy | null;
|
|
11
|
+
timeoutMs?: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function useVectorSearch(embeddingFn: (text: string) => Promise<number[]>, options: UseVectorSearchOptions): {
|
|
14
|
+
results: EmbeddingResult[] | null;
|
|
15
|
+
isLoading: boolean;
|
|
16
|
+
error: string | undefined;
|
|
17
|
+
search: (text: string) => Promise<void>;
|
|
18
|
+
};
|