Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
85593b3
Add error handling utilities
cotti Nov 4, 2025
3ad6fa6
Show more specific errors when needed
cotti Nov 4, 2025
3b625bf
Merge branch 'main' into feature/soa_error_handling
cotti Nov 4, 2025
69193d5
Improve error display on AskAi, and interrupt streams when rate limit…
cotti Nov 4, 2025
246c2a8
Improve CallOut behavior between tabs
cotti Nov 4, 2025
58180cb
Move custom Callout to its own component
cotti Nov 5, 2025
3d97e1f
Fix state issues
cotti Nov 5, 2025
5852ae9
Fix some more state quirks
cotti Nov 5, 2025
94af4cc
Remove unused parameter
cotti Nov 5, 2025
798595e
Clean ups
cotti Nov 5, 2025
10533b4
More clean ups
cotti Nov 5, 2025
ccbc85f
Cleanup
cotti Nov 5, 2025
53af01b
Merge branch 'refs/heads/main' into feature/soa_error_handling
cotti Nov 5, 2025
0faa9dc
Remove useCallback()
cotti Nov 5, 2025
2cd2b55
Refactor ErrorCallout state management to use modal store. Remove non…
cotti Nov 5, 2025
b40457b
Lint fixes
cotti Nov 5, 2025
9df7113
Reduce duplication in modalStore, lint
cotti Nov 5, 2025
8b8059e
Fix tests
cotti Nov 5, 2025
b06b579
Add test suite for SearchOrAskAiErrorCallout
cotti Nov 5, 2025
5711fdb
Move state into hooks and perform fixes
cotti Nov 6, 2025
4851554
Fix partial change
cotti Nov 6, 2025
ee2a54f
Cooldown should keep decrementing when moving between tabs
cotti Nov 7, 2025
08ac3c0
Disable sending rogue chat requests from search during chat cooldown
cotti Nov 7, 2025
1e024a4
Move ratelimithandler
cotti Nov 7, 2025
bf9564f
Add cancellation
cotti Nov 7, 2025
c59d6d3
Merge branch 'main' into feature/soa_error_handling
cotti Nov 7, 2025
8f152b9
Fix a few state quirks
cotti Nov 7, 2025
617b8cc
Adjust file name
cotti Nov 7, 2025
8cadcf0
Lint
cotti Nov 7, 2025
7582b50
Missed lint
cotti Nov 7, 2025
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
6 changes: 6 additions & 0 deletions src/Elastic.Documentation.Site/Assets/eui-icons-cache.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-nocheck: EUI icons do not have types
import { icon as EuiIconVisualizeApp } from '@elastic/eui/es/components/icon/assets/app_visualize'
import { icon as EuiIconArrowEnd } from '@elastic/eui/es/components/icon/assets/arrowEnd'
import { icon as EuiIconArrowStart } from '@elastic/eui/es/components/icon/assets/arrowStart'
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 EuiIconCheck } from '@elastic/eui/es/components/icon/assets/check'
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'
import { icon as EuiIconCross } from '@elastic/eui/es/components/icon/assets/cross'
Expand Down Expand Up @@ -59,4 +62,7 @@ appendIconComponentCache({
copy: EuiIconCopy,
play: EuiIconPlay,
sortUp: EuiIconSortUp,
arrowStart: EuiIconArrowStart,
arrowEnd: EuiIconArrowEnd,
comment: EuiIconComment,
})
32 changes: 32 additions & 0 deletions src/Elastic.Documentation.Site/Assets/modal.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,35 @@
@apply text-ink-dark hover:text-ink text-2xl font-bold no-underline;
}
}

/* Search or Ask AI animation for secondary buttons */

@keyframes slideInFromRight {
from {
right: 8px;
opacity: 0;
}
to {
right: 40px;
opacity: 1;
}
}

@keyframes slideOutToRight {
from {
right: 40px;
opacity: 1;
}
to {
right: 8px;
opacity: 0;
}
}

.slideInSearchOrAskAiInputAnimation {
animation: slideInFromRight 0.2s ease-out forwards;
}

.slideOutSearchOrAskAiInputAnimation {
animation: slideOutToRight 0.2s ease-out forwards;
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ const ALL_SUGGESTIONS: AskAiSuggestion[] = [
},
]

export const AskAiSuggestions = () => {
export const AskAiSuggestions = ({ disabled }: { disabled?: boolean }) => {
const { submitQuestion } = useChatActions()
const { setModalMode } = useModalActions()
const { euiTheme } = useEuiTheme()
Expand All @@ -64,9 +64,12 @@ export const AskAiSuggestions = () => {
fullWidth
size="s"
onClick={() => {
submitQuestion(suggestion.question)
setModalMode('askAi')
if (!disabled) {
submitQuestion(suggestion.question)
setModalMode('askAi')
}
}}
disabled={disabled}
>
{suggestion.question}
</EuiButton>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ jest.mock('./chat.store', () => ({
useChatActions: jest.fn(() => ({
submitQuestion: jest.fn(),
clearChat: jest.fn(),
clearNon429Errors: jest.fn(),
setAiProvider: jest.fn(),
})),
}))
Expand All @@ -29,6 +30,44 @@ jest.mock('./AskAiSuggestions', () => ({
),
}))

// Mock AiProviderSelector
jest.mock('./AiProviderSelector', () => ({
AiProviderSelector: () => (
<div data-testid="ai-provider-selector">Provider Selector</div>
),
}))

// Mock modal.store
jest.mock('../modal.store', () => ({
useModalActions: jest.fn(() => ({
setModalMode: jest.fn(),
openModal: jest.fn(),
closeModal: jest.fn(),
toggleModal: jest.fn(),
})),
}))

// Mock cooldown hooks
jest.mock('./useAskAiCooldown', () => ({
useIsAskAiCooldownActive: jest.fn(() => false),
useAskAiCooldown: jest.fn(() => null),
useAskAiCooldownActions: jest.fn(() => ({
setCooldown: jest.fn(),
updateCooldown: jest.fn(),
notifyCooldownFinished: jest.fn(),
acknowledgeCooldownFinished: jest.fn(),
})),
}))

jest.mock('../useCooldown', () => ({
useCooldown: jest.fn(),
}))

// Mock SearchOrAskAiErrorCallout
jest.mock('../SearchOrAskAiErrorCallout', () => ({
SearchOrAskAiErrorCallout: () => null,
}))

const mockUseChatMessages = jest.mocked(
jest.requireMock('./chat.store').useChatMessages
)
Expand All @@ -39,12 +78,14 @@ const mockUseChatActions = jest.mocked(
describe('Chat Component', () => {
const mockSubmitQuestion = jest.fn()
const mockClearChat = jest.fn()
const mockClearNon429Errors = jest.fn()

beforeEach(() => {
jest.clearAllMocks()
mockUseChatActions.mockReturnValue({
submitQuestion: mockSubmitQuestion,
clearChat: mockClearChat,
clearNon429Errors: mockClearNon429Errors,
})
})

Expand Down Expand Up @@ -196,7 +237,9 @@ describe('Chat Component', () => {
/Ask Elastic Docs AI Assistant/i
)
await user.type(input, question)
await user.click(screen.getByRole('button', { name: /send/i }))
await user.click(
screen.getByRole('button', { name: /send message/i })
)

// Assert
expect(mockSubmitQuestion).toHaveBeenCalledWith(question)
Expand Down
Loading
Loading