mirror of
https://github.com/langgenius/dify.git
synced 2026-07-27 15:08:35 +08:00
fix(web): prevent search hotkey hydration mismatch (#39574)
This commit is contained in:
parent
448e378fc0
commit
99c1cb7781
@ -0,0 +1,34 @@
|
||||
import { act, waitFor, within } from '@testing-library/react'
|
||||
import { hydrateRoot } from 'react-dom/client'
|
||||
import { renderToString } from 'react-dom/server'
|
||||
import { MainNavSearchButton } from '../search-button'
|
||||
|
||||
describe('MainNavSearchButton', () => {
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
it('renders Ctrl during SSR and corrects it after Mac hydration without a mismatch', async () => {
|
||||
vi.spyOn(window.navigator, 'platform', 'get').mockReturnValue('MacIntel')
|
||||
const app = <MainNavSearchButton />
|
||||
const container = document.createElement('div')
|
||||
container.innerHTML = renderToString(app)
|
||||
const getSearchButton = () =>
|
||||
within(container).getByRole('button', { name: 'app.gotoAnything.searchTitle' })
|
||||
|
||||
expect(getSearchButton()).toHaveTextContent('CtrlK')
|
||||
expect(getSearchButton()).not.toHaveTextContent('⌘')
|
||||
|
||||
const onRecoverableError = vi.fn()
|
||||
const root = hydrateRoot(container, app, {
|
||||
onRecoverableError,
|
||||
})
|
||||
|
||||
try {
|
||||
await waitFor(() => expect(getSearchButton()).toHaveTextContent('⌘K'))
|
||||
expect(onRecoverableError).not.toHaveBeenCalled()
|
||||
} finally {
|
||||
act(() => root.unmount())
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -2,13 +2,31 @@
|
||||
|
||||
import { DialogTrigger } from '@langgenius/dify-ui/dialog'
|
||||
import { Kbd } from '@langgenius/dify-ui/kbd'
|
||||
import { formatForDisplay } from '@tanstack/react-hotkeys'
|
||||
import { detectPlatform, formatForDisplay } from '@tanstack/react-hotkeys'
|
||||
import { useSyncExternalStore } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { gotoAnythingDialogHandle } from '@/app/components/goto-anything/dialog-handle'
|
||||
import { GOTO_ANYTHING_HOTKEY } from '@/app/components/goto-anything/hotkeys'
|
||||
|
||||
function noopSubscribe() {
|
||||
return () => {}
|
||||
}
|
||||
|
||||
function getPlatformSnapshot() {
|
||||
return detectPlatform()
|
||||
}
|
||||
|
||||
function getServerPlatformSnapshot(): ReturnType<typeof detectPlatform> {
|
||||
return 'linux'
|
||||
}
|
||||
|
||||
function useDisplayPlatform() {
|
||||
return useSyncExternalStore(noopSubscribe, getPlatformSnapshot, getServerPlatformSnapshot)
|
||||
}
|
||||
|
||||
export function MainNavSearchButton() {
|
||||
const { t } = useTranslation()
|
||||
const displayPlatform = useDisplayPlatform()
|
||||
|
||||
return (
|
||||
<DialogTrigger
|
||||
@ -24,7 +42,7 @@ export function MainNavSearchButton() {
|
||||
<span aria-hidden className="i-custom-vender-main-nav-quick-search h-4 w-4" />
|
||||
<Kbd className="h-4.5 min-w-0 rounded-[5px] border border-divider-deep bg-components-badge-bg-dimm px-1 py-0.5 system-2xs-medium-uppercase text-text-tertiary">
|
||||
{GOTO_ANYTHING_HOTKEY.split('+').map((key) => (
|
||||
<span key={key}>{formatForDisplay(key)}</span>
|
||||
<span key={key}>{formatForDisplay(key, { platform: displayPlatform })}</span>
|
||||
))}
|
||||
</Kbd>
|
||||
</DialogTrigger>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user