@fluid-topics/ft-search-context 1.2.21 → 1.2.22

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.
@@ -1,7 +1,7 @@
1
1
  import { FtSearchPageState } from "./model";
2
- import { FtReduxStore } from "@fluid-topics/ft-wc-utils";
2
+ import { FtReduxStore, ReduxWatcher } from "@fluid-topics/ft-wc-utils";
3
3
  import { FtSearchPageStateReducers } from "./redux";
4
- import { FtDateFilterTypeKeys, FtMetadataFilter, FtPublicClusterSortCriterion, FtSearchRequest, FtSearchScope, FtSearchSortCriterion, FtVirtualField } from "@fluid-topics/public-api";
4
+ import { FtDateFilterTypeKeys, FtMetadataFilter, FtPublicClusterSortCriterion, FtSearchRequest, FtSearchScope, FtSearchSortCriterion, FtSuggestRequest, FtVirtualField } from "@fluid-topics/public-api";
5
5
  import { FtSearchService } from "./utils/FtSearchService";
6
6
  export declare const searchInDocumentTitlesOnlySelector: (s: FtSearchPageState) => boolean;
7
7
  export declare class ClearAllFiltersEvent extends Event {
@@ -9,12 +9,14 @@ export declare class ClearAllFiltersEvent extends Event {
9
9
  constructor();
10
10
  }
11
11
  export declare class FtSearchStateManager {
12
- store: FtReduxStore<FtSearchPageState, FtSearchPageStateReducers>;
12
+ readonly store: FtReduxStore<FtSearchPageState, FtSearchPageStateReducers>;
13
13
  static build(id: string, service?: FtSearchService): FtSearchStateManager;
14
- service: FtSearchService;
14
+ readonly service: FtSearchService;
15
15
  errorHandler?: (e: Error) => void;
16
16
  ignoreEmptyQuery: boolean;
17
17
  openExternalDocumentInNewTab: boolean;
18
+ protected readonly searchWatcher: ReduxWatcher<FtSearchPageState, FtSearchRequest>;
19
+ protected readonly suggestWatcher: ReduxWatcher<FtSearchPageState, FtSuggestRequest>;
18
20
  constructor(store: FtReduxStore<FtSearchPageState, FtSearchPageStateReducers>, service?: FtSearchService);
19
21
  initService(): Promise<boolean>;
20
22
  setQuery(query: string): void;
@@ -49,11 +51,13 @@ export declare class FtSearchStateManager {
49
51
  private localesDebouncer;
50
52
  updateLocales(): Promise<boolean>;
51
53
  private searchDebouncer;
52
- launchSearch(): Promise<boolean>;
53
- private suggestDebouncer;
54
- launchSuggest(): Promise<boolean>;
54
+ launchSearch: (request?: FtSearchRequest) => Promise<boolean>;
55
+ private buildSearchRequest;
55
56
  private cancelableSearch;
56
57
  private fetchSearchData;
58
+ private suggestDebouncer;
59
+ launchSuggest: (request?: FtSuggestRequest) => Promise<boolean>;
60
+ private buildSuggestRequest;
57
61
  private cancelableSuggest;
58
62
  private fetchSuggestData;
59
63
  clear(): void;
@@ -1,4 +1,4 @@
1
- import { cancelable, CanceledPromiseError, Debouncer } from "@fluid-topics/ft-wc-utils";
1
+ import { cancelable, CanceledPromiseError, Debouncer, watch } from "@fluid-topics/ft-wc-utils";
2
2
  import { createSearchPageStore } from "./redux";
3
3
  import { FtSearchScope, FtVirtualField } from "@fluid-topics/public-api";
4
4
  import { FtSearchService } from "./utils/FtSearchService";
@@ -21,13 +21,36 @@ export class FtSearchStateManager {
21
21
  this.openExternalDocumentInNewTab = false;
22
22
  this.localesDebouncer = new Debouncer(10);
23
23
  this.searchDebouncer = new Debouncer(100);
24
+ this.launchSearch = (request) => {
25
+ return this.searchDebouncer.run(() => this.fetchSearchData(request !== null && request !== void 0 ? request : this.buildSearchRequest(this.store.getState())));
26
+ };
27
+ this.buildSearchRequest = (state) => {
28
+ return {
29
+ ...state.request,
30
+ facets: this.facetIds.map(id => ({ id })),
31
+ };
32
+ };
24
33
  this.suggestDebouncer = new Debouncer(300);
34
+ this.launchSuggest = (request) => {
35
+ return this.suggestDebouncer.run(() => this.fetchSuggestData(request !== null && request !== void 0 ? request : this.buildSuggestRequest(this.store.getState())));
36
+ };
37
+ this.buildSuggestRequest = (state) => {
38
+ return {
39
+ input: state.liveQuery,
40
+ metadataFilters: state.request.metadataFilters,
41
+ sort: state.request.sort,
42
+ contentLocale: state.request.contentLocale,
43
+ scope: state.request.scope,
44
+ };
45
+ };
25
46
  this.service = service !== null && service !== void 0 ? service : new FtSearchService();
26
47
  this.service.cache.addEventListener("clear-cache", (e) => {
27
48
  if (e.detail.clearedKeys.includes("available-locales")) {
28
49
  this.updateLocales();
29
50
  }
30
51
  });
52
+ this.searchWatcher = watch(store, this.buildSearchRequest, this.launchSearch);
53
+ this.suggestWatcher = watch(store, this.buildSuggestRequest, this.launchSuggest);
31
54
  }
32
55
  async initService() {
33
56
  this.updateLocales();
@@ -37,7 +60,6 @@ export class FtSearchStateManager {
37
60
  this.store.actions.setRequestQuery(query);
38
61
  this.store.actions.liveQuery(query);
39
62
  this.store.actions.setPageNumber(1);
40
- this.launchSearch();
41
63
  }
42
64
  setContentLocale(contentLocale) {
43
65
  var _a;
@@ -53,36 +75,29 @@ export class FtSearchStateManager {
53
75
  this.store.actions.setRequestContentLocale(contentLocale);
54
76
  this.store.actions.setPageNumber(1);
55
77
  this.store.actions.setRequestFilters([]);
56
- this.launchSearch();
57
78
  }
58
79
  return contentLocale;
59
80
  }
60
81
  forceContentLocale(contentLocale) {
61
82
  this.store.actions.setRequestContentLocale(contentLocale);
62
- this.launchSearch();
63
83
  }
64
84
  setPageSize(pageSize) {
65
85
  this.store.actions.setPageSize(pageSize);
66
- this.launchSearch();
67
86
  }
68
87
  setPageNumber(pageNumber) {
69
88
  this.store.actions.setPageNumber(pageNumber);
70
- this.launchSearch();
71
89
  }
72
90
  setSort(sort) {
73
91
  this.store.actions.setRequestSort(sort);
74
92
  this.store.actions.setPageNumber(1);
75
- this.launchSearch();
76
93
  }
77
94
  setFilters(filters) {
78
95
  const cleanFilters = filters.filter(f => !f.valueFilter || f.valueFilter.values.length > 0);
79
96
  this.store.actions.setRequestFilters(cleanFilters);
80
97
  this.store.actions.setPageNumber(1);
81
- this.launchSearch();
82
98
  }
83
99
  setClusterSortCriterion(criterions) {
84
100
  this.store.actions.setRequestClusterSortCriterion(criterions);
85
- this.launchSearch();
86
101
  }
87
102
  setSearchInDocumentTitlesOnly(searchInDocumentTitleOnly) {
88
103
  if (searchInDocumentTitleOnly) {
@@ -93,11 +108,9 @@ export class FtSearchStateManager {
93
108
  this.store.actions.setRequestVirtualField(FtVirtualField.EVERYWHERE);
94
109
  this.store.actions.setRequestScope(FtSearchScope.DEFAULT);
95
110
  }
96
- this.launchSearch();
97
111
  }
98
112
  setVirtualField(virtualField) {
99
113
  this.store.actions.setRequestVirtualField(virtualField);
100
- this.launchSearch();
101
114
  }
102
115
  get searchInDocumentTitlesOnly() {
103
116
  return searchInDocumentTitlesOnlySelector(this.store.getState());
@@ -109,7 +122,6 @@ export class FtSearchStateManager {
109
122
  }
110
123
  addFacet(id) {
111
124
  this.facetIds = [...this.facetIds, id];
112
- this.launchSearch();
113
125
  }
114
126
  replaceFacet(oldId, newId) {
115
127
  let facetIds = this.facetIds.filter(id => id != oldId);
@@ -117,7 +129,6 @@ export class FtSearchStateManager {
117
129
  facetIds.push(newId);
118
130
  }
119
131
  this.facetIds = facetIds;
120
- this.launchSearch();
121
132
  }
122
133
  get facetIds() {
123
134
  var _a;
@@ -203,7 +214,6 @@ export class FtSearchStateManager {
203
214
  }
204
215
  setLiveQuery(query) {
205
216
  this.store.actions.liveQuery(query);
206
- this.launchSuggest();
207
217
  }
208
218
  setRequest(request) {
209
219
  this.store.actions.setRequest({
@@ -212,18 +222,15 @@ export class FtSearchStateManager {
212
222
  });
213
223
  this.store.actions.liveQuery(request.query);
214
224
  this.store.actions.setPageNumber(1);
215
- this.launchSearch();
216
225
  }
217
226
  setScope(scope) {
218
227
  this.store.actions.setRequestScope(scope);
219
- this.launchSearch();
220
228
  }
221
229
  setOtherQueryParams(params) {
222
230
  this.store.actions.setOtherQueryParams(params);
223
231
  }
224
232
  setIgnoreEmptyQuery(ignoreEmptyQuery) {
225
233
  this.ignoreEmptyQuery = ignoreEmptyQuery;
226
- this.launchSearch();
227
234
  }
228
235
  setOpenExternalDocumentInNewTab(openExternalDocumentInNewTab) {
229
236
  this.openExternalDocumentInNewTab = openExternalDocumentInNewTab;
@@ -231,21 +238,10 @@ export class FtSearchStateManager {
231
238
  updateLocales() {
232
239
  return this.localesDebouncer.run(async () => this.store.actions.locales((await this.service.getAvailableSearchLocales()).contentLocales));
233
240
  }
234
- launchSearch() {
235
- this.launchSuggest();
236
- return this.searchDebouncer.run(() => this.fetchSearchData());
237
- }
238
- launchSuggest() {
239
- return this.suggestDebouncer.run(() => this.fetchSuggestData());
240
- }
241
- async fetchSearchData() {
241
+ async fetchSearchData(request) {
242
242
  var _a, _b;
243
243
  try {
244
244
  (_a = this.cancelableSearch) === null || _a === void 0 ? void 0 : _a.cancel();
245
- let request = {
246
- ...this.store.getState().request,
247
- facets: this.facetIds.map(id => ({ id })),
248
- };
249
245
  this.store.actions.paging(undefined);
250
246
  if (this.ignoreEmptyQuery && request.query.length == 0) {
251
247
  this.store.actions.results(undefined);
@@ -273,18 +269,9 @@ export class FtSearchStateManager {
273
269
  }
274
270
  }
275
271
  }
276
- async fetchSuggestData() {
272
+ async fetchSuggestData(request) {
277
273
  var _a;
278
274
  try {
279
- const searchState = this.store.getState();
280
- const searchRequest = searchState.request;
281
- const request = {
282
- input: searchState.liveQuery,
283
- metadataFilters: searchRequest.metadataFilters,
284
- sort: searchRequest.sort,
285
- contentLocale: searchRequest.contentLocale,
286
- scope: searchRequest.scope,
287
- };
288
275
  (_a = this.cancelableSuggest) === null || _a === void 0 ? void 0 : _a.cancel();
289
276
  this.cancelableSuggest = cancelable(this.service.launchSuggest(request));
290
277
  let results = await this.cancelableSuggest;
@@ -1,8 +1,11 @@
1
- import type { FtSearchLocales, FtSearchRequest, FtSearchResults, FtSuggestRequest, FtSuggestResults } from "@fluid-topics/public-api";
1
+ import { type FluidTopicsApi, FtSearchLocales, FtSearchRequest, FtSearchResults, FtSuggestRequest, FtSuggestResults } from "@fluid-topics/public-api";
2
2
  import { FtServiceWithCache } from "@fluid-topics/ft-app-context";
3
3
  export declare class FtSearchService extends FtServiceWithCache {
4
+ constructor(overrideApi?: FluidTopicsApi);
4
5
  launchSearch(request: FtSearchRequest): Promise<FtSearchResults>;
5
6
  launchSuggest(request: FtSuggestRequest): Promise<FtSuggestResults>;
6
7
  getAvailableSearchLocales(): Promise<FtSearchLocales>;
8
+ private sortFilters;
9
+ private sortObjectFields;
7
10
  hash(object: any): string;
8
11
  }
@@ -1,15 +1,46 @@
1
1
  import { FtServiceWithCache } from "@fluid-topics/ft-app-context";
2
2
  export class FtSearchService extends FtServiceWithCache {
3
+ constructor(overrideApi) {
4
+ super(true, overrideApi);
5
+ this.sortObjectFields = (_, value) => {
6
+ if (typeof value !== "object" || value == null || Array.isArray(value)) {
7
+ return value;
8
+ }
9
+ return Object.fromEntries(Object.entries(value)
10
+ .sort(([ka], [kb]) => ka.localeCompare(kb)));
11
+ };
12
+ }
3
13
  async launchSearch(request) {
4
- return this.cache.get(this.hash(request), async () => (await this.awaitApi).search(request), 2 * 60 * 1000);
14
+ const sortedRequest = {
15
+ ...request,
16
+ metadataFilters: this.sortFilters(request.metadataFilters),
17
+ facets: [...request.facets].sort((a, b) => a.id.localeCompare(b.id)),
18
+ };
19
+ return this.cache.get(this.hash(sortedRequest), async () => (await this.awaitApi).search(request), 2 * 60 * 1000);
5
20
  }
6
21
  async launchSuggest(request) {
7
- return this.cache.get(this.hash(request), async () => (await this.awaitApi).getSuggestions(request), 2 * 60 * 1000);
22
+ const sortedRequest = {
23
+ ...request,
24
+ metadataFilters: this.sortFilters(request.metadataFilters)
25
+ };
26
+ return this.cache.get(this.hash(sortedRequest), async () => (await this.awaitApi).getSuggestions(request), 2 * 60 * 1000);
8
27
  }
9
28
  async getAvailableSearchLocales() {
10
29
  return this.cache.get("available-locales", async () => (await this.awaitApi).getAvailableSearchLocales());
11
30
  }
31
+ sortFilters(filters) {
32
+ return filters
33
+ .map(f => f.valueFilter == null ? f : {
34
+ ...f,
35
+ valueFilter: {
36
+ ...f.valueFilter,
37
+ values: f.valueFilter.values.sort((a, b) => a.localeCompare(b))
38
+ }
39
+ })
40
+ .sort((a, b) => a.key.localeCompare(b.key));
41
+ }
12
42
  hash(object) {
13
- return "" + Array.from(JSON.stringify(object)).reduce((hash, char) => 0 | (31 * hash + char.charCodeAt(0)), 0);
43
+ return String(Array.from(JSON.stringify(object, this.sortObjectFields))
44
+ .reduce((hash, char) => 0 | (31 * hash + char.charCodeAt(0)), 0));
14
45
  }
15
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluid-topics/ft-search-context",
3
- "version": "1.2.21",
3
+ "version": "1.2.22",
4
4
  "description": "Context block for integrated search components",
5
5
  "keywords": [
6
6
  "Lit"
@@ -19,12 +19,12 @@
19
19
  "url": "ssh://git@scm.mrs.antidot.net:2222/fluidtopics/ft-web-components.git"
20
20
  },
21
21
  "dependencies": {
22
- "@fluid-topics/ft-app-context": "1.2.21",
23
- "@fluid-topics/ft-wc-utils": "1.2.21",
22
+ "@fluid-topics/ft-app-context": "1.2.22",
23
+ "@fluid-topics/ft-wc-utils": "1.2.22",
24
24
  "lit": "3.1.0"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@fluid-topics/public-api": "1.0.82"
28
28
  },
29
- "gitHead": "d5ad6e93693f963ea69c3ee8aed39f9c6f0d569a"
29
+ "gitHead": "29f6269b3af8af4c82f5ab2228d52b493ac3ddea"
30
30
  }