Use URL-based routing instead of local state
This commit is contained in:
parent
68274d8651
commit
45b1903e6b
|
|
@ -1,7 +1,7 @@
|
||||||
import { useEffect } from 'hono/jsx'
|
import { useEffect } from 'hono/jsx'
|
||||||
import { openAppSelectorModal } from '../modals'
|
import { openAppSelectorModal } from '../modals'
|
||||||
import { navigate } from '../router'
|
import { navigate } from '../router'
|
||||||
import { dashboardTab, isNarrow, setDashboardTab } from '../state'
|
import { dashboardTab, isNarrow } from '../state'
|
||||||
import {
|
import {
|
||||||
AppSelectorChevron,
|
AppSelectorChevron,
|
||||||
DashboardContainer,
|
DashboardContainer,
|
||||||
|
|
@ -30,8 +30,7 @@ export function DashboardLanding({ render }: { render: () => void }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const switchTab = (tab: typeof dashboardTab) => {
|
const switchTab = (tab: typeof dashboardTab) => {
|
||||||
setDashboardTab(tab)
|
navigate(tab === 'urls' ? '/' : `/${tab}`)
|
||||||
render()
|
|
||||||
if (tab === 'logs') scrollLogsToBottom()
|
if (tab === 'logs') scrollLogsToBottom()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import type { App } from '../../shared/types'
|
import type { App } from '../../shared/types'
|
||||||
import { apps, getSelectedTab, setSelectedTab } from '../state'
|
import { navigate } from '../router'
|
||||||
|
import { apps, getSelectedTab } from '../state'
|
||||||
import { Tab, TabBar } from '../styles'
|
import { Tab, TabBar } from '../styles'
|
||||||
import { resetToolIframe } from '../tool-iframes'
|
import { resetToolIframe } from '../tool-iframes'
|
||||||
|
|
||||||
|
|
@ -12,8 +13,7 @@ export function Nav({ app, render }: { app: App; render: () => void }) {
|
||||||
resetToolIframe(tab, app.name)
|
resetToolIframe(tab, app.name)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setSelectedTab(app.name, tab)
|
navigate(tab === 'overview' ? `/app/${app.name}` : `/app/${app.name}/${tab}`)
|
||||||
render()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all tools
|
// Find all tools
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { setCurrentView, setSelectedApp } from './state'
|
import { setCurrentView, setDashboardTab, setSelectedApp, setSelectedTab } from './state'
|
||||||
|
|
||||||
let _render: () => void
|
let _render: () => void
|
||||||
|
|
||||||
|
|
@ -31,14 +31,27 @@ function route() {
|
||||||
const path = location.pathname
|
const path = location.pathname
|
||||||
|
|
||||||
if (path.startsWith('/app/')) {
|
if (path.startsWith('/app/')) {
|
||||||
const name = decodeURIComponent(path.slice(5))
|
const rest = decodeURIComponent(path.slice(5))
|
||||||
|
const slashIdx = rest.indexOf('/')
|
||||||
|
const name = slashIdx === -1 ? rest : rest.slice(0, slashIdx)
|
||||||
|
const tab = slashIdx === -1 ? 'overview' : rest.slice(slashIdx + 1)
|
||||||
setSelectedApp(name)
|
setSelectedApp(name)
|
||||||
|
setSelectedTab(name, tab)
|
||||||
setCurrentView('dashboard')
|
setCurrentView('dashboard')
|
||||||
} else if (path === '/settings') {
|
} else if (path === '/settings') {
|
||||||
setSelectedApp(null)
|
setSelectedApp(null)
|
||||||
setCurrentView('settings')
|
setCurrentView('settings')
|
||||||
|
} else if (path === '/logs') {
|
||||||
|
setSelectedApp(null)
|
||||||
|
setDashboardTab('logs')
|
||||||
|
setCurrentView('dashboard')
|
||||||
|
} else if (path === '/metrics') {
|
||||||
|
setSelectedApp(null)
|
||||||
|
setDashboardTab('metrics')
|
||||||
|
setCurrentView('dashboard')
|
||||||
} else {
|
} else {
|
||||||
setSelectedApp(null)
|
setSelectedApp(null)
|
||||||
|
setDashboardTab('urls')
|
||||||
setCurrentView('dashboard')
|
setCurrentView('dashboard')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,19 +7,18 @@ export let currentView: 'dashboard' | 'settings' = 'dashboard'
|
||||||
export let isNarrow: boolean = window.matchMedia('(max-width: 768px)').matches
|
export let isNarrow: boolean = window.matchMedia('(max-width: 768px)').matches
|
||||||
export let selectedApp: string | null = null
|
export let selectedApp: string | null = null
|
||||||
export let sidebarCollapsed: boolean = localStorage.getItem('sidebarCollapsed') === 'true'
|
export let sidebarCollapsed: boolean = localStorage.getItem('sidebarCollapsed') === 'true'
|
||||||
export let dashboardTab: DashboardTab = (localStorage.getItem('dashboardTab') as DashboardTab) || 'urls'
|
export let dashboardTab: DashboardTab = 'urls'
|
||||||
export let sidebarSection: 'apps' | 'tools' = (localStorage.getItem('sidebarSection') as 'apps' | 'tools') || 'apps'
|
export let sidebarSection: 'apps' | 'tools' = (localStorage.getItem('sidebarSection') as 'apps' | 'tools') || 'apps'
|
||||||
|
|
||||||
// Server state (from SSE)
|
// Server state (from SSE)
|
||||||
export let apps: App[] = []
|
export let apps: App[] = []
|
||||||
|
|
||||||
// Tab state
|
// Tab state
|
||||||
export let appTabs: Record<string, string> = JSON.parse(localStorage.getItem('appTabs') || '{}')
|
export let appTabs: Record<string, string> = {}
|
||||||
|
|
||||||
// State setters
|
// State setters
|
||||||
export function setDashboardTab(tab: DashboardTab) {
|
export function setDashboardTab(tab: DashboardTab) {
|
||||||
dashboardTab = tab
|
dashboardTab = tab
|
||||||
localStorage.setItem('dashboardTab', tab)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setCurrentView(view: 'dashboard' | 'settings') {
|
export function setCurrentView(view: 'dashboard' | 'settings') {
|
||||||
|
|
@ -54,5 +53,4 @@ export const getSelectedTab = (appName: string | null) =>
|
||||||
export function setSelectedTab(appName: string | null, tab: string) {
|
export function setSelectedTab(appName: string | null, tab: string) {
|
||||||
if (!appName) return
|
if (!appName) return
|
||||||
appTabs[appName] = tab
|
appTabs[appName] = tab
|
||||||
localStorage.setItem('appTabs', JSON.stringify(appTabs))
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,10 @@ app.get('/dist/:file', async c => {
|
||||||
})
|
})
|
||||||
|
|
||||||
// SPA routes — serve the shell for all client-side paths
|
// SPA routes — serve the shell for all client-side paths
|
||||||
|
app.get('/app/:name/:tab', c => c.html(<Shell />))
|
||||||
app.get('/app/:name', c => c.html(<Shell />))
|
app.get('/app/:name', c => c.html(<Shell />))
|
||||||
|
app.get('/logs', c => c.html(<Shell />))
|
||||||
|
app.get('/metrics', c => c.html(<Shell />))
|
||||||
app.get('/settings', c => c.html(<Shell />))
|
app.get('/settings', c => c.html(<Shell />))
|
||||||
|
|
||||||
cleanupStalePublishers()
|
cleanupStalePublishers()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user