Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/Elastic.Documentation.Site/Assets/eui-icons-cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import { icon as EuiIconArrowStart } from '@elastic/eui/es/components/icon/asset
import { icon as EuiIconArrowDown } from '@elastic/eui/es/components/icon/assets/arrow_down'
import { icon as EuiIconArrowLeft } from '@elastic/eui/es/components/icon/assets/arrow_left'
import { icon as EuiIconArrowRight } from '@elastic/eui/es/components/icon/assets/arrow_right'
import { icon as EuiIconArrowUp } from '@elastic/eui/es/components/icon/assets/arrow_up'
import { icon as EuiIconCheck } from '@elastic/eui/es/components/icon/assets/check'
import { icon as EuiIconCode } from '@elastic/eui/es/components/icon/assets/code'
import { icon as EuiIconComment } from '@elastic/eui/es/components/icon/assets/comment'
import { icon as EuiIconCopy } from '@elastic/eui/es/components/icon/assets/copy'
import { icon as EuiIconCopyClipboard } from '@elastic/eui/es/components/icon/assets/copy_clipboard'
Expand All @@ -24,6 +26,7 @@ import { icon as EuiIconPopout } from '@elastic/eui/es/components/icon/assets/po
import { icon as EuiIconRefresh } from '@elastic/eui/es/components/icon/assets/refresh'
import { icon as EuiIconReturnKey } from '@elastic/eui/es/components/icon/assets/return_key'
import { icon as EuiIconSearch } from '@elastic/eui/es/components/icon/assets/search'
import { icon as EuiIconSortDown } from '@elastic/eui/es/components/icon/assets/sort_down'
import { icon as EuiIconSortUp } from '@elastic/eui/es/components/icon/assets/sort_up'
import { icon as EuiIconSparkles } from '@elastic/eui/es/components/icon/assets/sparkles'
import { icon as EuiIconThumbDown } from '@elastic/eui/es/components/icon/assets/thumbDown'
Expand All @@ -33,11 +36,13 @@ import { icon as EuiIconUser } from '@elastic/eui/es/components/icon/assets/user
import { icon as EuiIconWrench } from '@elastic/eui/es/components/icon/assets/wrench'
import { appendIconComponentCache } from '@elastic/eui/es/components/icon/icon'

appendIconComponentCache({
const iconMapping = {
newChat: EuiIconNewChat,
arrowUp: EuiIconArrowUp,
arrowDown: EuiIconArrowDown,
arrowLeft: EuiIconArrowLeft,
arrowRight: EuiIconArrowRight,
code: EuiIconCode,
document: EuiIconDocument,
dot: EuiIconDot,
empty: EuiIconEmpty,
Expand All @@ -62,7 +67,12 @@ appendIconComponentCache({
copy: EuiIconCopy,
play: EuiIconPlay,
sortUp: EuiIconSortUp,
sortDown: EuiIconSortDown,
arrowStart: EuiIconArrowStart,
arrowEnd: EuiIconArrowEnd,
comment: EuiIconComment,
})
}

appendIconComponentCache(iconMapping)

export const availableIcons = Object.keys(iconMapping)
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
EuiEmptyPrompt,
EuiSpacer,
EuiTitle,
useEuiTheme,
} from '@elastic/eui'
import { css } from '@emotion/react'
import { useCallback, useEffect, useRef, useState } from 'react'
Expand Down Expand Up @@ -42,7 +43,6 @@ const messagesStyles = css`
margin: 0 auto;
`

// Small helper for scroll behavior
const scrollToBottom = (container: HTMLDivElement | null) => {
if (!container) return
container.scrollTop = container.scrollHeight
Expand Down Expand Up @@ -74,6 +74,7 @@ const NewConversationHeader = ({
)

export const Chat = () => {
const { euiTheme } = useEuiTheme()
const messages = useChatMessages()
const { submitQuestion, clearChat, clearNon429Errors, cancelStreaming } =
useChatActions()
Expand All @@ -89,18 +90,15 @@ export const Chat = () => {
${useEuiOverflowScroll('y', true)}
`

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

// Handle abort function from StreamingAiMessage
const handleAbortReady = (abort: () => void) => {
const handleAbortReady = useCallback((abort: () => void) => {
abortFunctionRef.current = abort
}
}, [])

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

const handleSubmit = useCallback(
(question: string) => {
if (!question.trim()) return

// Prevent submission during countdown
if (isCooldownActive) {
const trimmedQuestion = question.trim()
if (!trimmedQuestion || isCooldownActive) {
return
}

clearNon429Errors()

submitQuestion(question.trim())
submitQuestion(trimmedQuestion)

if (inputRef.current) {
inputRef.current.value = ''
Expand Down Expand Up @@ -245,6 +240,7 @@ export const Chat = () => {
<div
css={css`
position: relative;
padding-inline: ${euiTheme.size.base};
`}
>
<EuiFieldText
Expand All @@ -266,7 +262,7 @@ export const Chat = () => {
}
css={css`
position: absolute;
right: 8px;
right: ${euiTheme.size.l};
top: 50%;
transform: translateY(-50%);
border-radius: 9999px;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import {
EuiBetaBadge,
EuiHorizontalRule,
EuiLink,
EuiText,
useEuiTheme,
} from '@elastic/eui'
import { css } from '@emotion/react'

export const InfoBanner = () => {
const { euiTheme } = useEuiTheme()
return (
<div
css={css`
padding: 0 ${euiTheme.size.base} ${euiTheme.size.base};
`}
>
<EuiHorizontalRule margin="m" />
<div
css={css`
display: flex;
align-items: center;
justify-content: center;
gap: ${euiTheme.size.s};
`}
>
<EuiBetaBadge
css={css`
display: inline-flex;
`}
label="Alpha"
color="accent"
tooltipContent="This feature is in private preview and is only enabled if you are in Elastic's Global VPN."
/>

<EuiText color="subdued" size="s">
This feature is in private preview.{' '}
<EuiLink
target="_blank"
rel="noopener noreferrer"
href="https://github.com/elastic/docs-eng-team/issues/new?template=search-or-ask-ai-feedback.yml"
>
Got feedback? We'd love to hear it!
</EuiLink>
</EuiText>
</div>
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -642,8 +642,12 @@ describe('Search Component', () => {
// Act
render(<Search />)

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

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