@memberjunction/ng-search 5.24.0 → 5.25.0
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/dist/__tests__/search-types.test.js +6 -2
- package/dist/__tests__/search-types.test.js.map +1 -1
- package/dist/__tests__/search.service.test.js +25 -18
- package/dist/__tests__/search.service.test.js.map +1 -1
- package/dist/lib/module.d.ts +7 -4
- package/dist/lib/module.d.ts.map +1 -1
- package/dist/lib/module.js +19 -4
- package/dist/lib/module.js.map +1 -1
- package/dist/lib/search-composite.component.d.ts +79 -0
- package/dist/lib/search-composite.component.d.ts.map +1 -0
- package/dist/lib/search-composite.component.js +258 -0
- package/dist/lib/search-composite.component.js.map +1 -0
- package/dist/lib/search-filter.component.d.ts +14 -1
- package/dist/lib/search-filter.component.d.ts.map +1 -1
- package/dist/lib/search-filter.component.js +128 -26
- package/dist/lib/search-filter.component.js.map +1 -1
- package/dist/lib/search-input.component.d.ts +61 -0
- package/dist/lib/search-input.component.d.ts.map +1 -0
- package/dist/lib/search-input.component.js +192 -0
- package/dist/lib/search-input.component.js.map +1 -0
- package/dist/lib/search-overlay.component.js +2 -2
- package/dist/lib/search-results.component.d.ts +9 -5
- package/dist/lib/search-results.component.d.ts.map +1 -1
- package/dist/lib/search-results.component.js +117 -98
- package/dist/lib/search-results.component.js.map +1 -1
- package/dist/lib/search-suggest.component.d.ts +95 -0
- package/dist/lib/search-suggest.component.d.ts.map +1 -0
- package/dist/lib/search-suggest.component.js +491 -0
- package/dist/lib/search-suggest.component.js.map +1 -0
- package/dist/lib/search-types.d.ts +27 -1
- package/dist/lib/search-types.d.ts.map +1 -1
- package/dist/lib/search-types.js.map +1 -1
- package/dist/lib/search.service.d.ts +27 -5
- package/dist/lib/search.service.d.ts.map +1 -1
- package/dist/lib/search.service.js +221 -92
- package/dist/lib/search.service.js.map +1 -1
- package/dist/public-api.d.ts +3 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +3 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +6 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search.service.js","sourceRoot":"","sources":["../../src/lib/search.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Search service that connects to the UnifiedSearchService via GraphQL.\n *\n * Provides a reactive interface for executing searches, managing search history,\n * and transforming raw search responses into display-ready grouped results.\n */\n\nimport { Injectable } from '@angular/core';\nimport { BehaviorSubject, Subject } from 'rxjs';\nimport { Metadata } from '@memberjunction/core';\nimport {\n SearchRequest,\n SearchResponse,\n SearchResultItem,\n SearchResultGroup,\n SearchFilter,\n SearchFilterOption\n} from './search-types';\n\n/** Default minimum relevance score threshold (0-1). Results below this are filtered out. */\nconst DEFAULT_MIN_SCORE = 0.35;\n\n/** Default icon mapping for source types */\nconst SOURCE_TYPE_ICONS: Record<string, string> = {\n 'entity': 'fa-solid fa-database',\n 'content-item': 'fa-solid fa-file-lines',\n 'file': 'fa-solid fa-file',\n 'web-page': 'fa-solid fa-globe',\n};\n\n/** Default labels for source types */\nconst SOURCE_TYPE_LABELS: Record<string, string> = {\n 'entity': 'Entity Records',\n 'content-item': 'Content Items',\n 'file': 'Documents',\n 'web-page': 'Web Pages',\n};\n\n/** Recent search entry for history */\nexport interface RecentSearch {\n Query: string;\n Timestamp: Date;\n ResultCount: number;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class SearchService {\n /** Current search response */\n public SearchResults$ = new BehaviorSubject<SearchResponse | null>(null);\n\n /** Whether a search is in progress */\n public IsSearching$ = new BehaviorSubject<boolean>(false);\n\n /** Recent search history (kept in memory, max 20 entries) */\n public RecentSearches$ = new BehaviorSubject<RecentSearch[]>([]);\n\n /** Error stream */\n public Errors$ = new Subject<string>();\n\n private readonly maxRecentSearches = 20;\n\n /**\n * Execute a search request via the SearchKnowledge GraphQL mutation.\n */\n public async ExecuteSearch(request: SearchRequest): Promise<SearchResponse> {\n this.IsSearching$.next(true);\n const startTime = Date.now();\n\n try {\n const response = await this.executeGraphQLSearch(request);\n response.ElapsedMs = Date.now() - startTime;\n\n this.SearchResults$.next(response);\n this.addToRecentSearches(request.Query, response.TotalCount);\n\n return response;\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Search failed';\n this.Errors$.next(errorMessage);\n const errorResponse = this.createEmptyResponse(errorMessage);\n this.SearchResults$.next(errorResponse);\n return errorResponse;\n } finally {\n this.IsSearching$.next(false);\n }\n }\n\n /** Clear the current search results */\n public ClearResults(): void {\n this.SearchResults$.next(null);\n }\n\n /** Clear recent search history */\n public ClearRecentSearches(): void {\n this.RecentSearches$.next([]);\n }\n\n /**\n * Group flat results by source type for display.\n */\n public GroupResults(results: SearchResultItem[]): SearchResultGroup[] {\n const groupMap = new Map<string, SearchResultItem[]>();\n\n for (const result of results) {\n const key = result.SourceType;\n const existing = groupMap.get(key);\n if (existing) {\n existing.push(result);\n } else {\n groupMap.set(key, [result]);\n }\n }\n\n return Array.from(groupMap.entries()).map(([sourceType, items]) => ({\n Label: SOURCE_TYPE_LABELS[sourceType] ?? sourceType,\n Icon: SOURCE_TYPE_ICONS[sourceType] ?? 'fa-solid fa-circle',\n SourceType: sourceType,\n Results: items,\n TotalCount: items.length\n }));\n }\n\n /**\n * Build filter facets from a set of results.\n */\n public BuildFilters(results: SearchResultItem[]): SearchFilter[] {\n return [\n this.buildSourceTypeFilter(results),\n this.buildEntityNameFilter(results),\n this.buildTagFilter(results)\n ];\n }\n\n /** Get the icon for a given source type */\n public GetSourceIcon(sourceType: string): string {\n return SOURCE_TYPE_ICONS[sourceType] ?? 'fa-solid fa-circle';\n }\n\n private buildSourceTypeFilter(results: SearchResultItem[]): SearchFilter {\n const counts = new Map<string, number>();\n for (const r of results) {\n counts.set(r.SourceType, (counts.get(r.SourceType) ?? 0) + 1);\n }\n const options: SearchFilterOption[] = Array.from(counts.entries()).map(([type, count]) => ({\n Label: SOURCE_TYPE_LABELS[type] ?? type,\n Value: type,\n Count: count,\n IsSelected: false,\n Icon: SOURCE_TYPE_ICONS[type]\n }));\n return { Category: 'Source Type', Options: options, MultiSelect: true };\n }\n\n private buildEntityNameFilter(results: SearchResultItem[]): SearchFilter {\n const counts = new Map<string, number>();\n for (const r of results) {\n counts.set(r.EntityName, (counts.get(r.EntityName) ?? 0) + 1);\n }\n const options: SearchFilterOption[] = Array.from(counts.entries())\n .sort((a, b) => b[1] - a[1])\n .map(([name, count]) => ({\n Label: name,\n Value: name,\n Count: count,\n IsSelected: false,\n Icon: 'fa-solid fa-table'\n }));\n return { Category: 'Entity', Options: options, MultiSelect: true };\n }\n\n private buildTagFilter(results: SearchResultItem[]): SearchFilter {\n const counts = new Map<string, number>();\n for (const r of results) {\n for (const tag of r.Tags) {\n counts.set(tag, (counts.get(tag) ?? 0) + 1);\n }\n }\n const options: SearchFilterOption[] = Array.from(counts.entries())\n .sort((a, b) => b[1] - a[1])\n .slice(0, 15)\n .map(([tag, count]) => ({\n Label: tag,\n Value: tag,\n Count: count,\n IsSelected: false,\n Icon: 'fa-solid fa-tag'\n }));\n return { Category: 'Tags', Options: options, MultiSelect: true };\n }\n\n private addToRecentSearches(query: string, resultCount: number): void {\n const current = this.RecentSearches$.value;\n const filtered = current.filter(s => s.Query !== query);\n const updated = [\n { Query: query, Timestamp: new Date(), ResultCount: resultCount },\n ...filtered\n ].slice(0, this.maxRecentSearches);\n this.RecentSearches$.next(updated);\n }\n\n private createEmptyResponse(errorMessage?: string): SearchResponse {\n return {\n Success: !errorMessage,\n Results: [],\n Groups: [],\n Filters: [],\n TotalCount: 0,\n ElapsedMs: 0,\n SourceCounts: { Vector: 0, FullText: 0, Entity: 0 },\n ErrorMessage: errorMessage\n };\n }\n\n /**\n * Execute search via the SearchKnowledge GraphQL mutation.\n */\n private async executeGraphQLSearch(request: SearchRequest): Promise<SearchResponse> {\n if (!request.Query.trim()) {\n return this.createEmptyResponse();\n }\n\n const provider = Metadata.Provider as { ExecuteGQL?: (query: string, variables: Record<string, unknown>) => Promise<Record<string, unknown>> };\n if (!provider?.ExecuteGQL) {\n return this.createEmptyResponse('GraphQL provider not available');\n }\n\n const mutation = `\n mutation SearchKnowledge($query: String!, $maxResults: Float, $filters: SearchFiltersInput, $minScore: Float) {\n SearchKnowledge(query: $query, maxResults: $maxResults, filters: $filters, minScore: $minScore) {\n Success\n TotalCount\n ElapsedMs\n ErrorMessage\n SourceCounts {\n Vector\n FullText\n Entity\n }\n Results {\n ID\n EntityName\n RecordID\n SourceType\n Title\n Snippet\n Score\n ScoreBreakdown {\n Vector\n FullText\n Entity\n }\n Tags\n EntityIcon\n RecordName\n MatchedAt\n RawMetadata\n }\n }\n }\n `;\n\n const filtersInput = this.buildFiltersInput(request);\n const minScore = request.MinScore ?? DEFAULT_MIN_SCORE;\n const variables: Record<string, unknown> = {\n query: request.Query,\n maxResults: request.MaxResults || 20,\n filters: filtersInput,\n minScore: minScore > 0 ? minScore : undefined,\n };\n\n const gqlResult = await provider.ExecuteGQL(mutation, variables);\n const data = (gqlResult as Record<string, unknown>)['SearchKnowledge'] as {\n Success: boolean;\n Results: Array<{\n ID: string; EntityName: string; RecordID: string; SourceType: string;\n Title: string; Snippet: string; Score: number;\n ScoreBreakdown: { Vector?: number; FullText?: number; Entity?: number };\n Tags: string[]; EntityIcon?: string; RecordName?: string; MatchedAt: string; RawMetadata?: string;\n }>;\n TotalCount: number;\n ElapsedMs: number;\n SourceCounts: { Vector: number; FullText: number; Entity: number };\n ErrorMessage?: string;\n };\n\n if (!data?.Success) {\n return this.createEmptyResponse(data?.ErrorMessage ?? 'Search failed');\n }\n\n const results: SearchResultItem[] = (data.Results ?? []).map(r => ({\n ID: r.ID,\n Title: r.RecordName || r.Title,\n Snippet: r.Snippet,\n EntityName: r.EntityName,\n RecordID: r.RecordID,\n SourceType: (r.SourceType as SearchResultItem['SourceType']) || 'entity',\n Score: r.Score,\n ScoreBreakdown: r.ScoreBreakdown ?? {},\n Tags: r.Tags ?? [],\n SourceIcon: r.EntityIcon || SOURCE_TYPE_ICONS[r.SourceType] || 'fa-solid fa-database',\n EntityIcon: r.EntityIcon,\n RecordName: r.RecordName,\n MatchedAt: new Date(r.MatchedAt),\n RawMetadata: r.RawMetadata,\n }));\n\n const groups = this.GroupResults(results);\n const filters = this.BuildFilters(results);\n\n return {\n Success: true,\n Results: results,\n Groups: groups,\n Filters: filters,\n TotalCount: data.TotalCount,\n ElapsedMs: data.ElapsedMs,\n SourceCounts: data.SourceCounts,\n };\n }\n\n /** Build the GraphQL filters input from active filter selections */\n private buildFiltersInput(request: SearchRequest): { EntityNames?: string[]; SourceTypes?: string[]; Tags?: string[] } | null {\n if (!request.ActiveFilters || Object.keys(request.ActiveFilters).length === 0) {\n return null;\n }\n\n const result: { EntityNames?: string[]; SourceTypes?: string[]; Tags?: string[] } = {};\n\n const entityFilters = request.ActiveFilters['Entity'];\n if (entityFilters?.length) {\n result.EntityNames = entityFilters;\n }\n\n const sourceFilters = request.ActiveFilters['Source Type'];\n if (sourceFilters?.length) {\n result.SourceTypes = sourceFilters;\n }\n\n const tagFilters = request.ActiveFilters['Tags'];\n if (tagFilters?.length) {\n result.Tags = tagFilters;\n }\n\n return Object.keys(result).length > 0 ? result : null;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"search.service.js","sourceRoot":"","sources":["../../src/lib/search.service.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Search service that connects to the UnifiedSearchService via GraphQL.\n *\n * Provides a reactive interface for executing searches, managing search history,\n * and transforming raw search responses into display-ready grouped results.\n */\n\nimport { Injectable } from '@angular/core';\nimport { BehaviorSubject, Subject } from 'rxjs';\nimport { Metadata, StartupManager } from '@memberjunction/core';\nimport { UserInfoEngine } from '@memberjunction/core-entities';\nimport { MJEventType, MJGlobal } from '@memberjunction/global';\nimport {\n GraphQLSearchClient,\n GraphQLDataProvider,\n SearchClientResponse,\n SearchClientResultItem\n} from '@memberjunction/graphql-dataprovider';\nimport {\n SearchRequest,\n SearchResponse,\n SearchResultItem,\n SearchResultGroup,\n SearchFilter,\n SearchFilterOption,\n SearchProviderInfo\n} from './search-types';\n\n/** Default minimum relevance score threshold (0-1). Results below this are filtered out. */\nconst DEFAULT_MIN_SCORE = 0.35;\n\n/** Fallback icon mapping for source types (used when provider metadata is not available) */\nconst FALLBACK_SOURCE_ICONS: Record<string, string> = {\n 'entity': 'fa-solid fa-database',\n 'vector': 'fa-solid fa-brain',\n 'fulltext': 'fa-solid fa-magnifying-glass',\n 'content-item': 'fa-solid fa-file-lines',\n 'file': 'fa-solid fa-file',\n 'web-page': 'fa-solid fa-globe',\n 'storage': 'fa-solid fa-folder-open',\n};\n\n/** Fallback labels for source types (used when provider metadata is not available) */\nconst FALLBACK_SOURCE_LABELS: Record<string, string> = {\n 'entity': 'Database',\n 'vector': 'Semantic Search',\n 'fulltext': 'Full-Text Search',\n 'content-item': 'Content Items',\n 'file': 'Documents',\n 'web-page': 'Web Pages',\n 'storage': 'File Storage',\n};\n\n/** User setting key for persisting recent searches */\nconst RECENT_SEARCHES_KEY = 'search.recentSearches';\n\n/** Recent search entry for history */\nexport interface RecentSearch {\n Query: string;\n Timestamp: Date;\n ResultCount: number;\n}\n\n/** JSON-safe shape for persistence (Date → ISO string) */\ninterface RecentSearchJson {\n Query: string;\n Timestamp: string;\n ResultCount: number;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class SearchService {\n /** Current search response */\n public SearchResults$ = new BehaviorSubject<SearchResponse | null>(null);\n\n /** Whether a search is in progress */\n public IsSearching$ = new BehaviorSubject<boolean>(false);\n\n /** Recent search history (persisted via UserInfoEngine, max 20 entries) */\n public RecentSearches$ = new BehaviorSubject<RecentSearch[]>([]);\n\n /** Error stream */\n public Errors$ = new Subject<string>();\n\n private readonly maxRecentSearches = 20;\n private recentSearchesLoaded = false;\n\n /** Cached provider metadata keyed by SourceType, populated from search responses */\n private providersBySourceType = new Map<string, SearchProviderInfo>();\n\n /**\n * Execute a search request via the SearchKnowledge GraphQL mutation.\n */\n public async ExecuteSearch(request: SearchRequest): Promise<SearchResponse> {\n this.IsSearching$.next(true);\n const startTime = Date.now();\n\n try {\n const response = await this.executeGraphQLSearch(request);\n response.ElapsedMs = Date.now() - startTime;\n\n this.SearchResults$.next(response);\n this.addToRecentSearches(request.Query, response.TotalCount);\n\n return response;\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Search failed';\n this.Errors$.next(errorMessage);\n const errorResponse = this.createEmptyResponse(errorMessage);\n this.SearchResults$.next(errorResponse);\n return errorResponse;\n } finally {\n this.IsSearching$.next(false);\n }\n }\n\n /**\n * Lightweight preview search for autocomplete/typeahead.\n * Does NOT update SearchResults$ or IsSearching$ observables,\n * and does NOT add to recent search history.\n */\n public async PreviewSearch(query: string, maxResults: number = 8): Promise<SearchResponse> {\n try {\n if (!query.trim()) {\n return this.createEmptyResponse();\n }\n\n const provider = Metadata.Provider;\n if (!(provider instanceof GraphQLDataProvider)) {\n return this.createEmptyResponse('GraphQL provider not available');\n }\n\n const client = new GraphQLSearchClient(provider);\n const clientResponse = await client.PreviewSearch(query, maxResults);\n return this.mapClientResponseToSearchResponse(clientResponse);\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Preview search failed';\n return this.createEmptyResponse(errorMessage);\n }\n }\n\n /** Clear the current search results */\n public ClearResults(): void {\n this.SearchResults$.next(null);\n }\n\n /** Clear recent search history (memory and persisted) */\n public ClearRecentSearches(): void {\n this.RecentSearches$.next([]);\n this.persistRecentSearches([]);\n }\n\n /**\n * Group flat results by source type for display.\n */\n public GroupResults(results: SearchResultItem[]): SearchResultGroup[] {\n const groupMap = new Map<string, SearchResultItem[]>();\n\n for (const result of results) {\n const key = result.SourceType;\n const existing = groupMap.get(key);\n if (existing) {\n existing.push(result);\n } else {\n groupMap.set(key, [result]);\n }\n }\n\n return Array.from(groupMap.entries()).map(([sourceType, items]) => {\n // Priority: cached provider metadata > per-result metadata > fallback maps\n const cached = this.providersBySourceType.get(sourceType);\n return {\n Label: cached?.DisplayName ?? items[0]?.ProviderLabel ?? FALLBACK_SOURCE_LABELS[sourceType] ?? sourceType,\n Icon: cached?.Icon ?? items[0]?.ProviderIcon ?? FALLBACK_SOURCE_ICONS[sourceType] ?? 'fa-solid fa-circle',\n SourceType: sourceType,\n Results: items,\n TotalCount: items.length\n };\n });\n }\n\n /**\n * Build filter facets from a set of results.\n */\n public BuildFilters(results: SearchResultItem[]): SearchFilter[] {\n return [\n this.buildSourceTypeFilter(results),\n this.buildEntityNameFilter(results),\n this.buildFileTypeFilter(results),\n this.buildTagFilter(results)\n ].filter(f => f.Options.length > 0); // Hide categories with no options\n }\n\n /** Get the icon for a given source type */\n public GetSourceIcon(sourceType: string): string {\n return this.providersBySourceType.get(sourceType)?.Icon ?? FALLBACK_SOURCE_ICONS[sourceType] ?? 'fa-solid fa-circle';\n }\n\n private buildSourceTypeFilter(results: SearchResultItem[]): SearchFilter {\n const counts = new Map<string, number>();\n for (const r of results) {\n counts.set(r.SourceType, (counts.get(r.SourceType) ?? 0) + 1);\n }\n const options: SearchFilterOption[] = Array.from(counts.entries()).map(([type, count]) => {\n const cached = this.providersBySourceType.get(type);\n return {\n Label: cached?.DisplayName ?? FALLBACK_SOURCE_LABELS[type] ?? type,\n Value: type,\n Count: count,\n IsSelected: false,\n Icon: cached?.Icon ?? FALLBACK_SOURCE_ICONS[type]\n };\n });\n return { Category: 'Source', Options: options, MultiSelect: true };\n }\n\n private buildEntityNameFilter(results: SearchResultItem[]): SearchFilter {\n const counts = new Map<string, number>();\n let fileCount = 0;\n for (const r of results) {\n if (r.ResultType === 'storage-file') {\n fileCount++;\n } else {\n counts.set(r.EntityName, (counts.get(r.EntityName) ?? 0) + 1);\n }\n }\n const options: SearchFilterOption[] = Array.from(counts.entries())\n .sort((a, b) => b[1] - a[1])\n .map(([name, count]) => ({\n Label: name,\n Value: name,\n Count: count,\n IsSelected: false,\n Icon: 'fa-solid fa-table'\n }));\n\n // Add a single \"Files\" entry for all storage file results\n if (fileCount > 0) {\n options.push({\n Label: 'Files',\n Value: '__storage-files__',\n Count: fileCount,\n IsSelected: false,\n Icon: 'fa-solid fa-file'\n });\n }\n\n return { Category: 'Entity', Options: options, MultiSelect: true };\n }\n\n private buildFileTypeFilter(results: SearchResultItem[]): SearchFilter {\n const counts = new Map<string, number>();\n for (const r of results) {\n if (r.ResultType !== 'storage-file') continue;\n const ext = r.Title?.split('.').pop()?.toUpperCase();\n if (ext && ext.length <= 6) {\n counts.set(ext, (counts.get(ext) ?? 0) + 1);\n }\n }\n const options: SearchFilterOption[] = Array.from(counts.entries())\n .sort((a, b) => b[1] - a[1])\n .map(([ext, count]) => ({\n Label: ext,\n Value: ext,\n Count: count,\n IsSelected: false,\n Icon: 'fa-solid fa-file'\n }));\n return { Category: 'File Type', Options: options, MultiSelect: true };\n }\n\n private buildTagFilter(results: SearchResultItem[]): SearchFilter {\n const counts = new Map<string, number>();\n for (const r of results) {\n for (const tag of r.Tags) {\n counts.set(tag, (counts.get(tag) ?? 0) + 1);\n }\n }\n const options: SearchFilterOption[] = Array.from(counts.entries())\n .sort((a, b) => b[1] - a[1])\n .slice(0, 15)\n .map(([tag, count]) => ({\n Label: tag,\n Value: tag,\n Count: count,\n IsSelected: false,\n Icon: 'fa-solid fa-tag'\n }));\n return { Category: 'Tags', Options: options, MultiSelect: true };\n }\n\n /**\n * Load persisted recent searches from UserInfoEngine.\n * Safe to call multiple times — only loads once.\n */\n public async LoadRecentSearches(): Promise<void> {\n if (this.recentSearchesLoaded) return;\n\n try {\n MJGlobal.Instance.GetEventListener(true).subscribe(async (event) => {\n if (event.event === MJEventType.LoggedIn) {\n await StartupManager.Instance.Startup();\n\n const engine = UserInfoEngine.Instance;\n console.log('[SearchService] After Startup — engine.Loaded:', engine.Loaded, 'UserSettings count:', engine.UserSettings.length);\n\n const json = engine.GetSetting(RECENT_SEARCHES_KEY);\n console.log('[SearchService] GetSetting(\"' + RECENT_SEARCHES_KEY + '\"):', json?.substring(0, 100));\n\n if (json) {\n const parsed = JSON.parse(json) as RecentSearchJson[];\n const searches: RecentSearch[] = parsed.map(s => ({\n Query: s.Query,\n Timestamp: new Date(s.Timestamp),\n ResultCount: s.ResultCount\n }));\n this.RecentSearches$.next(searches);\n }\n }\n });\n } catch (err) {\n console.error('[SearchService] LoadRecentSearches error:', err);\n }\n this.recentSearchesLoaded = true;\n }\n\n private addToRecentSearches(query: string, resultCount: number): void {\n const current = this.RecentSearches$.value;\n const filtered = current.filter(s => s.Query !== query);\n const updated = [\n { Query: query, Timestamp: new Date(), ResultCount: resultCount },\n ...filtered\n ].slice(0, this.maxRecentSearches);\n this.RecentSearches$.next(updated);\n this.persistRecentSearches(updated);\n }\n\n private persistRecentSearches(searches: RecentSearch[]): void {\n try {\n const json: RecentSearchJson[] = searches.map(s => ({\n Query: s.Query,\n Timestamp: s.Timestamp.toISOString(),\n ResultCount: s.ResultCount\n }));\n UserInfoEngine.Instance.SetSettingDebounced(RECENT_SEARCHES_KEY, JSON.stringify(json));\n } catch {\n // Silently fail if UserInfoEngine not available\n }\n }\n\n /** Cache provider metadata by SourceType for use in GroupResults/BuildFilters */\n private cacheProviders(providers: SearchProviderInfo[]): void {\n for (const p of providers) {\n this.providersBySourceType.set(p.SourceType, p);\n }\n }\n\n private createEmptyResponse(errorMessage?: string): SearchResponse {\n return {\n Success: !errorMessage,\n Results: [],\n Groups: [],\n Filters: [],\n TotalCount: 0,\n ElapsedMs: 0,\n SourceCounts: { Vector: 0, FullText: 0, Entity: 0, Storage: 0 },\n Providers: [],\n ErrorMessage: errorMessage\n };\n }\n\n /**\n * Execute search via the GraphQLSearchClient.\n */\n private async executeGraphQLSearch(request: SearchRequest): Promise<SearchResponse> {\n if (!request.Query.trim()) {\n return this.createEmptyResponse();\n }\n\n const provider = Metadata.Provider;\n if (!(provider instanceof GraphQLDataProvider)) {\n return this.createEmptyResponse('GraphQL provider not available');\n }\n\n const client = new GraphQLSearchClient(provider);\n const filters = this.buildClientFilters(request);\n const minScore = request.MinScore ?? DEFAULT_MIN_SCORE;\n\n const clientResponse = await client.ExecuteSearch({\n Query: request.Query,\n MaxResults: request.MaxResults || 20,\n MinScore: minScore > 0 ? minScore : undefined,\n Filters: filters\n });\n\n return this.mapClientResponseToSearchResponse(clientResponse);\n }\n\n /** Convert a SearchClientResponse into the SearchResponse shape used by this service */\n private mapClientResponseToSearchResponse(clientResponse: SearchClientResponse): SearchResponse {\n if (!clientResponse.Success) {\n return this.createEmptyResponse(clientResponse.ErrorMessage ?? 'Search failed');\n }\n\n // Cache provider metadata for use in GroupResults/BuildFilters\n const providers: SearchProviderInfo[] = (clientResponse.Providers ?? []).map(p => ({\n ID: p.ID,\n Name: p.Name,\n DisplayName: p.DisplayName,\n Icon: p.Icon,\n SourceType: p.SourceType,\n Priority: p.Priority,\n }));\n this.cacheProviders(providers);\n\n const results: SearchResultItem[] = (clientResponse.Results ?? []).map(r => this.mapClientResultItem(r));\n\n const groups = this.GroupResults(results);\n const filters = this.BuildFilters(results);\n\n return {\n Success: true,\n Results: results,\n Groups: groups,\n Filters: filters,\n TotalCount: clientResponse.TotalCount,\n ElapsedMs: clientResponse.ElapsedMs,\n SourceCounts: {\n Vector: clientResponse.SourceCounts.Vector,\n FullText: clientResponse.SourceCounts.FullText,\n Entity: clientResponse.SourceCounts.Entity,\n Storage: clientResponse.SourceCounts.Storage\n },\n Providers: providers,\n };\n }\n\n /** Map a single SearchClientResultItem to a SearchResultItem */\n private mapClientResultItem(r: SearchClientResultItem): SearchResultItem {\n return {\n ID: r.ID,\n Title: r.RecordName || r.Title,\n Snippet: r.Snippet,\n EntityName: r.EntityName,\n RecordID: r.RecordID,\n SourceType: (r.SourceType as SearchResultItem['SourceType']) || 'entity',\n ResultType: r.ResultType,\n Score: r.Score,\n ScoreBreakdown: r.ScoreBreakdown ?? {},\n Tags: r.Tags ?? [],\n SourceIcon: r.EntityIcon || r.ProviderIcon || FALLBACK_SOURCE_ICONS[r.SourceType] || 'fa-solid fa-database',\n EntityIcon: r.EntityIcon,\n RecordName: r.RecordName,\n MatchedAt: new Date(r.MatchedAt),\n RawMetadata: r.RawMetadata,\n ProviderId: r.ProviderId,\n ProviderLabel: r.ProviderLabel,\n ProviderIcon: r.ProviderIcon,\n };\n }\n\n /** Build the client filters from active filter selections */\n private buildClientFilters(request: SearchRequest): { EntityNames?: string[]; SourceTypes?: string[]; Tags?: string[] } | undefined {\n if (!request.ActiveFilters || Object.keys(request.ActiveFilters).length === 0) {\n return undefined;\n }\n\n const result: { EntityNames?: string[]; SourceTypes?: string[]; Tags?: string[] } = {};\n\n const entityFilters = request.ActiveFilters['Entity'];\n if (entityFilters?.length) {\n result.EntityNames = entityFilters;\n }\n\n const sourceFilters = request.ActiveFilters['Source'];\n if (sourceFilters?.length) {\n result.SourceTypes = sourceFilters;\n }\n\n const tagFilters = request.ActiveFilters['Tags'];\n if (tagFilters?.length) {\n result.Tags = tagFilters;\n }\n\n return Object.keys(result).length > 0 ? result : undefined;\n }\n}\n"]}
|
package/dist/public-api.d.ts
CHANGED
|
@@ -3,5 +3,8 @@ export * from './lib/search.service';
|
|
|
3
3
|
export * from './lib/search-overlay.component';
|
|
4
4
|
export * from './lib/search-results.component';
|
|
5
5
|
export * from './lib/search-filter.component';
|
|
6
|
+
export * from './lib/search-input.component';
|
|
7
|
+
export * from './lib/search-suggest.component';
|
|
8
|
+
export * from './lib/search-composite.component';
|
|
6
9
|
export * from './lib/module';
|
|
7
10
|
//# sourceMappingURL=public-api.d.ts.map
|
package/dist/public-api.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAIA,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"public-api.d.ts","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAIA,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,cAAc,CAAC"}
|
package/dist/public-api.js
CHANGED
|
@@ -6,5 +6,8 @@ export * from './lib/search.service';
|
|
|
6
6
|
export * from './lib/search-overlay.component';
|
|
7
7
|
export * from './lib/search-results.component';
|
|
8
8
|
export * from './lib/search-filter.component';
|
|
9
|
+
export * from './lib/search-input.component';
|
|
10
|
+
export * from './lib/search-suggest.component';
|
|
11
|
+
export * from './lib/search-composite.component';
|
|
9
12
|
export * from './lib/module';
|
|
10
13
|
//# sourceMappingURL=public-api.js.map
|
package/dist/public-api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"public-api.js","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,cAAc,CAAC","sourcesContent":["/*\n * Public API Surface of @memberjunction/ng-search\n */\n\nexport * from './lib/search-types';\nexport * from './lib/search.service';\nexport * from './lib/search-overlay.component';\nexport * from './lib/search-results.component';\nexport * from './lib/search-filter.component';\nexport * from './lib/module';\n"]}
|
|
1
|
+
{"version":3,"file":"public-api.js","sourceRoot":"","sources":["../src/public-api.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,cAAc,CAAC","sourcesContent":["/*\n * Public API Surface of @memberjunction/ng-search\n */\n\nexport * from './lib/search-types';\nexport * from './lib/search.service';\nexport * from './lib/search-overlay.component';\nexport * from './lib/search-results.component';\nexport * from './lib/search-filter.component';\nexport * from './lib/search-input.component';\nexport * from './lib/search-suggest.component';\nexport * from './lib/search-composite.component';\nexport * from './lib/module';\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-search",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.25.0",
|
|
4
4
|
"description": "MemberJunction: Reusable search overlay and results components - command palette / Spotlight style search",
|
|
5
5
|
"main": "./dist/public-api.js",
|
|
6
6
|
"typings": "./dist/public-api.d.ts",
|
|
@@ -27,9 +27,11 @@
|
|
|
27
27
|
"@angular/forms": "21.1.3"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@memberjunction/core": "5.
|
|
31
|
-
"@memberjunction/global": "5.
|
|
32
|
-
"@memberjunction/
|
|
30
|
+
"@memberjunction/core": "5.25.0",
|
|
31
|
+
"@memberjunction/global": "5.25.0",
|
|
32
|
+
"@memberjunction/graphql-dataprovider": "5.25.0",
|
|
33
|
+
"@memberjunction/core-entities": "5.25.0",
|
|
34
|
+
"@memberjunction/ng-shared-generic": "5.25.0",
|
|
33
35
|
"rxjs": "^7.8.2",
|
|
34
36
|
"tslib": "^2.8.1"
|
|
35
37
|
},
|