-
-
Notifications
You must be signed in to change notification settings - Fork 57
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 错误处理 & 配置优化 #58
Changes from all commits
09d5329
6b22c4a
e154615
7ccca77
ac7a337
6242abd
b7dd792
2023dd0
d6cd5de
ffdccc2
23b2d5d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
'use client'; | ||
|
||
import dynamic from 'next/dynamic'; | ||
|
||
export default dynamic(() => import('@/components/Error')); |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,22 @@ | ||||||
'use client'; | ||||||
|
||||||
import Error from 'next/error'; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Rename the imported - import Error from 'next/error';
+ import NextError from 'next/error'; Committable suggestion
Suggested change
|
||||||
import { useEffect } from 'react'; | ||||||
|
||||||
export default function GlobalError({ | ||||||
error, | ||||||
}: { | ||||||
error: Error & { digest?: string }; | ||||||
reset: () => void; | ||||||
}) { | ||||||
useEffect(() => { | ||||||
console.log('error', error); | ||||||
}, [error]); | ||||||
return ( | ||||||
<html> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a - <html>
+ <html lang="en"> Committable suggestion
Suggested change
|
||||||
<body> | ||||||
<Error statusCode={undefined as any} /> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Avoid using - <Error statusCode={undefined as any} />
+ <NextError statusCode={500} /> // Example: Use a specific status code
|
||||||
</body> | ||||||
</html> | ||||||
); | ||||||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,22 +1,18 @@ | ||||||
import { Analytics } from '@vercel/analytics/react'; | ||||||
import { cookies } from 'next/headers'; | ||||||
import { PropsWithChildren } from 'react'; | ||||||
|
||||||
import { VIDOL_THEME_APPEARANCE } from '@/constants/theme'; | ||||||
import Layout from '@/layout'; | ||||||
|
||||||
import StyleRegistry from './StyleRegistry'; | ||||||
|
||||||
const RootLayout = ({ children }: PropsWithChildren) => { | ||||||
// get default theme config to use with ssr | ||||||
const cookieStore = cookies(); | ||||||
const appearance = cookieStore.get(VIDOL_THEME_APPEARANCE); | ||||||
|
||||||
return ( | ||||||
<html lang="cn" suppressHydrationWarning> | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Provide a valid value for the - <html lang="cn" suppressHydrationWarning>
+ <html lang="zh-CN" suppressHydrationWarning> Committable suggestion
Suggested change
|
||||||
<body> | ||||||
<StyleRegistry> | ||||||
<Layout defaultAppearance={appearance?.value}>{children}</Layout> | ||||||
<Layout>{children}</Layout> | ||||||
</StyleRegistry> | ||||||
<Analytics /> | ||||||
</body> | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,43 @@ | ||||||
import { createStyles } from 'antd-style'; | ||||||
import NextImage from 'next/image'; | ||||||
|
||||||
import { AVATAR_IMAGE_SIZE, DEFAULT_USER_AVATAR_URL } from '@/constants/common'; | ||||||
|
||||||
const useStyle = createStyles( | ||||||
({ css, token }) => css` | ||||||
cursor: pointer; | ||||||
overflow: hidden; | ||||||
border-radius: 50%; | ||||||
transition: | ||||||
scale 400ms ${token.motionEaseOut}, | ||||||
box-shadow 100ms ${token.motionEaseOut}; | ||||||
|
||||||
&:hover { | ||||||
box-shadow: 0 0 0 3px ${token.colorText}; | ||||||
} | ||||||
|
||||||
&:active { | ||||||
scale: 0.8; | ||||||
} | ||||||
`, | ||||||
); | ||||||
|
||||||
interface Props { | ||||||
avatar?: string; | ||||||
size?: number; | ||||||
} | ||||||
|
||||||
export default (props: Props) => { | ||||||
const { size = AVATAR_IMAGE_SIZE, avatar } = props; | ||||||
const { styles } = useStyle(); | ||||||
return ( | ||||||
<NextImage | ||||||
className={styles} | ||||||
alt={avatar ? 'userAvatar' : 'LobeVidol'} | ||||||
height={size} | ||||||
src={!!avatar ? avatar : DEFAULT_USER_AVATAR_URL} | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simplify the conditional expression for clarity. - src={!!avatar ? avatar : DEFAULT_USER_AVATAR_URL}
+ src={avatar ? avatar : DEFAULT_USER_AVATAR_URL} Committable suggestion
Suggested change
|
||||||
unoptimized | ||||||
width={size} | ||||||
/> | ||||||
); | ||||||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
'use client'; | ||
|
||
import { FluentEmoji } from '@lobehub/ui'; | ||
import { Button } from 'antd'; | ||
import Link from 'next/link'; | ||
import { memo, useEffect } from 'react'; | ||
import { Flexbox } from 'react-layout-kit'; | ||
|
||
import { MAX_WIDTH } from '@/constants/common'; | ||
import ResetConfig from '@/features/Actions/ClearSession'; | ||
import ClearChat from '@/features/Actions/ResetConfig'; | ||
|
||
interface ErrorCaptureProps { | ||
error: Error & { digest?: string }; | ||
reset: () => void; | ||
} | ||
|
||
const ErrorCapture = memo<ErrorCaptureProps>(({ reset, error }) => { | ||
useEffect(() => { | ||
// Log the error to an error reporting service | ||
console.error(error); | ||
}, [error]); | ||
|
||
return ( | ||
<Flexbox align={'center'} justify={'center'} style={{ minHeight: '100%', width: '100%' }}> | ||
<h1 | ||
style={{ | ||
filter: 'blur(8px)', | ||
fontSize: `min(${MAX_WIDTH / 6}px, 25vw)`, | ||
fontWeight: 900, | ||
margin: 0, | ||
opacity: 0.12, | ||
position: 'absolute', | ||
zIndex: 0, | ||
}} | ||
> | ||
ERROR | ||
</h1> | ||
<FluentEmoji emoji={'🤧'} size={64} /> | ||
<h2 style={{ fontWeight: 'bold', marginTop: '1em', textAlign: 'center' }}> | ||
页面遇到一点问题... | ||
</h2> | ||
<p style={{ marginBottom: '2em' }}> | ||
项目当前正在施工中,不保证数据稳定性,如果遇到问题可以尝试 | ||
<ClearChat text="清除会话消息" type={'link'} /> | ||
或 <ResetConfig text="重置系统设置" type={'link'} /> | ||
,造成地不便敬请谅解 | ||
</p> | ||
<Flexbox gap={12} horizontal style={{ marginBottom: '1em' }}> | ||
<Button onClick={() => reset()}>重新加载</Button> | ||
<Link href="/"> | ||
<Button type={'primary'}>返回首页</Button> | ||
</Link> | ||
</Flexbox> | ||
</Flexbox> | ||
); | ||
}); | ||
|
||
ErrorCapture.displayName = 'ErrorCapture'; | ||
|
||
export default ErrorCapture; |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,97 @@ | ||||||||
import { Menu as AntdMenu, MenuProps as AntdMenuProps, ConfigProvider } from 'antd'; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Consider using these imports only for type annotations to clean up the import statements. - import { Menu as AntdMenu, MenuProps as AntdMenuProps, ConfigProvider } from 'antd';
+ import type { MenuProps as AntdMenuProps } from 'antd';
+ import { Menu as AntdMenu, ConfigProvider } from 'antd'; Committable suggestion
Suggested change
|
||||||||
import { createStyles } from 'antd-style'; | ||||||||
import { memo } from 'react'; | ||||||||
|
||||||||
const useStyles = createStyles(({ css, token, prefixCls }) => ({ | ||||||||
compact: css` | ||||||||
display: flex; | ||||||||
flex-direction: column; | ||||||||
gap: 0.125rem; | ||||||||
`, | ||||||||
menu: css` | ||||||||
flex: 1; | ||||||||
background: transparent; | ||||||||
border: none !important; | ||||||||
|
||||||||
.${prefixCls}-menu-item-divider { | ||||||||
margin-block: 0.125rem; | ||||||||
border-color: ${token.colorFillTertiary}; | ||||||||
|
||||||||
&:first-child { | ||||||||
margin-top: 0; | ||||||||
} | ||||||||
|
||||||||
&:last-child { | ||||||||
margin-bottom: 0; | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
.${prefixCls}-menu-item, .${prefixCls}-menu-submenu-title { | ||||||||
display: flex; | ||||||||
gap: 0.75rem; | ||||||||
align-items: center; | ||||||||
|
||||||||
height: unset; | ||||||||
min-height: 2rem; | ||||||||
padding: 0.375rem 0.75rem; | ||||||||
|
||||||||
line-height: 2; | ||||||||
|
||||||||
.anticon + .${prefixCls}-menu-title-content { | ||||||||
margin-inline-start: 0; | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
.${prefixCls}-menu-item-selected { | ||||||||
.${prefixCls}-menu-item-icon svg { | ||||||||
color: ${token.colorText}; | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
.${prefixCls}-menu-item-icon svg { | ||||||||
color: ${token.colorTextSecondary}; | ||||||||
} | ||||||||
|
||||||||
.${prefixCls}-menu-title-content { | ||||||||
flex: 1; | ||||||||
} | ||||||||
`, | ||||||||
})); | ||||||||
|
||||||||
export interface MenuProps extends AntdMenuProps { | ||||||||
variant?: 'default' | 'compact'; | ||||||||
} | ||||||||
|
||||||||
const Menu = memo<MenuProps>(({ className, selectable = false, variant, ...rest }) => { | ||||||||
const isCompact = variant === 'compact'; | ||||||||
const { cx, styles, theme } = useStyles(); | ||||||||
return ( | ||||||||
<ConfigProvider | ||||||||
theme={{ | ||||||||
components: { | ||||||||
Menu: { | ||||||||
controlHeightLG: 36, | ||||||||
iconMarginInlineEnd: 8, | ||||||||
iconSize: 16, | ||||||||
itemBorderRadius: theme.borderRadius, | ||||||||
itemColor: selectable ? theme.colorTextSecondary : theme.colorText, | ||||||||
itemHoverBg: theme.colorFillTertiary, | ||||||||
itemMarginBlock: isCompact ? 0 : 4, | ||||||||
itemMarginInline: isCompact ? 0 : 4, | ||||||||
itemSelectedBg: theme.colorFillSecondary, | ||||||||
paddingXS: -8, | ||||||||
}, | ||||||||
}, | ||||||||
}} | ||||||||
> | ||||||||
<AntdMenu | ||||||||
className={cx(styles.menu, isCompact && styles.compact, className)} | ||||||||
mode="vertical" | ||||||||
selectable={selectable} | ||||||||
{...rest} | ||||||||
/> | ||||||||
</ConfigProvider> | ||||||||
); | ||||||||
}); | ||||||||
|
||||||||
export default Menu; |
This file was deleted.
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,41 @@ | ||||||||||
import { App, Button } from 'antd'; | ||||||||||
import { ButtonType } from 'antd/es/button'; | ||||||||||
Comment on lines
+1
to
+2
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Optimize imports by using - import { App, Button } from 'antd';
- import { ButtonType } from 'antd/es/button';
+ import type { App, Button } from 'antd';
+ import type { ButtonType } from 'antd/es/button'; Committable suggestion
Suggested change
|
||||||||||
import React from 'react'; | ||||||||||
|
||||||||||
import { useAgentStore } from '@/store/agent'; | ||||||||||
import { useSessionStore } from '@/store/session'; | ||||||||||
|
||||||||||
interface Props { | ||||||||||
text?: string; | ||||||||||
type?: ButtonType; | ||||||||||
} | ||||||||||
export default (props: Props) => { | ||||||||||
const { text = '立即清除', type = 'primary' } = props; | ||||||||||
const clearAgentStorage = useAgentStore((s) => s.clearAgentStorage); | ||||||||||
const clearSessions = useSessionStore((s) => s.clearSessions); | ||||||||||
const { message, modal } = App.useApp(); | ||||||||||
|
||||||||||
const handleClear = () => { | ||||||||||
modal.confirm({ | ||||||||||
cancelText: '取消', | ||||||||||
centered: true, | ||||||||||
content: '操作无法撤销,清除后数据将无法恢复,请慎重操作', | ||||||||||
okButtonProps: { | ||||||||||
danger: true, | ||||||||||
}, | ||||||||||
okText: '确定', | ||||||||||
onOk: () => { | ||||||||||
clearSessions(); | ||||||||||
clearAgentStorage(); | ||||||||||
message.success('清除成功'); | ||||||||||
}, | ||||||||||
title: '确认清除所有会话消息?', | ||||||||||
}); | ||||||||||
}; | ||||||||||
|
||||||||||
return ( | ||||||||||
<Button danger onClick={handleClear} type={type}> | ||||||||||
{text} | ||||||||||
</Button> | ||||||||||
); | ||||||||||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add a space after the comma for consistent formatting.
Committable suggestion