fix: auto-compute environment slug + respect environment filter globally
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 1m26s
CI / docker (push) Successful in 1m6s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 37s

Part A: Environment creation slug is now auto-derived from display name
and shown read-only (matching app creation pattern). Removes manual slug
input.

Part B: All data queries now pass the selected environment to backend:
- Exchanges search, Dashboard L1/L2/L3 stats, Routes metrics, Route
  detail, correlation chains, and processor metrics all filter by
  selected environment.
- Backend RouteMetricsController now accepts environment parameter for
  both route and processor metrics endpoints.

Closes #XYZ

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-04-09 16:01:50 +02:00
parent f95a78a380
commit cb36d7936f
11 changed files with 81 additions and 43 deletions

View File

@@ -26,6 +26,14 @@ import {
import type { Environment } from '../../api/queries/admin/environments';
import styles from './UserManagement.module.css';
function slugify(name: string): string {
return name
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '')
.substring(0, 100);
}
export default function EnvironmentsPage() {
const { toast } = useToast();
const { data: environments = [], isLoading } = useEnvironments();
@@ -40,6 +48,10 @@ export default function EnvironmentsPage() {
const [newDisplayName, setNewDisplayName] = useState('');
const [newProduction, setNewProduction] = useState(false);
useEffect(() => {
setNewSlug(slugify(newDisplayName));
}, [newDisplayName]);
// Mutations
const createEnv = useCreateEnvironment();
const updateEnv = useUpdateEnvironment();
@@ -153,19 +165,15 @@ export default function EnvironmentsPage() {
<>
{creating && (
<div className={styles.createForm}>
<Input
placeholder="Slug (e.g. staging) *"
value={newSlug}
onChange={(e) => setNewSlug(e.target.value)}
/>
{duplicateSlug && (
<span className={styles.errorText}>Slug already exists</span>
)}
<Input
placeholder="Display name *"
value={newDisplayName}
onChange={(e) => setNewDisplayName(e.target.value)}
/>
<MonoText size="sm">{newSlug || '...'}</MonoText>
{duplicateSlug && (
<span className={styles.errorText}>Slug already exists</span>
)}
<label className={styles.securityRow}>
<Toggle checked={newProduction} onChange={() => setNewProduction(!newProduction)} />
Production environment