import { Server } from "@/lib/api"; /* * The browser's copy of services.ResolveTargets. * * This is a deliberate duplication: the authority is UnionTargets/MatchesTags in * server/internal/services/targets.go, and this exists only so a screen can * answer "how many servers?" without a round trip, since the browser already * holds the fleet. It must stay identical in MEANING to the Go version and * change in the same commit as it. * * It lives here rather than in a component because it had already been written * twice — once in the designer and once, wrongly, on the workflows list, where * the count ignored tags entirely and a tag-only workflow reported zero targets. */ /** True when srv carries every pair in sel. Tag keys AND together. */ export function matchesTags(srv: Server, sel: Record): boolean { // An EMPTY selector matches NOTHING, not everything. The alternative turns a // cleared field in the editor into a fleet-wide run. if (Object.keys(sel).length === 0) return false; return Object.entries(sel).every(([k, v]) => srv.tags?.[k] === v); } /** The distinct union of the named servers and the tag matches, in fleet order. */ export function resolveTargets(servers: Server[], ids: string[], sel: Record): Server[] { return servers.filter((s) => ids.includes(s.server_id) || matchesTags(s, sel)); }