enhancement: minor ui refinements (#4521)

* enhancement: minor ui refinements

* chore: update test case
This commit is contained in:
Faisal Amir 2025-01-26 20:41:52 +07:00 committed by GitHub
parent 5dc184eed9
commit cdc7d2ba47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 64 additions and 58 deletions

View File

@ -509,61 +509,61 @@ __metadata:
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension":
version: 0.1.10
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7dd866&locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension"
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f3025c&locator=%40janhq%2Fassistant-extension%40workspace%3Aassistant-extension"
dependencies:
rxjs: "npm:^7.8.1"
ulidx: "npm:^2.3.0"
checksum: 10c0/da0eed6e552ce2ff6f52a087e6e221101c3d0c03d92820840ee80c3ca1a17317a66525cb5bf59b6c1e8bd2e36e54763008f97e13000ae339dac49f5682fcfa65
checksum: 10c0/cda3dff029cc6ce8a9ddcd8ac3ff039b783eed9252c1c3f0b3f34a2cf68c00dc2755997b56c3c5796502aa7316b69b57758b15f338e64b4a8ef14b34d23b6c99
languageName: node
linkType: hard
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension":
version: 0.1.10
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7dd866&locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension"
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f3025c&locator=%40janhq%2Fconversational-extension%40workspace%3Aconversational-extension"
dependencies:
rxjs: "npm:^7.8.1"
ulidx: "npm:^2.3.0"
checksum: 10c0/da0eed6e552ce2ff6f52a087e6e221101c3d0c03d92820840ee80c3ca1a17317a66525cb5bf59b6c1e8bd2e36e54763008f97e13000ae339dac49f5682fcfa65
checksum: 10c0/cda3dff029cc6ce8a9ddcd8ac3ff039b783eed9252c1c3f0b3f34a2cf68c00dc2755997b56c3c5796502aa7316b69b57758b15f338e64b4a8ef14b34d23b6c99
languageName: node
linkType: hard
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension":
version: 0.1.10
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7dd866&locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension"
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f3025c&locator=%40janhq%2Fengine-management-extension%40workspace%3Aengine-management-extension"
dependencies:
rxjs: "npm:^7.8.1"
ulidx: "npm:^2.3.0"
checksum: 10c0/da0eed6e552ce2ff6f52a087e6e221101c3d0c03d92820840ee80c3ca1a17317a66525cb5bf59b6c1e8bd2e36e54763008f97e13000ae339dac49f5682fcfa65
checksum: 10c0/cda3dff029cc6ce8a9ddcd8ac3ff039b783eed9252c1c3f0b3f34a2cf68c00dc2755997b56c3c5796502aa7316b69b57758b15f338e64b4a8ef14b34d23b6c99
languageName: node
linkType: hard
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension":
version: 0.1.10
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7dd866&locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension"
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f3025c&locator=%40janhq%2Finference-cortex-extension%40workspace%3Ainference-cortex-extension"
dependencies:
rxjs: "npm:^7.8.1"
ulidx: "npm:^2.3.0"
checksum: 10c0/da0eed6e552ce2ff6f52a087e6e221101c3d0c03d92820840ee80c3ca1a17317a66525cb5bf59b6c1e8bd2e36e54763008f97e13000ae339dac49f5682fcfa65
checksum: 10c0/cda3dff029cc6ce8a9ddcd8ac3ff039b783eed9252c1c3f0b3f34a2cf68c00dc2755997b56c3c5796502aa7316b69b57758b15f338e64b4a8ef14b34d23b6c99
languageName: node
linkType: hard
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension":
version: 0.1.10
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7dd866&locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension"
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f3025c&locator=%40janhq%2Fmodel-extension%40workspace%3Amodel-extension"
dependencies:
rxjs: "npm:^7.8.1"
ulidx: "npm:^2.3.0"
checksum: 10c0/da0eed6e552ce2ff6f52a087e6e221101c3d0c03d92820840ee80c3ca1a17317a66525cb5bf59b6c1e8bd2e36e54763008f97e13000ae339dac49f5682fcfa65
checksum: 10c0/cda3dff029cc6ce8a9ddcd8ac3ff039b783eed9252c1c3f0b3f34a2cf68c00dc2755997b56c3c5796502aa7316b69b57758b15f338e64b4a8ef14b34d23b6c99
languageName: node
linkType: hard
"@janhq/core@file:../../core/package.tgz::locator=%40janhq%2Fmonitoring-extension%40workspace%3Amonitoring-extension":
version: 0.1.10
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=7dd866&locator=%40janhq%2Fmonitoring-extension%40workspace%3Amonitoring-extension"
resolution: "@janhq/core@file:../../core/package.tgz#../../core/package.tgz::hash=f3025c&locator=%40janhq%2Fmonitoring-extension%40workspace%3Amonitoring-extension"
dependencies:
rxjs: "npm:^7.8.1"
ulidx: "npm:^2.3.0"
checksum: 10c0/da0eed6e552ce2ff6f52a087e6e221101c3d0c03d92820840ee80c3ca1a17317a66525cb5bf59b6c1e8bd2e36e54763008f97e13000ae339dac49f5682fcfa65
checksum: 10c0/cda3dff029cc6ce8a9ddcd8ac3ff039b783eed9252c1c3f0b3f34a2cf68c00dc2755997b56c3c5796502aa7316b69b57758b15f338e64b4a8ef14b34d23b6c99
languageName: node
linkType: hard

View File

@ -7,9 +7,9 @@ import { twMerge } from 'tailwind-merge'
import { MainViewState } from '@/constants/screens'
import { LEFT_PANEL_WIDTH } from '../LeftPanelContainer'
import { leftPanelWidthAtom } from '../LeftPanelContainer'
import { RIGHT_PANEL_WIDTH } from '../RightPanelContainer'
import { rightPanelWidthAtom } from '../RightPanelContainer'
import {
mainViewStateAtom,
@ -28,6 +28,8 @@ const CenterPanelContainer = ({ children, isShowStarterScreen }: Props) => {
const showLeftPanel = useAtomValue(showLeftPanelAtom)
const showRightPanel = useAtomValue(showRightPanelAtom)
const mainViewState = useAtomValue(mainViewStateAtom)
const rightPanelWidth = useAtomValue(rightPanelWidthAtom)
const leftPanelWidth = useAtomValue(leftPanelWidthAtom)
return (
<div
@ -36,7 +38,7 @@ const CenterPanelContainer = ({ children, isShowStarterScreen }: Props) => {
maxWidth: matches
? '100%'
: mainViewState === MainViewState.Thread && !isShowStarterScreen
? `calc(100% - (${showRightPanel ? Number(localStorage.getItem(RIGHT_PANEL_WIDTH)) : 0}px + ${showLeftPanel ? Number(localStorage.getItem(LEFT_PANEL_WIDTH)) : 0}px))`
? `calc(100% - (${showRightPanel ? rightPanelWidth : 0}px + ${showLeftPanel ? leftPanelWidth : 0}px))`
: '100%',
}}
>

View File

@ -1,11 +1,9 @@
import { Fragment } from 'react'
import { Button } from '@janhq/joi'
import { Button, Tooltip } from '@janhq/joi'
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
import {
PanelLeftCloseIcon,
PanelLeftOpenIcon,
PanelRightOpenIcon,
PanelRightCloseIcon,
MinusIcon,
MenuIcon,
@ -13,6 +11,8 @@ import {
PaletteIcon,
XIcon,
PenSquareIcon,
Settings2,
History,
} from 'lucide-react'
import { twMerge } from 'tailwind-merge'
@ -91,7 +91,10 @@ const TopPanel = () => {
</Button>
) : (
<Button theme="icon" onClick={() => setShowLeftPanel(true)}>
<PanelLeftOpenIcon size={16} />
<Tooltip
trigger={<History size={16} />}
content="Threads History"
/>
</Button>
)}
</Fragment>
@ -135,7 +138,10 @@ const TopPanel = () => {
}
}}
>
<PanelRightOpenIcon size={16} />
<Tooltip
trigger={<Settings2 size={16} />}
content="Thread Settings"
/>
</Button>
)}
</Fragment>

