Show host in search results and filter sidebar by multiple hosts (#1825)
* feat(app): show host in command center and multi-select host filter Command-center agent results now show which host the workspace lives on, shown only when more than one host is connected (matching the sidebar). The sidebar display-preferences filter becomes multi-select — pick any number of hosts instead of one-or-all — and its host rows now carry a status dot on the left like the other host pickers. Persisted filter state migrates from the old single host to a host list. * test(app): extract host-filter and command-center e2e DSL helpers Move the mechanical menu/search interactions out of the new spec bodies into focused helpers so the tests read as user intent. * fix(app): drop the icon from the host filter "All hosts" item * fix(app): make multi-host e2e seeding order-independent The offline-host seed relied on Playwright running the test's init script after the fixture's registry reset — an ordering Playwright does not guarantee. Write the full registry and set the fixture's disable-once flag, then reload, so the multi-host seed survives regardless of script order. Also tag the pre-v2 hostFilter migration reader with COMPAT so the cleanup sweep can find it.
This commit is contained in:
@@ -89,7 +89,7 @@ export interface SidebarWorkspacesListResult {
|
||||
}
|
||||
|
||||
export function useSidebarWorkspacesList(options?: {
|
||||
hostFilter?: string | null;
|
||||
hostFilters?: readonly string[];
|
||||
enabled?: boolean;
|
||||
}): SidebarWorkspacesListResult {
|
||||
const runtime = getHostRuntimeStore();
|
||||
@@ -97,27 +97,31 @@ export function useSidebarWorkspacesList(options?: {
|
||||
const hostRegistryLoaded = useHostRegistryLoaded();
|
||||
const allServerIds = useMemo(() => allHosts.map((h) => h.serverId), [allHosts]);
|
||||
|
||||
const storeHostFilter = useSidebarViewStore((state) => state.hostFilter);
|
||||
const hostFilter = options?.hostFilter ?? storeHostFilter;
|
||||
const reconcileHostFilter = useSidebarViewStore((state) => state.reconcileHostFilter);
|
||||
const hasHostFilterMatch = hostFilter ? allServerIds.includes(hostFilter) : false;
|
||||
const effectiveHostFilter =
|
||||
hostFilter && (!hostRegistryLoaded || hasHostFilterMatch) ? hostFilter : null;
|
||||
const storeHostFilters = useSidebarViewStore((state) => state.hostFilters);
|
||||
const hostFilters = options?.hostFilters ?? storeHostFilters;
|
||||
const reconcileHostFilters = useSidebarViewStore((state) => state.reconcileHostFilters);
|
||||
const isActive = options?.enabled !== false;
|
||||
|
||||
const serverIds = useMemo(() => {
|
||||
if (effectiveHostFilter) {
|
||||
return allServerIds.filter((id) => id === effectiveHostFilter);
|
||||
if (hostFilters.length === 0) {
|
||||
return allServerIds;
|
||||
}
|
||||
return allServerIds;
|
||||
}, [allServerIds, effectiveHostFilter]);
|
||||
const selected = new Set(hostFilters);
|
||||
const matched = allServerIds.filter((id) => selected.has(id));
|
||||
// Registry has settled but none of the pinned hosts still exist — fall back to every
|
||||
// host rather than leaving the sidebar empty.
|
||||
if (hostRegistryLoaded && matched.length === 0) {
|
||||
return allServerIds;
|
||||
}
|
||||
return matched;
|
||||
}, [allServerIds, hostFilters, hostRegistryLoaded]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!hostRegistryLoaded) {
|
||||
return;
|
||||
}
|
||||
reconcileHostFilter(allServerIds);
|
||||
}, [allServerIds, hostRegistryLoaded, reconcileHostFilter]);
|
||||
reconcileHostFilters(allServerIds);
|
||||
}, [allServerIds, hostRegistryLoaded, reconcileHostFilters]);
|
||||
|
||||
const persistedProjectOrder = useSidebarOrderStore((state) => state.projectOrder ?? EMPTY_ORDER);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user