@salesforcedevs/dx-components 1.32.0-alpha.8 → 1.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lwc.config.json +1 -1
- package/package.json +3 -3
- package/src/modules/dx/agentMiawUi/agentMiawUi.css +4 -0
- package/src/modules/dx/agentMiawUi/agentMiawUi.html +3 -0
- package/src/modules/dx/agentMiawUi/agentMiawUi.ts +167 -0
- package/src/modules/dx/codeBlock/codeBlock.css +7 -0
- package/src/modules/dx/dropdownOption/dropdownOption.css +8 -13
- package/src/modules/dx/footer/footer.ts +55 -32
- package/src/modules/dx/globalHeader/globalHeader.html +2 -2
- package/src/modules/dx/globalHeader/globalHeader.ts +40 -30
- package/src/modules/dx/searchResults/searchResults.css +6 -105
- package/src/modules/dx/searchResults/searchResults.html +91 -87
- package/src/modules/dx/searchResults/searchResults.ts +477 -174
- package/src/modules/dx/sidebar/sidebar.css +0 -1
- package/src/modules/dx/sidebar/sidebar.html +5 -1
- package/src/modules/dx/sidebar/sidebar.ts +29 -44
- package/src/modules/dx/sidebarSearch/sidebarSearch.ts +343 -159
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.css +25 -43
- package/src/modules/dx/sidebarSearchResult/sidebarSearchResult.ts +4 -12
- package/src/modules/dx/tree/treeHandler.ts +2 -1
- package/src/modules/dx/treeTile/treeTile.css +4 -0
- package/src/modules/dx/treeTile/treeTile.html +10 -0
- package/src/modules/dx/treeTile/treeTile.ts +4 -0
- package/src/modules/dxUtils/async/async.ts +32 -0
- package/src/modules/dxUtils/data360Search/data360Search.ts +0 -168
|
@@ -1,71 +1,75 @@
|
|
|
1
1
|
import { LightningElement, api } from "lwc";
|
|
2
2
|
import debounce from "debounce";
|
|
3
|
-
import { track as trackGTM } from "dxUtils/analytics";
|
|
4
3
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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";
|
|
14
19
|
import { RecentSearches } from "dxUtils/recentSearches";
|
|
20
|
+
import { toJson } from "dxUtils/normalizers";
|
|
15
21
|
import {
|
|
16
|
-
type HighlightedSections,
|
|
17
22
|
Option,
|
|
18
23
|
PopoverRequestCloseType,
|
|
19
24
|
SidebarSearchResult
|
|
20
25
|
} from "typings/custom";
|
|
21
26
|
|
|
22
|
-
const
|
|
27
|
+
const RESULT_CLICK_LOCAL_STORAGE_KEY = "dx-sidebar-search-result-click";
|
|
28
|
+
export const SESSION_KEY = "dx-sidebar-search-state";
|
|
23
29
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
* Uses the same regex as the full-doc highlighter (createSearchRegExp) so sidebar
|
|
27
|
-
* and doc highlight the same phrases (including spaces between words).
|
|
28
|
-
*/
|
|
29
|
-
function getHighlightRanges(
|
|
30
|
-
text: string,
|
|
31
|
-
searchQuery: string
|
|
32
|
-
): HighlightedSections {
|
|
33
|
-
if (!text || !searchQuery.trim()) {
|
|
34
|
-
return [];
|
|
35
|
-
}
|
|
36
|
-
const re = createSearchRegExp(searchQuery.trim());
|
|
37
|
-
const ranges: HighlightedSections = [];
|
|
38
|
-
let match: RegExpExecArray | null;
|
|
39
|
-
while ((match = re.exec(text)) !== null) {
|
|
40
|
-
ranges.push({ offset: match.index, length: match[0].length });
|
|
41
|
-
}
|
|
42
|
-
return ranges;
|
|
43
|
-
}
|
|
30
|
+
const DEFAULT_RESULT_COUNT = 20;
|
|
31
|
+
const SEARCH_DEBOUNCE_DELAY = 1200;
|
|
44
32
|
|
|
45
33
|
const UserRecentSearches = new RecentSearches();
|
|
46
34
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
35
|
+
const normalizeCoveoAdvancedQueryValue = (version: string): string =>
|
|
36
|
+
version?.split(".").join("\\.");
|
|
50
37
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
38
|
+
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;
|
|
61
55
|
|
|
62
|
-
|
|
63
|
-
|
|
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
|
+
}
|
|
64
66
|
|
|
65
|
-
export default class SidebarSearch extends LightningElement {
|
|
66
67
|
@api
|
|
67
68
|
public fetchMoreResults() {
|
|
68
|
-
|
|
69
|
+
if (this.resultList?.state?.moreResultsAvailable) {
|
|
70
|
+
this.fetchingMoreResults = true;
|
|
71
|
+
this.resultList.fetchMoreResults();
|
|
72
|
+
}
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
@api
|
|
@@ -81,144 +85,313 @@ export default class SidebarSearch extends LightningElement {
|
|
|
81
85
|
this.dropdownRequestedOpen = value;
|
|
82
86
|
}
|
|
83
87
|
|
|
88
|
+
private _coveoAdvancedQueryConfig!: { [key: string]: any };
|
|
84
89
|
private dropdownRequestedOpen: boolean = false;
|
|
85
90
|
private recentSearches: Option[] = [];
|
|
86
|
-
private
|
|
91
|
+
private unsubscribeFromResultList: Unsubscribe = () => {};
|
|
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;
|
|
87
99
|
private didRender = false;
|
|
88
|
-
|
|
89
|
-
private
|
|
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
|
+
}
|
|
90
114
|
|
|
91
115
|
private get isDropdownOpen() {
|
|
92
116
|
return (
|
|
93
117
|
this.dropdownRequestedOpen &&
|
|
94
|
-
this.recentSearches
|
|
118
|
+
this.recentSearches &&
|
|
119
|
+
this.recentSearches.length > 0 &&
|
|
95
120
|
!this.value
|
|
96
121
|
);
|
|
97
122
|
}
|
|
98
123
|
|
|
99
124
|
constructor() {
|
|
100
125
|
super();
|
|
126
|
+
|
|
101
127
|
this.updateRecentSearches();
|
|
102
|
-
this.value =
|
|
128
|
+
this.value = getSidebarSearchParams() || "";
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
disconnectedCallback() {
|
|
132
|
+
this.unsubscribeFromResultList();
|
|
103
133
|
}
|
|
104
134
|
|
|
105
135
|
renderedCallback() {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const results = applySelectedAndSelect(cached.results);
|
|
121
|
-
this.dispatchChange(results);
|
|
122
|
-
this.dispatchOnLoading(false);
|
|
123
|
-
} else {
|
|
124
|
-
if (!this.didRender) {
|
|
125
|
-
this.dispatchHighlightedTermChange();
|
|
126
|
-
}
|
|
127
|
-
this.dispatchOnLoading(true);
|
|
128
|
-
this.fetchDataCloudSearch();
|
|
129
|
-
}
|
|
130
|
-
} else {
|
|
131
|
-
// No URL query: restore search bar and results from localStorage for this path
|
|
132
|
-
const baseUrlPath = getBaseUrlPath();
|
|
133
|
-
const cached = getStoredSearch(baseUrlPath);
|
|
134
|
-
if (cached?.query && !isCacheStale(cached)) {
|
|
135
|
-
this.value = cached.query;
|
|
136
|
-
const results = applySelectedAndSelect(
|
|
137
|
-
cached.results ?? []
|
|
138
|
-
);
|
|
139
|
-
this.dispatchChange(results);
|
|
140
|
-
this.dispatchHighlightedTermChange();
|
|
136
|
+
// in prod some of the critical coveo configuration attributes seem to arrive later
|
|
137
|
+
// so I needed to put this coveo startup flow here where we can wait for them to arrive
|
|
138
|
+
|
|
139
|
+
if (this.hasCorrectCoveoConfig && !this.engine) {
|
|
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
|
|
141
150
|
}
|
|
142
|
-
|
|
143
|
-
}
|
|
151
|
+
);
|
|
144
152
|
}
|
|
153
|
+
|
|
154
|
+
// If this is the first render and there is a search value, trigger
|
|
155
|
+
// term highlighting
|
|
145
156
|
if (!this.didRender && this.value) {
|
|
146
157
|
this.dispatchHighlightedTermChange();
|
|
147
158
|
}
|
|
159
|
+
|
|
148
160
|
this.didRender = true;
|
|
149
161
|
}
|
|
150
162
|
|
|
151
|
-
private
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
? new URL(href).pathname
|
|
158
|
-
: href;
|
|
159
|
-
const isSelected =
|
|
160
|
-
!!resultPath && resultPath === window.location.pathname;
|
|
161
|
-
const title = item.title ?? "";
|
|
162
|
-
const excerpt = item.matchedText ?? "";
|
|
163
|
-
const searchQuery = this.value.trim();
|
|
164
|
-
return {
|
|
165
|
-
title,
|
|
166
|
-
titleHighlights: getHighlightRanges(title, searchQuery),
|
|
167
|
-
excerpt,
|
|
168
|
-
excerptHighlights: getHighlightRanges(excerpt, searchQuery),
|
|
169
|
-
uniqueId: href || `result-${index}`,
|
|
170
|
-
href,
|
|
171
|
-
selected: isSelected,
|
|
172
|
-
select: () => {}
|
|
173
|
-
};
|
|
174
|
-
};
|
|
163
|
+
private initializeUserSession() {
|
|
164
|
+
const stringified = window.sessionStorage.getItem(SESSION_KEY);
|
|
165
|
+
|
|
166
|
+
if (!stringified) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
175
169
|
|
|
176
|
-
private async fetchDataCloudSearch(): Promise<void> {
|
|
177
170
|
try {
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
const
|
|
181
|
-
|
|
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
|
|
182
178
|
);
|
|
183
|
-
this.
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
setStoredSearch(getBaseUrlPath(), {
|
|
194
|
-
query: this.value.trim(),
|
|
195
|
-
results: cacheItems
|
|
196
|
-
});
|
|
197
|
-
} catch (err) {
|
|
198
|
-
console.error("Data 360 Search request failed", err);
|
|
199
|
-
this.dispatchChange([]);
|
|
200
|
-
} finally {
|
|
201
|
-
this.dispatchOnLoading(false);
|
|
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);
|
|
185
|
+
}
|
|
186
|
+
} catch (e) {
|
|
187
|
+
console.error(e);
|
|
188
|
+
window.sessionStorage.removeItem(SESSION_KEY);
|
|
202
189
|
}
|
|
203
190
|
}
|
|
204
191
|
|
|
205
|
-
private
|
|
206
|
-
|
|
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 {
|
|
242
|
+
this.dispatchOnLoading(false);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
this.syncAnalytics();
|
|
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) {
|
|
207
265
|
return;
|
|
208
266
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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;
|
|
286
|
+
}
|
|
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
|
|
215
302
|
});
|
|
303
|
+
|
|
304
|
+
engine.dispatch(registerSearchQueryAction);
|
|
216
305
|
}
|
|
217
306
|
|
|
218
|
-
private
|
|
307
|
+
private normalizeCoveoResult = (result: Result): SidebarSearchResult => {
|
|
308
|
+
const {
|
|
309
|
+
clickUri,
|
|
310
|
+
excerpt,
|
|
311
|
+
excerptHighlights,
|
|
312
|
+
raw: { sfhtml_url__c },
|
|
313
|
+
title,
|
|
314
|
+
titleHighlights,
|
|
315
|
+
uniqueId
|
|
316
|
+
} = result;
|
|
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
|
+
|
|
361
|
+
return {
|
|
362
|
+
title,
|
|
363
|
+
titleHighlights,
|
|
364
|
+
excerpt,
|
|
365
|
+
excerptHighlights,
|
|
366
|
+
uniqueId,
|
|
367
|
+
href,
|
|
368
|
+
selected: isSelected,
|
|
369
|
+
select: () =>
|
|
370
|
+
window.localStorage.setItem(
|
|
371
|
+
RESULT_CLICK_LOCAL_STORAGE_KEY,
|
|
372
|
+
JSON.stringify(result)
|
|
373
|
+
)
|
|
374
|
+
};
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
private updateSessionStorage() {
|
|
378
|
+
window.sessionStorage.setItem(
|
|
379
|
+
SESSION_KEY,
|
|
380
|
+
JSON.stringify({
|
|
381
|
+
coveoAdvancedQueryConfig: this.coveoAdvancedQueryConfig,
|
|
382
|
+
state: this.engine?.state
|
|
383
|
+
})
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private dispatchOnChangeEvent(results: Result[]) {
|
|
388
|
+
this.updateSessionStorage();
|
|
219
389
|
this.dispatchEvent(
|
|
220
390
|
new CustomEvent("change", {
|
|
221
|
-
detail: {
|
|
391
|
+
detail: {
|
|
392
|
+
results: results.map(this.normalizeCoveoResult),
|
|
393
|
+
value: this.value
|
|
394
|
+
}
|
|
222
395
|
})
|
|
223
396
|
);
|
|
224
397
|
}
|
|
@@ -254,18 +427,24 @@ export default class SidebarSearch extends LightningElement {
|
|
|
254
427
|
}
|
|
255
428
|
|
|
256
429
|
private submitSearch = debounce((isSyncingSearchValue = false) => {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
430
|
+
if (this.searchBox) {
|
|
431
|
+
UserRecentSearches.add(this.value);
|
|
432
|
+
this.updateRecentSearches();
|
|
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();
|
|
261
442
|
}
|
|
262
|
-
this.fetchDataCloudSearch();
|
|
263
443
|
}, SEARCH_DEBOUNCE_DELAY);
|
|
264
444
|
|
|
265
445
|
private onClickRecentSearch(e: CustomEvent) {
|
|
266
446
|
this.value = e.detail;
|
|
267
447
|
this.dispatchSidebarSearchChange(this.value);
|
|
268
|
-
this.dispatchOnLoading(true);
|
|
269
448
|
this.submitSearch(true);
|
|
270
449
|
}
|
|
271
450
|
|
|
@@ -282,6 +461,7 @@ export default class SidebarSearch extends LightningElement {
|
|
|
282
461
|
|
|
283
462
|
private onInputChange(e: CustomEvent) {
|
|
284
463
|
this.value = e.detail;
|
|
464
|
+
|
|
285
465
|
this.handleValueChange(false);
|
|
286
466
|
this.dispatchHighlightedTermChange();
|
|
287
467
|
}
|
|
@@ -296,14 +476,18 @@ export default class SidebarSearch extends LightningElement {
|
|
|
296
476
|
|
|
297
477
|
private handleValueChange(isSyncingSearchValue = false) {
|
|
298
478
|
if (this.value) {
|
|
299
|
-
this.didTrackThisSearch = false;
|
|
300
479
|
this.dispatchOnLoading(true);
|
|
301
|
-
this.
|
|
480
|
+
if (this.searchBox) {
|
|
481
|
+
this.submitSearch(isSyncingSearchValue);
|
|
482
|
+
}
|
|
302
483
|
} else {
|
|
484
|
+
// coveo's reaction to an empty value triggers a return of results
|
|
485
|
+
// bootlegging our own ux here`
|
|
303
486
|
this.dispatchOnLoading(false);
|
|
304
|
-
this.
|
|
487
|
+
this.dispatchOnChangeEvent([]);
|
|
488
|
+
// Empty search values are not submitted for search, so we need to manually
|
|
489
|
+
// trigger a search change on our own here
|
|
305
490
|
this.dispatchSidebarSearchChange(this.value);
|
|
306
|
-
setStoredSearch(getBaseUrlPath(), { query: "", results: [] });
|
|
307
491
|
}
|
|
308
492
|
}
|
|
309
493
|
}
|