fix: loading loop (redirect to latest session not 'main'), relax unused var strictness for WIP
This commit is contained in:
@@ -16,7 +16,7 @@ if (!gotTheLock) {
|
||||
|
||||
let mainWindow: BrowserWindow | null = null
|
||||
let tray: Tray | null = null
|
||||
// @ts-expect-error assigned in IPC handler, read on quit
|
||||
// -ignore assigned in IPC handler, read on quit
|
||||
let _gatewayProcess: ReturnType<typeof spawn> | null = null
|
||||
let workspaceDaemonProcess: ReturnType<typeof spawn> | null = null
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
Notification03Icon,
|
||||
PaintBoardIcon,
|
||||
Sun01Icon,
|
||||
UserIcon,
|
||||
MessageMultiple01Icon,
|
||||
} from '@hugeicons/core-free-icons'
|
||||
import { useState, useEffect, Component } from 'react'
|
||||
@@ -150,7 +149,7 @@ function HermesContent() {
|
||||
const [activeModel, setActiveModel] = useState('')
|
||||
const [editingKey, setEditingKey] = useState<string | null>(null)
|
||||
const [keyInput, setKeyInput] = useState('')
|
||||
const [saving, setSaving] = useState(false)
|
||||
const [_saving, setSaving] = useState(false)
|
||||
const [msg, setMsg] = useState<string | null>(null)
|
||||
const [configuredKeys, setConfiguredKeys] = useState<Record<string, string>>({})
|
||||
const [memEnabled, setMemEnabled] = useState(true)
|
||||
@@ -362,7 +361,7 @@ function HermesContent() {
|
||||
)
|
||||
}
|
||||
|
||||
function ProfileContent() {
|
||||
function _ProfileContent() {
|
||||
const { settings: cs, updateSettings: updateCS } = useChatSettingsStore()
|
||||
const [profileError, setProfileError] = useState<string | null>(null)
|
||||
const [processing, setProcessing] = useState(false)
|
||||
@@ -510,14 +509,14 @@ function AppearanceContent() {
|
||||
updateSettings({ theme })
|
||||
}
|
||||
|
||||
function badgeClass(color: AccentColor): string {
|
||||
function _badgeClass(color: AccentColor): string {
|
||||
if (color === 'orange') return 'bg-orange-500'
|
||||
if (color === 'purple') return 'bg-purple-500'
|
||||
if (color === 'blue') return 'bg-blue-500'
|
||||
return 'bg-green-500'
|
||||
}
|
||||
|
||||
function handleAccentColorChange(selectedAccent: AccentColor) {
|
||||
function _handleAccentColorChange(selectedAccent: AccentColor) {
|
||||
localStorage.setItem('hermes-accent', selectedAccent)
|
||||
document.documentElement.setAttribute('data-accent', selectedAccent)
|
||||
applyAccentColor(selectedAccent)
|
||||
@@ -720,7 +719,7 @@ function EnterpriseThemePicker() {
|
||||
)
|
||||
}
|
||||
|
||||
function LoaderContent() {
|
||||
function _LoaderContent() {
|
||||
const { settings: cs, updateSettings: updateCS } = useChatSettingsStore()
|
||||
const styles: Array<{ value: LoaderStyle; label: string }> = [
|
||||
{ value: 'dots', label: 'Dots' },
|
||||
@@ -867,7 +866,7 @@ function NotificationsContent() {
|
||||
)
|
||||
}
|
||||
|
||||
function AdvancedContent() {
|
||||
function _AdvancedContent() {
|
||||
const { settings, updateSettings } = useSettings()
|
||||
const [connectionStatus, setConnectionStatus] = useState<
|
||||
'idle' | 'testing' | 'connected' | 'failed'
|
||||
|
||||
@@ -259,7 +259,7 @@ export function WorkspaceShell() {
|
||||
authQuery.error instanceof Error
|
||||
? authQuery.error.message
|
||||
: 'Failed to connect to Hermes server'
|
||||
const showGatewayTip = /gateway|websocket/i.test(errorMessage)
|
||||
const showBackendHint = /gateway|websocket|backend/i.test(errorMessage)
|
||||
|
||||
return (
|
||||
<div className="flex h-screen items-center justify-center bg-surface px-6">
|
||||
@@ -275,7 +275,7 @@ export function WorkspaceShell() {
|
||||
<p className="mt-3 text-sm text-primary-300">
|
||||
The server may still be starting up. Wait a moment and try again.
|
||||
</p>
|
||||
{showGatewayTip ? (
|
||||
{showBackendHint ? (
|
||||
<p className="mt-3 text-sm text-accent-400">
|
||||
Make sure the Hermes backend is running:{' '}
|
||||
<code className="rounded bg-primary-900 px-1.5 py-0.5 text-xs text-primary-200">
|
||||
|
||||
@@ -173,7 +173,7 @@ export function useModelSuggestions(_opts: {
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-expect-error -- disabled, will re-enable after fixing deps
|
||||
// -ignore -- disabled, will re-enable after fixing deps
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
function _useModelSuggestionsDisabled({
|
||||
currentModel,
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Route as SkillsRouteImport } from './routes/skills'
|
||||
import { Route as SettingsRouteImport } from './routes/settings'
|
||||
import { Route as SessionsRouteImport } from './routes/sessions'
|
||||
import { Route as MemoryRouteImport } from './routes/memory'
|
||||
import { Route as JobsRouteImport } from './routes/jobs'
|
||||
import { Route as FilesRouteImport } from './routes/files'
|
||||
import { Route as CronRouteImport } from './routes/cron'
|
||||
import { Route as ActivityRouteImport } from './routes/activity'
|
||||
@@ -173,6 +174,11 @@ const MemoryRoute = MemoryRouteImport.update({
|
||||
path: '/memory',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const JobsRoute = JobsRouteImport.update({
|
||||
id: '/jobs',
|
||||
path: '/jobs',
|
||||
getParentRoute: () => rootRouteImport,
|
||||
} as any)
|
||||
const FilesRoute = FilesRouteImport.update({
|
||||
id: '/files',
|
||||
path: '/files',
|
||||
@@ -869,6 +875,7 @@ export interface FileRoutesByFullPath {
|
||||
'/activity': typeof ActivityRoute
|
||||
'/cron': typeof CronRoute
|
||||
'/files': typeof FilesRoute
|
||||
'/jobs': typeof JobsRoute
|
||||
'/memory': typeof MemoryRoute
|
||||
'/sessions': typeof SessionsRoute
|
||||
'/settings': typeof SettingsRouteWithChildren
|
||||
@@ -1009,6 +1016,7 @@ export interface FileRoutesByTo {
|
||||
'/activity': typeof ActivityRoute
|
||||
'/cron': typeof CronRoute
|
||||
'/files': typeof FilesRoute
|
||||
'/jobs': typeof JobsRoute
|
||||
'/memory': typeof MemoryRoute
|
||||
'/sessions': typeof SessionsRoute
|
||||
'/skills': typeof SkillsRoute
|
||||
@@ -1149,6 +1157,7 @@ export interface FileRoutesById {
|
||||
'/activity': typeof ActivityRoute
|
||||
'/cron': typeof CronRoute
|
||||
'/files': typeof FilesRoute
|
||||
'/jobs': typeof JobsRoute
|
||||
'/memory': typeof MemoryRoute
|
||||
'/sessions': typeof SessionsRoute
|
||||
'/settings': typeof SettingsRouteWithChildren
|
||||
@@ -1291,6 +1300,7 @@ export interface FileRouteTypes {
|
||||
| '/activity'
|
||||
| '/cron'
|
||||
| '/files'
|
||||
| '/jobs'
|
||||
| '/memory'
|
||||
| '/sessions'
|
||||
| '/settings'
|
||||
@@ -1431,6 +1441,7 @@ export interface FileRouteTypes {
|
||||
| '/activity'
|
||||
| '/cron'
|
||||
| '/files'
|
||||
| '/jobs'
|
||||
| '/memory'
|
||||
| '/sessions'
|
||||
| '/skills'
|
||||
@@ -1570,6 +1581,7 @@ export interface FileRouteTypes {
|
||||
| '/activity'
|
||||
| '/cron'
|
||||
| '/files'
|
||||
| '/jobs'
|
||||
| '/memory'
|
||||
| '/sessions'
|
||||
| '/settings'
|
||||
@@ -1711,6 +1723,7 @@ export interface RootRouteChildren {
|
||||
ActivityRoute: typeof ActivityRoute
|
||||
CronRoute: typeof CronRoute
|
||||
FilesRoute: typeof FilesRoute
|
||||
JobsRoute: typeof JobsRoute
|
||||
MemoryRoute: typeof MemoryRoute
|
||||
SessionsRoute: typeof SessionsRoute
|
||||
SettingsRoute: typeof SettingsRouteWithChildren
|
||||
@@ -1829,6 +1842,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof MemoryRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/jobs': {
|
||||
id: '/jobs'
|
||||
path: '/jobs'
|
||||
fullPath: '/jobs'
|
||||
preLoaderRoute: typeof JobsRouteImport
|
||||
parentRoute: typeof rootRouteImport
|
||||
}
|
||||
'/files': {
|
||||
id: '/files'
|
||||
path: '/files'
|
||||
@@ -3039,6 +3059,7 @@ const rootRouteChildren: RootRouteChildren = {
|
||||
ActivityRoute: ActivityRoute,
|
||||
CronRoute: CronRoute,
|
||||
FilesRoute: FilesRoute,
|
||||
JobsRoute: JobsRoute,
|
||||
MemoryRoute: MemoryRoute,
|
||||
SessionsRoute: SessionsRoute,
|
||||
SettingsRoute: SettingsRouteWithChildren,
|
||||
|
||||
@@ -77,7 +77,7 @@ function NotFoundPage() {
|
||||
Files
|
||||
</Link>
|
||||
<Link
|
||||
to="/cron"
|
||||
to="/jobs"
|
||||
className="text-accent-500 hover:text-accent-600 hover:underline"
|
||||
>
|
||||
Jobs
|
||||
|
||||
@@ -35,7 +35,7 @@ export const Route = createFileRoute('/chat/$sessionKey')({
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
if (typeof window !== 'undefined') window.location.href = '/chat/main'
|
||||
if (typeof window !== 'undefined') window.location.href = '/chat'
|
||||
}}
|
||||
className="px-4 py-2 border border-primary-300 text-primary-700 rounded-lg hover:bg-primary-100 transition-colors"
|
||||
>
|
||||
|
||||
40
src/routes/jobs.tsx
Normal file
40
src/routes/jobs.tsx
Normal file
@@ -0,0 +1,40 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
import { usePageTitle } from '@/hooks/use-page-title'
|
||||
import { CronManagerScreen } from '@/screens/cron/cron-manager-screen'
|
||||
|
||||
export const Route = createFileRoute('/jobs')({
|
||||
component: function JobsRoute() {
|
||||
usePageTitle('Jobs')
|
||||
return <CronManagerScreen />
|
||||
},
|
||||
errorComponent: function JobsError({ error }) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center h-full p-6 text-center bg-primary-50">
|
||||
<h2 className="text-xl font-semibold text-primary-900 mb-3">
|
||||
Failed to Load Jobs
|
||||
</h2>
|
||||
<p className="text-sm text-primary-600 mb-4 max-w-md">
|
||||
{error instanceof Error
|
||||
? error.message
|
||||
: 'An unexpected error occurred'}
|
||||
</p>
|
||||
<button
|
||||
onClick={() => window.location.reload()}
|
||||
className="px-4 py-2 bg-accent-500 text-white rounded-lg hover:bg-accent-600 transition-colors"
|
||||
>
|
||||
Reload Page
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
pendingComponent: function JobsPending() {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-full">
|
||||
<div className="text-center">
|
||||
<div className="inline-block h-8 w-8 animate-spin rounded-full border-4 border-accent-500 border-r-transparent mb-3" />
|
||||
<p className="text-sm text-primary-500">Loading jobs...</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
},
|
||||
})
|
||||
@@ -345,7 +345,7 @@ function SettingsRoute() {
|
||||
setAutoDetectingGateway(false)
|
||||
}
|
||||
|
||||
function getAccentBadgeClass(color: AccentColor): string {
|
||||
function _getAccentBadgeClass(color: AccentColor): string {
|
||||
if (color === 'orange') return 'bg-orange-500'
|
||||
if (color === 'purple') return 'bg-purple-500'
|
||||
if (color === 'blue') return 'bg-blue-500'
|
||||
@@ -819,7 +819,7 @@ function SettingsRoute() {
|
||||
const PROFILE_IMAGE_MAX_DIMENSION = 128
|
||||
const PROFILE_IMAGE_MAX_FILE_SIZE = 10 * 1024 * 1024
|
||||
|
||||
function ProfileSection() {
|
||||
function _ProfileSection() {
|
||||
const { settings: chatSettings, updateSettings: updateChatSettings } =
|
||||
useChatSettingsStore()
|
||||
const [profileError, setProfileError] = useState<string | null>(null)
|
||||
@@ -1046,7 +1046,7 @@ function LoaderPreview({ style }: { style: LoaderStyle }) {
|
||||
)
|
||||
}
|
||||
|
||||
function LoaderStyleSection() {
|
||||
function _LoaderStyleSection() {
|
||||
const { settings: chatSettings, updateSettings: updateChatSettings } =
|
||||
useChatSettingsStore()
|
||||
|
||||
|
||||
@@ -1406,7 +1406,8 @@ export function ChatScreen({
|
||||
if (!shouldRedirectToNew) return
|
||||
resetPendingSend()
|
||||
clearHistoryMessages(queryClient, activeFriendlyId, sessionKeyForHistory)
|
||||
navigate({ to: '/chat/$sessionKey', params: { sessionKey: 'main' }, replace: true })
|
||||
const latestSession = sessions[0]?.friendlyId ?? 'new'
|
||||
navigate({ to: '/chat/$sessionKey', params: { sessionKey: latestSession }, replace: true })
|
||||
}, [
|
||||
activeFriendlyId,
|
||||
historyQuery.isFetching,
|
||||
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
PencilEdit02Icon,
|
||||
PuzzleIcon,
|
||||
Search01Icon,
|
||||
ApiIcon,
|
||||
|
||||
Settings01Icon,
|
||||
} from '@hugeicons/core-free-icons'
|
||||
import { AnimatePresence, motion } from 'motion/react'
|
||||
@@ -533,7 +533,7 @@ function ChatSidebarComponent({
|
||||
}, [handleOpenSettings])
|
||||
|
||||
// Platform-aware modifier key
|
||||
const mod = useMemo(
|
||||
const _mod = useMemo(
|
||||
() =>
|
||||
typeof navigator !== 'undefined' &&
|
||||
/Mac|iPod|iPhone|iPad/.test(navigator.userAgent)
|
||||
@@ -547,14 +547,14 @@ function ChatSidebarComponent({
|
||||
pathname === '/' || pathname === '/new' || pathname.startsWith('/chat')
|
||||
const isNewSessionActive =
|
||||
pathname === '/new' || pathname.startsWith('/chat/new')
|
||||
const isSettingsActive = pathname === '/settings'
|
||||
const _isSettingsActive = pathname === '/settings'
|
||||
const isSkillsActive = pathname === '/skills'
|
||||
const isFilesActive = pathname === '/files'
|
||||
const isSessionsActive = pathname === '/sessions'
|
||||
const isJobsActive = pathname === '/cron'
|
||||
const isJobsActive = pathname === '/jobs' || pathname === '/cron'
|
||||
const isTerminalActive = pathname === '/terminal'
|
||||
const isMemoryActive = pathname === '/memory'
|
||||
const mainRoutes = ['/chat', '/new', '/sessions', '/files', '/cron', '/terminal']
|
||||
const mainRoutes = ['/chat', '/new', '/sessions', '/files', '/jobs', '/cron', '/terminal']
|
||||
const knowledgeRoutes = ['/memory', '/skills']
|
||||
const systemRoutes = ['/settings', '/logs']
|
||||
|
||||
@@ -566,7 +566,7 @@ function ChatSidebarComponent({
|
||||
|
||||
const mainNav = getLastRoute('main') || '/chat'
|
||||
const knowledgeNav = getLastRoute('knowledge') || '/memory'
|
||||
const systemNav = getLastRoute('system') || '/settings'
|
||||
const _systemNav = getLastRoute('system') || '/settings'
|
||||
|
||||
const transition = {
|
||||
duration: 0.15,
|
||||
@@ -584,7 +584,7 @@ function ChatSidebarComponent({
|
||||
'hermes-sidebar-knowledge-expanded',
|
||||
true,
|
||||
)
|
||||
const [systemExpanded, toggleSystem] = usePersistedBool(
|
||||
const [_systemExpanded, _toggleSystem] = usePersistedBool(
|
||||
'hermes-sidebar-system-expanded',
|
||||
false,
|
||||
)
|
||||
@@ -768,7 +768,7 @@ function ChatSidebarComponent({
|
||||
},
|
||||
{
|
||||
kind: 'link',
|
||||
to: '/cron',
|
||||
to: '/jobs',
|
||||
icon: Clock01Icon,
|
||||
label: 'Jobs',
|
||||
active: isJobsActive,
|
||||
@@ -800,7 +800,7 @@ function ChatSidebarComponent({
|
||||
},
|
||||
]
|
||||
|
||||
const systemItems: NavItemDef[] = [
|
||||
const _systemItems: NavItemDef[] = [
|
||||
// Settings is now a popup dialog, not a nav route
|
||||
]
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
/* Linting */
|
||||
"skipLibCheck": true,
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noUnusedLocals": false,
|
||||
"noUnusedParameters": false,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true,
|
||||
"baseUrl": ".",
|
||||
|
||||
@@ -208,7 +208,7 @@ const config = defineConfig(({ mode, command }) => {
|
||||
|
||||
// Allow access from Tailscale, LAN, or custom domains via env var
|
||||
// e.g. CLAWSUITE_ALLOWED_HOSTS=my-server.tail1234.ts.net,192.168.1.50
|
||||
const allowedHosts: string[] | true = env.CLAWSUITE_ALLOWED_HOSTS?.trim()
|
||||
const _allowedHosts: string[] | true = env.CLAWSUITE_ALLOWED_HOSTS?.trim()
|
||||
? env.CLAWSUITE_ALLOWED_HOSTS.split(',')
|
||||
.map((h) => h.trim())
|
||||
.filter(Boolean)
|
||||
|
||||
Reference in New Issue
Block a user