@memberjunction/ng-search 5.32.0 → 5.34.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 (34) hide show
  1. package/dist/__tests__/search.service.test.js +101 -0
  2. package/dist/__tests__/search.service.test.js.map +1 -1
  3. package/dist/lib/module.d.ts +6 -4
  4. package/dist/lib/module.d.ts.map +1 -1
  5. package/dist/lib/module.js +14 -4
  6. package/dist/lib/module.js.map +1 -1
  7. package/dist/lib/search-composite.component.d.ts +29 -2
  8. package/dist/lib/search-composite.component.d.ts.map +1 -1
  9. package/dist/lib/search-composite.component.js +72 -7
  10. package/dist/lib/search-composite.component.js.map +1 -1
  11. package/dist/lib/search-overlay.component.d.ts +42 -1
  12. package/dist/lib/search-overlay.component.d.ts.map +1 -1
  13. package/dist/lib/search-overlay.component.js +301 -128
  14. package/dist/lib/search-overlay.component.js.map +1 -1
  15. package/dist/lib/search-scope-child-grid.component.d.ts +166 -0
  16. package/dist/lib/search-scope-child-grid.component.d.ts.map +1 -0
  17. package/dist/lib/search-scope-child-grid.component.js +575 -0
  18. package/dist/lib/search-scope-child-grid.component.js.map +1 -0
  19. package/dist/lib/search-scope-selector.component.d.ts +71 -0
  20. package/dist/lib/search-scope-selector.component.d.ts.map +1 -0
  21. package/dist/lib/search-scope-selector.component.js +354 -0
  22. package/dist/lib/search-scope-selector.component.js.map +1 -0
  23. package/dist/lib/search-types.d.ts +18 -0
  24. package/dist/lib/search-types.d.ts.map +1 -1
  25. package/dist/lib/search-types.js.map +1 -1
  26. package/dist/lib/search.service.d.ts +36 -2
  27. package/dist/lib/search.service.d.ts.map +1 -1
  28. package/dist/lib/search.service.js +81 -2
  29. package/dist/lib/search.service.js.map +1 -1
  30. package/dist/public-api.d.ts +2 -0
  31. package/dist/public-api.d.ts.map +1 -1
  32. package/dist/public-api.js +2 -0
  33. package/dist/public-api.js.map +1 -1
  34. package/package.json +7 -7
@@ -1,4 +1,5 @@
1
1
  import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { Subject } from 'rxjs';
2
3
  import { Metadata } from '@memberjunction/core';
3
4
  import { GraphQLDataProvider, GraphQLSearchClient } from '@memberjunction/graphql-dataprovider';
4
5
  import { SearchService } from '../lib/search.service';
@@ -99,6 +100,89 @@ describe('SearchService', () => {
99
100
  expect(service.RecentSearches$.value.length).toBeLessThanOrEqual(20);
100
101
  });
101
102
  });
