mirror of
https://github.com/BloopAI/vibe-kanban.git
synced 2026-10-21 17:48:28 +00:00
* remote-web: fix user-system fetch routing during first host pairing
* refactor(remote-web): migrate fully to host-scoped URL routing
Make /hosts/{hostId} the single source of truth for active host context, remove legacy host resolution state, and migrate remote workspace/project routes to host-scoped paths only.
Also update shared web-core navigation/path parsing helpers and callsites to use route builders so remote host-scoped routing typechecks and behaves consistently end-to-end.
* refactor(web-core): replace resolveAppPath with app navigation intents
Introduce runtime-aware app navigation helpers for local and remote web, add useAppNavigation hook, migrate redirect/history callsites, and remove string-based resolveAppPath path guessing.
* refactor(routes): centralize app navigation and remove sidebar path builders
* refactor(routes): delete legacy navigation module and unify on appNavigation
* refactor(navigation): inject app route mapping via local/remote providers
* refactor(remote-nav): define non-host fallback mapping in remote root
* refactor(app-navigation): move route mappings into local and remote apps
* refactor(app-navigation): colocate local and remote navigation modules
* docs: add hard migration plan for app navigation refactor
* docs: define shared semantic destination model in navigation plan
* docs: update navigation plan to move kanban search to local state
* docs: include host scope and precedence in navigation model plan
* docs: specify remote host resolution and no-fallback navigation rules
* docs: switch navigation plan to draft-first create flow without nav state
* docs: add hostless remote behavior decisions to app navigation migration plan
* docs: clarify remote hostless navigation and 404 policy
* docs: define web-core direct route cleanup and Link removal scope
* docs: require typed replacement for to='.' navigation normalization
* docs: add remote host UX consolidation phase and host action policy
* docs: switch app navigation plan to in-memory kanban create defaults
* docs: lock kanban in-memory defaults rules and rollout order
* refactor: add semantic app destination parsing and unify project sidebar route parsing
* refactor: migrate app navigation to imperative destination API
Replace route-object navigation usage with appNavigation.navigate across web-core, move route mapping into local/remote adapters, remove ActionExecutorContext.navigate, and update migration plan phase tracking.
* refactor: consolidate remote host resolution and remove direct web-core route primitives
Add shared remote host selection helper, apply it in HomePage and RemoteAppShell, and replace remaining web-core onboarding/issue Link-Navigate usage with AppNavigation.
* refactor: move kanban create defaults to in-memory state and make app navigation path-only
* refactor: remove workspace-create router state and use scratch-only initialization
* refactor: use semantic first-project destinations in root and onboarding redirects
* chore: add app-navigation any guardrail and complete phases 7/8
* refactor: migrate AppNavigation to goTo API and enforce route guards
* refactor: remove navigate API and enforce destination dispatch
* fix: surface workspace draft creation failures in kanban panel
* refactor: move path resolution to app adapters and remove shared parser
* refactor: remove projectSidebarRoutes and consume AppDestination directly
* refactor: use explicit goTo methods in root and onboarding redirects
* refactor root redirect page to single-effect navigation flow
* remove previous-path replay and simplify project nav to root
* remove useKanbanNavigation and inline typed route-driven kanban nav
* refactor(web-core): centralize destination parsing with shared hooks
* refactor(kanban): hard-cut issue create routes and use composer state
* chore(navigation): move issue-create options to composer domain
Prune legacy allowlist entries and fix guard script behavior when allowlist is empty.
* docs: remove completed app navigation migration plan
99 lines
2.4 KiB
TypeScript
99 lines
2.4 KiB
TypeScript
import { useMemo } from "react";
|
|
import { useQuery } from "@tanstack/react-query";
|
|
import type { AppBarHost } from "@vibe/ui/components/AppBar";
|
|
import type { RelayHost } from "shared/remote-types";
|
|
import { listPairedRelayHosts } from "@/shared/lib/relayPairingStorage";
|
|
import { listRelayHosts } from "@/shared/lib/remoteApi";
|
|
|
|
const RELAY_APP_BAR_HOSTS_QUERY_KEY = ["relay-app-bar-hosts", "hosts"] as const;
|
|
const RELAY_APP_BAR_PAIRED_HOSTS_QUERY_KEY = [
|
|
"relay-app-bar-hosts",
|
|
"paired-hosts",
|
|
] as const;
|
|
|
|
interface UseRelayAppBarHostsResult {
|
|
hosts: AppBarHost[];
|
|
isLoading: boolean;
|
|
}
|
|
|
|
export interface ResolveRelayNavigationHostOptions {
|
|
routeHostId?: string | null;
|
|
}
|
|
|
|
export function resolveRelayNavigationHostId(
|
|
hosts: AppBarHost[],
|
|
options?: ResolveRelayNavigationHostOptions,
|
|
): string | null {
|
|
const routeHostId = options?.routeHostId ?? null;
|
|
if (routeHostId) {
|
|
return routeHostId;
|
|
}
|
|
|
|
const onlineHost = hosts.find((host) => host.status === "online");
|
|
if (onlineHost) {
|
|
return onlineHost.id;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function mapRelayHostStatus(
|
|
host: RelayHost,
|
|
pairedHostIds: Set<string>,
|
|
): AppBarHost["status"] {
|
|
if (!pairedHostIds.has(host.id)) {
|
|
return "unpaired";
|
|
}
|
|
|
|
return host.status === "online" ? "online" : "offline";
|
|
}
|
|
|
|
export function useRelayAppBarHosts(
|
|
enabled: boolean,
|
|
): UseRelayAppBarHostsResult {
|
|
const hostsQuery = useQuery({
|
|
queryKey: RELAY_APP_BAR_HOSTS_QUERY_KEY,
|
|
queryFn: listRelayHosts,
|
|
enabled,
|
|
staleTime: 30_000,
|
|
refetchInterval: 30_000,
|
|
});
|
|
|
|
const pairedHostsQuery = useQuery({
|
|
queryKey: RELAY_APP_BAR_PAIRED_HOSTS_QUERY_KEY,
|
|
queryFn: async () => {
|
|
try {
|
|
return await listPairedRelayHosts();
|
|
} catch (error) {
|
|
console.error("Failed to load paired relay hosts for app bar", error);
|
|
return [];
|
|
}
|
|
},
|
|
enabled,
|
|
staleTime: 5_000,
|
|
refetchInterval: 5_000,
|
|
});
|
|
|
|
const hosts = useMemo<AppBarHost[]>(() => {
|
|
if (!enabled) {
|
|
return [];
|
|
}
|
|
|
|
const relayHosts = hostsQuery.data ?? [];
|
|
const pairedHostIds = new Set(
|
|
(pairedHostsQuery.data ?? []).map((host) => host.host_id),
|
|
);
|
|
|
|
return relayHosts.map((host) => ({
|
|
id: host.id,
|
|
name: host.name,
|
|
status: mapRelayHostStatus(host, pairedHostIds),
|
|
}));
|
|
}, [enabled, hostsQuery.data, pairedHostsQuery.data]);
|
|
|
|
return {
|
|
hosts,
|
|
isLoading: enabled && (hostsQuery.isLoading || pairedHostsQuery.isLoading),
|
|
};
|
|
}
|