Merge pull request #5060 from menloresearch/feat/app-logs
feat: initial app logs
This commit is contained in:
commit
81e88f6632
14
src-tauri/capabilities/log-app-window.json
Normal file
14
src-tauri/capabilities/log-app-window.json
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"$schema": "../gen/schemas/desktop-schema.json",
|
||||||
|
"identifier": "logs-app-window",
|
||||||
|
"description": "enables permissions for the logs app window",
|
||||||
|
"windows": ["logs-app-window"],
|
||||||
|
"permissions": [
|
||||||
|
"core:default",
|
||||||
|
"core:window:allow-start-dragging",
|
||||||
|
"core:window:allow-set-theme",
|
||||||
|
"log:default",
|
||||||
|
"core:webview:allow-create-webview-window",
|
||||||
|
"core:window:allow-set-focus"
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
export const route = {
|
export const route = {
|
||||||
// home as new chat or thread
|
// home as new chat or thread
|
||||||
home: '/',
|
home: '/',
|
||||||
|
appLogs: '/logs',
|
||||||
assistant: '/assistant',
|
assistant: '/assistant',
|
||||||
settings: {
|
settings: {
|
||||||
index: '/settings',
|
index: '/settings',
|
||||||
|
|||||||
5
web-app/src/constants/windows.ts
Normal file
5
web-app/src/constants/windows.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const windowKey = {
|
||||||
|
logsAppWindow: 'logs-app-window',
|
||||||
|
logsWindowLocalApiServer: 'logs-window-local-api-server',
|
||||||
|
systemMonitorWindow: 'system-monitor-window',
|
||||||
|
}
|
||||||
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
import { Route as rootRoute } from './routes/__root'
|
import { Route as rootRoute } from './routes/__root'
|
||||||
import { Route as SystemMonitorImport } from './routes/system-monitor'
|
import { Route as SystemMonitorImport } from './routes/system-monitor'
|
||||||
|
import { Route as LogsImport } from './routes/logs'
|
||||||
import { Route as HubImport } from './routes/hub'
|
import { Route as HubImport } from './routes/hub'
|
||||||
import { Route as AssistantImport } from './routes/assistant'
|
import { Route as AssistantImport } from './routes/assistant'
|
||||||
import { Route as IndexImport } from './routes/index'
|
import { Route as IndexImport } from './routes/index'
|
||||||
@ -36,6 +37,12 @@ const SystemMonitorRoute = SystemMonitorImport.update({
|
|||||||
getParentRoute: () => rootRoute,
|
getParentRoute: () => rootRoute,
|
||||||
} as any)
|
} as any)
|
||||||
|
|
||||||
|
const LogsRoute = LogsImport.update({
|
||||||
|
id: '/logs',
|
||||||
|
path: '/logs',
|
||||||
|
getParentRoute: () => rootRoute,
|
||||||
|
} as any)
|
||||||
|
|
||||||
const HubRoute = HubImport.update({
|
const HubRoute = HubImport.update({
|
||||||
id: '/hub',
|
id: '/hub',
|
||||||
path: '/hub',
|
path: '/hub',
|
||||||
@ -152,6 +159,13 @@ declare module '@tanstack/react-router' {
|
|||||||
preLoaderRoute: typeof HubImport
|
preLoaderRoute: typeof HubImport
|
||||||
parentRoute: typeof rootRoute
|
parentRoute: typeof rootRoute
|
||||||
}
|
}
|
||||||
|
'/logs': {
|
||||||
|
id: '/logs'
|
||||||
|
path: '/logs'
|
||||||
|
fullPath: '/logs'
|
||||||
|
preLoaderRoute: typeof LogsImport
|
||||||
|
parentRoute: typeof rootRoute
|
||||||
|
}
|
||||||
'/system-monitor': {
|
'/system-monitor': {
|
||||||
id: '/system-monitor'
|
id: '/system-monitor'
|
||||||
path: '/system-monitor'
|
path: '/system-monitor'
|
||||||
@ -252,6 +266,7 @@ export interface FileRoutesByFullPath {
|
|||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/assistant': typeof AssistantRoute
|
'/assistant': typeof AssistantRoute
|
||||||
'/hub': typeof HubRoute
|
'/hub': typeof HubRoute
|
||||||
|
'/logs': typeof LogsRoute
|
||||||
'/system-monitor': typeof SystemMonitorRoute
|
'/system-monitor': typeof SystemMonitorRoute
|
||||||
'/local-api-server/logs': typeof LocalApiServerLogsRoute
|
'/local-api-server/logs': typeof LocalApiServerLogsRoute
|
||||||
'/settings/appearance': typeof SettingsAppearanceRoute
|
'/settings/appearance': typeof SettingsAppearanceRoute
|
||||||
@ -271,6 +286,7 @@ export interface FileRoutesByTo {
|
|||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/assistant': typeof AssistantRoute
|
'/assistant': typeof AssistantRoute
|
||||||
'/hub': typeof HubRoute
|
'/hub': typeof HubRoute
|
||||||
|
'/logs': typeof LogsRoute
|
||||||
'/system-monitor': typeof SystemMonitorRoute
|
'/system-monitor': typeof SystemMonitorRoute
|
||||||
'/local-api-server/logs': typeof LocalApiServerLogsRoute
|
'/local-api-server/logs': typeof LocalApiServerLogsRoute
|
||||||
'/settings/appearance': typeof SettingsAppearanceRoute
|
'/settings/appearance': typeof SettingsAppearanceRoute
|
||||||
@ -291,6 +307,7 @@ export interface FileRoutesById {
|
|||||||
'/': typeof IndexRoute
|
'/': typeof IndexRoute
|
||||||
'/assistant': typeof AssistantRoute
|
'/assistant': typeof AssistantRoute
|
||||||
'/hub': typeof HubRoute
|
'/hub': typeof HubRoute
|
||||||
|
'/logs': typeof LogsRoute
|
||||||
'/system-monitor': typeof SystemMonitorRoute
|
'/system-monitor': typeof SystemMonitorRoute
|
||||||
'/local-api-server/logs': typeof LocalApiServerLogsRoute
|
'/local-api-server/logs': typeof LocalApiServerLogsRoute
|
||||||
'/settings/appearance': typeof SettingsAppearanceRoute
|
'/settings/appearance': typeof SettingsAppearanceRoute
|
||||||
@ -312,6 +329,7 @@ export interface FileRouteTypes {
|
|||||||
| '/'
|
| '/'
|
||||||
| '/assistant'
|
| '/assistant'
|
||||||
| '/hub'
|
| '/hub'
|
||||||
|
| '/logs'
|
||||||
| '/system-monitor'
|
| '/system-monitor'
|
||||||
| '/local-api-server/logs'
|
| '/local-api-server/logs'
|
||||||
| '/settings/appearance'
|
| '/settings/appearance'
|
||||||
@ -330,6 +348,7 @@ export interface FileRouteTypes {
|
|||||||
| '/'
|
| '/'
|
||||||
| '/assistant'
|
| '/assistant'
|
||||||
| '/hub'
|
| '/hub'
|
||||||
|
| '/logs'
|
||||||
| '/system-monitor'
|
| '/system-monitor'
|
||||||
| '/local-api-server/logs'
|
| '/local-api-server/logs'
|
||||||
| '/settings/appearance'
|
| '/settings/appearance'
|
||||||
@ -348,6 +367,7 @@ export interface FileRouteTypes {
|
|||||||
| '/'
|
| '/'
|
||||||
| '/assistant'
|
| '/assistant'
|
||||||
| '/hub'
|
| '/hub'
|
||||||
|
| '/logs'
|
||||||
| '/system-monitor'
|
| '/system-monitor'
|
||||||
| '/local-api-server/logs'
|
| '/local-api-server/logs'
|
||||||
| '/settings/appearance'
|
| '/settings/appearance'
|
||||||
@ -368,6 +388,7 @@ export interface RootRouteChildren {
|
|||||||
IndexRoute: typeof IndexRoute
|
IndexRoute: typeof IndexRoute
|
||||||
AssistantRoute: typeof AssistantRoute
|
AssistantRoute: typeof AssistantRoute
|
||||||
HubRoute: typeof HubRoute
|
HubRoute: typeof HubRoute
|
||||||
|
LogsRoute: typeof LogsRoute
|
||||||
SystemMonitorRoute: typeof SystemMonitorRoute
|
SystemMonitorRoute: typeof SystemMonitorRoute
|
||||||
LocalApiServerLogsRoute: typeof LocalApiServerLogsRoute
|
LocalApiServerLogsRoute: typeof LocalApiServerLogsRoute
|
||||||
SettingsAppearanceRoute: typeof SettingsAppearanceRoute
|
SettingsAppearanceRoute: typeof SettingsAppearanceRoute
|
||||||
@ -387,6 +408,7 @@ const rootRouteChildren: RootRouteChildren = {
|
|||||||
IndexRoute: IndexRoute,
|
IndexRoute: IndexRoute,
|
||||||
AssistantRoute: AssistantRoute,
|
AssistantRoute: AssistantRoute,
|
||||||
HubRoute: HubRoute,
|
HubRoute: HubRoute,
|
||||||
|
LogsRoute: LogsRoute,
|
||||||
SystemMonitorRoute: SystemMonitorRoute,
|
SystemMonitorRoute: SystemMonitorRoute,
|
||||||
LocalApiServerLogsRoute: LocalApiServerLogsRoute,
|
LocalApiServerLogsRoute: LocalApiServerLogsRoute,
|
||||||
SettingsAppearanceRoute: SettingsAppearanceRoute,
|
SettingsAppearanceRoute: SettingsAppearanceRoute,
|
||||||
@ -415,6 +437,7 @@ export const routeTree = rootRoute
|
|||||||
"/",
|
"/",
|
||||||
"/assistant",
|
"/assistant",
|
||||||
"/hub",
|
"/hub",
|
||||||
|
"/logs",
|
||||||
"/system-monitor",
|
"/system-monitor",
|
||||||
"/local-api-server/logs",
|
"/local-api-server/logs",
|
||||||
"/settings/appearance",
|
"/settings/appearance",
|
||||||
@ -439,6 +462,9 @@ export const routeTree = rootRoute
|
|||||||
"/hub": {
|
"/hub": {
|
||||||
"filePath": "hub.tsx"
|
"filePath": "hub.tsx"
|
||||||
},
|
},
|
||||||
|
"/logs": {
|
||||||
|
"filePath": "logs.tsx"
|
||||||
|
},
|
||||||
"/system-monitor": {
|
"/system-monitor": {
|
||||||
"filePath": "system-monitor.tsx"
|
"filePath": "system-monitor.tsx"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -60,7 +60,8 @@ function RootLayout() {
|
|||||||
const router = useRouterState()
|
const router = useRouterState()
|
||||||
const isLocalAPIServerLogsRoute =
|
const isLocalAPIServerLogsRoute =
|
||||||
router.location.pathname === route.localApiServerlogs ||
|
router.location.pathname === route.localApiServerlogs ||
|
||||||
router.location.pathname === route.systemMonitor
|
router.location.pathname === route.systemMonitor ||
|
||||||
|
router.location.pathname === route.appLogs
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
|||||||
116
web-app/src/routes/logs.tsx
Normal file
116
web-app/src/routes/logs.tsx
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
import { createFileRoute } from '@tanstack/react-router'
|
||||||
|
import { route } from '@/constants/routes'
|
||||||
|
|
||||||
|
import { useEffect, useState, useRef } from 'react'
|
||||||
|
import { parseLogLine, readLogs } from '@/services/app'
|
||||||
|
import { listen } from '@tauri-apps/api/event'
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
export const Route = createFileRoute(route.appLogs as any)({
|
||||||
|
component: LogsViewer,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Define log entry type
|
||||||
|
interface LogEntry {
|
||||||
|
timestamp: string
|
||||||
|
level: 'info' | 'warn' | 'error' | 'debug'
|
||||||
|
target: string
|
||||||
|
message: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const LOG_EVENT_NAME = 'log://log'
|
||||||
|
|
||||||
|
function LogsViewer() {
|
||||||
|
const [logs, setLogs] = useState<LogEntry[]>([])
|
||||||
|
const logsContainerRef = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
readLogs().then((logData) => {
|
||||||
|
const logs = logData.filter(Boolean) as LogEntry[]
|
||||||
|
setLogs(logs)
|
||||||
|
|
||||||
|
// Scroll to bottom after initial logs are loaded
|
||||||
|
setTimeout(() => {
|
||||||
|
scrollToBottom()
|
||||||
|
}, 100)
|
||||||
|
})
|
||||||
|
let unsubscribe = () => {}
|
||||||
|
listen(LOG_EVENT_NAME, (event) => {
|
||||||
|
const { message } = event.payload as { message: string }
|
||||||
|
const log: LogEntry | undefined = parseLogLine(message)
|
||||||
|
if (log) {
|
||||||
|
setLogs((prevLogs) => {
|
||||||
|
const newLogs = [...prevLogs, log]
|
||||||
|
// Schedule scroll to bottom after state update
|
||||||
|
setTimeout(() => {
|
||||||
|
scrollToBottom()
|
||||||
|
}, 0)
|
||||||
|
return newLogs
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}).then((unsub) => {
|
||||||
|
unsubscribe = unsub
|
||||||
|
})
|
||||||
|
return () => {
|
||||||
|
unsubscribe()
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// Function to scroll to the bottom of the logs container
|
||||||
|
const scrollToBottom = () => {
|
||||||
|
if (logsContainerRef.current) {
|
||||||
|
const { scrollHeight, clientHeight } = logsContainerRef.current
|
||||||
|
logsContainerRef.current.scrollTop = scrollHeight - clientHeight
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to get appropriate color for log level
|
||||||
|
const getLogLevelColor = (level: string) => {
|
||||||
|
switch (level) {
|
||||||
|
case 'error':
|
||||||
|
return 'text-red-500'
|
||||||
|
case 'warn':
|
||||||
|
return 'text-yellow-500'
|
||||||
|
case 'info':
|
||||||
|
return 'text-blue-500'
|
||||||
|
case 'debug':
|
||||||
|
return 'text-gray-500'
|
||||||
|
default:
|
||||||
|
return 'text-gray-500'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format timestamp to be more readable
|
||||||
|
const formatTimestamp = (timestamp: string) => {
|
||||||
|
const date = new Date(timestamp)
|
||||||
|
return date.toLocaleTimeString()
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col h-full bg-main-view">
|
||||||
|
<div className="flex-1 overflow-auto" ref={logsContainerRef}>
|
||||||
|
<div className="font-mono p-2">
|
||||||
|
{logs.length === 0 ? (
|
||||||
|
<div className="text-center text-main-view-fg/50 py-8">
|
||||||
|
No logs available
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
logs.map((log, index) => (
|
||||||
|
<div key={index} className="mb-1 flex">
|
||||||
|
<span className="text-muted-foreground mr-2">
|
||||||
|
[{formatTimestamp(log.timestamp)}]
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
className={`mr-2 font-semibold ${getLogLevelColor(log.level)}`}
|
||||||
|
>
|
||||||
|
{log.level.toUpperCase()}
|
||||||
|
</span>
|
||||||
|
<span>{log.message}</span>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@ -26,7 +26,9 @@ import {
|
|||||||
getJanDataFolder,
|
getJanDataFolder,
|
||||||
relocateJanDataFolder,
|
relocateJanDataFolder,
|
||||||
} from '@/services/app'
|
} from '@/services/app'
|
||||||
import { IconFolder } from '@tabler/icons-react'
|
import { IconFolder, IconLogs } from '@tabler/icons-react'
|
||||||
|
import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||||
|
import { windowKey } from '@/constants/windows'
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export const Route = createFileRoute(route.settings.general as any)({
|
export const Route = createFileRoute(route.settings.general as any)({
|
||||||
@ -52,6 +54,43 @@ function General() {
|
|||||||
await factoryReset()
|
await factoryReset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleOpenLogs = async () => {
|
||||||
|
try {
|
||||||
|
// Check if logs window already exists
|
||||||
|
const existingWindow = await WebviewWindow.getByLabel(
|
||||||
|
windowKey.logsAppWindow
|
||||||
|
)
|
||||||
|
|
||||||
|
if (existingWindow) {
|
||||||
|
// If window exists, focus it
|
||||||
|
await existingWindow.setFocus()
|
||||||
|
console.log('Focused existing logs window')
|
||||||
|
} else {
|
||||||
|
// Create a new logs window using Tauri v2 WebviewWindow API
|
||||||
|
const logsWindow = new WebviewWindow(windowKey.logsAppWindow, {
|
||||||
|
url: route.appLogs,
|
||||||
|
title: 'App Logs - Jan',
|
||||||
|
width: 800,
|
||||||
|
height: 600,
|
||||||
|
resizable: true,
|
||||||
|
center: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Listen for window creation
|
||||||
|
logsWindow.once('tauri://created', () => {
|
||||||
|
console.log('Logs window created')
|
||||||
|
})
|
||||||
|
|
||||||
|
// Listen for window errors
|
||||||
|
logsWindow.once('tauri://error', (e) => {
|
||||||
|
console.error('Error creating logs window:', e)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to open logs window:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full">
|
<div className="flex flex-col h-full">
|
||||||
<HeaderPage>
|
<HeaderPage>
|
||||||
@ -66,9 +105,7 @@ function General() {
|
|||||||
<CardItem
|
<CardItem
|
||||||
title="App Version"
|
title="App Version"
|
||||||
actions={
|
actions={
|
||||||
<>
|
<span className="text-main-view-fg/80">v{VERSION}</span>
|
||||||
<span className="text-main-view-fg/80">v{VERSION}</span>
|
|
||||||
</>
|
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<CardItem
|
<CardItem
|
||||||
@ -110,6 +147,7 @@ function General() {
|
|||||||
variant="link"
|
variant="link"
|
||||||
size="sm"
|
size="sm"
|
||||||
className="hover:no-underline"
|
className="hover:no-underline"
|
||||||
|
title="App Data Folder"
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const selectedPath = await open({
|
const selectedPath = await open({
|
||||||
multiple: false,
|
multiple: false,
|
||||||
@ -137,10 +175,20 @@ function General() {
|
|||||||
title={t('settings.dataFolder.appLogs', {
|
title={t('settings.dataFolder.appLogs', {
|
||||||
ns: 'settings',
|
ns: 'settings',
|
||||||
})}
|
})}
|
||||||
description={t('settings.dataFolder.appLogsDesc', {
|
description="View detailed logs of the App"
|
||||||
ns: 'settings',
|
actions={
|
||||||
})}
|
<Button
|
||||||
actions={<></>}
|
variant="link"
|
||||||
|
size="sm"
|
||||||
|
onClick={handleOpenLogs}
|
||||||
|
title="App Logs"
|
||||||
|
>
|
||||||
|
{/* Open Logs */}
|
||||||
|
<div className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/15 bg-main-view-fg/10 transition-all duration-200 ease-in-out">
|
||||||
|
<IconLogs size={18} className="text-main-view-fg/50" />
|
||||||
|
</div>
|
||||||
|
</Button>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
|||||||
@ -31,6 +31,7 @@ import {
|
|||||||
import { getHardwareInfo } from '@/services/hardware'
|
import { getHardwareInfo } from '@/services/hardware'
|
||||||
import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
|
import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||||
import { formatMegaBytes } from '@/lib/utils'
|
import { formatMegaBytes } from '@/lib/utils'
|
||||||
|
import { windowKey } from '@/constants/windows'
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export const Route = createFileRoute(route.settings.hardware as any)({
|
export const Route = createFileRoute(route.settings.hardware as any)({
|
||||||
@ -167,7 +168,7 @@ function Hardware() {
|
|||||||
try {
|
try {
|
||||||
// Check if system monitor window already exists
|
// Check if system monitor window already exists
|
||||||
const existingWindow = await WebviewWindow.getByLabel(
|
const existingWindow = await WebviewWindow.getByLabel(
|
||||||
'system-monitor-window'
|
windowKey.systemMonitorWindow
|
||||||
)
|
)
|
||||||
|
|
||||||
if (existingWindow) {
|
if (existingWindow) {
|
||||||
@ -176,7 +177,7 @@ function Hardware() {
|
|||||||
console.log('Focused existing system monitor window')
|
console.log('Focused existing system monitor window')
|
||||||
} else {
|
} else {
|
||||||
// Create a new system monitor window
|
// Create a new system monitor window
|
||||||
const monitorWindow = new WebviewWindow('system-monitor-window', {
|
const monitorWindow = new WebviewWindow(windowKey.systemMonitorWindow, {
|
||||||
url: route.systemMonitor,
|
url: route.systemMonitor,
|
||||||
title: 'System Monitor - Jan',
|
title: 'System Monitor - Jan',
|
||||||
width: 900,
|
width: 900,
|
||||||
|
|||||||
@ -12,6 +12,8 @@ import { ApiPrefixInput } from '@/containers/ApiPrefixInput'
|
|||||||
import { useLocalApiServer } from '@/hooks/useLocalApiServer'
|
import { useLocalApiServer } from '@/hooks/useLocalApiServer'
|
||||||
import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
|
import { WebviewWindow } from '@tauri-apps/api/webviewWindow'
|
||||||
import { useAppState } from '@/hooks/useAppState'
|
import { useAppState } from '@/hooks/useAppState'
|
||||||
|
import { windowKey } from '@/constants/windows'
|
||||||
|
import { IconLogs } from '@tabler/icons-react'
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export const Route = createFileRoute(route.settings.local_api_server as any)({
|
export const Route = createFileRoute(route.settings.local_api_server as any)({
|
||||||
@ -63,7 +65,7 @@ function LocalAPIServer() {
|
|||||||
try {
|
try {
|
||||||
// Check if logs window already exists
|
// Check if logs window already exists
|
||||||
const existingWindow = await WebviewWindow.getByLabel(
|
const existingWindow = await WebviewWindow.getByLabel(
|
||||||
'logs-window-local-api-server'
|
windowKey.logsWindowLocalApiServer
|
||||||
)
|
)
|
||||||
|
|
||||||
if (existingWindow) {
|
if (existingWindow) {
|
||||||
@ -72,14 +74,17 @@ function LocalAPIServer() {
|
|||||||
console.log('Focused existing logs window')
|
console.log('Focused existing logs window')
|
||||||
} else {
|
} else {
|
||||||
// Create a new logs window using Tauri v2 WebviewWindow API
|
// Create a new logs window using Tauri v2 WebviewWindow API
|
||||||
const logsWindow = new WebviewWindow('logs-window-local-api-server', {
|
const logsWindow = new WebviewWindow(
|
||||||
url: '/local-api-server/logs',
|
windowKey.logsWindowLocalApiServer,
|
||||||
title: 'Local API server Logs - Jan',
|
{
|
||||||
width: 800,
|
url: route.localApiServerlogs,
|
||||||
height: 600,
|
title: 'Local API server Logs - Jan',
|
||||||
resizable: true,
|
width: 800,
|
||||||
center: true,
|
height: 600,
|
||||||
})
|
resizable: true,
|
||||||
|
center: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// Listen for window creation
|
// Listen for window creation
|
||||||
logsWindow.once('tauri://created', () => {
|
logsWindow.once('tauri://created', () => {
|
||||||
@ -131,8 +136,15 @@ function LocalAPIServer() {
|
|||||||
title="Server Logs"
|
title="Server Logs"
|
||||||
description="View detailed logs of the local API server"
|
description="View detailed logs of the local API server"
|
||||||
actions={
|
actions={
|
||||||
<Button variant="link" size="sm" onClick={handleOpenLogs}>
|
<Button
|
||||||
Open Logs
|
variant="link"
|
||||||
|
size="sm"
|
||||||
|
onClick={handleOpenLogs}
|
||||||
|
title="Server Logs"
|
||||||
|
>
|
||||||
|
<div className="size-6 cursor-pointer flex items-center justify-center rounded hover:bg-main-view-fg/15 bg-main-view-fg/10 transition-all duration-200 ease-in-out">
|
||||||
|
<IconLogs size={18} className="text-main-view-fg/50" />
|
||||||
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user