103
+ describe('StreamSearch', () => {
104
+ it('forwards Phase, ProviderName, and ElapsedMs unchanged and maps client results through mapClientResultItem', () => {
105
+ const stream$ = new Subject();
106
+ vi.spyOn(GraphQLSearchClient.prototype, 'StreamSearch').mockReturnValue(stream$);
107
+ const events = [];
108
+ const sub = service.StreamSearch({
109
+ Query: 'streamed query',
110
+ MaxResults: 10,
111
+ ActiveFilters: {},
112
+ IncludeSources: ['vector', 'fulltext']
113
+ }).subscribe({
114
+ next: ev => events.push(ev),
115
+ });
116
+ stream$.next({ StreamID: 'sid-1', Phase: 'provider', ProviderName: 'Vector', Results: [makeClientResultItem('a', 'fast-row')], ElapsedMs: 12 });
117
+ stream$.next({ StreamID: 'sid-1', Phase: 'fused', Results: [makeClientResultItem('a', 'fast-row'), makeClientResultItem('b', 'slow-row')], ElapsedMs: 50 });
118
+ stream$.next({ StreamID: 'sid-1', Phase: 'final', Results: [makeClientResultItem('a', 'fast-row'), makeClientResultItem('b', 'slow-row')], ElapsedMs: 75 });
119
+ expect(events).toHaveLength(3);
120
+ expect(events[0].Phase).toBe('provider');
121
+ expect(events[0].ProviderName).toBe('Vector');
122
+ expect(events[0].ElapsedMs).toBe(12);
123
+ // mapClientResultItem prefers RecordName over Title and unwraps RawMetadata; assert one mapped field
124
+ expect(events[0].Results?.[0].Title).toBe('fast-row');
125
+ expect(events[0].Results?.[0].MatchedAt).toBeInstanceOf(Date);
126
+ expect(events[1].Phase).toBe('fused');
127
+ expect(events[1].Results).toHaveLength(2);
128
+ expect(events[2].Phase).toBe('final');
129
+ expect(events[2].ElapsedMs).toBe(75);
130
+ sub.unsubscribe();
131
+ });
132
+ it('omits Results from emitted event when the wire frame has no Results', () => {
133
+ const stream$ = new Subject();
134
+ vi.spyOn(GraphQLSearchClient.prototype, 'StreamSearch').mockReturnValue(stream$);
135
+ const events = [];
136
+ const sub = service.StreamSearch({
137
+ Query: 'no-results phase',
138
+ MaxResults: 5,
139
+ ActiveFilters: {},
140
+ IncludeSources: ['vector']
141
+ }).subscribe({
142
+ next: ev => events.push(ev),
143
+ });
144
+ // 'reranked' phase server-side may carry no Results (it just signals the rerank step ran)
145
+ stream$.next({ StreamID: 'sid-2', Phase: 'reranked', ElapsedMs: 30 });
146
+ expect(events).toHaveLength(1);
147
+ expect(events[0].Phase).toBe('reranked');
148
+ expect(events[0].Results).toBeUndefined();
149
+ sub.unsubscribe();
150
+ });
151
+ it('propagates errors from the underlying client observable', () => {
152
+ const stream$ = new Subject();
153
+ vi.spyOn(GraphQLSearchClient.prototype, 'StreamSearch').mockReturnValue(stream$);
154
+ let captured = null;
155
+ const sub = service.StreamSearch({
156
+ Query: 'error path',
157
+ MaxResults: 5,
158
+ ActiveFilters: {},
159
+ IncludeSources: ['vector']
160
+ }).subscribe({
161
+ next: () => { },
162
+ error: err => { captured = err; },
163
+ });
164
+ stream$.error(new Error('upstream blew up'));
165
+ expect(captured).not.toBeNull();
166
+ expect(captured.message).toBe('upstream blew up');
167
+ sub.unsubscribe();
168
+ });
169
+ it('errors when no GraphQL provider is available (e.g., Metadata.Provider not yet bootstrapped)', () => {
170
+ Metadata['Provider'] = {}; // not a GraphQLDataProvider
171
+ let captured = null;
172
+ const sub = service.StreamSearch({
173
+ Query: 'no provider',
174
+ MaxResults: 5,
175
+ ActiveFilters: {},
176
+ IncludeSources: ['vector']
177
+ }).subscribe({
178
+ next: () => { },
179
+ error: err => { captured = err; },
180
+ });
181
+ expect(captured).not.toBeNull();
182
+ expect(captured.message).toBe('GraphQL provider not available');
183
+ sub.unsubscribe();
184
+ });
185
+ });
102
186
  describe('ClearResults', () => {
103
187
  it('should set SearchResults$ to null', async () => {
104
188
  await service.ExecuteSearch({
@@ -334,4 +418,21 @@ function createMockResult(id, sourceType, entityName, tags = []) {
334
418
  MatchedAt: new Date()
335
419
  };
336
420
  }
421
+ function makeClientResultItem(id, title) {
422
+ return {
423
+ ID: id,
424
+ EntityName: 'Contacts',
425
+ RecordID: `rec-${id}`,
426
+ SourceType: 'entity',
427
+ Title: title,
428
+ Snippet: `snippet for ${id}`,
429
+ Score: 0.91,
430
+ ScoreBreakdown: { Vector: 0.9, FullText: 0.92 },
431
+ Tags: ['streaming'],
432
+ EntityIcon: 'fa-solid fa-database',
433
+ RecordName: title,
434
+ MatchedAt: new Date().toISOString(),
435
+ ResultType: 'entity-record',
436
+ };
437
+ }
337
438
  //# sourceMappingURL=search.service.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"search.service.test.js","sourceRoot":"","sources":["../../src/__tests__/search.service.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAChG,OAAO,EAAE,aAAa,EAAgB,MAAM,uBAAuB,CAAC;AASpE;;;GAGG;AACH,SAAS,mBAAmB;IACxB,MAAM,iBAAiB,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC;QAChD,OAAO,EAAE,IAAI;QACb,OAAO,EAAE,EAAE;QACX,UAAU,EAAE,CAAC;QACb,SAAS,EAAE,CAAC;QACZ,YAAY,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;KAClE,CAAC,CAAC;IAEH,6DAA6D;IAC7D,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACjE,QAA+C,CAAC,UAAU,CAAC,GAAG,YAAY,CAAC;IAE5E,gGAAgG;IAChG,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;IAC/F,EAAE,CAAC,KAAK,CAAC,mBAAmB,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC,kBAAkB,CAAC,iBAAiB,CAAC,CAAC;IAE/F,OAAO,iBAAiB,CAAC;AAC7B,CAAC;AAED,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;IAC3B,IAAI,OAAsB,CAAC;IAE3B,UAAU,CAAC,GAAG,EAAE;QACZ,OAAO,GAAG,IAAI,aAAa,EAAE,CAAC;QAC9B,mBAAmB,EAAE,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;YAC1D,MAAM,MAAM,GAAc,EAAE,CAAC;YAC7B,OAAO,CAAC,YAAY,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;YAExD,MAAM,OAAO,CAAC,aAAa,CAAC;gBACxB,KAAK,EAAE,YAAY;gBACnB,UAAU,EAAE,EAAE;gBACd,aAAa,EAAE,EAAE;gBACjB,cAAc,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC;aACnD,CAAC,CAAC;YAEH,mCAAmC;YACnC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC/B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,6CAA6C,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,aAAa,CAAC;gBACzC,KAAK,EAAE,KAAK;gBACZ,UAAU,EAAE,EAAE;gBACd,aAAa,EAAE,EAAE;gBACjB,cAAc,EAAE,CAAC,QAAQ,CAAC;aAC7B,CAAC,CAAC;YAEH,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACzC,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,yCAAyC,EAAE,KAAK,IAAI,EAAE;YACrD,MAAM,OAAO,CAAC,aAAa,CAAC;gBACxB,KAAK,EAAE,MAAM;gBACb,UAAU,EAAE,EAAE;gBACd,aAAa,EAAE,EAAE;gBACjB,cAAc,EAAE,CAAC,QAAQ,CAAC;aAC7B,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC;YAC5C,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;YAC3C,MAAM,OAAO,CAAC,aAAa,CAAC;gBACxB,KAAK,EAAE,YAAY;gBACnB,UAAU,EAAE,EAAE;gBACd,aAAa,EAAE,EAAE;gBACjB,cAAc,EAAE,CAAC,QAAQ,CAAC;aAC7B,CAAC,CAAC;YAEH,MAAM,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC;YAC7C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oCAAoC,EAAE,KAAK,IAAI,EAAE;YAChD,MAAM,OAAO,GAAkB;gBAC3B,KAAK,EAAE,MAAM;gBACb,UAAU,EAAE,EAAE;gBACd,aAAa,EAAE,EAAE;gBACjB,cAAc,EAAE,CAAC,QAAQ,CAAC;aAC7B,CAAC;YAEF,MAAM,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YACrC,MAAM,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;YAErC,MAAM,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC;YAC7C,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;YACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC1B,MAAM,OAAO,CAAC,aAAa,CAAC;oBACxB,KAAK,EAAE,SAAS,CAAC,EAAE;oBACnB,UAAU,EAAE,EAAE;oBACd,aAAa,EAAE,EAAE;oBACjB,cAAc,EAAE,CAAC,QAAQ,CAAC;iBAC7B,CAAC,CAAC;YACP,CAAC;YAED,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;QACzE,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC1B,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;YAC/C,MAAM,OAAO,CAAC,aAAa,CAAC;gBACxB,KAAK,EAAE,MAAM;gBACb,UAAU,EAAE,EAAE;gBACd,aAAa,EAAE,EAAE;gBACjB,cAAc,EAAE,CAAC,QAAQ,CAAC;aAC7B,CAAC,CAAC;YAEH,OAAO,CAAC,YAAY,EAAE,CAAC;YACvB,MAAM,CAAC,OAAO,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;QACpD,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE;QACjC,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;YAC9C,MAAM,OAAO,CAAC,aAAa,CAAC;gBACxB,KAAK,EAAE,MAAM;gBACb,UAAU,EAAE,EAAE;gBACd,aAAa,EAAE,EAAE;gBACjB,cAAc,EAAE,CAAC,QAAQ,CAAC;aAC7B,CAAC,CAAC;YAEH,OAAO,CAAC,mBAAmB,EAAE,CAAC;YAC9B,MAAM,CAAC,OAAO,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC1D,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC1B,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;YAC3C,MAAM,OAAO,GAAuB;gBAChC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC;gBAC3C,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC;gBAC3C,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC;gBAC1C,gBAAgB,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,CAAC;aAC7C,CAAC;YAEF,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAE7C,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC/B,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC;YAChE,MAAM,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC7C,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;YACjD,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;YACxC,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC1B,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YACzD,MAAM,OAAO,GAAuB;gBAChC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,UAAU,CAAC,CAAC;gBACzD,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC,UAAU,CAAC,CAAC;aAC3D,CAAC;YAEF,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAE9C,MAAM,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;YAChE,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;YAC9C,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YAC7D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAChC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CACvD,CAAC;YAEF,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;YAC3D,MAAM,CAAC,SAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,mBAAmB,CAAC,EAAE,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,iEAAiE,EAAE,GAAG,EAAE;YACvE,MAAM,OAAO,GAAuB;gBAChC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBAC9D,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC;gBACrD,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,UAAU,CAAC,CAAC;aACtD,CAAC;YAEF,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;YAC3D,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;YAChC,MAAM,CAAC,SAAU,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAE1C,qDAAqD;YACrD,MAAM,SAAS,GAAG,SAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;YAClE,MAAM,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC;YAChC,MAAM,CAAC,SAAU,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,CAAC,SAAU,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;YAChD,MAAM,CAAC,SAAU,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAE1C,2CAA2C;YAC3C,MAAM,YAAY,GAAG,SAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC;YACxE,MAAM,CAAC,YAAa,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpC,MAAM,cAAc,GAAG,SAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,UAAU,CAAC,CAAC;YAC5E,MAAM,CAAC,cAAe,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YACzD,MAAM,OAAO,GAAuB;gBAChC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC;gBAC3C,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,WAAW,CAAC;aAC/C,CAAC;YAEF,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;YAC3D,MAAM,CAAC,SAAS,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,oCAAoC;QAC3E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;YAC5C,MAAM,OAAO,GAAuB;gBAChC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;gBACxD,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC;gBAChD,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,CAAC;aACnD,CAAC;YAEF,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;YAC3D,MAAM,CAAC,SAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACnD,MAAM,CAAC,SAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5C,MAAM,CAAC,SAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACjD,MAAM,CAAC,SAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE;QAC3B,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;YAClD,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;YACjE,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YAC3D,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;YACrD,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACpE,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,kEAAkE;IAClE,8EAA8E;IAC9E,kEAAkE;IAClE,QAAQ,CAAC,0DAA0D,EAAE,GAAG,EAAE;QACtE,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;YACtE,kCAAkC;YAClC,MAAM,WAAW,GAAuB;gBACpC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,KAAK,CAAC,CAAC;gBACpD,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC;gBACrD,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC;aACtD,CAAC;YAEF,0DAA0D;YAC1D,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;YAClD,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;YAEhE,iDAAiD;YACjD,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;YACtE,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;YACvE,MAAM,CAAC,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACvE,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;YACtD,MAAM,OAAO,GAAuB;gBAChC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;gBAC7D,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC;gBACrD,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;aAClE,CAAC;YAEF,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC;YAE3D,4DAA4D;YAC5D,MAAM,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAC3C,MAAM,SAAS,GAAG,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;YAClE,MAAM,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACrC,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;YAC5E,MAAM,WAAW,GAAuB;gBACpC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC;gBAC3C,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,WAAW,CAAC;gBAC5C,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,CAAC;aAC7C,CAAC;YAEF,wCAAwC;YACxC,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,CAAC,CAAC;YAE7E,2DAA2D;YAC3D,MAAM,eAAe,GAAG,OAAO,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC;YAC9D,MAAM,oBAAoB,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;YAChF,MAAM,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,gBAAgB;YAEvE,yDAAyD;YACzD,MAAM,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;YACtD,MAAM,gBAAgB,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;YACxE,MAAM,CAAC,gBAAgB,EAAE,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,mCAAmC;QAC1F,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,kEAAkE;IAClE,gEAAgE;IAChE,kEAAkE;IAClE,QAAQ,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACvD,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;YAC/D,MAAM,OAAO,GAAuB;gBAChC,EAAE,GAAG,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE;gBAC9D,EAAE,GAAG,gBAAgB,CAAC,GAAG,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE;gBACjE,EAAE,GAAG,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE;aAClE,CAAC;YAEF,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAE/B,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC;YAChE,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC5C,MAAM,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAExC,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,cAAc,CAAC,CAAC;YACvE,MAAM,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YAClD,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7C,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC1D,MAAM,OAAO,GAAuB;gBAChC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC;aAC1C,CAAC;YACF,8BAA8B;YAC7B,OAAO,CAAC,CAAC,CAAwC,CAAC,YAAY,CAAC,GAAG,aAAa,CAAC;YAEjF,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,8BAA8B;QAC/E,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;YACzD,MAAM,OAAO,GAAuB;gBAChC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,CAAC;aAC1C,CAAC;YACD,OAAO,CAAC,CAAC,CAAwC,CAAC,YAAY,CAAC,GAAG,gBAAgB,CAAC;YAEpF,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;QAEH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;YAC1D,MAAM,OAAO,GAAuB;gBAChC,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,UAAU,CAAC;gBAC3C,gBAAgB,CAAC,GAAG,EAAE,QAAQ,EAAE,WAAW,CAAC;aAC/C,CAAC;YACD,OAAO,CAAC,CAAC,CAAwC,CAAC,YAAY,CAAC,GAAG,eAAe,CAAC;YAEnF,MAAM,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC;YAC7C,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YAE/B,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC;YAChE,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAE5C,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,eAAe,CAAC,CAAC;YACvE,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YACjD,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAEH,SAAS,gBAAgB,CACrB,EAAU,EACV,UAA2D,EAC3D,UAAkB,EAClB,OAAiB,EAAE;IAEnB,OAAO;QACH,EAAE,EAAE,EAAE;QACN,KAAK,EAAE,UAAU,EAAE,EAAE;QACrB,OAAO,EAAE,sBAAsB,EAAE,EAAE;QACnC,UAAU,EAAE,UAAU;QACtB,QAAQ,EAAE,OAAO,EAAE,EAAE;QACrB,UAAU,EAAE,UAAU;QACtB,UAAU,EAAE,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,eAAe;QACpE,KAAK,EAAE,IAAI;QACX,cAAc,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE;QAC9C,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,sBAAsB;QAClC,SAAS,EAAE,IAAI,IAAI,EAAE;KACxB,CAAC;AACN,CAAC","sourcesContent":["import { describe, it, expect, beforeEach, vi } from 'vitest';\nimport { Metadata } from '@memberjunction/core';\nimport { GraphQLDataProvider, GraphQLSearchClient } from '@memberjunction/graphql-dataprovider';\nimport { SearchService, RecentSearch } from '../lib/search.service';\nimport {\n SearchRequest,\n SearchResponse,\n SearchResultItem,\n SearchResultGroup,\n SearchFilter\n} from '../lib/search-types';\n\n/**\n * Installs a fake Metadata.Provider that passes the `instanceof GraphQLDataProvider` check\n * and stubs GraphQLSearchClient.ExecuteSearch to return empty success.\n */\nfunction installMockProvider(): ReturnType<typeof vi.fn> {\n const mockExecuteSearch = vi.fn().mockResolvedValue({\n Success: true,\n Results: [],\n TotalCount: 0,\n ElapsedMs: 1,\n SourceCounts: { Vector: 0, FullText: 0, Entity: 0, Storage: 0 },\n });\n\n // Create a mock that passes `instanceof GraphQLDataProvider`\n const mockProvider = Object.create(GraphQLDataProvider.prototype);\n (Metadata as unknown as Record<string, unknown>)['Provider'] = mockProvider;\n\n // Stub GraphQLSearchClient.prototype so the service's `new GraphQLSearchClient(provider)` works\n vi.spyOn(GraphQLSearchClient.prototype, 'ExecuteSearch').mockImplementation(mockExecuteSearch);\n vi.spyOn(GraphQLSearchClient.prototype, 'PreviewSearch').mockImplementation(mockExecuteSearch);\n\n return mockExecuteSearch;\n}\n\ndescribe('SearchService', () => {\n let service: SearchService;\n\n beforeEach(() => {\n service = new SearchService();\n installMockProvider();\n });\n\n describe('ExecuteSearch', () => {\n it('should set IsSearching to true during search', async () => {\n const values: boolean[] = [];\n service.IsSearching$.subscribe(val => values.push(val));\n\n await service.ExecuteSearch({\n Query: 'test query',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector', 'fulltext', 'entity']\n });\n\n // Should have gone true then false\n expect(values).toContain(true);\n expect(values[values.length - 1]).toBe(false);\n });\n\n it('should return empty results for empty query', async () => {\n const response = await service.ExecuteSearch({\n Query: ' ',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n });\n\n expect(response.Success).toBe(true);\n expect(response.Results).toHaveLength(0);\n expect(response.TotalCount).toBe(0);\n });\n\n it('should update SearchResults$ observable', async () => {\n await service.ExecuteSearch({\n Query: 'test',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n });\n\n const result = service.SearchResults$.value;\n expect(result).not.toBeNull();\n expect(result?.Success).toBe(true);\n });\n\n it('should add to recent searches', async () => {\n await service.ExecuteSearch({\n Query: 'test query',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n });\n\n const recent = service.RecentSearches$.value;\n expect(recent.length).toBe(1);\n expect(recent[0].Query).toBe('test query');\n });\n\n it('should deduplicate recent searches', async () => {\n const request: SearchRequest = {\n Query: 'test',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n };\n\n await service.ExecuteSearch(request);\n await service.ExecuteSearch(request);\n\n const recent = service.RecentSearches$.value;\n expect(recent.length).toBe(1);\n });\n\n it('should limit recent searches to max 20', async () => {\n for (let i = 0; i < 25; i++) {\n await service.ExecuteSearch({\n Query: `query ${i}`,\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n });\n }\n\n expect(service.RecentSearches$.value.length).toBeLessThanOrEqual(20);\n });\n });\n\n describe('ClearResults', () => {\n it('should set SearchResults$ to null', async () => {\n await service.ExecuteSearch({\n Query: 'test',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n });\n\n service.ClearResults();\n expect(service.SearchResults$.value).toBeNull();\n });\n });\n\n describe('ClearRecentSearches', () => {\n it('should clear all recent searches', async () => {\n await service.ExecuteSearch({\n Query: 'test',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n });\n\n service.ClearRecentSearches();\n expect(service.RecentSearches$.value).toHaveLength(0);\n });\n });\n\n describe('GroupResults', () => {\n it('should group results by source type', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts'),\n createMockResult('2', 'entity', 'Contacts'),\n createMockResult('3', 'file', 'Documents'),\n createMockResult('4', 'web-page', 'Pages'),\n ];\n\n const groups = service.GroupResults(results);\n\n expect(groups).toHaveLength(3);\n const entityGroup = groups.find(g => g.SourceType === 'entity');\n expect(entityGroup?.Results).toHaveLength(2);\n expect(entityGroup?.Label).toBe('Database');\n });\n\n it('should return empty array for empty input', () => {\n const groups = service.GroupResults([]);\n expect(groups).toHaveLength(0);\n });\n });\n\n describe('BuildFilters', () => {\n it('should build source type, entity, and tag filters', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts', ['customer']),\n createMockResult('2', 'file', 'Documents', ['internal']),\n ];\n\n const filters = service.BuildFilters(results);\n\n expect(filters).toHaveLength(3);\n const sourceFilter = filters.find(f => f.Category === 'Source');\n expect(sourceFilter?.Options).toHaveLength(2);\n });\n\n it('should limit tags filter to 15 options', () => {\n const tags = Array.from({ length: 20 }, (_, i) => `tag${i}`);\n const results = tags.map((tag, i) =>\n createMockResult(String(i), 'entity', 'Test', [tag])\n );\n\n const filters = service.BuildFilters(results);\n const tagFilter = filters.find(f => f.Category === 'Tags');\n expect(tagFilter!.Options.length).toBeLessThanOrEqual(15);\n });\n\n it('should generate correct tag filter options with counts and icon', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts', ['crm', 'active']),\n createMockResult('2', 'entity', 'Companies', ['crm']),\n createMockResult('3', 'file', 'Docs', ['internal']),\n ];\n\n const filters = service.BuildFilters(results);\n const tagFilter = filters.find(f => f.Category === 'Tags');\n expect(tagFilter).toBeDefined();\n expect(tagFilter!.MultiSelect).toBe(true);\n\n // 'crm' appears in 2 results, should be sorted first\n const crmOption = tagFilter!.Options.find(o => o.Value === 'crm');\n expect(crmOption).toBeDefined();\n expect(crmOption!.Count).toBe(2);\n expect(crmOption!.Icon).toBe('fa-solid fa-tag');\n expect(crmOption!.IsSelected).toBe(false);\n\n // 'active' and 'internal' each appear once\n const activeOption = tagFilter!.Options.find(o => o.Value === 'active');\n expect(activeOption!.Count).toBe(1);\n const internalOption = tagFilter!.Options.find(o => o.Value === 'internal');\n expect(internalOption!.Count).toBe(1);\n });\n\n it('should omit Tags filter when no results have tags', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts'),\n createMockResult('2', 'entity', 'Companies'),\n ];\n\n const filters = service.BuildFilters(results);\n const tagFilter = filters.find(f => f.Category === 'Tags');\n expect(tagFilter).toBeUndefined(); // Empty categories are filtered out\n });\n\n it('should sort tags by count descending', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'A', ['rare', 'common']),\n createMockResult('2', 'entity', 'B', ['common']),\n createMockResult('3', 'entity', 'C', ['common']),\n ];\n\n const filters = service.BuildFilters(results);\n const tagFilter = filters.find(f => f.Category === 'Tags');\n expect(tagFilter!.Options[0].Value).toBe('common');\n expect(tagFilter!.Options[0].Count).toBe(3);\n expect(tagFilter!.Options[1].Value).toBe('rare');\n expect(tagFilter!.Options[1].Count).toBe(1);\n });\n });\n\n describe('GetSourceIcon', () => {\n it('should return correct icon for known types', () => {\n expect(service.GetSourceIcon('entity')).toContain('fa-database');\n expect(service.GetSourceIcon('file')).toContain('fa-file');\n expect(service.GetSourceIcon('web-page')).toContain('fa-globe');\n });\n\n it('should return fallback icon for unknown types', () => {\n expect(service.GetSourceIcon('unknown')).toContain('fa-circle');\n });\n });\n\n // ═══════════════════════════════════════════════════════════════\n // SR-3 Bug Fix: BuildFilters should preserve all options from full result set\n // ═══════════════════════════════════════════════════════════════\n describe('BuildFilters (SR-3: filter options from full result set)', () => {\n it('should include all entity names even when results are filtered', () => {\n // Full result set with 3 entities\n const fullResults: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts', ['crm']),\n createMockResult('2', 'entity', 'Companies', ['crm']),\n createMockResult('3', 'entity', 'Deals', ['sales']),\n ];\n\n // Build filters from FULL set (this is what the fix does)\n const filters = service.BuildFilters(fullResults);\n const entityFilter = filters.find(f => f.Category === 'Entity');\n\n // All 3 entities should appear in filter options\n expect(entityFilter?.Options).toHaveLength(3);\n expect(entityFilter?.Options.map(o => o.Value)).toContain('Contacts');\n expect(entityFilter?.Options.map(o => o.Value)).toContain('Companies');\n expect(entityFilter?.Options.map(o => o.Value)).toContain('Deals');\n });\n\n it('should count tags correctly across all results', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts', ['crm', 'sales']),\n createMockResult('2', 'entity', 'Companies', ['crm']),\n createMockResult('3', 'entity', 'Deals', ['sales', 'pipeline']),\n ];\n\n const filters = service.BuildFilters(results);\n const tagFilter = filters.find(f => f.Category === 'Tags');\n\n // 'crm' appears in 2 results, 'sales' in 2, 'pipeline' in 1\n expect(tagFilter?.Options).toHaveLength(3);\n const crmOption = tagFilter?.Options.find(o => o.Value === 'crm');\n expect(crmOption?.Count).toBe(2);\n });\n\n it('should not lose filter options when building from subset vs full set', () => {\n const fullResults: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts'),\n createMockResult('2', 'entity', 'Companies'),\n createMockResult('3', 'file', 'Documents'),\n ];\n\n // Simulating filtering to only Contacts\n const filteredResults = fullResults.filter(r => r.EntityName === 'Contacts');\n\n // Building from filtered set loses Companies and Documents\n const filteredFilters = service.BuildFilters(filteredResults);\n const filteredEntityFilter = filteredFilters.find(f => f.Category === 'Entity');\n expect(filteredEntityFilter?.Options).toHaveLength(1); // Only Contacts\n\n // Building from full set preserves all options (the fix)\n const fullFilters = service.BuildFilters(fullResults);\n const fullEntityFilter = fullFilters.find(f => f.Category === 'Entity');\n expect(fullEntityFilter?.Options).toHaveLength(3); // Contacts + Companies + Documents\n });\n });\n\n // ═══════════════════════════════════════════════════════════════\n // SR-4 Bug Fix: GroupResults should sort within groups by score\n // ═══════════════════════════════════════════════════════════════\n describe('GroupResults (SR-4: grouping and sorting)', () => {\n it('should group results by source type with correct labels', () => {\n const results: SearchResultItem[] = [\n { ...createMockResult('1', 'entity', 'Contacts'), Score: 0.9 },\n { ...createMockResult('2', 'content-item', 'Items'), Score: 0.8 },\n { ...createMockResult('3', 'entity', 'Companies'), Score: 0.7 },\n ];\n\n const groups = service.GroupResults(results);\n expect(groups).toHaveLength(2);\n\n const entityGroup = groups.find(g => g.SourceType === 'entity');\n expect(entityGroup?.Label).toBe('Database');\n expect(entityGroup?.TotalCount).toBe(2);\n\n const contentGroup = groups.find(g => g.SourceType === 'content-item');\n expect(contentGroup?.Label).toBe('Content Items');\n expect(contentGroup?.TotalCount).toBe(1);\n });\n\n it('should use fallback label for unknown source types', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Test'),\n ];\n // Hack source type to unknown\n (results[0] as unknown as Record<string, unknown>)['SourceType'] = 'custom-type';\n\n const groups = service.GroupResults(results);\n expect(groups[0].Label).toBe('custom-type'); // Falls back to raw type name\n });\n\n it('should use fallback icon for unknown source types', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Test'),\n ];\n (results[0] as unknown as Record<string, unknown>)['SourceType'] = 'unknown-source';\n\n const groups = service.GroupResults(results);\n expect(groups[0].Icon).toBe('fa-solid fa-circle');\n });\n\n it('should handle mixed known and unknown source types', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts'),\n createMockResult('2', 'entity', 'Companies'),\n ];\n (results[1] as unknown as Record<string, unknown>)['SourceType'] = 'custom-plugin';\n\n const groups = service.GroupResults(results);\n expect(groups).toHaveLength(2);\n\n const entityGroup = groups.find(g => g.SourceType === 'entity');\n expect(entityGroup?.Label).toBe('Database');\n\n const customGroup = groups.find(g => g.SourceType === 'custom-plugin');\n expect(customGroup?.Label).toBe('custom-plugin');\n expect(customGroup?.Icon).toBe('fa-solid fa-circle');\n });\n });\n});\n\nfunction createMockResult(\n id: string,\n sourceType: 'entity' | 'content-item' | 'file' | 'web-page',\n entityName: string,\n tags: string[] = []\n): SearchResultItem {\n return {\n ID: id,\n Title: `Result ${id}`,\n Snippet: `Snippet for result ${id}`,\n EntityName: entityName,\n RecordID: `rec-${id}`,\n SourceType: sourceType,\n ResultType: sourceType === 'file' ? 'storage-file' : 'entity-record',\n Score: 0.85,\n ScoreBreakdown: { Vector: 0.8, FullText: 0.9 },\n Tags: tags,\n SourceIcon: 'fa-solid fa-database',\n MatchedAt: new Date()\n };\n}\n"]}
1
+ {"version":3,"file":"search.service.test.js","sourceRoot":"","sources":["../../src/__tests__/search.service.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { describe, it, expect, beforeEach, vi } from 'vitest';\nimport { Subject } from 'rxjs';\nimport { Metadata } from '@memberjunction/core';\nimport { GraphQLDataProvider, GraphQLSearchClient } from '@memberjunction/graphql-dataprovider';\nimport { SearchService, RecentSearch } from '../lib/search.service';\nimport {\n SearchRequest,\n SearchResponse,\n SearchResultItem,\n SearchResultGroup,\n SearchFilter\n} from '../lib/search-types';\n\n/**\n * Installs a fake Metadata.Provider that passes the `instanceof GraphQLDataProvider` check\n * and stubs GraphQLSearchClient.ExecuteSearch to return empty success.\n */\nfunction installMockProvider(): ReturnType<typeof vi.fn> {\n const mockExecuteSearch = vi.fn().mockResolvedValue({\n Success: true,\n Results: [],\n TotalCount: 0,\n ElapsedMs: 1,\n SourceCounts: { Vector: 0, FullText: 0, Entity: 0, Storage: 0 },\n });\n\n // Create a mock that passes `instanceof GraphQLDataProvider`\n const mockProvider = Object.create(GraphQLDataProvider.prototype);\n (Metadata as unknown as Record<string, unknown>)['Provider'] = mockProvider;\n\n // Stub GraphQLSearchClient.prototype so the service's `new GraphQLSearchClient(provider)` works\n vi.spyOn(GraphQLSearchClient.prototype, 'ExecuteSearch').mockImplementation(mockExecuteSearch);\n vi.spyOn(GraphQLSearchClient.prototype, 'PreviewSearch').mockImplementation(mockExecuteSearch);\n\n return mockExecuteSearch;\n}\n\ndescribe('SearchService', () => {\n let service: SearchService;\n\n beforeEach(() => {\n service = new SearchService();\n installMockProvider();\n });\n\n describe('ExecuteSearch', () => {\n it('should set IsSearching to true during search', async () => {\n const values: boolean[] = [];\n service.IsSearching$.subscribe(val => values.push(val));\n\n await service.ExecuteSearch({\n Query: 'test query',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector', 'fulltext', 'entity']\n });\n\n // Should have gone true then false\n expect(values).toContain(true);\n expect(values[values.length - 1]).toBe(false);\n });\n\n it('should return empty results for empty query', async () => {\n const response = await service.ExecuteSearch({\n Query: ' ',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n });\n\n expect(response.Success).toBe(true);\n expect(response.Results).toHaveLength(0);\n expect(response.TotalCount).toBe(0);\n });\n\n it('should update SearchResults$ observable', async () => {\n await service.ExecuteSearch({\n Query: 'test',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n });\n\n const result = service.SearchResults$.value;\n expect(result).not.toBeNull();\n expect(result?.Success).toBe(true);\n });\n\n it('should add to recent searches', async () => {\n await service.ExecuteSearch({\n Query: 'test query',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n });\n\n const recent = service.RecentSearches$.value;\n expect(recent.length).toBe(1);\n expect(recent[0].Query).toBe('test query');\n });\n\n it('should deduplicate recent searches', async () => {\n const request: SearchRequest = {\n Query: 'test',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n };\n\n await service.ExecuteSearch(request);\n await service.ExecuteSearch(request);\n\n const recent = service.RecentSearches$.value;\n expect(recent.length).toBe(1);\n });\n\n it('should limit recent searches to max 20', async () => {\n for (let i = 0; i < 25; i++) {\n await service.ExecuteSearch({\n Query: `query ${i}`,\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n });\n }\n\n expect(service.RecentSearches$.value.length).toBeLessThanOrEqual(20);\n });\n });\n\n describe('StreamSearch', () => {\n it('forwards Phase, ProviderName, and ElapsedMs unchanged and maps client results through mapClientResultItem', () => {\n const stream$ = new Subject<{\n StreamID: string;\n Phase: string;\n ProviderName?: string;\n Results?: ReturnType<typeof makeClientResultItem>[];\n ElapsedMs?: number;\n ErrorMessage?: string;\n }>();\n vi.spyOn(GraphQLSearchClient.prototype, 'StreamSearch').mockReturnValue(stream$);\n\n const events: Array<{ Phase: string; ProviderName?: string; Results?: SearchResultItem[]; ElapsedMs?: number }> = [];\n const sub = service.StreamSearch({\n Query: 'streamed query',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector', 'fulltext']\n }).subscribe({\n next: ev => events.push(ev),\n });\n\n stream$.next({ StreamID: 'sid-1', Phase: 'provider', ProviderName: 'Vector', Results: [makeClientResultItem('a', 'fast-row')], ElapsedMs: 12 });\n stream$.next({ StreamID: 'sid-1', Phase: 'fused', Results: [makeClientResultItem('a', 'fast-row'), makeClientResultItem('b', 'slow-row')], ElapsedMs: 50 });\n stream$.next({ StreamID: 'sid-1', Phase: 'final', Results: [makeClientResultItem('a', 'fast-row'), makeClientResultItem('b', 'slow-row')], ElapsedMs: 75 });\n\n expect(events).toHaveLength(3);\n expect(events[0].Phase).toBe('provider');\n expect(events[0].ProviderName).toBe('Vector');\n expect(events[0].ElapsedMs).toBe(12);\n // mapClientResultItem prefers RecordName over Title and unwraps RawMetadata; assert one mapped field\n expect(events[0].Results?.[0].Title).toBe('fast-row');\n expect(events[0].Results?.[0].MatchedAt).toBeInstanceOf(Date);\n\n expect(events[1].Phase).toBe('fused');\n expect(events[1].Results).toHaveLength(2);\n expect(events[2].Phase).toBe('final');\n expect(events[2].ElapsedMs).toBe(75);\n\n sub.unsubscribe();\n });\n\n it('omits Results from emitted event when the wire frame has no Results', () => {\n const stream$ = new Subject<{ StreamID: string; Phase: string; ElapsedMs?: number }>();\n vi.spyOn(GraphQLSearchClient.prototype, 'StreamSearch').mockReturnValue(stream$);\n\n const events: Array<{ Phase: string; Results?: SearchResultItem[] }> = [];\n const sub = service.StreamSearch({\n Query: 'no-results phase',\n MaxResults: 5,\n ActiveFilters: {},\n IncludeSources: ['vector']\n }).subscribe({\n next: ev => events.push(ev),\n });\n\n // 'reranked' phase server-side may carry no Results (it just signals the rerank step ran)\n stream$.next({ StreamID: 'sid-2', Phase: 'reranked', ElapsedMs: 30 });\n\n expect(events).toHaveLength(1);\n expect(events[0].Phase).toBe('reranked');\n expect(events[0].Results).toBeUndefined();\n\n sub.unsubscribe();\n });\n\n it('propagates errors from the underlying client observable', () => {\n const stream$ = new Subject<{ StreamID: string; Phase: string }>();\n vi.spyOn(GraphQLSearchClient.prototype, 'StreamSearch').mockReturnValue(stream$);\n\n let captured: Error | null = null;\n const sub = service.StreamSearch({\n Query: 'error path',\n MaxResults: 5,\n ActiveFilters: {},\n IncludeSources: ['vector']\n }).subscribe({\n next: () => { /* ignore */ },\n error: err => { captured = err as Error; },\n });\n\n stream$.error(new Error('upstream blew up'));\n\n expect(captured).not.toBeNull();\n expect((captured as unknown as Error).message).toBe('upstream blew up');\n\n sub.unsubscribe();\n });\n\n it('errors when no GraphQL provider is available (e.g., Metadata.Provider not yet bootstrapped)', () => {\n (Metadata as unknown as Record<string, unknown>)['Provider'] = {}; // not a GraphQLDataProvider\n\n let captured: Error | null = null;\n const sub = service.StreamSearch({\n Query: 'no provider',\n MaxResults: 5,\n ActiveFilters: {},\n IncludeSources: ['vector']\n }).subscribe({\n next: () => { /* ignore */ },\n error: err => { captured = err as Error; },\n });\n\n expect(captured).not.toBeNull();\n expect((captured as unknown as Error).message).toBe('GraphQL provider not available');\n\n sub.unsubscribe();\n });\n });\n\n describe('ClearResults', () => {\n it('should set SearchResults$ to null', async () => {\n await service.ExecuteSearch({\n Query: 'test',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n });\n\n service.ClearResults();\n expect(service.SearchResults$.value).toBeNull();\n });\n });\n\n describe('ClearRecentSearches', () => {\n it('should clear all recent searches', async () => {\n await service.ExecuteSearch({\n Query: 'test',\n MaxResults: 10,\n ActiveFilters: {},\n IncludeSources: ['vector']\n });\n\n service.ClearRecentSearches();\n expect(service.RecentSearches$.value).toHaveLength(0);\n });\n });\n\n describe('GroupResults', () => {\n it('should group results by source type', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts'),\n createMockResult('2', 'entity', 'Contacts'),\n createMockResult('3', 'file', 'Documents'),\n createMockResult('4', 'web-page', 'Pages'),\n ];\n\n const groups = service.GroupResults(results);\n\n expect(groups).toHaveLength(3);\n const entityGroup = groups.find(g => g.SourceType === 'entity');\n expect(entityGroup?.Results).toHaveLength(2);\n expect(entityGroup?.Label).toBe('Database');\n });\n\n it('should return empty array for empty input', () => {\n const groups = service.GroupResults([]);\n expect(groups).toHaveLength(0);\n });\n });\n\n describe('BuildFilters', () => {\n it('should build source type, entity, and tag filters', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts', ['customer']),\n createMockResult('2', 'file', 'Documents', ['internal']),\n ];\n\n const filters = service.BuildFilters(results);\n\n expect(filters).toHaveLength(3);\n const sourceFilter = filters.find(f => f.Category === 'Source');\n expect(sourceFilter?.Options).toHaveLength(2);\n });\n\n it('should limit tags filter to 15 options', () => {\n const tags = Array.from({ length: 20 }, (_, i) => `tag${i}`);\n const results = tags.map((tag, i) =>\n createMockResult(String(i), 'entity', 'Test', [tag])\n );\n\n const filters = service.BuildFilters(results);\n const tagFilter = filters.find(f => f.Category === 'Tags');\n expect(tagFilter!.Options.length).toBeLessThanOrEqual(15);\n });\n\n it('should generate correct tag filter options with counts and icon', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts', ['crm', 'active']),\n createMockResult('2', 'entity', 'Companies', ['crm']),\n createMockResult('3', 'file', 'Docs', ['internal']),\n ];\n\n const filters = service.BuildFilters(results);\n const tagFilter = filters.find(f => f.Category === 'Tags');\n expect(tagFilter).toBeDefined();\n expect(tagFilter!.MultiSelect).toBe(true);\n\n // 'crm' appears in 2 results, should be sorted first\n const crmOption = tagFilter!.Options.find(o => o.Value === 'crm');\n expect(crmOption).toBeDefined();\n expect(crmOption!.Count).toBe(2);\n expect(crmOption!.Icon).toBe('fa-solid fa-tag');\n expect(crmOption!.IsSelected).toBe(false);\n\n // 'active' and 'internal' each appear once\n const activeOption = tagFilter!.Options.find(o => o.Value === 'active');\n expect(activeOption!.Count).toBe(1);\n const internalOption = tagFilter!.Options.find(o => o.Value === 'internal');\n expect(internalOption!.Count).toBe(1);\n });\n\n it('should omit Tags filter when no results have tags', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts'),\n createMockResult('2', 'entity', 'Companies'),\n ];\n\n const filters = service.BuildFilters(results);\n const tagFilter = filters.find(f => f.Category === 'Tags');\n expect(tagFilter).toBeUndefined(); // Empty categories are filtered out\n });\n\n it('should sort tags by count descending', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'A', ['rare', 'common']),\n createMockResult('2', 'entity', 'B', ['common']),\n createMockResult('3', 'entity', 'C', ['common']),\n ];\n\n const filters = service.BuildFilters(results);\n const tagFilter = filters.find(f => f.Category === 'Tags');\n expect(tagFilter!.Options[0].Value).toBe('common');\n expect(tagFilter!.Options[0].Count).toBe(3);\n expect(tagFilter!.Options[1].Value).toBe('rare');\n expect(tagFilter!.Options[1].Count).toBe(1);\n });\n });\n\n describe('GetSourceIcon', () => {\n it('should return correct icon for known types', () => {\n expect(service.GetSourceIcon('entity')).toContain('fa-database');\n expect(service.GetSourceIcon('file')).toContain('fa-file');\n expect(service.GetSourceIcon('web-page')).toContain('fa-globe');\n });\n\n it('should return fallback icon for unknown types', () => {\n expect(service.GetSourceIcon('unknown')).toContain('fa-circle');\n });\n });\n\n // ═══════════════════════════════════════════════════════════════\n // SR-3 Bug Fix: BuildFilters should preserve all options from full result set\n // ═══════════════════════════════════════════════════════════════\n describe('BuildFilters (SR-3: filter options from full result set)', () => {\n it('should include all entity names even when results are filtered', () => {\n // Full result set with 3 entities\n const fullResults: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts', ['crm']),\n createMockResult('2', 'entity', 'Companies', ['crm']),\n createMockResult('3', 'entity', 'Deals', ['sales']),\n ];\n\n // Build filters from FULL set (this is what the fix does)\n const filters = service.BuildFilters(fullResults);\n const entityFilter = filters.find(f => f.Category === 'Entity');\n\n // All 3 entities should appear in filter options\n expect(entityFilter?.Options).toHaveLength(3);\n expect(entityFilter?.Options.map(o => o.Value)).toContain('Contacts');\n expect(entityFilter?.Options.map(o => o.Value)).toContain('Companies');\n expect(entityFilter?.Options.map(o => o.Value)).toContain('Deals');\n });\n\n it('should count tags correctly across all results', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts', ['crm', 'sales']),\n createMockResult('2', 'entity', 'Companies', ['crm']),\n createMockResult('3', 'entity', 'Deals', ['sales', 'pipeline']),\n ];\n\n const filters = service.BuildFilters(results);\n const tagFilter = filters.find(f => f.Category === 'Tags');\n\n // 'crm' appears in 2 results, 'sales' in 2, 'pipeline' in 1\n expect(tagFilter?.Options).toHaveLength(3);\n const crmOption = tagFilter?.Options.find(o => o.Value === 'crm');\n expect(crmOption?.Count).toBe(2);\n });\n\n it('should not lose filter options when building from subset vs full set', () => {\n const fullResults: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts'),\n createMockResult('2', 'entity', 'Companies'),\n createMockResult('3', 'file', 'Documents'),\n ];\n\n // Simulating filtering to only Contacts\n const filteredResults = fullResults.filter(r => r.EntityName === 'Contacts');\n\n // Building from filtered set loses Companies and Documents\n const filteredFilters = service.BuildFilters(filteredResults);\n const filteredEntityFilter = filteredFilters.find(f => f.Category === 'Entity');\n expect(filteredEntityFilter?.Options).toHaveLength(1); // Only Contacts\n\n // Building from full set preserves all options (the fix)\n const fullFilters = service.BuildFilters(fullResults);\n const fullEntityFilter = fullFilters.find(f => f.Category === 'Entity');\n expect(fullEntityFilter?.Options).toHaveLength(3); // Contacts + Companies + Documents\n });\n });\n\n // ═══════════════════════════════════════════════════════════════\n // SR-4 Bug Fix: GroupResults should sort within groups by score\n // ═══════════════════════════════════════════════════════════════\n describe('GroupResults (SR-4: grouping and sorting)', () => {\n it('should group results by source type with correct labels', () => {\n const results: SearchResultItem[] = [\n { ...createMockResult('1', 'entity', 'Contacts'), Score: 0.9 },\n { ...createMockResult('2', 'content-item', 'Items'), Score: 0.8 },\n { ...createMockResult('3', 'entity', 'Companies'), Score: 0.7 },\n ];\n\n const groups = service.GroupResults(results);\n expect(groups).toHaveLength(2);\n\n const entityGroup = groups.find(g => g.SourceType === 'entity');\n expect(entityGroup?.Label).toBe('Database');\n expect(entityGroup?.TotalCount).toBe(2);\n\n const contentGroup = groups.find(g => g.SourceType === 'content-item');\n expect(contentGroup?.Label).toBe('Content Items');\n expect(contentGroup?.TotalCount).toBe(1);\n });\n\n it('should use fallback label for unknown source types', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Test'),\n ];\n // Hack source type to unknown\n (results[0] as unknown as Record<string, unknown>)['SourceType'] = 'custom-type';\n\n const groups = service.GroupResults(results);\n expect(groups[0].Label).toBe('custom-type'); // Falls back to raw type name\n });\n\n it('should use fallback icon for unknown source types', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Test'),\n ];\n (results[0] as unknown as Record<string, unknown>)['SourceType'] = 'unknown-source';\n\n const groups = service.GroupResults(results);\n expect(groups[0].Icon).toBe('fa-solid fa-circle');\n });\n\n it('should handle mixed known and unknown source types', () => {\n const results: SearchResultItem[] = [\n createMockResult('1', 'entity', 'Contacts'),\n createMockResult('2', 'entity', 'Companies'),\n ];\n (results[1] as unknown as Record<string, unknown>)['SourceType'] = 'custom-plugin';\n\n const groups = service.GroupResults(results);\n expect(groups).toHaveLength(2);\n\n const entityGroup = groups.find(g => g.SourceType === 'entity');\n expect(entityGroup?.Label).toBe('Database');\n\n const customGroup = groups.find(g => g.SourceType === 'custom-plugin');\n expect(customGroup?.Label).toBe('custom-plugin');\n expect(customGroup?.Icon).toBe('fa-solid fa-circle');\n });\n });\n});\n\nfunction createMockResult(\n id: string,\n sourceType: 'entity' | 'content-item' | 'file' | 'web-page',\n entityName: string,\n tags: string[] = []\n): SearchResultItem {\n return {\n ID: id,\n Title: `Result ${id}`,\n Snippet: `Snippet for result ${id}`,\n EntityName: entityName,\n RecordID: `rec-${id}`,\n SourceType: sourceType,\n ResultType: sourceType === 'file' ? 'storage-file' : 'entity-record',\n Score: 0.85,\n ScoreBreakdown: { Vector: 0.8, FullText: 0.9 },\n Tags: tags,\n SourceIcon: 'fa-solid fa-database',\n MatchedAt: new Date()\n };\n}\n\nfunction makeClientResultItem(id: string, title: string) {\n return {\n ID: id,\n EntityName: 'Contacts',\n RecordID: `rec-${id}`,\n SourceType: 'entity',\n Title: title,\n Snippet: `snippet for ${id}`,\n Score: 0.91,\n ScoreBreakdown: { Vector: 0.9, FullText: 0.92 },\n Tags: ['streaming'],\n EntityIcon: 'fa-solid fa-database',\n RecordName: title,\n MatchedAt: new Date().toISOString(),\n ResultType: 'entity-record',\n };\n}\n"]}
@@ -5,12 +5,14 @@ import * as i3 from "./search-filter.component";
5
5
  import * as i4 from "./search-input.component";
6
6
  import * as i5 from "./search-suggest.component";
7
7
  import * as i6 from "./search-composite.component";
8
- import * as i7 from "@angular/common";
9
- import * as i8 from "@angular/forms";
10
- import * as i9 from "@memberjunction/ng-shared-generic";
8
+ import * as i7 from "./search-scope-selector.component";
9
+ import * as i8 from "./search-scope-child-grid.component";
10
+ import * as i9 from "@angular/common";
11
+ import * as i10 from "@angular/forms";
12
+ import * as i11 from "@memberjunction/ng-shared-generic";
11
13
  export declare class SearchModule {
12
14
  static ɵfac: i0.ɵɵFactoryDeclaration<SearchModule, never>;
13
- static ɵmod: i0.ɵɵNgModuleDeclaration<SearchModule, [typeof i1.SearchOverlayComponent, typeof i2.SearchResultsComponent, typeof i3.SearchFilterComponent, typeof i4.SearchInputComponent, typeof i5.SearchSuggestComponent, typeof i6.SearchCompositeComponent], [typeof i7.CommonModule, typeof i8.FormsModule, typeof i9.SharedGenericModule], [typeof i1.SearchOverlayComponent, typeof i2.SearchResultsComponent, typeof i3.SearchFilterComponent, typeof i4.SearchInputComponent, typeof i5.SearchSuggestComponent, typeof i6.SearchCompositeComponent]>;
15
+ static ɵmod: i0.ɵɵNgModuleDeclaration<SearchModule, [typeof i1.SearchOverlayComponent, typeof i2.SearchResultsComponent, typeof i3.SearchFilterComponent, typeof i4.SearchInputComponent, typeof i5.SearchSuggestComponent, typeof i6.SearchCompositeComponent, typeof i7.SearchScopeSelectorComponent, typeof i8.SearchScopeChildGridComponent], [typeof i9.CommonModule, typeof i10.FormsModule, typeof i11.SharedGenericModule], [typeof i1.SearchOverlayComponent, typeof i2.SearchResultsComponent, typeof i3.SearchFilterComponent, typeof i4.SearchInputComponent, typeof i5.SearchSuggestComponent, typeof i6.SearchCompositeComponent, typeof i7.SearchScopeSelectorComponent, typeof i8.SearchScopeChildGridComponent]>;
14
16
  static ɵinj: i0.ɵɵInjectorDeclaration<SearchModule>;
15
17
  }
16
18
  //# sourceMappingURL=module.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":";;;;;;;;;;AAYA,qBAuBa,YAAY;yCAAZ,YAAY;0CAAZ,YAAY;0CAAZ,YAAY;CAAI"}
1
+ {"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":";;;;;;;;;;;;AAcA,qBA2Ba,YAAY;yCAAZ,YAAY;0CAAZ,YAAY;0CAAZ,YAAY;CAAI"}
@@ -8,6 +8,8 @@ import { SearchFilterComponent } from './search-filter.component';
8
8
  import { SearchInputComponent } from './search-input.component';
9
9
  import { SearchSuggestComponent } from './search-suggest.component';
10
10
  import { SearchCompositeComponent } from './search-composite.component';
11
+ import { SearchScopeSelectorComponent } from './search-scope-selector.component';
12
+ import { SearchScopeChildGridComponent } from './search-scope-child-grid.component';
11
13
  import * as i0 from "@angular/core";
12
14
  export class SearchModule {
13
15
  static ɵfac = function SearchModule_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SearchModule)(); };
@@ -25,7 +27,9 @@ export class SearchModule {
25
27
  SearchFilterComponent,
26
28
  SearchInputComponent,
27
29
  SearchSuggestComponent,
28
- SearchCompositeComponent
30
+ SearchCompositeComponent,
31
+ SearchScopeSelectorComponent,
32
+ SearchScopeChildGridComponent
29
33
  ],
30
34
  imports: [
31
35
  CommonModule,
@@ -38,7 +42,9 @@ export class SearchModule {
38
42
  SearchFilterComponent,
39
43
  SearchInputComponent,
40
44
  SearchSuggestComponent,
41
- SearchCompositeComponent
45
+ SearchCompositeComponent,
46
+ SearchScopeSelectorComponent,
47
+ SearchScopeChildGridComponent
42
48
  ]
43
49
  }]
44
50
  }], null, null); })();
