Skip to content

Commit b5aefb5

Browse files
committed
Add unit tests for Qdrant vector search options and data source
- Implement tests for QdrantVectorSearchOptions to verify property settings and default values. - Create tests for VectorSearchDataSource to validate constructor behavior, search functionality, caching, and error handling. - Add tests for VectorSearchResult, VectorSearchOptions, and VectorSearchDataSourceOptions to ensure correct defaults and custom values. - Introduce tests for service extension methods to validate registration and configuration of vector search services. - Update AutoComplete.Tests project file to include references for new Qdrant and related AI components.
1 parent 4fb78c5 commit b5aefb5

104 files changed

Lines changed: 10100 additions & 17 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
<PackageTags>blazor;autocomplete;component;ai;semantic-search;performance;trimming;aot;wcag;accessibility;theming;virtualization</PackageTags>
2525
<PackageReadmeFile>README.md</PackageReadmeFile>
2626
<PackageIcon>icon.png</PackageIcon>
27-
<Version>1.0.3</Version>
28-
<PackageReleaseNotes>Version 1.0.3 - Added .NET 10 support. Now targets .NET 8, .NET 9, and .NET 10.</PackageReleaseNotes>
27+
<Version>1.0.5</Version>
28+
<PackageReleaseNotes>Version 1.0.5 - Added OData integration package (EasyAppDev.Blazor.AutoComplete.OData) with support for OData v3/v4 endpoints, automatic $filter generation, multi-field search, and all filter strategies (StartsWith, Contains, FuzzyFallback). Enhanced demo pages with interactive search hints.</PackageReleaseNotes>
2929
<Copyright>Copyright (c) 2025 EasyAppDev</Copyright>
3030

3131
<!-- Documentation -->

