Skip to content

Commit 9695949

Browse files
authored
Implement latest search experience design (#2292)
* Implement latest search experience design * Fix test
1 parent 68932c1 commit 9695949

File tree

16 files changed

+652
-199
lines changed

16 files changed

+652
-199
lines changed

src/Elastic.Documentation.Site/Assets/eui-icons-cache.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import { icon as EuiIconArrowStart } from '@elastic/eui/es/components/icon/asset
66
import { icon as EuiIconArrowDown } from '@elastic/eui/es/components/icon/assets/arrow_down'
77
import { icon as EuiIconArrowLeft } from '@elastic/eui/es/components/icon/assets/arrow_left'
88
import { icon as EuiIconArrowRight } from '@elastic/eui/es/components/icon/assets/arrow_right'
9+
import { icon as EuiIconArrowUp } from '@elastic/eui/es/components/icon/assets/arrow_up'
910
import { icon as EuiIconCheck } from '@elastic/eui/es/components/icon/assets/check'
11+
import { icon as EuiIconCode } from '@elastic/eui/es/components/icon/assets/code'
1012
import { icon as EuiIconComment } from '@elastic/eui/es/components/icon/assets/comment'
1113
import { icon as EuiIconCopy } from '@elastic/eui/es/components/icon/assets/copy'
1214
import { icon as EuiIconCopyClipboard } from '@elastic/eui/es/components/icon/assets/copy_clipboard'
@@ -24,6 +26,7 @@ import { icon as EuiIconPopout } from '@elastic/eui/es/components/icon/assets/po
2426
import { icon as EuiIconRefresh } from '@elastic/eui/es/components/icon/assets/refresh'
2527
import { icon as EuiIconReturnKey } from '@elastic/eui/es/components/icon/assets/return_key'
2628
import { icon as EuiIconSearch } from '@elastic/eui/es/components/icon/assets/search'
29+
import { icon as EuiIconSortDown } from '@elastic/eui/es/components/icon/assets/sort_down'
2730
import { icon as EuiIconSortUp } from '@elastic/eui/es/components/icon/assets/sort_up'
2831
import { icon as EuiIconSparkles } from '@elastic/eui/es/components/icon/assets/sparkles'
2932
import { icon as EuiIconThumbDown } from '@elastic/eui/es/components/icon/assets/thumbDown'
@@ -33,11 +36,13 @@ import { icon as EuiIconUser } from '@elastic/eui/es/components/icon/assets/user
3336
import { icon as EuiIconWrench } from '@elastic/eui/es/components/icon/assets/wrench'
3437
import { appendIconComponentCache } from '@elastic/eui/es/components/icon/icon'
3538

36-
appendIconComponentCache({
39+
const iconMapping = {
3740
newChat: EuiIconNewChat,
41+
arrowUp: EuiIconArrowUp,
3842
arrowDown: EuiIconArrowDown,
3943
arrowLeft: EuiIconArrowLeft,
4044
arrowRight: EuiIconArrowRight,
45+
code: EuiIconCode,
4146
document: EuiIconDocument,
4247
dot: EuiIconDot,
4348
empty: EuiIconEmpty,
@@ -62,7 +67,12 @@ appendIconComponentCache({
6267
copy: EuiIconCopy,
6368
play: EuiIconPlay,
6469
sortUp: EuiIconSortUp,
70+
sortDown: EuiIconSortDown,
6571
arrowStart: EuiIconArrowStart,
6672
arrowEnd: EuiIconArrowEnd,
6773
comment: EuiIconComment,
68-
})
74+
}
75+
76+
appendIconComponentCache(iconMapping)
77+
78+
export const availableIcons = Object.keys(iconMapping)

src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/AskAi/Chat.tsx

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
EuiEmptyPrompt,
1616
EuiSpacer,
1717
EuiTitle,
18+
useEuiTheme,
1819
} from '@elastic/eui'
1920
import { css } from '@emotion/react'
2021
import { useCallback, useEffect, useRef, useState } from 'react'
@@ -42,7 +43,6 @@ const messagesStyles = css`
4243
margin: 0 auto;
4344
`
4445

45-
// Small helper for scroll behavior
4646
const scrollToBottom = (container: HTMLDivElement | null) => {
4747
if (!container) return
4848
container.scrollTop = container.scrollHeight
@@ -74,6 +74,7 @@ const NewConversationHeader = ({
7474
)
7575

7676
export const Chat = () => {
77+
const { euiTheme } = useEuiTheme()
7778
const messages = useChatMessages()
7879
const { submitQuestion, clearChat, clearNon429Errors, cancelStreaming } =
7980
useChatActions()
@@ -89,18 +90,15 @@ export const Chat = () => {
8990
${useEuiOverflowScroll('y', true)}
9091
`
9192

92-
// Check if there's an active streaming query
9393
const isStreaming =
9494
messages.length > 0 &&
9595
messages[messages.length - 1].type === 'ai' &&
9696
messages[messages.length - 1].status === 'streaming'
9797

98-
// Handle abort function from StreamingAiMessage
99-
const handleAbortReady = (abort: () => void) => {
98+
const handleAbortReady = useCallback((abort: () => void) => {
10099
abortFunctionRef.current = abort
101-
}
100+
}, [])
102101

103-
// Clear abort function when streaming ends
104102
useEffect(() => {
105103
if (!isStreaming) {
106104
abortFunctionRef.current = null
@@ -109,16 +107,13 @@ export const Chat = () => {
109107

110108
const handleSubmit = useCallback(
111109
(question: string) => {
112-
if (!question.trim()) return
113-
114-
// Prevent submission during countdown
115-
if (isCooldownActive) {
110+
const trimmedQuestion = question.trim()
111+
if (!trimmedQuestion || isCooldownActive) {
116112
return
117113
}
118114

119115
clearNon429Errors()
120-
121-
submitQuestion(question.trim())
116+
submitQuestion(trimmedQuestion)
122117

123118
if (inputRef.current) {
124119
inputRef.current.value = ''
@@ -245,6 +240,7 @@ export const Chat = () => {
245240
<div
246241
css={css`
247242
position: relative;
243+
padding-inline: ${euiTheme.size.base};
248244
`}
249245
>
250246
<EuiFieldText
@@ -266,7 +262,7 @@ export const Chat = () => {
266262
}
267263
css={css`
268264
position: absolute;
269-
right: 8px;
265+
right: ${euiTheme.size.l};
270266
top: 50%;
271267
transform: translateY(-50%);
272268
border-radius: 9999px;

src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/AskAi/highlight-worker.ts

Whitespace-only changes.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import {
2+
EuiBetaBadge,
3+
EuiHorizontalRule,
4+
EuiLink,
5+
EuiText,
6+
useEuiTheme,
7+
} from '@elastic/eui'
8+
import { css } from '@emotion/react'
9+
10+
export const InfoBanner = () => {
11+
const { euiTheme } = useEuiTheme()
12+
return (
13+
<div
14+
css={css`
15+
padding: 0 ${euiTheme.size.base} ${euiTheme.size.base};
16+
`}
17+
>
18+
<EuiHorizontalRule margin="m" />
19+
<div
20+
css={css`
21+
display: flex;
22+
align-items: center;
23+
justify-content: center;
24+
gap: ${euiTheme.size.s};
25+
`}
26+
>
27+
<EuiBetaBadge
28+
css={css`
29+
display: inline-flex;
30+
`}
31+
label="Alpha"
32+
color="accent"
33+
tooltipContent="This feature is in private preview and is only enabled if you are in Elastic's Global VPN."
34+
/>
35+
36+
<EuiText color="subdued" size="s">
37+
This feature is in private preview.{' '}
38+
<EuiLink
39+
target="_blank"
40+
rel="noopener noreferrer"
41+
href="https://github.com/elastic/docs-eng-team/issues/new?template=search-or-ask-ai-feedback.yml"
42+
>
43+
Got feedback? We'd love to hear it!
44+
</EuiLink>
45+
</EuiText>
46+
</div>
47+
</div>
48+
)
49+
}

src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/Search/Search.test.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -642,8 +642,12 @@ describe('Search Component', () => {
642642
// Act
643643
render(<Search />)
644644

645-
// Assert
646-
expect(screen.getByRole('progressbar')).toBeInTheDocument()
645+
// Assert - check that the loading spinner exists (it has aria-label="Loading" without trailing space)
646+
const progressbars = screen.getAllByRole('progressbar')
647+
const spinner = progressbars.find(
648+
(el) => el.getAttribute('aria-label') === 'Loading'
649+
)
650+
expect(spinner).toBeInTheDocument()
647651
})
648652

649653
it('should show loading spinner when isFetching is true', () => {

0 commit comments

Comments
 (0)