@@ -47,12 +53,16 @@ export class SearchModule {
47
53
  SearchFilterComponent,
48
54
  SearchInputComponent,
49
55
  SearchSuggestComponent,
50
- SearchCompositeComponent], imports: [CommonModule,
56
+ SearchCompositeComponent,
57
+ SearchScopeSelectorComponent,
58
+ SearchScopeChildGridComponent], imports: [CommonModule,
51
59
  FormsModule,
52
60
  SharedGenericModule], exports: [SearchOverlayComponent,
53
61
  SearchResultsComponent,
54
62
  SearchFilterComponent,
55
63
  SearchInputComponent,
56
64
  SearchSuggestComponent,
57
- SearchCompositeComponent] }); })();
65
+ SearchCompositeComponent,
66
+ SearchScopeSelectorComponent,
67
+ SearchScopeChildGridComponent] }); })();
58
68
  //# sourceMappingURL=module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"module.js","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAExE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;;AAyBxE,MAAM,OAAO,YAAY;sGAAZ,YAAY;4DAAZ,YAAY;gEAbjB,YAAY;YACZ,WAAW;YACX,mBAAmB;;iFAWd,YAAY;cAvBxB,QAAQ;eAAC;gBACN,YAAY,EAAE;oBACV,sBAAsB;oBACtB,sBAAsB;oBACtB,qBAAqB;oBACrB,oBAAoB;oBACpB,sBAAsB;oBACtB,wBAAwB;iBAC3B;gBACD,OAAO,EAAE;oBACL,YAAY;oBACZ,WAAW;oBACX,mBAAmB;iBACtB;gBACD,OAAO,EAAE;oBACL,sBAAsB;oBACtB,sBAAsB;oBACtB,qBAAqB;oBACrB,oBAAoB;oBACpB,sBAAsB;oBACtB,wBAAwB;iBAC3B;aACJ;;wFACY,YAAY,mBArBjB,sBAAsB;QACtB,sBAAsB;QACtB,qBAAqB;QACrB,oBAAoB;QACpB,sBAAsB;QACtB,wBAAwB,aAGxB,YAAY;QACZ,WAAW;QACX,mBAAmB,aAGnB,sBAAsB;QACtB,sBAAsB;QACtB,qBAAqB;QACrB,oBAAoB;QACpB,sBAAsB;QACtB,wBAAwB","sourcesContent":["import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { SharedGenericModule } from '@memberjunction/ng-shared-generic';\n\nimport { SearchOverlayComponent } from './search-overlay.component';\nimport { SearchResultsComponent } from './search-results.component';\nimport { SearchFilterComponent } from './search-filter.component';\nimport { SearchInputComponent } from './search-input.component';\nimport { SearchSuggestComponent } from './search-suggest.component';\nimport { SearchCompositeComponent } from './search-composite.component';\n\n@NgModule({\n declarations: [\n SearchOverlayComponent,\n SearchResultsComponent,\n SearchFilterComponent,\n SearchInputComponent,\n SearchSuggestComponent,\n SearchCompositeComponent\n ],\n imports: [\n CommonModule,\n FormsModule,\n SharedGenericModule\n ],\n exports: [\n SearchOverlayComponent,\n SearchResultsComponent,\n SearchFilterComponent,\n SearchInputComponent,\n SearchSuggestComponent,\n SearchCompositeComponent\n ]\n})\nexport class SearchModule { }\n"]}
