@memberjunction/ng-search 0.0.1 → 5.22.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.
Files changed (38) hide show
  1. package/dist/__tests__/search-types.test.d.ts +2 -0
  2. package/dist/__tests__/search-types.test.d.ts.map +1 -0
  3. package/dist/__tests__/search-types.test.js +107 -0
  4. package/dist/__tests__/search-types.test.js.map +1 -0
  5. package/dist/__tests__/search.service.test.d.ts +2 -0
  6. package/dist/__tests__/search.service.test.d.ts.map +1 -0
  7. package/dist/__tests__/search.service.test.js +183 -0
  8. package/dist/__tests__/search.service.test.js.map +1 -0
  9. package/dist/lib/module.d.ts +13 -0
  10. package/dist/lib/module.d.ts.map +1 -0
  11. package/dist/lib/module.js +43 -0
  12. package/dist/lib/module.js.map +1 -0
  13. package/dist/lib/search-filter.component.d.ts +39 -0
  14. package/dist/lib/search-filter.component.d.ts.map +1 -0
  15. package/dist/lib/search-filter.component.js +200 -0
  16. package/dist/lib/search-filter.component.js.map +1 -0
  17. package/dist/lib/search-overlay.component.d.ts +103 -0
  18. package/dist/lib/search-overlay.component.d.ts.map +1 -0
  19. package/dist/lib/search-overlay.component.js +626 -0
  20. package/dist/lib/search-overlay.component.js.map +1 -0
  21. package/dist/lib/search-results.component.d.ts +64 -0
  22. package/dist/lib/search-results.component.d.ts.map +1 -0
  23. package/dist/lib/search-results.component.js +378 -0
  24. package/dist/lib/search-results.component.js.map +1 -0
  25. package/dist/lib/search-types.d.ts +142 -0
  26. package/dist/lib/search-types.d.ts.map +1 -0
  27. package/dist/lib/search-types.js +8 -0
  28. package/dist/lib/search-types.js.map +1 -0
  29. package/dist/lib/search.service.d.ts +52 -0
  30. package/dist/lib/search.service.d.ts.map +1 -0
  31. package/dist/lib/search.service.js +287 -0
  32. package/dist/lib/search.service.js.map +1 -0
  33. package/dist/public-api.d.ts +7 -0
  34. package/dist/public-api.d.ts.map +1 -0
  35. package/dist/public-api.js +10 -0
  36. package/dist/public-api.js.map +1 -0
  37. package/package.json +38 -7
  38. package/README.md +0 -45
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-overlay.component.js","sourceRoot":"","sources":["../../src/lib/search-overlay.component.ts","../../src/lib/search-overlay.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Search Overlay Component\n *\n * A floating search overlay inspired by command palette / Spotlight style.\n * Triggered by Cmd+K (Mac) or Ctrl+K (Windows), appears as a centered\n * floating panel with backdrop blur, search input, and grouped results.\n *\n * Supports keyboard navigation (up/down/enter/escape), filter facets,\n * and responsive mobile layout.\n */\n\nimport {\n Component,\n EventEmitter,\n HostListener,\n Input,\n OnDestroy,\n OnInit,\n Output,\n ChangeDetectorRef,\n ElementRef,\n ViewChild,\n inject\n} from '@angular/core';\nimport { Subject } from 'rxjs';\nimport { debounceTime, takeUntil } from 'rxjs/operators';\nimport { SearchService } from './search.service';\nimport {\n SearchResultItem,\n SearchResultGroup,\n SearchFilter,\n SearchRequest,\n SearchResultSelectedEvent,\n SearchFilterChangeEvent,\n SearchExecutedEvent,\n} from './search-types';\n\n@Component({\n standalone: false,\n selector: 'mj-search-overlay',\n templateUrl: './search-overlay.component.html',\n styleUrls: ['./search-overlay.component.css']\n})\nexport class SearchOverlayComponent implements OnInit, OnDestroy {\n private cdr = inject(ChangeDetectorRef);\n protected searchService = inject(SearchService);\n private destroy$ = new Subject<void>();\n private searchInput$ = new Subject<string>();\n\n @ViewChild('searchInput') searchInputRef!: ElementRef<HTMLInputElement>;\n\n // --- Configuration Inputs ---\n\n /** Placeholder text for the search input */\n @Input() Placeholder = 'Search across all your knowledge...';\n\n /** Maximum number of results to fetch */\n @Input() MaxResults = 25;\n\n /** Whether the overlay is currently visible */\n private _IsOpen = false;\n\n @Input()\n set IsOpen(value: boolean) {\n const prev = this._IsOpen;\n this._IsOpen = value;\n if (value && !prev) {\n this.onOverlayOpened();\n }\n if (!value && prev) {\n this.onOverlayClosed();\n }\n }\n get IsOpen(): boolean {\n return this._IsOpen;\n }\n\n /** Debounce time in ms before search fires */\n @Input() DebounceMs = 250;\n\n /** Which search sources to include */\n @Input() IncludeSources: ('vector' | 'fulltext' | 'entity')[] = ['vector', 'fulltext', 'entity'];\n\n /** Whether to show filter facets */\n @Input() ShowFilters = true;\n\n /** Text for the agent CTA button */\n @Input() AgentCtaText = 'Ask Knowledge Agent';\n\n /** Whether to show the agent CTA */\n @Input() ShowAgentCta = true;\n\n // --- Outputs ---\n\n @Output() IsOpenChange = new EventEmitter<boolean>();\n @Output() ResultSelected = new EventEmitter<SearchResultSelectedEvent>();\n @Output() FilterChanged = new EventEmitter<SearchFilterChangeEvent>();\n @Output() SearchExecuted = new EventEmitter<SearchExecutedEvent>();\n @Output() AgentCtaClicked = new EventEmitter<string>();\n\n // --- Component State ---\n\n public Query = '';\n public IsSearching = false;\n public ResultGroups: SearchResultGroup[] = [];\n public AllResults: SearchResultItem[] = [];\n public Filters: SearchFilter[] = [];\n public ActiveFilters: Record<string, string[]> = {};\n public TotalCount = 0;\n public ElapsedMs = 0;\n public HighlightedIndex = -1;\n public HasSearched = false;\n\n /** All results flattened for keyboard navigation */\n public get FlatResults(): SearchResultItem[] {\n return this.AllResults;\n }\n\n ngOnInit(): void {\n this.setupSearchDebounce();\n this.subscribeToSearchState();\n }\n\n ngOnDestroy(): void {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n // --- Keyboard shortcuts ---\n\n @HostListener('document:keydown', ['$event'])\n HandleGlobalKeydown(event: KeyboardEvent): void {\n if (this.isToggleShortcut(event)) {\n event.preventDefault();\n this.ToggleOverlay();\n return;\n }\n if (this._IsOpen) {\n this.handleOverlayKeydown(event);\n }\n }\n\n /** Toggle the overlay open/closed */\n public ToggleOverlay(): void {\n this.IsOpen = !this._IsOpen;\n this.IsOpenChange.emit(this._IsOpen);\n }\n\n /** Open the overlay */\n public Open(): void {\n if (!this._IsOpen) {\n this.IsOpen = true;\n this.IsOpenChange.emit(true);\n }\n }\n\n /** Close the overlay */\n public Close(): void {\n if (this._IsOpen) {\n this.IsOpen = false;\n this.IsOpenChange.emit(false);\n }\n }\n\n /** Handle query input changes */\n public OnQueryInput(value: string): void {\n this.Query = value;\n this.searchInput$.next(value);\n }\n\n /** Handle clicking a result */\n public OnResultClick(result: SearchResultItem, event: MouseEvent): void {\n this.ResultSelected.emit({\n Result: result,\n OpenInNewTab: event.metaKey || event.ctrlKey\n });\n this.Close();\n }\n\n /** Handle selecting the highlighted result */\n public SelectHighlighted(): void {\n if (this.HighlightedIndex >= 0 && this.HighlightedIndex < this.FlatResults.length) {\n this.ResultSelected.emit({\n Result: this.FlatResults[this.HighlightedIndex],\n OpenInNewTab: false\n });\n this.Close();\n }\n }\n\n /** Handle filter option toggle */\n public OnFilterToggle(category: string, value: string): void {\n const current = this.ActiveFilters[category] ?? [];\n const index = current.indexOf(value);\n if (index >= 0) {\n current.splice(index, 1);\n } else {\n current.push(value);\n }\n this.ActiveFilters[category] = current;\n this.FilterChanged.emit({ Category: category, SelectedValues: current });\n this.executeSearch();\n }\n\n /** Clear all active filters */\n public ClearAllFilters(): void {\n this.ActiveFilters = {};\n this.executeSearch();\n }\n\n /** Handle clicking the agent CTA */\n public OnAgentCtaClick(): void {\n this.AgentCtaClicked.emit(this.Query);\n this.Close();\n }\n\n /** Handle clicking the backdrop to close */\n public OnBackdropClick(): void {\n this.Close();\n }\n\n /** Check if a filter option is active */\n public IsFilterActive(category: string, value: string): boolean {\n return (this.ActiveFilters[category] ?? []).includes(value);\n }\n\n /** Get a score display value (percentage) */\n public FormatScore(score: number): string {\n return `${Math.round(score * 100)}%`;\n }\n\n /** Format elapsed time display */\n public FormatElapsedTime(ms: number): string {\n if (ms < 1000) {\n return `${ms}ms`;\n }\n return `${(ms / 1000).toFixed(1)}s`;\n }\n\n // --- Private Methods ---\n\n private isToggleShortcut(event: KeyboardEvent): boolean {\n return (event.metaKey || event.ctrlKey) && event.key === 'k';\n }\n\n private handleOverlayKeydown(event: KeyboardEvent): void {\n switch (event.key) {\n case 'Escape':\n event.preventDefault();\n this.Close();\n break;\n case 'ArrowDown':\n event.preventDefault();\n this.moveHighlight(1);\n break;\n case 'ArrowUp':\n event.preventDefault();\n this.moveHighlight(-1);\n break;\n case 'Enter':\n event.preventDefault();\n this.SelectHighlighted();\n break;\n }\n }\n\n private moveHighlight(direction: number): void {\n const maxIndex = this.FlatResults.length - 1;\n if (maxIndex < 0) return;\n\n this.HighlightedIndex += direction;\n if (this.HighlightedIndex < 0) {\n this.HighlightedIndex = maxIndex;\n } else if (this.HighlightedIndex > maxIndex) {\n this.HighlightedIndex = 0;\n }\n this.cdr.detectChanges();\n }\n\n private setupSearchDebounce(): void {\n this.searchInput$\n .pipe(\n debounceTime(this.DebounceMs),\n takeUntil(this.destroy$)\n )\n .subscribe(() => this.executeSearch());\n }\n\n private subscribeToSearchState(): void {\n this.searchService.IsSearching$\n .pipe(takeUntil(this.destroy$))\n .subscribe(val => {\n this.IsSearching = val;\n this.cdr.detectChanges();\n });\n }\n\n private async executeSearch(): Promise<void> {\n const query = this.Query.trim();\n if (!query) {\n this.clearResults();\n return;\n }\n\n const request: SearchRequest = {\n Query: query,\n MaxResults: this.MaxResults,\n ActiveFilters: this.ActiveFilters,\n IncludeSources: this.IncludeSources,\n };\n\n const response = await this.searchService.ExecuteSearch(request);\n this.AllResults = response.Results;\n this.ResultGroups = response.Groups;\n this.Filters = response.Filters;\n this.TotalCount = response.TotalCount;\n this.ElapsedMs = response.ElapsedMs;\n this.HasSearched = true;\n this.HighlightedIndex = response.Results.length > 0 ? 0 : -1;\n\n this.SearchExecuted.emit({\n Query: query,\n Filters: this.ActiveFilters,\n ResultCount: response.TotalCount,\n ElapsedMs: response.ElapsedMs,\n });\n\n this.cdr.detectChanges();\n }\n\n private clearResults(): void {\n this.AllResults = [];\n this.ResultGroups = [];\n this.Filters = [];\n this.TotalCount = 0;\n this.ElapsedMs = 0;\n this.HasSearched = false;\n this.HighlightedIndex = -1;\n this.cdr.detectChanges();\n }\n\n private onOverlayOpened(): void {\n // Focus input after view updates\n Promise.resolve().then(() => {\n this.searchInputRef?.nativeElement?.focus();\n this.cdr.detectChanges();\n });\n }\n\n private onOverlayClosed(): void {\n this.HighlightedIndex = -1;\n }\n\n /** Check if any filters are active (used by template) */\n public hasActiveFilters(): boolean {\n return Object.values(this.ActiveFilters).some(v => v.length > 0);\n }\n\n /** Check if a result is currently keyboard-highlighted */\n public isResultHighlighted(result: SearchResultItem): boolean {\n const flatIndex = this.getFlatIndex(result);\n return flatIndex === this.HighlightedIndex;\n }\n\n /** Get the flat index of a result for keyboard navigation */\n public getFlatIndex(result: SearchResultItem): number {\n return this.FlatResults.indexOf(result);\n }\n}\n","@if (IsOpen) {\n <!-- Backdrop -->\n <div class=\"search-backdrop\" (click)=\"OnBackdropClick()\"></div>\n\n <!-- Spotlight container -->\n <div class=\"search-spotlight\" (click)=\"$event.stopPropagation()\">\n <!-- Search input area -->\n <div class=\"search-input-wrap\">\n <i class=\"fa-solid fa-magnifying-glass search-icon\"></i>\n <input\n #searchInput\n type=\"text\"\n class=\"search-input\"\n [placeholder]=\"Placeholder\"\n [value]=\"Query\"\n (input)=\"OnQueryInput($any($event.target).value)\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n />\n @if (IsSearching) {\n <div class=\"search-spinner\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n </div>\n }\n <div class=\"search-shortcut-hint\">\n <kbd>ESC</kbd>\n </div>\n </div>\n\n <!-- Results area -->\n <div class=\"search-results-area\">\n @if (ShowFilters && Filters.length > 0) {\n <!-- Filter chips -->\n <div class=\"search-filter-bar\">\n @for (filter of Filters; track filter.Category) {\n @for (option of filter.Options; track option.Value) {\n <button\n class=\"filter-chip\"\n [class.filter-chip-active]=\"IsFilterActive(filter.Category, option.Value)\"\n (click)=\"OnFilterToggle(filter.Category, option.Value)\"\n >\n @if (option.Icon) {\n <i [class]=\"option.Icon\"></i>\n }\n <span>{{ option.Label }}</span>\n <span class=\"filter-chip-count\">{{ option.Count }}</span>\n </button>\n }\n }\n @if (hasActiveFilters()) {\n <button class=\"filter-clear-btn\" (click)=\"ClearAllFilters()\">\n <i class=\"fa-solid fa-times\"></i> Clear\n </button>\n }\n </div>\n }\n\n @if (HasSearched && AllResults.length === 0 && !IsSearching) {\n <!-- No results -->\n <div class=\"search-empty-state\">\n <i class=\"fa-solid fa-search search-empty-icon\"></i>\n <p class=\"search-empty-title\">No results found</p>\n <p class=\"search-empty-text\">Try different keywords or remove some filters</p>\n @if (ShowAgentCta) {\n <button class=\"agent-cta-btn\" (click)=\"OnAgentCtaClick()\">\n <i class=\"fa-solid fa-robot\"></i>\n {{ AgentCtaText }}\n </button>\n }\n </div>\n }\n\n @if (!HasSearched && !IsSearching) {\n <!-- Recent searches -->\n <div class=\"search-recent\">\n @if (searchService.RecentSearches$.value.length > 0) {\n <div class=\"search-recent-header\">\n <span class=\"search-recent-title\">Recent Searches</span>\n </div>\n @for (recent of searchService.RecentSearches$.value; track recent.Query; let i = $index) {\n @if (i < 5) {\n <div class=\"search-recent-item\" (click)=\"OnQueryInput(recent.Query)\">\n <i class=\"fa-solid fa-clock search-recent-icon\"></i>\n <span>{{ recent.Query }}</span>\n <span class=\"search-recent-count\">{{ recent.ResultCount }} results</span>\n </div>\n }\n }\n } @else {\n <div class=\"search-empty-state search-empty-state-compact\">\n <i class=\"fa-solid fa-magnifying-glass search-empty-icon\"></i>\n <p class=\"search-empty-text\">Start typing to search across all your knowledge</p>\n </div>\n }\n </div>\n }\n\n @if (AllResults.length > 0) {\n <!-- Grouped results -->\n @for (group of ResultGroups; track group.SourceType) {\n <div class=\"result-group\">\n <div class=\"result-group-header\">\n <i [class]=\"group.Icon\"></i>\n <span class=\"result-group-label\">{{ group.Label }}</span>\n <span class=\"result-group-count\">{{ group.TotalCount }}</span>\n </div>\n @for (result of group.Results; track result.ID; let ri = $index) {\n <div\n class=\"result-item\"\n [class.result-item-highlighted]=\"isResultHighlighted(result)\"\n (click)=\"OnResultClick(result, $event)\"\n (mouseenter)=\"HighlightedIndex = getFlatIndex(result)\"\n >\n <div class=\"result-item-icon\">\n <i [class]=\"result.SourceIcon\"></i>\n </div>\n <div class=\"result-item-content\">\n <div class=\"result-item-title\">{{ result.Title }}</div>\n <div class=\"result-item-snippet\">{{ result.Snippet }}</div>\n @if (result.Tags.length > 0) {\n <div class=\"result-item-tags\">\n @for (tag of result.Tags; track tag; let ti = $index) {\n @if (ti < 3) {\n <span class=\"result-tag\">{{ tag }}</span>\n }\n }\n </div>\n }\n </div>\n <div class=\"result-item-score\">\n <span class=\"score-badge\">{{ FormatScore(result.Score) }}</span>\n </div>\n </div>\n }\n </div>\n }\n\n <!-- Footer -->\n <div class=\"search-footer\">\n <span class=\"search-footer-count\">\n {{ TotalCount }} results in {{ FormatElapsedTime(ElapsedMs) }}\n </span>\n @if (ShowAgentCta) {\n <button class=\"agent-cta-btn agent-cta-btn-small\" (click)=\"OnAgentCtaClick()\">\n <i class=\"fa-solid fa-robot\"></i>\n {{ AgentCtaText }}\n </button>\n }\n </div>\n }\n </div>\n </div>\n}\n"]}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * @fileoverview Search Results Component
3
+ *
4
+ * Displays search results grouped by source type with expandable sections.
5
+ * Used both within the search overlay and as a standalone results view
6
+ * in the Knowledge Hub search dashboard.
7
+ */
8
+ import { EventEmitter } from '@angular/core';
9
+ import { SearchResultItem, SearchResultGroup, SearchResultSelectedEvent } from './search-types';
10
+ import * as i0 from "@angular/core";
11
+ export declare class SearchResultsComponent {
12
+ private cdr;
13
+ /** Grouped search results to display */
14
+ ResultGroups: SearchResultGroup[];
15
+ /** Whether results are currently loading */
16
+ IsLoading: boolean;
17
+ /** Total result count */
18
+ TotalCount: number;
19
+ /** Elapsed search time in ms */
20
+ ElapsedMs: number;
21
+ /** Maximum results per group before "Show more" */
22
+ MaxPerGroup: number;
23
+ /** Whether to show score badges */
24
+ ShowScores: boolean;
25
+ /** Whether to show tags */
26
+ ShowTags: boolean;
27
+ /** Whether to show source type icons */
28
+ ShowSourceIcons: boolean;
29
+ ResultSelected: EventEmitter<SearchResultSelectedEvent>;
30
+ /** Emitted when user clicks "Open Record" — parent handles navigation */
31
+ OpenRecordRequested: EventEmitter<{
32
+ EntityName: string;
33
+ RecordID: string;
34
+ }>;
35
+ /** Tracks which groups are expanded */
36
+ ExpandedGroups: Set<string>;
37
+ /** Set of expanded result card IDs — multiple can be open simultaneously */
38
+ ExpandedResultIDs: Set<string>;
39
+ /** Toggle group expansion */
40
+ ToggleGroup(sourceType: string): void;
41
+ /** Whether a group is expanded */
42
+ IsGroupExpanded(sourceType: string): boolean;
43
+ /** Get visible results for a group (respecting max per group unless expanded) */
44
+ GetVisibleResults(group: SearchResultGroup): SearchResultItem[];
45
+ /** Whether a group has more results than shown */
46
+ HasMoreResults(group: SearchResultGroup): boolean;
47
+ /** Get the count of hidden results */
48
+ GetHiddenCount(group: SearchResultGroup): number;
49
+ /** Handle clicking a result */
50
+ OnResultClick(result: SearchResultItem, event: MouseEvent): void;
51
+ /** Toggle expand/collapse of a result card — multiple can be open */
52
+ ToggleExpand(result: SearchResultItem, event?: MouseEvent): void;
53
+ /** Check if a result card is expanded */
54
+ IsExpanded(resultID: string): boolean;
55
+ /** Handle "Open Record" button click */
56
+ OnOpenRecord(result: SearchResultItem, event: MouseEvent): void;
57
+ /** Format a score as a percentage */
58
+ FormatScore(score: number): string;
59
+ /** Format elapsed time */
60
+ FormatTime(ms: number): string;
61
+ static ɵfac: i0.ɵɵFactoryDeclaration<SearchResultsComponent, never>;
62
+ static ɵcmp: i0.ɵɵComponentDeclaration<SearchResultsComponent, "mj-search-results", never, { "ResultGroups": { "alias": "ResultGroups"; "required": false; }; "IsLoading": { "alias": "IsLoading"; "required": false; }; "TotalCount": { "alias": "TotalCount"; "required": false; }; "ElapsedMs": { "alias": "ElapsedMs"; "required": false; }; "MaxPerGroup": { "alias": "MaxPerGroup"; "required": false; }; "ShowScores": { "alias": "ShowScores"; "required": false; }; "ShowTags": { "alias": "ShowTags"; "required": false; }; "ShowSourceIcons": { "alias": "ShowSourceIcons"; "required": false; }; }, { "ResultSelected": "ResultSelected"; "OpenRecordRequested": "OpenRecordRequested"; }, never, never, false, never>;
63
+ }
64
+ //# sourceMappingURL=search-results.component.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-results.component.d.ts","sourceRoot":"","sources":["../../src/lib/search-results.component.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEH,YAAY,EAKf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;;AAEhG,qBAMa,sBAAsB;IAC/B,OAAO,CAAC,GAAG,CAA6B;IAExC,wCAAwC;IAC/B,YAAY,EAAE,iBAAiB,EAAE,CAAM;IAEhD,4CAA4C;IACnC,SAAS,UAAS;IAE3B,yBAAyB;IAChB,UAAU,SAAK;IAExB,gCAAgC;IACvB,SAAS,SAAK;IAEvB,mDAAmD;IAC1C,WAAW,SAAK;IAEzB,mCAAmC;IAC1B,UAAU,UAAQ;IAE3B,2BAA2B;IAClB,QAAQ,UAAQ;IAEzB,wCAAwC;IAC/B,eAAe,UAAQ;IAEtB,cAAc,0CAAiD;IAEzE,yEAAyE;IAC/D,mBAAmB;oBAAkC,MAAM;kBAAY,MAAM;OAAM;IAE7F,uCAAuC;IAChC,cAAc,cAAqB;IAE1C,4EAA4E;IACrE,iBAAiB,cAAqB;IAE7C,6BAA6B;IACtB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAS5C,kCAAkC;IAC3B,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAInD,iFAAiF;IAC1E,iBAAiB,CAAC,KAAK,EAAE,iBAAiB,GAAG,gBAAgB,EAAE;IAOtE,kDAAkD;IAC3C,cAAc,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO;IAIxD,sCAAsC;IAC/B,cAAc,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM;IAIvD,+BAA+B;IACxB,aAAa,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAOvE,qEAAqE;IAC9D,YAAY,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,CAAC,EAAE,UAAU,GAAG,IAAI;IAUvE,yCAAyC;IAClC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAI5C,wCAAwC;IACjC,YAAY,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI;IAQtE,qCAAqC;IAC9B,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IAIzC,0BAA0B;IACnB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM;yCA9G5B,sBAAsB;2CAAtB,sBAAsB;CAkHlC"}
@@ -0,0 +1,378 @@
1
+ /**
2
+ * @fileoverview Search Results Component
3
+ *
4
+ * Displays search results grouped by source type with expandable sections.
5
+ * Used both within the search overlay and as a standalone results view
6
+ * in the Knowledge Hub search dashboard.
7
+ */
8
+ import { Component, EventEmitter, Input, Output, ChangeDetectorRef, inject } from '@angular/core';
9
+ import * as i0 from "@angular/core";
10
+ import * as i1 from "@memberjunction/ng-shared-generic";
11
+ const _forTrack0 = ($index, $item) => $item.SourceType;
12
+ const _forTrack1 = ($index, $item) => $item.ID;
13
+ function SearchResultsComponent_Conditional_0_Template(rf, ctx) { if (rf & 1) {
14
+ i0.ɵɵelementStart(0, "div", 0);
15
+ i0.ɵɵelement(1, "mj-loading", 2);
16
+ i0.ɵɵelementEnd();
17
+ } }
18
+ function SearchResultsComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
19
+ i0.ɵɵelementStart(0, "div", 1);
20
+ i0.ɵɵelement(1, "i", 3);
21
+ i0.ɵɵelementStart(2, "p", 4);
22
+ i0.ɵɵtext(3, "No results to display");
23
+ i0.ɵɵelementEnd()();
24
+ } }
25
+ function SearchResultsComponent_Conditional_2_Conditional_3_Template(rf, ctx) { if (rf & 1) {
26
+ i0.ɵɵelementStart(0, "span", 6);
27
+ i0.ɵɵtext(1);
28
+ i0.ɵɵelementEnd();
29
+ } if (rf & 2) {
30
+ const ctx_r0 = i0.ɵɵnextContext(2);
31
+ i0.ɵɵadvance();
32
+ i0.ɵɵtextInterpolate1(" in ", ctx_r0.FormatTime(ctx_r0.ElapsedMs));
33
+ } }
34
+ function SearchResultsComponent_Conditional_2_For_5_Conditional_2_Template(rf, ctx) { if (rf & 1) {
35
+ i0.ɵɵelement(0, "i");
36
+ } if (rf & 2) {
37
+ const group_r3 = i0.ɵɵnextContext().$implicit;
38
+ i0.ɵɵclassMap(group_r3.Icon + " results-group-icon");
39
+ } }
40
+ function SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_9_Template(rf, ctx) { if (rf & 1) {
41
+ i0.ɵɵelementStart(0, "div", 21)(1, "div", 28)(2, "span", 29);
42
+ i0.ɵɵtext(3);
43
+ i0.ɵɵelementEnd()()();
44
+ } if (rf & 2) {
45
+ const result_r5 = i0.ɵɵnextContext().$implicit;
46
+ const ctx_r0 = i0.ɵɵnextContext(3);
47
+ i0.ɵɵadvance(3);
48
+ i0.ɵɵtextInterpolate(ctx_r0.FormatScore(result_r5.Score));
49
+ } }
50
+ function SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Conditional_1_Template(rf, ctx) { if (rf & 1) {
51
+ i0.ɵɵelementStart(0, "div", 30)(1, "span", 40);
52
+ i0.ɵɵtext(2, "Preview");
53
+ i0.ɵɵelementEnd();
54
+ i0.ɵɵelementStart(3, "p", 41);
55
+ i0.ɵɵtext(4);
56
+ i0.ɵɵelementEnd()();
57
+ } if (rf & 2) {
58
+ const result_r5 = i0.ɵɵnextContext(2).$implicit;
59
+ i0.ɵɵadvance(4);
60
+ i0.ɵɵtextInterpolate(result_r5.Snippet);
61
+ } }
62
+ function SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Conditional_15_Conditional_3_Template(rf, ctx) { if (rf & 1) {
63
+ i0.ɵɵtext(0);
64
+ } if (rf & 2) {
65
+ const result_r5 = i0.ɵɵnextContext(3).$implicit;
66
+ i0.ɵɵtextInterpolate1(" Vector: ", (result_r5.ScoreBreakdown.Vector * 100).toFixed(0), "% ");
67
+ } }
68
+ function SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Conditional_15_Conditional_4_Template(rf, ctx) { if (rf & 1) {
69
+ i0.ɵɵtext(0);
70
+ } if (rf & 2) {
71
+ const result_r5 = i0.ɵɵnextContext(3).$implicit;
72
+ i0.ɵɵtextInterpolate1(" FTS: ", (result_r5.ScoreBreakdown.FullText * 100).toFixed(0), "% ");
73
+ } }
74
+ function SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Conditional_15_Template(rf, ctx) { if (rf & 1) {
75
+ i0.ɵɵelementStart(0, "div", 32);
76
+ i0.ɵɵelement(1, "i", 42);
77
+ i0.ɵɵelementStart(2, "span");
78
+ i0.ɵɵconditionalCreate(3, SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Conditional_15_Conditional_3_Template, 1, 1);
79
+ i0.ɵɵconditionalCreate(4, SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Conditional_15_Conditional_4_Template, 1, 1);
80
+ i0.ɵɵelementEnd()();
81
+ } if (rf & 2) {
82
+ const result_r5 = i0.ɵɵnextContext(2).$implicit;
83
+ i0.ɵɵadvance(3);
84
+ i0.ɵɵconditional(result_r5.ScoreBreakdown.Vector ? 3 : -1);
85
+ i0.ɵɵadvance();
86
+ i0.ɵɵconditional(result_r5.ScoreBreakdown.FullText ? 4 : -1);
87
+ } }
88
+ function SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Conditional_16_For_2_Template(rf, ctx) { if (rf & 1) {
89
+ i0.ɵɵelementStart(0, "span", 43);
90
+ i0.ɵɵtext(1);
91
+ i0.ɵɵelementEnd();
92
+ } if (rf & 2) {
93
+ const tag_r7 = ctx.$implicit;
94
+ i0.ɵɵadvance();
95
+ i0.ɵɵtextInterpolate(tag_r7);
96
+ } }
97
+ function SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Conditional_16_Template(rf, ctx) { if (rf & 1) {
98
+ i0.ɵɵelementStart(0, "div", 37);
99
+ i0.ɵɵrepeaterCreate(1, SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Conditional_16_For_2_Template, 2, 1, "span", 43, i0.ɵɵrepeaterTrackByIdentity);
100
+ i0.ɵɵelementEnd();
101
+ } if (rf & 2) {
102
+ const result_r5 = i0.ɵɵnextContext(2).$implicit;
103
+ i0.ɵɵadvance();
104
+ i0.ɵɵrepeater(result_r5.Tags);
105
+ } }
106
+ function SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Template(rf, ctx) { if (rf & 1) {
107
+ const _r6 = i0.ɵɵgetCurrentView();
108
+ i0.ɵɵelementStart(0, "div", 27);
109
+ i0.ɵɵconditionalCreate(1, SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Conditional_1_Template, 5, 1, "div", 30);
110
+ i0.ɵɵelementStart(2, "div", 31)(3, "div", 32);
111
+ i0.ɵɵelement(4, "i", 33);
112
+ i0.ɵɵelementStart(5, "span");
113
+ i0.ɵɵtext(6);
114
+ i0.ɵɵelementEnd()();
115
+ i0.ɵɵelementStart(7, "div", 32);
116
+ i0.ɵɵelement(8, "i", 34);
117
+ i0.ɵɵelementStart(9, "span", 35);
118
+ i0.ɵɵtext(10);
119
+ i0.ɵɵelementEnd()();
120
+ i0.ɵɵelementStart(11, "div", 32);
121
+ i0.ɵɵelement(12, "i", 36);
122
+ i0.ɵɵelementStart(13, "span");
123
+ i0.ɵɵtext(14);
124
+ i0.ɵɵelementEnd()();
125
+ i0.ɵɵconditionalCreate(15, SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Conditional_15_Template, 5, 2, "div", 32);
126
+ i0.ɵɵelementEnd();
127
+ i0.ɵɵconditionalCreate(16, SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Conditional_16_Template, 3, 0, "div", 37);
128
+ i0.ɵɵelementStart(17, "div", 38)(18, "button", 39);
129
+ i0.ɵɵlistener("click", function SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Template_button_click_18_listener($event) { i0.ɵɵrestoreView(_r6); const result_r5 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnOpenRecord(result_r5, $event)); });
130
+ i0.ɵɵelement(19, "i", 24);
131
+ i0.ɵɵtext(20, " Open Record ");
132
+ i0.ɵɵelementEnd()()();
133
+ } if (rf & 2) {
134
+ const result_r5 = i0.ɵɵnextContext().$implicit;
135
+ const ctx_r0 = i0.ɵɵnextContext(3);
136
+ i0.ɵɵadvance();
137
+ i0.ɵɵconditional(result_r5.Snippet ? 1 : -1);
138
+ i0.ɵɵadvance(5);
139
+ i0.ɵɵtextInterpolate(result_r5.EntityName);
140
+ i0.ɵɵadvance(4);
141
+ i0.ɵɵtextInterpolate(result_r5.RecordID);
142
+ i0.ɵɵadvance(4);
143
+ i0.ɵɵtextInterpolate1("", result_r5.SourceType, " match");
144
+ i0.ɵɵadvance();
145
+ i0.ɵɵconditional(result_r5.ScoreBreakdown ? 15 : -1);
146
+ i0.ɵɵadvance();
147
+ i0.ɵɵconditional(ctx_r0.ShowTags && result_r5.Tags.length > 0 ? 16 : -1);
148
+ } }
149
+ function SearchResultsComponent_Conditional_2_For_5_For_9_Template(rf, ctx) { if (rf & 1) {
150
+ const _r4 = i0.ɵɵgetCurrentView();
151
+ i0.ɵɵelementStart(0, "div", 15)(1, "div", 16);
152
+ i0.ɵɵlistener("click", function SearchResultsComponent_Conditional_2_For_5_For_9_Template_div_click_1_listener() { const result_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.ToggleExpand(result_r5)); });
153
+ i0.ɵɵelementStart(2, "div", 17);
154
+ i0.ɵɵelement(3, "i");
155
+ i0.ɵɵelementEnd();
156
+ i0.ɵɵelementStart(4, "div", 18)(5, "div", 19);
157
+ i0.ɵɵtext(6);
158
+ i0.ɵɵelementEnd();
159
+ i0.ɵɵelementStart(7, "div", 20);
160
+ i0.ɵɵtext(8);
161
+ i0.ɵɵelementEnd()();
162
+ i0.ɵɵconditionalCreate(9, SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_9_Template, 4, 1, "div", 21);
163
+ i0.ɵɵelementStart(10, "div", 22)(11, "button", 23);
164
+ i0.ɵɵlistener("click", function SearchResultsComponent_Conditional_2_For_5_For_9_Template_button_click_11_listener($event) { const result_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.OnOpenRecord(result_r5, $event)); });
165
+ i0.ɵɵelement(12, "i", 24);
166
+ i0.ɵɵelementEnd();
167
+ i0.ɵɵelementStart(13, "button", 25);
168
+ i0.ɵɵlistener("click", function SearchResultsComponent_Conditional_2_For_5_For_9_Template_button_click_13_listener($event) { const result_r5 = i0.ɵɵrestoreView(_r4).$implicit; const ctx_r0 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r0.ToggleExpand(result_r5, $event)); });
169
+ i0.ɵɵelement(14, "i", 26);
170
+ i0.ɵɵelementEnd()()();
171
+ i0.ɵɵconditionalCreate(15, SearchResultsComponent_Conditional_2_For_5_For_9_Conditional_15_Template, 21, 6, "div", 27);
172
+ i0.ɵɵelementEnd();
173
+ } if (rf & 2) {
174
+ const result_r5 = ctx.$implicit;
175
+ const ctx_r0 = i0.ɵɵnextContext(3);
176
+ i0.ɵɵclassProp("result-card-expanded", ctx_r0.IsExpanded(result_r5.ID));
177
+ i0.ɵɵadvance(3);
178
+ i0.ɵɵclassMap(result_r5.EntityIcon || result_r5.SourceIcon || "fa-solid fa-database");
179
+ i0.ɵɵadvance(3);
180
+ i0.ɵɵtextInterpolate(result_r5.RecordName || result_r5.Title);
181
+ i0.ɵɵadvance(2);
182
+ i0.ɵɵtextInterpolate(result_r5.EntityName);
183
+ i0.ɵɵadvance();
184
+ i0.ɵɵconditional(ctx_r0.ShowScores ? 9 : -1);
185
+ i0.ɵɵadvance(5);
186
+ i0.ɵɵclassProp("fa-chevron-down", !ctx_r0.IsExpanded(result_r5.ID))("fa-chevron-up", ctx_r0.IsExpanded(result_r5.ID));
187
+ i0.ɵɵadvance();
188
+ i0.ɵɵconditional(ctx_r0.IsExpanded(result_r5.ID) ? 15 : -1);
189
+ } }
190
+ function SearchResultsComponent_Conditional_2_For_5_Conditional_10_Template(rf, ctx) { if (rf & 1) {
191
+ const _r8 = i0.ɵɵgetCurrentView();
192
+ i0.ɵɵelementStart(0, "button", 44);
193
+ i0.ɵɵlistener("click", function SearchResultsComponent_Conditional_2_For_5_Conditional_10_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r8); const group_r3 = i0.ɵɵnextContext().$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.ToggleGroup(group_r3.SourceType)); });
194
+ i0.ɵɵelement(1, "i", 45);
195
+ i0.ɵɵtext(2);
196
+ i0.ɵɵelementEnd();
197
+ } if (rf & 2) {
198
+ const group_r3 = i0.ɵɵnextContext().$implicit;
199
+ const ctx_r0 = i0.ɵɵnextContext(2);
200
+ i0.ɵɵadvance(2);
201
+ i0.ɵɵtextInterpolate1(" Show ", ctx_r0.GetHiddenCount(group_r3), " more results ");
202
+ } }
203
+ function SearchResultsComponent_Conditional_2_For_5_Template(rf, ctx) { if (rf & 1) {
204
+ const _r2 = i0.ɵɵgetCurrentView();
205
+ i0.ɵɵelementStart(0, "div", 7)(1, "div", 8);
206
+ i0.ɵɵlistener("click", function SearchResultsComponent_Conditional_2_For_5_Template_div_click_1_listener() { const group_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.ToggleGroup(group_r3.SourceType)); });
207
+ i0.ɵɵconditionalCreate(2, SearchResultsComponent_Conditional_2_For_5_Conditional_2_Template, 1, 2, "i", 9);
208
+ i0.ɵɵelementStart(3, "span", 10);
209
+ i0.ɵɵtext(4);
210
+ i0.ɵɵelementEnd();
211
+ i0.ɵɵelementStart(5, "span", 11);
212
+ i0.ɵɵtext(6);
213
+ i0.ɵɵelementEnd();
214
+ i0.ɵɵelement(7, "i", 12);
215
+ i0.ɵɵelementEnd();
216
+ i0.ɵɵrepeaterCreate(8, SearchResultsComponent_Conditional_2_For_5_For_9_Template, 16, 12, "div", 13, _forTrack1);
217
+ i0.ɵɵconditionalCreate(10, SearchResultsComponent_Conditional_2_For_5_Conditional_10_Template, 3, 1, "button", 14);
218
+ i0.ɵɵelementEnd();
219
+ } if (rf & 2) {
220
+ const group_r3 = ctx.$implicit;
221
+ const ctx_r0 = i0.ɵɵnextContext(2);
222
+ i0.ɵɵadvance(2);
223
+ i0.ɵɵconditional(ctx_r0.ShowSourceIcons ? 2 : -1);
224
+ i0.ɵɵadvance(2);
225
+ i0.ɵɵtextInterpolate(group_r3.Label);
226
+ i0.ɵɵadvance(2);
227
+ i0.ɵɵtextInterpolate1("(", group_r3.TotalCount, ")");
228
+ i0.ɵɵadvance();
229
+ i0.ɵɵclassProp("fa-chevron-down", !ctx_r0.IsGroupExpanded(group_r3.SourceType))("fa-chevron-up", ctx_r0.IsGroupExpanded(group_r3.SourceType));
230
+ i0.ɵɵadvance();
231
+ i0.ɵɵrepeater(ctx_r0.GetVisibleResults(group_r3));
232
+ i0.ɵɵadvance(2);
233
+ i0.ɵɵconditional(ctx_r0.HasMoreResults(group_r3) ? 10 : -1);
234
+ } }
235
+ function SearchResultsComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
236
+ i0.ɵɵelementStart(0, "div", 5)(1, "span");
237
+ i0.ɵɵtext(2);
238
+ i0.ɵɵelementEnd();
239
+ i0.ɵɵconditionalCreate(3, SearchResultsComponent_Conditional_2_Conditional_3_Template, 2, 1, "span", 6);
240
+ i0.ɵɵelementEnd();
241
+ i0.ɵɵrepeaterCreate(4, SearchResultsComponent_Conditional_2_For_5_Template, 11, 8, "div", 7, _forTrack0);
242
+ } if (rf & 2) {
243
+ const ctx_r0 = i0.ɵɵnextContext();
244
+ i0.ɵɵadvance(2);
245
+ i0.ɵɵtextInterpolate1("", ctx_r0.TotalCount, " results");
246
+ i0.ɵɵadvance();
247
+ i0.ɵɵconditional(ctx_r0.ElapsedMs > 0 ? 3 : -1);
248
+ i0.ɵɵadvance();
249
+ i0.ɵɵrepeater(ctx_r0.ResultGroups);
250
+ } }
251
+ export class SearchResultsComponent {
252
+ cdr = inject(ChangeDetectorRef);
253
+ /** Grouped search results to display */
254
+ ResultGroups = [];
255
+ /** Whether results are currently loading */
256
+ IsLoading = false;
257
+ /** Total result count */
258
+ TotalCount = 0;
259
+ /** Elapsed search time in ms */
260
+ ElapsedMs = 0;
261
+ /** Maximum results per group before "Show more" */
262
+ MaxPerGroup = 5;
263
+ /** Whether to show score badges */
264
+ ShowScores = true;
265
+ /** Whether to show tags */
266
+ ShowTags = true;
267
+ /** Whether to show source type icons */
268
+ ShowSourceIcons = true;
269
+ ResultSelected = new EventEmitter();
270
+ /** Emitted when user clicks "Open Record" — parent handles navigation */
271
+ OpenRecordRequested = new EventEmitter();
272
+ /** Tracks which groups are expanded */
273
+ ExpandedGroups = new Set();
274
+ /** Set of expanded result card IDs — multiple can be open simultaneously */
275
+ ExpandedResultIDs = new Set();
276
+ /** Toggle group expansion */
277
+ ToggleGroup(sourceType) {
278
+ if (this.ExpandedGroups.has(sourceType)) {
279
+ this.ExpandedGroups.delete(sourceType);
280
+ }
281
+ else {
282
+ this.ExpandedGroups.add(sourceType);
283
+ }
284
+ this.cdr.detectChanges();
285
+ }
286
+ /** Whether a group is expanded */
287
+ IsGroupExpanded(sourceType) {
288
+ return this.ExpandedGroups.has(sourceType);
289
+ }
290
+ /** Get visible results for a group (respecting max per group unless expanded) */
291
+ GetVisibleResults(group) {
292
+ if (this.IsGroupExpanded(group.SourceType)) {
293
+ return group.Results;
294
+ }
295
+ return group.Results.slice(0, this.MaxPerGroup);
296
+ }
297
+ /** Whether a group has more results than shown */
298
+ HasMoreResults(group) {
299
+ return group.Results.length > this.MaxPerGroup && !this.IsGroupExpanded(group.SourceType);
300
+ }
301
+ /** Get the count of hidden results */
302
+ GetHiddenCount(group) {
303
+ return group.Results.length - this.MaxPerGroup;
304
+ }
305
+ /** Handle clicking a result */
306
+ OnResultClick(result, event) {
307
+ this.ResultSelected.emit({
308
+ Result: result,
309
+ OpenInNewTab: event.metaKey || event.ctrlKey
310
+ });
311
+ }
312
+ /** Toggle expand/collapse of a result card — multiple can be open */
313
+ ToggleExpand(result, event) {
314
+ if (event)
315
+ event.stopPropagation();
316
+ if (this.ExpandedResultIDs.has(result.ID)) {
317
+ this.ExpandedResultIDs.delete(result.ID);
318
+ }
319
+ else {
320
+ this.ExpandedResultIDs.add(result.ID);
321
+ }
322
+ this.cdr.detectChanges();
323
+ }
324
+ /** Check if a result card is expanded */
325
+ IsExpanded(resultID) {
326
+ return this.ExpandedResultIDs.has(resultID);
327
+ }
328
+ /** Handle "Open Record" button click */
329
+ OnOpenRecord(result, event) {
330
+ event.stopPropagation();
331
+ this.OpenRecordRequested.emit({
332
+ EntityName: result.EntityName,
333
+ RecordID: result.RecordID
334
+ });
335
+ }
336
+ /** Format a score as a percentage */
337
+ FormatScore(score) {
338
+ return `${Math.round(score * 100)}%`;
339
+ }
340
+ /** Format elapsed time */
341
+ FormatTime(ms) {
342
+ if (ms < 1000)
343
+ return `${ms}ms`;
344
+ return `${(ms / 1000).toFixed(1)}s`;
345
+ }
346
+ static ɵfac = function SearchResultsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SearchResultsComponent)(); };
347
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SearchResultsComponent, selectors: [["mj-search-results"]], inputs: { ResultGroups: "ResultGroups", IsLoading: "IsLoading", TotalCount: "TotalCount", ElapsedMs: "ElapsedMs", MaxPerGroup: "MaxPerGroup", ShowScores: "ShowScores", ShowTags: "ShowTags", ShowSourceIcons: "ShowSourceIcons" }, outputs: { ResultSelected: "ResultSelected", OpenRecordRequested: "OpenRecordRequested" }, standalone: false, decls: 3, vars: 1, consts: [[1, "results-loading"], [1, "results-empty"], ["text", "Searching...", "size", "medium"], [1, "fa-solid", "fa-search", "results-empty-icon"], [1, "results-empty-text"], [1, "results-summary"], [1, "results-summary-time"], [1, "results-group"], [1, "results-group-header", 3, "click"], [3, "class"], [1, "results-group-label"], [1, "results-group-count"], [1, "fa-solid", "results-group-chevron"], [1, "result-card", 3, "result-card-expanded"], [1, "results-show-more"], [1, "result-card"], [1, "result-card-main", 3, "click"], [1, "result-card-icon-wrap"], [1, "result-card-body"], [1, "result-card-title"], [1, "result-card-entity"], [1, "result-card-score"], [1, "result-card-actions"], ["title", "Open record", 1, "result-open-btn", 3, "click"], [1, "fa-solid", "fa-arrow-up-right-from-square"], ["title", "Expand details", 1, "result-expand-btn", 3, "click"], [1, "fa-solid"], [1, "result-card-detail"], [1, "score-circle"], [1, "score-value"], [1, "detail-section"], [1, "detail-meta"], [1, "detail-meta-item"], [1, "fa-solid", "fa-layer-group"], [1, "fa-solid", "fa-fingerprint"], [1, "detail-record-id"], [1, "fa-solid", "fa-signal"], [1, "detail-tags"], [1, "detail-actions"], [1, "detail-open-btn", 3, "click"], [1, "detail-label"], [1, "detail-snippet"], [1, "fa-solid", "fa-chart-bar"], [1, "result-card-tag"], [1, "results-show-more", 3, "click"], [1, "fa-solid", "fa-chevron-down"]], template: function SearchResultsComponent_Template(rf, ctx) { if (rf & 1) {
348
+ i0.ɵɵconditionalCreate(0, SearchResultsComponent_Conditional_0_Template, 2, 0, "div", 0)(1, SearchResultsComponent_Conditional_1_Template, 4, 0, "div", 1)(2, SearchResultsComponent_Conditional_2_Template, 6, 2);
349
+ } if (rf & 2) {
350
+ i0.ɵɵconditional(ctx.IsLoading ? 0 : ctx.ResultGroups.length === 0 && ctx.TotalCount === 0 ? 1 : 2);
351
+ } }, dependencies: [i1.LoadingComponent], styles: ["\n\n\n.results-loading[_ngcontent-%COMP%] {\n display: flex;\n justify-content: center;\n padding: 3rem 1rem;\n}\n\n.results-empty[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 3rem 1rem;\n gap: 0.5rem;\n}\n\n.results-empty-icon[_ngcontent-%COMP%] {\n font-size: 2rem;\n color: var(--mj-text-muted);\n margin-bottom: 0.5rem;\n}\n\n.results-empty-text[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 0.9rem;\n}\n\n.results-summary[_ngcontent-%COMP%] {\n padding: 0.75rem 1rem;\n color: var(--mj-text-secondary);\n font-size: 0.85rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.results-summary-time[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n\n\n.results-group[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.results-group-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n cursor: pointer;\n transition: background 0.1s ease;\n}\n\n.results-group-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.results-group-icon[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n}\n\n.results-group-label[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 0.85rem;\n color: var(--mj-text-primary);\n flex: 1;\n}\n\n.results-group-count[_ngcontent-%COMP%] {\n font-size: 0.78rem;\n color: var(--mj-text-muted);\n}\n\n.results-group-chevron[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 0.7rem;\n transition: transform 0.2s ease;\n}\n\n\n\n.result-card[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n margin: 0 0 0.35rem 1.5rem;\n overflow: hidden;\n transition: border-color 0.15s, box-shadow 0.15s;\n}\n\n.result-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-default);\n}\n\n.result-card-expanded[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.result-card-main[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.65rem 0.85rem;\n cursor: pointer;\n transition: background 0.1s ease;\n}\n\n.result-card-main[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.result-card-icon-wrap[_ngcontent-%COMP%] {\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.8rem;\n flex-shrink: 0;\n}\n\n.result-card-body[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.result-card-title[_ngcontent-%COMP%] {\n color: var(--mj-text-primary);\n font-weight: 600;\n font-size: 0.85rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.result-card-entity[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 0.7rem;\n}\n\n.result-card-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-shrink: 0;\n}\n\n.result-open-btn[_ngcontent-%COMP%], \n.result-expand-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: transparent;\n color: var(--mj-text-muted);\n font-size: 11px;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.result-open-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.result-expand-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n\n\n.result-card-detail[_ngcontent-%COMP%] {\n padding: 0.75rem 1rem 0.85rem 3.5rem;\n border-top: 1px solid var(--mj-border-subtle);\n background: var(--mj-bg-surface-card);\n}\n\n.detail-section[_ngcontent-%COMP%] {\n margin-bottom: 0.65rem;\n}\n\n.detail-label[_ngcontent-%COMP%] {\n font-size: 0.7rem;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n margin-bottom: 0.25rem;\n display: block;\n}\n\n.detail-snippet[_ngcontent-%COMP%] {\n margin: 0;\n font-size: 0.82rem;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n.detail-meta[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 0.75rem;\n margin-bottom: 0.65rem;\n}\n\n.detail-meta-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 0.75rem;\n color: var(--mj-text-muted);\n}\n\n.detail-meta-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: 0.65rem;\n}\n\n.detail-record-id[_ngcontent-%COMP%] {\n font-family: monospace;\n font-size: 0.7rem;\n max-width: 180px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.detail-tags[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin-bottom: 0.65rem;\n}\n\n.detail-actions[_ngcontent-%COMP%] {\n display: flex;\n gap: 8px;\n}\n\n.detail-open-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border: 1px solid var(--mj-brand-primary);\n border-radius: 6px;\n background: transparent;\n color: var(--mj-brand-primary);\n font-size: 0.78rem;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.detail-open-btn[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.result-card-snippet[_ngcontent-%COMP%] {\n color: var(--mj-text-secondary);\n font-size: 0.82rem;\n line-height: 1.4;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.result-card-tags[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n margin-top: 0.35rem;\n}\n\n.result-card-tag[_ngcontent-%COMP%] {\n display: inline-block;\n padding: 0.1rem 0.4rem;\n border-radius: 4px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n font-size: 0.7rem;\n}\n\n.result-card-tag-more[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.result-card-score[_ngcontent-%COMP%] {\n flex-shrink: 0;\n margin-top: 0.2rem;\n}\n\n.score-circle[_ngcontent-%COMP%] {\n width: 2.5rem;\n height: 2.5rem;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n}\n\n.score-value[_ngcontent-%COMP%] {\n font-size: 0.7rem;\n font-weight: 700;\n color: var(--mj-brand-primary);\n}\n\n\n\n.results-show-more[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.5rem 1rem;\n border: none;\n background: transparent;\n color: var(--mj-brand-primary);\n font-size: 0.82rem;\n cursor: pointer;\n justify-content: center;\n transition: background 0.1s ease;\n}\n\n.results-show-more[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}"] });
352
+ }
353
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SearchResultsComponent, [{
354
+ type: Component,
355
+ args: [{ standalone: false, selector: 'mj-search-results', template: "@if (IsLoading) {\n <div class=\"results-loading\">\n <mj-loading text=\"Searching...\" size=\"medium\"></mj-loading>\n </div>\n} @else if (ResultGroups.length === 0 && TotalCount === 0) {\n <div class=\"results-empty\">\n <i class=\"fa-solid fa-search results-empty-icon\"></i>\n <p class=\"results-empty-text\">No results to display</p>\n </div>\n} @else {\n <!-- Results summary -->\n <div class=\"results-summary\">\n <span>{{ TotalCount }} results</span>\n @if (ElapsedMs > 0) {\n <span class=\"results-summary-time\"> in {{ FormatTime(ElapsedMs) }}</span>\n }\n </div>\n\n <!-- Grouped results -->\n @for (group of ResultGroups; track group.SourceType) {\n <div class=\"results-group\">\n <div class=\"results-group-header\" (click)=\"ToggleGroup(group.SourceType)\">\n @if (ShowSourceIcons) {\n <i [class]=\"group.Icon + ' results-group-icon'\"></i>\n }\n <span class=\"results-group-label\">{{ group.Label }}</span>\n <span class=\"results-group-count\">({{ group.TotalCount }})</span>\n <i class=\"fa-solid results-group-chevron\"\n [class.fa-chevron-down]=\"!IsGroupExpanded(group.SourceType)\"\n [class.fa-chevron-up]=\"IsGroupExpanded(group.SourceType)\"></i>\n </div>\n\n @for (result of GetVisibleResults(group); track result.ID) {\n <div class=\"result-card\" [class.result-card-expanded]=\"IsExpanded(result.ID)\">\n <!-- Main row -->\n <div class=\"result-card-main\" (click)=\"ToggleExpand(result)\">\n <div class=\"result-card-icon-wrap\">\n <i [class]=\"result.EntityIcon || result.SourceIcon || 'fa-solid fa-database'\"></i>\n </div>\n <div class=\"result-card-body\">\n <div class=\"result-card-title\">{{ result.RecordName || result.Title }}</div>\n <div class=\"result-card-entity\">{{ result.EntityName }}</div>\n </div>\n @if (ShowScores) {\n <div class=\"result-card-score\">\n <div class=\"score-circle\">\n <span class=\"score-value\">{{ FormatScore(result.Score) }}</span>\n </div>\n </div>\n }\n <div class=\"result-card-actions\">\n <button class=\"result-open-btn\" (click)=\"OnOpenRecord(result, $event)\" title=\"Open record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i>\n </button>\n <button class=\"result-expand-btn\" (click)=\"ToggleExpand(result, $event)\" title=\"Expand details\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!IsExpanded(result.ID)\"\n [class.fa-chevron-up]=\"IsExpanded(result.ID)\"></i>\n </button>\n </div>\n </div>\n\n <!-- Expanded detail -->\n @if (IsExpanded(result.ID)) {\n <div class=\"result-card-detail\">\n @if (result.Snippet) {\n <div class=\"detail-section\">\n <span class=\"detail-label\">Preview</span>\n <p class=\"detail-snippet\">{{ result.Snippet }}</p>\n </div>\n }\n <div class=\"detail-meta\">\n <div class=\"detail-meta-item\">\n <i class=\"fa-solid fa-layer-group\"></i>\n <span>{{ result.EntityName }}</span>\n </div>\n <div class=\"detail-meta-item\">\n <i class=\"fa-solid fa-fingerprint\"></i>\n <span class=\"detail-record-id\">{{ result.RecordID }}</span>\n </div>\n <div class=\"detail-meta-item\">\n <i class=\"fa-solid fa-signal\"></i>\n <span>{{ result.SourceType }} match</span>\n </div>\n @if (result.ScoreBreakdown) {\n <div class=\"detail-meta-item\">\n <i class=\"fa-solid fa-chart-bar\"></i>\n <span>\n @if (result.ScoreBreakdown.Vector) { Vector: {{ (result.ScoreBreakdown.Vector * 100).toFixed(0) }}% }\n @if (result.ScoreBreakdown.FullText) { FTS: {{ (result.ScoreBreakdown.FullText * 100).toFixed(0) }}% }\n </span>\n </div>\n }\n </div>\n @if (ShowTags && result.Tags.length > 0) {\n <div class=\"detail-tags\">\n @for (tag of result.Tags; track tag) {\n <span class=\"result-card-tag\">{{ tag }}</span>\n }\n </div>\n }\n <div class=\"detail-actions\">\n <button class=\"detail-open-btn\" (click)=\"OnOpenRecord(result, $event)\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Open Record\n </button>\n </div>\n </div>\n }\n </div>\n }\n\n @if (HasMoreResults(group)) {\n <button class=\"results-show-more\" (click)=\"ToggleGroup(group.SourceType)\">\n <i class=\"fa-solid fa-chevron-down\"></i>\n Show {{ GetHiddenCount(group) }} more results\n </button>\n }\n </div>\n }\n}\n", styles: ["/* Search Results Component */\n\n.results-loading {\n display: flex;\n justify-content: center;\n padding: 3rem 1rem;\n}\n\n.results-empty {\n display: flex;\n flex-direction: column;\n align-items: center;\n padding: 3rem 1rem;\n gap: 0.5rem;\n}\n\n.results-empty-icon {\n font-size: 2rem;\n color: var(--mj-text-muted);\n margin-bottom: 0.5rem;\n}\n\n.results-empty-text {\n color: var(--mj-text-muted);\n font-size: 0.9rem;\n}\n\n.results-summary {\n padding: 0.75rem 1rem;\n color: var(--mj-text-secondary);\n font-size: 0.85rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.results-summary-time {\n color: var(--mj-text-muted);\n}\n\n/* Group Header */\n.results-group {\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.results-group-header {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.75rem 1rem;\n cursor: pointer;\n transition: background 0.1s ease;\n}\n\n.results-group-header:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.results-group-icon {\n color: var(--mj-brand-primary);\n font-size: 0.85rem;\n}\n\n.results-group-label {\n font-weight: 600;\n font-size: 0.85rem;\n color: var(--mj-text-primary);\n flex: 1;\n}\n\n.results-group-count {\n font-size: 0.78rem;\n color: var(--mj-text-muted);\n}\n\n.results-group-chevron {\n color: var(--mj-text-muted);\n font-size: 0.7rem;\n transition: transform 0.2s ease;\n}\n\n/* Result Card \u2014 expandable */\n.result-card {\n border: 1px solid var(--mj-border-subtle);\n border-radius: 8px;\n margin: 0 0 0.35rem 1.5rem;\n overflow: hidden;\n transition: border-color 0.15s, box-shadow 0.15s;\n}\n\n.result-card:hover {\n border-color: var(--mj-border-default);\n}\n\n.result-card-expanded {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.result-card-main {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n padding: 0.65rem 0.85rem;\n cursor: pointer;\n transition: background 0.1s ease;\n}\n\n.result-card-main:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.result-card-icon-wrap {\n width: 2rem;\n height: 2rem;\n display: flex;\n align-items: center;\n justify-content: center;\n border-radius: 6px;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n font-size: 0.8rem;\n flex-shrink: 0;\n}\n\n.result-card-body {\n flex: 1;\n min-width: 0;\n}\n\n.result-card-title {\n color: var(--mj-text-primary);\n font-weight: 600;\n font-size: 0.85rem;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.result-card-entity {\n color: var(--mj-text-muted);\n font-size: 0.7rem;\n}\n\n.result-card-actions {\n display: flex;\n align-items: center;\n gap: 4px;\n flex-shrink: 0;\n}\n\n.result-open-btn,\n.result-expand-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n background: transparent;\n color: var(--mj-text-muted);\n font-size: 11px;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.result-open-btn:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border-color: var(--mj-brand-primary);\n color: var(--mj-brand-primary);\n}\n\n.result-expand-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* Expanded detail panel */\n.result-card-detail {\n padding: 0.75rem 1rem 0.85rem 3.5rem;\n border-top: 1px solid var(--mj-border-subtle);\n background: var(--mj-bg-surface-card);\n}\n\n.detail-section {\n margin-bottom: 0.65rem;\n}\n\n.detail-label {\n font-size: 0.7rem;\n font-weight: 600;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n margin-bottom: 0.25rem;\n display: block;\n}\n\n.detail-snippet {\n margin: 0;\n font-size: 0.82rem;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n.detail-meta {\n display: flex;\n flex-wrap: wrap;\n gap: 0.75rem;\n margin-bottom: 0.65rem;\n}\n\n.detail-meta-item {\n display: flex;\n align-items: center;\n gap: 5px;\n font-size: 0.75rem;\n color: var(--mj-text-muted);\n}\n\n.detail-meta-item i {\n font-size: 0.65rem;\n}\n\n.detail-record-id {\n font-family: monospace;\n font-size: 0.7rem;\n max-width: 180px;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n.detail-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n margin-bottom: 0.65rem;\n}\n\n.detail-actions {\n display: flex;\n gap: 8px;\n}\n\n.detail-open-btn {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n padding: 6px 14px;\n border: 1px solid var(--mj-brand-primary);\n border-radius: 6px;\n background: transparent;\n color: var(--mj-brand-primary);\n font-size: 0.78rem;\n font-weight: 500;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.detail-open-btn:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.result-card-snippet {\n color: var(--mj-text-secondary);\n font-size: 0.82rem;\n line-height: 1.4;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.result-card-tags {\n display: flex;\n flex-wrap: wrap;\n gap: 0.25rem;\n margin-top: 0.35rem;\n}\n\n.result-card-tag {\n display: inline-block;\n padding: 0.1rem 0.4rem;\n border-radius: 4px;\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n font-size: 0.7rem;\n}\n\n.result-card-tag-more {\n color: var(--mj-brand-primary);\n}\n\n.result-card-score {\n flex-shrink: 0;\n margin-top: 0.2rem;\n}\n\n.score-circle {\n width: 2.5rem;\n height: 2.5rem;\n border-radius: 50%;\n display: flex;\n align-items: center;\n justify-content: center;\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n border: 2px solid color-mix(in srgb, var(--mj-brand-primary) 30%, var(--mj-bg-surface));\n}\n\n.score-value {\n font-size: 0.7rem;\n font-weight: 700;\n color: var(--mj-brand-primary);\n}\n\n/* Show More Button */\n.results-show-more {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n width: 100%;\n padding: 0.5rem 1rem;\n border: none;\n background: transparent;\n color: var(--mj-brand-primary);\n font-size: 0.82rem;\n cursor: pointer;\n justify-content: center;\n transition: background 0.1s ease;\n}\n\n.results-show-more:hover {\n background: var(--mj-bg-surface-hover);\n}\n"] }]
356
+ }], null, { ResultGroups: [{
357
+ type: Input
358
+ }], IsLoading: [{
359
+ type: Input
360
+ }], TotalCount: [{
361
+ type: Input
362
+ }], ElapsedMs: [{
363
+ type: Input
364
+ }], MaxPerGroup: [{
365
+ type: Input
366
+ }], ShowScores: [{
367
+ type: Input
368
+ }], ShowTags: [{
369
+ type: Input
370
+ }], ShowSourceIcons: [{
371
+ type: Input
372
+ }], ResultSelected: [{
373
+ type: Output
374
+ }], OpenRecordRequested: [{
375
+ type: Output
376
+ }] }); })();
377
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SearchResultsComponent, { className: "SearchResultsComponent", filePath: "src/lib/search-results.component.ts", lineNumber: 25 }); })();
378
+ //# sourceMappingURL=search-results.component.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search-results.component.js","sourceRoot":"","sources":["../../src/lib/search-results.component.ts","../../src/lib/search-results.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Search Results Component\n *\n * Displays search results grouped by source type with expandable sections.\n * Used both within the search overlay and as a standalone results view\n * in the Knowledge Hub search dashboard.\n */\n\nimport {\n Component,\n EventEmitter,\n Input,\n Output,\n ChangeDetectorRef,\n inject\n} from '@angular/core';\nimport { SearchResultItem, SearchResultGroup, SearchResultSelectedEvent } from './search-types';\n\n@Component({\n standalone: false,\n selector: 'mj-search-results',\n templateUrl: './search-results.component.html',\n styleUrls: ['./search-results.component.css']\n})\nexport class SearchResultsComponent {\n private cdr = inject(ChangeDetectorRef);\n\n /** Grouped search results to display */\n @Input() ResultGroups: SearchResultGroup[] = [];\n\n /** Whether results are currently loading */\n @Input() IsLoading = false;\n\n /** Total result count */\n @Input() TotalCount = 0;\n\n /** Elapsed search time in ms */\n @Input() ElapsedMs = 0;\n\n /** Maximum results per group before \"Show more\" */\n @Input() MaxPerGroup = 5;\n\n /** Whether to show score badges */\n @Input() ShowScores = true;\n\n /** Whether to show tags */\n @Input() ShowTags = true;\n\n /** Whether to show source type icons */\n @Input() ShowSourceIcons = true;\n\n @Output() ResultSelected = new EventEmitter<SearchResultSelectedEvent>();\n\n /** Emitted when user clicks \"Open Record\" — parent handles navigation */\n @Output() OpenRecordRequested = new EventEmitter<{ EntityName: string; RecordID: string }>();\n\n /** Tracks which groups are expanded */\n public ExpandedGroups = new Set<string>();\n\n /** Set of expanded result card IDs — multiple can be open simultaneously */\n public ExpandedResultIDs = new Set<string>();\n\n /** Toggle group expansion */\n public ToggleGroup(sourceType: string): void {\n if (this.ExpandedGroups.has(sourceType)) {\n this.ExpandedGroups.delete(sourceType);\n } else {\n this.ExpandedGroups.add(sourceType);\n }\n this.cdr.detectChanges();\n }\n\n /** Whether a group is expanded */\n public IsGroupExpanded(sourceType: string): boolean {\n return this.ExpandedGroups.has(sourceType);\n }\n\n /** Get visible results for a group (respecting max per group unless expanded) */\n public GetVisibleResults(group: SearchResultGroup): SearchResultItem[] {\n if (this.IsGroupExpanded(group.SourceType)) {\n return group.Results;\n }\n return group.Results.slice(0, this.MaxPerGroup);\n }\n\n /** Whether a group has more results than shown */\n public HasMoreResults(group: SearchResultGroup): boolean {\n return group.Results.length > this.MaxPerGroup && !this.IsGroupExpanded(group.SourceType);\n }\n\n /** Get the count of hidden results */\n public GetHiddenCount(group: SearchResultGroup): number {\n return group.Results.length - this.MaxPerGroup;\n }\n\n /** Handle clicking a result */\n public OnResultClick(result: SearchResultItem, event: MouseEvent): void {\n this.ResultSelected.emit({\n Result: result,\n OpenInNewTab: event.metaKey || event.ctrlKey\n });\n }\n\n /** Toggle expand/collapse of a result card — multiple can be open */\n public ToggleExpand(result: SearchResultItem, event?: MouseEvent): void {\n if (event) event.stopPropagation();\n if (this.ExpandedResultIDs.has(result.ID)) {\n this.ExpandedResultIDs.delete(result.ID);\n } else {\n this.ExpandedResultIDs.add(result.ID);\n }\n this.cdr.detectChanges();\n }\n\n /** Check if a result card is expanded */\n public IsExpanded(resultID: string): boolean {\n return this.ExpandedResultIDs.has(resultID);\n }\n\n /** Handle \"Open Record\" button click */\n public OnOpenRecord(result: SearchResultItem, event: MouseEvent): void {\n event.stopPropagation();\n this.OpenRecordRequested.emit({\n EntityName: result.EntityName,\n RecordID: result.RecordID\n });\n }\n\n /** Format a score as a percentage */\n public FormatScore(score: number): string {\n return `${Math.round(score * 100)}%`;\n }\n\n /** Format elapsed time */\n public FormatTime(ms: number): string {\n if (ms < 1000) return `${ms}ms`;\n return `${(ms / 1000).toFixed(1)}s`;\n }\n}\n","@if (IsLoading) {\n <div class=\"results-loading\">\n <mj-loading text=\"Searching...\" size=\"medium\"></mj-loading>\n </div>\n} @else if (ResultGroups.length === 0 && TotalCount === 0) {\n <div class=\"results-empty\">\n <i class=\"fa-solid fa-search results-empty-icon\"></i>\n <p class=\"results-empty-text\">No results to display</p>\n </div>\n} @else {\n <!-- Results summary -->\n <div class=\"results-summary\">\n <span>{{ TotalCount }} results</span>\n @if (ElapsedMs > 0) {\n <span class=\"results-summary-time\"> in {{ FormatTime(ElapsedMs) }}</span>\n }\n </div>\n\n <!-- Grouped results -->\n @for (group of ResultGroups; track group.SourceType) {\n <div class=\"results-group\">\n <div class=\"results-group-header\" (click)=\"ToggleGroup(group.SourceType)\">\n @if (ShowSourceIcons) {\n <i [class]=\"group.Icon + ' results-group-icon'\"></i>\n }\n <span class=\"results-group-label\">{{ group.Label }}</span>\n <span class=\"results-group-count\">({{ group.TotalCount }})</span>\n <i class=\"fa-solid results-group-chevron\"\n [class.fa-chevron-down]=\"!IsGroupExpanded(group.SourceType)\"\n [class.fa-chevron-up]=\"IsGroupExpanded(group.SourceType)\"></i>\n </div>\n\n @for (result of GetVisibleResults(group); track result.ID) {\n <div class=\"result-card\" [class.result-card-expanded]=\"IsExpanded(result.ID)\">\n <!-- Main row -->\n <div class=\"result-card-main\" (click)=\"ToggleExpand(result)\">\n <div class=\"result-card-icon-wrap\">\n <i [class]=\"result.EntityIcon || result.SourceIcon || 'fa-solid fa-database'\"></i>\n </div>\n <div class=\"result-card-body\">\n <div class=\"result-card-title\">{{ result.RecordName || result.Title }}</div>\n <div class=\"result-card-entity\">{{ result.EntityName }}</div>\n </div>\n @if (ShowScores) {\n <div class=\"result-card-score\">\n <div class=\"score-circle\">\n <span class=\"score-value\">{{ FormatScore(result.Score) }}</span>\n </div>\n </div>\n }\n <div class=\"result-card-actions\">\n <button class=\"result-open-btn\" (click)=\"OnOpenRecord(result, $event)\" title=\"Open record\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i>\n </button>\n <button class=\"result-expand-btn\" (click)=\"ToggleExpand(result, $event)\" title=\"Expand details\">\n <i class=\"fa-solid\" [class.fa-chevron-down]=\"!IsExpanded(result.ID)\"\n [class.fa-chevron-up]=\"IsExpanded(result.ID)\"></i>\n </button>\n </div>\n </div>\n\n <!-- Expanded detail -->\n @if (IsExpanded(result.ID)) {\n <div class=\"result-card-detail\">\n @if (result.Snippet) {\n <div class=\"detail-section\">\n <span class=\"detail-label\">Preview</span>\n <p class=\"detail-snippet\">{{ result.Snippet }}</p>\n </div>\n }\n <div class=\"detail-meta\">\n <div class=\"detail-meta-item\">\n <i class=\"fa-solid fa-layer-group\"></i>\n <span>{{ result.EntityName }}</span>\n </div>\n <div class=\"detail-meta-item\">\n <i class=\"fa-solid fa-fingerprint\"></i>\n <span class=\"detail-record-id\">{{ result.RecordID }}</span>\n </div>\n <div class=\"detail-meta-item\">\n <i class=\"fa-solid fa-signal\"></i>\n <span>{{ result.SourceType }} match</span>\n </div>\n @if (result.ScoreBreakdown) {\n <div class=\"detail-meta-item\">\n <i class=\"fa-solid fa-chart-bar\"></i>\n <span>\n @if (result.ScoreBreakdown.Vector) { Vector: {{ (result.ScoreBreakdown.Vector * 100).toFixed(0) }}% }\n @if (result.ScoreBreakdown.FullText) { FTS: {{ (result.ScoreBreakdown.FullText * 100).toFixed(0) }}% }\n </span>\n </div>\n }\n </div>\n @if (ShowTags && result.Tags.length > 0) {\n <div class=\"detail-tags\">\n @for (tag of result.Tags; track tag) {\n <span class=\"result-card-tag\">{{ tag }}</span>\n }\n </div>\n }\n <div class=\"detail-actions\">\n <button class=\"detail-open-btn\" (click)=\"OnOpenRecord(result, $event)\">\n <i class=\"fa-solid fa-arrow-up-right-from-square\"></i> Open Record\n </button>\n </div>\n </div>\n }\n </div>\n }\n\n @if (HasMoreResults(group)) {\n <button class=\"results-show-more\" (click)=\"ToggleGroup(group.SourceType)\">\n <i class=\"fa-solid fa-chevron-down\"></i>\n Show {{ GetHiddenCount(group) }} more results\n </button>\n }\n </div>\n }\n}\n"]}