View File

@ -7,7 +7,7 @@ import {
} from 'react'
import { ScrollArea, useClickOutside, useMediaQuery } from '@janhq/joi'
import { useAtom, useAtomValue } from 'jotai'
import { atom, useAtom, useAtomValue } from 'jotai'
import { twMerge } from 'tailwind-merge'
@ -18,13 +18,12 @@ type Props = PropsWithChildren
const DEFAULT_LEFT_PANEL_WIDTH = 200
export const LEFT_PANEL_WIDTH = 'leftPanelWidth'
export const leftPanelWidthAtom = atom(DEFAULT_LEFT_PANEL_WIDTH)
const LeftPanelContainer = ({ children }: Props) => {
const [leftPanelRef, setLeftPanelRef] = useState<HTMLDivElement | null>(null)
const [isResizing, setIsResizing] = useState(false)
const [threadLeftPanelWidth, setLeftPanelWidth] = useState(
Number(localStorage.getItem(LEFT_PANEL_WIDTH)) || DEFAULT_LEFT_PANEL_WIDTH
)
const [leftPanelWidth, setLeftPanelWidth] = useAtom(leftPanelWidthAtom)
const [showLeftPanel, setShowLeftPanel] = useAtom(showLeftPanelAtom)
const matches = useMediaQuery('(max-width: 880px)')
const reduceTransparent = useAtomValue(reduceTransparentAtom)
@ -37,10 +36,12 @@ const LeftPanelContainer = ({ children }: Props) => {
const startResizing = useCallback(() => {
setIsResizing(true)
document.body.classList.add('select-none')
}, [])
const stopResizing = useCallback(() => {
setIsResizing(false)
document.body.classList.remove('select-none')
}, [])
const resize = useCallback(
@ -69,7 +70,7 @@ const LeftPanelContainer = ({ children }: Props) => {
}
}
},
[isResizing, leftPanelRef, setShowLeftPanel]
[isResizing, leftPanelRef, setLeftPanelWidth, setShowLeftPanel]
)
useEffect(() => {
@ -83,7 +84,7 @@ const LeftPanelContainer = ({ children }: Props) => {
window.removeEventListener('mousemove', resize)
window.removeEventListener('mouseup', stopResizing)
}
}, [resize, stopResizing])
}, [resize, setLeftPanelWidth, stopResizing])
return (
<div
@ -97,7 +98,7 @@ const LeftPanelContainer = ({ children }: Props) => {
reduceTransparent &&
'left-0 border-r border-[hsla(var(--app-border))] bg-[hsla(var(--left-panel-bg))]'
)}
style={{ width: showLeftPanel ? threadLeftPanelWidth : 0 }}
style={{ width: showLeftPanel ? leftPanelWidth : 0 }}
onMouseDown={(e) => isResizing && e.stopPropagation()}
>
<ScrollArea className="h-full w-full">

