@asd20/ui-next 2.11.0 → 2.12.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/CHANGELOG.md +19 -0
- package/helpers.js +1 -0
- package/package.json +1 -1
- package/src/components/organisms/Asd20AiSearch/index.vue +2 -0
- package/src/components/organisms/Asd20SiteNavigation/index.vue +4 -0
- package/src/components/organisms/Asd20SiteSearch/index.vue +180 -128
- package/src/components/templates/Asd20DistrictVideoTemplate/index.vue +6 -0
- package/src/components/templates/Asd20SchoolHomeTemplate/index.vue +6 -0
- package/src/components/templates/Asd20SchoolHomeVideoTemplate/index.vue +6 -0
- package/src/helpers/queryPeople.js +122 -0
- package/src/helpers/searchProxyUrl.js +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
# [2.12.0](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.11.1...ui-next-v2.12.0) (2026-05-26)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* add querypeople to public api contract ([a1a3141](https://github.com/academydistrict20/asd20-ui-next/commit/a1a3141ec8b3df29da27e947fecba80baf0169e1))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* add people to ai search ([241cf12](https://github.com/academydistrict20/asd20-ui-next/commit/241cf1247633f83a47b6fe3cd3bc91bbff275e80))
|
|
14
|
+
|
|
15
|
+
## [2.11.1](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.11.0...ui-next-v2.11.1) (2026-05-26)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
* remove search parameters from url ([b6bde4c](https://github.com/academydistrict20/asd20-ui-next/commit/b6bde4cb29ea762267ecd03f9739a47d8726ce1e))
|
|
21
|
+
|
|
3
22
|
# [2.11.0](https://github.com/academydistrict20/asd20-ui-next/compare/ui-next-v2.10.11...ui-next-v2.11.0) (2026-05-26)
|
|
4
23
|
|
|
5
24
|
|
package/helpers.js
CHANGED
|
@@ -42,6 +42,7 @@ export { default as queryEvents } from './src/helpers/queryEvents.js'
|
|
|
42
42
|
export { default as queryFiles } from './src/helpers/queryFiles.js'
|
|
43
43
|
export { default as queryMessages } from './src/helpers/queryMessages.js'
|
|
44
44
|
export { default as queryPages } from './src/helpers/queryPages.js'
|
|
45
|
+
export { default as queryPeople } from './src/helpers/queryPeople.js'
|
|
45
46
|
export { default as sendAccessibilityIssue } from './src/helpers/sendAccessibilityIssue.js'
|
|
46
47
|
export { default as sendEmail } from './src/helpers/sendEmail.js'
|
|
47
48
|
export { default as sortOrgsByLevel } from './src/helpers/sortOrgsByLevel.js'
|
package/package.json
CHANGED
|
@@ -53,12 +53,14 @@ export default {
|
|
|
53
53
|
pages: { type: Array, default: () => [] },
|
|
54
54
|
files: { type: Array, default: () => [] },
|
|
55
55
|
groups: { type: Array, default: () => [] },
|
|
56
|
+
people: { type: Array, default: () => [] },
|
|
56
57
|
showContacts: { type: Boolean, default: true },
|
|
57
58
|
includeDistrictResults: { type: Boolean, default: true },
|
|
58
59
|
searchLanguageCode: { type: String, default: null },
|
|
59
60
|
queryPagesHandler: { type: Function, default: null },
|
|
60
61
|
queryFilesHandler: { type: Function, default: null },
|
|
61
62
|
queryGroupsHandler: { type: Function, default: null },
|
|
63
|
+
queryPeopleHandler: { type: Function, default: null },
|
|
62
64
|
queryAiSiteHandler: { type: Function, default: null },
|
|
63
65
|
organization: { type: Object, default: () => ({}) },
|
|
64
66
|
organizationOptions: { type: Array, default: () => [] },
|
|
@@ -71,11 +71,13 @@
|
|
|
71
71
|
:pages="pages"
|
|
72
72
|
:files="files"
|
|
73
73
|
:groups="groups"
|
|
74
|
+
:people="people"
|
|
74
75
|
:include-district-results="includeDistrictResults"
|
|
75
76
|
:search-language-code="searchLanguageCode"
|
|
76
77
|
:query-pages-handler="queryPagesHandler"
|
|
77
78
|
:query-files-handler="queryFilesHandler"
|
|
78
79
|
:query-groups-handler="queryGroupsHandler"
|
|
80
|
+
:query-people-handler="queryPeopleHandler"
|
|
79
81
|
:query-ai-site-handler="queryAiSiteHandler"
|
|
80
82
|
:organization="organization"
|
|
81
83
|
:organization-options="organizationOptions"
|
|
@@ -118,12 +120,14 @@ export default {
|
|
|
118
120
|
pages: { type: Array, default: () => [] },
|
|
119
121
|
files: { type: Array, default: () => [] },
|
|
120
122
|
groups: { type: Array, default: () => [] },
|
|
123
|
+
people: { type: Array, default: () => [] },
|
|
121
124
|
showContacts: { type: Boolean, default: true },
|
|
122
125
|
includeDistrictResults: { type: Boolean, default: true },
|
|
123
126
|
searchLanguageCode: { type: String, default: null },
|
|
124
127
|
queryPagesHandler: { type: Function, default: null },
|
|
125
128
|
queryFilesHandler: { type: Function, default: null },
|
|
126
129
|
queryGroupsHandler: { type: Function, default: null },
|
|
130
|
+
queryPeopleHandler: { type: Function, default: null },
|
|
127
131
|
queryAiSiteHandler: { type: Function, default: null },
|
|
128
132
|
organization: { type: Object, default: null },
|
|
129
133
|
organizationOptions: { type: Array, default: () => [] },
|
|
@@ -324,37 +324,35 @@
|
|
|
324
324
|
v-if="
|
|
325
325
|
hasSubmitted &&
|
|
326
326
|
showContacts &&
|
|
327
|
-
|
|
328
|
-
!searchingFiles
|
|
327
|
+
contactResultCount === 0 &&
|
|
328
|
+
!searchingFiles &&
|
|
329
|
+
!searchingPeople
|
|
329
330
|
"
|
|
330
331
|
title="No Contacts Found"
|
|
331
332
|
description="Try using different keywords."
|
|
332
333
|
/>
|
|
333
334
|
<div
|
|
334
|
-
v-if="
|
|
335
|
+
v-if="contactResultCount > 0 && showContacts"
|
|
335
336
|
class="asd20-site-search__suggested"
|
|
336
337
|
>
|
|
337
338
|
<h3>
|
|
338
339
|
{{
|
|
339
|
-
|
|
340
|
+
contactResultCount > 1
|
|
340
341
|
? 'Suggested Contacts:'
|
|
341
342
|
: 'Suggested Contact:'
|
|
342
343
|
}}
|
|
343
344
|
</h3>
|
|
344
345
|
<asd20-list-item
|
|
345
|
-
v-for="item in
|
|
346
|
-
|
|
347
|
-
:
|
|
348
|
-
|
|
349
|
-
:logo-url="item.logoUrl"
|
|
350
|
-
:source-title="item.sourceTitle"
|
|
351
|
-
:attribution="!!item.logoUrl"
|
|
352
|
-
actionable
|
|
353
|
-
@click="selectedGroup = item.group"
|
|
346
|
+
v-for="item in contactListItems"
|
|
347
|
+
v-bind="item"
|
|
348
|
+
:key="item.key"
|
|
349
|
+
@click="onContactClick(item)"
|
|
354
350
|
/>
|
|
355
351
|
</div>
|
|
356
352
|
<asd20-loader
|
|
357
|
-
v-if="
|
|
353
|
+
v-if="
|
|
354
|
+
(searchingFiles || searchingPeople) && contactResultCount === 0
|
|
355
|
+
"
|
|
358
356
|
size="lg"
|
|
359
357
|
/>
|
|
360
358
|
</asd20-viewport>
|
|
@@ -467,6 +465,12 @@
|
|
|
467
465
|
</asd20-viewport>
|
|
468
466
|
</asd20-modal>
|
|
469
467
|
|
|
468
|
+
<asd20-person-modal
|
|
469
|
+
:person="selectedPerson"
|
|
470
|
+
:open="!!selectedPerson"
|
|
471
|
+
@dismiss="selectedPerson = null"
|
|
472
|
+
/>
|
|
473
|
+
|
|
470
474
|
<asd20-modal
|
|
471
475
|
:open="improvementFeedbackModalOpen"
|
|
472
476
|
title="Report Missing or Incorrect Information"
|
|
@@ -539,6 +543,7 @@ import Asd20Notification from '../../molecules/Asd20Notification'
|
|
|
539
543
|
import Asd20Loader from '../../molecules/Asd20Loader'
|
|
540
544
|
import Asd20Modal from '../../molecules/Asd20Modal'
|
|
541
545
|
import Asd20DepartmentContactCard from '../../molecules/Asd20DepartmentContactCard'
|
|
546
|
+
import Asd20PersonModal from '../../organisms/Asd20PersonModal'
|
|
542
547
|
import Asd20Button from '../../atoms/Asd20Button'
|
|
543
548
|
import Asd20Icon from '../../atoms/Asd20Icon'
|
|
544
549
|
import Asd20Spinner from '../../atoms/Asd20Spinner'
|
|
@@ -548,9 +553,11 @@ import Asd20Spinner from '../../atoms/Asd20Spinner'
|
|
|
548
553
|
import debounce from 'lodash/debounce'
|
|
549
554
|
import mapPagesToListItems from '../../../helpers/mapPagesToListItems'
|
|
550
555
|
import mapFilesToListItems from '../../../helpers/mapFilesToListItems'
|
|
556
|
+
import mapPeopleToListItems from '../../../helpers/mapPeopleToListItems'
|
|
551
557
|
import logSearchAnalytics from '../../../helpers/logSearchAnalytics'
|
|
552
558
|
import logSearchFeedback from '../../../helpers/logSearchFeedback'
|
|
553
559
|
import queryAiSite from '../../../helpers/queryAiSite'
|
|
560
|
+
import queryPeople from '../../../helpers/queryPeople'
|
|
554
561
|
import { NO_PAGE_RESULTS_FALLBACKS } from '../../../helpers/queryPages'
|
|
555
562
|
|
|
556
563
|
// Mixins
|
|
@@ -604,6 +611,7 @@ export default {
|
|
|
604
611
|
Asd20Loader,
|
|
605
612
|
Asd20Modal,
|
|
606
613
|
Asd20DepartmentContactCard,
|
|
614
|
+
Asd20PersonModal,
|
|
607
615
|
Asd20Button,
|
|
608
616
|
Asd20Icon,
|
|
609
617
|
Asd20Spinner,
|
|
@@ -625,6 +633,11 @@ export default {
|
|
|
625
633
|
{ type: Array, default: () => [] },
|
|
626
634
|
'search'
|
|
627
635
|
),
|
|
636
|
+
globalPropMixinFactory(
|
|
637
|
+
'people',
|
|
638
|
+
{ type: Array, default: () => [] },
|
|
639
|
+
'search'
|
|
640
|
+
),
|
|
628
641
|
globalPropMixinFactory(
|
|
629
642
|
'includeDistrictResults',
|
|
630
643
|
{ type: Boolean, default: true },
|
|
@@ -642,6 +655,7 @@ export default {
|
|
|
642
655
|
queryPagesHandler: { type: Function, default: null },
|
|
643
656
|
queryFilesHandler: { type: Function, default: null },
|
|
644
657
|
queryGroupsHandler: { type: Function, default: null },
|
|
658
|
+
queryPeopleHandler: { type: Function, default: null },
|
|
645
659
|
queryAiSiteHandler: { type: Function, default: null },
|
|
646
660
|
organization: {
|
|
647
661
|
type: Object,
|
|
@@ -666,12 +680,15 @@ export default {
|
|
|
666
680
|
aiTranscript: [],
|
|
667
681
|
|
|
668
682
|
selectedGroup: null,
|
|
683
|
+
selectedPerson: null,
|
|
669
684
|
searchingPages: false,
|
|
670
685
|
searchingFiles: false,
|
|
686
|
+
searchingPeople: false,
|
|
671
687
|
|
|
672
688
|
localSearchPages: null,
|
|
673
689
|
localSearchFiles: null,
|
|
674
690
|
localSearchGroups: null,
|
|
691
|
+
localSearchPeople: null,
|
|
675
692
|
|
|
676
693
|
keywordsFromAi: false,
|
|
677
694
|
aiKeywordsDisplayAnswer: '',
|
|
@@ -683,7 +700,6 @@ export default {
|
|
|
683
700
|
searchMode: '',
|
|
684
701
|
routeRestoreInProgress: false,
|
|
685
702
|
lastRestoredSearchKey: '',
|
|
686
|
-
skipNextRouteRestore: false,
|
|
687
703
|
suppressAutoRestore: false,
|
|
688
704
|
lastManualTabChangeAt: 0,
|
|
689
705
|
lastManualTabLabel: '',
|
|
@@ -724,6 +740,15 @@ export default {
|
|
|
724
740
|
return Array.isArray(this.resolvedGroups) ? this.resolvedGroups : []
|
|
725
741
|
},
|
|
726
742
|
|
|
743
|
+
currentPeople() {
|
|
744
|
+
if (Array.isArray(this.localSearchPeople)) return this.localSearchPeople
|
|
745
|
+
return Array.isArray(this.resolvedPeople) ? this.resolvedPeople : []
|
|
746
|
+
},
|
|
747
|
+
|
|
748
|
+
contactResultCount() {
|
|
749
|
+
return this.currentGroups.length + this.currentPeople.length
|
|
750
|
+
},
|
|
751
|
+
|
|
727
752
|
shouldUsePageFallbacks() {
|
|
728
753
|
const hasSearchText =
|
|
729
754
|
typeof this.keywords === 'string' && this.keywords.trim()
|
|
@@ -829,7 +854,7 @@ export default {
|
|
|
829
854
|
if (this.showContacts) {
|
|
830
855
|
assistantTabs.push({
|
|
831
856
|
label: 'Contacts',
|
|
832
|
-
badge: this.
|
|
857
|
+
badge: this.contactResultCount,
|
|
833
858
|
active: this.currentTab === 'Contacts',
|
|
834
859
|
})
|
|
835
860
|
}
|
|
@@ -852,7 +877,7 @@ export default {
|
|
|
852
877
|
if (this.showContacts) {
|
|
853
878
|
keywordTabs.push({
|
|
854
879
|
label: 'Contacts',
|
|
855
|
-
badge: this.
|
|
880
|
+
badge: this.contactResultCount,
|
|
856
881
|
active: this.currentTab === 'Contacts',
|
|
857
882
|
})
|
|
858
883
|
}
|
|
@@ -955,6 +980,8 @@ export default {
|
|
|
955
980
|
((g.shortName || g.title || '').match(/\b([A-Z])/g) || []).join('')
|
|
956
981
|
|
|
957
982
|
return {
|
|
983
|
+
key: `group-${g.id || g.title}`,
|
|
984
|
+
contactType: 'group',
|
|
958
985
|
group: g,
|
|
959
986
|
label: `${g.title}`,
|
|
960
987
|
textAvatar,
|
|
@@ -963,6 +990,17 @@ export default {
|
|
|
963
990
|
}
|
|
964
991
|
})
|
|
965
992
|
},
|
|
993
|
+
peopleListItems() {
|
|
994
|
+
return (mapPeopleToListItems(this.currentPeople) || []).map(item => ({
|
|
995
|
+
...item,
|
|
996
|
+
key: `person-${item.id || item.email || item.label}`,
|
|
997
|
+
contactType: 'person',
|
|
998
|
+
}))
|
|
999
|
+
},
|
|
1000
|
+
|
|
1001
|
+
contactListItems() {
|
|
1002
|
+
return [...this.peopleListItems, ...this.groupListItems]
|
|
1003
|
+
},
|
|
966
1004
|
feedbackFormUrlRaw() {
|
|
967
1005
|
if (this.aiSearchFeedbackFormUrl) return this.aiSearchFeedbackFormUrl
|
|
968
1006
|
const runtimeConfig = this.resolveRuntimeConfig()
|
|
@@ -1077,9 +1115,9 @@ export default {
|
|
|
1077
1115
|
this.focusQuery()
|
|
1078
1116
|
this.refreshResultsScrollLayer()
|
|
1079
1117
|
})
|
|
1080
|
-
this.
|
|
1118
|
+
this.restoreSearchState()
|
|
1081
1119
|
} else {
|
|
1082
|
-
this.
|
|
1120
|
+
this.clearLegacySearchRouteQuery()
|
|
1083
1121
|
if (!this.inline) this.unlockBodyScroll()
|
|
1084
1122
|
this.blurQuery()
|
|
1085
1123
|
}
|
|
@@ -1090,7 +1128,7 @@ export default {
|
|
|
1090
1128
|
if (newVal === 'Answers') {
|
|
1091
1129
|
this.$nextTick(() => this.refreshResultsScrollLayer())
|
|
1092
1130
|
}
|
|
1093
|
-
this.
|
|
1131
|
+
this.syncSearchState({ tab: newVal })
|
|
1094
1132
|
},
|
|
1095
1133
|
|
|
1096
1134
|
aiAnswer() {
|
|
@@ -1115,7 +1153,7 @@ export default {
|
|
|
1115
1153
|
this.selectedGroup = null
|
|
1116
1154
|
this.searchPages({ runId })
|
|
1117
1155
|
this.searchFilesWithGroupOwners({ runId })
|
|
1118
|
-
this.
|
|
1156
|
+
this.syncSearchState()
|
|
1119
1157
|
}
|
|
1120
1158
|
}, 400),
|
|
1121
1159
|
|
|
@@ -1124,7 +1162,7 @@ export default {
|
|
|
1124
1162
|
const runId = this.beginSearchRun()
|
|
1125
1163
|
this.searchPages({ runId })
|
|
1126
1164
|
this.searchFilesWithGroupOwners({ runId })
|
|
1127
|
-
this.
|
|
1165
|
+
this.syncSearchState()
|
|
1128
1166
|
},
|
|
1129
1167
|
// Clear AI answer if user clears the input
|
|
1130
1168
|
|
|
@@ -1137,34 +1175,20 @@ export default {
|
|
|
1137
1175
|
this.aiKeywordsDisplayPages = ''
|
|
1138
1176
|
}
|
|
1139
1177
|
},
|
|
1140
|
-
|
|
1141
|
-
'$route.query': {
|
|
1142
|
-
handler() {
|
|
1143
|
-
if (this.suppressAutoRestore) return
|
|
1144
|
-
if (this.searchingAi) return
|
|
1145
|
-
if (this.hasRecentManualTabSelection()) return
|
|
1146
|
-
if (this.skipNextRouteRestore) {
|
|
1147
|
-
this.skipNextRouteRestore = false
|
|
1148
|
-
return
|
|
1149
|
-
}
|
|
1150
|
-
if (!this.getRouteSearchState(this.$route.query)) {
|
|
1151
|
-
this.lastRestoredSearchKey = ''
|
|
1152
|
-
}
|
|
1153
|
-
if (this.active) this.restoreSearchStateFromRoute()
|
|
1154
|
-
},
|
|
1155
|
-
},
|
|
1156
1178
|
},
|
|
1157
1179
|
|
|
1158
1180
|
mounted() {
|
|
1159
1181
|
if (this.active && !this.inline) {
|
|
1160
1182
|
this.lockBodyScroll()
|
|
1161
1183
|
}
|
|
1162
|
-
|
|
1184
|
+
const didReload = this.didPageReload()
|
|
1185
|
+
if (didReload) {
|
|
1163
1186
|
this.persistSearchState(null)
|
|
1164
1187
|
this.lastRestoredSearchKey = ''
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1188
|
+
}
|
|
1189
|
+
this.clearLegacySearchRouteQuery()
|
|
1190
|
+
if (!didReload && this.active) {
|
|
1191
|
+
this.restoreSearchState()
|
|
1168
1192
|
}
|
|
1169
1193
|
if (typeof window !== 'undefined') {
|
|
1170
1194
|
window.addEventListener('resize', this.onWindowReflow, { passive: true })
|
|
@@ -1231,7 +1255,7 @@ export default {
|
|
|
1231
1255
|
: 'en'
|
|
1232
1256
|
},
|
|
1233
1257
|
|
|
1234
|
-
setSearchResults({ pages, files, groups } = {}) {
|
|
1258
|
+
setSearchResults({ pages, files, groups, people } = {}) {
|
|
1235
1259
|
if (pages !== undefined) {
|
|
1236
1260
|
this.localSearchPages = Array.isArray(pages) ? pages : []
|
|
1237
1261
|
}
|
|
@@ -1241,12 +1265,16 @@ export default {
|
|
|
1241
1265
|
if (groups !== undefined) {
|
|
1242
1266
|
this.localSearchGroups = Array.isArray(groups) ? groups : []
|
|
1243
1267
|
}
|
|
1268
|
+
if (people !== undefined) {
|
|
1269
|
+
this.localSearchPeople = Array.isArray(people) ? people : []
|
|
1270
|
+
}
|
|
1244
1271
|
},
|
|
1245
1272
|
|
|
1246
1273
|
readSearchResults(target) {
|
|
1247
1274
|
if (target === 'pages') return this.currentPages
|
|
1248
1275
|
if (target === 'files') return this.currentFiles
|
|
1249
1276
|
if (target === 'groups') return this.currentGroups
|
|
1277
|
+
if (target === 'people') return this.currentPeople
|
|
1250
1278
|
return []
|
|
1251
1279
|
},
|
|
1252
1280
|
|
|
@@ -1260,6 +1288,9 @@ export default {
|
|
|
1260
1288
|
if (target === 'groups') {
|
|
1261
1289
|
return Array.isArray(this.resolvedGroups) ? this.resolvedGroups : []
|
|
1262
1290
|
}
|
|
1291
|
+
if (target === 'people') {
|
|
1292
|
+
return Array.isArray(this.resolvedPeople) ? this.resolvedPeople : []
|
|
1293
|
+
}
|
|
1263
1294
|
return []
|
|
1264
1295
|
},
|
|
1265
1296
|
|
|
@@ -1323,9 +1354,24 @@ export default {
|
|
|
1323
1354
|
}
|
|
1324
1355
|
},
|
|
1325
1356
|
|
|
1326
|
-
|
|
1327
|
-
if (
|
|
1328
|
-
|
|
1357
|
+
async queryPeopleWithFallback(payload) {
|
|
1358
|
+
if (typeof this.queryPeopleHandler === 'function') {
|
|
1359
|
+
const result = await this.queryPeopleHandler(payload)
|
|
1360
|
+
if (Array.isArray(result)) return result
|
|
1361
|
+
return result && Array.isArray(result.people) ? result.people : []
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
const searchStore = this.getSearchStore()
|
|
1365
|
+
if (searchStore) {
|
|
1366
|
+
await searchStore.dispatch('search/queryPeople', payload)
|
|
1367
|
+
return Array.isArray(this.resolvedPeople) ? this.resolvedPeople : []
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
const { people } = await queryPeople({
|
|
1371
|
+
...payload,
|
|
1372
|
+
runtimeConfig: this.resolveRuntimeConfig(),
|
|
1373
|
+
})
|
|
1374
|
+
return Array.isArray(people) ? people : []
|
|
1329
1375
|
},
|
|
1330
1376
|
|
|
1331
1377
|
isLocalDevelopmentHost(hostname = '') {
|
|
@@ -1406,7 +1452,7 @@ export default {
|
|
|
1406
1452
|
if (this.searchingAi) return
|
|
1407
1453
|
if (this.hasRecentManualTabSelection()) return
|
|
1408
1454
|
if (!this.active || this.routeRestoreInProgress) return
|
|
1409
|
-
this.
|
|
1455
|
+
this.restoreSearchState()
|
|
1410
1456
|
},
|
|
1411
1457
|
|
|
1412
1458
|
hasRecentManualTabSelection() {
|
|
@@ -1546,6 +1592,7 @@ export default {
|
|
|
1546
1592
|
pages: Array.isArray(this.currentPages) ? this.currentPages : [],
|
|
1547
1593
|
files: Array.isArray(this.currentFiles) ? this.currentFiles : [],
|
|
1548
1594
|
groups: Array.isArray(this.currentGroups) ? this.currentGroups : [],
|
|
1595
|
+
people: Array.isArray(this.currentPeople) ? this.currentPeople : [],
|
|
1549
1596
|
aiAnswer: this.aiAnswer || null,
|
|
1550
1597
|
aiSources: Array.isArray(this.aiSources) ? this.aiSources : [],
|
|
1551
1598
|
aiErrorMessage: this.aiErrorMessage || '',
|
|
@@ -1560,7 +1607,7 @@ export default {
|
|
|
1560
1607
|
},
|
|
1561
1608
|
|
|
1562
1609
|
persistSearchCacheSnapshot(overrides = {}) {
|
|
1563
|
-
const state = this.
|
|
1610
|
+
const state = this.getCurrentSearchState(overrides)
|
|
1564
1611
|
if (!state) return
|
|
1565
1612
|
this.persistSearchState(state, {
|
|
1566
1613
|
cache: this.buildSearchCacheSnapshot(),
|
|
@@ -1656,7 +1703,8 @@ export default {
|
|
|
1656
1703
|
const pages = Array.isArray(snapshot.pages) ? snapshot.pages : []
|
|
1657
1704
|
const files = Array.isArray(snapshot.files) ? snapshot.files : []
|
|
1658
1705
|
const groups = Array.isArray(snapshot.groups) ? snapshot.groups : []
|
|
1659
|
-
|
|
1706
|
+
const people = Array.isArray(snapshot.people) ? snapshot.people : []
|
|
1707
|
+
this.setSearchResults({ pages, files, groups, people })
|
|
1660
1708
|
|
|
1661
1709
|
if (!skipTabUpdate) {
|
|
1662
1710
|
const preferredTab = SEARCH_ROUTE_TABS.has(targetState.tab)
|
|
@@ -1673,33 +1721,7 @@ export default {
|
|
|
1673
1721
|
return true
|
|
1674
1722
|
},
|
|
1675
1723
|
|
|
1676
|
-
|
|
1677
|
-
const rawText = this.normalizeRouteQueryValue(
|
|
1678
|
-
routeQuery[SEARCH_ROUTE_QUERY_KEYS.text]
|
|
1679
|
-
)
|
|
1680
|
-
const rawIncludeDistrictResults = this.normalizeRouteQueryValue(
|
|
1681
|
-
routeQuery[SEARCH_ROUTE_QUERY_KEYS.includeDistrictResults]
|
|
1682
|
-
)
|
|
1683
|
-
const rawMode = this.normalizeRouteQueryValue(
|
|
1684
|
-
routeQuery[SEARCH_ROUTE_QUERY_KEYS.mode]
|
|
1685
|
-
)
|
|
1686
|
-
const rawTab = this.normalizeRouteQueryValue(
|
|
1687
|
-
routeQuery[SEARCH_ROUTE_QUERY_KEYS.tab]
|
|
1688
|
-
)
|
|
1689
|
-
const rawUpdatedAt = this.normalizeRouteQueryValue(
|
|
1690
|
-
routeQuery[SEARCH_ROUTE_QUERY_KEYS.updatedAt]
|
|
1691
|
-
)
|
|
1692
|
-
|
|
1693
|
-
return this.normalizeSearchState({
|
|
1694
|
-
text: rawText,
|
|
1695
|
-
mode: rawMode,
|
|
1696
|
-
tab: rawTab,
|
|
1697
|
-
includeDistrictResults: rawIncludeDistrictResults,
|
|
1698
|
-
updatedAt: rawUpdatedAt,
|
|
1699
|
-
})
|
|
1700
|
-
},
|
|
1701
|
-
|
|
1702
|
-
getCurrentSearchStateForRoute(overrides = {}) {
|
|
1724
|
+
getCurrentSearchState(overrides = {}) {
|
|
1703
1725
|
const hasSubmitted =
|
|
1704
1726
|
typeof overrides.hasSubmitted === 'boolean'
|
|
1705
1727
|
? overrides.hasSubmitted
|
|
@@ -1746,35 +1768,17 @@ export default {
|
|
|
1746
1768
|
}
|
|
1747
1769
|
},
|
|
1748
1770
|
|
|
1749
|
-
|
|
1750
|
-
if (!state) return {}
|
|
1751
|
-
const values = {
|
|
1752
|
-
[SEARCH_ROUTE_QUERY_KEYS.text]: state.text,
|
|
1753
|
-
[SEARCH_ROUTE_QUERY_KEYS.mode]: state.mode,
|
|
1754
|
-
[SEARCH_ROUTE_QUERY_KEYS.tab]: state.tab,
|
|
1755
|
-
[SEARCH_ROUTE_QUERY_KEYS.includeDistrictResults]:
|
|
1756
|
-
state.includeDistrictResults ? '1' : '0',
|
|
1757
|
-
}
|
|
1758
|
-
const updatedAt = Number(state.updatedAt)
|
|
1759
|
-
if (Number.isFinite(updatedAt) && updatedAt > 0) {
|
|
1760
|
-
values[SEARCH_ROUTE_QUERY_KEYS.updatedAt] = String(
|
|
1761
|
-
Math.round(updatedAt)
|
|
1762
|
-
)
|
|
1763
|
-
}
|
|
1764
|
-
return values
|
|
1765
|
-
},
|
|
1766
|
-
|
|
1767
|
-
buildQueryWithSearchState(state) {
|
|
1771
|
+
buildQueryWithoutSearchState() {
|
|
1768
1772
|
const nextQuery = { ...((this.$route && this.$route.query) || {}) }
|
|
1769
1773
|
Object.keys(SEARCH_ROUTE_QUERY_KEYS).forEach(key => {
|
|
1770
1774
|
delete nextQuery[SEARCH_ROUTE_QUERY_KEYS[key]]
|
|
1771
1775
|
})
|
|
1772
|
-
return
|
|
1776
|
+
return nextQuery
|
|
1773
1777
|
},
|
|
1774
1778
|
|
|
1775
|
-
async
|
|
1779
|
+
async clearLegacySearchRouteQuery() {
|
|
1776
1780
|
if (!this.$router || !this.$route) return
|
|
1777
|
-
const nextQuery = this.
|
|
1781
|
+
const nextQuery = this.buildQueryWithoutSearchState()
|
|
1778
1782
|
await this.replaceRouteQuery(nextQuery)
|
|
1779
1783
|
},
|
|
1780
1784
|
|
|
@@ -1800,25 +1804,20 @@ export default {
|
|
|
1800
1804
|
async replaceRouteQuery(query) {
|
|
1801
1805
|
if (!this.$router || !this.$route) return
|
|
1802
1806
|
if (this.isSameQuery(this.$route.query, query)) return
|
|
1803
|
-
this.skipNextRouteRestore = true
|
|
1804
1807
|
try {
|
|
1805
1808
|
await this.$router.replace({ path: this.$route.path, query })
|
|
1806
1809
|
} catch (error) {
|
|
1807
|
-
this.skipNextRouteRestore = false
|
|
1808
1810
|
// Ignore duplicate navigation and transient route replacement races.
|
|
1809
1811
|
}
|
|
1810
1812
|
},
|
|
1811
1813
|
|
|
1812
|
-
|
|
1814
|
+
syncSearchState(overrides = {}) {
|
|
1813
1815
|
if (this.routeRestoreInProgress) return
|
|
1814
|
-
|
|
1815
|
-
const state = this.getCurrentSearchStateForRoute(overrides)
|
|
1816
|
+
const state = this.getCurrentSearchState(overrides)
|
|
1816
1817
|
this.lastRestoredSearchKey = state
|
|
1817
|
-
? `
|
|
1818
|
+
? `storage:${JSON.stringify(state)}`
|
|
1818
1819
|
: ''
|
|
1819
1820
|
this.persistSearchState(state, { preserveCache: true })
|
|
1820
|
-
const nextQuery = this.buildQueryWithSearchState(state)
|
|
1821
|
-
await this.replaceRouteQuery(nextQuery)
|
|
1822
1821
|
},
|
|
1823
1822
|
|
|
1824
1823
|
appendSearchContextToUrl(rawUrl) {
|
|
@@ -1826,14 +1825,11 @@ export default {
|
|
|
1826
1825
|
return rawUrl
|
|
1827
1826
|
},
|
|
1828
1827
|
|
|
1829
|
-
async
|
|
1828
|
+
async restoreSearchState() {
|
|
1830
1829
|
if (this.suppressAutoRestore) return
|
|
1831
1830
|
if (this.searchingAi) return
|
|
1832
|
-
if (
|
|
1831
|
+
if (this.routeRestoreInProgress) return
|
|
1833
1832
|
const restoreStartedAt = Date.now()
|
|
1834
|
-
const routeStateCandidate = this.getRouteSearchState(this.$route.query)
|
|
1835
|
-
const routeStateFresh = this.isSearchStateFresh(routeStateCandidate)
|
|
1836
|
-
const routeState = routeStateFresh ? routeStateCandidate : null
|
|
1837
1833
|
const persistedRecordCandidate = this.readPersistedSearchRecord()
|
|
1838
1834
|
const persistedRecordFresh =
|
|
1839
1835
|
persistedRecordCandidate &&
|
|
@@ -1845,24 +1841,16 @@ export default {
|
|
|
1845
1841
|
if (persistedRecordCandidate && !persistedRecordFresh) {
|
|
1846
1842
|
this.persistSearchState(null)
|
|
1847
1843
|
}
|
|
1848
|
-
if (routeStateCandidate && !routeStateFresh) {
|
|
1849
|
-
await this.clearSearchStateFromRouteQuery()
|
|
1850
|
-
}
|
|
1851
1844
|
|
|
1852
|
-
const
|
|
1853
|
-
? null
|
|
1854
|
-
: persistedRecord && persistedRecord.state
|
|
1855
|
-
? persistedRecord.state
|
|
1856
|
-
: null
|
|
1857
|
-
const restoredState = routeState || persistedState
|
|
1845
|
+
const restoredState =
|
|
1846
|
+
persistedRecord && persistedRecord.state ? persistedRecord.state : null
|
|
1858
1847
|
if (!restoredState) return
|
|
1859
1848
|
|
|
1860
|
-
const restoreSource = routeState ? 'route' : 'storage'
|
|
1861
1849
|
const cacheVersion = this.getSearchCacheVersion(
|
|
1862
1850
|
persistedRecord,
|
|
1863
1851
|
restoredState
|
|
1864
1852
|
)
|
|
1865
|
-
const restoreKey =
|
|
1853
|
+
const restoreKey = `storage:${JSON.stringify(
|
|
1866
1854
|
restoredState
|
|
1867
1855
|
)}:${cacheVersion}`
|
|
1868
1856
|
if (restoreKey === this.lastRestoredSearchKey) return
|
|
@@ -2253,10 +2241,43 @@ export default {
|
|
|
2253
2241
|
|
|
2254
2242
|
dismiss() {
|
|
2255
2243
|
if (!this.active) return
|
|
2256
|
-
this.
|
|
2244
|
+
this.clearLegacySearchRouteQuery()
|
|
2257
2245
|
this.$emit('update:active', false)
|
|
2258
2246
|
},
|
|
2259
2247
|
|
|
2248
|
+
onContactClick(item) {
|
|
2249
|
+
if (!item) return
|
|
2250
|
+
if (item.contactType === 'person') {
|
|
2251
|
+
this.selectedPerson = this.normalizePersonForModal(item.person || item)
|
|
2252
|
+
return
|
|
2253
|
+
}
|
|
2254
|
+
if (item.group) {
|
|
2255
|
+
this.selectedGroup = item.group
|
|
2256
|
+
}
|
|
2257
|
+
},
|
|
2258
|
+
|
|
2259
|
+
normalizePersonForModal(person = {}) {
|
|
2260
|
+
const jobTitles = Array.isArray(person.jobTitles)
|
|
2261
|
+
? person.jobTitles
|
|
2262
|
+
: person.jobTitles
|
|
2263
|
+
? [person.jobTitles]
|
|
2264
|
+
: person.jobTypes
|
|
2265
|
+
? Array.isArray(person.jobTypes)
|
|
2266
|
+
? person.jobTypes
|
|
2267
|
+
: [person.jobTypes]
|
|
2268
|
+
: []
|
|
2269
|
+
|
|
2270
|
+
return {
|
|
2271
|
+
...person,
|
|
2272
|
+
id: person.id || person.employeeId || person.profileId || person.userId,
|
|
2273
|
+
displayName: person.displayName || person.name || '',
|
|
2274
|
+
jobTitles,
|
|
2275
|
+
workPhone: person.workPhone || person.phone || '',
|
|
2276
|
+
thumbnailUrl:
|
|
2277
|
+
person.thumbnailUrl || person.thumbnail || person.photoUrl || '',
|
|
2278
|
+
}
|
|
2279
|
+
},
|
|
2280
|
+
|
|
2260
2281
|
resolveRuntimeConfig() {
|
|
2261
2282
|
const runtimeConfig =
|
|
2262
2283
|
this.$config ||
|
|
@@ -2421,9 +2442,11 @@ export default {
|
|
|
2421
2442
|
this.beginSearchRun()
|
|
2422
2443
|
}
|
|
2423
2444
|
this.selectedGroup = null
|
|
2445
|
+
this.selectedPerson = null
|
|
2424
2446
|
this.searchingAi = preserveAiLoading ? this.searchingAi : false
|
|
2425
2447
|
this.searchingPages = false
|
|
2426
2448
|
this.searchingFiles = false
|
|
2449
|
+
this.searchingPeople = false
|
|
2427
2450
|
this.activeAiQuestionKey = preserveAiLoading
|
|
2428
2451
|
? this.activeAiQuestionKey
|
|
2429
2452
|
: ''
|
|
@@ -2446,7 +2469,7 @@ export default {
|
|
|
2446
2469
|
this.aiTranscript = []
|
|
2447
2470
|
this.anchoredUserTurnId = null
|
|
2448
2471
|
}
|
|
2449
|
-
this.setSearchResults({ pages: [], files: [], groups: [] })
|
|
2472
|
+
this.setSearchResults({ pages: [], files: [], groups: [], people: [] })
|
|
2450
2473
|
},
|
|
2451
2474
|
|
|
2452
2475
|
async clearInput() {
|
|
@@ -2460,7 +2483,7 @@ export default {
|
|
|
2460
2483
|
await this.clearSearchState()
|
|
2461
2484
|
this.currentTab = 'Answers'
|
|
2462
2485
|
this.persistSearchState(null)
|
|
2463
|
-
|
|
2486
|
+
this.syncSearchState({ hasSubmitted: false, text: '' })
|
|
2464
2487
|
this.lastRestoredSearchKey = ''
|
|
2465
2488
|
|
|
2466
2489
|
this.$nextTick(() => {
|
|
@@ -2551,8 +2574,11 @@ export default {
|
|
|
2551
2574
|
async searchFilesWithGroupOwners(options = {}) {
|
|
2552
2575
|
const runId = options.runId || this.searchRunId
|
|
2553
2576
|
const groupsPromise = this.searchGroups({ runId })
|
|
2577
|
+
const peoplePromise = this.searchPeople({ runId })
|
|
2554
2578
|
await this.searchFiles({ runId })
|
|
2555
2579
|
if (!this.isCurrentSearchRun(runId)) return []
|
|
2580
|
+
await peoplePromise
|
|
2581
|
+
if (!this.isCurrentSearchRun(runId)) return []
|
|
2556
2582
|
const ownerFilters = await groupsPromise
|
|
2557
2583
|
if (!this.isCurrentSearchRun(runId)) return ownerFilters
|
|
2558
2584
|
if (ownerFilters.length > 0) {
|
|
@@ -2593,6 +2619,32 @@ export default {
|
|
|
2593
2619
|
)
|
|
2594
2620
|
},
|
|
2595
2621
|
|
|
2622
|
+
async searchPeople(options = {}) {
|
|
2623
|
+
const runId = options.runId || this.searchRunId
|
|
2624
|
+
const searchInput = {
|
|
2625
|
+
keywords: this.keywords,
|
|
2626
|
+
question: this.searchQuestion || this.inputText,
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2629
|
+
this.searchingPeople = true
|
|
2630
|
+
try {
|
|
2631
|
+
let people = []
|
|
2632
|
+
try {
|
|
2633
|
+
people = await this.queryPeopleWithFallback(searchInput)
|
|
2634
|
+
} catch (error) {
|
|
2635
|
+
people = []
|
|
2636
|
+
}
|
|
2637
|
+
if (!this.isCurrentSearchRun(runId)) return this.currentPeople
|
|
2638
|
+
this.setSearchResults({ people })
|
|
2639
|
+
this.persistSearchCacheSnapshot()
|
|
2640
|
+
return this.currentPeople
|
|
2641
|
+
} finally {
|
|
2642
|
+
if (this.isCurrentSearchRun(runId)) {
|
|
2643
|
+
this.searchingPeople = false
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2646
|
+
},
|
|
2647
|
+
|
|
2596
2648
|
async onSubmitInput() {
|
|
2597
2649
|
if (this.searchingAi) return
|
|
2598
2650
|
const text = (this.inputText || '').trim()
|
|
@@ -2602,7 +2654,7 @@ export default {
|
|
|
2602
2654
|
this.searchMode = ''
|
|
2603
2655
|
await this.clearSearchState()
|
|
2604
2656
|
this.persistSearchState(null)
|
|
2605
|
-
|
|
2657
|
+
this.syncSearchState({ hasSubmitted: false, text: '' })
|
|
2606
2658
|
this.lastRestoredSearchKey = ''
|
|
2607
2659
|
this.$nextTick(() => {
|
|
2608
2660
|
this.suppressAutoRestore = false
|
|
@@ -2617,7 +2669,7 @@ export default {
|
|
|
2617
2669
|
this.searchMode = mode
|
|
2618
2670
|
|
|
2619
2671
|
if (mode === 'question') {
|
|
2620
|
-
this.
|
|
2672
|
+
this.syncSearchState({ text, mode, tab: 'Answers' })
|
|
2621
2673
|
this.searchAi(text)
|
|
2622
2674
|
} else {
|
|
2623
2675
|
await this.clearSearchState()
|
|
@@ -2629,7 +2681,7 @@ export default {
|
|
|
2629
2681
|
this.searchFilesWithGroupOwners({ runId })
|
|
2630
2682
|
if (!this.isCurrentSearchRun(runId)) return
|
|
2631
2683
|
this.currentTab = 'Pages'
|
|
2632
|
-
this.
|
|
2684
|
+
this.syncSearchState({ text, mode, tab: 'Pages' })
|
|
2633
2685
|
this.$nextTick(() => this.refreshResultsScrollLayer())
|
|
2634
2686
|
|
|
2635
2687
|
// Log keyword-only search analytics
|
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
:pages="searchPages"
|
|
14
14
|
:files="searchFiles"
|
|
15
15
|
:groups="searchGroups"
|
|
16
|
+
:people="searchPeople"
|
|
16
17
|
:include-district-results="includeDistrictResults"
|
|
17
18
|
:search-language-code="searchLanguageCode"
|
|
18
19
|
:query-pages-handler="queryPagesHandler"
|
|
19
20
|
:query-files-handler="queryFilesHandler"
|
|
20
21
|
:query-groups-handler="queryGroupsHandler"
|
|
22
|
+
:query-people-handler="queryPeopleHandler"
|
|
21
23
|
:query-ai-site-handler="queryAiSiteHandler"
|
|
22
24
|
:organization="organization"
|
|
23
25
|
:organization-options="organizationOptions"
|
|
@@ -65,11 +67,13 @@
|
|
|
65
67
|
:pages="searchPages"
|
|
66
68
|
:files="searchFiles"
|
|
67
69
|
:groups="searchGroups"
|
|
70
|
+
:people="searchPeople"
|
|
68
71
|
:include-district-results="includeDistrictResults"
|
|
69
72
|
:search-language-code="searchLanguageCode"
|
|
70
73
|
:query-pages-handler="queryPagesHandler"
|
|
71
74
|
:query-files-handler="queryFilesHandler"
|
|
72
75
|
:query-groups-handler="queryGroupsHandler"
|
|
76
|
+
:query-people-handler="queryPeopleHandler"
|
|
73
77
|
:query-ai-site-handler="queryAiSiteHandler"
|
|
74
78
|
:organization="organization"
|
|
75
79
|
:organization-options="organizationOptions"
|
|
@@ -221,11 +225,13 @@ export default {
|
|
|
221
225
|
searchPages: { type: Array, default: () => [] },
|
|
222
226
|
searchFiles: { type: Array, default: () => [] },
|
|
223
227
|
searchGroups: { type: Array, default: () => [] },
|
|
228
|
+
searchPeople: { type: Array, default: () => [] },
|
|
224
229
|
includeDistrictResults: { type: Boolean, default: true },
|
|
225
230
|
searchLanguageCode: { type: String, default: null },
|
|
226
231
|
queryPagesHandler: { type: Function, default: null },
|
|
227
232
|
queryFilesHandler: { type: Function, default: null },
|
|
228
233
|
queryGroupsHandler: { type: Function, default: null },
|
|
234
|
+
queryPeopleHandler: { type: Function, default: null },
|
|
229
235
|
queryAiSiteHandler: { type: Function, default: null },
|
|
230
236
|
aiSearchFeedbackFormUrl: { type: String, default: '' },
|
|
231
237
|
},
|
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
:pages="searchPages"
|
|
14
14
|
:files="searchFiles"
|
|
15
15
|
:groups="searchGroups"
|
|
16
|
+
:people="searchPeople"
|
|
16
17
|
:include-district-results="includeDistrictResults"
|
|
17
18
|
:search-language-code="searchLanguageCode"
|
|
18
19
|
:query-pages-handler="queryPagesHandler"
|
|
19
20
|
:query-files-handler="queryFilesHandler"
|
|
20
21
|
:query-groups-handler="queryGroupsHandler"
|
|
22
|
+
:query-people-handler="queryPeopleHandler"
|
|
21
23
|
:query-ai-site-handler="queryAiSiteHandler"
|
|
22
24
|
:organization-options="organizationOptions"
|
|
23
25
|
:organization="organization"
|
|
@@ -109,11 +111,13 @@
|
|
|
109
111
|
:pages="searchPages"
|
|
110
112
|
:files="searchFiles"
|
|
111
113
|
:groups="searchGroups"
|
|
114
|
+
:people="searchPeople"
|
|
112
115
|
:include-district-results="includeDistrictResults"
|
|
113
116
|
:search-language-code="searchLanguageCode"
|
|
114
117
|
:query-pages-handler="queryPagesHandler"
|
|
115
118
|
:query-files-handler="queryFilesHandler"
|
|
116
119
|
:query-groups-handler="queryGroupsHandler"
|
|
120
|
+
:query-people-handler="queryPeopleHandler"
|
|
117
121
|
:query-ai-site-handler="queryAiSiteHandler"
|
|
118
122
|
:organization="organization"
|
|
119
123
|
:organization-options="organizationOptions"
|
|
@@ -234,11 +238,13 @@ export default {
|
|
|
234
238
|
searchPages: { type: Array, default: () => [] },
|
|
235
239
|
searchFiles: { type: Array, default: () => [] },
|
|
236
240
|
searchGroups: { type: Array, default: () => [] },
|
|
241
|
+
searchPeople: { type: Array, default: () => [] },
|
|
237
242
|
includeDistrictResults: { type: Boolean, default: true },
|
|
238
243
|
searchLanguageCode: { type: String, default: null },
|
|
239
244
|
queryPagesHandler: { type: Function, default: null },
|
|
240
245
|
queryFilesHandler: { type: Function, default: null },
|
|
241
246
|
queryGroupsHandler: { type: Function, default: null },
|
|
247
|
+
queryPeopleHandler: { type: Function, default: null },
|
|
242
248
|
queryAiSiteHandler: { type: Function, default: null },
|
|
243
249
|
aiSearchFeedbackFormUrl: { type: String, default: '' },
|
|
244
250
|
},
|
|
@@ -13,11 +13,13 @@
|
|
|
13
13
|
:pages="searchPages"
|
|
14
14
|
:files="searchFiles"
|
|
15
15
|
:groups="searchGroups"
|
|
16
|
+
:people="searchPeople"
|
|
16
17
|
:include-district-results="includeDistrictResults"
|
|
17
18
|
:search-language-code="searchLanguageCode"
|
|
18
19
|
:query-pages-handler="queryPagesHandler"
|
|
19
20
|
:query-files-handler="queryFilesHandler"
|
|
20
21
|
:query-groups-handler="queryGroupsHandler"
|
|
22
|
+
:query-people-handler="queryPeopleHandler"
|
|
21
23
|
:query-ai-site-handler="queryAiSiteHandler"
|
|
22
24
|
:organization="organization"
|
|
23
25
|
:organization-options="organizationOptions"
|
|
@@ -110,11 +112,13 @@
|
|
|
110
112
|
:pages="searchPages"
|
|
111
113
|
:files="searchFiles"
|
|
112
114
|
:groups="searchGroups"
|
|
115
|
+
:people="searchPeople"
|
|
113
116
|
:include-district-results="includeDistrictResults"
|
|
114
117
|
:search-language-code="searchLanguageCode"
|
|
115
118
|
:query-pages-handler="queryPagesHandler"
|
|
116
119
|
:query-files-handler="queryFilesHandler"
|
|
117
120
|
:query-groups-handler="queryGroupsHandler"
|
|
121
|
+
:query-people-handler="queryPeopleHandler"
|
|
118
122
|
:query-ai-site-handler="queryAiSiteHandler"
|
|
119
123
|
:organization="organization"
|
|
120
124
|
:organization-options="organizationOptions"
|
|
@@ -239,11 +243,13 @@ export default {
|
|
|
239
243
|
searchPages: { type: Array, default: () => [] },
|
|
240
244
|
searchFiles: { type: Array, default: () => [] },
|
|
241
245
|
searchGroups: { type: Array, default: () => [] },
|
|
246
|
+
searchPeople: { type: Array, default: () => [] },
|
|
242
247
|
includeDistrictResults: { type: Boolean, default: true },
|
|
243
248
|
searchLanguageCode: { type: String, default: null },
|
|
244
249
|
queryPagesHandler: { type: Function, default: null },
|
|
245
250
|
queryFilesHandler: { type: Function, default: null },
|
|
246
251
|
queryGroupsHandler: { type: Function, default: null },
|
|
252
|
+
queryPeopleHandler: { type: Function, default: null },
|
|
247
253
|
queryAiSiteHandler: { type: Function, default: null },
|
|
248
254
|
aiSearchFeedbackFormUrl: { type: String, default: '' },
|
|
249
255
|
},
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import axios from 'axios'
|
|
2
|
+
|
|
3
|
+
import { hasSearchProxyRuntime, resolveSearchProxyUrl } from './searchProxyUrl'
|
|
4
|
+
import { normalizeBaseUrl, resolveRuntimeConfigValue } from './runtimeConfig'
|
|
5
|
+
|
|
6
|
+
function searchPayload({ keywords = '', top = 10 }) {
|
|
7
|
+
const trimmedKeywords = keywords.trim()
|
|
8
|
+
const terms = trimmedKeywords.split(/\s+/).filter(Boolean)
|
|
9
|
+
const expandedTerms = terms
|
|
10
|
+
.map(term => `displayName:${term}* OR email:${term}*`)
|
|
11
|
+
.join(' OR ')
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
count: true,
|
|
15
|
+
queryType: 'full',
|
|
16
|
+
search: trimmedKeywords
|
|
17
|
+
? `"${trimmedKeywords}"${expandedTerms ? ` OR ${expandedTerms}` : ''}`
|
|
18
|
+
: '*',
|
|
19
|
+
top,
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default async function queryPeople({
|
|
24
|
+
keywords = '',
|
|
25
|
+
top = 10,
|
|
26
|
+
limit = 0,
|
|
27
|
+
requireKeywords = true,
|
|
28
|
+
indexName = 'people-index',
|
|
29
|
+
requestUrl = '',
|
|
30
|
+
runtimeConfig = null,
|
|
31
|
+
searchKey = '',
|
|
32
|
+
apiVersion = '',
|
|
33
|
+
searchEndpoint = '',
|
|
34
|
+
endpoint = '',
|
|
35
|
+
}) {
|
|
36
|
+
if (!keywords && requireKeywords) {
|
|
37
|
+
return {
|
|
38
|
+
people: [],
|
|
39
|
+
facets: [],
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const resolvedLimit = Number.isFinite(Number(limit)) && Number(limit) > 0
|
|
44
|
+
? Number(limit)
|
|
45
|
+
: top
|
|
46
|
+
const resolvedSearchKey = resolveRuntimeConfigValue({
|
|
47
|
+
explicitValue: searchKey,
|
|
48
|
+
runtimeConfig,
|
|
49
|
+
runtimeConfigKeys: ['azureSearchKey'],
|
|
50
|
+
envKeys: [
|
|
51
|
+
'AZURE_SEARCH_KEY',
|
|
52
|
+
'VUE_APP_AZURE_SEARCH_KEY',
|
|
53
|
+
'GRIDSOME_AZURE_SEARCH_KEY',
|
|
54
|
+
],
|
|
55
|
+
})
|
|
56
|
+
const resolvedApiVersion = resolveRuntimeConfigValue({
|
|
57
|
+
explicitValue: apiVersion,
|
|
58
|
+
runtimeConfig,
|
|
59
|
+
runtimeConfigKeys: ['azureSearchVersion'],
|
|
60
|
+
envKeys: [
|
|
61
|
+
'AZURE_SEARCH_VERSION',
|
|
62
|
+
'VUE_APP_AZURE_SEARCH_API_VERSION',
|
|
63
|
+
'GRIDSOME_AZURE_SEARCH_API_VERSION',
|
|
64
|
+
],
|
|
65
|
+
})
|
|
66
|
+
const resolvedSearchEndpoint = resolveRuntimeConfigValue({
|
|
67
|
+
explicitValue: searchEndpoint || endpoint,
|
|
68
|
+
runtimeConfig,
|
|
69
|
+
runtimeConfigKeys: ['azureSearchEndpoint'],
|
|
70
|
+
envKeys: [
|
|
71
|
+
'AZURE_SEARCH_ENDPOINT',
|
|
72
|
+
'VUE_APP_AZURE_SEARCH_ENDPOINT',
|
|
73
|
+
'GRIDSOME_AZURE_SEARCH_ENDPOINT',
|
|
74
|
+
],
|
|
75
|
+
})
|
|
76
|
+
const resolvedRequestUrl =
|
|
77
|
+
typeof requestUrl === 'string' && requestUrl.trim()
|
|
78
|
+
? requestUrl.trim()
|
|
79
|
+
: !resolvedSearchEndpoint &&
|
|
80
|
+
hasSearchProxyRuntime(runtimeConfig)
|
|
81
|
+
? resolveSearchProxyUrl('people', runtimeConfig)
|
|
82
|
+
: ''
|
|
83
|
+
|
|
84
|
+
if (
|
|
85
|
+
!resolvedRequestUrl &&
|
|
86
|
+
(!resolvedSearchEndpoint || !resolvedSearchKey || !resolvedApiVersion)
|
|
87
|
+
) {
|
|
88
|
+
throw new Error('Azure Search or proxy configuration is required for queryPeople.')
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const payload = {
|
|
92
|
+
keywords,
|
|
93
|
+
limit: resolvedLimit,
|
|
94
|
+
indexName,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const { data } = resolvedRequestUrl
|
|
98
|
+
? await axios({
|
|
99
|
+
method: 'post',
|
|
100
|
+
url: resolvedRequestUrl,
|
|
101
|
+
data: payload,
|
|
102
|
+
})
|
|
103
|
+
: await axios({
|
|
104
|
+
method: 'post',
|
|
105
|
+
headers: {
|
|
106
|
+
'api-key': resolvedSearchKey,
|
|
107
|
+
},
|
|
108
|
+
params: {
|
|
109
|
+
'api-version': resolvedApiVersion,
|
|
110
|
+
},
|
|
111
|
+
url: `${normalizeBaseUrl(resolvedSearchEndpoint)}/indexes/${indexName}/docs/search`,
|
|
112
|
+
data: searchPayload({
|
|
113
|
+
keywords,
|
|
114
|
+
top: resolvedLimit,
|
|
115
|
+
}),
|
|
116
|
+
})
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
people: Array.isArray(data.value) ? data.value : [],
|
|
120
|
+
facets: data['@search.facets'],
|
|
121
|
+
}
|
|
122
|
+
}
|