mirror of
https://github.com/langgenius/dify.git
synced 2026-05-26 03:47:42 +08:00
fix(web): name log sort and resend controls
This commit is contained in:
@ -117,11 +117,9 @@ describe('DetailPanel', () => {
|
||||
})
|
||||
|
||||
it('should render close button', () => {
|
||||
const { container } = render(<DetailPanel runID="run-123" onClose={defaultOnClose} />)
|
||||
render(<DetailPanel runID="run-123" onClose={defaultOnClose} />)
|
||||
|
||||
// Close button has RiCloseLine icon
|
||||
const closeButton = container.querySelector('span.cursor-pointer')
|
||||
expect(closeButton).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'common.operation.close' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render Run component with correct URLs', () => {
|
||||
@ -173,12 +171,11 @@ describe('DetailPanel', () => {
|
||||
const user = userEvent.setup()
|
||||
const onClose = vi.fn()
|
||||
|
||||
const { container } = render(<DetailPanel runID="run-123" onClose={onClose} />)
|
||||
render(<DetailPanel runID="run-123" onClose={onClose} />)
|
||||
|
||||
const closeButton = container.querySelector('span.cursor-pointer')
|
||||
expect(closeButton).toBeInTheDocument()
|
||||
const closeButton = screen.getByRole('button', { name: 'common.operation.close' })
|
||||
|
||||
await user.click(closeButton!)
|
||||
await user.click(closeButton)
|
||||
|
||||
expect(onClose).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
@ -27,9 +27,14 @@ const DetailPanel: FC<ILogDetail> = ({ runID, onClose, canReplay = false }) => {
|
||||
|
||||
return (
|
||||
<div className="relative flex grow flex-col pt-3">
|
||||
<span className="absolute top-4 right-3 z-20 cursor-pointer p-1" onClick={onClose}>
|
||||
<RiCloseLine className="h-4 w-4 text-text-tertiary" />
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={t('operation.close', { ns: 'common' })}
|
||||
className="absolute top-4 right-3 z-20 cursor-pointer border-none bg-transparent p-1 focus-visible:ring-1 focus-visible:ring-components-input-border-active focus-visible:outline-hidden"
|
||||
onClick={onClose}
|
||||
>
|
||||
<RiCloseLine className="h-4 w-4 text-text-tertiary" aria-hidden="true" />
|
||||
</button>
|
||||
<div className="flex items-center bg-components-panel-bg">
|
||||
<h1 className="shrink-0 px-4 py-1 system-xl-semibold text-text-primary">{t('runDetail.workflowTitle', { ns: 'appLog' })}</h1>
|
||||
{canReplay && (
|
||||
@ -38,11 +43,11 @@ const DetailPanel: FC<ILogDetail> = ({ runID, onClose, canReplay = false }) => {
|
||||
render={(
|
||||
<button
|
||||
type="button"
|
||||
className="mr-1 flex h-6 w-6 items-center justify-center rounded-md hover:bg-state-base-hover"
|
||||
className="mr-1 flex h-6 w-6 items-center justify-center rounded-md border-none bg-transparent p-0 hover:bg-state-base-hover"
|
||||
aria-label={t('runDetail.testWithParams', { ns: 'appLog' })}
|
||||
onClick={handleReplay}
|
||||
>
|
||||
<RiPlayLargeLine className="h-4 w-4 text-text-tertiary" />
|
||||
<RiPlayLargeLine className="h-4 w-4 text-text-tertiary" aria-hidden="true" />
|
||||
</button>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -11,10 +11,10 @@ const mockItems = [
|
||||
]
|
||||
|
||||
describe('Sort component — real portal integration', () => {
|
||||
const setup = (props = {}) => {
|
||||
const setup = (props: Partial<React.ComponentProps<typeof Sort>> = {}) => {
|
||||
const onSelect = vi.fn()
|
||||
const user = userEvent.setup()
|
||||
const { container, rerender } = render(
|
||||
const { rerender } = render(
|
||||
<Sort value="created_at" items={mockItems} onSelect={onSelect} order="" {...props} />,
|
||||
)
|
||||
|
||||
@ -28,10 +28,9 @@ describe('Sort component — real portal integration', () => {
|
||||
|
||||
// helper: returns right-side sort button element
|
||||
const getSortButton = (): HTMLElement => {
|
||||
const btn = container.querySelector('.rounded-r-lg')
|
||||
if (!btn)
|
||||
throw new Error('Sort button (rounded-r-lg) not found in rendered container')
|
||||
return btn as HTMLElement
|
||||
return screen.getByRole('button', {
|
||||
name: props.order ? 'appLog.filter.ascending' : 'appLog.filter.descending',
|
||||
})
|
||||
}
|
||||
|
||||
return { user, onSelect, rerender, getTriggerWrapper, getSortButton }
|
||||
|
||||
@ -85,10 +85,15 @@ const Sort: FC<Props> = ({
|
||||
</DropdownMenuContent>
|
||||
</div>
|
||||
</DropdownMenu>
|
||||
<div className="ml-px cursor-pointer rounded-r-lg bg-components-button-tertiary-bg p-2 hover:bg-components-button-tertiary-bg-hover" onClick={() => onSelect(`${order ? '' : '-'}${value}`)}>
|
||||
{!order && <RiSortAsc className="h-4 w-4 text-components-button-tertiary-text" />}
|
||||
{order && <RiSortDesc className="h-4 w-4 text-components-button-tertiary-text" />}
|
||||
</div>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={t(`filter.${order ? 'ascending' : 'descending'}`, { ns: 'appLog' })}
|
||||
className="ml-px cursor-pointer rounded-r-lg border-none bg-components-button-tertiary-bg p-2 hover:bg-components-button-tertiary-bg-hover focus-visible:ring-1 focus-visible:ring-components-input-border-active focus-visible:outline-hidden"
|
||||
onClick={() => onSelect(`${order ? '' : '-'}${value}`)}
|
||||
>
|
||||
{!order && <RiSortAsc className="h-4 w-4 text-components-button-tertiary-text" aria-hidden="true" />}
|
||||
{order && <RiSortDesc className="h-4 w-4 text-components-button-tertiary-text" aria-hidden="true" />}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
)
|
||||
|
||||
@ -31,7 +31,7 @@ describe('Countdown', () => {
|
||||
localStorage.setItem(COUNT_DOWN_KEY, '0')
|
||||
render(<Countdown />)
|
||||
|
||||
expect(screen.getByText('login.checkCode.resend')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'login.checkCode.resend' })).toBeInTheDocument()
|
||||
expect(screen.queryByText('s')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
@ -39,7 +39,7 @@ describe('Countdown', () => {
|
||||
localStorage.setItem(COUNT_DOWN_KEY, '1000')
|
||||
render(<Countdown />)
|
||||
|
||||
expect(screen.queryByText('login.checkCode.resend')).not.toBeInTheDocument()
|
||||
expect(screen.queryByRole('button', { name: 'login.checkCode.resend' })).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
@ -79,7 +79,7 @@ describe('Countdown', () => {
|
||||
|
||||
render(<Countdown onResend={onResend} />)
|
||||
|
||||
const resendLink = screen.getByText('login.checkCode.resend')
|
||||
const resendLink = screen.getByRole('button', { name: 'login.checkCode.resend' })
|
||||
fireEvent.click(resendLink)
|
||||
|
||||
expect(onResend).toHaveBeenCalledTimes(1)
|
||||
@ -90,7 +90,7 @@ describe('Countdown', () => {
|
||||
|
||||
render(<Countdown />)
|
||||
|
||||
const resendLink = screen.getByText('login.checkCode.resend')
|
||||
const resendLink = screen.getByRole('button', { name: 'login.checkCode.resend' })
|
||||
fireEvent.click(resendLink)
|
||||
|
||||
expect(localStorage.setItem).toHaveBeenCalledWith(COUNT_DOWN_KEY, String(COUNT_DOWN_TIME_MS))
|
||||
@ -101,7 +101,7 @@ describe('Countdown', () => {
|
||||
|
||||
render(<Countdown />)
|
||||
|
||||
const resendLink = screen.getByText('login.checkCode.resend')
|
||||
const resendLink = screen.getByRole('button', { name: 'login.checkCode.resend' })
|
||||
expect(() => fireEvent.click(resendLink)).not.toThrow()
|
||||
})
|
||||
})
|
||||
@ -127,14 +127,14 @@ describe('Countdown', () => {
|
||||
localStorage.setItem(COUNT_DOWN_KEY, '0')
|
||||
render(<Countdown />)
|
||||
|
||||
expect(screen.getByText('login.checkCode.resend')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'login.checkCode.resend' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should handle negative time values', () => {
|
||||
localStorage.setItem(COUNT_DOWN_KEY, '-1000')
|
||||
render(<Countdown />)
|
||||
|
||||
expect(screen.getByText('login.checkCode.resend')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'login.checkCode.resend' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should round time display correctly', () => {
|
||||
@ -160,7 +160,7 @@ describe('Countdown', () => {
|
||||
|
||||
render(<Countdown onResend={onResend} />)
|
||||
|
||||
expect(screen.getByText('login.checkCode.resend')).toBeInTheDocument()
|
||||
expect(screen.getByRole('button', { name: 'login.checkCode.resend' })).toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render correctly without any props', () => {
|
||||
|
||||
@ -41,7 +41,15 @@ export default function Countdown({ onResend }: CountdownProps) {
|
||||
</span>
|
||||
)}
|
||||
{
|
||||
time <= 0 && <span className="cursor-pointer system-xs-medium text-text-accent-secondary" onClick={resend}>{t('checkCode.resend', { ns: 'login' })}</span>
|
||||
time <= 0 && (
|
||||
<button
|
||||
type="button"
|
||||
className="cursor-pointer border-none bg-transparent p-0 system-xs-medium text-text-accent-secondary focus-visible:ring-1 focus-visible:ring-components-input-border-active focus-visible:outline-hidden"
|
||||
onClick={resend}
|
||||
>
|
||||
{t('checkCode.resend', { ns: 'login' })}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
</p>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user