more testing
This commit is contained in:
1 parent
1aa264675e
commit
2da2649a2f
11 files changed
+293
-51
No files matched your search
@@ -1,3 +1,6 @@
|
||||
import { useCallback, useMemo } from "react"
|
||||
import { useLocation } from "wouter"
|
||||
|
||||
// Route ↔ tab mapping. Tabs live in the URL (wouter) so deep links survive
|
||||
// the OIDC login redirect at the ingress: users.k6n.net sends you back to
|
||||
// exactly the view you requested, and URLs are shareable/bookmarkable.
|
||||
@@ -12,14 +15,28 @@ export const TAB_PATHS: Record<string, string> = {
|
||||
"/setup": "tab4",
|
||||
"/trends": "tab5",
|
||||
"/search": "tab6",
|
||||
"/frontend": "tab7",
|
||||
"/rum": "tab7",
|
||||
"/frontend": "tab7",
|
||||
}
|
||||
|
||||
|
||||
/** Tab value for a location pathname, or null when the path isn't a tab. */
|
||||
/** Splits "/issues/abc/trace/def" into base "/issues" and rest ["abc","trace","def"]. */
|
||||
export function splitPath(path: string): { base: string; rest: string[] } {
|
||||
const parts = path.split("/").filter(Boolean)
|
||||
return { base: "/" + (parts[0] ?? ""), rest: parts.slice(1).map((p) => decodeURIComponent(p)) }
|
||||
}
|
||||
|
||||
/** Builds a path below a tab base, e.g. joinPath("/issues", ["abc", "trace", "def"]). */
|
||||
export function joinPath(base: string, rest: string[]): string {
|
||||
return [base, ...rest.map((p) => encodeURIComponent(p))].join("/")
|
||||
}
|
||||
|
||||
/**
|
||||
* Tab value for a location pathname, or null when the path isn't a tab.
|
||||
* Deeper paths ("/issues/<id>/trace/<id>") belong to their first segment's tab.
|
||||
*/
|
||||
export function tabForPath(path: string): string | null {
|
||||
return TAB_PATHS[path] ?? null
|
||||
return TAB_PATHS[splitPath(path).base] ?? null
|
||||
}
|
||||
|
||||
/** Canonical path for a tab value, or null when the tab has no route. */
|
||||
@@ -29,3 +46,28 @@ export function pathForTab(tab: string): string | null {
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Sub-route below the current tab: `segments` are the path parts after the
|
||||
* tab base and `go` rewrites them, so selection state (which issue, which
|
||||
* trace, ...) lives in the URL and survives reloads, back/forward and sharing.
|
||||
*/
|
||||
export function useSubRoute(): {
|
||||
segments: string[]
|
||||
go: (segments: string[], options?: { replace?: boolean }) => void
|
||||
} {
|
||||
const [location, navigate] = useLocation()
|
||||
const { base, rest } = splitPath(location)
|
||||
const key = rest.join("/")
|
||||
// Stable identity per URL so effects can depend on `segments` directly.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const segments = useMemo(() => rest, [key])
|
||||
const go = useCallback(
|
||||
(next: string[], options?: { replace?: boolean }) => navigate(joinPath(base, next), options),
|
||||
[base, navigate],
|
||||
)
|
||||
return { segments, go }
|
||||
}
|
||||
|
||||
/** Short reference for showing an id to humans (full id stays in the URL). */
|
||||
export const shortId = (id: string) => (id.length > 10 ? id.slice(0, 8) : id)
|
||||
Reference in new issue
Block a user