1
+ {"version":3,"file":"module.js","sourceRoot":"","sources":["../../src/lib/module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,mCAAmC,CAAC;AAExE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,EAAE,4BAA4B,EAAE,MAAM,mCAAmC,CAAC;AACjF,OAAO,EAAE,6BAA6B,EAAE,MAAM,qCAAqC,CAAC;;AA6BpF,MAAM,OAAO,YAAY;sGAAZ,YAAY;4DAAZ,YAAY;gEAfjB,YAAY;YACZ,WAAW;YACX,mBAAmB;;iFAad,YAAY;cA3BxB,QAAQ;eAAC;gBACN,YAAY,EAAE;oBACV,sBAAsB;oBACtB,sBAAsB;oBACtB,qBAAqB;oBACrB,oBAAoB;oBACpB,sBAAsB;oBACtB,wBAAwB;oBACxB,4BAA4B;oBAC5B,6BAA6B;iBAChC;gBACD,OAAO,EAAE;oBACL,YAAY;oBACZ,WAAW;oBACX,mBAAmB;iBACtB;gBACD,OAAO,EAAE;oBACL,sBAAsB;oBACtB,sBAAsB;oBACtB,qBAAqB;oBACrB,oBAAoB;oBACpB,sBAAsB;oBACtB,wBAAwB;oBACxB,4BAA4B;oBAC5B,6BAA6B;iBAChC;aACJ;;wFACY,YAAY,mBAzBjB,sBAAsB;QACtB,sBAAsB;QACtB,qBAAqB;QACrB,oBAAoB;QACpB,sBAAsB;QACtB,wBAAwB;QACxB,4BAA4B;QAC5B,6BAA6B,aAG7B,YAAY;QACZ,WAAW;QACX,mBAAmB,aAGnB,sBAAsB;QACtB,sBAAsB;QACtB,qBAAqB;QACrB,oBAAoB;QACpB,sBAAsB;QACtB,wBAAwB;QACxB,4BAA4B;QAC5B,6BAA6B","sourcesContent":["import { NgModule } from '@angular/core';\nimport { CommonModule } from '@angular/common';\nimport { FormsModule } from '@angular/forms';\nimport { SharedGenericModule } from '@memberjunction/ng-shared-generic';\n\nimport { SearchOverlayComponent } from './search-overlay.component';\nimport { SearchResultsComponent } from './search-results.component';\nimport { SearchFilterComponent } from './search-filter.component';\nimport { SearchInputComponent } from './search-input.component';\nimport { SearchSuggestComponent } from './search-suggest.component';\nimport { SearchCompositeComponent } from './search-composite.component';\nimport { SearchScopeSelectorComponent } from './search-scope-selector.component';\nimport { SearchScopeChildGridComponent } from './search-scope-child-grid.component';\n\n@NgModule({\n declarations: [\n SearchOverlayComponent,\n SearchResultsComponent,\n SearchFilterComponent,\n SearchInputComponent,\n SearchSuggestComponent,\n SearchCompositeComponent,\n SearchScopeSelectorComponent,\n SearchScopeChildGridComponent\n ],\n imports: [\n CommonModule,\n FormsModule,\n SharedGenericModule\n ],\n exports: [\n SearchOverlayComponent,\n SearchResultsComponent,\n SearchFilterComponent,\n SearchInputComponent,\n SearchSuggestComponent,\n SearchCompositeComponent,\n SearchScopeSelectorComponent,\n SearchScopeChildGridComponent\n ]\n})\nexport class SearchModule { }\n"]}
@@ -9,7 +9,7 @@ import { EventEmitter, OnDestroy, OnInit } from '@angular/core';
9
9
  import { SearchService, RecentSearch } from './search.service';
10
10
  import { SearchInputComponent } from './search-input.component';
11
11
  import { SearchSuggestComponent } from './search-suggest.component';
12
- import { SearchResultItem } from './search-types';
12
+ import { SearchResultItem, SearchScopeInfo } from './search-types';
13
13
  import * as i0 from "@angular/core";
14
14
  export declare class SearchCompositeComponent implements OnInit, OnDestroy {
15
15
  private cdr;
@@ -32,6 +32,13 @@ export declare class SearchCompositeComponent implements OnInit, OnDestroy {
32
32
  EnablePreview: boolean;
33
33
  /** Whether to enable recent searches display */
34
34
  EnableRecent: boolean;
35
+ /**
36
+ * Whether to show the scope selector inline with the search input. When true (default),
37
+ * the composite lazy-loads the list of scopes the current user can see and renders the
38
+ * selector only if at least one scope exists. When zero scopes are visible the selector
39
+ * stays hidden and the UX is identical to the pre-scope unscoped behavior.
40
+ */
41
+ EnableScopeSelector: boolean;
35
42
  /** Emitted when a result is selected from the preview dropdown */
36
43
  ResultSelected: EventEmitter<SearchResultItem>;
37
44
  /** Emitted when the user presses Enter or selects a recent search (full search) */
@@ -47,6 +54,19 @@ export declare class SearchCompositeComponent implements OnInit, OnDestroy {
47
54
  PreviewTotalCount: number;
48
55
  IsPreviewLoading: boolean;
49
56
  private previewSearchVersion;
57
+ /**
58
+ * Scopes the current user can see. Populated by `SearchService.LoadScopes()` on init.
59
+ * When empty, the scope selector is not rendered (unscoped-as-before UX).
60
+ */
61
+ AvailableScopes: SearchScopeInfo[];
62
+ /** Whether any scope is visible to the current user — drives selector visibility. */
63
+ HasScopes: boolean;
64
+ /**
65
+ * Currently selected scope IDs. Empty array means "Global" / unscoped. Read by the
66
+ * shell (or any parent) on submit via the exposed getter, and mirrored to the server
67
+ * through `SearchRequest.ScopeIDs` on the full submitted search.
68
+ */
69
+ SelectedScopeIDs: string[];
50
70
  ngOnInit(): void;
51
71
  ngOnDestroy(): void;
52
72
  OnDocumentMousedown(event: MouseEvent): void;
@@ -69,12 +89,19 @@ export declare class SearchCompositeComponent implements OnInit, OnDestroy {
69
89
  OnSeeAllRequested(query: string): void;
70
90
  /** Handle "Clear" recent searches */
71
91
  OnClearRecentRequested(): void;
92
+ /**
93
+ * Relay a selection change from the embedded scope selector to local state. Parents
94
+ * read `SelectedScopeIDs` directly on submit; no output event is needed because
95
+ * scope selection doesn't alter the inline preview (preview stays global for speed).
96
+ */
97
+ OnScopeSelectionChange(scopeIDs: string[]): void;
72
98
  private openSuggest;
73
99
  private closeSuggest;
74
100
  private subscribeToRecentSearches;
101
+ private subscribeToScopes;
75
102
  private executePreviewSearch;
76
103
  private clearPreviewResults;
77
104
  static ɵfac: i0.ɵɵFactoryDeclaration<SearchCompositeComponent, never>;
78
- static ɵcmp: i0.ɵɵComponentDeclaration<SearchCompositeComponent, "mj-search-composite", never, { "Placeholder": { "alias": "Placeholder"; "required": false; }; "ShowShortcutHint": { "alias": "ShowShortcutHint"; "required": false; }; "DebounceMs": { "alias": "DebounceMs"; "required": false; }; "MinQueryLength": { "alias": "MinQueryLength"; "required": false; }; "MaxPreviewResults": { "alias": "MaxPreviewResults"; "required": false; }; "EnablePreview": { "alias": "EnablePreview"; "required": false; }; "EnableRecent": { "alias": "EnableRecent"; "required": false; }; }, { "ResultSelected": "ResultSelected"; "SearchSubmitted": "SearchSubmitted"; "SeeAllRequested": "SeeAllRequested"; }, never, never, false, never>;
105
+ static ɵcmp: i0.ɵɵComponentDeclaration<SearchCompositeComponent, "mj-search-composite", never, { "Placeholder": { "alias": "Placeholder"; "required": false; }; "ShowShortcutHint": { "alias": "ShowShortcutHint"; "required": false; }; "DebounceMs": { "alias": "DebounceMs"; "required": false; }; "MinQueryLength": { "alias": "MinQueryLength"; "required": false; }; "MaxPreviewResults": { "alias": "MaxPreviewResults"; "required": false; }; "EnablePreview": { "alias": "EnablePreview"; "required": false; }; "EnableRecent": { "alias": "EnableRecent"; "required": false; }; "EnableScopeSelector": { "alias": "EnableScopeSelector"; "required": false; }; }, { "ResultSelected": "ResultSelected"; "SearchSubmitted": "SearchSubmitted"; "SeeAllRequested": "SeeAllRequested"; }, never, never, false, never>;
79
106
  }
80
107
  //# sourceMappingURL=search-composite.component.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"search-composite.component.d.ts","sourceRoot":"","sources":["../../src/lib/search-composite.component.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAGH,YAAY,EAGZ,SAAS,EACT,MAAM,EAKT,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;;AAElD,qBAMa,wBAAyB,YAAW,MAAM,EAAE,SAAS;IAC9D,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,UAAU,CAAsB;IACxC,SAAS,CAAC,aAAa,gBAAyB;IAChD,OAAO,CAAC,QAAQ,CAAuB;IAEb,cAAc,EAAG,oBAAoB,CAAC;IACpC,gBAAgB,EAAG,sBAAsB,CAAC;IAItE,4CAA4C;IACnC,WAAW,SAAe;IAEnC,0DAA0D;IACjD,gBAAgB,UAAQ;IAEjC,sDAAsD;IAC7C,UAAU,SAAO;IAE1B,8DAA8D;IACrD,cAAc,SAAK;IAE5B,gEAAgE;IACvD,iBAAiB,SAAK;IAE/B,sDAAsD;IAC7C,aAAa,UAAQ;IAE9B,gDAAgD;IACvC,YAAY,UAAQ;IAI7B,kEAAkE;IACxD,cAAc,iCAAwC;IAEhE,mFAAmF;IACzE,eAAe,uBAA8B;IAEvD,uDAAuD;IAC7C,eAAe,uBAA8B;IAIhD,KAAK,SAAM;IACX,aAAa,UAAS;IAE7B,yEAAyE;IACzE,IAAW,mBAAmB,IAAI,MAAM,CAEvC;IACM,cAAc,EAAE,gBAAgB,EAAE,CAAM;IACxC,cAAc,EAAE,YAAY,EAAE,CAAM;IACpC,iBAAiB,SAAK;IACtB,gBAAgB,UAAS;IAChC,OAAO,CAAC,oBAAoB,CAAK;IAEjC,QAAQ,IAAI,IAAI;IAKhB,WAAW,IAAI,IAAI;IAQnB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAU5C,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAuBzC,oDAAoD;IAC7C,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAYzC,sCAAsC;IAC/B,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAazC,yBAAyB;IAClB,cAAc,IAAI,IAAI;IAI7B,uCAAuC;IAChC,cAAc,IAAI,IAAI;IAM7B,2BAA2B;IACpB,cAAc,IAAI,IAAI;IAM7B,oDAAoD;IAC7C,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAKvD,qCAAqC;IAC9B,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAM5C,6BAA6B;IACtB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7C,qCAAqC;IAC9B,sBAAsB,IAAI,IAAI;IAMrC,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,yBAAyB;YASnB,oBAAoB;IAyBlC,OAAO,CAAC,mBAAmB;yCA9NlB,wBAAwB;2CAAxB,wBAAwB;CAmOpC"}
1
+ {"version":3,"file":"search-composite.component.d.ts","sourceRoot":"","sources":["../../src/lib/search-composite.component.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAGH,YAAY,EAGZ,SAAS,EACT,MAAM,EAKT,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;;AAEnE,qBAMa,wBAAyB,YAAW,MAAM,EAAE,SAAS;IAC9D,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,UAAU,CAAsB;IACxC,SAAS,CAAC,aAAa,gBAAyB;IAChD,OAAO,CAAC,QAAQ,CAAuB;IAEb,cAAc,EAAG,oBAAoB,CAAC;IACpC,gBAAgB,EAAG,sBAAsB,CAAC;IAItE,4CAA4C;IACnC,WAAW,SAAe;IAEnC,0DAA0D;IACjD,gBAAgB,UAAQ;IAEjC,sDAAsD;IAC7C,UAAU,SAAO;IAE1B,8DAA8D;IACrD,cAAc,SAAK;IAE5B,gEAAgE;IACvD,iBAAiB,SAAK;IAE/B,sDAAsD;IAC7C,aAAa,UAAQ;IAE9B,gDAAgD;IACvC,YAAY,UAAQ;IAE7B;;;;;OAKG;IACM,mBAAmB,UAAQ;IAIpC,kEAAkE;IACxD,cAAc,iCAAwC;IAEhE,mFAAmF;IACzE,eAAe,uBAA8B;IAEvD,uDAAuD;IAC7C,eAAe,uBAA8B;IAIhD,KAAK,SAAM;IACX,aAAa,UAAS;IAE7B,yEAAyE;IACzE,IAAW,mBAAmB,IAAI,MAAM,CAEvC;IACM,cAAc,EAAE,gBAAgB,EAAE,CAAM;IACxC,cAAc,EAAE,YAAY,EAAE,CAAM;IACpC,iBAAiB,SAAK;IACtB,gBAAgB,UAAS;IAChC,OAAO,CAAC,oBAAoB,CAAK;IAEjC;;;OAGG;IACI,eAAe,EAAE,eAAe,EAAE,CAAM;IAE/C,qFAAqF;IAC9E,SAAS,EAAE,OAAO,CAAS;IAElC;;;;OAIG;IACI,gBAAgB,EAAE,MAAM,EAAE,CAAM;IAEvC,QAAQ,IAAI,IAAI;IAShB,WAAW,IAAI,IAAI;IAQnB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI;IAU5C,aAAa,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAuBzC,oDAAoD;IAC7C,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAYzC,sCAAsC;IAC/B,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAazC,yBAAyB;IAClB,cAAc,IAAI,IAAI;IAI7B,uCAAuC;IAChC,cAAc,IAAI,IAAI;IAM7B,2BAA2B;IACpB,cAAc,IAAI,IAAI;IAM7B,oDAAoD;IAC7C,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAKvD,qCAAqC;IAC9B,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAM5C,6BAA6B;IACtB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAK7C,qCAAqC;IAC9B,sBAAsB,IAAI,IAAI;IAIrC;;;;OAIG;IACI,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI;IAMvD,OAAO,CAAC,WAAW;IAMnB,OAAO,CAAC,YAAY;IAMpB,OAAO,CAAC,yBAAyB;IASjC,OAAO,CAAC,iBAAiB;YAkBX,oBAAoB;IAyBlC,OAAO,CAAC,mBAAmB;yCArRlB,wBAAwB;2CAAxB,wBAAwB;CA0RpC"}