View File

@ -44,11 +44,6 @@ export default function ModelReload() {
Reloading model {stateModel.model?.id}
</span>
</div>
<div className="my-4 mb-2 text-center">
<span className="text-[hsla(var(--text-secondary)]">
Model is reloading to apply new changes.
</span>
</div>
</div>
)
}

View File

@ -4,8 +4,6 @@ import { PropsWithChildren } from 'react'
import { Toaster } from 'react-hot-toast'
import { SWRConfig } from 'swr'
import EventListener from '@/containers/Providers/EventListener'
import JotaiWrapper from '@/containers/Providers/Jotai'

View File

@ -1,9 +1,11 @@
import '@testing-library/jest-dom'
import { waitFor } from '@testing-library/react'
import React from 'react'
import { render, fireEvent } from '@testing-library/react'
import RightPanelContainer from './index'
import { useAtom } from 'jotai'
import RightPanelContainer, { rightPanelWidthAtom } from './index'
import { showRightPanelAtom } from '@/helpers/atoms/App.atom'
import { reduceTransparentAtom } from '@/helpers/atoms/Setting.atom'
// Mocking ResizeObserver
class ResizeObserver {
@ -34,24 +36,24 @@ jest.mock('jotai', () => {
const originalModule = jest.requireActual('jotai')
return {
...originalModule,
useAtom: jest.fn(),
useAtomValue: jest.fn(),
useAtomValue: jest.fn((atom) => {
if (atom === reduceTransparentAtom) return false
if (atom === showRightPanelAtom) return true
}),
useAtom: jest.fn((atom) => {
if (atom === rightPanelWidthAtom) return [280, jest.fn()]
if (atom === showRightPanelAtom) return [true, mockSetShowRightPanel]
return [null, jest.fn()]
}),
}
})
const mockSetShowRightPanel = jest.fn()
const mockShowRightPanel = true // Change this to test the panel visibility
beforeEach(() => {
// Setting up the localStorage mock
localStorage.clear()
localStorage.setItem('rightPanelWidth', '280') // Setting a default width
// Mocking the atom behavior
;(useAtom as jest.Mock).mockImplementation(() => [
mockShowRightPanel,
mockSetShowRightPanel,
])
})
describe('RightPanelContainer', () => {
@ -66,12 +68,15 @@ describe('RightPanelContainer', () => {
expect(getByText('Child Content')).toBeInTheDocument()
})
it('initializes width from localStorage', () => {
it('initializes width from localStorage', async () => {
const { container } = render(<RightPanelContainer />)
// Check the width from localStorage is applied
const rightPanel = container.firstChild as HTMLDivElement
expect(rightPanel.style.width).toBe('280px') // Width from localStorage
// Wait for the width to be applied
await waitFor(() => {
expect(rightPanel.style.width).toBe('280px') // Correct width from localStorage
})
})
it('changes width on resizing', () => {

View File

@ -7,7 +7,7 @@ import {
} from 'react'
import { ScrollArea, useClickOutside, useMediaQuery } from '@janhq/joi'
import { useAtom, useAtomValue } from 'jotai'
import { atom, useAtom, useAtomValue } from 'jotai'
import { twMerge } from 'tailwind-merge'
@ -19,11 +19,11 @@ type Props = PropsWithChildren
const DEFAULT_RIGHT_PANEL_WIDTH = 280
export const RIGHT_PANEL_WIDTH = 'rightPanelWidth'
export const rightPanelWidthAtom = atom(DEFAULT_RIGHT_PANEL_WIDTH)
const RightPanelContainer = ({ children }: Props) => {
const [isResizing, setIsResizing] = useState(false)
const [threadRightPanelWidth, setRightPanelWidth] = useState(
Number(localStorage.getItem(RIGHT_PANEL_WIDTH)) || DEFAULT_RIGHT_PANEL_WIDTH
)
const [rightPanelWidth, setRightPanelWidth] = useAtom(rightPanelWidthAtom)
const [rightPanelRef, setRightPanelRef] = useState<HTMLDivElement | null>(
null
)
@ -40,10 +40,12 @@ const RightPanelContainer = ({ children }: Props) => {
const startResizing = useCallback(() => {
setIsResizing(true)
document.body.classList.add('select-none')
}, [])
const stopResizing = useCallback(() => {
setIsResizing(false)
document.body.classList.remove('select-none')
}, [])
const resize = useCallback(
@ -72,7 +74,7 @@ const RightPanelContainer = ({ children }: Props) => {
}
}
},
[isResizing, rightPanelRef, setShowRightPanel]
[isResizing, rightPanelRef, setRightPanelWidth, setShowRightPanel]
)
useEffect(() => {
@ -86,7 +88,7 @@ const RightPanelContainer = ({ children }: Props) => {
window.removeEventListener('mousemove', resize)
window.removeEventListener('mouseup', stopResizing)
}
}, [resize, stopResizing])
}, [resize, setRightPanelWidth, stopResizing])
return (
<div
@ -100,7 +102,7 @@ const RightPanelContainer = ({ children }: Props) => {
reduceTransparent &&
'border-l border-[hsla(var(--app-border))] bg-[hsla(var(--right-panel-bg))]'
)}
style={{ width: showRightPanel ? threadRightPanelWidth : 0 }}
style={{ width: showRightPanel ? rightPanelWidth : 0 }}
onMouseDown={(e) => isResizing && e.preventDefault()}
>
<ScrollArea className="h-full w-full">

View File

@ -10,7 +10,6 @@ import { useConfigurations } from '@/hooks/useConfigurations'
import {
ignoreSslAtom,
proxyAtom,
proxyEnabledAtom,
verifyProxySslAtom,
verifyProxyHostSslAtom,
verifyPeerSslAtom,
@ -21,7 +20,6 @@ import {
} from '@/helpers/atoms/AppConfig.atom'
const ProxySettings = ({ onBack }: { onBack: () => void }) => {
const [proxyEnabled] = useAtom(proxyEnabledAtom)
const [proxy, setProxy] = useAtom(proxyAtom)
const [noProxy, setNoProxy] = useAtom(noProxyAtom)
const [partialProxy, setPartialProxy] = useState<string>(proxy)

View File

@ -2,7 +2,6 @@ import React from 'react'
import { InferenceEngine } from '@janhq/core'
import { ScrollArea } from '@janhq/joi'
import { useAtomValue } from 'jotai'
import { useGetEngines } from '@/hooks/useEngineManagement'