@salesforcedevs/dx-components 1.28.6 → 1.28.7-alpha.1
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforcedevs/dx-components",
|
|
3
|
-
"version": "1.28.
|
|
3
|
+
"version": "1.28.7-alpha.1",
|
|
4
4
|
"description": "DX Lightning web components",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"engines": {
|
|
@@ -44,5 +44,5 @@
|
|
|
44
44
|
"luxon": "3.4.4",
|
|
45
45
|
"msw": "^2.12.4"
|
|
46
46
|
},
|
|
47
|
-
"gitHead": "
|
|
47
|
+
"gitHead": "3782e0f52d705901c7307ba5751d1c3297f7ca25"
|
|
48
48
|
}
|
|
@@ -48,10 +48,6 @@
|
|
|
48
48
|
<dx-sidebar-search
|
|
49
49
|
onchange={onSearchChange}
|
|
50
50
|
onloading={onSearchLoading}
|
|
51
|
-
coveo-organization-id={coveoOrganizationId}
|
|
52
|
-
coveo-public-access-token={coveoPublicAccessToken}
|
|
53
|
-
coveo-search-hub={coveoSearchHub}
|
|
54
|
-
coveo-advanced-query-config={coveoAdvancedQueryConfig}
|
|
55
51
|
></dx-sidebar-search>
|
|
56
52
|
</div>
|
|
57
53
|
<slot name="version-picker"></slot>
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import cx from "classnames";
|
|
2
2
|
import { api, track } from "lwc";
|
|
3
3
|
import { TreeNode, SidebarSearchResult } from "typings/custom";
|
|
4
|
-
import { getSidebarSearchParams } from "dxUtils/coveo";
|
|
5
4
|
import { toJson } from "dxUtils/normalizers";
|
|
6
5
|
import SidebarSearch from "dx/sidebarSearch";
|
|
7
6
|
import { SidebarBase } from "dxBaseElements/sidebarBase";
|
|
8
7
|
|
|
9
8
|
const MOBILE_SIZE_MATCH = "768px";
|
|
10
9
|
|
|
10
|
+
const getSearchQueryParam = (): string | null =>
|
|
11
|
+
typeof window !== "undefined"
|
|
12
|
+
? new URLSearchParams(window.location.search).get("q")
|
|
13
|
+
: null;
|
|
14
|
+
|
|
11
15
|
export default class Sidebar extends SidebarBase {
|
|
12
|
-
@api coveoOrganizationId!: string;
|
|
13
|
-
@api coveoPublicAccessToken!: string;
|
|
14
|
-
@api coveoSearchHub!: string;
|
|
15
|
-
@api coveoAdvancedQueryConfig!: string;
|
|
16
16
|
@api header: string = "";
|
|
17
17
|
|
|
18
18
|
@api
|
|
@@ -130,7 +130,7 @@ export default class Sidebar extends SidebarBase {
|
|
|
130
130
|
constructor() {
|
|
131
131
|
super();
|
|
132
132
|
|
|
133
|
-
if (
|
|
133
|
+
if (getSearchQueryParam()) {
|
|
134
134
|
this.isSearchLoading = true;
|
|
135
135
|
this.scrollToSelectedSearchResult = true;
|
|
136
136
|
}
|
|
@@ -175,7 +175,7 @@ export default class Sidebar extends SidebarBase {
|
|
|
175
175
|
this.isSearchLoading = e.detail;
|
|
176
176
|
}
|
|
177
177
|
|
|
178
|
-
private onSidebarSearchContentScroll(scrollEvent) {
|
|
178
|
+
private onSidebarSearchContentScroll(scrollEvent: Event) {
|
|
179
179
|
if (this.isSearchLoading) {
|
|
180
180
|
return;
|
|
181
181
|
}
|
|
@@ -1,75 +1,45 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
2
|
import debounce from "debounce";
|
|
3
|
-
import {
|
|
4
|
-
Result,
|
|
5
|
-
ResultList,
|
|
6
|
-
Unsubscribe,
|
|
7
|
-
ResultsPerPage,
|
|
8
|
-
SearchBox,
|
|
9
|
-
buildInteractiveResult,
|
|
10
|
-
buildResultList,
|
|
11
|
-
buildResultsPerPage,
|
|
12
|
-
buildSearchBox,
|
|
13
|
-
loadAdvancedSearchQueryActions,
|
|
14
|
-
SearchEngine,
|
|
15
|
-
SearchAppState,
|
|
16
|
-
loadQueryActions
|
|
17
|
-
} from "@coveo/headless";
|
|
18
|
-
import { buildSearchEngine, getSidebarSearchParams } from "dxUtils/coveo";
|
|
19
3
|
import { RecentSearches } from "dxUtils/recentSearches";
|
|
20
|
-
import { toJson } from "dxUtils/normalizers";
|
|
21
4
|
import {
|
|
22
5
|
Option,
|
|
23
6
|
PopoverRequestCloseType,
|
|
24
7
|
SidebarSearchResult
|
|
25
8
|
} from "typings/custom";
|
|
26
9
|
|
|
27
|
-
const RESULT_CLICK_LOCAL_STORAGE_KEY = "dx-sidebar-search-result-click";
|
|
28
|
-
export const SESSION_KEY = "dx-sidebar-search-state";
|
|
29
|
-
|
|
30
|
-
const DEFAULT_RESULT_COUNT = 20;
|
|
31
10
|
const SEARCH_DEBOUNCE_DELAY = 1200;
|
|
11
|
+
const DATA_CLOUD_SEARCH_PATH = "/data-cloud-search/search";
|
|
12
|
+
|
|
13
|
+
/** Origin used for Data Cloud search (always production so results point to developer.salesforce.com). */
|
|
14
|
+
const DATA_CLOUD_SEARCH_ORIGIN = "https://developer.salesforce.com";
|
|
32
15
|
|
|
33
16
|
const UserRecentSearches = new RecentSearches();
|
|
34
17
|
|
|
35
|
-
const
|
|
36
|
-
|
|
18
|
+
const getSearchQueryParam = (): string =>
|
|
19
|
+
new URLSearchParams(window.location.search).get("q") ?? "";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Returns the base URL path for the current page, always using developer.salesforce.com.
|
|
23
|
+
* e.g. on QA or prod, path /docs/atlas.en-us.apexcode.meta/apexcode/apex_dev_guide.htm
|
|
24
|
+
* -> https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode
|
|
25
|
+
*/
|
|
26
|
+
const getBaseUrlPath = (): string => {
|
|
27
|
+
const url = DATA_CLOUD_SEARCH_ORIGIN + window.location.pathname;
|
|
28
|
+
const lastSlash = url.lastIndexOf("/");
|
|
29
|
+
return lastSlash > 0 ? url.substring(0, lastSlash) : url;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/** Data Cloud Search API result item (title, url, matchedText) */
|
|
33
|
+
interface DataCloudSearchResultItem {
|
|
34
|
+
title?: string;
|
|
35
|
+
url?: string;
|
|
36
|
+
matchedText?: string;
|
|
37
|
+
}
|
|
37
38
|
|
|
38
39
|
export default class SidebarSearch extends LightningElement {
|
|
39
|
-
@api coveoOrganizationId!: string;
|
|
40
|
-
@api coveoPublicAccessToken!: string;
|
|
41
|
-
@api coveoSearchHub!: string;
|
|
42
|
-
@api
|
|
43
|
-
get coveoAdvancedQueryConfig(): { [key: string]: any } {
|
|
44
|
-
return this._coveoAdvancedQueryConfig;
|
|
45
|
-
}
|
|
46
|
-
set coveoAdvancedQueryConfig(value) {
|
|
47
|
-
const jsonValue = toJson(value);
|
|
48
|
-
const hasChanged =
|
|
49
|
-
this._coveoAdvancedQueryConfig &&
|
|
50
|
-
Object.entries(jsonValue).some(
|
|
51
|
-
([key, val]: [string, any]) =>
|
|
52
|
-
this._coveoAdvancedQueryConfig[key] !== val
|
|
53
|
-
);
|
|
54
|
-
this._coveoAdvancedQueryConfig = jsonValue;
|
|
55
|
-
|
|
56
|
-
if (hasChanged && this.engine && this.value !== "") {
|
|
57
|
-
this.dispatchOnLoading(true);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (hasChanged && this.engine) {
|
|
61
|
-
// set advanced filters needs access to the latest coveoAdvancedQueryConfig
|
|
62
|
-
this.setAdvancedFilters(this.engine);
|
|
63
|
-
this.submitSearch(true);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
40
|
@api
|
|
68
41
|
public fetchMoreResults() {
|
|
69
|
-
|
|
70
|
-
this.fetchingMoreResults = true;
|
|
71
|
-
this.resultList.fetchMoreResults();
|
|
72
|
-
}
|
|
42
|
+
// Data Cloud Search API does not expose pagination in the same way; no-op
|
|
73
43
|
}
|
|
74
44
|
|
|
75
45
|
@api
|
|
@@ -85,313 +55,98 @@ export default class SidebarSearch extends LightningElement {
|
|
|
85
55
|
this.dropdownRequestedOpen = value;
|
|
86
56
|
}
|
|
87
57
|
|
|
88
|
-
private _coveoAdvancedQueryConfig!: { [key: string]: any };
|
|
89
58
|
private dropdownRequestedOpen: boolean = false;
|
|
90
59
|
private recentSearches: Option[] = [];
|
|
91
|
-
private
|
|
92
|
-
private resultList: ResultList | null = null;
|
|
93
|
-
private resultsPerPage: ResultsPerPage | null = null;
|
|
94
|
-
private preloadedState?: SearchAppState;
|
|
95
|
-
private searchBox: SearchBox | null = null;
|
|
96
|
-
private value?: string = "";
|
|
97
|
-
private engine: SearchEngine | null = null;
|
|
98
|
-
private fetchingMoreResults: boolean = false;
|
|
60
|
+
private value: string = "";
|
|
99
61
|
private didRender = false;
|
|
100
|
-
|
|
101
|
-
private get hasCorrectCoveoConfig(): boolean {
|
|
102
|
-
const coveoConfigurations = [
|
|
103
|
-
this.coveoOrganizationId,
|
|
104
|
-
this.coveoPublicAccessToken,
|
|
105
|
-
this.coveoSearchHub,
|
|
106
|
-
this.coveoAdvancedQueryConfig
|
|
107
|
-
];
|
|
108
|
-
|
|
109
|
-
return coveoConfigurations.every(
|
|
110
|
-
(val) =>
|
|
111
|
-
!!val && (typeof val === "string" || typeof val === "object")
|
|
112
|
-
);
|
|
113
|
-
}
|
|
62
|
+
private dataCloudSearchInitialized: boolean = false;
|
|
114
63
|
|
|
115
64
|
private get isDropdownOpen() {
|
|
116
65
|
return (
|
|
117
66
|
this.dropdownRequestedOpen &&
|
|
118
|
-
this.recentSearches &&
|
|
119
|
-
this.recentSearches.length > 0 &&
|
|
67
|
+
this.recentSearches?.length > 0 &&
|
|
120
68
|
!this.value
|
|
121
69
|
);
|
|
122
70
|
}
|
|
123
71
|
|
|
124
72
|
constructor() {
|
|
125
73
|
super();
|
|
126
|
-
|
|
127
74
|
this.updateRecentSearches();
|
|
128
|
-
this.value =
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
disconnectedCallback() {
|
|
132
|
-
this.unsubscribeFromResultList();
|
|
75
|
+
this.value = getSearchQueryParam();
|
|
133
76
|
}
|
|
134
77
|
|
|
135
78
|
renderedCallback() {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
this.initializeUserSession();
|
|
141
|
-
this.initializeCoveo();
|
|
142
|
-
} else if (!this.hasCorrectCoveoConfig) {
|
|
143
|
-
console.error(
|
|
144
|
-
"Incorrect coveo search configuration provided. All coveo configuration attributes must be defined.",
|
|
145
|
-
{
|
|
146
|
-
coveoOrganizationId: this.coveoOrganizationId,
|
|
147
|
-
coveoPublicAccessToken: this.coveoPublicAccessToken,
|
|
148
|
-
coveoSearchHub: this.coveoSearchHub,
|
|
149
|
-
coveoAdvancedQueryConfig: this.coveoAdvancedQueryConfig
|
|
150
|
-
}
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// If this is the first render and there is a search value, trigger
|
|
155
|
-
// term highlighting
|
|
156
|
-
if (!this.didRender && this.value) {
|
|
157
|
-
this.dispatchHighlightedTermChange();
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
this.didRender = true;
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
private initializeUserSession() {
|
|
164
|
-
const stringified = window.sessionStorage.getItem(SESSION_KEY);
|
|
165
|
-
|
|
166
|
-
if (!stringified) {
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
try {
|
|
171
|
-
const json = JSON.parse(stringified);
|
|
172
|
-
|
|
173
|
-
const hasSameConfig = Object.entries(
|
|
174
|
-
json.coveoAdvancedQueryConfig
|
|
175
|
-
).every(
|
|
176
|
-
([key, value]: [string, any]) =>
|
|
177
|
-
this.coveoAdvancedQueryConfig[key] === value
|
|
178
|
-
);
|
|
179
|
-
const hasSameQuery = json?.state?.query?.q === this.value;
|
|
180
|
-
|
|
181
|
-
if (hasSameConfig && hasSameQuery) {
|
|
182
|
-
this.preloadedState = json?.state;
|
|
183
|
-
} else {
|
|
184
|
-
window.sessionStorage.removeItem(SESSION_KEY);
|
|
79
|
+
if (!this.dataCloudSearchInitialized) {
|
|
80
|
+
this.dataCloudSearchInitialized = true;
|
|
81
|
+
if (!this.didRender && this.value) {
|
|
82
|
+
this.dispatchHighlightedTermChange();
|
|
185
83
|
}
|
|
186
|
-
|
|
187
|
-
console.error(e);
|
|
188
|
-
window.sessionStorage.removeItem(SESSION_KEY);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
private initializeCoveo = () => {
|
|
193
|
-
try {
|
|
194
|
-
this.engine = buildSearchEngine({
|
|
195
|
-
organizationId: this.coveoOrganizationId,
|
|
196
|
-
publicAccessToken: this.coveoPublicAccessToken,
|
|
197
|
-
searchHub: this.coveoSearchHub,
|
|
198
|
-
preloadedState: this.preloadedState
|
|
199
|
-
});
|
|
200
|
-
} catch (ex) {
|
|
201
|
-
console.error(`Coveo engine failed to initialize (${ex})`);
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (!this.engine) {
|
|
205
|
-
console.error("Coveo engine failed to initialize!");
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
if (this.preloadedState) {
|
|
210
|
-
const actions = loadQueryActions(this.engine);
|
|
211
|
-
this.engine.dispatch(actions.updateQuery({ q: this.value || "" }));
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
this.resultList = buildResultList(this.engine, {
|
|
215
|
-
options: { fieldsToInclude: ["sfhtml_url__c"] }
|
|
216
|
-
});
|
|
217
|
-
|
|
218
|
-
this.resultsPerPage = buildResultsPerPage(this.engine, {
|
|
219
|
-
initialState: {
|
|
220
|
-
numberOfResults: DEFAULT_RESULT_COUNT
|
|
221
|
-
}
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
this.searchBox = buildSearchBox(this.engine, {
|
|
225
|
-
options: { numberOfSuggestions: 3 }
|
|
226
|
-
});
|
|
227
|
-
|
|
228
|
-
this.setAdvancedFilters(this.engine);
|
|
229
|
-
|
|
230
|
-
this.unsubscribeFromResultList = this.resultList?.subscribe(
|
|
231
|
-
this.onResultListChange
|
|
232
|
-
);
|
|
233
|
-
|
|
234
|
-
if (this.value) {
|
|
235
|
-
this.dispatchHighlightedTermChange();
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (!this.preloadedState) {
|
|
239
|
-
if (this.value) {
|
|
240
|
-
this.submitSearch();
|
|
241
|
-
} else {
|
|
84
|
+
if (!this.value) {
|
|
242
85
|
this.dispatchOnLoading(false);
|
|
243
86
|
}
|
|
244
87
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
};
|
|
248
|
-
|
|
249
|
-
private syncAnalytics = () => {
|
|
250
|
-
const storedResult = window.localStorage.getItem(
|
|
251
|
-
RESULT_CLICK_LOCAL_STORAGE_KEY
|
|
252
|
-
);
|
|
253
|
-
if (storedResult) {
|
|
254
|
-
const interactiveResult = buildInteractiveResult(this.engine!, {
|
|
255
|
-
options: { result: JSON.parse(storedResult) }
|
|
256
|
-
});
|
|
257
|
-
interactiveResult.cancelPendingSelect();
|
|
258
|
-
interactiveResult.select();
|
|
259
|
-
window.localStorage.removeItem(RESULT_CLICK_LOCAL_STORAGE_KEY);
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
private onResultListChange = () => {
|
|
264
|
-
if (!this.resultList) {
|
|
265
|
-
return;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const { isLoading, firstSearchExecuted, results } =
|
|
269
|
-
this.resultList.state;
|
|
270
|
-
|
|
271
|
-
if ((!firstSearchExecuted && !isLoading) || !this.value) {
|
|
272
|
-
// coveo search is firing off some unwanted payloads on startup
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (!isLoading) {
|
|
277
|
-
this.dispatchOnChangeEvent(results);
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (!this.fetchingMoreResults) {
|
|
281
|
-
this.dispatchOnLoading(isLoading);
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (!isLoading && this.fetchingMoreResults) {
|
|
285
|
-
this.fetchingMoreResults = false;
|
|
88
|
+
if (!this.didRender && this.value) {
|
|
89
|
+
this.dispatchHighlightedTermChange();
|
|
286
90
|
}
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
private setAdvancedFilters(engine: SearchEngine) {
|
|
290
|
-
const aq = Object.entries(this.coveoAdvancedQueryConfig).reduce(
|
|
291
|
-
(result, [key, value]) =>
|
|
292
|
-
`${result}(@${key}=="${normalizeCoveoAdvancedQueryValue(
|
|
293
|
-
value
|
|
294
|
-
)}")`,
|
|
295
|
-
""
|
|
296
|
-
);
|
|
297
|
-
|
|
298
|
-
const registerSearchQueryAction = loadAdvancedSearchQueryActions(
|
|
299
|
-
engine
|
|
300
|
-
).registerAdvancedSearchQueries({
|
|
301
|
-
aq: aq
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
engine.dispatch(registerSearchQueryAction);
|
|
91
|
+
this.didRender = true;
|
|
305
92
|
}
|
|
306
93
|
|
|
307
|
-
private
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
// discussion about this normalization here: https://salesforce-internal.slack.com/archives/C020S6784JX/p1639506238376600
|
|
319
|
-
|
|
320
|
-
let pathname, queryParam;
|
|
321
|
-
if (sfhtml_url__c) {
|
|
322
|
-
pathname = `/docs/${sfhtml_url__c}`;
|
|
323
|
-
} else {
|
|
324
|
-
const isNestedGuide = clickUri.includes("/guide/");
|
|
325
|
-
const url = new URL(clickUri);
|
|
326
|
-
const extension =
|
|
327
|
-
isNestedGuide && !url.pathname?.endsWith(".html")
|
|
328
|
-
? ".html"
|
|
329
|
-
: "";
|
|
330
|
-
pathname = `${url.pathname}${extension}`;
|
|
331
|
-
queryParam = url.search;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
let href;
|
|
335
|
-
let isSelected = false;
|
|
336
|
-
const isReferenceUrl = clickUri.includes("/references/");
|
|
337
|
-
if (isReferenceUrl) {
|
|
338
|
-
if (queryParam) {
|
|
339
|
-
href = `${pathname}${queryParam}&q=${this.value}`;
|
|
340
|
-
} else {
|
|
341
|
-
href = `${pathname}?q=${this.value}`;
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
//NOTE: This is specific to references related comparison
|
|
345
|
-
const resultHrefWithMetaQuery = `${pathname}${queryParam}`;
|
|
346
|
-
|
|
347
|
-
const urlParams = new URLSearchParams(window.location.search);
|
|
348
|
-
const metaQueryParam = urlParams.get("meta");
|
|
349
|
-
|
|
350
|
-
let currentUrlPathWithQuery = window.location.pathname;
|
|
351
|
-
if (metaQueryParam) {
|
|
352
|
-
currentUrlPathWithQuery = `${currentUrlPathWithQuery}?meta=${metaQueryParam}`;
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
isSelected = resultHrefWithMetaQuery === currentUrlPathWithQuery;
|
|
356
|
-
} else {
|
|
357
|
-
href = `${pathname}?q=${this.value}`;
|
|
358
|
-
isSelected = pathname === window.location.pathname;
|
|
359
|
-
}
|
|
360
|
-
|
|
94
|
+
private normalizeDataCloudResult = (
|
|
95
|
+
item: DataCloudSearchResultItem,
|
|
96
|
+
index: number
|
|
97
|
+
): SidebarSearchResult => {
|
|
98
|
+
const href = item.url ?? "";
|
|
99
|
+
const resultPath = href.startsWith("http")
|
|
100
|
+
? new URL(href).pathname
|
|
101
|
+
: href;
|
|
102
|
+
const isSelected =
|
|
103
|
+
!!resultPath && resultPath === window.location.pathname;
|
|
361
104
|
return {
|
|
362
|
-
title,
|
|
363
|
-
titleHighlights,
|
|
364
|
-
excerpt,
|
|
365
|
-
excerptHighlights,
|
|
366
|
-
uniqueId
|
|
105
|
+
title: item.title ?? "",
|
|
106
|
+
titleHighlights: [],
|
|
107
|
+
excerpt: item.matchedText ?? "",
|
|
108
|
+
excerptHighlights: [],
|
|
109
|
+
uniqueId: href || `result-${index}`,
|
|
367
110
|
href,
|
|
368
111
|
selected: isSelected,
|
|
369
|
-
select: () =>
|
|
370
|
-
window.localStorage.setItem(
|
|
371
|
-
RESULT_CLICK_LOCAL_STORAGE_KEY,
|
|
372
|
-
JSON.stringify(result)
|
|
373
|
-
)
|
|
112
|
+
select: () => {}
|
|
374
113
|
};
|
|
375
114
|
};
|
|
376
115
|
|
|
377
|
-
private
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
116
|
+
private async fetchDataCloudSearch(): Promise<void> {
|
|
117
|
+
const body = {
|
|
118
|
+
searchQuery: this.value.trim(),
|
|
119
|
+
baseUrlPath: getBaseUrlPath()
|
|
120
|
+
};
|
|
121
|
+
try {
|
|
122
|
+
const res = await fetch(DATA_CLOUD_SEARCH_PATH, {
|
|
123
|
+
method: "POST",
|
|
124
|
+
headers: { "Content-Type": "application/json" },
|
|
125
|
+
body: JSON.stringify(body)
|
|
126
|
+
});
|
|
127
|
+
if (!res.ok) {
|
|
128
|
+
throw new Error(`Search API error: ${res.status}`);
|
|
129
|
+
}
|
|
130
|
+
const data = await res.json();
|
|
131
|
+
const rawResults: DataCloudSearchResultItem[] = Array.isArray(data)
|
|
132
|
+
? data
|
|
133
|
+
: data?.results ?? data?.data?.results ?? [];
|
|
134
|
+
const results: SidebarSearchResult[] = rawResults.map(
|
|
135
|
+
this.normalizeDataCloudResult
|
|
136
|
+
);
|
|
137
|
+
this.dispatchChange(results);
|
|
138
|
+
} catch (err) {
|
|
139
|
+
console.error("Data Cloud Search request failed", err);
|
|
140
|
+
this.dispatchChange([]);
|
|
141
|
+
} finally {
|
|
142
|
+
this.dispatchOnLoading(false);
|
|
143
|
+
}
|
|
385
144
|
}
|
|
386
145
|
|
|
387
|
-
private
|
|
388
|
-
this.updateSessionStorage();
|
|
146
|
+
private dispatchChange(results: SidebarSearchResult[]) {
|
|
389
147
|
this.dispatchEvent(
|
|
390
148
|
new CustomEvent("change", {
|
|
391
|
-
detail: {
|
|
392
|
-
results: results.map(this.normalizeCoveoResult),
|
|
393
|
-
value: this.value
|
|
394
|
-
}
|
|
149
|
+
detail: { results, value: this.value }
|
|
395
150
|
})
|
|
396
151
|
);
|
|
397
152
|
}
|
|
@@ -427,19 +182,12 @@ export default class SidebarSearch extends LightningElement {
|
|
|
427
182
|
}
|
|
428
183
|
|
|
429
184
|
private submitSearch = debounce((isSyncingSearchValue = false) => {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
// When `isSyncingSearchValue` is true, we are submitting in a case
|
|
435
|
-
// where the search box is already synced correctly.
|
|
436
|
-
if (!isSyncingSearchValue) {
|
|
437
|
-
this.dispatchSidebarSearchChange(this.value);
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
this.searchBox.updateText(this.value || "");
|
|
441
|
-
this.searchBox.submit();
|
|
185
|
+
UserRecentSearches.add(this.value);
|
|
186
|
+
this.updateRecentSearches();
|
|
187
|
+
if (!isSyncingSearchValue) {
|
|
188
|
+
this.dispatchSidebarSearchChange(this.value);
|
|
442
189
|
}
|
|
190
|
+
this.fetchDataCloudSearch();
|
|
443
191
|
}, SEARCH_DEBOUNCE_DELAY);
|
|
444
192
|
|
|
445
193
|
private onClickRecentSearch(e: CustomEvent) {
|
|
@@ -461,7 +209,6 @@ export default class SidebarSearch extends LightningElement {
|
|
|
461
209
|
|
|
462
210
|
private onInputChange(e: CustomEvent) {
|
|
463
211
|
this.value = e.detail;
|
|
464
|
-
|
|
465
212
|
this.handleValueChange(false);
|
|
466
213
|
this.dispatchHighlightedTermChange();
|
|
467
214
|
}
|
|
@@ -477,16 +224,10 @@ export default class SidebarSearch extends LightningElement {
|
|
|
477
224
|
private handleValueChange(isSyncingSearchValue = false) {
|
|
478
225
|
if (this.value) {
|
|
479
226
|
this.dispatchOnLoading(true);
|
|
480
|
-
|
|
481
|
-
this.submitSearch(isSyncingSearchValue);
|
|
482
|
-
}
|
|
227
|
+
this.submitSearch(isSyncingSearchValue);
|
|
483
228
|
} else {
|
|
484
|
-
// coveo's reaction to an empty value triggers a return of results
|
|
485
|
-
// bootlegging our own ux here`
|
|
486
229
|
this.dispatchOnLoading(false);
|
|
487
|
-
this.
|
|
488
|
-
// Empty search values are not submitted for search, so we need to manually
|
|
489
|
-
// trigger a search change on our own here
|
|
230
|
+
this.dispatchChange([]);
|
|
490
231
|
this.dispatchSidebarSearchChange(this.value);
|
|
491
232
|
}
|
|
492
233
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
2
|
import cx from "classnames";
|
|
3
|
-
import {
|
|
3
|
+
import { HighlightedSections } from "typings/custom";
|
|
4
4
|
|
|
5
|
-
const toChunks = (value: string, highlights:
|
|
5
|
+
const toChunks = (value: string, highlights: HighlightedSections) => {
|
|
6
6
|
if (!highlights || highlights.length < 1) {
|
|
7
7
|
return [
|
|
8
8
|
{
|
|
@@ -51,11 +51,11 @@ const toChunks = (value: string, highlights: CoveoHighlights) => {
|
|
|
51
51
|
|
|
52
52
|
export default class SidebarSearchResult extends LightningElement {
|
|
53
53
|
@api description!: string;
|
|
54
|
-
@api descriptionHighlights!:
|
|
54
|
+
@api descriptionHighlights!: HighlightedSections;
|
|
55
55
|
@api href!: string;
|
|
56
56
|
@api selected!: boolean;
|
|
57
57
|
@api header!: string;
|
|
58
|
-
@api titleHighlights!:
|
|
58
|
+
@api titleHighlights!: HighlightedSections;
|
|
59
59
|
@api select!: Function;
|
|
60
60
|
|
|
61
61
|
private get titleChunks() {
|