Skip to content

Commit 261b44d

Browse files
authored
feat: Standardize inline error messages (#4530)
1 parent c46e30d commit 261b44d

File tree

2 files changed

+67
-30
lines changed

2 files changed

+67
-30
lines changed

web/containers/ErrorMessage/index.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ describe('ErrorMessage Component', () => {
6969

7070
render(<ErrorMessage message={message} />)
7171

72-
expect(screen.getByText('troubleshooting assistance')).toBeInTheDocument()
72+
expect(screen.getByText('Troubleshooting')).toBeInTheDocument()
7373
})
7474

7575
it('opens troubleshooting modal when link is clicked', () => {
@@ -84,7 +84,7 @@ describe('ErrorMessage Component', () => {
8484

8585
render(<ErrorMessage message={message} />)
8686

87-
fireEvent.click(screen.getByText('troubleshooting assistance'))
87+
fireEvent.click(screen.getByText('Troubleshooting'))
8888
expect(mockSetModalTroubleShooting).toHaveBeenCalledWith(true)
8989
})
9090
})

web/containers/ErrorMessage/index.tsx

Lines changed: 65 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { useRef, useState } from 'react'
2+
13
import {
24
EngineManager,
35
ErrorCode,
@@ -7,6 +9,8 @@ import {
79

810
import { useAtomValue, useSetAtom } from 'jotai'
911

12+
import { CheckIcon, ClipboardIcon, SearchCodeIcon } from 'lucide-react'
13+
1014
import AutoLink from '@/containers/AutoLink'
1115
import ModalTroubleShooting, {
1216
modalTroubleShootingAtom,
@@ -24,30 +28,25 @@ const ErrorMessage = ({ message }: { message: ThreadMessage }) => {
2428
const setMainState = useSetAtom(mainViewStateAtom)
2529
const setSelectedSettingScreen = useSetAtom(selectedSettingAtom)
2630
const activeAssistant = useAtomValue(activeAssistantAtom)
27-
28-
const defaultDesc = () => {
29-
return (
30-
<>
31-
<p>
32-
{`Something's wrong.`} Access&nbsp;
33-
<span
34-
className="cursor-pointer text-[hsla(var(--app-link))] underline"
35-
onClick={() => setModalTroubleShooting(true)}
36-
>
37-
troubleshooting assistance
38-
</span>
39-
&nbsp;now.
40-
</p>
41-
<ModalTroubleShooting />
42-
</>
43-
)
44-
}
31+
const errorDivRef = useRef<HTMLDivElement>(null)
32+
const [copied, setCopied] = useState(false)
4533

4634
const getEngine = () => {
4735
const engineName = activeAssistant?.model?.engine
4836
return engineName ? EngineManager.instance().get(engineName) : null
4937
}
5038

39+
const handleCopy = () => {
40+
if (errorDivRef.current) {
41+
const errorText = errorDivRef.current.innerText
42+
if (errorText) {
43+
navigator.clipboard.writeText(errorText)
44+
setCopied(true)
45+
setTimeout(() => setCopied(false), 2000)
46+
}
47+
}
48+
}
49+
5150
const getErrorTitle = () => {
5251
const engine = getEngine()
5352

@@ -69,9 +68,9 @@ const ErrorMessage = ({ message }: { message: ThreadMessage }) => {
6968
</button>{' '}
7069
and try again.
7170
</span>
72-
{defaultDesc()}
7371
</>
7472
)
73+
7574
default:
7675
return (
7776
<p
@@ -90,7 +89,6 @@ const ErrorMessage = ({ message }: { message: ThreadMessage }) => {
9089
{message?.content[0]?.text?.value && (
9190
<AutoLink text={message?.content[0]?.text?.value} />
9291
)}
93-
{defaultDesc()}
9492
</>
9593
)}
9694
</p>
@@ -99,15 +97,54 @@ const ErrorMessage = ({ message }: { message: ThreadMessage }) => {
9997
}
10098

10199
return (
102-
<div className="mx-auto my-6 max-w-[700px]">
103-
{!!message.metadata?.error && (
104-
<div
105-
key={message.id}
106-
className="mx-6 flex flex-col items-center space-y-2 text-center font-medium text-[hsla(var(--text-secondary))]"
107-
>
108-
{getErrorTitle()}
100+
<div className="mx-auto my-6 max-w-[700px] px-4">
101+
<div
102+
className="mx-auto max-w-[400px] rounded-lg border border-[hsla(var(--app-border))]"
103+
key={message.id}
104+
>
105+
<div className="flex justify-between border-b border-inherit px-4 py-2">
106+
<h6 className="text-[hsla(var(--destructive-bg))]">Error</h6>
107+
<div className="flex gap-x-4 text-xs">
108+
<div>
109+
<span
110+
className="flex cursor-pointer items-center gap-x-1 text-[hsla(var(--app-link))]"
111+
onClick={() => setModalTroubleShooting(true)}
112+
>
113+
<SearchCodeIcon size={14} className="text-inherit" />
114+
Troubleshooting
115+
</span>
116+
<ModalTroubleShooting />
117+
</div>
118+
<div
119+
className="flex cursor-pointer items-center gap-x-1 text-[hsla(var(--text-secondary))]"
120+
onClick={handleCopy}
121+
>
122+
{copied ? (
123+
<>
124+
<CheckIcon
125+
size={14}
126+
className="text-[hsla(var(--success-bg))]"
127+
/>
128+
Copied
129+
</>
130+
) : (
131+
<>
132+
<ClipboardIcon size={14} className="text-inherit" />
133+
Copy
134+
</>
135+
)}
136+
</div>
137+
</div>
138+
</div>
139+
<div className="max-h-[80px] w-full overflow-x-auto p-4 py-2">
140+
<div
141+
className="text-xs leading-relaxed text-[hsla(var(--text-secondary))]"
142+
ref={errorDivRef}
143+
>
144+
{getErrorTitle()}
145+
</div>
109146
</div>
110-
)}
147+
</div>
111148
</div>
112149
)
113150
}

0 commit comments

Comments
 (0)