Skip to content

Commit 8fcd779

Browse files
authored
Add legal disclaimer and reposition empty chat components (#2380)
* Add legal disclaimer and reposition empty chat components * Add link to General Privacy Statement
1 parent 14bb01f commit 8fcd779

File tree

6 files changed

+169
-113
lines changed

6 files changed

+169
-113
lines changed

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

Lines changed: 35 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { useModalActions } from '../modal.store'
22
import { useChatActions } from './chat.store'
3-
import { EuiButton, useEuiTheme } from '@elastic/eui'
3+
import { useIsAskAiCooldownActive } from './useAskAiCooldown'
4+
import { EuiButton, EuiText, useEuiTheme, EuiSpacer } from '@elastic/eui'
45
import { css } from '@emotion/react'
5-
import * as React from 'react'
66
import { useMemo } from 'react'
77

88
export interface AskAiSuggestion {
@@ -37,9 +37,10 @@ const ALL_SUGGESTIONS: AskAiSuggestion[] = [
3737
},
3838
]
3939

40-
export const AskAiSuggestions = ({ disabled }: { disabled?: boolean }) => {
40+
export const AskAiSuggestions = () => {
4141
const { submitQuestion } = useChatActions()
4242
const { setModalMode } = useModalActions()
43+
const disabled = useIsAskAiCooldownActive()
4344
const { euiTheme } = useEuiTheme()
4445

4546
// Randomly select 3 questions from the comprehensive list
@@ -50,29 +51,37 @@ export const AskAiSuggestions = ({ disabled }: { disabled?: boolean }) => {
5051
}, [])
5152

5253
return (
53-
<ul>
54-
{selectedSuggestions.map((suggestion) => (
55-
<li
56-
key={suggestion.question}
57-
css={css`
58-
margin-bottom: ${euiTheme.size.s};
59-
`}
60-
>
61-
<EuiButton
62-
color="text"
63-
size="s"
64-
onClick={() => {
65-
if (!disabled) {
66-
submitQuestion(suggestion.question)
67-
setModalMode('askAi')
68-
}
69-
}}
70-
disabled={disabled}
54+
<div
55+
css={css`
56+
padding-inline: ${euiTheme.size.base};
57+
`}
58+
>
59+
<EuiSpacer size="m" />
60+
<EuiText size="xs">Example questions:</EuiText>
61+
<ul>
62+
{selectedSuggestions.map((suggestion) => (
63+
<li
64+
key={suggestion.question}
65+
css={css`
66+
margin-top: ${euiTheme.size.s};
67+
`}
7168
>
72-
{suggestion.question}
73-
</EuiButton>
74-
</li>
75-
))}
76-
</ul>
69+
<EuiButton
70+
color="text"
71+
size="s"
72+
onClick={() => {
73+
if (!disabled) {
74+
submitQuestion(suggestion.question)
75+
setModalMode('askAi')
76+
}
77+
}}
78+
disabled={disabled}
79+
>
80+
{suggestion.question}
81+
</EuiButton>
82+
</li>
83+
))}
84+
</ul>
85+
</div>
7786
)
7887
}

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

Lines changed: 86 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { InfoBanner } from '../InfoBanner'
22
import { KeyboardShortcutsFooter } from '../KeyboardShortcutsFooter'
3-
import { SearchOrAskAiErrorCallout } from '../SearchOrAskAiErrorCallout'
3+
import { LegalDisclaimer } from '../LegalDisclaimer'
44
import AiIcon from '../ai-icon.svg'
55
import { useModalActions } from '../modal.store'
66
import { AskAiSuggestions } from './AskAiSuggestions'
77
import { ChatInput } from './ChatInput'
88
import { ChatMessageList } from './ChatMessageList'
99
import {
10-
ChatMessage,
1110
useChatActions,
1211
useChatMessages,
1312
useChatScrollPosition,
13+
useIsChatEmpty,
1414
useIsStreaming,
1515
} from './chat.store'
1616
import { useIsAskAiCooldownActive } from './useAskAiCooldown'
@@ -22,7 +22,6 @@ import {
2222
EuiHorizontalRule,
2323
EuiIcon,
2424
EuiSpacer,
25-
EuiText,
2625
EuiToolTip,
2726
useEuiFontSize,
2827
useEuiOverflowScroll,
@@ -32,7 +31,8 @@ import { css } from '@emotion/react'
3231
import { RefObject, useCallback, useEffect, useRef, useState } from 'react'
3332

3433
export const Chat = () => {
35-
const messages = useChatMessages()
34+
const { euiTheme } = useEuiTheme()
35+
const isEmpty = useIsChatEmpty()
3636
const inputRef = useRef<HTMLTextAreaElement>(null)
3737
const scrollRef = useRef<HTMLDivElement>(null)
3838

@@ -44,15 +44,11 @@ export const Chat = () => {
4444
inputRef.current?.focus()
4545
}, [])
4646

47-
const {
48-
inputValue,
49-
setInputValue,
50-
handleSubmit,
51-
handleAbort,
52-
handleAbortReady,
53-
isStreaming,
54-
isCooldownActive,
55-
} = useChatSubmit(scrollRef)
47+
const [scrollAreaProps, setScrollAreaProps] = useState<{
48+
onAbortReady: (abort: () => void) => void
49+
}>({
50+
onAbortReady: () => {},
51+
})
5652

5753
return (
5854
<EuiFlexGroup
@@ -62,26 +58,51 @@ export const Chat = () => {
6258
>
6359
<ChatHeader />
6460

65-
<ChatScrollArea
66-
scrollRef={scrollRef}
67-
onScroll={handleScroll}
68-
messages={messages}
69-
isCooldownActive={isCooldownActive}
70-
onAbortReady={handleAbortReady}
71-
/>
61+
{isEmpty ? (
62+
<EuiFlexItem grow={true} css={emptyStateContainerStyles}>
63+
<EuiEmptyPrompt
64+
icon={<EuiIcon type={AiIcon} size="xxl" />}
65+
title={<h2>Hi! I'm the Elastic Docs AI Assistant</h2>}
66+
body={
67+
<p>
68+
I'm here to help you find answers about Elastic,
69+
powered entirely by our technical documentation.
70+
How can I help?
71+
</p>
72+
}
73+
/>
74+
</EuiFlexItem>
75+
) : (
76+
<ChatScrollArea
77+
scrollRef={scrollRef}
78+
onScroll={handleScroll}
79+
onAbortReady={scrollAreaProps.onAbortReady}
80+
/>
81+
)}
7282

7383
<ChatInputArea
7484
inputRef={inputRef}
75-
value={inputValue}
76-
onChange={setInputValue}
77-
onSubmit={handleSubmit}
78-
onAbort={handleAbort}
79-
disabled={isCooldownActive}
80-
isStreaming={isStreaming}
85+
scrollRef={scrollRef}
8186
onMetaSemicolon={handleMetaSemicolon}
87+
onStateChange={setScrollAreaProps}
8288
/>
8389

90+
{isEmpty && (
91+
<>
92+
<AskAiSuggestions />
93+
<EuiSpacer size="m" />
94+
<div
95+
css={css`
96+
padding-inline: ${euiTheme.size.base};
97+
`}
98+
>
99+
<LegalDisclaimer />
100+
</div>
101+
</>
102+
)}
103+
84104
<InfoBanner />
105+
85106
<KeyboardShortcutsFooter shortcuts={KEYBOARD_SHORTCUTS} />
86107
</EuiFlexGroup>
87108
)
@@ -154,18 +175,15 @@ const ChatHeader = () => {
154175
interface ChatScrollAreaProps {
155176
scrollRef: RefObject<HTMLDivElement>
156177
onScroll: () => void
157-
messages: ChatMessage[]
158-
isCooldownActive: boolean
159178
onAbortReady: (abort: () => void) => void
160179
}
161180

162181
const ChatScrollArea = ({
163182
scrollRef,
164183
onScroll,
165-
messages,
166-
isCooldownActive,
167184
onAbortReady,
168185
}: ChatScrollAreaProps) => {
186+
const messages = useChatMessages()
169187
const { euiTheme } = useEuiTheme()
170188

171189
const scrollableStyles = css`
@@ -179,69 +197,48 @@ const ChatScrollArea = ({
179197
return (
180198
<EuiFlexItem grow={true} css={scrollContainerStyles}>
181199
<div ref={scrollRef} css={scrollableStyles} onScroll={onScroll}>
182-
{messages.length === 0 ? (
183-
<ChatEmptyState disabled={isCooldownActive} />
184-
) : (
185-
<div css={messagesStyles}>
186-
<ChatMessageList
187-
messages={messages}
188-
onAbortReady={onAbortReady}
189-
/>
190-
</div>
191-
)}
200+
<div css={messagesStyles}>
201+
<ChatMessageList
202+
messages={messages}
203+
onAbortReady={onAbortReady}
204+
/>
205+
</div>
192206
</div>
193207
</EuiFlexItem>
194208
)
195209
}
196210

197-
const ChatEmptyState = ({ disabled }: { disabled: boolean }) => (
198-
<>
199-
<EuiEmptyPrompt
200-
icon={<EuiIcon type={AiIcon} size="xxl" />}
201-
title={<h2>Hi! I'm the Elastic Docs AI Assistant</h2>}
202-
body={
203-
<p>
204-
I'm here to help you find answers about Elastic, powered
205-
entirely by our technical documentation. How can I help?
206-
</p>
207-
}
208-
/>
209-
<EuiSpacer size="s" />
210-
<div>
211-
<EuiText size="xs" color="subdued">
212-
Example questions
213-
</EuiText>
214-
<EuiSpacer size="s" />
215-
<AskAiSuggestions disabled={disabled} />
216-
</div>
217-
<div css={messagesStyles}>
218-
<SearchOrAskAiErrorCallout error={null} domain="askAi" />
219-
</div>
220-
</>
221-
)
222-
223211
interface ChatInputAreaProps {
224212
inputRef: RefObject<HTMLTextAreaElement>
225-
value: string
226-
onChange: (value: string) => void
227-
onSubmit: (question: string) => void
228-
onAbort: () => void
229-
disabled: boolean
230-
isStreaming: boolean
213+
scrollRef: RefObject<HTMLDivElement>
231214
onMetaSemicolon?: () => void
215+
onStateChange?: (state: {
216+
onAbortReady: (abort: () => void) => void
217+
}) => void
232218
}
233219

234220
const ChatInputArea = ({
235221
inputRef,
236-
value,
237-
onChange,
238-
onSubmit,
239-
onAbort,
240-
disabled,
241-
isStreaming,
222+
scrollRef,
242223
onMetaSemicolon,
224+
onStateChange,
243225
}: ChatInputAreaProps) => {
244226
const { euiTheme } = useEuiTheme()
227+
const {
228+
inputValue,
229+
setInputValue,
230+
handleSubmit,
231+
handleAbort,
232+
handleAbortReady,
233+
isStreaming,
234+
isCooldownActive,
235+
} = useChatSubmit(scrollRef)
236+
237+
useEffect(() => {
238+
onStateChange?.({
239+
onAbortReady: handleAbortReady,
240+
})
241+
}, [handleAbortReady, onStateChange])
245242

246243
return (
247244
<EuiFlexItem grow={false}>
@@ -253,11 +250,11 @@ const ChatInputArea = ({
253250
`}
254251
>
255252
<ChatInput
256-
value={value}
257-
onChange={onChange}
258-
onSubmit={onSubmit}
259-
onAbort={onAbort}
260-
disabled={disabled}
253+
value={inputValue}
254+
onChange={setInputValue}
255+
onSubmit={handleSubmit}
256+
onAbort={handleAbort}
257+
disabled={isCooldownActive}
261258
inputRef={inputRef}
262259
isStreaming={isStreaming}
263260
onMetaSemicolon={onMetaSemicolon}
@@ -394,6 +391,12 @@ const scrollContainerStyles = css`
394391
overflow: hidden;
395392
`
396393

394+
const emptyStateContainerStyles = css`
395+
display: flex;
396+
align-items: center;
397+
justify-content: center;
398+
`
399+
397400
const messagesStyles = css`
398401
max-width: 800px;
399402
margin: 0 auto;

src/Elastic.Documentation.Site/Assets/web-components/SearchOrAskAi/AskAi/chat.store.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,3 +434,5 @@ export const useIsStreaming = () =>
434434
const last = state.chatMessages[state.chatMessages.length - 1]
435435
return last?.type === 'ai' && last?.status === 'streaming'
436436
})
437+
export const useIsChatEmpty = () =>
438+
chatStore((state) => state.chatMessages.length === 0)

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,16 @@ export const InfoBanner = () => {
2929
label="Alpha"
3030
size="s"
3131
color="accent"
32-
tooltipContent="This feature is in private preview and is only enabled if you are in Elastic's Global VPN."
32+
tooltipContent="This feature is in private preview."
3333
/>
34-
34+
·
3535
<EuiText color="subdued" size="s">
36-
This feature is in private preview.{' '}
3736
<EuiLink
3837
target="_blank"
3938
rel="noopener noreferrer"
4039
href="https://github.com/elastic/docs-eng-team/issues/new?template=search-or-ask-ai-feedback.yml"
4140
>
42-
Got feedback? We'd love to hear it!
41+
Give feedback
4342
</EuiLink>
4443
</EuiText>
4544
</div>

0 commit comments

Comments
 (0)