@memberjunction/ng-search 0.0.1 → 5.23.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.d.ts +2 -0
- package/dist/__tests__/search-types.test.d.ts.map +1 -0
- package/dist/__tests__/search-types.test.js +107 -0
- package/dist/__tests__/search-types.test.js.map +1 -0
- package/dist/__tests__/search.service.test.d.ts +2 -0
- package/dist/__tests__/search.service.test.d.ts.map +1 -0
- package/dist/__tests__/search.service.test.js +183 -0
- package/dist/__tests__/search.service.test.js.map +1 -0
- package/dist/lib/module.d.ts +13 -0
- package/dist/lib/module.d.ts.map +1 -0
- package/dist/lib/module.js +43 -0
- package/dist/lib/module.js.map +1 -0
- package/dist/lib/search-filter.component.d.ts +39 -0
- package/dist/lib/search-filter.component.d.ts.map +1 -0
- package/dist/lib/search-filter.component.js +200 -0
- package/dist/lib/search-filter.component.js.map +1 -0
- package/dist/lib/search-overlay.component.d.ts +103 -0
- package/dist/lib/search-overlay.component.d.ts.map +1 -0
- package/dist/lib/search-overlay.component.js +626 -0
- package/dist/lib/search-overlay.component.js.map +1 -0
- package/dist/lib/search-results.component.d.ts +64 -0
- package/dist/lib/search-results.component.d.ts.map +1 -0
- package/dist/lib/search-results.component.js +378 -0
- package/dist/lib/search-results.component.js.map +1 -0
- package/dist/lib/search-types.d.ts +142 -0
- package/dist/lib/search-types.d.ts.map +1 -0
- package/dist/lib/search-types.js +8 -0
- package/dist/lib/search-types.js.map +1 -0
- package/dist/lib/search.service.d.ts +52 -0
- package/dist/lib/search.service.d.ts.map +1 -0
- package/dist/lib/search.service.js +287 -0
- package/dist/lib/search.service.js.map +1 -0
- package/dist/public-api.d.ts +7 -0
- package/dist/public-api.d.ts.map +1 -0
- package/dist/public-api.js +10 -0
- package/dist/public-api.js.map +1 -0
- package/package.json +38 -7
- package/README.md +0 -45
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Shared types for the ng-search package.
|
|
3
|
+
*
|
|
4
|
+
* Defines the data contracts for search results, filters,
|
|
5
|
+
* and events used across all search components.
|
|
6
|
+
*/
|
|
7
|
+
/** Represents a single search result item */
|
|
8
|
+
export interface SearchResultItem {
|
|
9
|
+
/** Unique identifier */
|
|
10
|
+
ID: string;
|
|
11
|
+
/** Display title */
|
|
12
|
+
Title: string;
|
|
13
|
+
/** Short text snippet showing match context */
|
|
14
|
+
Snippet: string;
|
|
15
|
+
/** The entity name this result belongs to */
|
|
16
|
+
EntityName: string;
|
|
17
|
+
/** The primary key of the source record */
|
|
18
|
+
RecordID: string;
|
|
19
|
+
/** Classification of the result source */
|
|
20
|
+
SourceType: 'entity' | 'content-item' | 'file' | 'web-page';
|
|
21
|
+
/** Relevance score between 0 and 1 */
|
|
22
|
+
Score: number;
|
|
23
|
+
/** Breakdown of how the score was computed */
|
|
24
|
+
ScoreBreakdown: ScoreBreakdown;
|
|
25
|
+
/** Human-readable tags */
|
|
26
|
+
Tags: string[];
|
|
27
|
+
/** Font Awesome icon class for the source type */
|
|
28
|
+
SourceIcon: string;
|
|
29
|
+
/** Entity-specific icon from EntityInfo.Icon (e.g., "fa-solid fa-robot") */
|
|
30
|
+
EntityIcon?: string;
|
|
31
|
+
/** Human-readable record name resolved from EntityRecordName */
|
|
32
|
+
RecordName?: string;
|
|
33
|
+
/** When this result was matched */
|
|
34
|
+
MatchedAt: Date;
|
|
35
|
+
}
|
|
36
|
+
/** Breakdown of score contribution from each search source */
|
|
37
|
+
export interface ScoreBreakdown {
|
|
38
|
+
Vector?: number;
|
|
39
|
+
FullText?: number;
|
|
40
|
+
Entity?: number;
|
|
41
|
+
}
|
|
42
|
+
/** Grouped search results by source type */
|
|
43
|
+
export interface SearchResultGroup {
|
|
44
|
+
/** The source type label */
|
|
45
|
+
Label: string;
|
|
46
|
+
/** Font Awesome icon class */
|
|
47
|
+
Icon: string;
|
|
48
|
+
/** The source type key */
|
|
49
|
+
SourceType: string;
|
|
50
|
+
/** Results in this group */
|
|
51
|
+
Results: SearchResultItem[];
|
|
52
|
+
/** Total count for this source (may exceed Results.length if paginated) */
|
|
53
|
+
TotalCount: number;
|
|
54
|
+
}
|
|
55
|
+
/** Faceted filter configuration */
|
|
56
|
+
export interface SearchFilter {
|
|
57
|
+
/** Filter category name */
|
|
58
|
+
Category: string;
|
|
59
|
+
/** Filter options within this category */
|
|
60
|
+
Options: SearchFilterOption[];
|
|
61
|
+
/** Whether multiple options can be selected */
|
|
62
|
+
MultiSelect: boolean;
|
|
63
|
+
}
|
|
64
|
+
/** Single filter option within a category */
|
|
65
|
+
export interface SearchFilterOption {
|
|
66
|
+
/** Display label */
|
|
67
|
+
Label: string;
|
|
68
|
+
/** Value to filter by */
|
|
69
|
+
Value: string;
|
|
70
|
+
/** Count of results matching this option */
|
|
71
|
+
Count: number;
|
|
72
|
+
/** Whether this option is currently selected */
|
|
73
|
+
IsSelected: boolean;
|
|
74
|
+
/** Font Awesome icon class */
|
|
75
|
+
Icon?: string;
|
|
76
|
+
}
|
|
77
|
+
/** Search request parameters */
|
|
78
|
+
export interface SearchRequest {
|
|
79
|
+
/** The search query string */
|
|
80
|
+
Query: string;
|
|
81
|
+
/** Maximum number of results to return */
|
|
82
|
+
MaxResults: number;
|
|
83
|
+
/** Active filter selections */
|
|
84
|
+
ActiveFilters: Record<string, string[]>;
|
|
85
|
+
/** Which search sources to include */
|
|
86
|
+
IncludeSources: ('vector' | 'fulltext' | 'entity')[];
|
|
87
|
+
/**
|
|
88
|
+
* Minimum relevance score (0-1) to include in results.
|
|
89
|
+
* Results below this threshold are filtered out.
|
|
90
|
+
* Default: 0.35 (35%).
|
|
91
|
+
*/
|
|
92
|
+
MinScore?: number;
|
|
93
|
+
}
|
|
94
|
+
/** Search response from the service */
|
|
95
|
+
export interface SearchResponse {
|
|
96
|
+
/** Whether the search succeeded */
|
|
97
|
+
Success: boolean;
|
|
98
|
+
/** The search results */
|
|
99
|
+
Results: SearchResultItem[];
|
|
100
|
+
/** Grouped results by source type */
|
|
101
|
+
Groups: SearchResultGroup[];
|
|
102
|
+
/** Available filters based on results */
|
|
103
|
+
Filters: SearchFilter[];
|
|
104
|
+
/** Total result count across all sources */
|
|
105
|
+
TotalCount: number;
|
|
106
|
+
/** Time taken in milliseconds */
|
|
107
|
+
ElapsedMs: number;
|
|
108
|
+
/** Count of results from each source */
|
|
109
|
+
SourceCounts: {
|
|
110
|
+
Vector: number;
|
|
111
|
+
FullText: number;
|
|
112
|
+
Entity: number;
|
|
113
|
+
};
|
|
114
|
+
/** Error message if Success is false */
|
|
115
|
+
ErrorMessage?: string;
|
|
116
|
+
}
|
|
117
|
+
/** Event emitted when a search result is selected */
|
|
118
|
+
export interface SearchResultSelectedEvent {
|
|
119
|
+
/** The selected result item */
|
|
120
|
+
Result: SearchResultItem;
|
|
121
|
+
/** Whether to open in a new tab */
|
|
122
|
+
OpenInNewTab: boolean;
|
|
123
|
+
}
|
|
124
|
+
/** Event emitted when filters change */
|
|
125
|
+
export interface SearchFilterChangeEvent {
|
|
126
|
+
/** The filter category that changed */
|
|
127
|
+
Category: string;
|
|
128
|
+
/** The new selected values */
|
|
129
|
+
SelectedValues: string[];
|
|
130
|
+
}
|
|
131
|
+
/** Event emitted when search is executed */
|
|
132
|
+
export interface SearchExecutedEvent {
|
|
133
|
+
/** The search query */
|
|
134
|
+
Query: string;
|
|
135
|
+
/** Active filters */
|
|
136
|
+
Filters: Record<string, string[]>;
|
|
137
|
+
/** Number of results returned */
|
|
138
|
+
ResultCount: number;
|
|
139
|
+
/** Time taken in ms */
|
|
140
|
+
ElapsedMs: number;
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=search-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-types.d.ts","sourceRoot":"","sources":["../../src/lib/search-types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-types.js","sourceRoot":"","sources":["../../src/lib/search-types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG","sourcesContent":["/**\n * @fileoverview Shared types for the ng-search package.\n *\n * Defines the data contracts for search results, filters,\n * and events used across all search components.\n */\n\n/** Represents a single search result item */\nexport interface SearchResultItem {\n /** Unique identifier */\n ID: string;\n /** Display title */\n Title: string;\n /** Short text snippet showing match context */\n Snippet: string;\n /** The entity name this result belongs to */\n EntityName: string;\n /** The primary key of the source record */\n RecordID: string;\n /** Classification of the result source */\n SourceType: 'entity' | 'content-item' | 'file' | 'web-page';\n /** Relevance score between 0 and 1 */\n Score: number;\n /** Breakdown of how the score was computed */\n ScoreBreakdown: ScoreBreakdown;\n /** Human-readable tags */\n Tags: string[];\n /** Font Awesome icon class for the source type */\n SourceIcon: string;\n /** Entity-specific icon from EntityInfo.Icon (e.g., \"fa-solid fa-robot\") */\n EntityIcon?: string;\n /** Human-readable record name resolved from EntityRecordName */\n RecordName?: string;\n /** When this result was matched */\n MatchedAt: Date;\n}\n\n/** Breakdown of score contribution from each search source */\nexport interface ScoreBreakdown {\n Vector?: number;\n FullText?: number;\n Entity?: number;\n}\n\n/** Grouped search results by source type */\nexport interface SearchResultGroup {\n /** The source type label */\n Label: string;\n /** Font Awesome icon class */\n Icon: string;\n /** The source type key */\n SourceType: string;\n /** Results in this group */\n Results: SearchResultItem[];\n /** Total count for this source (may exceed Results.length if paginated) */\n TotalCount: number;\n}\n\n/** Faceted filter configuration */\nexport interface SearchFilter {\n /** Filter category name */\n Category: string;\n /** Filter options within this category */\n Options: SearchFilterOption[];\n /** Whether multiple options can be selected */\n MultiSelect: boolean;\n}\n\n/** Single filter option within a category */\nexport interface SearchFilterOption {\n /** Display label */\n Label: string;\n /** Value to filter by */\n Value: string;\n /** Count of results matching this option */\n Count: number;\n /** Whether this option is currently selected */\n IsSelected: boolean;\n /** Font Awesome icon class */\n Icon?: string;\n}\n\n/** Search request parameters */\nexport interface SearchRequest {\n /** The search query string */\n Query: string;\n /** Maximum number of results to return */\n MaxResults: number;\n /** Active filter selections */\n ActiveFilters: Record<string, string[]>;\n /** Which search sources to include */\n IncludeSources: ('vector' | 'fulltext' | 'entity')[];\n /**\n * Minimum relevance score (0-1) to include in results.\n * Results below this threshold are filtered out.\n * Default: 0.35 (35%).\n */\n MinScore?: number;\n}\n\n/** Search response from the service */\nexport interface SearchResponse {\n /** Whether the search succeeded */\n Success: boolean;\n /** The search results */\n Results: SearchResultItem[];\n /** Grouped results by source type */\n Groups: SearchResultGroup[];\n /** Available filters based on results */\n Filters: SearchFilter[];\n /** Total result count across all sources */\n TotalCount: number;\n /** Time taken in milliseconds */\n ElapsedMs: number;\n /** Count of results from each source */\n SourceCounts: { Vector: number; FullText: number; Entity: number };\n /** Error message if Success is false */\n ErrorMessage?: string;\n}\n\n/** Event emitted when a search result is selected */\nexport interface SearchResultSelectedEvent {\n /** The selected result item */\n Result: SearchResultItem;\n /** Whether to open in a new tab */\n OpenInNewTab: boolean;\n}\n\n/** Event emitted when filters change */\nexport interface SearchFilterChangeEvent {\n /** The filter category that changed */\n Category: string;\n /** The new selected values */\n SelectedValues: string[];\n}\n\n/** Event emitted when search is executed */\nexport interface SearchExecutedEvent {\n /** The search query */\n Query: string;\n /** Active filters */\n Filters: Record<string, string[]>;\n /** Number of results returned */\n ResultCount: number;\n /** Time taken in ms */\n ElapsedMs: number;\n}\n"]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { BehaviorSubject, Subject } from 'rxjs';
|
|
2
|
+
import { SearchRequest, SearchResponse, SearchResultItem, SearchResultGroup, SearchFilter } from './search-types';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
/** Recent search entry for history */
|
|
5
|
+
export interface RecentSearch {
|
|
6
|
+
Query: string;
|
|
7
|
+
Timestamp: Date;
|
|
8
|
+
ResultCount: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class SearchService {
|
|
11
|
+
/** Current search response */
|
|
12
|
+
SearchResults$: BehaviorSubject<SearchResponse | null>;
|
|
13
|
+
/** Whether a search is in progress */
|
|
14
|
+
IsSearching$: BehaviorSubject<boolean>;
|
|
15
|
+
/** Recent search history (kept in memory, max 20 entries) */
|
|
16
|
+
RecentSearches$: BehaviorSubject<RecentSearch[]>;
|
|
17
|
+
/** Error stream */
|
|
18
|
+
Errors$: Subject<string>;
|
|
19
|
+
private readonly maxRecentSearches;
|
|
20
|
+
/**
|
|
21
|
+
* Execute a search request via the SearchKnowledge GraphQL mutation.
|
|
22
|
+
*/
|
|
23
|
+
ExecuteSearch(request: SearchRequest): Promise<SearchResponse>;
|
|
24
|
+
/** Clear the current search results */
|
|
25
|
+
ClearResults(): void;
|
|
26
|
+
/** Clear recent search history */
|
|
27
|
+
ClearRecentSearches(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Group flat results by source type for display.
|
|
30
|
+
*/
|
|
31
|
+
GroupResults(results: SearchResultItem[]): SearchResultGroup[];
|
|
32
|
+
/**
|
|
33
|
+
* Build filter facets from a set of results.
|
|
34
|
+
*/
|
|
35
|
+
BuildFilters(results: SearchResultItem[]): SearchFilter[];
|
|
36
|
+
/** Get the icon for a given source type */
|
|
37
|
+
GetSourceIcon(sourceType: string): string;
|
|
38
|
+
private buildSourceTypeFilter;
|
|
39
|
+
private buildEntityNameFilter;
|
|
40
|
+
private buildTagFilter;
|
|
41
|
+
private addToRecentSearches;
|
|
42
|
+
private createEmptyResponse;
|
|
43
|
+
/**
|
|
44
|
+
* Execute search via the SearchKnowledge GraphQL mutation.
|
|
45
|
+
*/
|
|
46
|
+
private executeGraphQLSearch;
|
|
47
|
+
/** Build the GraphQL filters input from active filter selections */
|
|
48
|
+
private buildFiltersInput;
|
|
49
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SearchService, never>;
|
|
50
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<SearchService>;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=search.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.service.d.ts","sourceRoot":"","sources":["../../src/lib/search.service.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAEhD,OAAO,EACH,aAAa,EACb,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,YAAY,EAEf,MAAM,gBAAgB,CAAC;;AAqBxB,sCAAsC;AACtC,MAAM,WAAW,YAAY;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACvB;AAED,qBACa,aAAa;IACtB,8BAA8B;IACvB,cAAc,yCAAoD;IAEzE,sCAAsC;IAC/B,YAAY,2BAAuC;IAE1D,6DAA6D;IACtD,eAAe,kCAA2C;IAEjE,mBAAmB;IACZ,OAAO,kBAAyB;IAEvC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAM;IAExC;;OAEG;IACU,aAAa,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAuB3E,uCAAuC;IAChC,YAAY,IAAI,IAAI;IAI3B,kCAAkC;IAC3B,mBAAmB,IAAI,IAAI;IAIlC;;OAEG;IACI,YAAY,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,iBAAiB,EAAE;IAsBrE;;OAEG;IACI,YAAY,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,YAAY,EAAE;IAQhE,2CAA2C;IACpC,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAIhD,OAAO,CAAC,qBAAqB;IAe7B,OAAO,CAAC,qBAAqB;IAiB7B,OAAO,CAAC,cAAc;IAoBtB,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,mBAAmB;IAa3B;;OAEG;YACW,oBAAoB;IAsGlC,oEAAoE;IACpE,OAAO,CAAC,iBAAiB;yCAjRhB,aAAa;6CAAb,aAAa;CAySzB"}
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Search service that connects to the UnifiedSearchService via GraphQL.
|
|
3
|
+
*
|
|
4
|
+
* Provides a reactive interface for executing searches, managing search history,
|
|
5
|
+
* and transforming raw search responses into display-ready grouped results.
|
|
6
|
+
*/
|
|
7
|
+
import { Injectable } from '@angular/core';
|
|
8
|
+
import { BehaviorSubject, Subject } from 'rxjs';
|
|
9
|
+
import { Metadata } from '@memberjunction/core';
|
|
10
|
+
import * as i0 from "@angular/core";
|
|
11
|
+
/** Default minimum relevance score threshold (0-1). Results below this are filtered out. */
|
|
12
|
+
const DEFAULT_MIN_SCORE = 0.35;
|
|
13
|
+
/** Default icon mapping for source types */
|
|
14
|
+
const SOURCE_TYPE_ICONS = {
|
|
15
|
+
'entity': 'fa-solid fa-database',
|
|
16
|
+
'content-item': 'fa-solid fa-file-lines',
|
|
17
|
+
'file': 'fa-solid fa-file',
|
|
18
|
+
'web-page': 'fa-solid fa-globe',
|
|
19
|
+
};
|
|
20
|
+
/** Default labels for source types */
|
|
21
|
+
const SOURCE_TYPE_LABELS = {
|
|
22
|
+
'entity': 'Entity Records',
|
|
23
|
+
'content-item': 'Content Items',
|
|
24
|
+
'file': 'Documents',
|
|
25
|
+
'web-page': 'Web Pages',
|
|
26
|
+
};
|
|
27
|
+
export class SearchService {
|
|
28
|
+
/** Current search response */
|
|
29
|
+
SearchResults$ = new BehaviorSubject(null);
|
|
30
|
+
/** Whether a search is in progress */
|
|
31
|
+
IsSearching$ = new BehaviorSubject(false);
|
|
32
|
+
/** Recent search history (kept in memory, max 20 entries) */
|
|
33
|
+
RecentSearches$ = new BehaviorSubject([]);
|
|
34
|
+
/** Error stream */
|
|
35
|
+
Errors$ = new Subject();
|
|
36
|
+
maxRecentSearches = 20;
|
|
37
|
+
/**
|
|
38
|
+
* Execute a search request via the SearchKnowledge GraphQL mutation.
|
|
39
|
+
*/
|
|
40
|
+
async ExecuteSearch(request) {
|
|
41
|
+
this.IsSearching$.next(true);
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
try {
|
|
44
|
+
const response = await this.executeGraphQLSearch(request);
|
|
45
|
+
response.ElapsedMs = Date.now() - startTime;
|
|
46
|
+
this.SearchResults$.next(response);
|
|
47
|
+
this.addToRecentSearches(request.Query, response.TotalCount);
|
|
48
|
+
return response;
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
const errorMessage = err instanceof Error ? err.message : 'Search failed';
|
|
52
|
+
this.Errors$.next(errorMessage);
|
|
53
|
+
const errorResponse = this.createEmptyResponse(errorMessage);
|
|
54
|
+
this.SearchResults$.next(errorResponse);
|
|
55
|
+
return errorResponse;
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
this.IsSearching$.next(false);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** Clear the current search results */
|
|
62
|
+
ClearResults() {
|
|
63
|
+
this.SearchResults$.next(null);
|
|
64
|
+
}
|
|
65
|
+
/** Clear recent search history */
|
|
66
|
+
ClearRecentSearches() {
|
|
67
|
+
this.RecentSearches$.next([]);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Group flat results by source type for display.
|
|
71
|
+
*/
|
|
72
|
+
GroupResults(results) {
|
|
73
|
+
const groupMap = new Map();
|
|
74
|
+
for (const result of results) {
|
|
75
|
+
const key = result.SourceType;
|
|
76
|
+
const existing = groupMap.get(key);
|
|
77
|
+
if (existing) {
|
|
78
|
+
existing.push(result);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
groupMap.set(key, [result]);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return Array.from(groupMap.entries()).map(([sourceType, items]) => ({
|
|
85
|
+
Label: SOURCE_TYPE_LABELS[sourceType] ?? sourceType,
|
|
86
|
+
Icon: SOURCE_TYPE_ICONS[sourceType] ?? 'fa-solid fa-circle',
|
|
87
|
+
SourceType: sourceType,
|
|
88
|
+
Results: items,
|
|
89
|
+
TotalCount: items.length
|
|
90
|
+
}));
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Build filter facets from a set of results.
|
|
94
|
+
*/
|
|
95
|
+
BuildFilters(results) {
|
|
96
|
+
return [
|
|
97
|
+
this.buildSourceTypeFilter(results),
|
|
98
|
+
this.buildEntityNameFilter(results),
|
|
99
|
+
this.buildTagFilter(results)
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
/** Get the icon for a given source type */
|
|
103
|
+
GetSourceIcon(sourceType) {
|
|
104
|
+
return SOURCE_TYPE_ICONS[sourceType] ?? 'fa-solid fa-circle';
|
|
105
|
+
}
|
|
106
|
+
buildSourceTypeFilter(results) {
|
|
107
|
+
const counts = new Map();
|
|
108
|
+
for (const r of results) {
|
|
109
|
+
counts.set(r.SourceType, (counts.get(r.SourceType) ?? 0) + 1);
|
|
110
|
+
}
|
|
111
|
+
const options = Array.from(counts.entries()).map(([type, count]) => ({
|
|
112
|
+
Label: SOURCE_TYPE_LABELS[type] ?? type,
|
|
113
|
+
Value: type,
|
|
114
|
+
Count: count,
|
|
115
|
+
IsSelected: false,
|
|
116
|
+
Icon: SOURCE_TYPE_ICONS[type]
|
|
117
|
+
}));
|
|
118
|
+
return { Category: 'Source Type', Options: options, MultiSelect: true };
|
|
119
|
+
}
|
|
120
|
+
buildEntityNameFilter(results) {
|
|
121
|
+
const counts = new Map();
|
|
122
|
+
for (const r of results) {
|
|
123
|
+
counts.set(r.EntityName, (counts.get(r.EntityName) ?? 0) + 1);
|
|
124
|
+
}
|
|
125
|
+
const options = Array.from(counts.entries())
|
|
126
|
+
.sort((a, b) => b[1] - a[1])
|
|
127
|
+
.map(([name, count]) => ({
|
|
128
|
+
Label: name,
|
|
129
|
+
Value: name,
|
|
130
|
+
Count: count,
|
|
131
|
+
IsSelected: false,
|
|
132
|
+
Icon: 'fa-solid fa-table'
|
|
133
|
+
}));
|
|
134
|
+
return { Category: 'Entity', Options: options, MultiSelect: true };
|
|
135
|
+
}
|
|
136
|
+
buildTagFilter(results) {
|
|
137
|
+
const counts = new Map();
|
|
138
|
+
for (const r of results) {
|
|
139
|
+
for (const tag of r.Tags) {
|
|
140
|
+
counts.set(tag, (counts.get(tag) ?? 0) + 1);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
const options = Array.from(counts.entries())
|
|
144
|
+
.sort((a, b) => b[1] - a[1])
|
|
145
|
+
.slice(0, 15)
|
|
146
|
+
.map(([tag, count]) => ({
|
|
147
|
+
Label: tag,
|
|
148
|
+
Value: tag,
|
|
149
|
+
Count: count,
|
|
150
|
+
IsSelected: false,
|
|
151
|
+
Icon: 'fa-solid fa-tag'
|
|
152
|
+
}));
|
|
153
|
+
return { Category: 'Tags', Options: options, MultiSelect: true };
|
|
154
|
+
}
|
|
155
|
+
addToRecentSearches(query, resultCount) {
|
|
156
|
+
const current = this.RecentSearches$.value;
|
|
157
|
+
const filtered = current.filter(s => s.Query !== query);
|
|
158
|
+
const updated = [
|
|
159
|
+
{ Query: query, Timestamp: new Date(), ResultCount: resultCount },
|
|
160
|
+
...filtered
|
|
161
|
+
].slice(0, this.maxRecentSearches);
|
|
162
|
+
this.RecentSearches$.next(updated);
|
|
163
|
+
}
|
|
164
|
+
createEmptyResponse(errorMessage) {
|
|
165
|
+
return {
|
|
166
|
+
Success: !errorMessage,
|
|
167
|
+
Results: [],
|
|
168
|
+
Groups: [],
|
|
169
|
+
Filters: [],
|
|
170
|
+
TotalCount: 0,
|
|
171
|
+
ElapsedMs: 0,
|
|
172
|
+
SourceCounts: { Vector: 0, FullText: 0, Entity: 0 },
|
|
173
|
+
ErrorMessage: errorMessage
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Execute search via the SearchKnowledge GraphQL mutation.
|
|
178
|
+
*/
|
|
179
|
+
async executeGraphQLSearch(request) {
|
|
180
|
+
if (!request.Query.trim()) {
|
|
181
|
+
return this.createEmptyResponse();
|
|
182
|
+
}
|
|
183
|
+
const provider = Metadata.Provider;
|
|
184
|
+
if (!provider?.ExecuteGQL) {
|
|
185
|
+
return this.createEmptyResponse('GraphQL provider not available');
|
|
186
|
+
}
|
|
187
|
+
const mutation = `
|
|
188
|
+
mutation SearchKnowledge($query: String!, $maxResults: Float, $filters: SearchFiltersInput, $minScore: Float) {
|
|
189
|
+
SearchKnowledge(query: $query, maxResults: $maxResults, filters: $filters, minScore: $minScore) {
|
|
190
|
+
Success
|
|
191
|
+
TotalCount
|
|
192
|
+
ElapsedMs
|
|
193
|
+
ErrorMessage
|
|
194
|
+
SourceCounts {
|
|
195
|
+
Vector
|
|
196
|
+
FullText
|
|
197
|
+
Entity
|
|
198
|
+
}
|
|
199
|
+
Results {
|
|
200
|
+
ID
|
|
201
|
+
EntityName
|
|
202
|
+
RecordID
|
|
203
|
+
SourceType
|
|
204
|
+
Title
|
|
205
|
+
Snippet
|
|
206
|
+
Score
|
|
207
|
+
ScoreBreakdown {
|
|
208
|
+
Vector
|
|
209
|
+
FullText
|
|
210
|
+
Entity
|
|
211
|
+
}
|
|
212
|
+
Tags
|
|
213
|
+
EntityIcon
|
|
214
|
+
RecordName
|
|
215
|
+
MatchedAt
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
`;
|
|
220
|
+
const filtersInput = this.buildFiltersInput(request);
|
|
221
|
+
const minScore = request.MinScore ?? DEFAULT_MIN_SCORE;
|
|
222
|
+
const variables = {
|
|
223
|
+
query: request.Query,
|
|
224
|
+
maxResults: request.MaxResults || 20,
|
|
225
|
+
filters: filtersInput,
|
|
226
|
+
minScore: minScore > 0 ? minScore : undefined,
|
|
227
|
+
};
|
|
228
|
+
const gqlResult = await provider.ExecuteGQL(mutation, variables);
|
|
229
|
+
const data = gqlResult['SearchKnowledge'];
|
|
230
|
+
if (!data?.Success) {
|
|
231
|
+
return this.createEmptyResponse(data?.ErrorMessage ?? 'Search failed');
|
|
232
|
+
}
|
|
233
|
+
const results = (data.Results ?? []).map(r => ({
|
|
234
|
+
ID: r.ID,
|
|
235
|
+
Title: r.RecordName || r.Title,
|
|
236
|
+
Snippet: r.Snippet,
|
|
237
|
+
EntityName: r.EntityName,
|
|
238
|
+
RecordID: r.RecordID,
|
|
239
|
+
SourceType: r.SourceType || 'entity',
|
|
240
|
+
Score: r.Score,
|
|
241
|
+
ScoreBreakdown: r.ScoreBreakdown ?? {},
|
|
242
|
+
Tags: r.Tags ?? [],
|
|
243
|
+
SourceIcon: r.EntityIcon || SOURCE_TYPE_ICONS[r.SourceType] || 'fa-solid fa-database',
|
|
244
|
+
EntityIcon: r.EntityIcon,
|
|
245
|
+
RecordName: r.RecordName,
|
|
246
|
+
MatchedAt: new Date(r.MatchedAt),
|
|
247
|
+
}));
|
|
248
|
+
const groups = this.GroupResults(results);
|
|
249
|
+
const filters = this.BuildFilters(results);
|
|
250
|
+
return {
|
|
251
|
+
Success: true,
|
|
252
|
+
Results: results,
|
|
253
|
+
Groups: groups,
|
|
254
|
+
Filters: filters,
|
|
255
|
+
TotalCount: data.TotalCount,
|
|
256
|
+
ElapsedMs: data.ElapsedMs,
|
|
257
|
+
SourceCounts: data.SourceCounts,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
/** Build the GraphQL filters input from active filter selections */
|
|
261
|
+
buildFiltersInput(request) {
|
|
262
|
+
if (!request.ActiveFilters || Object.keys(request.ActiveFilters).length === 0) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
const result = {};
|
|
266
|
+
const entityFilters = request.ActiveFilters['Entity'];
|
|
267
|
+
if (entityFilters?.length) {
|
|
268
|
+
result.EntityNames = entityFilters;
|
|
269
|
+
}
|
|
270
|
+
const sourceFilters = request.ActiveFilters['Source Type'];
|
|
271
|
+
if (sourceFilters?.length) {
|
|
272
|
+
result.SourceTypes = sourceFilters;
|
|
273
|
+
}
|
|
274
|
+
const tagFilters = request.ActiveFilters['Tags'];
|
|
275
|
+
if (tagFilters?.length) {
|
|
276
|
+
result.Tags = tagFilters;
|
|
277
|
+
}
|
|
278
|
+
return Object.keys(result).length > 0 ? result : null;
|
|
279
|
+
}
|
|
280
|
+
static ɵfac = function SearchService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SearchService)(); };
|
|
281
|
+
static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: SearchService, factory: SearchService.ɵfac, providedIn: 'root' });
|
|
282
|
+
}
|
|
283
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SearchService, [{
|
|
284
|
+
type: Injectable,
|
|
285
|
+
args: [{ providedIn: 'root' }]
|
|
286
|
+
}], null, null); })();
|
|
287
|
+
//# sourceMappingURL=search.service.js.map
|
|
@@ -0,0 +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 }\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;\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 }));\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"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export * from './lib/search-types';
|
|
2
|
+
export * from './lib/search.service';
|
|
3
|
+
export * from './lib/search-overlay.component';
|
|
4
|
+
export * from './lib/search-results.component';
|
|
5
|
+
export * from './lib/search-filter.component';
|
|
6
|
+
export * from './lib/module';
|
|
7
|
+
//# sourceMappingURL=public-api.d.ts.map
|
|
@@ -0,0 +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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Public API Surface of @memberjunction/ng-search
|
|
3
|
+
*/
|
|
4
|
+
export * from './lib/search-types';
|
|
5
|
+
export * from './lib/search.service';
|
|
6
|
+
export * from './lib/search-overlay.component';
|
|
7
|
+
export * from './lib/search-results.component';
|
|
8
|
+
export * from './lib/search-filter.component';
|
|
9
|
+
export * from './lib/module';
|
|
10
|
+
//# sourceMappingURL=public-api.js.map
|
|
@@ -0,0 +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"]}
|
package/package.json
CHANGED
|
@@ -1,10 +1,41 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memberjunction/ng-search",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
9
|
-
]
|
|
3
|
+
"version": "5.23.0",
|
|
4
|
+
"description": "MemberJunction: Reusable search overlay and results components - command palette / Spotlight style search",
|
|
5
|
+
"main": "./dist/public-api.js",
|
|
6
|
+
"typings": "./dist/public-api.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"/dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"build": "ngc",
|
|
13
|
+
"test:watch": "vitest"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [],
|
|
16
|
+
"author": "MemberJunction.com",
|
|
17
|
+
"license": "ISC",
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@angular/compiler": "21.1.3",
|
|
20
|
+
"@angular/compiler-cli": "21.1.3",
|
|
21
|
+
"vitest": "^4.0.18"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@angular/common": "21.1.3",
|
|
25
|
+
"@angular/core": "21.1.3",
|
|
26
|
+
"@angular/router": "21.1.3",
|
|
27
|
+
"@angular/forms": "21.1.3"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@memberjunction/core": "5.23.0",
|
|
31
|
+
"@memberjunction/global": "5.23.0",
|
|
32
|
+
"@memberjunction/ng-shared-generic": "5.23.0",
|
|
33
|
+
"rxjs": "^7.8.2",
|
|
34
|
+
"tslib": "^2.8.1"
|
|
35
|
+
},
|
|
36
|
+
"sideEffects": false,
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/MemberJunction/MJ"
|
|
40
|
+
}
|
|
10
41
|
}
|