EasyAppDev.Blazor.AutoComplete.sln

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,16 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAppDev.Blazor.AutoCompl
2727
EndProject
2828
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoComplete.ODataTests", "tests\AutoComplete.ODataTests\AutoComplete.ODataTests.csproj", "{3F97AFAE-6181-44CA-B641-2BD1CB3104E7}"
2929
EndProject
30+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAppDev.Blazor.AutoComplete.AI.PostgreSql", "src\EasyAppDev.Blazor.AutoComplete.AI.PostgreSql\EasyAppDev.Blazor.AutoComplete.AI.PostgreSql.csproj", "{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}"
31+
EndProject
32+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAppDev.Blazor.AutoComplete.AI.AzureSearch", "src\EasyAppDev.Blazor.AutoComplete.AI.AzureSearch\EasyAppDev.Blazor.AutoComplete.AI.AzureSearch.csproj", "{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}"
33+
EndProject
34+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAppDev.Blazor.AutoComplete.AI.Pinecone", "src\EasyAppDev.Blazor.AutoComplete.AI.Pinecone\EasyAppDev.Blazor.AutoComplete.AI.Pinecone.csproj", "{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}"
35+
EndProject
36+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAppDev.Blazor.AutoComplete.AI.Qdrant", "src\EasyAppDev.Blazor.AutoComplete.AI.Qdrant\EasyAppDev.Blazor.AutoComplete.AI.Qdrant.csproj", "{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}"
37+
EndProject
38+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EasyAppDev.Blazor.AutoComplete.AI.CosmosDb", "src\EasyAppDev.Blazor.AutoComplete.AI.CosmosDb\EasyAppDev.Blazor.AutoComplete.AI.CosmosDb.csproj", "{3770D98C-BB80-4615-BD19-7E803725FFB3}"
39+
EndProject
3040
Global
3141
GlobalSection(SolutionConfigurationPlatforms) = preSolution
3242
Debug|Any CPU = Debug|Any CPU
@@ -145,6 +155,66 @@ Global
145155
{3F97AFAE-6181-44CA-B641-2BD1CB3104E7}.Release|x64.Build.0 = Release|Any CPU
146156
{3F97AFAE-6181-44CA-B641-2BD1CB3104E7}.Release|x86.ActiveCfg = Release|Any CPU
147157
{3F97AFAE-6181-44CA-B641-2BD1CB3104E7}.Release|x86.Build.0 = Release|Any CPU
158+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
159+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}.Debug|Any CPU.Build.0 = Debug|Any CPU
160+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}.Debug|x64.ActiveCfg = Debug|Any CPU
161+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}.Debug|x64.Build.0 = Debug|Any CPU
162+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}.Debug|x86.ActiveCfg = Debug|Any CPU
163+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}.Debug|x86.Build.0 = Debug|Any CPU
164+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}.Release|Any CPU.ActiveCfg = Release|Any CPU
165+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}.Release|Any CPU.Build.0 = Release|Any CPU
166+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}.Release|x64.ActiveCfg = Release|Any CPU
167+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}.Release|x64.Build.0 = Release|Any CPU
168+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}.Release|x86.ActiveCfg = Release|Any CPU
169+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F}.Release|x86.Build.0 = Release|Any CPU
170+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
171+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}.Debug|Any CPU.Build.0 = Debug|Any CPU
172+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}.Debug|x64.ActiveCfg = Debug|Any CPU
173+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}.Debug|x64.Build.0 = Debug|Any CPU
174+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}.Debug|x86.ActiveCfg = Debug|Any CPU
175+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}.Debug|x86.Build.0 = Debug|Any CPU
176+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}.Release|Any CPU.ActiveCfg = Release|Any CPU
177+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}.Release|Any CPU.Build.0 = Release|Any CPU
178+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}.Release|x64.ActiveCfg = Release|Any CPU
179+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}.Release|x64.Build.0 = Release|Any CPU
180+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}.Release|x86.ActiveCfg = Release|Any CPU
181+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935}.Release|x86.Build.0 = Release|Any CPU
182+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
183+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
184+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}.Debug|x64.ActiveCfg = Debug|Any CPU
185+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}.Debug|x64.Build.0 = Debug|Any CPU
186+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}.Debug|x86.ActiveCfg = Debug|Any CPU
187+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}.Debug|x86.Build.0 = Debug|Any CPU
188+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
189+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}.Release|Any CPU.Build.0 = Release|Any CPU
190+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}.Release|x64.ActiveCfg = Release|Any CPU
191+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}.Release|x64.Build.0 = Release|Any CPU
192+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}.Release|x86.ActiveCfg = Release|Any CPU
193+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2}.Release|x86.Build.0 = Release|Any CPU
194+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
195+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}.Debug|Any CPU.Build.0 = Debug|Any CPU
196+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}.Debug|x64.ActiveCfg = Debug|Any CPU
197+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}.Debug|x64.Build.0 = Debug|Any CPU
198+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}.Debug|x86.ActiveCfg = Debug|Any CPU
199+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}.Debug|x86.Build.0 = Debug|Any CPU
200+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}.Release|Any CPU.ActiveCfg = Release|Any CPU
201+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}.Release|Any CPU.Build.0 = Release|Any CPU
202+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}.Release|x64.ActiveCfg = Release|Any CPU
203+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}.Release|x64.Build.0 = Release|Any CPU
204+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}.Release|x86.ActiveCfg = Release|Any CPU
205+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA}.Release|x86.Build.0 = Release|Any CPU
206+
{3770D98C-BB80-4615-BD19-7E803725FFB3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
207+
{3770D98C-BB80-4615-BD19-7E803725FFB3}.Debug|Any CPU.Build.0 = Debug|Any CPU
208+
{3770D98C-BB80-4615-BD19-7E803725FFB3}.Debug|x64.ActiveCfg = Debug|Any CPU
209+
{3770D98C-BB80-4615-BD19-7E803725FFB3}.Debug|x64.Build.0 = Debug|Any CPU
210+
{3770D98C-BB80-4615-BD19-7E803725FFB3}.Debug|x86.ActiveCfg = Debug|Any CPU
211+
{3770D98C-BB80-4615-BD19-7E803725FFB3}.Debug|x86.Build.0 = Debug|Any CPU
212+
{3770D98C-BB80-4615-BD19-7E803725FFB3}.Release|Any CPU.ActiveCfg = Release|Any CPU
213+
{3770D98C-BB80-4615-BD19-7E803725FFB3}.Release|Any CPU.Build.0 = Release|Any CPU
214+
{3770D98C-BB80-4615-BD19-7E803725FFB3}.Release|x64.ActiveCfg = Release|Any CPU
215+
{3770D98C-BB80-4615-BD19-7E803725FFB3}.Release|x64.Build.0 = Release|Any CPU
216+
{3770D98C-BB80-4615-BD19-7E803725FFB3}.Release|x86.ActiveCfg = Release|Any CPU
217+
{3770D98C-BB80-4615-BD19-7E803725FFB3}.Release|x86.Build.0 = Release|Any CPU
148218
EndGlobalSection
149219
GlobalSection(SolutionProperties) = preSolution
150220
HideSolutionNode = FALSE
@@ -159,5 +229,10 @@ Global
159229
{B2C3D4E5-F6A7-8901-BCDE-F12345678901} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
160230
{CC7C0450-CC37-44DE-B0DB-F2719DC6A197} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
161231
{3F97AFAE-6181-44CA-B641-2BD1CB3104E7} = {0AB3BF05-4346-4AA6-1389-037BE0695223}
232+
{0400D6A9-933B-4F3C-B40E-1DB5F75FD97F} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
233+
{5B71FFF8-F1BA-4FDE-ACA7-E09611DE3935} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
234+
{A81B7BD6-FE2E-4D58-9549-5119AC2AC4B2} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
235+
{4DC3DCA8-B4E5-4B79-A3DE-CA455B6022AA} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
236+
{3770D98C-BB80-4615-BD19-7E803725FFB3} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
162237
EndGlobalSection
163238
EndGlobal

README.md

Lines changed: 144 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,10 @@ var options = new ODataOptions
361361
| `AdditionalFilter` | `string?` | `null` | Static filter ANDed with search |
362362
| `CaseInsensitive` | `bool` | `true` | Use tolower() wrapper |
363363
| `MinSearchLength` | `int` | `1` | Min chars before API call |
364+
| `TimeoutSeconds` | `int` | `30` | HTTP request timeout |
364365
| `CustomHeaders` | `Dictionary<string,string>?` | `null` | HTTP headers (e.g., Authorization) |
366+
| `ResultsPropertyName` | `string` | `"value"` | JSON property containing results |
367+
| `IncludeCount` | `bool` | `false` | Include $count in response |
365368

366369
### Fluent Builder
367370

@@ -444,17 +447,143 @@ Configuration in `appsettings.json`:
444447

445448
### AI Parameters
446449

447-
| Parameter | Default | Description |
448-
|-----------|---------|-------------|
449-
| `SimilarityThreshold` | `0.15` | Minimum cosine similarity (0-1) for results |
450-
| `MinSearchLength` | `3` | Characters before semantic search triggers |
451-
| `DebounceMs` | `500` | Delay before API call |
452-
| `ItemCacheDuration` | `1 hour` | Embedding cache TTL for items |
453-
| `QueryCacheDuration` | `15 min` | Embedding cache TTL for queries |
454-
| `MaxItemCacheSize` | `10,000` | Maximum cached item embeddings |
455-
| `MaxQueryCacheSize` | `1,000` | Maximum cached query embeddings |
456-
| `PreWarmCache` | `false` | Generate all embeddings on init |
457-
| `ShowCacheStatus` | `true` | Display cache statistics |
450+
| Parameter | Type | Default | Description |
451+
|-----------|------|---------|-------------|
452+
| `SimilarityThreshold` | `float` | `0.15` | Minimum cosine similarity (0-1) for results |
453+
| `MinSearchLength` | `int` | `3` | Characters before semantic search triggers |
454+
| `DebounceMs` | `int` | `500` | Delay before API call |
455+
| `MaxResults` | `int?` | `null` | Maximum results (null = all matching) |
456+
| `ItemCacheDuration` | `TimeSpan` | `1 hour` | Embedding cache TTL for items |
457+
| `QueryCacheDuration` | `TimeSpan` | `15 min` | Embedding cache TTL for queries |
458+
| `MaxItemCacheSize` | `int` | `10,000` | Maximum cached item embeddings |
459+
| `MaxQueryCacheSize` | `int` | `1,000` | Maximum cached query embeddings |
460+
| `PreWarmCache` | `bool` | `false` | Generate all embeddings on init |
461+
| `ShowCacheStatus` | `bool` | `true` | Display cache statistics |
462+
463+
## Vector Database Providers
464+
465+
For production deployments with persistent storage and scalable semantic search, use external vector database providers. These eliminate the need to regenerate embeddings on restart and support millions of items.
466+
467+
### Supported Providers
468+
469+
| Provider | Package | Features |
470+
|----------|---------|----------|
471+
| PostgreSQL (pgvector) | `EasyAppDev.Blazor.AutoComplete.AI.PostgreSql` | Self-hosted, 6 distance functions (Cosine, L2, DotProduct, Manhattan, Hamming, Jaccard), HNSW index |
472+
| Azure AI Search | `EasyAppDev.Blazor.AutoComplete.AI.AzureSearch` | Hybrid search (vector + keyword), semantic ranking, managed service |
473+
| Pinecone | `EasyAppDev.Blazor.AutoComplete.AI.Pinecone` | Serverless, namespaces, automatic scaling |
474+
| Qdrant | `EasyAppDev.Blazor.AutoComplete.AI.Qdrant` | Open-source, self-hosted, advanced filtering |
475+
| Azure CosmosDB | `EasyAppDev.Blazor.AutoComplete.AI.CosmosDb` | Multi-model, global distribution, integrated NoSQL |
476+
477+
### Quick Start (PostgreSQL)
478+
479+
```bash
480+
dotnet add package EasyAppDev.Blazor.AutoComplete.AI.PostgreSql
481+
```
482+
483+
```csharp
484+
using EasyAppDev.Blazor.AutoComplete.AI.PostgreSql.Extensions;
485+
486+
// Configure services
487+
builder.Services.AddAutoCompletePostgres<Product>(
488+
configureOptions: options =>
489+
{
490+
options.ConnectionString = "Host=localhost;Database=myapp;Username=user;Password=pass";
491+
options.CollectionName = "products";
492+
options.EmbeddingDimensions = 1536; // text-embedding-3-small
493+
},
494+
textSelector: p => $"{p.Name} {p.Description} {p.Category}",
495+
idSelector: p => p.Id.ToString());
496+
497+
// Add OpenAI embeddings and vector search data source
498+
builder.Services.AddAutoCompleteVectorSearch<Product>(
499+
openAiApiKey: "sk-...",
500+
configureOptions: options =>
501+
{
502+
options.MaxResults = 20;
503+
options.MinSimilarityScore = 0.15f;
504+
});
505+
```
506+
507+
Component usage is unchanged:
508+
509+
```razor
510+
<SemanticAutoComplete TItem="Product"
511+
TextField="@(p => p.Name)"
512+
@bind-Value="selectedProduct" />
513+
```
514+
515+
### Quick Start (Azure AI Search)
516+
517+
```bash
518+
dotnet add package EasyAppDev.Blazor.AutoComplete.AI.AzureSearch
519+
```
520+
521+
```csharp
522+
using EasyAppDev.Blazor.AutoComplete.AI.AzureSearch.Extensions;
523+
524+
builder.Services.AddAutoCompleteAzureSearch<Product>(
525+
configureOptions: options =>
526+
{
527+
options.Endpoint = "https://my-search.search.windows.net";
528+
options.ApiKey = "your-api-key";
529+
options.IndexName = "products";
530+
options.EnableHybridSearch = true; // Vector + keyword search
531+
},
532+
textSelector: p => $"{p.Name} {p.Description}",
533+
idSelector: p => p.Id.ToString());
534+
535+
builder.Services.AddAutoCompleteVectorSearchWithAzure<Product>(
536+
endpoint: "https://my-openai.openai.azure.com/",
537+
apiKey: "your-openai-key",
538+
deploymentName: "text-embedding-ada-002",
539+
configureOptions: options =>
540+
{
541+
options.EnableHybridSearch = true;
542+
});
543+
```
544+
545+
### When to Use Vector Providers
546+
547+
| Scenario | Recommendation |
548+
|----------|----------------|
549+
| Development/Prototyping | Use in-memory `SemanticSearchDataSource` |
550+
| Small datasets (< 10K items) | Either approach works |
551+
| Production (> 10K items) | Use vector provider |
552+
| Need persistence across restarts | Use vector provider |
553+
| Multi-instance deployment | Use vector provider (shared database) |
554+
| Need hybrid search (vector + keyword) | Azure AI Search or CosmosDB |
555+
556+
### Indexing Data
557+
558+
Before searching, index your data:
559+
560+
```csharp
561+
// Inject the indexer
562+
public class ProductService
563+
{
564+
private readonly IVectorIndexer<Product> _indexer;
565+
566+
public async Task IndexProductsAsync(IEnumerable<Product> products)
567+
{
568+
// Ensure collection/index exists
569+
await _indexer.EnsureCollectionExistsAsync();
570+
571+
// Index all items (with progress reporting)
572+
_indexer.ProgressChanged += (s, e) =>
573+
Console.WriteLine($"Indexed {e.ProcessedItems}/{e.TotalItems}");
574+
575+
await _indexer.IndexAsync(products);
576+
}
577+
578+
public async Task IndexSingleProductAsync(Product product)
579+
{
580+
// Upsert single item
581+
await _indexer.IndexAsync(product);
582+
}
583+
}
584+
```
585+
586+
See the [Migration Guide](docs/migration-guide.md) for detailed instructions on migrating from in-memory search to vector providers.
458587

459588
## API Reference
460589

@@ -463,16 +592,16 @@ Configuration in `appsettings.json`:
463592
| Parameter | Type | Default | Description |
464593
|-----------|------|---------|-------------|
465594
| `Items` | `IEnumerable<TItem>?` | `null` | Collection of items |
466-
| `DataSource` | `IAutoCompleteDataSource<TItem>?` | `null` | Async data source |
595+
| `DataSource` | `IAutoCompleteDataSource<TItem>?` | `null` | Async data source (takes precedence over Items) |
467596
| `Value` | `TItem?` | `null` | Selected value (two-way) |
468597
| `ValueChanged` | `EventCallback<TItem?>` | | Selection change event |
469598
| `TextField` | `Expression<Func<TItem, string>>?` | `null` | Display text property |
470599
| `SearchFields` | `Expression<Func<TItem, string[]>>?` | `null` | Multi-field search |
471600
| `Placeholder` | `string?` | `null` | Input placeholder |
472601
| `MinSearchLength` | `int` | `1` | Min chars before search |
602+
| `MaxSearchLength` | `int` | `500` | Max input length (security, max 2000) |
473603
| `MaxDisplayedItems` | `int` | `100` | Max items shown |
474604
| `DebounceMs` | `int` | `300` | Debounce delay (ms) |
475-
| `MaxSearchLength` | `int` | `500` | Max input length (security) |
476605
| `AllowClear` | `bool` | `true` | Show clear button |
477606
| `Disabled` | `bool` | `false` | Disable component |
478607
| `CloseOnSelect` | `bool` | `true` | Close on selection |
@@ -500,9 +629,9 @@ Configuration in `appsettings.json`:
500629
| Parameter | Type | Default | Description |
501630
|-----------|------|---------|-------------|
502631
| `Theme` | `Theme` | `Auto` | Light/Dark/Auto |
503-
| `ThemePreset` | `ThemePreset` | `None` | Design system |
632+
| `ThemePreset` | `ThemePreset` | `None` | Design system (Material, Fluent, Modern, Bootstrap) |
504633
| `BootstrapTheme` | `BootstrapTheme` | `Default` | Bootstrap color variant |
505-
| `Size` | `ComponentSize` | `Default` | Component size |
634+
| `Size` | `ComponentSize` | `Default` | Component size (Compact, Default, Large) |
506635
| `EnableThemeTransitions` | `bool` | `true` | Smooth transitions |
507636
| `RightToLeft` | `bool` | `false` | RTL text direction |
508637
| `ThemeOverrides` | `ThemeOptions?` | `null` | Structured overrides |
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Web">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<RootNamespace>AzureSearchDemo</RootNamespace>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<ProjectReference Include="..\..\..\src\EasyAppDev.Blazor.AutoComplete\EasyAppDev.Blazor.AutoComplete.csproj" />
12+
<ProjectReference Include="..\..\..\src\EasyAppDev.Blazor.AutoComplete.AI\EasyAppDev.Blazor.AutoComplete.AI.csproj" />
13+
<ProjectReference Include="..\..\..\src\EasyAppDev.Blazor.AutoComplete.AI.AzureSearch\EasyAppDev.Blazor.AutoComplete.AI.AzureSearch.csproj" />
14+
</ItemGroup>
15+
16+
</Project>
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Azure AI Search Demo</title>
7+
<base href="/" />
8+
<link href="_content/EasyAppDev.Blazor.AutoComplete/styles/autocomplete.base.css" rel="stylesheet" />
9+
<link href="css/app.css" rel="stylesheet" />
10+
<HeadOutlet />
11+
</head>
12+
<body>
13+
<Routes />
14+
<script src="_framework/blazor.web.js"></script>
15+
</body>
16+
</html>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@inherits LayoutComponentBase
2+
3+
<main class="container py-4">
4+
@Body
5+
</main>

0 commit comments

Comments
 (0)