mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-28 19:11:03 +08:00
fix: subpath navigation
This commit is contained in:
@@ -14,7 +14,7 @@ import {
|
||||
type RecentProjectItem,
|
||||
type ProjectQuery,
|
||||
} from "../../client"
|
||||
import { type Path } from "../../shared/navigation"
|
||||
import { strip, type Path } from "../../shared/navigation"
|
||||
import { clean, friendly } from "../../shared/utils"
|
||||
import {
|
||||
projectStatus,
|
||||
@@ -111,6 +111,7 @@ function Glyph(props: { name: "projects" | "settings" | "profile" }) {
|
||||
export function AppSidebar(props: Props) {
|
||||
const loc = useLocation()
|
||||
const params = createMemo(() => new URLSearchParams(loc.search))
|
||||
const route = createMemo(() => strip(loc.pathname))
|
||||
const discoverable = () => shouldDiscover(params())
|
||||
const fallback = () => base(params())
|
||||
const [url, setUrl] = createSignal(fallback())
|
||||
@@ -126,14 +127,14 @@ export function AppSidebar(props: Props) {
|
||||
|
||||
// project currently rendered by ProjectConsoleRoute — it owns unread tracking for its terminals
|
||||
const activeProject = createMemo(() => {
|
||||
const match = loc.pathname.match(/^\/projects\/([^/]+)/)
|
||||
const match = route().match(/^\/projects\/([^/]+)/)
|
||||
return match ? decodeURIComponent(match[1]) : undefined
|
||||
})
|
||||
|
||||
const settings = () => `/settings${tail(params())}`
|
||||
const selected = (item: RecentProjectItem) =>
|
||||
loc.pathname.startsWith(`/projects/${encodeURIComponent(item.id)}/`) ||
|
||||
loc.pathname === `/projects/${encodeURIComponent(item.id)}`
|
||||
route().startsWith(`/projects/${encodeURIComponent(item.id)}/`) ||
|
||||
route() === `/projects/${encodeURIComponent(item.id)}`
|
||||
|
||||
const nav = () => [
|
||||
{ href: "/projects", label: "Projects", name: "projects", path: "/projects" },
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
type TuiPatch,
|
||||
} from "../client"
|
||||
import { ConfigContext, type Task } from "./config"
|
||||
import { strip } from "../shared/navigation"
|
||||
import { clean, errMsg } from "../shared/utils"
|
||||
import { useLocation, useParams } from "@solidjs/router"
|
||||
|
||||
@@ -45,7 +46,8 @@ export function ConfigProvider(props: { children?: JSX.Element }) {
|
||||
const discoverable = () => shouldDiscover(search())
|
||||
const fallback = () => base(search())
|
||||
const [url, setUrl] = createSignal(fallback())
|
||||
const scope = createMemo<Scope>(() => (loc.pathname.startsWith("/projects/") ? "project" : "global"))
|
||||
const route = createMemo(() => strip(loc.pathname))
|
||||
const scope = createMemo<Scope>(() => (route().startsWith("/projects/") ? "project" : "global"))
|
||||
const [saving, setSaving] = createSignal<string | undefined>()
|
||||
const [failure, setFailure] = createSignal<string | undefined>()
|
||||
const needs = createMemo(() => scope() === "project")
|
||||
|
||||
@@ -8,6 +8,7 @@ import { CountTag, Tag } from "@kilocode/kilo-web-ui/tag"
|
||||
import { CustomSelect, type SelectOption } from "../../components/CustomSelect"
|
||||
import { SearchField } from "../../components/SearchField"
|
||||
import { useConfig } from "../../context/config"
|
||||
import { settings } from "../../shared/navigation"
|
||||
import { toolCapabilities, toolName } from "../../shared/utils"
|
||||
import { ConfigPage, SourceBadge } from "./ConfigPage"
|
||||
import { ActionSelect, label as actionLabel, tone as actionTone } from "./PermissionsRoute"
|
||||
@@ -30,13 +31,6 @@ const modes = [
|
||||
{ value: "all", label: "Both" },
|
||||
] satisfies SelectOption<"primary" | "subagent" | "all">[]
|
||||
|
||||
function base(input: string) {
|
||||
const index = input.indexOf("/settings")
|
||||
if (index > 0) return `${input.slice(0, index)}/settings`
|
||||
if (input.startsWith("/config")) return "/config"
|
||||
return "/settings"
|
||||
}
|
||||
|
||||
function desc(item: AgentItem) {
|
||||
return item.description ?? "No description available."
|
||||
}
|
||||
@@ -51,7 +45,7 @@ function useAgentLinks() {
|
||||
const nav = useNavigate()
|
||||
const href = (id?: string) => {
|
||||
const suffix = id ? `/${encodeURIComponent(id)}` : ""
|
||||
return `${base(loc.pathname)}/agents${suffix}${loc.search}`
|
||||
return `${settings(loc.pathname)}/agents${suffix}${loc.search}`
|
||||
}
|
||||
return { href, nav }
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import { createMemo, For } from "solid-js"
|
||||
import { Icon } from "@kilocode/kilo-web-ui/icon"
|
||||
import { configNav, type ConfigGroup, type ConfigNode } from "./sections"
|
||||
import { friendly } from "../../shared/utils"
|
||||
import { settings, strip } from "../../shared/navigation"
|
||||
import { useConfig } from "../../context/config"
|
||||
|
||||
function repo(input: string) {
|
||||
@@ -14,20 +15,17 @@ export function ConfigSidebar() {
|
||||
const loc = useLocation()
|
||||
const params = useParams()
|
||||
const ctx = useConfig()
|
||||
const project = createMemo(() => loc.pathname.startsWith("/projects/"))
|
||||
const route = createMemo(() => strip(loc.pathname))
|
||||
const project = createMemo(() => route().startsWith("/projects/"))
|
||||
const scope = createMemo(() => {
|
||||
if (!project()) return "Global"
|
||||
const dir = ctx.query()?.dir
|
||||
if (dir) return friendly(repo(dir))
|
||||
return friendly(decodeURIComponent(params.project ?? "Project"))
|
||||
})
|
||||
const base = createMemo(() => {
|
||||
const index = loc.pathname.indexOf("/settings")
|
||||
if (index > 0) return `${loc.pathname.slice(0, index)}/settings`
|
||||
return "/settings"
|
||||
})
|
||||
const base = createMemo(() => settings(route()))
|
||||
const active = createMemo(() => {
|
||||
const rest = loc.pathname.slice(base().length)
|
||||
const rest = route().slice(base().length)
|
||||
if (rest === "/models") return "/models/default"
|
||||
return rest || "/"
|
||||
})
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import { expect, test } from "bun:test"
|
||||
import { path, settings, strip } from "./navigation"
|
||||
|
||||
test("strips the deployed console base from route paths", () => {
|
||||
expect(strip("/console/projects/demo/settings/agents", "/console")).toBe("/projects/demo/settings/agents")
|
||||
expect(strip("/console", "/console")).toBe("/")
|
||||
expect(strip("/consoleish/projects", "/console")).toBe("/consoleish/projects")
|
||||
})
|
||||
|
||||
test("classifies routes after stripping the console base", () => {
|
||||
expect(path("/console/projects/demo/settings/agents", "/console")).toBe("/project")
|
||||
expect(path("/console/settings/agents", "/console")).toBe("/settings")
|
||||
expect(path("/console/profile", "/console")).toBe("/profile")
|
||||
})
|
||||
|
||||
test("builds settings roots without preserving the console base", () => {
|
||||
expect(settings("/console/projects/demo/settings/agents", "/console")).toBe("/projects/demo/settings")
|
||||
expect(settings("/console/settings/agents", "/console")).toBe("/settings")
|
||||
})
|
||||
@@ -1,8 +1,28 @@
|
||||
export type Path = "/projects" | "/project" | "/profile" | "/settings"
|
||||
|
||||
export function path(input: string): Path {
|
||||
if (input === "/profile") return "/profile"
|
||||
if (input.startsWith("/settings") || input.startsWith("/config")) return "/settings"
|
||||
if (input.startsWith("/projects/")) return "/project"
|
||||
function base() {
|
||||
return (import.meta.env?.BASE_URL ?? "/").replace(/\/$/, "")
|
||||
}
|
||||
|
||||
export function strip(input: string, prefix = base()) {
|
||||
if (!prefix || prefix === "/") return input
|
||||
if (input === prefix) return "/"
|
||||
if (input.startsWith(`${prefix}/`)) return input.slice(prefix.length)
|
||||
return input
|
||||
}
|
||||
|
||||
export function settings(input: string, prefix = base()) {
|
||||
const route = strip(input, prefix)
|
||||
const index = route.indexOf("/settings")
|
||||
if (index > 0) return `${route.slice(0, index)}/settings`
|
||||
if (route.startsWith("/config")) return "/config"
|
||||
return "/settings"
|
||||
}
|
||||
|
||||
export function path(input: string, prefix = base()): Path {
|
||||
const route = strip(input, prefix)
|
||||
if (route === "/profile") return "/profile"
|
||||
if (route.startsWith("/settings") || route.startsWith("/config")) return "/settings"
|
||||
if (route.startsWith("/projects/")) return "/project"
|
||||
return "/projects"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user