fix: Fix linter and tests
This commit is contained in:
parent
43d20e2a32
commit
4718203960
@ -1,4 +1,3 @@
|
|||||||
/* eslint-disable react-hooks/exhaustive-deps */
|
|
||||||
import ReactMarkdown, { Components } from 'react-markdown'
|
import ReactMarkdown, { Components } from 'react-markdown'
|
||||||
import remarkGfm from 'remark-gfm'
|
import remarkGfm from 'remark-gfm'
|
||||||
import remarkEmoji from 'remark-emoji'
|
import remarkEmoji from 'remark-emoji'
|
||||||
@ -154,7 +153,7 @@ const CodeComponent = memo(
|
|||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{React.createElement(SyntaxHighlighter as React.ComponentType<any>, {
|
{React.createElement(SyntaxHighlighter as React.ComponentType<Record<string, unknown>>, {
|
||||||
style:
|
style:
|
||||||
prismStyles[
|
prismStyles[
|
||||||
codeBlockStyle
|
codeBlockStyle
|
||||||
|
|||||||
@ -6,6 +6,37 @@ import { useNavigate, useMatches } from '@tanstack/react-router'
|
|||||||
import { useGeneralSetting } from '@/hooks/useGeneralSetting'
|
import { useGeneralSetting } from '@/hooks/useGeneralSetting'
|
||||||
import { useModelProvider } from '@/hooks/useModelProvider'
|
import { useModelProvider } from '@/hooks/useModelProvider'
|
||||||
|
|
||||||
|
// Mock global platform constants - simulate desktop (Tauri) environment
|
||||||
|
Object.defineProperty(global, 'IS_IOS', { value: false, writable: true })
|
||||||
|
Object.defineProperty(global, 'IS_ANDROID', { value: false, writable: true })
|
||||||
|
Object.defineProperty(global, 'IS_WEB_APP', { value: false, writable: true })
|
||||||
|
|
||||||
|
// Mock platform features
|
||||||
|
vi.mock('@/lib/platform/const', () => ({
|
||||||
|
PlatformFeatures: {
|
||||||
|
hardwareMonitoring: true,
|
||||||
|
shortcut: true, // Desktop has shortcuts enabled
|
||||||
|
localInference: true,
|
||||||
|
localApiServer: true,
|
||||||
|
modelHub: true,
|
||||||
|
systemIntegrations: true,
|
||||||
|
httpsProxy: true,
|
||||||
|
defaultProviders: true,
|
||||||
|
analytics: true,
|
||||||
|
webAutoModelSelection: false,
|
||||||
|
modelProviderSettings: true,
|
||||||
|
mcpAutoApproveTools: false,
|
||||||
|
mcpServersSettings: true,
|
||||||
|
extensionsSettings: true,
|
||||||
|
assistants: true,
|
||||||
|
authentication: false,
|
||||||
|
googleAnalytics: false,
|
||||||
|
alternateShortcutBindings: false,
|
||||||
|
firstMessagePersistedThread: false,
|
||||||
|
temporaryChat: false,
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
// Mock dependencies
|
// Mock dependencies
|
||||||
vi.mock('@tanstack/react-router', () => ({
|
vi.mock('@tanstack/react-router', () => ({
|
||||||
Link: ({ children, to, className }: any) => (
|
Link: ({ children, to, className }: any) => (
|
||||||
@ -81,6 +112,12 @@ describe('SettingsMenu', () => {
|
|||||||
expect(screen.getByText('common:appearance')).toBeInTheDocument()
|
expect(screen.getByText('common:appearance')).toBeInTheDocument()
|
||||||
expect(screen.getByText('common:privacy')).toBeInTheDocument()
|
expect(screen.getByText('common:privacy')).toBeInTheDocument()
|
||||||
expect(screen.getByText('common:modelProviders')).toBeInTheDocument()
|
expect(screen.getByText('common:modelProviders')).toBeInTheDocument()
|
||||||
|
// Platform-specific features tested separately
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders keyboard shortcuts on desktop platforms', () => {
|
||||||
|
// This test assumes desktop platform (mocked in setup with shortcut: true)
|
||||||
|
render(<SettingsMenu />)
|
||||||
expect(screen.getByText('common:keyboardShortcuts')).toBeInTheDocument()
|
expect(screen.getByText('common:keyboardShortcuts')).toBeInTheDocument()
|
||||||
expect(screen.getByText('common:hardware')).toBeInTheDocument()
|
expect(screen.getByText('common:hardware')).toBeInTheDocument()
|
||||||
expect(screen.getByText('common:local_api_server')).toBeInTheDocument()
|
expect(screen.getByText('common:local_api_server')).toBeInTheDocument()
|
||||||
|
|||||||
@ -7,6 +7,18 @@ import {
|
|||||||
import { PlatformFeature } from '@/lib/platform/types'
|
import { PlatformFeature } from '@/lib/platform/types'
|
||||||
import { PlatformFeatures } from '@/lib/platform/const'
|
import { PlatformFeatures } from '@/lib/platform/const'
|
||||||
|
|
||||||
|
// Type definition for the auth service from extensions-web
|
||||||
|
interface AuthServiceInterface {
|
||||||
|
getAllProviders: () => string[]
|
||||||
|
loginWithProvider: (providerId: ProviderType) => Promise<void>
|
||||||
|
handleProviderCallback: (providerId: ProviderType, code: string, state?: string) => Promise<void>
|
||||||
|
isAuthenticatedWithProvider: (providerId: ProviderType) => boolean
|
||||||
|
logout: () => Promise<void>
|
||||||
|
getCurrentUser: (forceRefresh?: boolean) => Promise<User | null>
|
||||||
|
isAuthenticated: () => boolean
|
||||||
|
onAuthEvent: (callback: (event: MessageEvent) => void) => () => void
|
||||||
|
}
|
||||||
|
|
||||||
interface AuthState {
|
interface AuthState {
|
||||||
// Auth service
|
// Auth service
|
||||||
authService: JanAuthService | null
|
authService: JanAuthService | null
|
||||||
@ -69,7 +81,7 @@ const useAuthStore = create<AuthState>()((set, get) => ({
|
|||||||
if (!authService) {
|
if (!authService) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
return (authService as any).getAllProviders()
|
return (authService as AuthServiceInterface).getAllProviders()
|
||||||
},
|
},
|
||||||
|
|
||||||
loginWithProvider: async (providerId: ProviderType) => {
|
loginWithProvider: async (providerId: ProviderType) => {
|
||||||
@ -78,7 +90,7 @@ const useAuthStore = create<AuthState>()((set, get) => ({
|
|||||||
throw new Error('Authentication not available on this platform')
|
throw new Error('Authentication not available on this platform')
|
||||||
}
|
}
|
||||||
|
|
||||||
await (authService as any).loginWithProvider(providerId)
|
await (authService as AuthServiceInterface).loginWithProvider(providerId)
|
||||||
},
|
},
|
||||||
|
|
||||||
handleProviderCallback: async (
|
handleProviderCallback: async (
|
||||||
@ -91,7 +103,7 @@ const useAuthStore = create<AuthState>()((set, get) => ({
|
|||||||
throw new Error('Authentication not available on this platform')
|
throw new Error('Authentication not available on this platform')
|
||||||
}
|
}
|
||||||
|
|
||||||
await (authService as any).handleProviderCallback(providerId, code, state)
|
await (authService as AuthServiceInterface).handleProviderCallback(providerId, code, state)
|
||||||
// Reload auth state after successful callback
|
// Reload auth state after successful callback
|
||||||
await loadAuthState()
|
await loadAuthState()
|
||||||
},
|
},
|
||||||
@ -102,7 +114,7 @@ const useAuthStore = create<AuthState>()((set, get) => ({
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return (authService as any).isAuthenticatedWithProvider(providerId)
|
return (authService as AuthServiceInterface).isAuthenticatedWithProvider(providerId)
|
||||||
},
|
},
|
||||||
|
|
||||||
logout: async () => {
|
logout: async () => {
|
||||||
@ -133,7 +145,7 @@ const useAuthStore = create<AuthState>()((set, get) => ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const profile = await (authService as any).getCurrentUser(forceRefresh)
|
const profile = await (authService as AuthServiceInterface).getCurrentUser(forceRefresh)
|
||||||
set({
|
set({
|
||||||
user: profile,
|
user: profile,
|
||||||
isAuthenticated: profile !== null,
|
isAuthenticated: profile !== null,
|
||||||
@ -156,11 +168,11 @@ const useAuthStore = create<AuthState>()((set, get) => ({
|
|||||||
set({ isLoading: true })
|
set({ isLoading: true })
|
||||||
|
|
||||||
// Check if user is authenticated with any provider
|
// Check if user is authenticated with any provider
|
||||||
const isAuth = (authService as any).isAuthenticated()
|
const isAuth = (authService as AuthServiceInterface).isAuthenticated()
|
||||||
|
|
||||||
// Load user profile if authenticated
|
// Load user profile if authenticated
|
||||||
if (isAuth) {
|
if (isAuth) {
|
||||||
const profile = await (authService as any).getCurrentUser(forceRefresh)
|
const profile = await (authService as AuthServiceInterface).getCurrentUser(forceRefresh)
|
||||||
set({
|
set({
|
||||||
user: profile,
|
user: profile,
|
||||||
isAuthenticated: profile !== null,
|
isAuthenticated: profile !== null,
|
||||||
@ -184,12 +196,12 @@ const useAuthStore = create<AuthState>()((set, get) => ({
|
|||||||
|
|
||||||
subscribeToAuthEvents: (callback: (event: MessageEvent) => void) => {
|
subscribeToAuthEvents: (callback: (event: MessageEvent) => void) => {
|
||||||
const { authService } = get()
|
const { authService } = get()
|
||||||
if (!authService || typeof (authService as any).onAuthEvent !== 'function') {
|
if (!authService || typeof (authService as AuthServiceInterface).onAuthEvent !== 'function') {
|
||||||
return () => {} // Return no-op cleanup
|
return () => {} // Return no-op cleanup
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return (authService as any).onAuthEvent(callback)
|
return (authService as AuthServiceInterface).onAuthEvent(callback)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.warn('Failed to subscribe to auth events:', error)
|
console.warn('Failed to subscribe to auth events:', error)
|
||||||
return () => {}
|
return () => {}
|
||||||
|
|||||||
@ -131,6 +131,7 @@ export const useChat = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
return currentThread
|
return currentThread
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [createThread, retrieveThread, router])
|
}, [createThread, retrieveThread, router])
|
||||||
|
|
||||||
const restartModel = useCallback(
|
const restartModel = useCallback(
|
||||||
|
|||||||
@ -41,7 +41,7 @@ export const useLocalApiServer = create<LocalApiServerState>()(
|
|||||||
serverHost: '127.0.0.1',
|
serverHost: '127.0.0.1',
|
||||||
setServerHost: (value) => set({ serverHost: value }),
|
setServerHost: (value) => set({ serverHost: value }),
|
||||||
// Use port 0 (auto-assign) for mobile to avoid conflicts, 1337 for desktop
|
// Use port 0 (auto-assign) for mobile to avoid conflicts, 1337 for desktop
|
||||||
serverPort: (typeof window !== 'undefined' && (window as any).IS_ANDROID) || (typeof window !== 'undefined' && (window as any).IS_IOS) ? 0 : 1337,
|
serverPort: (typeof window !== 'undefined' && (window as { IS_ANDROID?: boolean }).IS_ANDROID) || (typeof window !== 'undefined' && (window as { IS_IOS?: boolean }).IS_IOS) ? 0 : 1337,
|
||||||
setServerPort: (value) => set({ serverPort: value }),
|
setServerPort: (value) => set({ serverPort: value }),
|
||||||
apiPrefix: '/v1',
|
apiPrefix: '/v1',
|
||||||
setApiPrefix: (value) => set({ apiPrefix: value }),
|
setApiPrefix: (value) => set({ apiPrefix: value }),
|
||||||
|
|||||||
@ -16,7 +16,7 @@ const setupMobileViewport = () => {
|
|||||||
|
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
// Update viewport meta tag to disable zoom
|
// Update viewport meta tag to disable zoom
|
||||||
let viewportMeta = document.querySelector('meta[name="viewport"]')
|
const viewportMeta = document.querySelector('meta[name="viewport"]')
|
||||||
if (viewportMeta) {
|
if (viewportMeta) {
|
||||||
viewportMeta.setAttribute('content',
|
viewportMeta.setAttribute('content',
|
||||||
'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover'
|
'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover'
|
||||||
|
|||||||
@ -91,6 +91,7 @@ export default defineConfig(({ mode }) => {
|
|||||||
watch: {
|
watch: {
|
||||||
// 3. tell vite to ignore watching `src-tauri`
|
// 3. tell vite to ignore watching `src-tauri`
|
||||||
ignored: ['**/src-tauri/**'],
|
ignored: ['**/src-tauri/**'],
|
||||||
|
usePolling: true
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user