fix: commands respect selected environment
Backend: AgentRegistryService gains findByApplicationAndEnvironment() and environment-aware addGroupCommandWithReplies() overload. AgentCommandController and ApplicationConfigController accept optional environment query parameter. When set, commands only target agents in that environment. Backward compatible — null means all environments. Frontend: All command mutations (config update, route control, traced processors, tap config, route recording) now pass selectedEnv to the backend via query parameter. Prevents cross-environment command leakage — e.g., updating config for prod no longer pushes to dev agents. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import { useCatalog } from '../../api/queries/catalog';
|
||||
import { useAgents } from '../../api/queries/agents';
|
||||
import { useApplicationConfig, useUpdateApplicationConfig } from '../../api/queries/commands';
|
||||
import type { TapDefinition, ConfigUpdateResponse } from '../../api/queries/commands';
|
||||
import { useEnvironmentStore } from '../../api/environment-store';
|
||||
import { useCanControl } from '../../auth/auth-store';
|
||||
import { useTracingStore } from '../../stores/tracing-store';
|
||||
import type { NodeAction, NodeConfig } from '../../components/ProcessDiagram/types';
|
||||
@@ -23,6 +24,7 @@ import type { SelectedExchange } from '../Dashboard/Dashboard';
|
||||
export default function ExchangesPage() {
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const selectedEnv = useEnvironmentStore((s) => s.environment);
|
||||
const { appId: scopedAppId, routeId: scopedRouteId, exchangeId: scopedExchangeId } =
|
||||
useParams<{ appId?: string; routeId?: string; exchangeId?: string }>();
|
||||
|
||||
@@ -143,6 +145,7 @@ interface DiagramPanelProps {
|
||||
}
|
||||
|
||||
function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearSelection }: DiagramPanelProps) {
|
||||
const selectedEnv = useEnvironmentStore((s) => s.environment);
|
||||
const { timeRange } = useGlobalFilters();
|
||||
const timeFrom = timeRange.start.toISOString();
|
||||
const timeTo = timeRange.end.toISOString();
|
||||
@@ -240,7 +243,7 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
|
||||
|
||||
const handleTapSave = useCallback((updatedConfig: typeof appConfig) => {
|
||||
if (!updatedConfig) return;
|
||||
updateConfig.mutate(updatedConfig, {
|
||||
updateConfig.mutate({ config: updatedConfig, environment: selectedEnv }, {
|
||||
onSuccess: (saved: ConfigUpdateResponse) => {
|
||||
if (saved.pushResult.success) {
|
||||
toast({ title: 'Tap configuration saved', description: `Pushed to ${saved.pushResult.total}/${saved.pushResult.total} agents (v${saved.config.version})`, variant: 'success' });
|
||||
@@ -258,7 +261,7 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
|
||||
const handleTapDelete = useCallback((tap: TapDefinition) => {
|
||||
if (!appConfig) return;
|
||||
const taps = appConfig.taps.filter(t => t.tapId !== tap.tapId);
|
||||
updateConfig.mutate({ ...appConfig, taps }, {
|
||||
updateConfig.mutate({ config: { ...appConfig, taps }, environment: selectedEnv }, {
|
||||
onSuccess: (saved: ConfigUpdateResponse) => {
|
||||
if (saved.pushResult.success) {
|
||||
toast({ title: 'Tap deleted', description: `${tap.attributeName} removed — pushed to ${saved.pushResult.total}/${saved.pushResult.total} agents (v${saved.config.version})`, variant: 'success' });
|
||||
@@ -287,10 +290,10 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS
|
||||
const enabled = nodeId in newMap;
|
||||
const tracedProcessors: Record<string, string> = {};
|
||||
for (const [k, v] of Object.entries(newMap)) tracedProcessors[k] = v;
|
||||
updateConfig.mutate({
|
||||
updateConfig.mutate({ config: {
|
||||
...appConfig,
|
||||
tracedProcessors,
|
||||
}, {
|
||||
}, environment: selectedEnv }, {
|
||||
onSuccess: (saved: ConfigUpdateResponse) => {
|
||||
if (saved.pushResult.success) {
|
||||
toast({ title: `Tracing ${enabled ? 'enabled' : 'disabled'}`, description: `${nodeId} — pushed to ${saved.pushResult.total}/${saved.pushResult.total} agents (v${saved.config.version})`, variant: 'success' });
|
||||
|
||||
Reference in New Issue
Block a user